/* * Seven Kingdoms: Ancient Adversaries * * Copyright 1997,1998 Enlight Software Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ //Filename : OUNITAT2.CPP //Description : Object Unit attack processing function //Owner : Alex #include #include #include #include #include #include #include #include #include #include #include #ifdef NO_DEBUG_UNIT #undef err_when #undef err_here #undef err_if #undef err_else #undef err_now #define err_when(cond) #define err_here() #define err_if(cond) #define err_else #define err_now(msg) #undef DEBUG #endif //--------- Begin of function Unit::attack_unit ---------// // overloaded function. // the unit calling this function is to attack target by (1) default // ordering or by (2) defense mode // // Note : (targetXLoc, targetYLoc) should be the upper left corner // location of the target // // targetXLoc - target x location // targetYLoc - target y location // xOffset, yOffset - offset location to (targetXLoc, targetYLoc) // resetBlockedEdge - reset blocked_edge if true // void Unit::attack_unit(int targetXLoc, int targetYLoc, int xOffset, int yOffset, int resetBlockedEdge) { Location* locPtr = world.get_loc(targetXLoc, targetYLoc); //--- AI attacking a nation which its NationRelation::should_attack is 0 ---// int targetNationRecno = 0; if( locPtr->has_unit(UNIT_LAND) ) { Unit* unitPtr = unit_array[ locPtr->unit_recno(UNIT_LAND) ]; if( unitPtr->unit_id != UNIT_EXPLOSIVE_CART ) // attacking own porcupine is allowed targetNationRecno = unitPtr->nation_recno; } else if( locPtr->is_firm() ) { targetNationRecno = firm_array[locPtr->firm_recno()]->nation_recno; } else if( locPtr->is_town() ) { targetNationRecno = town_array[locPtr->town_recno()]->nation_recno; } if( nation_recno && targetNationRecno ) { if( nation_array[nation_recno]->get_relation(targetNationRecno)->should_attack==0 ) return; } //------------------------------------------------------------// // return if this unit cannot do the attack action, or die //------------------------------------------------------------// if(!can_attack()) { stop2(KEEP_DEFENSE_MODE); return; } else if(is_unit_dead()) return; err_when(!can_attack()); locPtr = world.get_loc(targetXLoc, targetYLoc); err_when(!locPtr); char targetMobileType = (next_x_loc()==targetXLoc && next_y_loc()==targetYLoc) ? locPtr->has_any_unit(mobile_type) : locPtr->has_any_unit(); if(targetMobileType) { Unit *targetUnit = unit_array[locPtr->unit_recno(targetMobileType)]; attack_unit(targetUnit->sprite_recno, xOffset, yOffset, resetBlockedEdge); } //------ set ai_original_target_?_loc --------// if( ai_unit ) { ai_original_target_x_loc = targetXLoc; ai_original_target_y_loc = targetYLoc; } } //----------- End of function Unit::attack_unit -----------// //--------- Begin of function Unit::attack_unit ---------// // overloaded function, // // targetRecno - target recno // xOffset, yOffset - offset location to (targetXLoc, targetYLoc) // resetBlockedEdge - reset blocked_edge if true // void Unit::attack_unit(short targetRecno, int xOffset, int yOffset, int resetBlockedEdge) { //------------------------------------------------------------// // return if this unit cannot do the attack action, or die //------------------------------------------------------------// if(!can_attack()) { stop2(KEEP_DEFENSE_MODE); return; } else if(is_unit_dead()) return; err_when(!can_attack()); //----------------------------------------------------------------------------------// // Note for non-air unit, // 1) If target's mobile type == mobile_type and thir territory id are different, // call move_to() instead of attacking. // 2) In the case, this unit is a land unit and the target is a sea unit, skip // checking for range attacking. It is because the ship may be in the coast side // there this unit can attack it by close attack. In other cases, a unit without // the ability of doing range attacking cannot attack target with different mobile // type to its. // 3) If the region_id of the target located is same as that of thus unit located, // order this unit to move to it and process attacking // 4) If the unit can't reach a location there it can do range attack, call move_to() // rather than resume the action. The reason not to resume the action, even though // the unit reach a location there can do range attack later, is that the action // will be resumed in function idle_detect_target() //----------------------------------------------------------------------------------// int curXLoc = next_x_loc(); int curYLoc = next_y_loc(); err_when(unit_array.is_deleted(targetRecno)); Unit *targetUnit = unit_array[targetRecno]; char targetMobileType = targetUnit->mobile_type; int targetXLoc = targetUnit->next_x_loc(); int targetYLoc = targetUnit->next_y_loc(); int diffTerritoryAttack = 0, maxRange=0; Location *locPtr = world.get_loc(targetUnit->next_x_loc(), targetUnit->next_y_loc()); err_when(!locPtr); if(targetMobileType && mobile_type!=UNIT_AIR) // air unit can move to anywhere { //------------------------------------------------------------------------// // return if not feasible condition //------------------------------------------------------------------------// if((mobile_type!=UNIT_LAND || targetMobileType!=UNIT_SEA) && mobile_type!=targetMobileType) { if(!can_attack_different_target_type()) { //-************ improve later **************-// //-******** should escape from being attacked ********-// if(in_any_defense_mode()) general_defend_mode_detect_target(); return; } } //------------------------------------------------------------------------// // handle the case the unit and the target are in different territory //------------------------------------------------------------------------// if(world.get_loc(curXLoc, curYLoc)->region_id!=locPtr->region_id) { maxRange = max_attack_range(); Unit *unitPtr = unit_array[locPtr->unit_recno(targetMobileType)]; if(!possible_place_for_range_attack(targetXLoc, targetYLoc, unitPtr->sprite_info->loc_width, unitPtr->sprite_info->loc_height, maxRange)) { if(action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET) move_to(targetXLoc, targetYLoc); else // in defend mode, but unable to attack target general_defend_mode_detect_target(1); return; } else // can reach diffTerritoryAttack = 1; } } //------------------------------------------------------------// // no unit there //------------------------------------------------------------// if(!targetMobileType) { if(action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET || action_mode2==ACTION_DEFEND_TOWN_ATTACK_TARGET || action_mode2==ACTION_MONSTER_DEFEND_ATTACK_TARGET) { stop2(KEEP_DEFENSE_MODE); err_when((action_mode2!=ACTION_AUTO_DEFENSE_DETECT_TARGET || action_para2!=AUTO_DEFENSE_DETECT_COUNT) && (action_mode2!=ACTION_DEFEND_TOWN_DETECT_TARGET || action_para2!=UNIT_DEFEND_TOWN_DETECT_COUNT) && (action_mode2!=ACTION_MONSTER_DEFEND_DETECT_TARGET || action_para2!=MONSTER_DEFEND_DETECT_COUNT)); } err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(action_mode==ACTION_ATTACK_UNIT || action_para || action_x_loc!=-1 || action_y_loc!=-1); return; } //------------------------------------------------------------// // cannot attack this nation //------------------------------------------------------------// err_when(targetUnit->next_x_loc()!=targetXLoc || targetUnit->next_y_loc()!=targetYLoc); if(!nation_can_attack(targetUnit->nation_recno) && targetUnit->unit_id!=UNIT_EXPLOSIVE_CART) { stop2(KEEP_DEFENSE_MODE); err_when(action_mode==ACTION_ATTACK_UNIT && !action_para); err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); return; } //----------------------------------------------------------------// // action_mode2: checking for equal action or idle action //----------------------------------------------------------------// if((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) && action_para2==targetUnit->sprite_recno && action_x_loc2==targetXLoc && action_y_loc2==targetYLoc) { //------------ old order ------------// err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(action_mode==ACTION_ATTACK_UNIT && !action_para); if(cur_action!=SPRITE_IDLE) { //------- the old order is processing, return -------// #ifdef DEBUG if(action_mode==ACTION_ATTACK_UNIT) { 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_para!=action_para2 || action_x_loc!=action_x_loc2 || action_y_loc!=action_y_loc2); } else err_when(action_mode!=ACTION_STOP || action_para || action_x_loc!=-1 || action_y_loc!=-1); #endif return; }//else the action becomes idle } else { //-------------- store new order ----------------// if(action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET) action_mode2 = ACTION_ATTACK_UNIT; action_para2 = targetUnit->sprite_recno; action_x_loc2 = targetXLoc; action_y_loc2 = targetYLoc; } //-------------------------------------------------------------// // process new order //-------------------------------------------------------------// stop(); cur_attack = 0; int attackDistance = cal_distance(targetXLoc, targetYLoc, targetUnit->sprite_info->loc_width, targetUnit->sprite_info->loc_height); choose_best_attack_mode(attackDistance, targetMobileType); AttackInfo* attackInfo = attack_info_array+cur_attack; if(attackInfo->attack_range=MAX_WORLD_X_LOC) xLoc = MAX_WORLD_X_LOC-1; if(yLoc<0) yLoc = 0; else if(yLoc>=MAX_WORLD_Y_LOC) yLoc = MAX_WORLD_Y_LOC-1; search(xLoc, yLoc, 1); // offset location is given, so move there directly } else { //if(mobile_type!=targetMobileType) if(diffTerritoryAttack) { //--------------------------------------------------------------------------------// // 1) different type from target, target located in different territory from this // unit. But able to attack this target by range attacking //--------------------------------------------------------------------------------// move_to_range_attack(targetXLoc, targetYLoc, targetUnit->sprite_id, SEARCH_MODE_ATTACK_UNIT_BY_RANGE, maxRange); } else { //--------------------------------------------------------------------------------// // 1) same type of target, // 2) this unit is air unit, or // 3) different type from target, but target located in the same territory of this // unit. //--------------------------------------------------------------------------------// searchResult = search(targetXLoc, targetYLoc, 1, SEARCH_MODE_TO_ATTACK, targetUnit->sprite_recno); } } //---------------------------------------------------------------// // initialize parameters for blocked edge handling in attacking //---------------------------------------------------------------// if(searchResult) { waiting_term = 0; if(resetBlockedEdge) memset(blocked_edge, 0, sizeof(char)*4); } else memset(blocked_edge, 0xff, sizeof(char)*4); // for reactivating idle action } else if(cur_action==SPRITE_IDLE) // the target is within attack range, attacks it now if the unit is idle { //---------------------------------------------------------------// // attack now //---------------------------------------------------------------// set_cur(next_x, next_y); set_attack_dir(curXLoc, curYLoc, targetXLoc, targetYLoc); if(is_dir_correct()) { if(attackInfo->attack_range==1) { set_attack(); turn_delay = 0; } } else set_turn(); } action_mode = ACTION_ATTACK_UNIT; action_para = targetUnit->sprite_recno; action_x_loc = targetXLoc; action_y_loc = targetYLoc; //------ set ai_original_target_?_loc --------// if( ai_unit ) { ai_original_target_x_loc = targetXLoc; ai_original_target_y_loc = targetYLoc; } err_when(action_mode==ACTION_ATTACK_UNIT && !action_para); err_when(action_mode!=action_mode2 && action_mode!=ACTION_ATTACK_UNIT); err_when(action_para!=action_para2 || !action_para); err_when(action_x_loc!=action_x_loc2 || action_y_loc!=action_y_loc2); } //----------- End of function Unit::attack_unit -----------// //--------- Begin of function Unit::process_attack_unit ---------// // process the action to attack a unit // void Unit::process_attack_unit() { if(!can_attack()) { stop2(KEEP_DEFENSE_MODE); return; } err_when(!action_para || action_mode!=ACTION_ATTACK_UNIT || !can_attack()); // unable to attack // ###### begin Gilbert 17/3 #######// //err_when(attack_info_array[cur_attack].attack_range != attack_range); // ###### end Gilbert 17/3 #######// //--------------------------------------------------------------------------// // stop if the targeted unit has been killed or target belongs our nation //--------------------------------------------------------------------------// int clearOrder = 0; Unit* targetUnit; if(unit_array.is_deleted(action_para) || action_para==sprite_recno) clearOrder++; else { targetUnit = unit_array[action_para]; if(targetUnit->nation_recno && !nation_can_attack(targetUnit->nation_recno) && targetUnit->unit_id!=UNIT_EXPLOSIVE_CART) // cannot attack this nation clearOrder++; } if(clearOrder) { //------------------------------------------------------------// // change to detect target if in defense mode //------------------------------------------------------------// /*if(action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET || action_mode2==ACTION_DEFEND_TOWN_ATTACK_TARGET || action_mode2==ACTION_MONSTER_DEFEND_ATTACK_TARGET) { stop2(KEEP_DEFENSE_MODE); err_when((action_misc!=ACTION_MISC_DEFENSE_CAMP_RECNO && action_misc!=ACTION_MISC_DEFEND_TOWN_RECNO && action_misc!=ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO) || !action_misc_para); return; } stop2(); // clear order err_when(cur_action==SPRITE_ATTACK && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc())); err_when(action_mode==ACTION_ATTACK_UNIT && !action_para); err_when(cur_action==SPRITE_ATTACK && action_mode==ACTION_STOP); return;*/ #ifdef DEBUG int inDefMode = in_any_defense_mode(); #endif stop2(KEEP_DEFENSE_MODE); #ifdef DEBUG if(inDefMode) { err_when((action_misc!=ACTION_MISC_DEFENSE_CAMP_RECNO && action_misc!=ACTION_MISC_DEFEND_TOWN_RECNO && action_misc!=ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO) || !action_misc_para); } #endif err_when(cur_action==SPRITE_ATTACK && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc())); err_when(action_mode==ACTION_ATTACK_UNIT && !action_para); err_when(cur_action==SPRITE_ATTACK && action_mode==ACTION_STOP); return; } err_when(ai_unit && nation_recno== targetUnit->nation_recno); // ai_unit don't attack itself, but players can //--------------------------------------------------------------------------// // stop action if target goes into town/firm, ships (go to other territory) //--------------------------------------------------------------------------// if(!targetUnit->is_visible()) { stop2(KEEP_DEFENSE_MODE); // clear order err_when(action_mode==ACTION_ATTACK_UNIT && !action_para); err_when(cur_action==SPRITE_ATTACK && action_mode==ACTION_STOP); return; } //------------------------------------------------------------// // if the caravan is entered a firm, attack the firm //------------------------------------------------------------// if(targetUnit->caravan_in_firm()) { //----- for caravan entering the market -------// err_when(targetUnit->unit_id!=UNIT_CARAVAN); if(firm_array.is_deleted(targetUnit->action_para)) // the current firm recno of the firm the caravan entered is stored in action_para stop2(KEEP_DEFENSE_MODE); // clear order else { Firm* firmPtr = firm_array[targetUnit->action_para]; attack_firm(firmPtr->loc_x1, firmPtr->loc_y1); } err_when(action_mode==ACTION_ATTACK_UNIT && !action_para); return; } //---------------- define parameters ---------------------// int targetXLoc = targetUnit->next_x_loc(); int targetYLoc = targetUnit->next_y_loc(); int spriteXLoc = next_x_loc(); int spriteYLoc = next_y_loc(); AttackInfo* attackInfo = attack_info_array+cur_attack; //----------------------------------------------------// #ifdef DEBUG short x, y, h, w; SpriteInfo* targetSpriteInfo = targetUnit->sprite_info; for(h=0, y=spriteYLoc; hloc_height; h++, y++) { for(w=0, x=spriteXLoc; wloc_width; w++, x++) err_when(world.get_unit_recno(x,y,mobile_type)!=sprite_recno); } for(h=0, y=targetYLoc; hloc_height; h++, y++) { for(w=0, x=targetXLoc; wloc_width; w++, x++) err_when(world.get_unit_recno(x,y,targetUnit->mobile_type)!=targetUnit->sprite_recno); } #endif //------------------------------------------------------------// // If this unit's target has moved, change the destination accordingly. //------------------------------------------------------------// if( targetXLoc != action_x_loc || targetYLoc != action_y_loc ) { target_move(targetUnit); if(action_mode==ACTION_STOP) return; } //-----------------------------------------------------// // If the unit is currently attacking somebody. //-----------------------------------------------------// //if( cur_action==SPRITE_ATTACK && next_x==cur_x && next_y==cur_y) if(abs(cur_x-next_x)<=sprite_info->speed && abs(cur_y-next_y)<=sprite_info->speed) { if(cur_action==SPRITE_ATTACK) { err_when(!is_dir_correct()); //###### begin alex 18/3 #######// err_when(attack_info_array[cur_attack].attack_range != attack_range); //###### end alex 18/3 #######// attack_target(targetUnit); } else { //-----------------------------------------------------// // If the unit is on its way to attack somebody and it // has got close next to the target, attack now //-----------------------------------------------------// #ifdef DEBUG if(on_way_to_attack(targetUnit)) return; // skip the following error checking #else on_way_to_attack(targetUnit); #endif } } err_when(action_mode==ACTION_ATTACK_UNIT && !action_para); err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(cur_action==SPRITE_ATTACK && attack_range==1 && cal_distance(targetXLoc, targetYLoc, targetUnit->sprite_info->loc_width, targetUnit->sprite_info->loc_height)>1); } //---------- End of function Unit::process_attack_unit ----------// //--------- Begin of function Unit::target_move ---------// // called by process_attack_unit when the target is moved // // targetUnit - pointer to the target // void Unit::target_move(Unit* targetUnit) { //------------------------------------------------------------------------------------// // chekcing whether ship can follow to attack target. It is always true if the unit is // not ship. 1 for allowing, 0 otherwise //------------------------------------------------------------------------------------// int allowMove = 1; if(sprite_info->sprite_sub_type=='M') { UnitInfo* unitInfo = unit_res[unit_id]; if(unitInfo->carry_goods_capacity) { UnitMarine *shipPtr = (UnitMarine*) this; if(shipPtr->auto_mode && shipPtr->stop_defined_num>1) allowMove = 0; } } //---------------------------------------------------------// int targetXLoc = targetUnit->next_x_loc(); int targetYLoc = targetUnit->next_y_loc(); SpriteInfo *targetSpriteInfo = targetUnit->sprite_info; int attackDistance = cal_distance(targetXLoc, targetYLoc, targetSpriteInfo->loc_width, targetSpriteInfo->loc_height); action_x_loc2 = action_x_loc = targetXLoc; // update target location action_y_loc2 = action_y_loc = targetYLoc; //---------------------------------------------------------------------// // target is out of attacking range, move closer to it //---------------------------------------------------------------------// int curXLoc = next_x_loc(); int curYLoc = next_y_loc(); if(attackDistance>attack_range) { //---------------- stop all actions if not allow to move -----------------// if(!allowMove) { stop2(); return; } err_when(action_mode!=ACTION_ATTACK_UNIT || action_para!=targetUnit->sprite_recno); //---------------------------------------------------------------------// // follow the target using the result_path_dist //---------------------------------------------------------------------// if(!update_attack_path_dist()) { if(cur_action==SPRITE_MOVE || cur_action==SPRITE_WAIT || cur_action==SPRITE_READY_TO_MOVE) return; } if(move_try_to_range_attack(targetUnit)) { err_when(action_x_loc!=targetXLoc || action_y_loc!=targetYLoc); //-----------------------------------------------------------------------// // reset attack parameters //-----------------------------------------------------------------------// range_attack_x_loc = range_attack_y_loc = -1; err_when(action_mode!=ACTION_ATTACK_UNIT); err_when(action_para!=targetUnit->sprite_recno); choose_best_attack_mode(attackDistance, targetUnit->mobile_type); // choose better attack mode to attack the target err_when(attackDistance>attack_range && cur_action==SPRITE_ATTACK); } } else // attackDistance <= attack_range { //-----------------------------------------------------------------------------// // although the target has moved, the unit can still attack it. no need to move //-----------------------------------------------------------------------------// if(abs(cur_x-next_x)>=sprite_info->speed || abs(cur_y-next_y)>=sprite_info->speed) return; // return as moving if(attackDistance==1 && attack_range>1) // may change attack mode choose_best_attack_mode(attackDistance, targetUnit->mobile_type); if(attack_range>1) // range attack { //------------------ do range attack ----------------------// AttackInfo *attackInfo = attack_info_array + cur_attack; if(bullet_array.add_bullet_possible(curXLoc, curYLoc, mobile_type, targetXLoc, targetYLoc, targetUnit->mobile_type, targetSpriteInfo->loc_width, targetSpriteInfo->loc_height, range_attack_x_loc, range_attack_y_loc, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) // range attack possible { set_cur(next_x, next_y); err_when(range_attack_x_loc==-1 || range_attack_y_loc==-1); set_attack_dir(curXLoc, curYLoc, range_attack_x_loc, range_attack_y_loc); #ifdef AMPLUS cycle_eqv_attack(); attackInfo = attack_info_array + cur_attack; // cur_attack may change #endif cur_frame = 1; if(is_dir_correct()) set_attack(); else set_turn(); } else // unable to do range attack, move to target { err_when(range_attack_x_loc!=-1 || range_attack_y_loc!=-1); if(!allowMove) { stop2(); return; } if(move_try_to_range_attack(targetUnit)) { err_when(action_x_loc!=targetXLoc || action_y_loc!=targetYLoc); //range_attack_x_loc = range_attack_y_loc = -1; err_when(action_mode!=ACTION_ATTACK_UNIT); err_when(action_para!=targetUnit->sprite_recno); } } } else if(attackDistance==1) // close attack { err_when(attack_range>1); set_cur(next_x, next_y); set_attack_dir(curXLoc, curYLoc, targetXLoc, targetYLoc); cur_frame = 1; if(is_dir_correct()) set_attack(); else set_turn(); } } } //---------- End of function Unit::target_move ----------// //----------------- Begin of function Unit::attack_target -----------------// // called by process_attack_unit when the unit is now attacking the target // // targetUnit - pointer to target unit // void Unit::attack_target(Unit* targetUnit) { err_when(cur_x!=next_x || cur_y!=next_y); err_when(action_mode==ACTION_ATTACK_UNIT && !action_para); err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(!is_dir_correct()); if(remain_attack_delay) return; int unitXLoc = next_x_loc(); int unitYLoc = next_y_loc(); if(attack_range>1) // use range attack { //---------------- use range attack -----------------// AttackInfo *attackInfo = attack_info_array+cur_attack; if(cur_frame!=attackInfo->bullet_out_frame) return; // wait for bullet_out_frame if(!bullet_array.bullet_path_possible(unitXLoc, unitYLoc, mobile_type, range_attack_x_loc, range_attack_y_loc, targetUnit->mobile_type, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) { SpriteInfo *targetSpriteInfo = targetUnit->sprite_info; if((targetSpriteInfo->loc_width>1 || targetSpriteInfo->loc_height>1) && !bullet_array.add_bullet_possible(unitXLoc, unitYLoc, mobile_type, action_x_loc, action_y_loc, targetUnit->mobile_type, targetSpriteInfo->loc_width, targetSpriteInfo->loc_height, range_attack_x_loc, range_attack_y_loc, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) // seek for another possible point to attack if target size > 1x1 { //------ no suitable location to attack target by bullet, move to target --------// if(!result_node_array || !result_node_count || !result_path_dist) if(!move_try_to_range_attack(targetUnit)) return; // can't reach a location to attack target err_when(action_x_loc!=targetUnit->next_x_loc() || action_y_loc!=targetUnit->next_y_loc()); err_when(action_mode!=ACTION_ATTACK_UNIT); err_when(action_para!=targetUnit->sprite_recno); } } bullet_array.add_bullet(this, targetUnit); // ####### begin Gilbert 14/7 ########// add_close_attack_effect(); // ####### end Gilbert 14/7 ########// // ------- reduce power --------// cur_power -= attackInfo->consume_power; err_when(cur_power < 0); //### begin alex 28/10 ###// if(cur_power<0) // ***** BUGHERE cur_power = 0; //#### end alex 28/10 ####// set_remain_attack_delay(); return; // bullet emits } else // close attack { //--------------------- close attack ------------------------// AttackInfo *attackInfo = attack_info_array+cur_attack; err_when(action_x_loc!=action_x_loc2 || action_y_loc!=action_y_loc2); err_when((unitXLoc!=action_x_loc || unitYLoc!=action_y_loc) && final_dir!=(get_dir(unitXLoc, unitYLoc, action_x_loc, action_y_loc))); if(cur_frame==cur_sprite_attack()->frame_count) { if(targetUnit->unit_id == UNIT_EXPLOSIVE_CART && targetUnit->is_nation(nation_recno)) ((UnitExpCart *)targetUnit)->trigger_explode(); else hit_target(this, targetUnit, actual_damage()); // ####### begin Gilbert 14/7 ########// add_close_attack_effect(); // ####### end Gilbert 14/7 ########// //------- reduce power --------// cur_power -= attackInfo->consume_power; err_when(cur_power < 0); //### begin alex 28/10 ###// if(cur_power<0) // ***** BUGHERE cur_power = 0; //#### end alex 28/10 ####// set_remain_attack_delay(); } } } //------------------ End of function Unit::attack_target ------------------// //--------- Begin of function Unit::on_way_to_attack ---------// // called by process_attack_unit when the unit is still on its // way to attack the target. // // return 1 if new target is detected // return 0 otherwise // // targetUnit - pointer to target Unit // int Unit::on_way_to_attack(Unit* targetUnit) { err_when(abs(cur_x-next_x)>sprite_info->speed || abs(cur_y-next_y)>sprite_info->speed); err_when(cur_action==SPRITE_ATTACK); if(mobile_type==UNIT_LAND) { if(attack_range==1) { //------------------------------------------------------------// // for close attack, the unit unable to attack the target if // it is not in the target surrounding //------------------------------------------------------------// if(result_path_dist > attack_range) return detect_surround_target(); } else if(result_path_dist && cur_action!=SPRITE_TURN) { if(detect_surround_target()) return 1; // detect surrounding target while walking } } int targetXLoc = targetUnit->next_x_loc(); int targetYLoc = targetUnit->next_y_loc(); SpriteInfo* targetSpriteInfo = targetUnit->sprite_info; int attackDistance = cal_distance(targetXLoc , targetYLoc, targetSpriteInfo->loc_width, targetSpriteInfo->loc_height); if(attackDistance<=attack_range) // able to attack target { if((attackDistance==1) && attack_range>1) // often false condition is checked first choose_best_attack_mode(1, targetUnit->mobile_type); // may change to close attack if(attack_range>1) // use range attack { set_cur(next_x, next_y); AttackInfo *attackInfo = attack_info_array+cur_attack; int curXLoc = next_x_loc(); int curYLoc = next_y_loc(); if(!bullet_array.add_bullet_possible(curXLoc, curYLoc, mobile_type, targetXLoc, targetYLoc, targetUnit->mobile_type, targetSpriteInfo->loc_width, targetSpriteInfo->loc_height, range_attack_x_loc, range_attack_y_loc, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) { //------- no suitable location, move to target ---------// if(!result_node_array || !result_node_count || !result_path_dist) if(!move_try_to_range_attack(targetUnit)) return 0; // can't reach a location to attack target err_when(action_mode!=ACTION_ATTACK_UNIT || action_para!=targetUnit->sprite_recno); return 0; } //---------- able to do range attack ----------// err_when(range_attack_x_loc==-1 || range_attack_y_loc==-1); set_attack_dir(next_x_loc(), next_y_loc(), range_attack_x_loc, range_attack_y_loc); cur_frame = 1; if(is_dir_correct()) set_attack(); else set_turn(); } else // close attack { //---------- attack now ---------// set_cur(next_x, next_y); terminate_move(); err_when(cur_frame!=1); set_attack_dir(next_x_loc(), next_y_loc(), targetXLoc, targetYLoc); if(is_dir_correct()) set_attack(); else set_turn(); } err_when(cur_x!=next_x || cur_y!=next_y); } return 0; } //---------- End of function Unit::on_way_to_attack ----------// //--------- Begin of function Unit::detect_surround_target ---------// // This function is used to detect enemy in the surrounding of the unit // // return 1 if target is detected // return 0 otherwise // int Unit::detect_surround_target() { #define DIMENSION 3 #define CHECK_SIZE DIMENSION*DIMENSION int curXLoc = next_x_loc(); int curYLoc = next_y_loc(); int checkXLoc, checkYLoc, xShift, yShift; Unit *targetPtr; Location *locPtr; short targetRecno; for(int i=2; i<=CHECK_SIZE; ++i) { m.cal_move_around_a_point(i, DIMENSION, DIMENSION, xShift, yShift); checkXLoc = curXLoc+xShift; checkYLoc = curYLoc+yShift; if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC) continue; locPtr = world.get_loc(checkXLoc, checkYLoc); if(locPtr->has_unit(UNIT_LAND)) { targetRecno = locPtr->unit_recno(UNIT_LAND); if(unit_array.is_deleted(targetRecno)) continue; targetPtr = unit_array[targetRecno]; if(targetPtr->nation_recno==nation_recno) continue; if(idle_detect_unit_checking(targetRecno)) { attack_unit(targetRecno); return 1; } } } return 0; } //---------- End of function Unit::detect_surround_target ----------// //--------- Begin of function Unit::attack_firm ---------// // the unit calling this function is to attack target by (1) default // ordering or by (2) defense mode // // Note : (firmXLoc, firmYLoc) should be the upper left corner location // of the firm. // // firmXLoc - x location of the firm // firmYLoc - y location of the firm // xOffset - x offset to the firm // yOffset - y offset to the firm // resetBlockedEdge - flag to variable blocked_edge // void Unit::attack_firm(int firmXLoc, int firmYLoc, int xOffset, int yOffset, int resetBlockedEdge) { //------------------------------------------------------------// // return if this unit cannot do the attack action //------------------------------------------------------------// if(!can_attack()) { stop2(KEEP_DEFENSE_MODE); return; } else if(is_unit_dead()) return; err_when(!can_attack()); Location *locPtr = world.get_loc(firmXLoc, firmYLoc); err_when(!locPtr); //------------------------------------------------------------// // no firm there //------------------------------------------------------------// if(!locPtr->is_firm()) { if(action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET || action_mode2==ACTION_DEFEND_TOWN_ATTACK_TARGET || action_mode2==ACTION_MONSTER_DEFEND_ATTACK_TARGET) { stop2(KEEP_DEFENSE_MODE); err_when((action_mode2!=ACTION_AUTO_DEFENSE_DETECT_TARGET || action_para2!=AUTO_DEFENSE_DETECT_COUNT) && (action_mode2!=ACTION_DEFEND_TOWN_DETECT_TARGET || action_para2!=UNIT_DEFEND_TOWN_DETECT_COUNT) && (action_mode2!=ACTION_MONSTER_DEFEND_DETECT_TARGET || action_para2!=MONSTER_DEFEND_DETECT_COUNT)); } err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(action_mode==ACTION_ATTACK_FIRM || action_para || action_x_loc!=-1 || action_y_loc!=-1); return; } //------------------------------------------------------------// // cannot attack this nation //------------------------------------------------------------// Firm *firmPtr = firm_array[locPtr->firm_recno()]; err_when(firmPtr->loc_x1!=firmXLoc || firmPtr->loc_y1!=firmYLoc); if(!nation_can_attack(firmPtr->nation_recno)) { stop2(KEEP_DEFENSE_MODE); err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(action_mode==ACTION_ATTACK_FIRM && !action_para); return; } //------------------------------------------------------------------------------------// // move there if cannot reach the effective attacking region //------------------------------------------------------------------------------------// int diffTerritoryAttack = 0, maxRange=0; if(mobile_type!=UNIT_AIR && world.get_loc(next_x_loc(), next_y_loc())->region_id!=locPtr->region_id) { maxRange = max_attack_range(); //Firm *firmPtr = firm_array[locPtr->firm_recno()]; FirmInfo *firmInfo = firm_res[firmPtr->firm_id]; if(!possible_place_for_range_attack(firmXLoc, firmYLoc, firmInfo->loc_width, firmInfo->loc_height, maxRange)) { if(action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET) move_to(firmXLoc, firmYLoc); return; } else // can reach diffTerritoryAttack = 1; } //----------------------------------------------------------------// // action_mode2: checking for equal action or idle action //----------------------------------------------------------------// if((action_mode2==ACTION_ATTACK_FIRM || action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET || action_mode2==ACTION_DEFEND_TOWN_ATTACK_TARGET || action_mode2==ACTION_MONSTER_DEFEND_ATTACK_TARGET) && action_para2==firmPtr->firm_recno && action_x_loc2==firmXLoc && action_y_loc2==firmYLoc) { //-------------- old order -------------// err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(action_mode==ACTION_ATTACK_FIRM && !action_para); if(cur_action!=SPRITE_IDLE) { //------- old order is processing --------// #ifdef DEBUG if(action_mode==ACTION_ATTACK_FIRM) { err_when(action_mode2!=ACTION_ATTACK_FIRM && action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET); err_when(action_para!=action_para2 || action_x_loc!=action_x_loc2 || action_y_loc!=action_y_loc2); } else err_when(action_mode!=ACTION_STOP || action_para || action_x_loc!=-1 || action_y_loc!=-1); #endif return; } } else { //-------------- new order -------------// if(action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET) action_mode2 = ACTION_ATTACK_FIRM; action_para2 = firmPtr->firm_recno; action_x_loc2 = firmXLoc; action_y_loc2 = firmYLoc; } //-------------------------------------------------------------// // process new order //-------------------------------------------------------------// stop(); cur_attack = 0; int defenseMode = in_auto_defense_mode(); if(defenseMode) set_search_tries(AUTO_DEFENSE_SEARCH_TRIES); FirmInfo *firmInfo = firm_res[firmPtr->firm_id]; int attackDistance = cal_distance(firmXLoc, firmYLoc, firmInfo->loc_width, firmInfo->loc_height); choose_best_attack_mode(attackDistance); AttackInfo* attackInfo = attack_info_array+cur_attack; if(attackInfo->attack_range=MAX_WORLD_X_LOC) xLoc = MAX_WORLD_X_LOC-1; if(yLoc<0) yLoc = 0; else if(yLoc>=MAX_WORLD_Y_LOC) yLoc = MAX_WORLD_Y_LOC-1; search(xLoc, yLoc, 1); // offset location is given, so move there directly } else // without offset given, so call set_move_to_surround() { if(diffTerritoryAttack) { //--------------------------------------------------------------------------------// // 1) different type from target, target located in different territory from this // unit. But able to attack this target by range attacking //--------------------------------------------------------------------------------// move_to_range_attack(firmXLoc, firmYLoc, firmPtr->firm_id, SEARCH_MODE_ATTACK_FIRM_BY_RANGE, maxRange); } else { //--------------------------------------------------------------------------------// // 1) same type of target, // 2) this unit is air unit, or // 3) different type from target, but target located in the same territory of this // unit. //--------------------------------------------------------------------------------// searchResult = set_move_to_surround(firmXLoc, firmYLoc, firmInfo->loc_width, firmInfo->loc_height, BUILDING_TYPE_FIRM_MOVE_TO, 0, 0); } } //---------------------------------------------------------------// // initialize parameters for blocked edge handling in attacking //---------------------------------------------------------------// if(searchResult) { waiting_term = 0; if(resetBlockedEdge) memset(blocked_edge, 0, sizeof(char)*4); } else memset(blocked_edge, 0xff, sizeof(char)*4); // for reactivating idle action } else if(cur_action==SPRITE_IDLE) { //---------------------------------------------------------------// // attack now //---------------------------------------------------------------// set_cur(next_x, next_y); if(firmPtr->firm_id!=FIRM_RESEARCH) set_attack_dir(next_x_loc(), next_y_loc(), firmPtr->center_x, firmPtr->center_y); else // FIRM_RESEARCH with size 2x3 { int curXLoc = next_x_loc(); int curYLoc = next_y_loc(); int hitXLoc = (curXLoc > firmPtr->loc_x1) ? firmPtr->loc_x2 : firmPtr->loc_x1; int hitYLoc; if(curYLoc < firmPtr->center_y) hitYLoc = firmPtr->loc_y1; else if(curYLoc == firmPtr->center_y) hitYLoc = firmPtr->center_y; else hitYLoc = firmPtr->loc_y2; set_attack_dir(curXLoc, curYLoc, hitXLoc, hitYLoc); } if(is_dir_correct()) { if(attackInfo->attack_range==1) set_attack(); //else range_attack is processed in calling process_attack_firm() } else set_turn(); } action_mode = ACTION_ATTACK_FIRM; action_para = firmPtr->firm_recno; action_x_loc = firmXLoc; action_y_loc = firmYLoc; if(defenseMode) reset_search_tries(); err_when(action_mode==ACTION_ATTACK_FIRM && action_para==0); err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(action_mode!=action_mode2 && action_mode!=ACTION_ATTACK_FIRM); err_when(action_para!=action_para2 || !action_para); err_when(action_x_loc!=action_x_loc2 || action_y_loc!=action_y_loc2); } //----------- End of function Unit::attack_firm -----------// //--------- Begin of function Unit::process_attack_firm ---------// // // Called by pre_process(), Unit's own function, not a derived // function of Sprite. // // process attacking firm // void Unit::process_attack_firm() { if(!can_attack()) { stop2(KEEP_DEFENSE_MODE); return; } //------- if the targeted firm has been destroyed --------// err_when(!action_para || action_mode!=ACTION_ATTACK_FIRM || !can_attack()); // unable to attack // ###### begin Gilbert 17/3 #######// //err_when(attack_info_array[cur_attack].attack_range != attack_range); // ###### end Gilbert 17/3 #######// Firm *targetFirm; int clearOrder = 0; //------------------------------------------------------------// // check attack conditions //------------------------------------------------------------// if(firm_array.is_deleted(action_para)) clearOrder++; else { targetFirm = firm_array[action_para]; err_when(!targetFirm || action_para!=targetFirm->firm_recno); err_when(action_x_loc != targetFirm->loc_x1 || action_y_loc != targetFirm->loc_y1); if(!nation_can_attack(targetFirm->nation_recno)) // cannot attack this nation clearOrder++; } if(clearOrder) { //------------------------------------------------------------// // change to detect target if in defend mode //------------------------------------------------------------// /*if(action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET || action_mode2==ACTION_DEFEND_TOWN_ATTACK_TARGET || action_mode2==ACTION_MONSTER_DEFEND_ATTACK_TARGET) { err_when((action_misc!=ACTION_MISC_DEFENSE_CAMP_RECNO && action_misc!=ACTION_MISC_DEFEND_TOWN_RECNO && action_misc!=ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO) || !action_misc_para); stop2(KEEP_DEFENSE_MODE); return; } err_when(action_mode2==ACTION_AUTO_DEFENSE_DETECT_TARGET || action_mode2==ACTION_AUTO_DEFENSE_BACK_CAMP || action_mode2==ACTION_DEFEND_TOWN_DETECT_TARGET || action_mode2==ACTION_DEFEND_TOWN_BACK_TOWN || action_mode2==ACTION_MONSTER_DEFEND_DETECT_TARGET || action_mode2==ACTION_MONSTER_DEFEND_BACK_FIRM); stop2(); // clear order err_when(cur_action==SPRITE_ATTACK && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc())); err_when(action_mode==ACTION_ATTACK_FIRM && !action_para); err_when(cur_action==SPRITE_ATTACK && action_mode==ACTION_STOP); return;*/ #ifdef DEBUG int inDefMode = in_any_defense_mode(); #endif stop2(KEEP_DEFENSE_MODE); #ifdef DEBUG if(inDefMode) { err_when((action_misc!=ACTION_MISC_DEFENSE_CAMP_RECNO && action_misc!=ACTION_MISC_DEFEND_TOWN_RECNO && action_misc!=ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO) || !action_misc_para); } #endif err_when(cur_action==SPRITE_ATTACK && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc())); err_when(action_mode==ACTION_ATTACK_FIRM && !action_para); err_when(cur_action==SPRITE_ATTACK && action_mode==ACTION_STOP); return; } err_when(ai_unit && nation_recno==targetFirm->nation_recno); // ai unit don't attack itself, but players can //-----------------------------------------------------// // If the unit is currently attacking somebody. //-----------------------------------------------------// if(cur_action==SPRITE_ATTACK) { err_when(cur_x!=next_x || cur_y!=next_y || !is_dir_correct()); //###### begin alex 18/3 #######// err_when(attack_info_array[cur_attack].attack_range != attack_range); //###### end alex 18/3 #######// if(remain_attack_delay) return; AttackInfo* attackInfo = attack_info_array+cur_attack; if( attackInfo->attack_range > 1 ) // range attack { //--------- wait for bullet emit ----------// if(cur_frame!=attackInfo->bullet_out_frame) return; //------- seek location to attack by bullet ----------// int curXLoc = next_x_loc(); int curYLoc = next_y_loc(); if(!bullet_array.bullet_path_possible(curXLoc, curYLoc, mobile_type, range_attack_x_loc, range_attack_y_loc, UNIT_LAND, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) { FirmInfo *firmInfo = firm_res[targetFirm->firm_id]; if(!bullet_array.add_bullet_possible(curXLoc, curYLoc, mobile_type, action_x_loc, action_y_loc, UNIT_LAND, firmInfo->loc_width, firmInfo->loc_height, range_attack_x_loc, range_attack_y_loc, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) { //------- no suitable location, so move to target again ---------// set_move_to_surround(action_x_loc, action_y_loc, firmInfo->loc_width, firmInfo->loc_height, BUILDING_TYPE_FIRM_MOVE_TO); err_when(action_mode!=ACTION_ATTACK_FIRM || action_para!=targetFirm->firm_recno); return; } } //--------- add bullet, bullet emits ----------// bullet_array.add_bullet(this, action_x_loc, action_y_loc); // ####### begin Gilbert 14/7 ########// add_close_attack_effect(); // ####### end Gilbert 14/7 ########// // ------- reduce power --------// cur_power -= attackInfo->consume_power; err_when(cur_power < 0); //### begin alex 28/10 ###// if(cur_power<0) // ***** BUGHERE cur_power = 0; //#### end alex 28/10 ####// set_remain_attack_delay(); return; } else // close attack { if(cur_frame!=cur_sprite_attack()->frame_count) return; // is attacking hit_firm(this, action_x_loc, action_y_loc, actual_damage()); // ####### begin Gilbert 14/7 ########// add_close_attack_effect(); // ####### end Gilbert 14/7 ########// // ------- reduce power --------// cur_power -= attackInfo->consume_power; err_when(cur_power < 0); //### begin alex 28/10 ###// if(cur_power<0) // ***** BUGHERE cur_power = 0; //#### end alex 28/10 ####// set_remain_attack_delay(); } } //--------------------------------------------------------------------------------------------------// // If the unit is on its way to attack somebody, if it has gotten close next to the target, attack now //--------------------------------------------------------------------------------------------------// else if(abs(cur_x-next_x)<=sprite_info->speed && abs(cur_y-next_y)<=sprite_info->speed ) // it has moved to the specified location. check cur_x & go_x to make sure the sprite has completely move to the location, not just crossing it. { err_when(cur_action==SPRITE_ATTACK); if(mobile_type==UNIT_LAND) { if(detect_surround_target()) return; } if(attack_range==1) { //------------------------------------------------------------// // for close attack, the unit unable to attack the firm if // it is not in the firm surrounding //------------------------------------------------------------// if(result_path_dist > attack_range) return; } FirmInfo *firmInfo = firm_res[targetFirm->firm_id]; int targetXLoc = targetFirm->loc_x1; int targetYLoc = targetFirm->loc_y1; int attackDistance = cal_distance(targetXLoc , targetYLoc, firmInfo->loc_width, firmInfo->loc_height); int curXLoc = next_x_loc(); int curYLoc = next_y_loc(); if(attackDistance<=attack_range) // able to attack target { if((attackDistance==1) && attack_range>1) // often false condition is checked first choose_best_attack_mode(1); // may change to use close attack if(attack_range>1) // use range attack { set_cur(next_x, next_y); AttackInfo *attackInfo = attack_info_array+cur_attack; if(!bullet_array.add_bullet_possible(curXLoc, curYLoc, mobile_type, targetXLoc, targetYLoc, UNIT_LAND, firmInfo->loc_width, firmInfo->loc_height, range_attack_x_loc, range_attack_y_loc, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) { //------- no suitable location, move to target ---------// if(!result_node_array || !result_node_count) // no step for continue moving set_move_to_surround(action_x_loc, action_y_loc, firmInfo->loc_width, firmInfo->loc_height, BUILDING_TYPE_FIRM_MOVE_TO); err_when(action_mode!=ACTION_ATTACK_FIRM || action_para!=targetFirm->firm_recno); return; // unable to attack, continue to move } //---------- able to do range attack ----------// set_attack_dir(curXLoc, curYLoc, range_attack_x_loc, range_attack_y_loc); cur_frame = 1; if(is_dir_correct()) set_attack(); else set_turn(); } else // close attack { //---------- attack now ---------// set_cur(next_x, next_y); terminate_move(); err_when(cur_frame!=1); if(targetFirm->firm_id!=FIRM_RESEARCH) set_attack_dir(curXLoc, curYLoc, targetFirm->center_x, targetFirm->center_y); else // FIRM_RESEARCH with size 2x3 { int hitXLoc = (curXLoc > targetFirm->loc_x1) ? targetFirm->loc_x2 : targetFirm->loc_x1; int hitYLoc; if(curYLoc < targetFirm->center_y) hitYLoc = targetFirm->loc_y1; else if(curYLoc == targetFirm->center_y) hitYLoc = targetFirm->center_y; else hitYLoc = targetFirm->loc_y2; set_attack_dir(curXLoc, curYLoc, hitXLoc, hitYLoc); } if(is_dir_correct()) set_attack(); else set_turn(); } err_when(cur_x!=next_x || cur_y!=next_y); } } err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); } //----------- End of function Unit::process_attack_firm -----------// //--------- Begin of function Unit::attack_town ---------// // the unit calling this function is to attack target by (1) default // ordering or by (2) defense mode // // Note : (townXLoc, townYLoc) should be the upper left corner location // of the town. // // townXLoc - x location of the town // townYLoc - y location of the town // xOffset - x offset to the town // yOffset - y offset to the town // resetBlockedEdge - flag to reset variable block_edge // void Unit::attack_town(int townXLoc, int townYLoc, int xOffset, int yOffset, int resetBlockedEdge) { //------------------------------------------------------------// // return if this unit cannot do the attack action //------------------------------------------------------------// if(!can_attack()) { stop2(KEEP_DEFENSE_MODE); return; } else if(is_unit_dead()) return; err_when(!can_attack()); Location *locPtr = world.get_loc(townXLoc, townYLoc); err_when(!locPtr); //------------------------------------------------------------// // no town there //------------------------------------------------------------// if(!locPtr->is_town()) { if(action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET || action_mode2==ACTION_DEFEND_TOWN_ATTACK_TARGET || action_mode2==ACTION_MONSTER_DEFEND_ATTACK_TARGET) { stop(KEEP_DEFENSE_MODE); err_when((action_mode2!=ACTION_AUTO_DEFENSE_DETECT_TARGET || action_para2!=AUTO_DEFENSE_DETECT_COUNT) && (action_mode2!=ACTION_DEFEND_TOWN_DETECT_TARGET || action_para2!=UNIT_DEFEND_TOWN_DETECT_COUNT) && (action_mode2!=ACTION_MONSTER_DEFEND_DETECT_TARGET || action_para2!=MONSTER_DEFEND_DETECT_COUNT)); } err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(action_mode==ACTION_ATTACK_TOWN || action_para || action_x_loc!=-1 || action_y_loc!=-1); return; } //------------------------------------------------------------// // cannot attack this nation //------------------------------------------------------------// Town *townPtr = town_array[locPtr->town_recno()]; err_when(townPtr->loc_x1!=townXLoc || townPtr->loc_y1!=townYLoc); if(!nation_can_attack(townPtr->nation_recno)) { stop2(KEEP_DEFENSE_MODE); err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(action_mode==ACTION_ATTACK_FIRM && !action_para); return; } //------------------------------------------------------------------------------------// // move there if cannot reach the effective attacking region //------------------------------------------------------------------------------------// int diffTerritoryAttack = 0, maxRange=0; if(mobile_type!=UNIT_AIR && world.get_loc(next_x_loc(), next_y_loc())->region_id!=locPtr->region_id) { maxRange = max_attack_range(); if(!possible_place_for_range_attack(townXLoc, townYLoc, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, maxRange)) { if(action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode!=ACTION_MONSTER_DEFEND_ATTACK_TARGET) move_to(townXLoc, townYLoc); return; } else // can reach diffTerritoryAttack = 1; } //----------------------------------------------------------------// // action_mode2: checking for equal action or idle action //----------------------------------------------------------------// if((action_mode2==ACTION_ATTACK_TOWN || action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET || action_mode2==ACTION_DEFEND_TOWN_ATTACK_TARGET || action_mode2==ACTION_MONSTER_DEFEND_ATTACK_TARGET) && action_para2==townPtr->town_recno && action_x_loc2==townXLoc && action_y_loc2==townYLoc) { //----------- old order ------------// err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(action_mode==ACTION_ATTACK_TOWN && !action_para); if(cur_action!=SPRITE_IDLE) { //-------- old order is processing -------// #ifdef DEBUG if(action_mode==ACTION_ATTACK_TOWN) { err_when(action_mode2!=ACTION_ATTACK_TOWN && action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET); err_when(action_para!=action_para2 || action_x_loc!=action_x_loc2 || action_y_loc!=action_y_loc2); } else err_when(action_mode!=ACTION_STOP || action_para || action_x_loc!=-1 || action_y_loc!=-1); #endif return; } } else { //------------ new order -------------// if(action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET) action_mode2 = ACTION_ATTACK_TOWN; action_para2 = townPtr->town_recno; action_x_loc2 = townXLoc; action_y_loc2 = townYLoc; } //-------------------------------------------------------------// // process new order //-------------------------------------------------------------// stop(); cur_attack = 0; int attackDistance = cal_distance(townXLoc, townYLoc, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT); choose_best_attack_mode(attackDistance); AttackInfo* attackInfo = attack_info_array+cur_attack; if(attackInfo->attack_range=MAX_WORLD_X_LOC) xLoc = MAX_WORLD_X_LOC-1; if(yLoc<0) yLoc = 0; else if(yLoc>=MAX_WORLD_Y_LOC) yLoc = MAX_WORLD_Y_LOC-1; search(xLoc, yLoc, 1); // offset location is given, so move there directly } else // without offset given, so call set_move_to_surround() { if(diffTerritoryAttack) { //--------------------------------------------------------------------------------// // 1) different type from target, target located in different territory but able to // attack this target by range attacking //--------------------------------------------------------------------------------// move_to_range_attack(townXLoc, townYLoc, 0, SEARCH_MODE_ATTACK_TOWN_BY_RANGE, maxRange); } else { //--------------------------------------------------------------------------------// // 1) same type of target, // 2) this unit is air unit, or // 3) different type from target, but target located in the same territory //--------------------------------------------------------------------------------// searchResult = set_move_to_surround(townXLoc, townYLoc, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, BUILDING_TYPE_TOWN_MOVE_TO, 0, 0); } } //---------------------------------------------------------------// // initialize parameters for blocked edge handling in attacking //---------------------------------------------------------------// if(searchResult) { waiting_term = 0; if(resetBlockedEdge) memset(blocked_edge, 0, sizeof(char)*4); } else memset(blocked_edge, 0xff, sizeof(char)*4); // for reactivating idle action } else if(cur_action==SPRITE_IDLE) { //---------------------------------------------------------------// // attack now //---------------------------------------------------------------// set_cur(next_x, next_y); set_attack_dir(next_x_loc(), next_y_loc(), townPtr->center_x, townPtr->center_y); if(is_dir_correct()) { if(attackInfo->attack_range==1) set_attack(); } else set_turn(); } action_mode = ACTION_ATTACK_TOWN; action_para = townPtr->town_recno; action_x_loc = townXLoc; action_y_loc = townYLoc; err_when(action_mode==ACTION_ATTACK_TOWN && action_para==0); err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(action_mode!=action_mode2 && action_mode!=ACTION_ATTACK_TOWN); err_when(action_para!=action_para2 || !action_para); err_when(action_x_loc!=action_x_loc2 || action_y_loc!=action_y_loc2); } //----------- End of function Unit::attack_town -----------// //--------- Begin of function Unit::process_attack_town ---------// // functions process attacking town // void Unit::process_attack_town() { if(!can_attack()) { stop2(KEEP_DEFENSE_MODE); return; } err_when(!action_para || action_mode!=ACTION_ATTACK_TOWN || !can_attack()); // unable to attack // ###### begin Gilbert 17/3 #######// //err_when(attack_info_array[cur_attack].attack_range != attack_range); // ###### end Gilbert 17/3 #######// Town* targetTown; int clearOrder = 0; //------------------------------------------------------------// // check attack conditions //------------------------------------------------------------// if(town_array.is_deleted(action_para)) clearOrder++; else { targetTown = town_array[action_para]; err_when(!targetTown || action_para!=targetTown->town_recno); err_when(action_x_loc != targetTown->loc_x1 || action_y_loc != targetTown->loc_y1); if(!nation_can_attack(targetTown->nation_recno)) // cannot attack this nation clearOrder++; } if(clearOrder) { //------------------------------------------------------------// // change to detect target if in defend mode //------------------------------------------------------------// /*if(action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET || action_mode2==ACTION_DEFEND_TOWN_ATTACK_TARGET || action_mode2==ACTION_MONSTER_DEFEND_ATTACK_TARGET) { err_when((action_misc!=ACTION_MISC_DEFENSE_CAMP_RECNO && action_misc!=ACTION_MISC_DEFEND_TOWN_RECNO && action_misc!=ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO) || !action_misc_para); stop2(KEEP_DEFENSE_MODE); return; } err_when(action_mode2==ACTION_AUTO_DEFENSE_DETECT_TARGET || action_mode2==ACTION_AUTO_DEFENSE_BACK_CAMP || action_mode2==ACTION_DEFEND_TOWN_DETECT_TARGET || action_mode2==ACTION_DEFEND_TOWN_BACK_TOWN || action_mode2==ACTION_MONSTER_DEFEND_DETECT_TARGET || action_mode2==ACTION_MONSTER_DEFEND_BACK_FIRM); stop2(); // clear order err_when(cur_action==SPRITE_ATTACK && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc())); err_when(action_mode==ACTION_ATTACK_TOWN && !action_para); err_when(cur_action==SPRITE_ATTACK && action_mode==ACTION_STOP); return;*/ #ifdef DEBUG int inDefMode = in_any_defense_mode(); #endif stop2(KEEP_DEFENSE_MODE); #ifdef DEBUG if(inDefMode) { err_when((action_misc!=ACTION_MISC_DEFENSE_CAMP_RECNO && action_misc!=ACTION_MISC_DEFEND_TOWN_RECNO && action_misc!=ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO) || !action_misc_para); } #endif err_when(cur_action==SPRITE_ATTACK && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc())); err_when(action_mode==ACTION_ATTACK_TOWN && !action_para); err_when(cur_action==SPRITE_ATTACK && action_mode==ACTION_STOP); return; } err_when(ai_unit && nation_recno==targetTown->nation_recno); // ai unit don't attack itself, but players can //-----------------------------------------------------// // If the unit is currently attacking somebody. //-----------------------------------------------------// if(cur_action==SPRITE_ATTACK) { err_when(cur_x!=next_x || cur_y!=next_y || !is_dir_correct()); //###### begin alex 18/3 #######// err_when(attack_info_array[cur_attack].attack_range != attack_range); //###### end alex 18/3 #######// if(remain_attack_delay) return; AttackInfo* attackInfo = attack_info_array+cur_attack; if( attackInfo->attack_range > 1 ) // range attack { //---------- wait for bullet emit ---------// if(cur_frame!=attackInfo->bullet_out_frame) return; //------- seek location to attack target by bullet --------// int curXLoc = next_x_loc(); int curYLoc = next_y_loc(); if(!bullet_array.bullet_path_possible(curXLoc, curYLoc, mobile_type, range_attack_x_loc, range_attack_y_loc, UNIT_LAND, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) { if(!bullet_array.add_bullet_possible(curXLoc, curYLoc, mobile_type, action_x_loc, action_y_loc, UNIT_LAND, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, range_attack_x_loc, range_attack_y_loc, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) { //----- no suitable location, move to target --------// set_move_to_surround(action_x_loc, action_y_loc, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, BUILDING_TYPE_TOWN_MOVE_TO); err_when(action_mode!=ACTION_ATTACK_TOWN || action_para!=targetTown->town_recno); return; } } //--------- add bullet, bullet emits --------// bullet_array.add_bullet(this, action_x_loc, action_y_loc); // ####### begin Gilbert 14/7 ########// add_close_attack_effect(); // ####### end Gilbert 14/7 ########// // ------- reduce power --------// cur_power -= attackInfo->consume_power; err_when(cur_power < 0); //### begin alex 28/10 ###// if(cur_power<0) // ***** BUGHERE cur_power = 0; //#### end alex 28/10 ####// set_remain_attack_delay(); return; } else // close attack { if(cur_frame!=cur_sprite_attack()->frame_count) return; // attacking err_when(final_dir != (check_unit_dir1 = get_dir(next_x_loc(), next_y_loc(), targetTown->center_x, targetTown->center_y))); hit_town(this, action_x_loc, action_y_loc, actual_damage()); // ####### begin Gilbert 14/7 ########// add_close_attack_effect(); // ####### end Gilbert 14/7 ########// // ------- reduce power --------// cur_power -= attackInfo->consume_power; err_when(cur_power < 0); //### begin alex 28/10 ###// if(cur_power<0) // ***** BUGHERE cur_power = 0; //#### end alex 28/10 ####// set_remain_attack_delay(); } } //--------------------------------------------------------------------------------------------------// // If the unit is on its way to attack the town, if it has gotten close next to it, attack now //--------------------------------------------------------------------------------------------------// else if(abs(cur_x-next_x)<=sprite_info->speed && abs(cur_y-next_y)<=sprite_info->speed)// it has moved to the specified location. check cur_x & go_x to make sure the sprite has completely move to the location, not just crossing it. { err_when(cur_action==SPRITE_ATTACK); if(mobile_type==UNIT_LAND) { if(detect_surround_target()) return; } if(attack_range==1) { //------------------------------------------------------------// // for close attack, the unit unable to attack the firm if // it is not in the firm surrounding //------------------------------------------------------------// if(result_path_dist > attack_range) return; } int targetXLoc = targetTown->loc_x1; int targetYLoc = targetTown->loc_y1; int attackDistance = cal_distance(targetXLoc , targetYLoc, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT); if(attackDistance<=attack_range) // able to attack target { if((attackDistance==1) && attack_range>1) // often false condition is checked first choose_best_attack_mode(1); // may change to use close attack if(attack_range>1) // use range attack { set_cur(next_x, next_y); AttackInfo *attackInfo = attack_info_array+cur_attack; int curXLoc = next_x_loc(); int curYLoc = next_y_loc(); if(!bullet_array.add_bullet_possible(curXLoc, curYLoc, mobile_type, targetXLoc, targetYLoc, UNIT_LAND, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, range_attack_x_loc, range_attack_y_loc, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) { //------- no suitable location, move to target ---------// if(!result_node_array || !result_node_count) // no step for continuing moving set_move_to_surround(action_x_loc, action_y_loc, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, BUILDING_TYPE_TOWN_MOVE_TO); err_when(action_mode!=ACTION_ATTACK_TOWN || action_para!=targetTown->town_recno); return; // unable to attack, continue to move } //---------- able to do range attack ----------// set_attack_dir(next_x_loc(), next_y_loc(), range_attack_x_loc, range_attack_y_loc); cur_frame = 1; if(is_dir_correct()) set_attack(); else set_turn(); } else // close attack { //---------- attack now ---------// set_cur(next_x, next_y); terminate_move(); err_when(cur_frame!=1); set_dir(next_x_loc(), next_y_loc(), targetTown->center_x, targetTown->center_y); if(is_dir_correct()) set_attack(); else set_turn(); } err_when(cur_x!=next_x || cur_y!=next_y); } } err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); } //----------- End of function Unit::process_attack_town -----------// //--------- Begin of function Unit::attack_wall ---------// // wallXLoc, wallYLoc - the wall location // xOffset, yOffset - the offset from the wall location // for the unit to move to // resetBlockedEdge - flag to reset variable blocked_edge // // the unit calling this function is to attack target by (1) default // ordering or by (2) defense mode // // Note : (wallXLoc, wallYLoc) should be the upper left corner location // of the wall // void Unit::attack_wall(int wallXLoc, int wallYLoc, int xOffset, int yOffset, int resetBlockedEdge) { //------------------------------------------------------------// // return if this unit cannot do the attack action //------------------------------------------------------------// if(!can_attack()) { stop2(KEEP_DEFENSE_MODE); return; } else if(is_unit_dead()) return; err_when(!can_attack()); Location *locPtr = world.get_loc(wallXLoc, wallYLoc); err_when(!locPtr); //------------------------------------------------------------// // no wall there //------------------------------------------------------------// if(!locPtr->is_wall()) { if(action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET || action_mode2==ACTION_DEFEND_TOWN_ATTACK_TARGET || action_mode2==ACTION_MONSTER_DEFEND_ATTACK_TARGET) { stop(KEEP_DEFENSE_MODE); err_when((action_mode2!=ACTION_AUTO_DEFENSE_DETECT_TARGET || action_para2!=AUTO_DEFENSE_DETECT_COUNT) && (action_mode2!=ACTION_DEFEND_TOWN_DETECT_TARGET || action_para2!=UNIT_DEFEND_TOWN_DETECT_COUNT) && (action_mode2!=ACTION_MONSTER_DEFEND_DETECT_TARGET || action_para2!=MONSTER_DEFEND_DETECT_COUNT)); } err_when(action_mode==ACTION_ATTACK_WALL && action_para); err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); return; } //------------------------------------------------------------// // cannot attack this nation //------------------------------------------------------------// if(!nation_can_attack(locPtr->wall_nation_recno())) { stop2(KEEP_DEFENSE_MODE); err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(action_mode==ACTION_ATTACK_WALL || action_para || action_x_loc!=-1 || action_y_loc!=-1); return; } //------------------------------------------------------------------------------------// // move there if cannot reach the effective attacking region //------------------------------------------------------------------------------------// int diffTerritoryAttack = 0, maxRange=0; if(mobile_type!=UNIT_AIR && world.get_loc(next_x_loc(), next_y_loc())->region_id!=locPtr->region_id) { maxRange = max_attack_range(); if(!possible_place_for_range_attack(wallXLoc, wallYLoc, 1, 1, maxRange)) { if(action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode!=ACTION_MONSTER_DEFEND_ATTACK_TARGET) move_to(wallXLoc, wallYLoc); return; } else // can reach diffTerritoryAttack = 1; } //----------------------------------------------------------------// // action_mode2: checking for equal action or idle action //----------------------------------------------------------------// if((action_mode2==ACTION_ATTACK_WALL || action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET || action_mode2==ACTION_DEFEND_TOWN_ATTACK_TARGET || action_mode2==ACTION_MONSTER_DEFEND_ATTACK_TARGET) && !action_para2 && action_x_loc2==wallXLoc && action_y_loc2==wallYLoc) { //------------ old order ------------// err_when(action_mode==ACTION_ATTACK_WALL && action_para); err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); if(cur_action!=SPRITE_IDLE) { //------- old order is processing --------// #ifdef DEBUG if(action_mode==ACTION_ATTACK_WALL) { err_when(action_mode2!=ACTION_ATTACK_WALL && action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET); err_when(action_para!=action_para2 || action_x_loc!=action_x_loc2 || action_y_loc!=action_y_loc2); } else err_when(action_mode!=ACTION_STOP || action_para || action_x_loc!=-1 || action_y_loc!=-1); #endif return; } } else { //-------------- new order -------------// if(action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET) action_mode2 = ACTION_ATTACK_WALL; action_para2 = 0; action_x_loc2 = wallXLoc; action_y_loc2 = wallYLoc; } //-------------------------------------------------------------// // process new order //-------------------------------------------------------------// stop(); cur_attack = 0; int attackDistance = cal_distance(wallXLoc, wallYLoc, 1, 1); choose_best_attack_mode(attackDistance); AttackInfo* attackInfo = attack_info_array+cur_attack; if(attackInfo->attack_range=MAX_WORLD_X_LOC) xLoc = MAX_WORLD_X_LOC-1; if(yLoc<0) yLoc = 0; else if(yLoc>=MAX_WORLD_Y_LOC) yLoc = MAX_WORLD_Y_LOC-1; search(xLoc, yLoc, 1); // offset location is given, so move there directly } else { if(diffTerritoryAttack) { //--------------------------------------------------------------------------------// // 1) different type from target, target located in different territory but able to // attack this target by range attacking //--------------------------------------------------------------------------------// move_to_range_attack(wallXLoc, wallYLoc, 0, SEARCH_MODE_ATTACK_WALL_BY_RANGE, maxRange); } else { //--------------------------------------------------------------------------------// // 1) same type of target, // 2) this unit is air unit, or // 3) different type from target, but target located in the same territory //--------------------------------------------------------------------------------// searchResult = set_move_to_surround(wallXLoc, wallYLoc, 1, 1, BUILDING_TYPE_WALL, 0, 0); } } //---------------------------------------------------------------// // initialize parameters for blocked edge handling in attacking //---------------------------------------------------------------// if(searchResult) { waiting_term = 0; if(resetBlockedEdge) memset(blocked_edge, 0, sizeof(char)*4); } else memset(blocked_edge, 0xff, sizeof(char)*4); } else if(cur_action==SPRITE_IDLE) { //---------------------------------------------------------------// // attack now //---------------------------------------------------------------// set_cur(next_x, next_y); set_attack_dir(next_x_loc(), next_y_loc(), wallXLoc, wallYLoc); if(is_dir_correct()) { if(attackInfo->attack_range==1) set_attack(); } else set_turn(); } action_mode = ACTION_ATTACK_WALL; action_para = 0; action_x_loc = wallXLoc; action_y_loc = wallYLoc; err_when(action_mode==ACTION_ATTACK_WALL && action_para); err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); err_when(action_mode!=action_mode2 && action_mode!=ACTION_ATTACK_WALL); err_when(action_para!=action_para2 || action_para); err_when(action_x_loc!=action_x_loc2 || action_y_loc!=action_y_loc2); } //----------- End of function Unit::attack_wall -----------// //--------- Begin of function Unit::process_attack_wall ---------// // process attack wall // void Unit::process_attack_wall() { if(!can_attack()) { stop2(KEEP_DEFENSE_MODE); return; } err_when(action_para || action_mode!=ACTION_ATTACK_WALL); // action_para should be 0 err_when(!can_attack()); // unable to attack // ###### begin Gilbert 17/3 #######// //err_when(attack_info_array[cur_attack].attack_range != attack_range); // ###### end Gilbert 17/3 #######// //------------------------------------------------------------// // if the targeted wall has been destroyed //------------------------------------------------------------// Location *locPtr = world.get_loc(action_x_loc, action_y_loc); if(!locPtr->is_wall()) { stop2(KEEP_DEFENSE_MODE); err_when(cur_action==SPRITE_ATTACK && action_mode==ACTION_STOP); return; } //-----------------------------------------------------// // If the unit is currently attacking. //-----------------------------------------------------// if(cur_action==SPRITE_ATTACK) { err_when(cur_x!=next_x || cur_y!=next_y || !is_dir_correct()); //###### begin alex 18/3 #######// err_when(attack_info_array[cur_attack].attack_range != attack_range); //###### end alex 18/3 #######// if(remain_attack_delay) return; AttackInfo* attackInfo = attack_info_array+cur_attack; if( attackInfo->attack_range > 1 ) // range attack { //--------- wait for bullet emit ----------// if(cur_frame!=attackInfo->bullet_out_frame) return; //---------- seek location to attack target by bullet --------// int curXLoc = next_x_loc(); int curYLoc = next_y_loc(); if(!bullet_array.bullet_path_possible(curXLoc, curYLoc, mobile_type, range_attack_x_loc, range_attack_y_loc, UNIT_LAND, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) { if(!bullet_array.add_bullet_possible(curXLoc, curYLoc, mobile_type, action_x_loc, action_y_loc, UNIT_LAND, 1, 1, range_attack_x_loc, range_attack_y_loc, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) { //--------- no suitable location, move to target ----------// set_move_to_surround(action_x_loc, action_y_loc, 1, 1, BUILDING_TYPE_WALL); err_when(action_mode!=ACTION_ATTACK_WALL || action_para); return; } } //---------- add bullet, bullet emits -----------// bullet_array.add_bullet(this, action_x_loc, action_y_loc); // ####### begin Gilbert 14/7 ########// add_close_attack_effect(); // ####### end Gilbert 14/7 ########// // ------- reduce power --------// cur_power -= attackInfo->consume_power; err_when(cur_power < 0); //### begin alex 28/10 ###// if(cur_power<0) // ***** BUGHERE cur_power = 0; //#### end alex 28/10 ####// set_remain_attack_delay(); return; } else { if(cur_frame!=cur_sprite_attack()->frame_count) return; // attacking err_when(final_dir!=(check_unit_dir1=get_dir(move_to_x_loc, move_to_y_loc, action_x_loc, action_y_loc))); hit_wall(this, action_x_loc, action_y_loc, actual_damage()); // ####### begin Gilbert 14/7 ########// add_close_attack_effect(); // ####### end Gilbert 14/7 ########// //------- reduce power --------// cur_power -= attackInfo->consume_power; err_when(cur_power < 0); //### begin alex 28/10 ###// if(cur_power<0) // ***** BUGHERE cur_power = 0; //#### end alex 28/10 ####// set_remain_attack_delay(); } } //--------------------------------------------------------------------------------------------------// // If the unit is on its way to attack somebody, if it has gotten close next to the target, attack now //--------------------------------------------------------------------------------------------------// else if(abs(cur_x-next_x)<=sprite_info->speed && abs(cur_y-next_y)<=sprite_info->speed ) // it has moved to the specified location. check cur_x & go_x to make sure the sprite has completely move to the location, not just crossing it. { err_when(cur_action==SPRITE_ATTACK); if(mobile_type==UNIT_LAND) { if(detect_surround_target()) return; } if(attack_range==1) { //------------------------------------------------------------// // for close attack, the unit unable to attack the firm if // it is not in the firm surrounding //------------------------------------------------------------// if(result_path_dist > attack_range) return; } int attackDistance = cal_distance(action_x_loc, action_y_loc, 1, 1); if(attackDistance<=attack_range) // able to attack target { if((attackDistance==1) && attack_range>1) // often false condition is checked first choose_best_attack_mode(1); // may change to use close attack if(attack_range>1) // use range attack { set_cur(next_x, next_y); AttackInfo *attackInfo = attack_info_array+cur_attack; int curXLoc = next_x_loc(); int curYLoc = next_y_loc(); if(!bullet_array.add_bullet_possible(curXLoc, curYLoc, mobile_type, action_x_loc, action_y_loc, UNIT_LAND, 1, 1, range_attack_x_loc, range_attack_y_loc, attackInfo->bullet_speed, attackInfo->bullet_sprite_id)) { //------- no suitable location, move to target ---------// if(!result_node_array || !result_node_count) // no step for continuing moving set_move_to_surround(action_x_loc, action_y_loc, 1, 1, BUILDING_TYPE_WALL); err_when(action_mode!=ACTION_ATTACK_WALL || action_para); return; // unable to attack, continue to move } //---------- able to do range attack ----------// set_attack_dir(curXLoc, curYLoc, range_attack_x_loc, range_attack_y_loc); cur_frame = 1; if(is_dir_correct()) set_attack(); else set_turn(); } else // close attack { //---------- attack now ---------// set_cur(next_x, next_y); terminate_move(); err_when(cur_frame!=1); set_attack_dir(next_x_loc(), next_y_loc(), action_x_loc, action_y_loc); if(is_dir_correct()) set_attack(); else set_turn(); } err_when(cur_x!=next_x || cur_y!=next_y); } } err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); } //----------- End of function Unit::process_attack_wall -----------//