Aus Starcraft II Map-Editor Wiki
//==================================================================================================
// Melee AI Functions
//--------------------------------------------------------------------------------------------------
// rough rating target:
// insane 2300
// very hard 2000
// hard 1700
// medium 1400
// easy 1100
// very easy 800
//==================================================================================================
const bool DEBUG = true;
const bool DEBUG_MAIN_STATE = false;
const bool DEBUG_ATTACK_STATE = false;
const bool DEBUG_WAVE = false;
const int e_flagsScouting = 1;
const int e_flagsDiversion = 2;
const int e_flagsTimeout = 3;
const int e_flagsRunScared = 4;
const int e_flagsDetect = 5;
const int e_flagsZergStock = 6;
const int e_flagsExpanded = 7;
const int e_flagsLateScout = 8;
const int e_flagsClearObs = 9;
const int e_flagsEarlyDefScout = 10;
// limit of 16 states in CCaptain
const int e_mainState = 1;
const int e_mainSubState = 2;
const int e_attackState = 3;
const int e_divert1State = 4;
const int e_divert2State = 5;
const int e_openRollState = 6;
const int e_middleRollState = 7;
const int e_lateRollState = 8;
// main states
const int e_mainState_Disabled = -1;
const int e_mainState_Off = 0;
const int e_mainState_Init = 1;
const int e_mainState_OpenGnd0 = 2;
const int e_mainState_OpenGnd1 = 3;
const int e_mainState_OpenGnd2 = 4;
const int e_mainState_OpenGnd3 = 5;
const int e_mainState_OpenGnd4 = 6;
const int e_mainState_OpenGnd5 = 7;
const int e_mainState_OpenAir0 = 8;
const int e_mainState_OpenAir1 = 9;
const int e_mainState_OpenAir2 = 10;
const int e_mainState_OpenAir3 = 11;
const int e_mainState_OpenAir4 = 12;
const int e_mainState_OpenAir5 = 13;
const int e_mainState_Mid0 = 14;
const int e_mainState_Mid1 = 15;
const int e_mainState_Mid2 = 16;
const int e_mainState_Mid3 = 17;
const int e_mainState_Mid4 = 18;
const int e_mainState_Mid5 = 19;
const int e_mainState_Late0 = 20;
const int e_mainState_Late1 = 21;
const int e_mainState_Late2 = 22;
const int e_mainState_Late3 = 23;
const int e_mainState_Late4 = 24;
const int e_mainState_Late5 = 25;
// main sub states
const int e_mainSubState_Unset = 1;
const int e_mainSubState_GndA = 2;
const int e_mainSubState_GndB = 3;
const int e_mainSubState_AirA = 4;
const int e_mainSubState_AirB = 5;
// attack states
const int e_attackState_Wait = 1;
const int e_attackState_Idle = 2;
const int e_attackState_Attack = 3;
const int e_attackState_DropAttack = 4;
const int e_attackState_Scared = 5;
const int e_attackState_Retreat = 6;
const int e_attackState_DropRetreat = 7;
const int e_attackState_InRetreat = 8;
const fixed c_evalDefendRange = 20;
const fixed c_evalRange = 10;
const fixed c_evalHarassRange = 8;
// drop attack variables
const fixed c_dropCheckRollFreq = 60.0;
const fixed c_dropCheckAttackFreq = 240.0;
const int c_dropAttackChance = 75;
//--------------------------------------------------------------------------------------------------
// DebugAI
//--------------------------------------------------------------------------------------------------
void DebugAI (string s) {
if (DEBUG) {
TriggerDebugOutput(1, StringToText(s), true);
}
}
//--------------------------------------------------------------------------------------------------
void DebugAIPlayer (int player, string s) {
if (DEBUG) {
TriggerDebugOutput(
1,
StringToText("[") +
PlayerColorName(PlayerGetColorIndex(player, false)) +
StringToText("] ") +
StringToText(s),
true
);
}
}
//--------------------------------------------------------------------------------------------------
void DebugAIPlayerWave (int player, string s) {
if (DEBUG_WAVE) {
DebugAIPlayer(player, s);
}
}
//--------------------------------------------------------------------------------------------------
void DebugVarInt (string s, int value) {
DebugAI(s + "= " + IntToString(value));
}
//--------------------------------------------------------------------------------------------------
void DebugVarString (string s, string value) {
DebugAI(s + "= " + value);
}
//--------------------------------------------------------------------------------------------------
void DebugVarInt2 (string s1, int value1, string s2, int value2) {
DebugAI(s1 + "= " + IntToString(value1) + ", " + s2 + "= " + IntToString(value2));
}
//--------------------------------------------------------------------------------------------------
void DebugVarInt3 (string s1, int value1, string s2, int value2, string s3, int value3) {
DebugAI(s1 + "= " + IntToString(value1) + ", "
+ s2 + "= " + IntToString(value2) + ", "
+ s3 + "= " + IntToString(value3)
);
}
//--------------------------------------------------------------------------------------------------
void DebugVarBool (string s, bool value) {
if (value) {
DebugAI(s + "= true");
}
else {
DebugAI(s + "= false");
}
}
//--------------------------------------------------------------------------------------------------
string AttackStateName (int state) {
if (state == e_attackState_Wait) { return "Wait"; }
if (state == e_attackState_Attack) { return "Attack"; }
if (state == e_attackState_DropAttack) { return "DropAttack"; }
if (state == e_attackState_Idle) { return "Idle"; }
if (state == e_attackState_Scared) { return "Scared"; }
if (state == e_attackState_Retreat) { return "Retreat"; }
if (state == e_attackState_DropRetreat) { return "DropRetreat"; }
if (state == e_attackState_InRetreat) { return "InRetreat"; }
return "?" + IntToString(state) + "?";
}
//--------------------------------------------------------------------------------------------------
string WaveStateName (int state) {
if (state == c_waveStateIdle) { return "Idle"; }
if (state == c_waveStateSuicide) { return "Suicide"; }
if (state == c_waveStateMerge) { return "Merge"; }
if (state == c_waveStateAttack) { return "Attack"; }
if (state == c_waveStateDefend) { return "Defend"; }
if (state == c_waveStateScout) { return "Scout"; }
if (state == c_waveStateRetreat) { return "Retreat"; }
if (state == c_waveStateClearObs) { return "ClearObs"; }
if (state == c_waveStateGuardHome) { return "Home"; }
return "?" + IntToString(state) + "?";
}
//--------------------------------------------------------------------------------------------------
void DebugWave (int player, string name, wave w) {
string threat;
if (AIDefenseThreat(c_dtAnyThreat, player, w)) {
threat = "true";
}
else {
threat = "false";
}
DebugAIPlayer(
player,
"wave=" + name +
", units=" + IntToString(AIWaveUnitCount(w)) +
", state=" + WaveStateName(AIWaveState(w)) +
", ratio=" + IntToString(AIWaveEvalRatio(w, c_evalRange)) +
", combat=" + IntToString(AIWaveGetTimeInCombat(w)) +
", safe=" + IntToString(AIWaveGetTimeSinceCombat(w)) +
", threat=" + threat
);
}
//--------------------------------------------------------------------------------------------------
void DebugMelee (int player) {
DebugWave(player, "main", AIWaveGet(player, c_waveMain));
DebugWave(player, "atck", AIWaveGet(player, c_waveAttack));
DebugWave(player, "dfnd", AIWaveGet(player, c_waveDefend));
DebugWave(player, "div1", AIWaveGet(player, c_waveDivert1));
DebugWave(player, "div2", AIWaveGet(player, c_waveDivert2));
DebugWave(player, "clob", AIWaveGet(player, c_waveClearObs));
DebugWave(player, "home", AIWaveGet(player, c_waveHome));
DebugVarInt2(
"peons cur", AIGetCurPeonCount(player, c_townMax),
"max", AIGetMaxPeonCount(player, c_townMax)
);
DebugVarBool("e_flagsScouting", AIGetFlag(player, e_flagsScouting));
DebugVarBool("e_flagsTimeout", AIGetFlag(player, e_flagsTimeout));
}
//--------------------------------------------------------------------------------------------------
bool DebugMeleeTrigger (bool c, bool a) {
if (a) {
DebugMelee(StringToInt(StringWord(EventChatMessage(false), 2)));
}
return true;
}
//--------------------------------------------------------------------------------------------------
bool g_debugMeleeInit = false;
void DebugMeleeInit () {
trigger t;
if (!g_debugMeleeInit) {
t = TriggerCreate("DebugMeleeTrigger");
TriggerAddEventChatMessage(t, 1, "waves", false);
g_debugMeleeInit = true;
}
}
//--------------------------------------------------------------------------------------------------
string MainStateName (int state) {
if (state == e_mainState_Init) { return "Init"; }
else if (state == e_mainState_OpenGnd0) { return "OpenGnd0"; }
else if (state == e_mainState_OpenGnd1) { return "OpenGnd1"; }
else if (state == e_mainState_OpenGnd2) { return "OpenGnd2"; }
else if (state == e_mainState_OpenGnd3) { return "OpenGnd3"; }
else if (state == e_mainState_OpenGnd4) { return "OpenGnd4"; }
else if (state == e_mainState_OpenGnd5) { return "OpenGnd5"; }
else if (state == e_mainState_OpenAir0) { return "OpenAir0"; }
else if (state == e_mainState_OpenAir1) { return "OpenAir1"; }
else if (state == e_mainState_OpenAir2) { return "OpenAir2"; }
else if (state == e_mainState_OpenAir3) { return "OpenAir3"; }
else if (state == e_mainState_OpenAir4) { return "OpenAir4"; }
else if (state == e_mainState_OpenAir5) { return "OpenAir5"; }
else if (state == e_mainState_Mid0) { return "Mid0"; }
else if (state == e_mainState_Mid1) { return "Mid1"; }
else if (state == e_mainState_Mid2) { return "Mid2"; }
else if (state == e_mainState_Mid3) { return "Mid3"; }
else if (state == e_mainState_Mid4) { return "Mid4"; }
else if (state == e_mainState_Mid5) { return "Mid5"; }
else if (state == e_mainState_Late0) { return "Late0"; }
else if (state == e_mainState_Late1) { return "Late1"; }
else if (state == e_mainState_Late2) { return "Late2"; }
else if (state == e_mainState_Late3) { return "Late3"; }
else if (state == e_mainState_Late4) { return "Late4"; }
else if (state == e_mainState_Late5) { return "Late5"; }
else if (state == e_mainState_Off) { return "Off"; }
return "?" + IntToString(state) + "?";
}
//--------------------------------------------------------------------------------------------------
// AISetAttackState
//--------------------------------------------------------------------------------------------------
void AISetAttackState (int player, int attackState) {
string msg;
int oldState = AIState(player, e_attackState);
AISetSpecificState(player, e_attackState, attackState);
if (DEBUG_ATTACK_STATE) {
msg = "Player " + IntToString(player) + "-" + PlayerRace(player) + " attack state " +
AttackStateName(oldState) + " -> " + AttackStateName(attackState);
DebugAI(msg);
}
}
//--------------------------------------------------------------------------------------------------
// AISetMainState
//--------------------------------------------------------------------------------------------------
void AISetMainState (int player, int mainState, int mainSubState) {
string msg;
int oldMainState = AIState(player, e_mainState);
int oldSubState = AIState(player, e_mainSubState);
AISetSpecificState(player, e_mainState, mainState);
AISetSpecificState(player, e_mainSubState, mainSubState);
if (DEBUG_MAIN_STATE) {
msg = "Player " + IntToString(player) + "-" + PlayerRace(player) + " main state " +
MainStateName(oldMainState) + "(" + IntToString(oldSubState) + ") --> " +
MainStateName(mainState) + "(" + IntToString(mainSubState) + ")";
DebugAI(msg);
}
}
//--------------------------------------------------------------------------------------------------
// EndMeleeScript
//--------------------------------------------------------------------------------------------------
void EndMeleeScript (int player) {
string msg = "Reached end of script for player " + IntToString(player) + "-" +
PlayerRace(player) + " : More AI code coming soon.";
UIDisplayMessage(PlayerGroupAll(), c_messageAreaSubtitle, StringToText(msg));
DebugAI(msg);
AISetMainState(player, e_mainState_Disabled, e_mainSubState_Unset);
}
//--------------------------------------------------------------------------------------------------
// ErrorMeleeScript
//--------------------------------------------------------------------------------------------------
void ErrorMeleeScript (int player, string error) {
string msg = "A script logic error occurred for player " + IntToString(player) +
"-" + PlayerRace(player) + " : " + error;
UIDisplayMessage(PlayerGroupAll(), c_messageAreaSubtitle, StringToText(msg));
DebugAI(msg);
AISetMainState(player, e_mainState_Disabled, e_mainSubState_Unset);
}
//--------------------------------------------------------------------------------------------------
// AISetGasPeons
//--------------------------------------------------------------------------------------------------
void AISetGasPeons (int player, int count, string type, string from) {
int sources = AITechCount(player, from, c_techCountCompleteOnly);
if (sources < 1
|| AIHasRes(player, 0, 200)
|| AITechCount(player, type, c_techCountCompleteOnly) < 8)
{
AISetGasPeonCountOverride(player, c_townMain, c_defaultGasPeonCount);
}
else if (sources == 1) {
AISetGasPeonCountOverride(player, c_townMain, 3);
}
else { // sources == 2+
AISetGasPeonCountOverride(player, c_townMain, count);
}
}
//--------------------------------------------------------------------------------------------------
// AISetStockAll
//--------------------------------------------------------------------------------------------------
void AISetStockAll (int player, string source, int max, string what) {
int make = AITechCount(player, what, c_techCountCompleteOnly)
+ 2 * AITechCount(player, source, c_techCountCompleteOnly);
if (make > max) {
make = max;
}
AISetStock(player, make, what);
}
//--------------------------------------------------------------------------------------------------
// AIMergeUnit
//--------------------------------------------------------------------------------------------------
void AIMergeUnit (int player, unit u, wave w) {
wave merge = AIWaveCreate(AIWaveInfoCreate(), player, AIGetGatherLocation(player, c_townMain));
AIWaveAddUnit(merge, u);
AIWaveSetType(merge, c_waveStateMerge, AIWaveTargetMerge(w));
}
//--------------------------------------------------------------------------------------------------
// AINewUnitDefault
//--------------------------------------------------------------------------------------------------
void AINewUnitDefault (int player, unit u) {
wave w = AIWaveGet(player, c_waveMain);
if (AIDefenseThreat(c_dtAnyThreat, player, w)) {
AIMergeUnit(player, u, w);
}
else {
AIWaveAddUnit(w, u);
}
}
//--------------------------------------------------------------------------------------------------
// AICreateOrder
//--------------------------------------------------------------------------------------------------
order AICreateOrder (int player, string abilLink, int abilIndex) {
abilcmd cmd = AbilityCommand(abilLink, abilIndex);
order ord;
if (cmd == c_nullCmd) {
return null;
}
ord = Order(cmd);
OrderSetPlayer(ord, player);
return ord;
}
//--------------------------------------------------------------------------------------------------
// AITacticalOrder
//--------------------------------------------------------------------------------------------------
order AITacticalOrder (int player, unit aiUnit, string abilLink) {
order ord = AICreateOrder(player, abilLink, 0);
if (!UnitOrderIsValid(aiUnit, ord)) {
return null;
}
return ord;
}
//--------------------------------------------------------------------------------------------------
// AITacticalOrderIndex
//--------------------------------------------------------------------------------------------------
order AITacticalOrderIndex (int player, unit aiUnit, string abilLink, int abilIndex) {
order ord = AICreateOrder(player, abilLink, abilIndex);
if (!UnitOrderIsValid(aiUnit, ord)) {
return null;
}
return ord;
}
//--------------------------------------------------------------------------------------------------
// AICombatPriority
//--------------------------------------------------------------------------------------------------
unit AICombatPriority (unit target, unitgroup attackers, unitgroup enemies) {
return AIDefaultCombatPriority(target, attackers, enemies);
}
//--------------------------------------------------------------------------------------------------
// AIDefendTown
//--------------------------------------------------------------------------------------------------
void AIDefendTown (int player, wave w) {
int eval = AIWaveEvalRatio(w, c_evalDefendRange);
int staticPercent = AILastWaveEvalStaticRatio();
int neededEval = 60;
if (staticPercent > 90) {
neededEval = 80;
}
else if (staticPercent > 40) {
neededEval = 70;
}
if (eval < neededEval) {
if (AIWaveState(w) != c_waveStateRetreat) {
DebugAIPlayerWave(player, "defend1 set wave = retreat to gather defense");
AIWaveSetType(w, c_waveStateRetreat, AIWaveTargetGatherD(player, c_townMax));
}
}
else if (AIWaveState(w) != c_waveStateDefend) {
if (eval > neededEval+10) {
if (AIWaveGetTimeSinceOrdered(w) >= 20) {
DebugAIPlayerWave(player, "defend2 set wave = defend vs. threats");
AIWaveSetType(w, c_waveStateDefend, AIWaveTargetMeleeDefend(player));
}
}
}
}
//--------------------------------------------------------------------------------------------------
// AIWaveDefend
//--------------------------------------------------------------------------------------------------
void AIWaveDefend (int player, wave w) {
if (AIDefenseThreat(c_dtAnyThreat, player, w)) {
AIDefendTown(player, w);
}
else if (AIWaveState(w) != c_waveStateIdle) {
DebugAIPlayerWave(player, "defend3 set defend = idle at gather defense");
AIWaveSetType(w, c_waveStateIdle, AIWaveTargetGatherD(player, c_townMax));
}
}
//--------------------------------------------------------------------------------------------------
// AIWaveMain
//--------------------------------------------------------------------------------------------------
void AIWaveMain (int player, wave w) {
unit obstruction = null;
int count = AIWaveUnitCount(w);
int state = AIWaveState(w);
int attackState = AIState(player, e_attackState);
if (AIWaveIsInCombat(w)) {
return;
}
if (AIDefenseThreat(c_dtAnyThreat, player, w)) {
AIDefendTown(player, w);
return;
}
if (count >= 3 && AIGetFlag(player, e_flagsTimeout)) {
if (attackState != e_attackState_DropAttack && attackState != e_attackState_DropRetreat) {
AIWaveMerge(player, c_waveMain, c_waveAttack);
return;
}
}
if (state != c_waveStateIdle) {
DebugAIPlayerWave(player, "main2 set main = idle at gather offense");
AIWaveSetType(w, c_waveStateIdle, AIWaveTargetGatherO(player, c_townMax));
}
}
//--------------------------------------------------------------------------------------------------
// AIWaveDivert
//--------------------------------------------------------------------------------------------------
void AIWaveDivert (int player, wave w, int stateIndex) {
int state;
int count;
if (AIDefenseThreat(c_dtAnyThreat, player, w)) {
AIDefendTown(player, w);
return;
}
state = AIWaveState(w);
if (state == c_waveStateDefend) {
DebugAIPlayerWave(player, "divert1 set divert = idle at gather defense");//xxx
AIWaveSetType(w, c_waveStateIdle, AIWaveTargetGatherD(player, c_townMax));
return;
}
if (!AIGetFlag(player, e_flagsDiversion)) {
return;
}
if (AIWaveEvalRatio(w, c_evalHarassRange) < 100) {
if (state != c_waveStateRetreat) {
DebugAIPlayerWave(player, "divert2 set divert = retreat to harass point");//xxx
AIWaveSetType(w, c_waveStateRetreat, AIWaveHarassRetreat(player, w, c_evalHarassRange));
}
}
else if (state != c_waveStateAttack) {
if (AIWaveGetTimeSinceOrdered(w) >= 10) {
DebugAIPlayerWave(player, "divert3 set divert = attack harass target");//xxx
AIWaveSetType(w, c_waveStateAttack, AIWaveTargetMeleeHarass(player));
}
}
}
//--------------------------------------------------------------------------------------------------
// AIWaveHome
//--------------------------------------------------------------------------------------------------
void AIWaveHome (int player, wave w) {
int state;
state = AIWaveState(w);
if (state != c_waveStateGuardHome) {
DebugAIPlayerWave(player, "home set divert = idle at gather defense");
AIWaveSetType(w, c_waveStateGuardHome, AIWaveTargetGatherD(player, c_townMax));
return;
}
}
//--------------------------------------------------------------------------------------------------
// AIWaveClearObs
//--------------------------------------------------------------------------------------------------
void AIWaveClearObs (int player, wave w) {
unit obstruction = AIGetObstruction(player);
unit oldTarget = null;
int obsLife;
int state = AIWaveState(w);
// If there are no longer any obstructions, merge back into the main wave
if (obstruction == null) {
DebugAIPlayerWave(player, "clearobs1 merge clear obstruction -> main");
AIWaveMerge(player, c_waveClearObs, c_waveMain);
return;
}
// Defend against threats, unless we're almost done destroying the obstruction
obsLife = UnitGetPropertyInt(obstruction, c_unitPropLifePercent, c_unitPropCurrent);
if (AIDefenseThreat(c_dtAnyThreat, player, w) && obsLife > 20) {
AIDefendTown(player, w);
return;
}
// Let's hunt some rock!
oldTarget = AIWaveTargetGetUnit(AIWaveGetTarget(w));
if (state != c_waveStateClearObs || obstruction != oldTarget) {
DebugAIPlayerWave(player, "clearobs2 set clear obstruction = clear obstruction");
AIWaveSetType(w, c_waveStateClearObs, AIWaveTargetUnit(obstruction));
}
}
//--------------------------------------------------------------------------------------------------
// AINewDetector
//--------------------------------------------------------------------------------------------------
void AINewDetector (int player, unit u, bool offerToScout) {
wave defendWave = AIWaveGet(player, c_waveDefend);
wave attackWave = AIWaveGet(player, c_waveAttack);
// first offer it to the attack wave if that wave has some units in it
if (AIWaveUnitCount(attackWave) >= 4) {
if (AIWaveDetectorCount(attackWave) == 0) {
AIWaveAddUnitPriority(attackWave, u, c_prioWavePeon);
return;
}
}
// next offer it to the defense wave
if (AIWaveDetectorCount(defendWave) == 0) {
AIWaveAddUnitPriority(defendWave, u, c_prioWavePeon);
return;
}
// last offer it to the scout synapse
if (offerToScout) {
if (AIOfferNewScout(player, u)) {
return;
}
}
// let the attack wave claim a second one
if (AIWaveUnitCount(attackWave) >= 4) {
if (AIWaveDetectorCount(attackWave) < 2) {
AIWaveAddUnitPriority(attackWave, u, c_prioWavePeon);
return;
}
}
// else add the detector to the extra scout group
AIAddToExtraScoutGroup(player, u);
}
//--------------------------------------------------------------------------------------------------
// AIWaveNeedClearObsUnits
//--------------------------------------------------------------------------------------------------
bool AIWaveNeedClearObsUnits (int player) {
unit obstruction = null;
wave waveClob = null;
wave waveAtck = null;
int countClob = 0;
int countAtck = 0;
int evalAtck = 0;
// Check global option
if (AIGetFlag(player, e_flagsClearObs) == false) {
return false;
}
// Don't clear obstructions in the first 10 minutes (leaves the AI too open to being rushed)
if (AIGetTime() < 600) {
return false;
}
// See if there is any obstruction
obstruction = AIGetObstruction(player);
if (obstruction == null) {
return false;
}
// See if the clear obstruction wave is already full
waveClob = AIWaveGet(player, c_waveClearObs);
countClob = AIWaveUnitCount(waveClob);
if (countClob >= 4) {
return false;
}
// If the attack wave is getting weak, keep units available for it instead
waveAtck = AIWaveGet(player, c_waveAttack);
countAtck = AIWaveUnitCount(waveAtck);
evalAtck = AIWaveEvalRatio(waveAtck, c_evalRange);
if (countAtck > 0 && evalAtck < 80) {
return false;
}
// Yes, units are needed for clear obstruction duty
return true;
}
//--------------------------------------------------------------------------------------------------
// AIWaveAttackDefend
//--------------------------------------------------------------------------------------------------
static bool AIWaveAttackDefend (int player, wave w, int state) {
if (!AIDefenseThreat(c_dtRealThreat, player, w)) {
return false;
}
if ( state == e_attackState_Idle || state == e_attackState_Wait ||
(AIWaveEval(AIWaveGet(player, c_waveMain)) + AIWaveEval(AIWaveGet(player, c_waveDefend)) < AIDefenseThreatEval(c_dtEvalRealThreats, player)) )
{
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
// AIIsAttacking
//--------------------------------------------------------------------------------------------------
bool AIIsAttacking (int player) {
wave waveAttack = null;
// for now I'm not counting e_attackState_DropAttack as attacking, it is a specialized attack
// and not easy for other AI's to coordinate with it
if (AIState(player, e_attackState) != e_attackState_Attack) {
return false;
}
waveAttack = AIWaveGet(player, c_waveAttack);
if (AIWaveUnitCount(waveAttack) == 0) {
return false;
}
if (AIWaveState(waveAttack) != c_waveStateAttack) {
return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------
// AINeedsDefending
//--------------------------------------------------------------------------------------------------
bool AINeedsDefending (int player) {
return AIWaveAttackDefend(player, c_nullWave, e_attackState_Attack);
}
//--------------------------------------------------------------------------------------------------
// TestUseDropAttack
//--------------------------------------------------------------------------------------------------
bool TestUseDropAttack (int player, wave w) {
int numMobileTransports;
// see if we can and want to do a drop attack
numMobileTransports = AIGetNumMobileTransports(player);
if (numMobileTransports >= 1) {
// we have a transport, so request more so we can use them to do a drop later
AISetWantsMultipleTransport(player, true);
}
else {
// don't worry about drops if we have no transports.
return false;
}
if (numMobileTransports < 3) {
// wait until we have at least 3 transports to try a drop
return false;
}
if (AIGetNextDropTimeCheck(player) >= AIGetTime()) {
// only check drop attacks every so often
return false;
}
AISetNextDropTimeCheck(player, AIGetTime() + c_dropCheckRollFreq);
if (RandomInt(1,100) > c_dropAttackChance) {
return false;
}
if (!AIFindDropAttackTarget(player, AIGetGatherLocation(player, c_townMain))) {
return false;
}
AISetNextDropTimeCheck(player, AIGetTime() + c_dropCheckAttackFreq);
AISetAttackState(player, e_attackState_DropAttack);
DebugAIPlayerWave(player, "attack1drop merge main -> attack; set attack = drop attack");
AIWaveMerge(player, c_waveMain, c_waveAttack);
AIWaveSetType(w, c_waveStateDropAttack, AIWaveTargetMeleeDrop(player, AILastDropLocation(), AILastDropGoal()));
return true;
}
//--------------------------------------------------------------------------------------------------
// AdvancedIdleAttackLogic
//--------------------------------------------------------------------------------------------------
void AdvancedIdleAttackLogic (int player, wave w, int count) {
// hard/insane logic for when to attack again
int eval;
bool enoughForce = false;
if (AILastAttackRatio(w) >= 120) {
// if the last attack was successful (we killed a good bit more than we lost)
// then attack again as soon as we've gathered 20 units or it's been a short amount of time
if (count >= 20) {
AISetAttackState(player, e_attackState_Attack);
}
else if (count >= 10 && AIGetFlag(player, e_flagsTimeout) && AIWaveGetTimeSinceCombat(w) >= 120) {
AISetAttackState(player, e_attackState_Attack);
}
}
else if (AILastAttackRatio(w) >= 80) {
// if the last attack was even (we did fight and we killed about as much as we lost)
// then we to attack until we've regrouped a bit
if (count >= 12) {
if (TestUseDropAttack(player,w)) {
return;
}
}
if (count >= 30) {
AISetAttackState(player, e_attackState_Attack);
}
else if (count >= 15 && AIGetFlag(player, e_flagsTimeout) && AIWaveGetTimeSinceCombat(w) >= 300 - 5*count) {
AISetAttackState(player, e_attackState_Attack);
}
}
else { // AILastAttackRatio(w) < 80
// if the last attack was a failure (we either retreated right away or lost more then we killed)
if (count >= 12) {
if (TestUseDropAttack(player,w)) {
return;
}
}
if (count < 20) {
return;
}
// force us to gather more units than last time, or use at least 160 food cap
if (PlayerGetPropertyInt(player, c_playerPropSuppliesUsed) > 160) {
enoughForce = true;
}
else {
eval = AIWaveEval(w) + AIWaveEval(AIWaveGet(player, c_waveMain));
if (IntToFixed(eval) > IntToFixed(AILastAttackStartEval(w)) * 1.33) {
enoughForce = true;
}
}
if (enoughForce) {
AISetAttackState(player, e_attackState_Attack);
}
}
}
//--------------------------------------------------------------------------------------------------
// AIWaveAttack
//--------------------------------------------------------------------------------------------------
void AIWaveAttack (int player, wave w) {
int state = AIState(player, e_attackState);
int eval;
int time;
int count;
//--- DEFEND ---
if (AIWaveAttackDefend(player, w, state)) {
AIDefendTown(player, w);
return;
}
//--- ATTACK ---
if (state == e_attackState_Attack) {
time = AIWaveGetTimeInCombat(w);
eval = AIWaveEvalRatio(w, c_evalRange);
if (eval >= 70 && eval <= 85 && time <= 3) { // when not fighting and only a little weak
if (AIGetFlag(player, e_flagsRunScared)) { // need to add check for ranges & max eval
AISetAttackState(player, e_attackState_Scared);
}
else {
AISetAttackState(player, e_attackState_Retreat);
}
}
else if (eval < 70) { // need to add check for faster/retreat blocked
AISetAttackState(player, e_attackState_Retreat);
}
else if (AIWaveState(w) != c_waveStateAttack) {
DebugAIPlayerWave(player, "attack1 merge main -> attack; set attack = attack vs. melee target");
AIWaveMerge(player, c_waveMain, c_waveAttack);
AIWaveSetType(w, c_waveStateAttack, AIWaveTargetMelee(player));
}
}
//--- DROP-ATTACK ---
if (state == e_attackState_DropAttack) {
eval = AIWaveEvalRatio(w, c_evalRange);
if (eval < 80) { // need to add check for can we retreat successfully
AISetAttackState(player, e_attackState_DropRetreat);
}
if (AIWaveState(w) != c_waveStateDropAttack) {
DebugAIPlayerWave(player, "attack1a In drop attack state, but not drop attack wave state?");
AISetAttackState(player, e_attackState_DropRetreat);
}
}
//--- SCARED ---
else if (state == e_attackState_Scared) {
eval = AIWaveEvalRatio(w, c_evalRange);
if (eval > 95) { // turn and fight when strong
AISetAttackState(player, e_attackState_Attack);
}
else if (eval < 70) { // retreat entirely if getting picked off
AISetAttackState(player, e_attackState_Retreat);
}
else if (AIWaveState(w) != c_waveStateRetreat) {
DebugAIPlayerWave(player, "attack2 merge main -> attack; set attack = retreat to gather offense");
AIWaveMerge(player, c_waveMain, c_waveAttack);
AIWaveSetType(w, c_waveStateRetreat, AIWaveTargetGatherO(player, c_townMain));
}
}
//--- RETREAT ---
else if (state == e_attackState_Retreat) {
DebugAIPlayerWave(player, "attack3 set attack = retreat to gather offense");
AIWaveSetType(w, c_waveStateRetreat, AIWaveTargetGatherO(player, c_townMain));
AISetAttackState(player, e_attackState_InRetreat);
}
//--- DROP RETREAT ---
else if (state == e_attackState_DropRetreat) {
DebugAIPlayerWave(player, "attack3drop set attack = drop retreat to gather offense");
AIWaveSetType(w, c_waveStateDropRetreat, AIWaveTargetGatherO(player, c_townMain));
AISetAttackState(player, e_attackState_InRetreat);
}
//--- IN RETREAT ---
else if (state == e_attackState_InRetreat) {
if (AIWaveState(w) != c_waveStateRetreat && AIWaveState(w) != c_waveStateDropRetreat) {
DebugAIPlayerWave(player, "attack4 merge main -> attack");
AIWaveMerge(player, c_waveMain, c_waveAttack);
AISetAttackState(player, e_attackState_Idle);
}
}
//--- IDLE ---
else if (state == e_attackState_Idle) {
count = AIWaveUnitCount(w) + AIWaveUnitCount(AIWaveGet(player, c_waveMain));
// wait 30 seonds at least after retreating before attacking again
if (AIWaveGetTimeSinceRetreat(w) > 30) {
// always support allies attacking
if (AIAnyAllyAttacking(player)) {
AISetAttackState(player, e_attackState_Attack);
}
if (PlayerDifficulty(player) >= c_skirVeryHard) {
if (AIWaveState(w) == c_waveStateIdle) {
// wait until the wave is idle before considering attacking again
AdvancedIdleAttackLogic(player, w, count);
}
}
else {
// base logic attack any time we have more than 30 units or it's been a while
if (count >= 30) {
AISetAttackState(player, e_attackState_Attack);
}
else if (AIGetFlag(player, e_flagsTimeout) && AIWaveGetTimeSinceCombat(w) >= 300-10*count) {
AISetAttackState(player, e_attackState_Attack);
}
}
}
if (AIState(player, e_attackState) == e_attackState_Idle) {
if (AIWaveState(w) != c_waveStateIdle) {
DebugAIPlayerWave(player, "attack5 set attack = idle at gather offense");
AIWaveSetType(w, c_waveStateIdle, AIWaveTargetGatherO(player, c_townMax));
}
}
}
}
//--------------------------------------------------------------------------------------------------
// AIWaveThinkDefault
//--------------------------------------------------------------------------------------------------
void AIWaveThinkDefault (int player, wave w, int type) {
if (AIWaveUnitCount(w) < 1) {
return;
}
if (type == c_waveMain) {
AIWaveMain(player, w);
}
else if (type == c_waveDefend) {
AIWaveDefend(player, w);
}
else if (type == c_waveAttack) {
AIWaveAttack(player, w);
}
else if (type == c_waveDivert1) {
AIWaveDivert(player, w, e_divert1State);
}
else if (type == c_waveDivert2) {
AIWaveDivert(player, w, e_divert2State);
}
else if (type == c_waveClearObs) {
AIWaveClearObs(player, w);
}
else if (type == c_waveHome) {
AIWaveHome(player, w);
}
}
//--------------------------------------------------------------------------------------------------
// AIMainStateSelect
//--------------------------------------------------------------------------------------------------
int AIMainStateSelect (int player, int roll, int range, int state, int subState) {
if (roll >= 1 && roll <= range) {
AISetMainState(player, state, subState);
}
return roll - range;
}
//--------------------------------------------------------------------------------------------------
// AIMergeWait
//--------------------------------------------------------------------------------------------------
void AIMergeWait (int player, int count, string what, int size, int state, int subState) {
wave atk = AIWaveGet(player, c_waveAttack);
if (AIWaveState(atk) != c_waveStateRetreat) {
if (AIWaveUnitCount(AIWaveGet(player, c_waveMain)) >= 3 ||
AITechCount(player, what, c_techCountCompleteOnly) >= count)
{
DebugAIPlayerWave(player, "merge1 merge main -> attack");
AIWaveMerge(player, c_waveMain, c_waveAttack);
}
}
if (AIWaveUnitCount(atk) >= size) {
AISetAttackState(player, e_attackState_Attack);
AISetMainState(player, state, subState);
AISetFlag(player, e_flagsTimeout, true);
}
else if (AIHasRes(player, 1000, 500)) {
AISetMainState(player, state, subState);
AISetFlag(player, e_flagsTimeout, true);
}
}
//--------------------------------------------------------------------------------------------------
// AIStockAndWait
//--------------------------------------------------------------------------------------------------
bool AIStockAndWait (int player, int count, string type) {
if (AITechCount(player, type, c_techCountInProgressOrBetter) < count) {
AISetStock( player, count, type );
AIEnableStock(player);
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
// AISuspectDetectionDanger
//--------------------------------------------------------------------------------------------------
bool AISuspectDetectionDanger (int player) {
bool suspectDanger = false;
suspectDanger = AIDefaultSuspectDetectionDanger(player);
// script additions / override of the default
return suspectDanger;
}
//--------------------------------------------------------------------------------------------------
// AITownIsFull
//--------------------------------------------------------------------------------------------------
void AITownIsFull (int player, int town) {
// town was unable to place a building because it ran out of room, it may still
// be possible to place a smaller building or a different type of building
AIUpdateMainTown(player);
// if we only have no non-full town, we may want to expand now
}
//--------------------------------------------------------------------------------------------------
// AITownWasLost
//--------------------------------------------------------------------------------------------------
void AITownWasLost (int player, int town) {
// one of our towns was destroyed/lost, happens when we lose our last dropoff at the town (or all buildings).
AIUpdateMainTown(player);
}
//--------------------------------------------------------------------------------------------------
// AIMakeTest
//--------------------------------------------------------------------------------------------------
bool AIMakeTest (int player, int min, int max, string type, string tech,
string base, int addons, string addon)
{
int count = AICounterUnits(player, c_maxPlayers, type);
if (count <= 0) {
return false;
}
if (count < min) {
count = min;
}
else if (count > max) {
count = max;
}
if (AITechCount(player, type, c_techCountInProgressOrBetter) >= count) {
return false;
}
if (count > 5) {
AISetStockUnitNext( player, 3, base, c_stockIdle );
AISetStockUnitNext( player, addons, addon, c_stockIdle );
}
else if (count > 2) {
AISetStockUnitNext( player, 2, base, c_stockIdle );
if (addons > 2) {
AISetStockUnitNext( player, 2, addon, c_stockIdle );
}
else {
AISetStockUnitNext( player, addons, addon, c_stockIdle );
}
}
if (tech != c_noTech) {
AISetStock( player, 1, tech );
}
AISetStockUnitNext( player, count, type, c_stockAlways );
return true;
}
//--------------------------------------------------------------------------------------------------
// AIMineralsTotal
//--------------------------------------------------------------------------------------------------
int AIMineralsTotal (int player) {
return PlayerGetPropertyInt(player, c_playerPropMinerals) + AIGetMineralAmountLeft(player, c_townMax);
}
//--------------------------------------------------------------------------------------------------
// AIWavePrimaryCount
//--------------------------------------------------------------------------------------------------
int AIWavePrimaryCount (int player) {
return AIWaveUnitCount(AIWaveGet(player, c_waveMain)) + AIWaveUnitCount(AIWaveGet(player, c_waveAttack));
}
//--------------------------------------------------------------------------------------------------
// AIDiffEnum
//--------------------------------------------------------------------------------------------------
int AIDiffEnum (int player, int base) {
return base + PlayerDifficulty(player);
}
//--------------------------------------------------------------------------------------------------
// AIDiffThreshold
//--------------------------------------------------------------------------------------------------
int AIDiffThreshold (int player, int defaultValue, int threshold, int alternateValue) {
int diff = PlayerDifficulty(player);
if (diff < threshold) {
return defaultValue;
}
return alternateValue;
}
//--------------------------------------------------------------------------------------------------
// AIAddDetectionDangerUnits
//--------------------------------------------------------------------------------------------------
void AIAddDetectionDangerUnits (int player) {
AIAddDetectionDanger(player, c_TU_Ghost);
AIAddDetectionDanger(player, c_TU_Banshee);
AIAddDetectionDanger(player, c_ZU_Lurker);
AIAddDetectionDanger(player, c_PU_DarkTemplar);
AIAddDetectionDanger(player, c_PU_Mothership);
AIAddDetectionDanger(player, c_TB_GhostAcademy);
AIAddDetectionDanger(player, c_TB_FusionCore);
AIAddDetectionDanger(player, c_ZB_LurkerDen);
AIAddDetectionDanger(player, c_PB_DarkShrine);
}
//--------------------------------------------------------------------------------------------------
// Default startup routine
//--------------------------------------------------------------------------------------------------
void AIMeleeStart (int player) {
point targ;
if (DEBUG) {
DebugMeleeInit();
}
AIStart(player, false, DifficultyAPM(PlayerDifficulty(player)));
if (PlayerDifficulty(player) >= c_skirVeryHard) {
if (PlayerDifficulty(player) >= c_skirCheater) {
AIHarvestBonus(player, 2.0);
AISetDifficulty(player, c_diffNormalVision, false);
AISetDifficulty(player, c_diffLimitAPM, false);
}
AISetFlag(player, e_flagsRunScared, false); // TODO fix scared and re-add this
}
else {
AISetDifficulty(player, c_diffAdvanceWave, false);
AISetDifficulty(player, c_diffFleeDamage, false);
AISetDifficulty(player, c_diffWaveAvoidDanger, false);
AISetFlag(player, e_flagsRunScared, false);
}
AISetDifficulty(player, c_diffAutoLoadBunkers, false);
AISetDifficulty(player, c_diffEarlyGameRepair, false);
AISetDifficulty(player, c_diffEarlyDefenseScout, false);
AISetFlag(player, e_flagsLateScout, false);
AISetFlag(player, e_flagsClearObs, false);
AIDeclareTown(player, c_townOne, PlayerStartLocation(player));
AISetMainTown(player, c_townOne);
AIHarvest(player, c_townOne);
AISetNumScouts(player, 1);
AIScout(player);
AISetAllStates(player, 1);
targ = AIWaveTargetGatherOPoint(player, c_townMain);
AIWaveSet(player, c_waveMain, AIWaveCreate(AIWaveInfoCreate(), player, targ));
AIWaveSet(player, c_waveAttack, AIWaveCreate(AIWaveInfoCreate(), player, targ));
AIWaveSet(player, c_waveDivert1, AIWaveCreate(AIWaveInfoCreate(), player, targ));
AIWaveSet(player, c_waveDivert2, AIWaveCreate(AIWaveInfoCreate(), player, targ));
AIWaveSet(player, c_waveClearObs, AIWaveCreate(AIWaveInfoCreate(), player, targ));
AIWaveSet(player, c_waveHome, AIWaveCreate(AIWaveInfoCreate(), player, targ));
targ = AIWaveTargetGatherDPoint(player, c_townMain);
AIWaveSet(player, c_waveDefend, AIWaveCreate(AIWaveInfoCreate(), player, targ));
AITransportIgnore(player, "VikingAssault");
AITransportSetPanic(player, 0.6);
AITransportSetReturn(player, targ);
AISpecifiedMakers();
AISetDefaultCombatFlags(player, true);
AIAddDetectionDangerUnits(player);
//AISetNukeConstants(player);
}
include "TriggerLibs/MeleeNotHardAI"
Autoren: Peq