Modding Wishlist


Requests done by Neiv are in green
Requests done by iquare are in orange
Requests done by FaRTy1billion are in blue
Requests done by poiuy_qwert are in brown
Requests done by Veeq7 are in cyan


New Commands



worker_id, gas_id, power_id, supply_id, and creep_id
worker_id(unitId, flags), gas_id(unitID, flags) | power_id(unitID, flags) | creep_id(unitID, flags)
This would set the units used by the AI as gas, power, supply, and creep generating structures. `flags` would be 0 or `clear`, e.g. `gas_id(assimilator, clear)` to stop the AI from building/using default gas structures, or to dynamically clear them in the middle of the script for whatever niche reason.

guard_jump
guard_jump(player, operator, quantity, military, (PosX, PosY), flag, block)
Jumps to `block` if `player` does not command `operator` `quantity` guard positions of `military` at (region/location) `(PosX, PosY)`. `flag` would be Req for requested, Sat for satisfied, or 0 for no flag.

attack_priority
attack_priority(unitID, flag, priority)
Tells the AI to prioritize regions with `unitID` in or around them for targets when using `attack_prepare`. `unitID` can also be Group_Factories, Group_Buildings, Group_Men, or Any. `flag` can be Add or Remove. Ignored by `attack_to`.

attack_drop
attack_drop()
Tells the AI to use transports for the next attack. Cleared with `attack_clear`.

max_transports
max_transports(value)
Identical to `max_workers`, but for transports. Would overwrite the limit of 3 transports (or 5 with `check_transports`). Would also limit Zerg AI from using more than the specified value of overlords at any given time.

town_jump
town_jump(playerID, operator, townType, location, block)
Searches the specified location or region for a town of the specified type owned by the specified player, and jumps/calls if true.
  • operators: True, False, True_Wait, False_Wait, True_Call, False_Call
  • townTypes: town, areatown, specific ID, any


preference_jump
preference_jump(player, order, target, operator, quantity, block)
Compares order usage of player and jumps if true

  • order: combinable with `|`
  • target: unitId, Own, Ally, Enemy, Any, combinable with `|`


kill_town
kill_town(id)
Kills the specified town; if used on a main town, resets all AI flags and region states

pathing
pathing(player, operator, location, block)
Compares or writes pathing data at the specified regions and jumps if true.

  • player: 0-14, with 13 being current player and 14 being all players
  • operator: True, False, True_Jump, False_Jump, True_Call, False_Call
  • location: (PosX, PosY ~ R) or Loc.n, selects all pathfinder regions for reading/writing

When comparing, all regions must be pathable (true) or unpathable (false) to trigger a jump.
When writing, all selected regions will be considered pathable or unpathable for the specified player.

start_loc
start_loc(player, location)
Sets the selected player's start location (without assigning a resarea) to the selected region.

set_region
set_region(player, operator, region, state)
Sets the specified regions to the specified state for the specified player.

  • operator: Set, Remove
  • state: 0-9


wait_for
wait_for(operator, quantity, unitType, townId, flag)
Waits for the computer to own the specified quantity of units in the town the command is called.

  • flags:
    • build (done building/training)
    • buildstart (building/training in progress)
    • dead
    • request (not yet in progress)
  • townId: set by `set_id`, uses current town if `255`, global if `Any`


play_sound
play_sound(playerId, soundId, location, volume, flags)
Plays the specified sound for the specified player.

  • volume: 0-100
  • flags:
    • Mute - muted if the mute trigger is active
    • Reduce(volume) - reduced to volume by the mute trigger.


town_add
town_add(quantity, unitId, location, sourceTown, destTown)
Adds the specified number of units to the specified town, set by set_id; uses current town if `255`

sprite_color
sprite_color(spriteId, location, color, flag)
Sets the player color of the specified sprites.

  • color: integer based on tminimap.pcx, e.g. 0 is red, 15 is cyan; supports extended colors
  • flags:
    • setPlayer(Id) - affects all sprites owned by the specified player; cancelled with removePlayer(Id).
    • gameView - changes the game view color of the specified sprites.
    • minimap - changes the minimap color of the specified sprites.


button_name
button_name(playerId, stattxtId1, stattxtId2)
Sets the specified in-game string to the specified user-defined string.

  • stattxtId1: string ID in stat_txt.tbl to forward to Id2
  • stattxtId2: string ID to use instead of Id1


set_race
set_race(playerId, race, block)
Reads or writes race.

  • race: Terran, Zerg, Protoss, Independent, Neutral, Inactive, Human, UserSelect, Random.


player_name
player_name(playerId, operator, string, block)
Reads or writes the player names seen in the score screen.

mining_efficiency
mining_efficiency(playerId, operator, unitType, resourceType, quantity)
Modifies mining efficiency for the specified player's units.

  • operator: Set, Add, Subtract, Randomize.
  • resourceType: Ore, Gas, GasDepleted


unit_flags
unit_flags(playerId, unitId, flag)
Modifies flag data for the specified player's units.

  • flags:
    • temp (only affects units that exist at the time the command is called)
    • all other flags from idle_orders 'UnitFlags' and 'WithoutUnitFlags' fields.


create_unit_new
create_unit_new(playerId, unitId, quantity, location, flag)
Creates units.

  • flag: lifted, hallucination, invincible, cloaked, burrowed, ignorePlacement.


remove_unit
remove_unit(playerId, unitId, quantity, location, flag)
Removes units.

  • flag: same as create_unit, besides ignorePlacement.


max_builders
max_builders(unitId, quantity)
Restricts the AI to the specified number of builders at any given time. Also controls how many SCVs can repair at any given time.

tile_jump
tile_jump(operator, area, flag, jumpType, block)
Compares terrain status and jumps if true.

  • operator: True or False
  • area: (PosX, PosY)~R or Loc.n~R
  • flag: creep, power, walkable, unbuildable, heightLow, heightMed, heightHigh, ramp
  • jumpType: Jump, Call, Wait, combinable with `|`


define
define(playerId, operator, quantity, unitId, block)
Reads/writes %1playerId's define_max value of %4(unitId).

force
force(playerId, operator, quantity, block)
Reads/writes %1playerId's max_force value.

region_force
region_force(playerId, area, operator, quantity, block)
Reads/writes %1playerId's requested force in %2area.

build_request
build_request(playerId, townId, operator, quantity, unitId, priority, jumpType, block)
Reads/writes %1playerId's build request values of %5unitId and %6priority in %2townId, %7jumpType if true.

  • jumpType: Jump, Wait, Call, combinable with `|`


resource_write
resource_write(operator, quantity, resourceType, playerId, resourceContainer, area)
Write %2quantity %3resourceType to all %4resourceContainer owned by %5playerId in %6area.

  • operator: Set, Add, Subtract, Randomize
  • resourceType: ore, gas, any
  • resourceContainer: unitId of resource containers to modify, combinable with `|`
  • area: coordinates or Loc.n


enemy_force
enemy_force(defenderId, attackerId, regionState, operator, quantity, quantityType, jumpType, block)
Read %2attackerId's forces in %1defenderId's %3regionState regions, and %7jumpType if true.

  • quantityType: `unit` or `force`


player_combat
player_combat(playerId1, playerId2, area, operator, jumpType, block)
Checks for combat between %1playerId1 and %2playerId2 in %3area using %4operator, %5jumpType %6block if reading a true comparison

  • operator: True, False


request_control
request_control(playerId, townId, requestType, flag)
Allow %1playerId's %3requestTypes in %2townId to be satisfied by %4flag

  • requestType: build (includes player_need), train (includes train, queue, do_morph, wait_train), defend (includes defensebuild, defenseuse, and defense), attack (includes attack_add and attack_rand), and guard (includes guard and place_guard)
  • unitId: 65535 to ignore this field (all specified requestTypes will be modified)
  • flag: Global, Local


wait_startattack
If an attack is being prepared, wait until it commences.

id_jump
id_jump(operator, townId, block)
Check for a town with %2townId and %1operator to %3block if true. Read-only.

build_new
%1quantity %2unitId [%3flag] [%4priority]
Queues %1quantity of %2unitid [at %4priority] [comparing %3flags].

%3flags can be:

  • Resources(%AplayerId %Boperator %CresourceQuantity %DresourceType)
  • Tile(%AlayoutId [from new_layout] %Bflag [creep/power] %Cboolean [true/false|wait])
  • IfReq(%Aboolean [true/false|wait] [%BunitId]) | if %BunitId is present, check that unit's tech requirements instead of %2unitId's requirements
  • Own(%Aplayerid %Boperator %Cquantity %Dunitid [%EtownCheck] [local or global] [%Farea]) | compare %Aplayerid %Cquantity of %Dunitid using %Boperator, taking %EtownCheck and %Farea into account
  • Layout(%AlayoutId [from new_layout]) | can be combined with '|' to take multiple identifiers
  • IfLayout(%Aboolean [true/false|wait]) | check availability of layouts, checking for identifiers if they are present
  • IfNeeded | like player_need
  • Type(%Atype [request or queue])
  • Add | adds %1quantity to existing queues/requests, like add_build
  • Subtract | subtract %1quantity
  • Max(%Avalue) | maximum number of structures that can be added

ex. build_new 1 evolution_chamber 0 90
queue one evolution chamber at priority 90 (no flags)
ex. build_new 1 evolution_chamber Own(13 AtLeast|Wait 10 drone)|Own(13 AtLeast|Wait 2 hatchery)|IfReq(True|Wait)|Tile(ev1|ev2|ev3 Creep True|Wait)|Type(Request)
wait to request one evolution chamber until current player owns 10 drones, 2 hatcheries, and the evolution chamber's tech requirements, and has creep tiles in coordinates matching layouts ev1, ev2, or ev3
ex. build_new 3 evolution_chamber Tile(ev1|ev2|ev3 0 Creep True)|Layout(ev1|ev2|ev3)
queue three evolution chambers at coordinates matching layouts ev1, ev2, and ev3, if those declarations have creep tiles
ex. build_new 1 barracks Layout(rax1|rax2|rax3|rax4)|IfLayout(True|Wait)
wait to queue 1 barracks at coordinates matching rax1, rax2, rax3, or rax4 until one of those layouts is available

attack_jump:
%1playerid %2comparison %3quantity %4unitId [%5flags] [%6block]
%2comparison %3quantity of %4unitId owned by %1playerId in the current attack wave, comparing %5flags and targeting %6block

%5flags can be:

  • Supply | Reads %3quantity as a supply threshold instead of a unit quantity

ex.
attack_jump 13 AtLeast 30 Group_Men WaitFor(720)|Supply
wait for up to 720 frames or until current player has added at least 30 supply of men to the attack wave

upgrade_new
%1quantity %2upgradeId %3priority %4flags
request %1quantity of %2upgradeId at %3priority, considering %4flags

%4flags can be:

  • Resources(%AplayerId %Boperator %CresourceQuantity %DresourceType)
  • InProgress(%Aboolean [true/false|wait]) | checks if a level of this upgrade is already being upgraded
  • IfReq(%Aboolean [true/false|wait] [%BupgradeId]) | if %BupgradeId is present, check that upgrade's tech requirements instead of %2upgradeId's requirements
  • Own(%Aplayerid %Boperator %Cquantity %Dunitid [%EtownCheck] [local or global] [%Farea]) | compare %Aplayerid %Cquantity of %Dunitid using %Boperator, taking %EtownCheck and %Farea into account
  • Type(%Atype [request or queue])
  • Add | adds %1quantity to existing queues/requests
  • Subtract | subtract %1quantity
  • Max(%Avalue) | maximum number of upgrades that can be added

ex.
upgrade_new 1 t_infantry_armor 88 Add|Max(5)|InProgress(False|Wait)|Own(13 AtLeast|Wait 1 engineering_bay Global)|Type(Queue)
wait to queue 1 level of infantry armor at priority 88 until infantry armor is not being upgraded and current player owns at least one engineering bay, capping at level 5

damage_dealt comparison subcommand
%1playerId1 %2playerId2 %3operator %4quantity %5damageType [%6victimType] [%7area] [%8block] [%9player]
using %3operator, compare %1playerId1's %5damageType of %2playerId['s %6victimType] to %4quantity, taking into account %7area and targeting %9player's %8block if applicable

%4damageType can be:

  • Damage
  • Kills
  • Score

%6victimType can be:

  • Any (default)
  • unit(%AunitId) | can also be Group_Buildings, Group_Factories, Group_Men, or Any (but why would you do that?)

ex.
damage_dealt 14 13 AtLeast|Jump 10 Kills Group_Men 5 buildB 13
if foes have killed at least 10 current player men in location 5, jump to current player's buildB block

damage_dealt 3 7 AtLeast|Wait 500 Score Any 63 atkStart 13
wait to jump to current player's atkStart block until player 4 has scored at least 500 points from killing player 8 any unit

attack_reset
attack_reset
If there is an attack ongoing, cancel it and attack_add any surviving units to a new attack party.

target_random
target_random [%1targetPlayer]
If multiple players are provided (separated by ‘|`), randomly selects between valid players (i.e. player must be enemy, player must have units on the map, player must not be defeated). If left blank, targets a different player than the previous attack’s target (assuming another player exists on the map).

defend_prepare
defend_prepare [%1targetPlayer]
Automatically picks preparation and target regions for defending %1targetPlayer. If left blank, defends itself. If no enemies are present in %1targetPlayer's town regions, does nothing. Default timeout of 30 seconds, can be modified with attack_timeout.

income comparison subcommand
%1playerId %2operator %3quantity %4resourceType %5timeFrame [%6block] [%7playerId]
using %2operator, compares %1playerId's income of %4resourceType in %5timeFrame to %3quantity

%2operator can be:

  • AtLeast, AtMost, Exactly primary
  • MoreThan, LessThan, EqualTo alternative — used instead of primary and have the following arguments:
    • %AplayerId %Boffset [%CresourceType] [%DtimeFrame]
    • if %CresourceType and %DtimeFrame are left blank, values from the main command are inherited for the comparison
    • %Boffset is added to %AplayerId's income, similar to unit_check's offsets
  • Wait|Jump|Call|Multi secondary — appended to primary and alternative operators

%3quantity notes:

  • when using an alternative operator, %3quantity is interpreted as an offset for %1playerId's income

ex:
income 13 AtLeast|Wait 500 Ore 1440
wait until current player's mineral income is at least 500 in 1440 frames

income 13 LessThan(2 0)|Jump 0 Ore 2880 xExpand 13
if current player's mineral income in the previous 2880 frames is less than player 3's mineral income in the previous 2880 frames, jump to local block xExpand


Engine Updates



idle_orders:
  • add medic heal
  • add flag that detects when units have been added to attack group
  • allow users to specify %hp required for `Deathrattle` orders to be issued
  • add `State` flag for special unit states (`Cloaked|NotCloaked|Sieged|Burrowed|Disabled` etc)
  • add `Targeted` flag for units that are targeting the tgt_unit_id
  • add `NotSelf` to flags (issue_order/idle_orders)
  • add `NearUnit` to flags, accepting specific units and OtherUnit (issue_order/idle_orders)
  • add `Owner` flag for units owned by the specified player IDs (combinable with `|`)
  • add `TileHeight` flag for tile height comparisons (0-2 for default values)

issue_order:

  • add ‘Queue` flag that adds it to the units’ queued orders


aicontrol:

  • `vulture_mines_off` and `vulture_mines_on` for toggling default vulture mine placement
  • `ignore_invincibile` for ignoring regions with only invincible enemy units
  • `no_building_base_layout` to prevent the AI from building structures in base_layout locations


base_layout:

  • add `Set_Random` and `Remove_Random` operators for random selection of locations of even priority.


idle_tactics:

  • ‘drop_priority([healthType]([operator] quantity))` to override default transport panic behaviors
    • drop_priority(hp(LessThanPercent 30))
  • `cloak_energy(operator quantity)` to set the minimum amount of energy required for units to cloak
    • cloak_energy(GreaterThan 50)
  • `cloak_range(unitType pixels)` to make valid units cloak when they are within range of enemy units
    • cloak_range(Group_Men|missile_turret|photon_cannon|spore_colony 1280)
  • `safe_nuke(operator unitQuantity pixels) to prevent AI from nuking when %1operator %2unitQuantity are %3pixels from the nuke site
    • safe_nuke(AtLeast 6 720)
  • `exit_range(unitQuantity weaponId range)` to make up to %1unitQuantity units move %3range (pixels) away from the weapon impact site of %2weaponId
    • exit_range(6 disruption_web 160)
  • `priority_target(attackerId targetId range flag)` to make %1attackerId focus %2targetId within %3range (pixels) of attacker as long as %4flags are true.
    • %4flags: CanWin - if %1attackerId can kill the unit that’s attacking it, change focus temporarily
    • priority_target(firebat|vulture|wraith drone|probe|scv 160 CanWin
  • `position(%1positionerId %2targetId %3range %4priority %5flag)` to make %1positionerId stay within %3range of %2targetId as long as %4flags are true
    • %4priority: competes only with other position idle_tactics declarations
    • %5flags: Self(Hp|Life|Shields|Energy|Incombat|Status|UnitFlags), Target(Hp|Life|Shields|Energy|InCombat|Status|UnitFlags)
    • position(firebat siege_tank|t_siege_mode 12 Target(InCombat)


remove_[request]:
remove_tech(tech, townID)
remove_upgrade(level, upgrade, townID)
remove_train(count, unit, townID)
Currently only supports building request removals.

town_state

  • `worker` to toggle whether workers are assigned to the town
  • `mining` to toggle whether assigned workers are allowed to harvest resources
  • `independent` to toggle whether requests can be satisfied from other towns
    • should have %4flags Military, Worker, Building, Upgrade, Tech to specify which requests are controlled


config:

  • starting_unit_deploy %1boolean - True or False, enables deploy animations for units
  • deploy_anim %1unitId %2iscriptAnimation %3animationSpeed - if starting_unit_deploy is True, preplaced %1unitIds will play %2iscriptAnimation at %3animationSpeed on map start (not on save/load)
  • resource_regen %1unitId %2rate %3flags - sets %1unitId's regeneration rate to %2rate if %3flags are true;
    • harvest(%Aboolean) - if true, %2rate only takes effect when %1unitId is being harvested
    • resources(%Aoperator %Bquantity) - %2rate only takes into effect when %1unitId has %Aoperator %Bquantity resources left


other AI problems:
Various issues with AI, solutions to which have not been explored (yet).

Base management:

  • If AI run out of money when trying to place a structure, the would-be builder returns to mine. They should stay at the build site until sufficient money is gathered, with a common sense timeout of 5-10 seconds telling them to return to mining duties if no structure is built. Such a timeout could also be controlled through an aiscript command.
  • AI workers should also be sent to build structures before the resource totals are added up. This would reduce floated resources and increase the efficiency of the AI's build orders.

Defense:

  • AI often fail to defend adequately, sending one or two units per cycle to their deaths instead of conducting a more organized defense. The AI should organize defense parties in similar fashion to how they organize attack parties, with the defense party being slightly more powerful than the attackers.
  • But some cases call for more desperate defense, like early game worker massacres or a town hall being close to death, and the AI should throw everything nearby in such cases.
  • An even more niche bit of decision making should be deciding when the AI should base trade and when it should recall its attacking forces.

Early Game Attacks:

  • AI cannot handle having a worker attack their buildings, which is especially debilitating in the early game. An obvious fix would be having 1.5 workers requested for defense for every attacking worker.
  • AI also cannot handle early attacks very well, due to their complete lack of micro. Kiting would help this, but ultimately AI need to become capable of worker drilling and generally using workers to attack (both in early game defense and early game rushes of their own).
  • Terran AIs should be able to use more than one SCV to repair the same structure, commensurate to the amount of nearby damage potential - for example, 1 SCV per nearby Dragoon. SCVs should also remain on repair duty until enemy units have departed, with another common sense timeout sending extra workers back to mining duties if no damage has been inflicted across 15-20 seconds. Such a timeout could also be controlled through an aiscript command.

Production:

  • AI will often append a unit's training to a busy factory instead of an idle one, spending about two seconds before cancelling it from the busy factory and requesting it at the idle one. This time wasting reduces efficiency needlessly. The AI should loop through all production structures, prioritizing idle ones for trainings/queuings.
  • AI never check for structures with available addon space before issuing liftoff orders. The AI should loop through all available structures that can build the requested addon, prioritizing idle lifted structures, then landed structures with available space, then landed structures without available space.

Attacking:

  • AI are incapable of cancelling attacks once the bulk of their forces are defeated or a larger force is scouted.
  • AI attackers often abandon the attack when more town regions are created from expansions and extra structures. Attacking units should be their own kind of military class to resolve this issue.

Spellcasters:

  • Medics: AI has no sanity or safety checks associated with ordering Medics to heal wounded infantry. AI also often ignores allied organics in favor of their own, when in reality it should be based on force value or resource cost or some other merit. Medics are also often frontlining in attacks and suicide after all combat units are lost instead of retreating.
  • Defilers: AI seem to follow hardcoded instructions to burrow Defilers near their spell targets, which is among the most dangerous places for expensive spellcasters. In general, vital and expensive caster units should be guarded by other units, and should retreat to the backline after casting spells.

Misc Requests



misc
method to change units.dat, weapons.dat flingy.dat, sprites.dat, images.dat values based on player ID

multiple attacks:
Being able to manage multiple attacks from the same AI player would allow for significantly more versatility when constructing AI scripts in large-scale environments.

improved attack logic:
  • Units used in AI attacks should automatically acquire targets while en route to their destination. Right now, they move to attack a certain target, instead of attack-moving to that target. Would be good to have them attack-move to the prepare region as well.
  • Additionally, ‘attack_prepare` chooses suboptimal targets a lot of the time. Though it’s possible to use randomized attack patterns with ‘attack_to`, making `attack_prepare` choose from a list of X nearest enemy-owned regions would be ideal for when users just want the AI to pick its own targets dynamically without accounting for every possible player action through script jumps and calls.
  • The ideal general-purpose attack logic would prioritize military/defense in a region, followed by production and then everything else.
  • Also: if AI could ignore regions with invulnerable units/buildings in them when choosing attack targets, that’d be great (maybe as a header command, like `ignore_invuln`).


repair:
Terran AI that owns zerg/protoss units occasionally attempts to repair them.

morphing:

  • The prerequisite unit of morphed guards (both archons, mutalisk morphs, lurkers) tend to travel some distance from their assigned guard position before morphing, and then remain where they are after they complete the morph instead of moving to their assigned guard position.
  • Excess prerequisites occasionally move to the morphing site. This behavior also happens with drones morphing to buildings and can needlessly slow down the AI while also looking pretty dumb. Excess prerequisites for morphed units (i.e. not drones) will idle near the morphing site until used for something. This may be a separate issue from the first one.
  • Morphed units do not currently accept define_max values and as a result are less stringently controlled script-side. Fixing this would obviously let modders use appropriate values of morphed units instead of praying that the AI doesn't do something dumb. This can be worked around with intelligent uses of `train` since the aise changes to that command.

carrier/reaver guards
Carrier and reaver guards idle near their factory instead of moving to their guard spots.

units with subunits
Carriers and reavers owned by the AI occasionally "forget" to idly train their subunits.

creep/power placement ignored on loss
XKo0S6p.png
When rebuilding lost creep structures, zerg AI tend to ignore the `creep` command (e.g. `creep(4)`) and thus rebuild everything in the same spot instead of achieving creep spread.
The same is true for protoss AIs who will seek to rebuild everything wherever they can fit it, leading to really cluttered bases after some structures have been lost. This may be a separate issue entirely.

request limits
defense(build/use) - 20 per type
train - unknown? Assumed 64
build - 30? per town?
attack_add - 64

other limits
towns - 100
military - 1000
units - 1700
sprites - 500 without parent flingy, 500 for fog of war sprites, 2500 total

the stuck worker bug
If towns far apart from one another call for workers from each other, workers will often get stuck, hanging the thread that requested the worker.

Completed Requests