Spoon bots
Re: Spoon bots
Well... It's certainly possible to script movement randomly, or even somewhat intelligently, but to make them automatically plot routes on every map without getting stuck is a bit tricky.
That's why I suggested tracing the routes players take. Bot's could spawn where players spawn, and trace the routes a player previously took from that spawn point.
Imagine spawn rushing the enemy base, snagging the flag, bouncing off the boundary and flying back for a quick capture, then a bot spawns exactly where you did and launches across the map, capping the flag just like you did...
Maybe they'll even walk up to inventory stations and buy the same load-out you did.
As for teamwork bots, that's a bit more difficult. You see, the ones launching mortars are specifically looking for that one player's targeting laser. So, maybe we code targeting laser on mount to pair with any friendly bots in range...
When it comes to healing assets, I think you might as well turn base healing on rather than worrying about programming bots to do that. It's already an admin/vote option in the tab menu, I think.
And lastly, by the time you've perfected the AI code so bots never get stuck and behave like regular players on every map, someone's gonna make a new map that is incompatible, with like teleports or something that the bots cannot find. If you're gonna be testing the code on every map, you might as well draw up some paths on those maps and re-save the mission.
One thing I'd like to do, is instead of duplicating every map, one with bots and keeping the original without, just add bots to each and every map, but have an admin/vote option to prevent them from spawning.
Likewise, there's no reason to have maps categorized by mission objectives. Every map should have all of the elements required for each mission objective, but voting to change the objectives could hide/show flags, increase/decrease point values for destroying things, etc...
Personally, I'd categorize maps by planet... In other words, every map built on the lush broadsides/blastsides terrain would be in one category, all of the variants of roller coaster in another, etc... Then you could pick a terrain you like to ski on and cycle through all the different base configurations mappers have thought up, while voting to toggle objectives and bots to mix things up...
Woah, I went off on a tangent there.
That's why I suggested tracing the routes players take. Bot's could spawn where players spawn, and trace the routes a player previously took from that spawn point.
Imagine spawn rushing the enemy base, snagging the flag, bouncing off the boundary and flying back for a quick capture, then a bot spawns exactly where you did and launches across the map, capping the flag just like you did...
Maybe they'll even walk up to inventory stations and buy the same load-out you did.
As for teamwork bots, that's a bit more difficult. You see, the ones launching mortars are specifically looking for that one player's targeting laser. So, maybe we code targeting laser on mount to pair with any friendly bots in range...
When it comes to healing assets, I think you might as well turn base healing on rather than worrying about programming bots to do that. It's already an admin/vote option in the tab menu, I think.
And lastly, by the time you've perfected the AI code so bots never get stuck and behave like regular players on every map, someone's gonna make a new map that is incompatible, with like teleports or something that the bots cannot find. If you're gonna be testing the code on every map, you might as well draw up some paths on those maps and re-save the mission.
One thing I'd like to do, is instead of duplicating every map, one with bots and keeping the original without, just add bots to each and every map, but have an admin/vote option to prevent them from spawning.
Likewise, there's no reason to have maps categorized by mission objectives. Every map should have all of the elements required for each mission objective, but voting to change the objectives could hide/show flags, increase/decrease point values for destroying things, etc...
Personally, I'd categorize maps by planet... In other words, every map built on the lush broadsides/blastsides terrain would be in one category, all of the variants of roller coaster in another, etc... Then you could pick a terrain you like to ski on and cycle through all the different base configurations mappers have thought up, while voting to toggle objectives and bots to mix things up...
Woah, I went off on a tangent there.
Re: Spoon bots
I feel like providing an example of clean code versus self described dirty code.
The following 2 functions are nearly identical in process.
I believe that garbage was written by Werewolf.
Here's what the same function looks like after I clean it up.
The following 2 functions are nearly identical in process.
Code: Select all
function AI::ProcessAutoSpawn() // A *VERY* dirty way to process the spoonbot.cs file... I know ;-)
{
if (($Spoonbot::AutoSpawn) && (!$Spoonbot::BotTree_Design)) // Not more bots in design mode.
{
if ($Spoonbot::Bot1Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot1Name @ ", " @ $Spoonbot::Bot1Team @ ", 0);",1);
if ($Spoonbot::Bot2Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot2Name @ ", " @ $Spoonbot::Bot2Team @ ", 0);",4);
if ($Spoonbot::Bot3Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot3Name @ ", " @ $Spoonbot::Bot3Team @ ", 0);",7);
if ($Spoonbot::Bot4Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot4Name @ ", " @ $Spoonbot::Bot4Team @ ", 0);",10);
if ($Spoonbot::Bot5Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot5Name @ ", " @ $Spoonbot::Bot5Team @ ", 0);",13);
if ($Spoonbot::Bot6Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot6Name @ ", " @ $Spoonbot::Bot6Team @ ", 0);",16);
if ($Spoonbot::Bot7Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot7Name @ ", " @ $Spoonbot::Bot7Team @ ", 0);",20);
if ($Spoonbot::Bot8Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot8Name @ ", " @ $Spoonbot::Bot8Team @ ", 0);",24);
if ($Spoonbot::Bot9Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot9Name @ ", " @ $Spoonbot::Bot9Team @ ", 0);",28);
if ($Spoonbot::Bot10Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot10Name @ ", " @ $Spoonbot::Bot10Team @ ", 0);",32);
if ($Spoonbot::Bot11Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot11Name @ ", " @ $Spoonbot::Bot11Team @ ", 0);",36);
if ($Spoonbot::Bot12Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot12Name @ ", " @ $Spoonbot::Bot12Team @ ", 0);",40);
if ($Spoonbot::Bot13Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot13Name @ ", " @ $Spoonbot::Bot13Team @ ", 0);",44);
if ($Spoonbot::Bot14Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot14Name @ ", " @ $Spoonbot::Bot14Team @ ", 0);",48);
if ($Spoonbot::Bot15Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot15Name @ ", " @ $Spoonbot::Bot15Team @ ", 0);",52);
if ($Spoonbot::Bot16Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot16Name @ ", " @ $Spoonbot::Bot16Team @ ", 0);",56);
if ($Spoonbot::Bot17Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot17Name @ ", " @ $Spoonbot::Bot17Team @ ", 0);",60);
if ($Spoonbot::Bot18Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot18Name @ ", " @ $Spoonbot::Bot18Team @ ", 0);",64);
if ($Spoonbot::Bot19Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot19Name @ ", " @ $Spoonbot::Bot19Team @ ", 0);",68);
if ($Spoonbot::Bot20Name != "0")
schedule("AI::spawnAdditionalBot(" @ $Spoonbot::Bot20Name @ ", " @ $Spoonbot::Bot20Team @ ", 0);",72);
// AI::spawnAdditionalBot($Spoonbot::Bot2Name, $Spoonbot::Bot2Team, 0);
}
}
Here's what the same function looks like after I clean it up.
Code: Select all
function AI::ProcessAutoSpawn() // A *VERY* clean way to process the spoonbot.cs file... -perrinoia
{
while(%i++ <= 20 && $Spoonbot::AutoSpawn && !$Spoonbot::BotTree_Design) // Not more bots in design mode.
schedule(sprintf("if(%1 != "0") AI::spawnAdditionalBot(%1, %2, 0);", $Spoonbot::Bot[%i @ Name], $Spoonbot::Bot[%i @ Team]), %i * 3);
}
Re: Spoon bots
I guess running around and creating the paths manually is more reliable. And one Broadside tree file can be used for almost every Broadside remake so there's that. I do want to have the spoonbot menu available for more maps eventually, but the intention of making the bots a map type was so eventually anybody can hop on and fight bots in ctf or duel them in arena without needing to be an admin. Gotta think of the little people and randoms who just want to hop on and test out the mod. Probably funner to try to learn than in a real match, we should've had this years ago.
One of the bots is already running around and healing team assets and it works pretty good. I think having a bot that guards the base and heals things is pretty useful and the one that plays heavy on the flag is nice to have even if you just need someone to hold the flag for you. Also if we add the deployables to the attack list for the offensive bots they should only attack them assuming no enemy player is in range.
You're right that code is much sexier. I just started learning how to write some of those things too from this pdf so I will actually know what I am looking at now
One of the bots is already running around and healing team assets and it works pretty good. I think having a bot that guards the base and heals things is pretty useful and the one that plays heavy on the flag is nice to have even if you just need someone to hold the flag for you. Also if we add the deployables to the attack list for the offensive bots they should only attack them assuming no enemy player is in range.
You're right that code is much sexier. I just started learning how to write some of those things too from this pdf so I will actually know what I am looking at now
![Rolling Eyes :roll:](./images/smilies/icon_rolleyes.gif)
Having a guard bot that you could spawn which would follow your path would be pretty sweet I have to admit. And if they get knocked off that path by something they need to teleport back on so it doesn't just take one deviation to screw them up. There's already this:
function TrackPath(%player)
{
%box = GetBoxCenter(%player);
%vel = Item::getVelocity(%player);
%obj = NewObject("Tracker",StaticShape,TrackerTracer,true);
AddToSet("MissionCleanup\\Extras",%obj);
GameBase::setPosition(%obj,Vector::add(%box,"0 0 6"));
if(%vel != "0 0 0")
{
GameBase::setRotation(%obj,Vector::getVelRotation(%vel));
}
else
{
GameBase::setRotation(%obj,GameBase::getRotation(%Player));
}
Schedule("GameBase::startFadeOut("@ %Obj @");", 18, %obj);
Schedule("deleteObject("@ %Obj @");", 20.5, %obj);
Schedule("TrackPath("@ %Player @");", 0.2, %player);
}
Re: Spoon bots
That PDF was extremely helpful to me when I was learning.
If you have any questions, feel free to ask me...
Unfortunately you can't ask the original author anymore, as she past away of a brain tumor, I believe.
As for the tracer thing... That's the right idea, but I believe that particular code is meant for flame trails and the like.
Simple fix, change the tracer object to a marker and don't delete it after a few seconds.
Also, in case you're wondering, the purpose of delaying the bot spawns instead of making them all spawn at once is to reduce lag at mission start.
If you have any questions, feel free to ask me...
Unfortunately you can't ask the original author anymore, as she past away of a brain tumor, I believe.
As for the tracer thing... That's the right idea, but I believe that particular code is meant for flame trails and the like.
Simple fix, change the tracer object to a marker and don't delete it after a few seconds.
Also, in case you're wondering, the purpose of delaying the bot spawns instead of making them all spawn at once is to reduce lag at mission start.
Re: Spoon bots
Hey, I've been sick for the past week with a combo gut punch of e-coli, dehydration, kidney stone, and possibly the flu. Feeling better now. Threw out my old bedding and bought all new pillows and sheets. Took another look at the spoonbots and here's what I've found:
function AI::jet() and function AI::jump() both do something stupid.
They use GameBase::testPosition() to determine if the bot can move up before launching the player up.
When GameBase::testPosition() is called, it moves the object to the specified position, then reports whether or not the object's shapefile overlapped any other shapefiles on it's way.
GameBase::testPosition() does NOT automatically return the object to it's original position.
Both AI::jet() and AI::jump() teleport the bot upwards, then, IF it CAN move there, they teleport back to their original position and launch upwards at predetermined velocities.
However, if they do overlap other shapefiles on the way up, they remain up.
You could be fighting one in a base, and suddenly they might teleport through the ceiling.
Now the simplest solution would be to remove the test. After all, there's no better test than trial and error, right?
But the currently predetermined velocities are strong enough to bash the bot's heads in on the ceilings if they attempt to jump or fly indoors.
This is also why their movements are so spastic.
Instead, I suggest a much smoother approach. Smaller, more frequent tweaks, to their velocities...
Why are they jumping, anyway? Currently, the answer is lottery based. Every so many seconds the bots draw a random number and if it meats some criteria, they attempt to jump. That's dumb. They should have a better reason than that.
I suggest 3 reasons to jump.
The jet function should be recursively scheduled until getLOSInfo passes, although you might also want to simulate an energy limit and actually drain it's energy each time, too. It should be scheduled frequently and add just a bit of upward momentum to the bot so it's a smooth flight rather than a random crazy Ivan in mid air.
Now back to the jump function, we need a little hop to get us going, and I don't think there's any testing needed to prevent collision damage or anything if we make it a small jump. Big enough to step on a jump pad or hop over a vehicle station. Not big enough to get out of the raindance base without jet assist.
Anywho, that's my pseudo code for tonight/this morning. I'm gonna try to get some sleep now.
function AI::jet() and function AI::jump() both do something stupid.
They use GameBase::testPosition() to determine if the bot can move up before launching the player up.
When GameBase::testPosition() is called, it moves the object to the specified position, then reports whether or not the object's shapefile overlapped any other shapefiles on it's way.
GameBase::testPosition() does NOT automatically return the object to it's original position.
Both AI::jet() and AI::jump() teleport the bot upwards, then, IF it CAN move there, they teleport back to their original position and launch upwards at predetermined velocities.
However, if they do overlap other shapefiles on the way up, they remain up.
You could be fighting one in a base, and suddenly they might teleport through the ceiling.
Now the simplest solution would be to remove the test. After all, there's no better test than trial and error, right?
But the currently predetermined velocities are strong enough to bash the bot's heads in on the ceilings if they attempt to jump or fly indoors.
This is also why their movements are so spastic.
Instead, I suggest a much smoother approach. Smaller, more frequent tweaks, to their velocities...
Why are they jumping, anyway? Currently, the answer is lottery based. Every so many seconds the bots draw a random number and if it meats some criteria, they attempt to jump. That's dumb. They should have a better reason than that.
I suggest 3 reasons to jump.
- bunny hopping in response to damage (might wanna throw in a local sound like "ouch" or "argh" when damage is received.
- Jump+jet when no line of sight to next waypoint.
- Jump over small obstacle when stuck on something but can see next waypoint.
- Bunny hop would be repeatedly scheduled via a loop from function Player::onDamage.
- jump on the other hand would be periodic, maybe once a minute, not terribly important.
- jet would be called by jump, and would call itself often until the bot can see it's target, has no energy, or is dead.
Code: Select all
deleteVariables("LOS::*");
%jet = !getLOSInfo(getBoxCenter(), GameBase::getPosition(%nextWaypoint), 1);
// $LOS::Object = obstacle that needs to be vaulted.
// $LOS::Position = exact coordinate where line of sight is interrupted by $LOS::Object
// $LOS::Normal = normalized vector indicating the rotation of the surface obstructing the bot's view to their next waypoint
Now back to the jump function, we need a little hop to get us going, and I don't think there's any testing needed to prevent collision damage or anything if we make it a small jump. Big enough to step on a jump pad or hop over a vehicle station. Not big enough to get out of the raindance base without jet assist.
Anywho, that's my pseudo code for tonight/this morning. I'm gonna try to get some sleep now.
Re: Spoon bots
Damn that sickness sounds brutal. I got it bad this year as well with the flu at first, but then the cough lingered for weeks and my throat would close up so badly I would wake up from not breathing. Gotta get that flu shot next year for sure.
That code explains a lot of their behavior. I feel like we should have them teleporting back on track assuming they haven't been able to get back by jumping and jetting after some period of time or maybe have them ctrl+k. Sometimes if you give them a flag on raindance they will stand under the flag base continually trying to jet up onto it, but hit their head and they never recover but just keep doing that. It's nice to have bots that people can't just pitchfork away someplace or lock in with a bunch of deployable platforms or something. These fuckers need to be resilient.
That code explains a lot of their behavior. I feel like we should have them teleporting back on track assuming they haven't been able to get back by jumping and jetting after some period of time or maybe have them ctrl+k. Sometimes if you give them a flag on raindance they will stand under the flag base continually trying to jet up onto it, but hit their head and they never recover but just keep doing that. It's nice to have bots that people can't just pitchfork away someplace or lock in with a bunch of deployable platforms or something. These fuckers need to be resilient.
Re: Spoon bots
Agreed. I need to learn what all this bot tree bullshit is... Just looks like arbitrary lists of numbers to me... Gonna hafta figure out what each number is used for.
Re: Spoon bots
Do any of you feel like the bot maps give you input lag? Just feels like my buttons are delayed or stuck at some points, though my ping or PL show no fluctuating. Perrin and I danced around each other in Titan like a bunch of noobs. Felt like we were both suffering from it. =/
DaRk{OZ}
[FAQ] - Frequently Asked Questions
[FAQ] - Frequently Asked Questions
Re: Spoon bots
I've noticed that too, and the zappy inventories are a little slow alsoDaRk wrote:Do any of you feel like the bot maps give you input lag? Just feels like my buttons are delayed or stuck at some points, though my ping or PL show no fluctuating. Perrin and I danced around each other in Titan like a bunch of noobs. Felt like we were both suffering from it. =/
Re: Spoon bots
Yeah, definitely a noticeable difference.
I also noticed a happy mod bot in the code, and see a few of them frequently shooting at the hills.
I also noticed a happy mod bot in the code, and see a few of them frequently shooting at the hills.