extern int gRioterQuery = -1; extern int gSiegeQuery = -1; extern int gEnemyQuery = -1; extern int gRioterMaxAttackDistance = 100; // Rioters will ignore siege that is farther away than this distance void setRioterMaxAttackDistance(int dist = -1) { gRioterMaxAttackDistance = dist; } // Set the number of seconds between when the rule will update void setRioterAttackUpdateFrequency(int freq = -1) { xsSetRuleMinInterval("makeRiotersAttack", freq); } void runRioterAttackRoutine(int unused = -1) { // give them perfect vision kbLookAtAllUnitsOnMap(); // initialze queries if(gRioterQuery == -1) { gRioterQuery = kbUnitQueryCreate("Rioter Query"); kbUnitQuerySetPlayerID(gRioterQuery, cMyID); kbUnitQuerySetUnitType(gRioterQuery, cUnitTypeLogicalTypeLandPickerChoice); kbUnitQuerySetState(gRioterQuery, cUnitStateAlive); } if(gSiegeQuery == -1) { gSiegeQuery = kbUnitQueryCreate("Patrol Unit Query"); kbUnitQuerySetPlayerRelation(gSiegeQuery, cPlayerRelationEnemyNotGaia); kbUnitQuerySetUnitType(gSiegeQuery, cUnitTypeAbstractArtillery); kbUnitQuerySetState(gSiegeQuery, cUnitStateAlive); } if(gEnemyQuery == -1) { gEnemyQuery = kbUnitQueryCreate("Patrol Unit Query"); kbUnitQuerySetPlayerRelation(gEnemyQuery, cPlayerRelationEnemyNotGaia); kbUnitQuerySetUnitType(gEnemyQuery, cUnitTypeMilitary); kbUnitQuerySetState(gEnemyQuery, cUnitStateAlive); } // run the queries kbUnitQueryResetResults(gRioterQuery); kbUnitQueryExecute(gRioterQuery); int rioters = kbUnitQueryNumberResults(gRioterQuery); aiEcho("rioters " + rioters); kbUnitQueryResetResults(gSiegeQuery); kbUnitQueryExecute(gSiegeQuery); int siegeUnits = kbUnitQueryNumberResults(gSiegeQuery); aiEcho("siege " + siegeUnits); kbUnitQueryResetResults(gEnemyQuery); kbUnitQueryExecute(gEnemyQuery); int enemies = kbUnitQueryNumberResults(gEnemyQuery); aiEcho("enemies " + enemies); for(i = 0; < rioters) { int rioterID = kbUnitQueryGetResult(gRioterQuery, i); vector rioterLoc = kbUnitGetPosition(rioterID); float tempDist = 0; // find closest siege unit int closestID = -1; float closestDistance = 1000; for(j = 0; < siegeUnits) { int siegeID = kbUnitQueryGetResult(gSiegeQuery, j); tempDist = xsVectorLength(rioterLoc - kbUnitGetPosition(siegeID)); if(tempDist < closestDistance && tempDist < gRioterMaxAttackDistance) { closestID = siegeID; closestDistance = tempDist; } } // make 'em attack if(closestID != -1) { aiTaskUnitWork(rioterID, closestID); aiEcho("rioter " + rioterID + " attack unit " + closestID); } else { for(j = 0; < enemies) { int enemyID = kbUnitQueryGetResult(gEnemyQuery, j); tempDist = xsVectorLength(rioterLoc - kbUnitGetPosition(enemyID)); if(tempDist < closestDistance && tempDist < gRioterMaxAttackDistance) { closestID = enemyID; closestDistance = tempDist; } } } } } rule makeRiotersAttack active minInterval 5 { runRioterAttackRoutine(-1); } void main() { kbAreaCalculate(); }