bool RuleActor::act_per_unit()

in rts/engine/rule_actor.cc [224:330]


bool RuleActor::act_per_unit(const GameEnv &env, const Unit *u, const int *state, RegionHist *region_hist, string *state_string, AssignedCmds *assigned_cmds) {
    UnitType ut = u->GetUnitType();
    const CmdDurative *curr_cmd = _receiver->GetUnitDurativeCmd(u->GetId());
    bool idle = (curr_cmd == nullptr);
    CmdType cmdtype = idle ? INVALID_CMD : curr_cmd->type();

    if (ut == BASE && state[STATE_BUILD_WORKER] && idle) {
        if (_preload.BuildIfAffordable(WORKER)) {
            *state_string = "Build worker..Success";
            store_cmd(u, _B(WORKER), assigned_cmds);
        }
    }

    // Ask workers to gather.
    if (ut == WORKER) {
        // Gather!
        if (idle) store_cmd(u, _preload.GetGatherCmd(), assigned_cmds);

        // If resource permit, build barracks.
        if (cmdtype == GATHER && state[STATE_BUILD_BARRACK] && ! region_hist->has_built_barracks) {
            if (_preload.Affordable(BARRACKS)) {
                *state_string = "Build barracks..Success";
                CmdBPtr cmd = _preload.GetBuildBarracksCmd(env);
                if (cmd != nullptr) {
                    store_cmd(u, std::move(cmd), assigned_cmds);
                    region_hist->has_built_barracks = true;
                    _preload.Build(BARRACKS);
                }
            }
        }
    }

    if (ut == BARRACKS && idle) {
        if (state[STATE_BUILD_MELEE_TROOP] && ! region_hist->has_built_melee) {
            if (_preload.BuildIfAffordable(MELEE_ATTACKER)) {
                *state_string = "Build Melee Troop..Success";
                store_cmd(u, _B(MELEE_ATTACKER), assigned_cmds);
                region_hist->has_built_melee = true;
            }
        }

        if (state[STATE_BUILD_RANGE_TROOP] && ! region_hist->has_built_range) {
            if (_preload.BuildIfAffordable(RANGE_ATTACKER)) {
                *state_string = "Build Range Troop..Success";
                store_cmd(u, _B(RANGE_ATTACKER), assigned_cmds);
                region_hist->has_built_range = true;
            }
        }
    }

    if (state[STATE_ATTACK] && (ut == MELEE_ATTACKER || ut == RANGE_ATTACKER)) {
        if (idle) store_cmd(u, _preload.GetAttackEnemyBaseCmd(), assigned_cmds);
    }

    if (state[STATE_HIT_AND_RUN]) {
        // cout << "Enter hit and run procedure" << endl << flush;
        auto enemy_troops = _preload.EnemyTroops();
        *state_string = "Hit and run";
        if (ut == RANGE_ATTACKER) {
            // cout << "Enemy only have worker" << endl << flush;
            if (enemy_troops[MELEE_ATTACKER].empty() && enemy_troops[RANGE_ATTACKER].empty() && ! enemy_troops[WORKER].empty()) {
                hit_and_run(env, u, enemy_troops[WORKER], assigned_cmds);
            }

            if (! enemy_troops[MELEE_ATTACKER].empty()) {
                hit_and_run(env, u, enemy_troops[MELEE_ATTACKER], assigned_cmds);
            }
        }
        if (ut == RANGE_ATTACKER || ut == MELEE_ATTACKER) {
            if (! enemy_troops[RANGE_ATTACKER].empty() && idle) {
                store_cmd(u, _A(enemy_troops[RANGE_ATTACKER][0]->GetId()), assigned_cmds);
            }
        }
    }

    const auto& enemy_troops_in_range = _preload.EnemyTroopsInRange();
    const auto& enemy_attacking_economy = _preload.EnemyAttackingEconomy();

    if ((ut == RANGE_ATTACKER || ut == MELEE_ATTACKER)
            && idle && state[STATE_ATTACK_IN_RANGE] && ! enemy_troops_in_range.empty()) {
        *state_string = "Attack enemy in range..Success";
        auto cmd = _A(enemy_troops_in_range[0]->GetId());
        store_cmd(u, std::move(cmd), assigned_cmds);
    }

    if (state[STATE_DEFEND]) {
      // Group Retaliation. All troops attack.
      *state_string = "Defend enemy attack..NOOP";
      const Unit *enemy_at_resource = _preload.EnemyAtResource();
      if (enemy_at_resource != nullptr) {
          *state_string = "Defend enemy attack..Success";
          store_cmd(u, _A(enemy_at_resource->GetId()), assigned_cmds);
      }

      const Unit *enemy_at_base = _preload.EnemyAtBase();
      if (enemy_at_base != nullptr) {
          *state_string = "Defend enemy attack..Success";
          store_cmd(u, _A(enemy_at_base->GetId()), assigned_cmds);
      }
      if (! enemy_attacking_economy.empty()) {
          *state_string = "Defend enemy attack..Success";
          auto it = enemy_attacking_economy.begin();
          store_cmd(u, _A((*it)->GetId()), assigned_cmds);
      }
    }
    return true;
}