I have submitted Steamhammer 3.4.8 to AIST S4. Here is the change list, nice and long considering how long there was to work on it. The deadline isn’t for hours yet, so revealing my Dark Secrets early might theoretically come back to bite me, but... eh, it won’t bite hard. I’m still concealing my specific preparation for these opponents.
I tried for important advances that wouldn’t take long. I think I met my promise that Steamhammer will play a more “lucid” game, but let’s see how many fresh bugs I didn’t notice! The biggest improvements are pathfinding for ground units, smoothing of combat sim results, and more supple lurker behavior. My intention has always, ever since I started Steamhammer in December 2016, been to work on mutalisk micro before lurker micro, because it is more important. But I let it pass for too long, and now other bots have strong muta micro. I’ll get back to mutas (they are still more important), but I always want to do something different from everybody else, and now I want to work on lurkers first.
The irradiated squad is a nice improvement, too. Anyway, read on.
map analysis
• Reject starting bases (as identified by BWAPI::Broodwar->getStartLocations()
) which have no minerals; they are no longer considered bases, much less possible starting bases. I think these are always observer slots. The AIST S4 version of Aztec has observer slots. Formerly, Steamhammer accepted whatever BWAPI told it and created a Base
object for each one, marked as a starting base. The error had surprisingly little effect on play (Steamhammer is not tempted to expand to valueless “bases”), but it did cause sneaky mistakes. One is that a starting base is assigned a natural if conditions are met, with the result that the center bases on Aztec were considered naturals of some of the observer slots, and that information could be used for certain decisions, like where to make a hidden base. I’m glad I found this by looking at the maps, because the mistaken decisions might have been a nightmare to diagnose!
scouting
• The scout worker is released whenever friendly combat units are near. This is the final relaxation of the originally tight conditions for releasing the scout worker early, which I’ve been progressively relaxing.
• If the enemy has no known anti-air units, send an overlord to each base on the map to keep watch. Formerly, the rule was “if the enemy is not known to have tech to make anti-air units”, which was rarely satisfied outside the early game when there weren’t overlords available to distribute.
squads
• An irradiated squad centralizes the code for managing irradiated units and implements fancier behavior. Every irradiated organic unit (the ones harmed by the irradiate spell) goes into the squad, except for queens which have enough energy to cast and defilers after consume is researched—they will try to cast something before dying. Formerly, an irradiated unit that could burrow would, and that was the extent of the reaction (the successful reaction, anyway; mutas had code to separate out an irradiated muta, but it mysteriously broke). Now, an irradiated unit that is near friendly units will burrow if it can, or try to flee from its friends if it cannot. If it is near enemy units, it will approach to expose them to the radiation, and also attack if it can. If neither, it will run and do what scouting it can. Some of the behavior looks questionable, and I suspect bugs, but it’s good enough for now. The reaction of unirradiated units to nearby irradiated units is unchanged—only workers try to protect themselves, others carry on as usual.
• A newly-created squad did not pass along its order to its own micromanagers until it was updated. It was an oversight inherited from UAlbertaBot. The main effect is that a defense squad would not begin to act until exactly 8 frames after it was created, so defense was always a little bit late.
• The debug display for squads now shows two new pieces of information: A # symbol if the squad is using pathfinding, and the squad’s status string. The status string is sometimes unchanging, sometimes informative. For example, the Scourge squad has status Attack or Stand By, depending on whether enemy flyers are targetable.
• There was a minor bug in deciding which enemy unit last-seen location to visit next after all known enemy buildings are destroyed. The fix has little effect.
other ops and tactics
• Smooth attack/retreat combat sim decisions over time. I think this is the single most important change. Micro is less jittery and more decisive. I’m leaving out details for today; it’s worth a separate post.
• I found and fixed several more bugs related to spell units. The most important misbehavior was that Steamhammer treated an enemy comsat scan of a base as an attack that needed to be fended off. Every time terran scanned a base, a couple of mutalisks might peel off the flock and head there to defeat the scan. They never failed!
• I added time hysteresis to the defense squads, on top of their existing range hysteresis. After the enemies have been seen off, the squad waits out a time limit before it is disbanded. I was not convinced that the feature helps play, so I set the time limit to only 1 second.
• When a cluster of units is ordered to retreat, it may decide—depending on a simplified geometry calculation involving a risk radius—to “retreat forward” to join with friends. This helps a small cluster join up with a big cluster that is already in a fight. I decreased the risk radius, except in the case where the enemy is terran and has sieged tanks. It should help small clusters retreat forward more often.
• Earlier, I introduced a bug into FAP by adding an incorrect MAX_DISTANCE constant. I had forgotten that the distances are squared. Fixed.
micro
• Pathfinding for ground units for calls to the.micro.Move()
, the.micro.MoveNear()
, and the.micro.MoveSafely()
, (but not the.micro.AttackMove()
) at the option of the caller. I’ll post details tomorrow or so. It was easy to guess I would do this now, because Medusa is in the AIST S4 map pool, where Starcraft’s built-in pathfinder likes to pile up units at the blocked back doors of the bases.
• A unit trying to move safely (with the.micro.MoveSafely()
) does not try to avoid interceptors, only carriers. Trying to avoid swooping interceptors causes erratic movements, not escape movements.
zerg
• Lurker behavior is smarter. When I first implemented lurkers in Steamhammer 1.3 in 2017, I found that if they obeyed the combat sim like other squad units, they were nearly useless; they did not understand when to burrow, or where to burrow, or when to unburrow. The SparCraft combat simulator I had at the time did not support lurkers. Steamhammer could not tell when the enemy had detected them. So I gave lurkers spartan hyper-aggressive tactics: Always attack, burrow at max range versus a target that can shoot back and directly next to a target that cannot, and unburrow when no target is in range. I’ve made only minor refinements since, because it worked surprisingly well, especially against terran bots. But the crudeness shows, and hyper-aggressive is often hyper-stupid. A lone lurker would boldly attack a line of cannons. Steamhammer has lost a lot of lurkers for free.
Today Steamhammer is a capable squad commander, and it can judge pretty faithfully when a lurker remains undetected by the enemy and should remain safely burrowed despite (meaning because of) the large enemy force on hand. Lurkers in a defense squad remain hyper-aggressive, so that they do not hesitate to eliminate enemies from the zerg base. Other lurkers now advance or retreat together with the units in their cluster, with some exceptions for retreat (see below) so that lurkers don’t unburrow too often. Lurker play remains clumsy, but it is far more flexible than before, and better overall.
• A lurker that Steamhammer believes is undetected will not retreat as long as it is in range of a target. It will remain burrowed, or it will burrow then and there instead of retreating. I made this change in an earlier version, but it had no effect until now because lurkers did not retreat.
• Failing the above check, if a burrowed lurker is asked to retreat then there is one more check: Will it survive long enough to unburrow? It calculates an expected survival time in frames and compares it to the time to unburrow plus a safety margin. If it won’t live that long, it doesn’t bother unburrowing; maybe it can get a last shot in. I do the same calculation for sieged tanks, with the unsiege time, so that a tank beset by zealots still has a chance for a last shot at some distant dragoon.
• I fixed a bug in the hidden enemies check; it handles an invalid missing ui.unit
correctly. I don’t think it makes a practical difference with the existing codebase. The hidden enemies check prevents unburrowing when the lurker is undetected and, if it unburrows, at risk of dying to a cloaked unit, or a known unit out of sight on high ground. This check often (not always) prevents the cycle: Burrow on low ground just in range of a bunker up the ramp -> bunker stops shooting because the lurker is no longer visible -> the bunker is no longer visible to the lurker -> the lurker unburrows -> the bunker starts shooting again and becomes visible -> the lurker burrows....
• When possible, a lurker, guardian, or devourer will morph out of enemy view. When within enemy static defense range, it will not morph at all—at least theoretically; I’ve seen it happen so I think the check is not accurate. Lurkers should more often surprise the enemy, and cocoons should be shot down less often.
• An urgent sunken to stop vultures, or an urgent spore to stop wraiths or corsairs, is made quickly, rather than, oh, whenever the bot happens to get around to it, might be any minute now if we’re still alive then. The slowness was due to a bad design decision I made in reworking the code in the SSCAIT tournament version.
• Insert a fresh overlord after a spore colony, not before, when making supply and a spore is next in the queue, and similarly for the evolution chamber prerequisite. Formerly, when corsairs ravaged the overlords, Steamhammer gave priority to getting its supply back into the green. The corsairs had only to camp the zerg base for protoss to win.
• When scourge finds that its target is very close, it attacks even if the combat sim says to retreat. Scourge uses a combat simulation, excluding air units, to avoid ground fire. Often it would be on the verge of shooting down a corsair, but a dragoon was a little too close.... Steamhammer has missed a lot of kills that way.
• The defensive sunken versus cannons is tuned slightly.
openings
• There are no new or changed openings, only a change to how one opening is configured to be used. I saw the OverpoolTurtle
build, a bot exploit opening that is objectively horrible, played in one game against a human on SCHNAIL, and that was one time too many. I removed it from the matchup and counter configurations, so it should be played very rarely unless it is found to succeed, and almost never against a human.
configuration
• New flag for Crazyhammer. Setting Config::Strategy::Crazyhammer
to true causes Steamhammer to choose its openings purely at random from its large library, ignoring anything it may have learned. It’s used for Crazyhammer on SCHNAIL.
• New debug flag Debug::DrawLurkerTactics
draws the name of the current default lurker behavior, either “Aggressive” or “With squad”. It doesn’t convey any information at the moment, since whenever there are lurkers they are “With squad”. I plan for lurker behavior to become more varied and complex, and then the debug flag will be useful.
unused stuff
• The movement sim is included and potentially valuable, but unused. There is code in FAP and in CombatSimulation
.
• Fixed a primordial crashing bug in enemy unit clustering, making it also potentially valuable. But it’s turned off for now.
Next: Pathfinding.