//------- Begin of function Unit::think_change_attack_target -------// // // When the unit is attacking a firm or town, look out for enemy units // to attack. Enemy units should be attacked first. // int Unit::think_change_attack_target() { err_when( !nation_recno ); // only for nation units //----------------------------------------------// int attackRange = MAX(attack_range, 8); int attackScanRange = attackRange*2+1; int xOffset, yOffset; int xLoc, yLoc; Location* locPtr; int curXLoc = next_x_loc(), curYLoc = next_y_loc(); BYTE regionId = world.get_region_id(curXLoc, curYLoc); for( int i=2 ; i<attackScanRange*attackScanRange ; i++ ) { m.cal_move_around_a_point(i, attackScanRange, attackScanRange, xOffset, yOffset); xLoc = curXLoc + xOffset; yLoc = curYLoc + yOffset; xLoc = MAX(0, xLoc); xLoc = MIN(MAX_WORLD_X_LOC-1, xLoc); yLoc = MAX(0, yLoc); yLoc = MIN(MAX_WORLD_Y_LOC-1, yLoc); locPtr = world.get_loc(xLoc, yLoc); if( locPtr->region_id != regionId ) continue; //----- if there is a unit on the location ------// if( locPtr->has_unit(UNIT_LAND) ) { int unitRecno = locPtr->unit_recno(UNIT_LAND); if( unit_array.is_deleted(unitRecno) ) continue; if( unit_array[unitRecno]->nation_recno != nation_recno && idle_detect_unit_checking(unitRecno) ) { save_original_action(); original_target_x_loc = xLoc; original_target_y_loc = yLoc; attack_unit(xLoc, yLoc); return 1; } } } return 0; }
void attack_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: "<< *this << std::endl; // Stop the user from issuing any commands while the unit is attacking const events::command_disabler disable_commands; //@note: yes, this is a decision done here. It's that way because we want to allow a simpler attack 'with whatever weapon is considered best', and because we want to allow the defender to pick it's weapon. That's why aggression is needed. a cleaner solution is needed. battle_context bc(get_info().units, attacker_loc_, defender_loc_, attacker_weapon_, -1, aggression_); int attacker_weapon = bc.get_attacker_stats().attack_num; int defender_weapon = bc.get_defender_stats().attack_num; if(attacker_weapon < 0) { set_error(E_UNABLE_TO_CHOOSE_ATTACKER_WEAPON); return; } const unit *d_ = get_unit(get_info(),defender_loc_); const unit *a_ = get_unit(get_info(),attacker_loc_); //@todo 1.9: change ToD to be location specific for the defender unit recorder.add_attack(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, a_->type_id(), d_->type_id(), a_->level(), d_->level(), resources::tod_manager->turn(), resources::tod_manager->get_time_of_day()); rand_rng::invalidate_seed(); rand_rng::clear_new_seed_callback(); while (!rand_rng::has_valid_seed()) { manager::raise_user_interact(); manager::raise_sync_network(); SDL_Delay(10); } recorder.add_seed("attack", rand_rng::get_last_seed()); attack_unit(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon); dialogs::advance_unit(attacker_loc_, true); const unit_map::const_iterator defender = get_info().units.find(defender_loc_); if(defender != get_info().units.end()) { const size_t defender_team = size_t(defender->second.side()) - 1; if(defender_team < get_info().teams.size()) { dialogs::advance_unit(defender_loc_ , !get_info().teams[defender_team].is_human()); } } set_gamestate_changed(); //start of ugly hack. @todo 1.9 rework that via extended event system //until event system is reworked, we note the attack this way get_info().recent_attacks.insert(defender_loc_); //end of ugly hack try { manager::raise_gamestate_changed(); } catch (...) { is_ok(); //Silences "unchecked result" warning throw; } }
void attack_unit_and_advance(const map_location &attacker, const map_location &defender, int attack_with, int defend_with, bool update_display, const ai::unit_advancements_aspect& ai_advancement) { attack_unit(attacker, defender, attack_with, defend_with, update_display); unit_map::const_iterator atku = resources::units->find(attacker); if (atku != resources::units->end()) { advance_unit_at(advance_unit_params(attacker).ai_advancements(ai_advancement)); } unit_map::const_iterator defu = resources::units->find(defender); if (defu != resources::units->end()) { advance_unit_at(advance_unit_params(defender).ai_advancements(ai_advancement)); } }
//------ Begin of function Unit::handle_blocked_move_s11 -------// // both blocked and blocking are size 1 // void Unit::handle_blocked_move_s11(Unit *unitPtr) { err_when( world.get_unit_recno(next_x_loc(), next_y_loc(), mobile_type) != sprite_recno ); err_when( world.get_unit_recno(unitPtr->next_x_loc(), unitPtr->next_y_loc(), unitPtr->mobile_type) != unitPtr->sprite_recno ); err_when(cur_x!=next_x || cur_y!=next_y); int waitTerm; int moveStep = move_step_magn(); switch(unitPtr->cur_action) { //------------------------------------------------------------------------------------// // handle blocked for units belonging to the same nation. For those belonging to other // nations, wait for it moving to other locations or search for another path. //------------------------------------------------------------------------------------// case SPRITE_WAIT: // the blocking unit is waiting err_when(unitPtr->go_x==unitPtr->cur_x && unitPtr->go_y==unitPtr->cur_y); case SPRITE_TURN: if(unitPtr->nation_recno==nation_recno) handle_blocked_wait(unitPtr); // check for cycle wait for our nation else if(waiting_term>=MAX_WAITING_TERM_DIFF) { search_or_stop(move_to_x_loc, move_to_y_loc, 1); // recall searching waiting_term = 0; } else // wait set_wait(); return; //------------------------------------------------------------------------------------// // We know from the cur_action of the blocking unit it is moving to another locations, // the blocked unit wait for a number of terms or search again. //------------------------------------------------------------------------------------// case SPRITE_MOVE: case SPRITE_READY_TO_MOVE: case SPRITE_SHIP_EXTRA_MOVE: if(unit_id!=UNIT_CARAVAN && unitPtr->unit_id==UNIT_CARAVAN) // don't wait for caravans, and caravans don't wait for other units { search(move_to_x_loc, move_to_y_loc, 1, SEARCH_MODE_A_UNIT_IN_GROUP); } else { waitTerm = (nation_recno==unitPtr->nation_recno) ? MAX_WAITING_TERM_SAME : MAX_WAITING_TERM_DIFF; if(waiting_term>=waitTerm) { search_or_wait(); waiting_term = 0; } else set_wait(); } return; //------------------------------------------------------------------------------------// // handling blocked for idle unit //------------------------------------------------------------------------------------// case SPRITE_IDLE: err_when(unitPtr->result_node_array!=NULL); if(unitPtr->action_mode==ACTION_SHIP_TO_BEACH) { //----------------------------------------------------------------------// // the blocking unit is trying to move to beach, so wait a number of terms, // or call searching again //----------------------------------------------------------------------// if(abs(unitPtr->next_x_loc()-unitPtr->action_x_loc2)<=moveStep && abs(unitPtr->next_y_loc()-unitPtr->action_y_loc2)<=moveStep && terrain_res[world.get_loc(unitPtr->action_x_loc2, unitPtr->action_y_loc2)->terrain_id]->average_type !=TERRAIN_OCEAN) { if(action_mode2==ACTION_SHIP_TO_BEACH && action_x_loc2==unitPtr->action_x_loc2 && action_y_loc2==unitPtr->action_y_loc2) { int tempX, tempY; ship_to_beach(action_x_loc2, action_y_loc2, tempX, tempY); } else { waitTerm = (nation_recno==unitPtr->nation_recno) ? MAX_WAITING_TERM_SAME : MAX_WAITING_TERM_DIFF; if(waiting_term>=waitTerm) stop2(); else set_wait(); } return; } } if(unitPtr->nation_recno==nation_recno) //-------- same nation { //------------------------------------------------------------------------------------// // units from our nation //------------------------------------------------------------------------------------// if(unitPtr->unit_group_id==unit_group_id) { //--------------- from the same group -----------------// if(way_point_count && !unitPtr->way_point_count) { //------------ reset way point --------------// stop2(); reset_way_point_array(); } else if((unitPtr->next_x_loc() != move_to_x_loc || unitPtr->next_y_loc() != move_to_y_loc) && (unitPtr->cur_action==SPRITE_IDLE && unitPtr->action_mode2==ACTION_STOP)) move_to_my_loc(unitPtr); // push the blocking unit and exchange their destination else if(unitPtr->action_mode == ACTION_SETTLE) set_wait(); // wait for the settler else if(waiting_term>MAX_WAITING_TERM_SAME) { //---------- stop if wait too long ----------// terminate_move(); waiting_term = 0; } else set_wait(); } else if(unitPtr->action_mode2==ACTION_STOP) handle_blocked_by_idle_unit(unitPtr); else if(way_point_count && !unitPtr->way_point_count) { stop2(); reset_way_point_array(); } else search_or_stop(move_to_x_loc, move_to_y_loc, 1); // recall A* algorithm by default mode } else // different nation { //------------------------------------------------------------------------------------// // units from other nations //------------------------------------------------------------------------------------// if(unitPtr->next_x_loc() == move_to_x_loc && unitPtr->next_y_loc() == move_to_y_loc) { terminate_move(); // destination occupied by other unit if(action_mode==ACTION_ATTACK_UNIT && unitPtr->nation_recno!=nation_recno && unitPtr->sprite_recno==action_para) { err_when(action_x_loc!=unitPtr->next_x_loc() || action_y_loc!=unitPtr->next_y_loc()); err_when(action_mode2!=ACTION_ATTACK_UNIT && action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET); err_when(action_para2!=action_para); err_when(action_x_loc!=action_x_loc2 || action_y_loc!=action_y_loc2); set_dir(next_x, next_y, unitPtr->next_x, unitPtr->next_y); if(is_dir_correct()) attack_unit(action_para); else set_turn(); cur_frame = 1; } } else search_or_stop(move_to_x_loc, move_to_y_loc, 1); // recall A* algorithm by default mode } return; //------------------------------------------------------------------------------------// // don't wait for attackers from other nations, search for another path. //------------------------------------------------------------------------------------// case SPRITE_ATTACK: //----------------------------------------------------------------// // don't wait for other nation unit, call searching again //----------------------------------------------------------------// if(nation_recno!=unitPtr->nation_recno) { search_or_stop(move_to_x_loc, move_to_y_loc, 1); return; } //------------------------------------------------------------------------------------// // for attackers owned by our commander, handled blocked case by case as follows. //------------------------------------------------------------------------------------// switch(unitPtr->action_mode) { case ACTION_ATTACK_UNIT: if(action_para && !unit_array.is_deleted(action_para)) { Unit *targetPtr = unit_array[action_para]; handle_blocked_attack_unit(unitPtr, targetPtr); } else search_or_stop(move_to_x_loc, move_to_y_loc, 1, SEARCH_MODE_A_UNIT_IN_GROUP); break; case ACTION_ATTACK_FIRM: if(!unitPtr->action_para || firm_array.is_deleted(unitPtr->action_para)) set_wait(); else handle_blocked_attack_firm(unitPtr); break; case ACTION_ATTACK_TOWN: if(!unitPtr->action_para || town_array.is_deleted(unitPtr->action_para)) set_wait(); else handle_blocked_attack_town(unitPtr); break; case ACTION_ATTACK_WALL: if(unitPtr->action_para) set_wait(); else handle_blocked_attack_wall(unitPtr); break; case ACTION_GO_CAST_POWER: set_wait(); break; default: err_here(); break; } return; //------------------------------------------------------------------------------------// // the blocked unit can pass after the blocking unit disappears in air. //------------------------------------------------------------------------------------// case SPRITE_DIE: set_wait(); // assume this unit will not wait too long return; default: err_here(); break; } err_when(cur_x==go_x && cur_y==go_y && (cur_x!=next_x || cur_y!=next_y)); }
//for most cases, this takes world coordinates, but not always!!! void g1_human_class::player_clicked(g1_object_class * obj, float gx, float gy,w32 command) { g1_object_type convoy_type=g1_get_object_type(li_convoy.get()); switch (command) { case DEFAULT: { if (obj && obj->player_num==team() && obj->get_flag(g1_object_class::SELECTABLE)) { clear_selected(); if (obj == commander()) { selected_object = 0; } else { g1_convoy_class * c=(g1_convoy_class *)g1_object_type_array[convoy_type]->create_object(convoy_type,0); c->setup(obj); c->player_num=team(); selected_object=c; selected_object->mark_as_selected(); } } else if (selected_object.valid()) { send_selected_units(gx,gy); } else { select_path(gx,gy); } } break; case ATTACK: { if (selected_object.valid()&&selected_object->player_num==team()) { attack_unit(obj,gx,gy); } //remember: this only works if //target is in range break; } case GOTO: if (selected_object.valid()&&selected_object->player_num==team()) { send_selected_units(gx,gy); } break; case SELECT: { //single objects can be selected, even if they don't //belong to the local user if (!obj/*||obj->player_num!=team() ||!obj->get_flag(g1_object_class::SELECTABLE) */) { break; } clear_selected(); g1_convoy_class * c=(g1_convoy_class *)g1_create_object(convoy_type); c->player_num=obj->player_num; if (!obj->get_flag(g1_object_class::SELECTABLE)) { c->player_num=0; } //a slight hack to prevent the user //from actually sending commands //to this unit. c->setup(obj); selected_object=c; selected_object->mark_as_selected(); break; } case ADD_TO_LIST: { if ((selected_object.valid()&&selected_object->id!=g1_get_object_type(li_convoy.get())) || !obj || obj->player_num!=team() || !obj->get_flag(g1_object_class::SELECTABLE)) { break; } if (!selected_object.valid()) { g1_convoy_class * cn=(g1_convoy_class *) g1_create_object(convoy_type); cn->player_num=team(); cn->setup(obj); selected_object=cn; cn->mark_as_selected(); break; } ((g1_convoy_class *)selected_object.get())->add_object(obj); } break; case START_DRAG: { dragstartx=gx; //Screen coordinates!!! dragstarty=gy; break; } case DRAGGING: { dragdestx=gx; dragdesty=gy; //w16 mod; //if (i4_current_app->get_window_manager()->shift_pressed()) // mod=ADD_TO_OLD; //else if (i4_current_app->get_window_manager()->alt_pressed()) // mod=SUB_FROM_OLD; //else // mod=CLEAR_OLD; //select_objects_in_range(dragstartx,dragstarty,dragendx,dragendy,mod); } break; case END_DRAG: { dragstartx=dragstarty=dragdestx=dragdesty=-1; } break; case SELECT_PATH: { select_path(gx,gy); } break; default: break; } }
//--------- Begin of function Unit::monster_defend_attack_unit ---------// // set to attack target // // <short> targetRecno - recno of the target // void Unit::monster_defend_attack_unit(short targetRecno) { action_mode2 = ACTION_MONSTER_DEFEND_ATTACK_TARGET; attack_unit(targetRecno); }
//--------- Begin of function Unit::defend_town_attack_unit ---------// // set to defensive mode // // <short> targetRecno - record of target // void Unit::defend_town_attack_unit(short targetRecno) { action_mode2 = ACTION_DEFEND_TOWN_ATTACK_TARGET; attack_unit(targetRecno); }
//--------- Begin of function Unit::defense_attack_unit ---------// // defensive attack units // // <short> targetRecno - recno of the target // void Unit::defense_attack_unit(short targetRecno) { action_mode2 = ACTION_AUTO_DEFENSE_ATTACK_TARGET; attack_unit(targetRecno); }
//--------- Begin of function Unit::general_defend_mode_process_attack_target ---------// // process unit defense action. If target is dead, action_mode changes to detect_mode // // return 1 if action mode changes to detect mode // return 0 otherwise // int Unit::general_defend_mode_process_attack_target() { Location *locPtr; Unit *unitPtr; Town *townPtr; Firm *firmPtr; SpriteInfo *spriteInfo; FirmInfo *firmInfo; int clearToDetect = 0; //------------------------------------------------------------------------------// // if the unit's action mode is in defensive attack action, process the corresponding // checking. //------------------------------------------------------------------------------// switch(action_mode) { case ACTION_ATTACK_UNIT: if(unit_array.is_deleted(action_para2)) clearToDetect++; else { err_when(unit_array.is_deleted(action_para2)); unitPtr = unit_array[action_para2]; //if(unitPtr->cur_action==SPRITE_IDLE) // clearToDetect++; if(!nation_can_attack(unitPtr->nation_recno)) // cannot attack this nation clearToDetect++; } break; case ACTION_ATTACK_FIRM: if(firm_array.is_deleted(action_para2)) clearToDetect++; else { err_when(firm_array.is_deleted(action_para2)); firmPtr = firm_array[action_para2]; if(!nation_can_attack(firmPtr->nation_recno)) // cannot attack this nation clearToDetect++; } break; case ACTION_ATTACK_TOWN: if(town_array.is_deleted(action_para2)) clearToDetect++; else { err_when(town_array.is_deleted(action_para2)); townPtr = town_array[action_para2]; if(!nation_can_attack(townPtr->nation_recno)) // cannot attack this nation clearToDetect++; } break; case ACTION_ATTACK_WALL: locPtr = world.get_loc(action_x_loc2, action_y_loc2); if(!locPtr->is_wall() || !nation_can_attack(locPtr->power_nation_recno)) clearToDetect++; break; default: clearToDetect++; break; } //------------------------------------------------------------------------------// // suitation changed to defensive detecting mode //------------------------------------------------------------------------------// if(clearToDetect) { //----------------------------------------------------------// // target is dead, change to detect state for another target //----------------------------------------------------------// reset_action_para(); return 1; } else if(waiting_term<ATTACK_WAITING_TERM) waiting_term++; else { //------------------------------------------------------------------------------// // process the corresponding attacking procedure. //------------------------------------------------------------------------------// waiting_term = 0; switch(action_mode) { case ACTION_ATTACK_UNIT: err_when(unit_array.is_deleted(action_para2) || !unitPtr); spriteInfo = unitPtr->sprite_info; //-----------------------------------------------------------------// // attack the target if able to reach the target surrounding, otherwise // continue to wait //-----------------------------------------------------------------// action_x_loc2 = unitPtr->next_x_loc(); // update target location action_y_loc2 = unitPtr->next_y_loc(); if(space_for_attack(action_x_loc2, action_y_loc2, unitPtr->mobile_type, spriteInfo->loc_width, spriteInfo->loc_height)) attack_unit(unitPtr->sprite_recno); break; case ACTION_ATTACK_FIRM: err_when(firm_array.is_deleted(action_para2) || !firmPtr); firmInfo = firm_res[firmPtr->firm_id]; //-----------------------------------------------------------------// // attack the target if able to reach the target surrounding, otherwise // continue to wait //-----------------------------------------------------------------// attack_firm(action_x_loc2, action_y_loc2); if(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, action_x_loc2, action_y_loc2, firmInfo->loc_width, firmInfo->loc_height)) waiting_term = 0; break; case ACTION_ATTACK_TOWN: err_when(town_array.is_deleted(action_para2) || !townPtr); //-----------------------------------------------------------------// // attack the target if able to reach the target surrounding, otherwise // continue to wait //-----------------------------------------------------------------// attack_town(action_x_loc2, action_y_loc2); if(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, action_x_loc2, action_y_loc2, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT)) waiting_term = 0; break; case ACTION_ATTACK_WALL: err_when(action_para || action_para2); attack_wall(action_x_loc2, action_y_loc2); if(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, action_x_loc2, action_y_loc2, 1, 1)) waiting_term = 0; break; default: err_here(); break; } } return 0; }