![]() Mechstorm's Complete Map Making Tutorial or MCM for Short. Covering Mechwarrior4, Mechwarrior4:BK and Mechwarrior4:Mercs. If you have any questions feel free to drop by our Mechstorm Editor/Scripting help Forum after you have registered on our forums. |
Welcome to Giskard's little chat about bots the universe and everything. In this document I'll share some of my thoughts and ideas with you regarding bots and how they work. Which should be of interest to scripters mainly or those with basic understanding of mechwarrior scripting but want to know how some commands actually work in practice so you can be more creative when making your own bots. Understanding the actual effects of certain commands not only leads to improved gameplay but a massive leap forward in how effective bots can be. Being able to take advantage of some commands side effects or play down bad commands side effects by replacing them with commands that do similar tasks but have no bad side effects can be extremely interesting and useful. I often joke about being able to make my bots do the "Jane Fondas work out" to music but it is actually possible to do that. All you need is a good working knowledge of the bot commands and a good imagination. Here I hope to provide the working knowledge part. The rest is up to you.
One Tip before I begin. DO NOT EDIT THE MISCFUNCS,ABL mentioned in this doc.
First lets look at the standard Uberbot by microsoft.
Take your time and become familar with it.
fsm UberBot : integer;
// UberBot: //------------------------------------------------------------------
const //------------------------------------------------------------------ type //------------------------------------------------------------------ var function Init; // driver settings EnablePerWeaponRayCasting (ME,TRUE); endfunction; //------------------------------------------------------------------ state StartState; code endstate; //------------------------------------------------------------------ state WaitToAmbushState; OrderMoveLookOut; //------------------------------------------------------------------ state AttackState; OrderAttackTactic(TACTIC_FAST_CIRCLE,TRUE); //------------------------------------------------------------------ state DeadState; endstate;
|
Hopefully you have studied it enough now to be able to recognise which points I am refering too below.
First the lines
attackRange = 9999;
withdrawRange = 9999;
9999 is actually the range but its hard to know what it actually means in practice when you see attack range and withdrawrange. Nor is it clear what difference changing these can make to your bots. So lets look at these in detail.
Attackrange is actually used when the bot scans for targets. The reason why bots automatically know where you are is because the attack range is set to 9999 meters.Which basically gives them a radar range of 9999 meters and most maps are less than 5000m. Before you go and set that to normal radar ranges consider this, how exactly is the bot supposed to know where to move too if it has the correct radar range entered here ?
You see the problem, if you set the range to 1000 or 1200 meters then the bots will only detect enemies within that range. Which is great for coops, it adds some realistic behavour to your missions but its bad for multiplayer generally when the bots are expected to attack the player, it makes them wait at their spawn point for the enemy to come to them. You need to use paths and other commands to tell them where to move first so they will get within radar range of the enemy. After that everything will work fine. So whilst using attackRange = 9999; is a bit of cheat, its a nessessary cheat for multiplayer games where the bots are not carefully scripted to perform certain tasks.
Now we see Withdrawrange.
This is range the bot should give up on a target and seek a new one. So generally you want this set to the max radar range of the bot. Idealy you want the attack range set to max range of the weapons fitted to the bot and the withdraw range set to the max radar range. At least for coops, for multiplayer bots that are not carefully controlled you will need 9999 entered for both of these.
Btw the attackrange and withdrawrange are used by a var called searchrange thats part of the findobject function in the miscfuncs.abl. We will be talking about that in detail later.
On to the rest of the function init entry now.
|
SetFiringDelay (ME,0.0,0.0); EnablePerWeaponRayCasting (ME,TRUE); |
This part is interesting and I am now going to share some of my secrets with you. After many years of experiementing I worked out the ideal bot settings for use against normal players. You can adjust these settings for use against better players easily.
Time for some cause and effect issues whilst I step through the best settings.
SetFiringDelay (ME,0.0,0.0); = uber bot
SetFiringDelay (ME,1.0,4.0); = Noobie
Thats represents the difference between a noobie bot and an elite style bot. The uber bot entry never waits to fire its next shot, when ever the weapon is ready it shoots. The Noobie bot always has to wait between 1 and 4 seconds no matter what. So it fires less often than the Uber bot. Which is a better more realistic setting but unlike the player, the bot will not suddenly fire frantically when its in a dog fight. It will keep firing at the same old pace. Perhaps this is an area some of you can be creative in and add some code to adjust this when a bot gets close to its target. Not tried it yet my self but it sounds like a good idea.
SetFiringDelay (ME,0.4,1.0);
This would make the bots shooting habbits appear more human.
What was that, you want deadly bots ?
Well now you know what causes the bots to shoot faster, lets see how much common
sense you've applied to this problem.
Lets look at the Uziel, the default config the mech mounts two PPC if i remember right. So in your opinion, what happens if that Uziel shoots those PPCs the moment they recharge and keeps doing so.
Yup the bot overheats. Thats why Uber bots can be seen to be smoking during combat. The SetFiringDelay (ME,0.0,0.0); just makes them overheat faster if you give them to the wrong settings. So uber bots are just massive supernovas on a hot map and not the best bot at all, even though they are supposed to be the best. Unlike the player, the bot does not know when to stop shooting. So check the bots loadout before going mad with the setfiredelay.
About know you should start to understand why imagination and common sense is a requirement for AI work and why having the skills to script a bot is simply not enough. Imagination is by far the most important skill to have when designing bots.
Now for SetIgnoreFriendlyFire
SetIgnoreFriendlyFire (ME,true);
You all can guess what this does, it makes the bot ignore friendly fire. Change the true to a false and you could end up causing a riot amongst the bots. When I have worked on AIs for other games with complex alignments I found turning a feature similar to this off can lead to some extremely undesirable effects. Dam funny effects but not what you want really. I do recommend you try it once just for a laugh but it is not something you want on a release map. So leave this alone generally.
I'll tell you a little story about what I saw happen in 2 different games, this example is from Neverwinter Nights. I made my own virtual world, set all the faction alignments up so perfectly they all had different attitudes towards each other and all had reasons to help or not help should a fight break out. Well... a stray arrow hit a guard so the guards attacked me, the guards hit a merchant who was in the way so the merchants attacked the guards. When that happened the people of my town attacked the merchants and those who like the merchants attacked the people of the town. 20 minutes later I killed the last surviving person in my town after wiping away the tears that where streaming down my face because I was laughing so hard.
Btw Eldar Scrolls 4: Oblivion has this problem, its actually built in to the game, just lure a goblin out of the sewers in the Imperial city and stand back :)
Who said AI work was boring :)
Anyway, on with the show.....
A far more interesting command is this one.
SetIsShotRadius (ME,200);
What this does is it means any shots that hit ME (ME being the bot running the script) count as a hit. The 200 is the range the shots need to be from the bot to count as a hit. So any shot passing within 200m of the bot will count as a hit and the bot will register it as a hit. Clearly you will not damage a mech if you do not actually hit it but having a shell whisling past your ear is a good example of what this means to the bot. I found values as low as 50 can work well, lower than that and nothing but a CT hit will count as a hit. So never go below 50.
SetIsShotRadius is a command that stores information I use heavily later with other commands, so changing this setting can have dramatic effects on the bots behavour if you use my bot scripts such as the lancement bots or leaderbot. Or anything made since I released those.
Time to address Moods the bots have.
The following commands set the starting mood and the mood the bot regards as its normal mood. The idea is it gets angry and works it self in to a frenzy and the mood changes, then it calms down and the mood reverts to what ever mood was normal for the bot. The mood effects the tactics it can use and those tactics are chosen when you use "OrderAttackTactic(TACTIC_PICK_BEST,TRUE);" in your bot. So the bots tactics dynamically change during the game.
SetEntropyMood (ME,AGRESSIVE_END);
SetCurMood (ME,AGRESSIVE_END);
All this sounds very cool and is a great idea I am sure you will agree. But you have not seen the tactics that get chosen. I have. To be honest they are far from the best tactics a bot should use and various conflicting commands cause the bot to appear confused and turn left and right without shooting anything. A problem made worse by the findobject command that I'll deal with later. So I tend to override these moods and make my own using only tactics that are suitable for bot. Basically I leave these alone so if I do use "TACTIC_PICK_BEST" these settings will automatically apply, saves me adding these lines back in basically. I am lazy that way :)
A typical Uber bot cheat next.
SetSkillLevel (ME,100,999,100);
or in English.
SetSkillLevel(who,pilot,gunnery,elite)
But in theory this should work to set and entire teams bots to the same skill level too, untested though.
SetSkillLevel (TeamobjectID(1),100,999,100);
Notice the 999, thats the the bots ability to shoot, 100 is the highest none cheating skill setting. This is why uber bots never miss. At this point id like to show you a command further down in the this function.
EnablePerWeaponRayCasting (ME,TRUE);
Enableperweaponraycasting causes a more accurate routine to be used to track the shot, making a bot even more accurate. But this comes at the expense of cpu time. In missions using a lot of bots its better to turn this off. For bots that are not supposed to be good shots, its also better to leave this turned off but for lrm boats, its better to turn this on because bots do not wait for the lockon before they fire so lrms miss a lot when bots fire them.
As you can see, the uber bot cheats like hell when shooting but what about the other settings.
Well the first and last number is the piloting skill and the end number concerns the bots ability to use certain tactics. Like the moods it governs what the mech can do. Since no faction in their right minds would let a noobie use a mech, we should assume that piloting and elite settings are 100. This means the mechwarrior in the mech can actually control his mech correctly but it also solves another problem map makers are familar with. It gives the bot a greater chance of being able to navigate on difficult or badly designed terrains. So its worth using the following settings on all bots.
SetSkillLevel (Me,100,xxx,100);
Notice I XXX'd out the gunnery skill. Time to share some of my findings with you.
The following is a typical second line mechwarrior with low skill levels.
SetSkillLevel (ME,100,50,100);
This is a mechwarror of average skill levels.
SetSkillLevel (ME,100,70,100);
This is an elite mechwarrior that does not cheat.
SetSkillLevel (ME,100,100,100);
I use the "SetSkillLevel (who,100,70,100);" mainly in my bots and they usually own the players most of the time. So the answer to to question "whos your daddy" is the averaged skilled bot in my missions, embarrising for all those who got beaten up by them lol. These settings will result in a more human bot that can navigate and work its way out of most areas on a map eventually without looking like at total noob whos been drinking to much beer. Only their ability to shoot straight is effected but thats the only area that ever worked right, the other areas need the higher settings to avoid problems.
Next up Speed.
SetAttackThrottle (ME,100);
SetMinSpeed (ME,100);
As you can see the uber bot has 1 speed, thats 100% throttle all the time. Hardly a realistic setting is it.But the bots have no other speed than the setting mentioned here. The attack throttle is the max throttle they will use in combat and the min speed is the lowest speed they should use normally. So if you want them to walk around slowly kicking rocks and then do the 100meter sprint when an enemy approaches try these settings below.
SetAttackThrottle (ME,600);
SetMinSpeed (ME,20);
Not many vehicles or mechs are faster than 600 in Mercs, so 600 is a good top end speed. Any mech or vehicle that cannot do that speed will just run at their own max speed instead. So a Daishi would never do 600kph even if you set it here. :)
We dealt with EnablePerWeaponRayCasting (ME,TRUE); above so its time to leave the bot skill settings and enter area of the code that actually controls the mech.
Lets look at States now.
The trans line in the start state names the state to jump too next. Which is the "WaitToAmbushState;" but you can edit the start states "trans WaitToAmbushState;" command to say "trans mybotsstate;" and then change the "state WaitToAmbushState;" below it to "state mybotsstate:" and the game would not complain. You see the state names do not actually matter, you can call them anything but a "state StartState;" has to exist and so does a "state DeadState;"
The start state is executed once when the bot first drops on to the map and the DeadState is run once when the bot dies. The command "orderDie;" in the deadstate stops the script running, it does not destroy the model, use the command destroy(me) for that. . So if you want to add more commands to the dead state you need to add them before the orderdie command. A good example of a deadstate command would be "chatmessage"ARGH, you got me, Im dying...argh....argh...im going to win an oscar for this...Thud."; :)
Now you know about the 2 important states that have to exist and you know everything in between them can be renamed to anything you like providing you "trans" to those new state names, we can focus on the real cool stuff but before we do lets remind you of the trans to state commands.
To get to a state called "state mystate;" you have to use the command "trans mystate;", consider this a goto command. Thats all it is. The computer will run any single state over and over until it reaches a trans line and is told to go somewhere else.
Ok lets look at the "state WaitToAmbushState;"
| state WaitToAmbushState; code if (Bot_FindEnemy(attackrange)) then trans AttackState; endif; OrderMoveLookOut; |
Remember that moods problem I highlighted above, well here is part 2 of that problem with the line below. When a mech is shot its mood changes and the next line checks when it is shot whilst scanning for targets. Trouble is, it only considers what to do about it being shot when it loses its current target. So its mood changes but it doesnt actually do anything about being shot at except under some very special conditions. So you could stand behind it with 4 guass and blast it and it would ignore you providing it still had its original target.
if (Bot_FindEnemy(attackrange)) then
I know the line above does not actually say "isshot" or anything like it but thats because the command Bot_FindEnemy is actually a function found in the miscfuncs.abl file. The one I told you not to edit. Here is the real command being run here.
This one cheats btw.
| function Bot_FindEnemy(integer searchrange) : boolean; var integer foe; code foe = FindObject(ME,FA_ENEMY,FT_DEFAULT,FC_BEST_TARGET,FF_WHO_SHOT + FF_SEEPLAYER + FF_LOOK_EVERYWHERE,searchrange); if (foe <> no_unit) then SetTarget (me,foe); return (true); endif; return (false); |
And here is one that does not cheat.
| function FindEnemy(integer searchrange, integer flags) : boolean; var integer foe; code foe = FindObject(ME,FA_ENEMY,flags,FC_BEST_TARGET,FF_WHO_SHOT + FF_SEEPLAYER,searchrange); if (foe <> no_unit) then SetTarget (me,foe); return (true); endif; return (false); |
Take a few minutes to look at the findobject line, see if you can see why the bot_findobject cheats.
Heres the line that cheats.
foe = FindObject(ME,FA_ENEMY,FT_DEFAULT,FC_BEST_TARGET,FF_WHO_SHOT + FF_SEEPLAYER + FF_LOOK_EVERYWHERE,searchrange);
Heres the line that does not cheat.
foe = FindObject(ME,FA_ENEMY,flags,FC_BEST_TARGET,FF_WHO_SHOT + FF_SEEPLAYER,searchrange);
Search range is just the attackrange I mentioned earlier.
Notice the FF_LOOK_EVERYWHERE from the clip taking from the bot_findobject function. Now you know the other reason bots know where you are and know the normal FindEnemy function does not cheat can easily be added in the bot script, heres how.
| state WaitToAmbushState; code if (Bot_FindEnemy(attackrange)) then trans AttackState; endif; OrderMoveLookOut; |
Changed the code to this Or reverse this tip if you want the bot to cheat because it is for team battle or something.
| state WaitToAmbushState; code if (FindEnemy(attackrange)) then trans AttackState; endif; OrderMoveLookOut; |
Easy ay.
Sometimes you may want to make some changes to the findenemy routines like the change that stops incoming shots confusing the hell out of the bots.
Eg this line.
foe = FindObject(ME,FA_ENEMY,FT_DEFAULT,FC_BEST_TARGET,FF_WHO_SHOT + FF_SEEPLAYER + FF_LOOK_EVERYWHERE,searchrange);
Notice the FF_WHO_SHOT + part. Sometimes its wise to remove that part. If you do and your not allowed to edit the miscfuncs.abl then your going to wonder how the hell your supposed to make the change. Well its easy.
Heres the uberbot function Init; entry.
| function Init; code // script-specific variables attackRange = 9999; withdrawRange = 9999; // driver settings EnablePerWeaponRayCasting (ME,TRUE); endfunction; |
Right below endfunction cut and past the miscfuncs.abl function you want to edit. Like so.
| function Bot_FindEnemy(integer searchrange) : boolean; var integer foe; code foe = FindObject(ME,FA_ENEMY,FT_DEFAULT,FC_BEST_TARGET,FF_WHO_SHOT + FF_SEEPLAYER + FF_LOOK_EVERYWHERE,searchrange); if (foe <> no_unit) then SetTarget (me,foe); return (true); endif; return (false); |
Right below that should be the start state. Now just edit the first line above which says....
function Bot_FindEnemy(integer searchrange) : boolean;
To something like.
function MyBot_FindEnemy(integer searchrange) : boolean;
Then change the code you wanted to change in that function. Finally go to the state below.
| state WaitToAmbushState; code if (Bot_FindEnemy(attackrange)) then trans AttackState; endif; OrderMoveLookOut; |
Change the "if (Bot_FindEnemy(attackrange)) then" line to "if (MyBot_FindEnemy(attackrange)) then".
Now the bots using your own findenemy function.
You may notice a trans line under that line, that means if it finds a target it goes to the attack state. If it does not it executes the command "OrderMoveLookOut;" which basically tells it to look left and right and do nothing else until a target appears. This is the command that is used if your attackrange is set to a realistic radar range but nothing is actually in range. The bot stops, looks and left and right all the time. Nothing else.
Lets look at the attack state now.
Once in the attack state the line "if (LeaveAttackState(withdrawRange)) then" only runs if it loses its target. So the command being excuted most of the time is "OrderAttackTactic(TACTIC_FAST_CIRCLE,TRUE);"
| state AttackState; code if (LeaveAttackState(withdrawRange)) then trans WaitToAmbushState; endif; OrderAttackTactic(TACTIC_FAST_CIRCLE,TRUE); |
The LeaveAttackState is another function found in the miscfuncs.abl file. It looks like this.
| function LeaveAttackState(integer withdrawrange) : boolean; var integer target; code target = gettarget(me); //1. I somehow got here without a legitimate target
|
What that function actually does is this, in order of what the bot actually checks for.
If I have no target return "no target". = goes back to the state
WaitToAmbushState;
If my target is dead, return "no target". = goes back to the state
WaitToAmbushState;
If my target is beyond my withdraw range, return "no target". = goes
back to the state WaitToAmbushState;
And finally at long last it actually checks if the last mech to shoot it is not it's current target with the line...
if (WhoShot(me) <> target) then = then goes back to the state WaitToAmbushState anyway;
Some good that was, what a total waste of time.
So the last thing a standard microsoft bot does is check to see if its being shot at when it loses its current target and then ignores the result.
The findenemy command (from the state WaitToAmbushState;) that uses the FF_WHO_SHOT setting results in a mech chosing a target that suits its "FA_ENEMY,FT_DEFAULT,FC_BEST_TARGET" settings then overriding that with FF_WHO_SHOT each time it gets shot. Trouble is, that order is not always running because of the way the AI Brain file for bots is laid out. So the bot has to be shot whilst scanning for a target to react.
End result of this is the findobject command sometimes gets confused leaving the mech constantly turning left and right when hit and becomes a sitting duck as it switches targets. This the behavour you often see when a bot is being shot at a lot and does not appear to do much shooting back. Now you know why that happens.
That problem exists on all microsoft bots.
Here is my solution.
Cut and paste this in to the attack state and the WaitToAmbushState to override the default behavour. Ignore the tactic line for now.
| if ((isshot(me)) == true) then shooter = Whoshot(me); SetTarget (me,shooter); endif; |
The attack state should look like this.
|
state AttackState;
if ((isshot(me)) == true) then OrderAttackTactic(TACTIC_FAST_CIRCLE,TRUE); |
The waittoabmush version looks like this, it has an extra trans command in it too notice.
|
state WaitToAmbushState; if ((isshot(me)) == true) then OrderMoveLookOut; |
Then change the lines below found at the top of the bot file to look like the second example below here.
| // UberBot: // Intended to display the maximum amount of challenge that the game can provide. //------------------------------------------------------------------
const //------------------------------------------------------------------ type //------------------------------------------------------------------ var |
Change too....
// UberBot: // Intended to display the maximum amount of challenge that the game can provide. //------------------------------------------------------------------
const //------------------------------------------------------------------ type //------------------------------------------------------------------ var |
Notice the last line has changed.
There is now no confusion, the bot is given a clear order to set its target to the shooter and that means it will attack the player who shot it. If somebody else shots it, it will attack them instead. So it will always defend it self.
I often use this next line to ensure the bots team mates help it out.
SetTargetDesirability(shooter, 1);
Just add it below SetTarget (me,shooter);.
End result, each shot attracts more friendly bots to aid the bot in fighting off its attacker. That is what I mean by being creative and using your imagination to make the bots better. No need for fancy team code, the bot commands do the work for you so easily if you look out for that stuff.
Time to deal with the last item on our list of important features.
OrderAttackTactic(TACTIC_FAST_CIRCLE,TRUE);
This governs what the mech will do. What ever you put in here will be used by the mech.
If you use TACTIC_FAST_CIRCLE then thats all that gets used. If you use TACTIC_PICK_BEST then the bot uses the mood system to choose its tactics.
A full list of tactics can be found in the Orders doc and the Mechstorm orders doc but here's the full list for you right now. I'll put the ones that work well in bold type and make the ones that quit out under certain conditions bold and italics. The latter type of commands are best used with TACTIC_PICK_BEST because the AI can then pick a new tactic.The others that are not in bold can cause problems and require an experienced bot creator test them first. Notice I said bot creator, not scripter. Bot are a little weird and you need to understand the mechanics to identify why a command is not working the way it should. Basically its like know how to strip down a car but not appricating why it pulls to the left because your not familar with how the car handles on the road.
|
Common Tactics. TACTIC_PICK_BEST = Tells the Combat AI to pick the best tactic.
This is the same as a generic OrderAttack(). TACTIC_STARE = Stand and stare evilly. Specialist Tactics. TACTIC_SHOOT_ONLY = Only shoot; don't try to move under any circumstances.
This is the ONLY tactic turrets can use. |
Coop fans will find they can use more commands but need to know exactly what each of these tactics do and need to assign them to the correct vehicle, aircraft or mech or they will face problems.
Theres a lot that can be done to make the bots behave more like a human player. I spent years messing around with bots and trying different things out. Learning what a command did, then learning how it actually worked in the game in practice. The two are not the same. Certain combinations of commands give vastly different results than those you would expect and a good knowledge of how different mech configurations actually work in practice is must know stuff. So you may find it helpful to take out the stock configs for a run once in a while so you know the problems the bot will face and can allow for it in your bot configs. But that is an advanced topic, normal bot creators will not bother with that stuff. They will make the bot, test it to make sure it works and be happy.
I am not that kind of bot creator though, I love all the AI stuff, its very interesting to me. So I like to try and improve things all the time. So to finish up I am going to post some bots files for you to look at in this doc and you can look over them at your leasure and see what ideas I have played with.
Map makers keen on writing their own bots who have mastered the information above will find these next examples extremely interesting.
Lancemate and leaderbot: Lancemate bot first.
| / Mechstorms Lancemate Bot by Giskard. // Requires you name a leader bot for the lance. // A dedicated leader bot script is provided in this archive. // // Instructions. // In the editor choose a bot as a lance leader and give it a totally original name. // Eg leader1, leader2, leader2, Bob, what ever. // Then find the line mechleader = eve_leader; in the function Init; right at the top of that function. // Change it to say mechleader = eve_youbotname; Where yourbotname is the name of your lance leader bot. // // Using more than one lance and leader. // Change the line "fsm lancemate : integer;" to "fsm lancemate2 : integer;", "fsm lancemate3 : integer;" // For each lance and leader combo you add to your missions or multiplayer maps. // Your not allowed to have 2 different scripts // with the same fsm name in mw4 so if you want 2 leaders, you need to edit the fsm for the second lancemate // script. // // Thats it. All done. // // Now assign this script to all lance mates of that leader bot. // You can give the leader bot the leader bot script that comes with this archive but you do not have too. // The lancemate script will work with any script you assign to the leader bot. // // Just remember, these lancemates have feelings and get a bit angry if somebody shoots their leader :) fsm lancemate : integer; const type var // Do not edit anything below this. // script-specific variables // driver settings // EnablePerWeaponRayCasting (ME,TRUE); state StartState; code endstate; state WaitToAmbushState; if (boss == 0) then //if (boss == 1) then OrderMoveLookOut;
endstate; state theykilledkenny; endstate; state lancematestate; OrderMoveToObject (mechleader, 600); if ((isshot(mechleader)) == true) then GetTarget(mechleader); trans lancemateattackstate; endstate; state lancemateattackstate;
endstate; state AttackState; // dam need to change my tactics OrderAttackTactic(TACTIC_PICK_BEST,TRUE); endstate; state AttackState2; if ((isshot(me)) == true) then // walking away to sniper range, then switching tactics if im still
being hit. OrderAttackTactic(TACTIC_BACK_UP_AND_FIRE,TRUE); endstate; state AttackState3; OrderAttackTactic(TACTIC_SNIPE,TRUE); endstate; state DeadState; endstate;
|
Now the leader bot that is used as a lancer leader and a good standalone bot.
| // Mechstorms Leader Bot by Giskard. // Requirements: None. // Purpose: Designed to work with the lancemate script so their leader behaves in an intelligent manner. // // Dont make kill this bot your self, get one of your mates to do it. Somebody with no scripting experience :) // Then sit back and watch what this bots lance mates do to him when he destroys their leader. // Good for laugh :) fsm leaderbot : integer;
var function Init; //mechlance = groupobjectid(3); // script-specific variables // driver settings // EnablePerWeaponRayCasting (ME,TRUE); endfunction; state StartState; code endstate;
OrderMoveLookOut; state AttackState; // dam need to change my tactics OrderAttackTactic(TACTIC_PICK_BEST,TRUE); endstate; state AttackState2; if ((isshot(me)) == true) then // walking away to sniper range, then switching tactics if im still
being hit. OrderAttackTactic(TACTIC_BACK_UP_AND_FIRE,TRUE); endstate; state AttackState3; OrderAttackTactic(TACTIC_SNIPE,TRUE); endstate; state DeadState; endstate;
|
Now for a slightly buggy Mechstorm bot. This bot is buggy because it allows the mechs to choose tactics based on the type of mech the bot is using and not all mechs suit the tactics Ive chosen.
| // Mechstorms own Super bot. // Its Smarter than your average bot :) // Features. // // Checks what mech its in and choses its tactics based on that. // Does not ignore you when you shoot it. // Any mech that shoots and hits it is increasingly seen as a threat. // Any mech that kills it becomes major threat. // Any mech with a threat level high enough will be targeted more often. // // How to use: just assign it to mech in the editor and stand back:) // // Currently configured to be Average at shooting. // Increase the Gunneryskill below to make it a better shot. fsm dsrp_MechstormBot : integer; const type var pilotskill = 999; // End of Editable Settings hits = 0; // driver settings EnablePerWeaponRayCasting (ME,TRUE); endfunction; function getmechsettactic; code switch (mymech) Case M_ArcticWolf: Case M_Argus: Case M_Atlas: Case M_BlackKnight: Case M_Catapult: Case M_CauldronBorn: Case M_Chimera: Case M_Cougar: Case M_Daishi: Case M_Madcat_MKII: Case M_Masakari: Case M_Mauler: Case M_Templar: Case NoMechID:
code endstate; state WaitToAmbushState;
if ((isshot(me)) == true) then OrderMoveLookOut; state AttackState; OrderAttackTactic(mytactic,TRUE); state DeadState; endstate;
|
Now for the current prototype bot I am working on. This one fixes the issues in all of the above bots and takes a brand new approach to bot scripting. I have not yet set up my normal bot skills in this one because I have been testing other features primarily. Basically its the uber bot using my own AI routines, since I personally do not rate the uber bots settings, i'll be changing them at some point before I actually release this bot.
This bot adds and removes mechs from its threat list on the fly, when more than 1 bot uses this script both bots will gang up against the biggest threats. The tactics they choose are based on the type of mech using the script but in this prototype I have stuck strictly to the safer tactics, the ones I know work well.
Anyway, let me introduce to you the X1 Prototype bot, a work in progress name for my latest monster for mercs :)
| fsm X1Bot : integer;
function Init; // script-specific variables
EnablePerWeaponRayCasting (ME,TRUE); endfunction; function X1Bot_FindEnemy(integer searchrange) : boolean; return (false); endfunction; function getmechsettactic; code switch (mymech) Case M_Argus: Case M_Atlas: Case M_BlackKnight: Case M_Catapult: Case M_CauldronBorn: Case M_Chimera: Case M_Cougar: Case M_Daishi: Case M_Madcat_MKII: Case M_Masakari: Case M_Mauler: Case M_Templar: Endswitch;
code endstate;
if (attackcheck == 0) then //if (attackcheck == 0) then if (attackcheck == 1) then // mytactic = TACTIC_SNIPE; if ((isshot(me)) == true) then If (isdead(shooter1)) then // Here we let the old AI moods system take over for a bit.
state DeadState; shooter1 = WhoDestroyed(me); endstate;
|