/* * 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 : OUNITAAT.CPP //Description : Object UnitArray - part 2 #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 //------ static variables for attacking ------// // ATTACK_DIR is defined in OUNIT.H #define MAX_TARGET_SIZE 4 #define MAX_UNIT_SURROUND_SIZE MAX_TARGET_SIZE+2 // handle the case up to target size 4x4 #define SHIFT_ADJUST 1 // since the upper left offset position is (-1, -1) static short *unit_processed_array; // store those processed unit sprite_recno static short unit_processed_count; // count the number processed units static short *dir_array_ptr[ATTACK_DIR]; // store units' sprite_recno in each direction static short dir_array_count[ATTACK_DIR]; // num of unit in each direction static char unreachable_table[MAX_UNIT_SURROUND_SIZE][MAX_UNIT_SURROUND_SIZE]; // table shared for all attackers //************* debug ***************// #ifdef DEBUG //--------------------------------------------------------------------------------// // resultNum - the num of free space around the target // width - width of target // height - height of target //--------------------------------------------------------------------------------// static void debug_analyse_result_check(int resultNum, int width, int height) { int count=0, i, j; for(i=0; i targetWidth - target width // targetHeight - target height // char UnitArray::get_target_surround_loc(int targetWidth, int targetHeight) { static char surround_loc[MAX_TARGET_SIZE][MAX_TARGET_SIZE] // width, height = { { 8, 10, 12, 14}, {10, 12, 14, 16}, {12, 14, 16, 18}, {14, 16, 18, 20}}; return surround_loc[targetWidth-1][targetHeight-1]; } //----------- End of function UnitArray::get_target_surround_loc -----------// //--------- Begin of function UnitArray::update_unreachable_table ---------// // check target surroundig to drop those unreachable location // // targetXLoc - target x location // targetYLoc - target y location // targetWidth - target width // targetHeight - target height // mobileType - mobile type of the attacker // analyseResult - reference for returning num of reachable location // void UnitArray::update_unreachable_table(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, char mobileType, int &analyseResult) { int xLoc1, yLoc1, xLoc2, yLoc2, i; //----------------------------------------------------------------------// // checking for left & right edges, calculate location and counter //----------------------------------------------------------------------// xLoc1 = targetXLoc-1; xLoc2 = targetXLoc+targetWidth; if(targetYLoc==0) { i = targetHeight+1; yLoc1=targetYLoc; } else { i = targetHeight+2; yLoc1=targetYLoc-1; } if(targetYLoc+targetHeight>=MAX_WORLD_Y_LOC) i--; for(yLoc2=yLoc1-targetYLoc+SHIFT_ADJUST; i>0; i--, yLoc1++, yLoc2++) { //---- left edge ----// if(xLoc1>=0 && !unreachable_table[0][yLoc2] && !world.get_loc(xLoc1, yLoc1)->can_move(mobileType)) { unreachable_table[0][yLoc2] = 1; analyseResult--; } //----- right edge -----// if(xLoc2can_move(mobileType)) { unreachable_table[targetWidth+1][yLoc2] = 1; analyseResult--; } if(!analyseResult) return; } //----------------------------------------------------------------------// // checking for the top and bottom edges //----------------------------------------------------------------------// yLoc1 = targetYLoc-1; yLoc2 = targetYLoc+targetHeight; for(i=0, xLoc1=targetXLoc, xLoc2=xLoc1-targetXLoc+SHIFT_ADJUST; i=0 && !unreachable_table[xLoc2][0] && !world.get_loc(xLoc1, yLoc1)->can_move(mobileType)) { unreachable_table[xLoc2][0] = 1; analyseResult--; } //----- bottom edge -----// if(yLoc2can_move(mobileType)) { unreachable_table[xLoc2][targetHeight+1] = 1; analyseResult--; } if(!analyseResult) return; } debug_result_check(analyseResult, targetWidth, targetHeight); err_when(analyseResult<0); } //----------- End of function UnitArray::update_unreachable_table -----------// //--------- Begin of function UnitArray::attack ---------// // // Order the unit to attack a specific location. // // targetXLoc, targetYLoc - target location // divided - whether the units are divided // selectedUnitArray - an array of recno of selected units. // selectedCount - no. of selected units. // [char] remoteAction - whether this is an action carried out by a remote machine or not. // (default: 0) // targetUnitRecno - if it is unit, pass the unit recno, otherwise 0 // void UnitArray::attack(int targetXLoc, int targetYLoc, int divided, short* selectedUnitArray, int selectedCount, char remoteAction, int targetUnitRecno) { err_when(targetXLoc<0 || targetYLoc<0 || targetXLoc>=MAX_WORLD_X_LOC || targetYLoc>=MAX_WORLD_Y_LOC); // ######## patch begin Gilbert 5/8 #########// int targetNationRecno = 0; if( targetUnitRecno == 0 ) { // unit determined from the location int tmpMobileType; Location* locPtr = world.get_loc(targetXLoc, targetYLoc); targetUnitRecno = locPtr->get_any_unit(tmpMobileType) ; } else { // location determined by the unit Unit *unitPtr; if( !unit_array.is_deleted(targetUnitRecno) && (unitPtr = unit_array[targetUnitRecno]) && unitPtr->is_visible() ) { targetXLoc = unitPtr->next_x_loc(); targetYLoc = unitPtr->next_y_loc(); if( unitPtr->unit_id != UNIT_EXPLOSIVE_CART ) // attacking own porcupine is allowed targetNationRecno = unitPtr->nation_recno; } else targetUnitRecno = 0; } if( targetUnitRecno == 0 ) { //--- set the target coordination to the top left position of the town/firm ---// Location* locPtr = world.get_loc(targetXLoc, targetYLoc); //---- if there is a firm on this location -----// if( locPtr->is_firm() ) { Firm* firmPtr = firm_array[locPtr->firm_recno()]; targetXLoc = firmPtr->loc_x1; targetYLoc = firmPtr->loc_y1; targetNationRecno = firmPtr->nation_recno; } //---- if there is a town on this location -----// else if( locPtr->is_town() ) { Town* townPtr = town_array[locPtr->town_recno()]; targetXLoc = townPtr->loc_x1; targetYLoc = townPtr->loc_y1; targetNationRecno = townPtr->nation_recno; } else return; } // ######## patch end Gilbert 5/8 #########// //--------- AI debug code ---------// //--- AI attacking a nation which its NationRelation::should_attack is 0 ---// Unit* attackUnit = unit_array[ selectedUnitArray[0] ]; if( attackUnit->nation_recno && targetNationRecno ) { if( nation_array[attackUnit->nation_recno]->get_relation(targetNationRecno)->should_attack==0 ) return; } //-------- if it's a multiplayer game --------// if( !remoteAction && remote.is_enable() ) { short* shortPtr = (short*) remote.new_send_queue_msg(MSG_UNIT_ATTACK, sizeof(short) * (5+selectedCount) ); shortPtr[0] = targetXLoc; shortPtr[1] = targetYLoc; shortPtr[2] = targetUnitRecno; shortPtr[3] = selectedCount; shortPtr[4] = divided; memcpy( shortPtr+5, selectedUnitArray, sizeof(short) * selectedCount ); } else { if(!divided) { divide_array(targetXLoc, targetYLoc, selectedUnitArray, selectedCount, 1); // 1 for excluding the recno in target location Location* locPtr = world.get_loc(targetXLoc, targetYLoc); int targetMobileType = locPtr->has_any_unit(); if(selected_land_unit_count) attack_call(targetXLoc, targetYLoc, UNIT_LAND, targetMobileType, 1, selected_land_unit_array, selected_land_unit_count, targetUnitRecno); if(selected_sea_unit_count) attack_call(targetXLoc, targetYLoc, UNIT_SEA, targetMobileType, 1, selected_sea_unit_array, selected_sea_unit_count, targetUnitRecno); if(selected_air_unit_count) attack_call(targetXLoc, targetYLoc, UNIT_AIR, targetMobileType, 1, selected_air_unit_array, selected_air_unit_count, targetUnitRecno); selected_land_unit_count = selected_sea_unit_count = selected_air_unit_count = 0; mem_del(selected_land_unit_array); mem_del(selected_sea_unit_array); mem_del(selected_air_unit_array); return; } else err_here(); } } //----------- End of function UnitArray::attack -----------// //--------- Begin of function UnitArray::attack_call ---------// // targetXLoc - target x location // targetYLoc - target y location // mobileType - attacker's mobile type // targetMobileType - target mobile type // divided - whether the units are divided // selectedUnitArray - selected units' recno. // selectedCount - num of selected units // void UnitArray::attack_call(int targetXLoc, int targetYLoc, char mobileType, char targetMobileType, int divided, short* selectedUnitArray, int selectedCount, int targetUnitRecno) { //------------- attack now -------------// err_when( selectedCount > 10000 ); Location* locPtr = world.get_loc(targetXLoc, targetYLoc); err_when(!locPtr); // ##### patch begin Gilbert 5/8 ######// //if(targetMobileType) if( targetUnitRecno && !unit_array.is_deleted(targetUnitRecno) ) { //---------------- attack unit --------------// //Unit *targetUnit = unit_array[locPtr->unit_recno(targetMobileType)]; Unit *targetUnit = unit_array[targetUnitRecno]; if(!targetUnit->is_visible() || targetUnit->hit_points<=0) return; // short targetUnitRecno = targetUnit->sprite_recno; attack_unit(targetXLoc, targetYLoc, targetUnitRecno, selectedUnitArray, selectedCount); } // ##### patch end Gilbert 5/8 ######// else if(locPtr->is_firm()) { //------------------ attack firm -------------------// Firm *firmPtr = firm_array[locPtr->firm_recno()]; err_when(!firmPtr); if(firmPtr->hit_points<=0) return; attack_firm(targetXLoc, targetYLoc, firmPtr->firm_recno, selectedUnitArray, selectedCount); } else if(locPtr->is_town()) { //-------------------- attack town -------------------// Town *townPtr = town_array[locPtr->town_recno()]; err_when(!townPtr); attack_town(targetXLoc, targetYLoc, townPtr->town_recno, selectedUnitArray, selectedCount); } else if(locPtr->is_wall()) { //------------------ attack wall ---------------------// attack_wall(targetXLoc, targetYLoc, selectedUnitArray, selectedCount); } else return; // no target for attacking } //----------- End of function UnitArray::attack_call -----------// //--------- Begin of function UnitArray::attack_unit ---------// // targetXLoc, targetYLoc - the unit upper left location // targetunitRecno - the unit recno // // Note : this attack function only for attackers with size 1x1. // void UnitArray::attack_unit(int targetXLoc, int targetYLoc, short targetUnitRecno, short* selectedUnitArray, int selectedCount) { err_when(selectedCount<=0); if(selectedCount==1) { Unit *unitPtr = (Unit*) get_ptr(selectedUnitArray[0]); unitPtr->unit_group_id = unit_array.cur_group_id++; unitPtr->attack_unit(targetXLoc, targetYLoc); return; } //********************** improve later begin **************************// //---------------------------------------------------------------------// // codes for differnt territory or different mobile_type attacking should // be added in the future. //---------------------------------------------------------------------// Unit *firstUnitPtr = unit_array[selectedUnitArray[0]]; Unit *targetPtr2 = unit_array[targetUnitRecno]; if( (world.get_loc(targetXLoc, targetYLoc)->region_id != world.get_loc(firstUnitPtr->next_x_loc(), firstUnitPtr->next_y_loc())->region_id) || (targetPtr2->mobile_type!=firstUnitPtr->mobile_type) ) { Unit *unitPtr; set_group_id(selectedUnitArray, selectedCount); for(int i=0; iattack_unit(targetXLoc, targetYLoc); } return; } //*********************** improve later end ***************************// //----------- initialize local parameters ------------// Unit *targetPtr = unit_array[targetUnitRecno]; int targetWidth = targetPtr->sprite_info->loc_width; int targetHeight = targetPtr->sprite_info->loc_height; int targetXLoc2 = targetXLoc + targetWidth - 1; int targetYLoc2 = targetYLoc + targetHeight - 1; char surroundLoc = get_target_surround_loc(targetWidth, targetHeight); char *xOffsetPtr = get_target_x_offset(targetWidth, targetHeight, 0); char *yOffsetPtr = get_target_y_offset(targetWidth, targetHeight, 0); //---------------------------------------------------------------------// // construct data structure //---------------------------------------------------------------------// int tempVar = sizeof(short)*selectedCount; memset(dir_array_count, 0, sizeof(dir_array_count)); int count; for(count=0; countmobile_type); debug_result_check(analyseResult, targetWidth, targetHeight); err_when(analyseResult<0); if(!analyseResult) // 0 if all surround location is not accessible { //------------------------------------------------------------// // special handling for this case //------------------------------------------------------------// handle_attack_target_totally_blocked(targetXLoc, targetYLoc, targetUnitRecno, selectedUnitArray, selectedCount, 1); for(count=0; count=surroundLoc) { destCount = 0; xOffsetPtr = get_target_x_offset(targetWidth, targetHeight, count); yOffsetPtr = get_target_y_offset(targetWidth, targetHeight, count); xOffset = *xOffsetPtr; yOffset = *yOffsetPtr; } else { xOffset = *(++xOffsetPtr); yOffset = *(++yOffsetPtr); } if(!unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST]) break; } } err_when(unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST]); //------------------------------------------------------------// // find the closest attacker //------------------------------------------------------------// err_when(unprocessed>2000 || unprocessed <0); xLoc = targetXLoc + xOffset; yLoc = targetYLoc + yOffset; err_when(!world.get_loc(xLoc, yLoc)->can_move(targetPtr->mobile_type)); for(i=0, minDist=0x7FFFFFF; inext_x_loc()); yDist = abs(yLoc-unitPtr->next_y_loc()); dist = (xDist >= yDist) ? xDist*10+yDist : yDist*10+xDist; if(dist < minDist) { minDist = dist; unitPos = i; } } unitPtr = (Unit*) get_ptr(curArrayPtr[unitPos]); curArrayPtr[unitPos] = curArrayPtr[--unprocessed]; // move the units in the back to the front err_when(unitPtr->action_mode2!=ACTION_ATTACK_WALL && unitPtr->cur_action==SPRITE_ATTACK && unitPtr->action_para==0); seek_path.set_status(PATH_WAIT); err_when(seek_path.path_status==PATH_NODE_USED_UP); unitPtr->attack_unit(targetXLoc, targetYLoc, xOffset, yOffset); //------------------------------------------------------------// // store the unit sprite_recno in the array //------------------------------------------------------------// unit_processed_array[unit_processed_count++] = unitPtr->sprite_recno; //------------------------------------------------------------// // set the flag if unreachable //------------------------------------------------------------// if(seek_path.path_status==PATH_NODE_USED_UP) { unreachable_table[xLoc-targetXLoc+SHIFT_ADJUST][yLoc-targetYLoc+SHIFT_ADJUST] = 1; analyseResult--; debug_result_check(analyseResult, targetWidth, targetHeight); err_when(analyseResult<0); //------------------------------------------------------------// // the nearby location should also be unreachable //------------------------------------------------------------// check_nearby_location(targetXLoc, targetYLoc, xOffset, yOffset, targetWidth, targetHeight, targetPtr->mobile_type, analyseResult); } update_unreachable_table(targetXLoc, targetYLoc, targetWidth, targetHeight, unitPtr->mobile_type, analyseResult); #ifdef DEBUG for(int di=0; di=1 && di<=targetWidth && dj>=1 && dj<=targetHeight) continue; int debugXLoc = targetXLoc+di-SHIFT_ADJUST; int debugYLoc = targetYLoc+dj-SHIFT_ADJUST; if(debugXLoc<0 || debugXLoc>=MAX_WORLD_X_LOC || debugYLoc<0 || debugYLoc>=MAX_WORLD_Y_LOC) continue; Location *dlPtr = world.get_loc(debugXLoc, debugYLoc); err_when(!dlPtr->can_move(targetPtr->mobile_type) && unreachable_table[di][dj]==0); } } #endif } } //---------------------------------------------------------------------// // set the unreachable flag for each units //---------------------------------------------------------------------// //-************** codes here ***************-// //---------------------------------------------------------------------// // destruct data structure //---------------------------------------------------------------------// for(count=0; count targetXLoc, targetYLoc - the firm upper left location // firmRecno - the firm recno // // try to calculate the best location for each unit to move to the // surrounding of the firm for attacking // void UnitArray::attack_firm(int targetXLoc, int targetYLoc, short firmRecno, short* selectedUnitArray, int selectedCount) { err_when(selectedCount<=0); if(selectedCount==1) { Unit *unitPtr = (Unit*) get_ptr(selectedUnitArray[0]); unitPtr->unit_group_id = unit_array.cur_group_id++; unitPtr->attack_firm(targetXLoc, targetYLoc); return; } //********************** improve later begin **************************// //---------------------------------------------------------------------// // codes for differnt territory or different mobile_type attacking should // be added in the future. //---------------------------------------------------------------------// Unit *firstUnitPtr = unit_array[selectedUnitArray[0]]; if(world.get_loc(targetXLoc, targetYLoc)->region_id != world.get_loc(firstUnitPtr->next_x_loc(), firstUnitPtr->next_y_loc())->region_id) { Unit *unitPtr; set_group_id(selectedUnitArray, selectedCount); for(int i=0; iattack_firm(targetXLoc, targetYLoc); } return; } //*********************** improve later end ***************************// //----------- initialize local parameters ------------// Firm *firmPtr = firm_array[firmRecno]; FirmInfo *firmInfo = firm_res[firmPtr->firm_id]; int firmWidth = firmInfo->loc_width; int firmHeight = firmInfo->loc_height; int targetXLoc2 = targetXLoc + firmWidth - 1; // the lower right corner of the firm int targetYLoc2 = targetYLoc + firmHeight -1; char *xOffsetPtr, *yOffsetPtr; //---------------------------------------------------------------------// // construct data structure //---------------------------------------------------------------------// int tempVar = sizeof(short)*selectedCount; memset(dir_array_count, 0, sizeof(dir_array_count)); int count; for(count=0; countmobile_type); debug_result_check(analyseResult, firmWidth, firmHeight); err_when(analyseResult<0); if(!analyseResult) // 0 if all surround location is not accessible { //------------------------------------------------------------// // special handling for this case //------------------------------------------------------------// handle_attack_target_totally_blocked(targetXLoc, targetYLoc, firmRecno, selectedUnitArray, selectedCount, 2); for(count=0; count2000 || unprocessed <0); while(unprocessed) { //-----------------------------------------------------// // find a reachable location, or not searched location //-----------------------------------------------------// err_when(analyseResult<0); if(!analyseResult) { handle_attack_target_totally_blocked(targetXLoc, targetYLoc, firmRecno, selectedUnitArray, selectedCount, 2); for(count=0; count=surroundLoc) { destCount = 0; xOffsetPtr = get_target_x_offset(firmWidth, firmHeight, count); yOffsetPtr = get_target_y_offset(firmWidth, firmHeight, count); xOffset = *xOffsetPtr; yOffset = *yOffsetPtr; } else { xOffset = *(++xOffsetPtr); yOffset = *(++yOffsetPtr); } if(!unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST]) break; } } err_when(unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST]); //------------------------------------------------------------// // find the closest attacker //------------------------------------------------------------// err_when(unprocessed>2000 || unprocessed <0); xLoc = targetXLoc + xOffset; yLoc = targetYLoc + yOffset; err_when(!world.get_loc(xLoc, yLoc)->can_move(unitPtr->mobile_type)); for(i=0, minDist=0x7FFFFFF; inext_x_loc()); yDist = abs(yLoc-unitPtr->next_y_loc()); dist = (xDist >= yDist) ? xDist*10+yDist : yDist*10+xDist; if(dist < minDist) { minDist = dist; unitPos = i; } } unitPtr = (Unit*) get_ptr(curArrayPtr[unitPos]); curArrayPtr[unitPos] = curArrayPtr[--unprocessed]; // move the units in the back to the front err_when(unitPtr->action_mode2!=ACTION_ATTACK_WALL && unitPtr->cur_action==SPRITE_ATTACK && unitPtr->action_para==0); seek_path.set_status(PATH_WAIT); err_when(seek_path.path_status==PATH_NODE_USED_UP); unitPtr->attack_firm(targetXLoc, targetYLoc, xOffset, yOffset); //------------------------------------------------------------// // set the flag if unreachable //------------------------------------------------------------// if(seek_path.path_status==PATH_NODE_USED_UP) { unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST] = 1; analyseResult--; debug_result_check(analyseResult, firmWidth, firmHeight); err_when(analyseResult<0); //------------------------------------------------------------// // the nearby location should also be unreachable //------------------------------------------------------------// check_nearby_location(targetXLoc, targetYLoc, xOffset, yOffset, firmWidth, firmHeight, unitPtr->mobile_type, analyseResult); } update_unreachable_table(targetXLoc, targetYLoc, firmWidth, firmHeight, unitPtr->mobile_type, analyseResult); #ifdef DEBUG for(int di=0; di=1 && di<=firmWidth && dj>=1 && dj<=firmHeight) continue; int debugXLoc = targetXLoc+di-SHIFT_ADJUST; int debugYLoc = targetYLoc+dj-SHIFT_ADJUST; if(debugXLoc<0 || debugXLoc>=MAX_WORLD_X_LOC || debugYLoc<0 || debugYLoc>=MAX_WORLD_Y_LOC) continue; Location *dlPtr = world.get_loc(debugXLoc, debugYLoc); err_when(!dlPtr->can_move(unitPtr->mobile_type) && unreachable_table[di][dj]==0); } } #endif } } //---------------------------------------------------------------------// // set the unreachable flag for each units //---------------------------------------------------------------------// //-************** codes here ***************-// //---------------------------------------------------------------------// // destruct data structure //---------------------------------------------------------------------// for(count=0; count targetXLoc, targetYLoc - the town upper left location // townRecno - the town recno // // try to calculate the best location for each unit to move to the // surrounding of the town for attacking // void UnitArray::attack_town(int targetXLoc, int targetYLoc, short townRecno, short* selectedUnitArray, int selectedCount) { err_when(selectedCount<=0); if(selectedCount==1) { Unit *unitPtr = (Unit*) get_ptr(selectedUnitArray[0]); unitPtr->unit_group_id = unit_array.cur_group_id++; unitPtr->attack_town(targetXLoc, targetYLoc); return; } //********************** improve later begin **************************// //---------------------------------------------------------------------// // codes for differnt territory or different mobile_type attacking should // be added in the future. //---------------------------------------------------------------------// Unit *firstUnitPtr = unit_array[selectedUnitArray[0]]; if(world.get_loc(targetXLoc, targetYLoc)->region_id != world.get_loc(firstUnitPtr->next_x_loc(), firstUnitPtr->next_y_loc())->region_id) { Unit *unitPtr; set_group_id(selectedUnitArray, selectedCount); for(int i=0; iattack_town(targetXLoc, targetYLoc); } return; } //*********************** improve later end ***************************// //----------- initialize local parameters ------------// int targetXLoc2 = targetXLoc + STD_TOWN_LOC_WIDTH - 1; // the lower right corner of the firm int targetYLoc2 = targetYLoc + STD_TOWN_LOC_HEIGHT - 1; char *xOffsetPtr, *yOffsetPtr; //---------------------------------------------------------------------// // construct data structure //---------------------------------------------------------------------// int tempVar = sizeof(short)*selectedCount; memset(dir_array_count, 0, sizeof(dir_array_count)); int count; for(count=0; countmobile_type); debug_result_check(analyseResult, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT); err_when(analyseResult<0); if(!analyseResult) // 0 if all surround location is not accessible { //------------------------------------------------------------// // special handling for this case //------------------------------------------------------------// handle_attack_target_totally_blocked(targetXLoc, targetYLoc, townRecno, selectedUnitArray, selectedCount, 3); for(count=0; count=surroundLoc) { destCount = 0; xOffsetPtr = get_target_x_offset(STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, count); yOffsetPtr = get_target_y_offset(STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, count); xOffset = *xOffsetPtr; yOffset = *yOffsetPtr; } else { xOffset = *(++xOffsetPtr); yOffset = *(++yOffsetPtr); } if(!unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST]) break; } } err_when(unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST]); //------------------------------------------------------------// // find the closest attacker //------------------------------------------------------------// err_when(unprocessed>2000 || unprocessed <0); xLoc = targetXLoc + xOffset; yLoc = targetYLoc + yOffset; err_when(!world.get_loc(xLoc, yLoc)->can_move(unitPtr->mobile_type)); for(i=0, minDist=0x7FFFFFF; inext_x_loc()); yDist = abs(yLoc-unitPtr->next_y_loc()); dist = (xDist >= yDist) ? xDist*10+yDist : yDist*10+xDist; if(dist < minDist) { minDist = dist; unitPos = i; } } unitPtr = (Unit*) get_ptr(curArrayPtr[unitPos]); curArrayPtr[unitPos] = curArrayPtr[--unprocessed]; // move the units in the back to the front err_when(unitPtr->action_mode2!=ACTION_ATTACK_WALL && unitPtr->cur_action==SPRITE_ATTACK && unitPtr->action_para==0); seek_path.set_status(PATH_WAIT); err_when(seek_path.path_status==PATH_NODE_USED_UP); unitPtr->attack_town(targetXLoc, targetYLoc, xOffset, yOffset); //------------------------------------------------------------// // set the flag if unreachable //------------------------------------------------------------// if(seek_path.path_status==PATH_NODE_USED_UP) { unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST] = 1; analyseResult--; debug_result_check(analyseResult, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT); err_when(analyseResult<0); //------------------------------------------------------------// // the nearby location should also be unreachable //------------------------------------------------------------// check_nearby_location(targetXLoc, targetYLoc, xOffset, yOffset, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, unitPtr->mobile_type, analyseResult); } update_unreachable_table(targetXLoc, targetYLoc, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, unitPtr->mobile_type, analyseResult); #ifdef DEBUG Location *dlPtr; for(int di=0; di=1 && di<=STD_TOWN_LOC_WIDTH && dj>=1 && dj<=STD_TOWN_LOC_HEIGHT) continue; int debugXLoc = targetXLoc+di-SHIFT_ADJUST; int debugYLoc = targetYLoc+dj-SHIFT_ADJUST; if(debugXLoc<0 || debugXLoc>=MAX_WORLD_X_LOC || debugYLoc<0 || debugYLoc>=MAX_WORLD_Y_LOC) continue; dlPtr = world.get_loc(debugXLoc, debugYLoc); err_when(!dlPtr->can_move(unitPtr->mobile_type) && unreachable_table[di][dj]==0); } } #endif } } //---------------------------------------------------------------------// // set the unreachable flag for each units //---------------------------------------------------------------------// //-************** codes here ***************-// //---------------------------------------------------------------------// // destruct data structure //---------------------------------------------------------------------// for(count=0; count targetXLoc - x location of the wall // targetYLoc - y location of the wall // void UnitArray::attack_wall(int targetXLoc, int targetYLoc, short* selectedUnitArray, int selectedCount) { err_when(selectedCount<=0); if(selectedCount==1) { Unit *unitPtr = (Unit*) get_ptr(selectedUnitArray[0]); unitPtr->unit_group_id = unit_array.cur_group_id++; unitPtr->attack_wall(targetXLoc, targetYLoc); return; } //********************** improve later begin **************************// //---------------------------------------------------------------------// // codes for differnt territory or different mobile_type attacking should // be added in the future. //---------------------------------------------------------------------// Unit *firstUnitPtr = unit_array[selectedUnitArray[0]]; if(world.get_loc(targetXLoc, targetYLoc)->region_id != world.get_loc(firstUnitPtr->next_x_loc(), firstUnitPtr->next_y_loc())->region_id) { Unit *unitPtr; set_group_id(selectedUnitArray, selectedCount); for(int i=0; iattack_wall(targetXLoc, targetYLoc); } return; } //*********************** improve later end ***************************// //----------- initialize local parameters ------------// char *xOffsetPtr, *yOffsetPtr; //---------------------------------------------------------------------// // construct data structure //---------------------------------------------------------------------// int tempVar = sizeof(short)*selectedCount; memset(dir_array_count, 0, sizeof(dir_array_count)); int count; for(count=0; countmobile_type); debug_result_check(analyseResult, 1, 1); err_when(analyseResult<0); if(!analyseResult) // 0 if all surround location is not accessible { //------------------------------------------------------------// // special handling for this case //------------------------------------------------------------// handle_attack_target_totally_blocked(targetXLoc, targetYLoc, 0, selectedUnitArray, selectedCount, 0); for(count=0; count=surroundLoc) { destCount = 0; xOffsetPtr = get_target_x_offset(1, 1, count); yOffsetPtr = get_target_y_offset(1, 1, count); xOffset = *xOffsetPtr; yOffset = *yOffsetPtr; } else { xOffset = *(++xOffsetPtr); yOffset = *(++yOffsetPtr); } if(!unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST]) break; } } err_when(unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST]); //------------------------------------------------------------// // find the closest attacker //------------------------------------------------------------// err_when(unprocessed>2000 || unprocessed <0); xLoc = targetXLoc + xOffset; yLoc = targetYLoc + yOffset; err_when(!world.get_loc(xLoc, yLoc)->can_move(unitPtr->mobile_type)); for(i=0, minDist=0x7FFFFFF; inext_x_loc()); yDist = abs(yLoc-unitPtr->next_y_loc()); dist = (xDist >= yDist) ? xDist*10+yDist : yDist*10+xDist; if(dist < minDist) { minDist = dist; unitPos = i; } } unitPtr = (Unit*) get_ptr(curArrayPtr[unitPos]); curArrayPtr[unitPos] = curArrayPtr[--unprocessed]; // move the units in the back to the front err_when(unitPtr->action_mode2!=ACTION_ATTACK_WALL && unitPtr->cur_action==SPRITE_ATTACK && unitPtr->action_para==0); seek_path.set_status(PATH_WAIT); err_when(seek_path.path_status==PATH_NODE_USED_UP); unitPtr->attack_wall(targetXLoc, targetYLoc, xOffset, yOffset); //------------------------------------------------------------// // set the flag if unreachable //------------------------------------------------------------// if(seek_path.path_status==PATH_NODE_USED_UP) { unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST] = 1; analyseResult--; debug_result_check(analyseResult, 1, 1); err_when(analyseResult<0); //------------------------------------------------------------// // the nearby location should also be unreachable //------------------------------------------------------------// check_nearby_location(targetXLoc, targetYLoc, xOffset, yOffset, 1, 1, unitPtr->mobile_type, analyseResult); } update_unreachable_table(targetXLoc, targetYLoc, 1, 1, unitPtr->mobile_type, analyseResult); #ifdef DEBUG for(int di=0; di<3; di++) { for(int dj=0; dj<3; dj++) { if(di==1 && dj==1) continue; int debugXLoc = targetXLoc+di-SHIFT_ADJUST; int debugYLoc = targetYLoc+dj-SHIFT_ADJUST; if(debugXLoc<0 || debugXLoc>=MAX_WORLD_X_LOC || debugYLoc<0 || debugYLoc>=MAX_WORLD_Y_LOC) continue; Location *dlPtr = world.get_loc(debugXLoc, debugYLoc); err_when(!dlPtr->can_move(unitPtr->mobile_type) && unreachable_table[di][dj]==0); } } #endif } } //---------------------------------------------------------------------// // set the unreachable flag for each units //---------------------------------------------------------------------// //-************** codes here ***************-// //---------------------------------------------------------------------// // destruct data structure //---------------------------------------------------------------------// for(count=0; count xLoc1 - top left x location of the target // yLoc1 - top left y location of the target // xLoc2 - bottom right x location of the target // yLoc2 - bottom right y location of the target // selectedUnitArray - recno. of selected units // selectedCount - count of selected units // unitGroupId - group id for the selected units // // targetType - 0 for wall, 1 for unit, 2 for firm, 3 for town // void UnitArray::arrange_units_in_group(int xLoc1, int yLoc1, int xLoc2, int yLoc2, short* selectedUnitArray, int selectedCount, DWORD unitGroupId, int targetType) { Unit *unitPtr; int curXLoc, curYLoc; for(int i=0; iunit_group_id = unitGroupId; // set unit_group_id err_when(unitPtr->cur_action==SPRITE_IDLE && (unitPtr->cur_x!=unitPtr->next_x || unitPtr->cur_y!=unitPtr->next_y)); if(unitPtr->cur_action==SPRITE_IDLE) unitPtr->set_ready(); curXLoc = unitPtr->next_x_loc(); curYLoc = unitPtr->next_y_loc(); if(curXLoc>=xLoc1-1 && curXLoc<=xLoc2+1 && curYLoc>=yLoc1-1 && curYLoc<=yLoc2+1) { //------------- already in the target surrounding ----------------// switch(targetType) { case 0: unitPtr->attack_wall(xLoc1, yLoc1); break; case 1: unitPtr->attack_unit(xLoc1, yLoc1); break; case 2: unitPtr->attack_firm(xLoc1, yLoc1); break; case 3: unitPtr->attack_town(xLoc1, yLoc1); break; } continue; } //---- the attacker need to call searching to reach the target ----// if(curXLoc < xLoc1) { if(curYLoc < yLoc1) // 8 dir_array_ptr[7][dir_array_count[7]++] = selectedUnitArray[i]; else if(curYLoc > yLoc2)// 2 dir_array_ptr[1][dir_array_count[1]++] = selectedUnitArray[i]; else // 1 dir_array_ptr[0][dir_array_count[0]++] = selectedUnitArray[i]; } else if(curXLoc > xLoc2) { if(curYLoc < yLoc1) // 6 dir_array_ptr[5][dir_array_count[5]++] = selectedUnitArray[i]; else if(curYLoc > yLoc2)// 4 dir_array_ptr[3][dir_array_count[3]++] = selectedUnitArray[i]; else // 5 dir_array_ptr[4][dir_array_count[4]++] = selectedUnitArray[i]; } else // curXLoc==targetXLoc2 { if(curYLoc < yLoc1) // 7 dir_array_ptr[6][dir_array_count[6]++] = selectedUnitArray[i]; else if(curYLoc > yLoc2)// 3 dir_array_ptr[2][dir_array_count[2]++] = selectedUnitArray[i]; else // curXLoc==xLoc2 && curYLoc==yLoc2 { // target is one of the selected unit, error err_here(); } } } } //----------- End of function UnitArray::arrange_units_in_group -----------// //--------- Begin of function UnitArray::analyse_surround_location ---------// // return the number of accessible surrounding location of the target // // targetXLoc - target x location // targetYLoc - target y location // targetWidth - target width // targetHeight - target height // mobileType - target mobile type // int UnitArray::analyse_surround_location(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, char mobileType) { static char xIncreTable[4] = { 1, 0, -1, 0}; static char yIncreTable[4] = { 0, 1, 0, -1}; err_when(targetWidth<1 || targetWidth>4); Location *locPtr; int xLoc = targetXLoc-1; int yLoc = targetYLoc-1; int targetXLoc2 = targetXLoc + targetWidth - 1; int targetYLoc2 = targetYLoc + targetHeight - 1; int bound = 2*(targetWidth + targetHeight) + 4; // (x+2)*(y+2) - xy int increCount=4, xIncre, yIncre, found=0; err_when(targetWidth==3 && targetHeight==3 && bound!=16); for(int i=0; i=MAX_WORLD_X_LOC || yLoc<0 || yLoc>=MAX_WORLD_Y_LOC) unreachable_table[xLoc-targetXLoc+SHIFT_ADJUST][yLoc-targetYLoc+SHIFT_ADJUST] = 1; else { locPtr = world.get_loc(xLoc, yLoc); if(!locPtr->can_move(mobileType)) unreachable_table[xLoc-targetXLoc+SHIFT_ADJUST][yLoc-targetYLoc+SHIFT_ADJUST] = 1; else found++; } if((xLoc==targetXLoc-1 || xLoc==targetXLoc2+1) && (yLoc==targetYLoc-1 || yLoc==targetYLoc2+1)) // at the corner { if((++increCount)>=4) increCount = 0; xIncre = xIncreTable[increCount]; yIncre = yIncreTable[increCount]; } xLoc += xIncre; yLoc += yIncre; } return found; } //----------- End of function UnitArray::analyse_surround_location -----------// //--------- Begin of function UnitArray::check_nearby_location ---------// // check the target location to find out how many of its surrounding location // is not blocked // // targetXLoc - target x location // targetYLoc - target y location // xOffset - x offset from target x location // yOffset - y offset from target y location // targetWidth - target width // targetHeight - target height // targetMobileType - target mobile type // analyseResult - reference for returning // void UnitArray::check_nearby_location(int targetXLoc, int targetYLoc, char xOffset, char yOffset, int targetWidth, int targetHeight, char targetMobileType, int& analyseResult) { #ifdef DEBUG int backupAnalyseResult = analyseResult; char debugUnreachableTable[MAX_UNIT_SURROUND_SIZE][MAX_UNIT_SURROUND_SIZE]; memcpy(debugUnreachableTable, unreachable_table, sizeof(char)*MAX_UNIT_SURROUND_SIZE*MAX_UNIT_SURROUND_SIZE); #endif debug_result_check(analyseResult, targetWidth, targetHeight); static char leftXIncreTable[4] = { 1, 0, -1, 0}; static char leftYIncreTable[4] = { 0, 1, 0, -1}; static char rightXIncreTable[4] = { -1, 0, 1, 0}; static char rightYIncreTable[4] = { 0, 1, 0, -1}; err_when(targetWidth<1 || targetWidth>4); Location *locPtr; int targetXLoc2 = targetXLoc + targetWidth - 1; int targetYLoc2 = targetYLoc + targetHeight - 1; int bound = 2*(targetWidth + targetHeight) + 4; // (x+2)*(y+2) - xy int leftXLoc ,leftYLoc, leftContinue=1; int leftXIncre, leftYIncre, leftIncreCount; int rightXLoc, rightYLoc, rightContinue=1; int rightXIncre, rightYIncre, rightIncreCount=1; //-------------------------------------------------------------------------------------// // determine the initial situation //-------------------------------------------------------------------------------------// if((xOffset==-1 || xOffset==targetWidth) && (yOffset==-1 || yOffset==targetHeight)) // at the corner { if(xOffset==-1) { if(yOffset==-1) // upper left corner { leftXIncre = 1; leftYIncre = 0; leftIncreCount = 0; rightXIncre = 0; rightYIncre = 1; rightIncreCount = 1; } else // lower left corner { leftXIncre = 0; leftYIncre = -1; leftIncreCount = 3; rightXIncre = 1; rightYIncre = 0; rightIncreCount = 2; } } else { if(yOffset==-1) // upper right corner { leftXIncre = 0; leftYIncre = 1; leftIncreCount = 1; rightXIncre = -1; rightYIncre = 0; rightIncreCount = 0; } else // lower right corner { leftXIncre = -1; leftYIncre = 0; leftIncreCount = 2; rightXIncre = 0; rightYIncre = -1; rightIncreCount = 3; } } } else // at the edge { if(xOffset==-1) // left edge { leftXIncre = 0; leftYIncre = -1; leftIncreCount = 3; rightXIncre = 0; rightYIncre = 1; rightIncreCount = 1; } else if(xOffset==targetWidth) // right edge { leftXIncre = 0; leftYIncre = 1; leftIncreCount = 1; rightXIncre = 0; rightYIncre = -1; rightIncreCount = 3; } else if(yOffset==-1) // upper edge { leftXIncre = 1; leftYIncre = 0; leftIncreCount = 0; rightXIncre = -1; rightYIncre = 0; rightIncreCount = 0; } else if(yOffset==targetHeight) // lower edge { leftXIncre = -1; leftYIncre = 0; leftIncreCount = 2; rightXIncre = 1; rightYIncre = 0; rightIncreCount = 2; } } leftXLoc = rightXLoc = targetXLoc + xOffset; leftYLoc = rightYLoc = targetYLoc + yOffset; int canReach; int outBoundary; // true if out of map boundary //-------------------------------------------------------------------------------------// // count the reachable location //-------------------------------------------------------------------------------------// for(int i=1; i=4) leftIncreCount = 0; leftXIncre = leftXIncreTable[leftIncreCount]; leftYIncre = leftYIncreTable[leftIncreCount]; } if(leftXLoc>=0 && leftXLoc=0 && leftYLoccan_move(targetMobileType)) canReach = 1; } } else outBoundary = 1; if(canReach) leftContinue = 0; else if(!outBoundary) { err_when(unreachable_table[leftXLoc-targetXLoc+SHIFT_ADJUST][leftYLoc-targetYLoc+SHIFT_ADJUST]); unreachable_table[leftXLoc-targetXLoc+SHIFT_ADJUST][leftYLoc-targetYLoc+SHIFT_ADJUST] = 1; analyseResult--; debug_result_check(analyseResult, targetWidth, targetHeight); err_when(analyseResult<0); } #ifdef DEBUG else err_when(!unreachable_table[leftXLoc-targetXLoc+SHIFT_ADJUST][leftYLoc-targetYLoc+SHIFT_ADJUST]); #endif i++; } //------------------------------------------------------------// // process right hand side checking //------------------------------------------------------------// if(rightContinue) { canReach = 0; outBoundary = 0; rightXLoc += rightXIncre; rightYLoc += rightYIncre; if((rightXLoc==targetXLoc-1 || rightXLoc==targetXLoc2+1) && (rightYLoc==targetYLoc-1 || rightYLoc==targetYLoc2+1)) { if((++rightIncreCount)>=4) rightIncreCount = 0; rightXIncre = rightXIncreTable[rightIncreCount]; rightYIncre = rightYIncreTable[rightIncreCount]; } if(rightXLoc>=0 && rightXLoc=0 && rightYLoccan_move(targetMobileType)) canReach = 1; } } else outBoundary = 1; if(canReach) rightContinue = 0; else if(!outBoundary) { err_when(unreachable_table[rightXLoc-targetXLoc+SHIFT_ADJUST][rightYLoc-targetYLoc+SHIFT_ADJUST]); unreachable_table[rightXLoc-targetXLoc+SHIFT_ADJUST][rightYLoc-targetYLoc+SHIFT_ADJUST] = 1; analyseResult--; debug_result_check(analyseResult, targetWidth, targetHeight); err_when(analyseResult<0); } #ifdef DEBUG else err_when(!unreachable_table[rightXLoc-targetXLoc+SHIFT_ADJUST][rightYLoc-targetYLoc+SHIFT_ADJUST]); #endif } if(!leftContinue && !rightContinue) break; } } //----------- End of function UnitArray::check_nearby_location -----------// //--------- Begin of function UnitArray::handle_attack_target_totally_blocked ---------// // handle attacking while the target is totally blocked // // targetXLoc - target x loc // targetYLoc - target y loc // targetRecno - target recno // selectedUnitArray - selected units' recno // selectedCount - num of selected unit // targetType - 0 for wall, 1 for unit, 2 for firm, 3 for town // void UnitArray::handle_attack_target_totally_blocked(int targetXLoc, int targetYLoc, short targetRecno, short *selectedUnitArray, short selectedCount, int targetType) { if(unit_processed_count>0) // some units can reach the target surrounding { Unit *processedPtr, *unitPtr; int proCount = unit_processed_count - 1; int unproCount = selectedCount - proCount - 1; // number of unprocessed int sCount = selectedCount-1; int found, i, recno; #ifdef DEBUG int debugCount; #endif //------------------------------------------------------------------------------------// // use the result of those processed units as a reference of those unprocessed units //------------------------------------------------------------------------------------// while(unproCount) { err_when(unit_array.is_deleted(unit_processed_array[proCount])); processedPtr = (Unit*) get_ptr(unit_processed_array[proCount]); #ifdef DEBUG debugCount = 0; #endif err_when(sCount<0); do { #ifdef DEBUG debugCount++; err_when(debugCount>1000); #endif found = 0; recno = selectedUnitArray[sCount]; for(i=0; iselectedCount); sCount--; }while(found); unitPtr = (Unit *) get_ptr(recno); unitPtr->move_to(processedPtr->move_to_x_loc, processedPtr->move_to_y_loc); switch(targetType) { case 0: // wall unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_WALL; err_when(targetRecno); break; case 1: // unit unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_UNIT; err_when(!targetRecno); break; case 2: // firm unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_FIRM; err_when(!targetRecno); break; case 3: // town unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_TOWN; err_when(!targetRecno); break; } unitPtr->action_para = unitPtr->action_para2 = targetRecno; unitPtr->action_x_loc = unitPtr->action_x_loc2 = targetXLoc; unitPtr->action_y_loc = unitPtr->action_y_loc2 = targetYLoc; proCount--; if(proCount<0) proCount = unit_processed_count - 1; unproCount--; } } else // none of the units reaches the target surrounding { //----------------------------------------------------------------// // handle the case for 1x1 units now, no 2x2 units //----------------------------------------------------------------// //-*********** improve later ************-// int unprocessed = selectedCount; Unit *firstPtr = (Unit *) get_ptr(selectedUnitArray[unprocessed-1]); switch(targetType) { case 0: firstPtr->attack_wall(targetXLoc, targetYLoc); break; case 1: firstPtr->attack_unit(targetXLoc, targetYLoc); break; case 2: firstPtr->attack_firm(targetXLoc, targetYLoc); break; case 3: firstPtr->attack_town(targetXLoc, targetYLoc); break; } int moveToXLoc = firstPtr->move_to_x_loc; int moveToYLoc = firstPtr->move_to_y_loc; /*if(seek_path.path_status==PATH_NODE_USED_UP) { int debug = 0; }*/ Unit *unitPtr; while(unprocessed) { unitPtr = (Unit *) get_ptr(selectedUnitArray[unprocessed-1]); unitPtr->move_to(moveToXLoc, moveToYLoc); switch(targetType) { case 0: // wall unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_WALL; unitPtr->action_para = unitPtr->action_para2 = 0; break; case 1: // unit unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_UNIT; unitPtr->action_para = unitPtr->action_para2 = targetRecno; break; case 2: // firm unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_FIRM; unitPtr->action_para = unitPtr->action_para2 = targetRecno; break; case 3: // town unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_TOWN; unitPtr->action_para = unitPtr->action_para2 = targetRecno; break; } unitPtr->action_x_loc = unitPtr->action_x_loc2 = targetXLoc; unitPtr->action_y_loc = unitPtr->action_y_loc2 = targetYLoc; unprocessed--; } } } //----------- End of function UnitArray::handle_attack_target_totally_blocked -----------//