123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978 |
- /*
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
- //Filename : OUNITAT3.CPP
- //Description : Object Unit's decision making functions for attacking same or different type of target and reactivating
- // idle unit that are ordered to attack
- //Owner : Alex
- #include <ALL.h>
- #include <OWORLD.h>
- #include <OUNIT.h>
- #include <OGAME.h>
- #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::move_try_to_range_attack ---------//
- // return 1 if it is possible to reach a location to attack the target
- // return 0 otherwise
- //
- // <Unit*> targetUnit - pointer to target unit
- //
- int Unit::move_try_to_range_attack(Unit* targetUnit)
- {
- int curXLoc = next_x_loc();
- int curYLoc = next_y_loc();
- int targetXLoc = targetUnit->next_x_loc();
- int targetYLoc = targetUnit->next_y_loc();
- if(world.get_loc(curXLoc, curYLoc)->region_id==world.get_loc(targetXLoc, targetYLoc)->region_id)
- {
- //------------ for same region id, search now ---------------//
- if(search(targetXLoc, targetYLoc, 1, SEARCH_MODE_TO_ATTACK, action_para))
- return 1;
- else // search failure,
- {
- stop2(KEEP_DEFENSE_MODE);
- return 0;
- }
- }
- else
- {
- //--------------- different territory ------------------//
- int targetWidth = targetUnit->sprite_info->loc_width;
- int targetHeight = targetUnit->sprite_info->loc_height;
- int maxRange = max_attack_range();
- if(possible_place_for_range_attack(targetXLoc, targetYLoc, targetWidth, targetHeight, maxRange))
- {
- //---------------------------------------------------------------------------------//
- // space is found, attack target now
- //---------------------------------------------------------------------------------//
- if(move_to_range_attack(targetXLoc, targetYLoc, targetUnit->sprite_id, SEARCH_MODE_ATTACK_UNIT_BY_RANGE, maxRange))
- return 1;
- else
- {
- stop2(KEEP_DEFENSE_MODE);
- return 0;
- }
- return 1;
- }
- else
- {
- //---------------------------------------------------------------------------------//
- // unable to find location to attack the target, stop or move to the target
- //---------------------------------------------------------------------------------//
- 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, 1); // abort attacking, just call move_to() instead
- else
- stop2(KEEP_DEFENSE_MODE);
- return 0;
- }
- }
- return 0;
- }
- //----------- End of function Unit::move_try_to_range_attack -----------//
- //--------- Begin of function Unit::move_to_range_attack ---------//
- // search and attack target
- //
- // <int> targetXLoc - target x location
- // <int> targetYLoc - target y location
- // <short> miscNo - is sprite_id if target is a unit
- // is firm_id if target is a firm
- // is 0 if target is a town or a wall
- // <short> searchMode - search mode being used
- // <short> maxRange - max attack range of this unit
- //
- int Unit::move_to_range_attack(int targetXLoc, int targetYLoc, short miscNo, short searchMode, short maxRange)
- {
- //---------------------------------------------------------------------------------//
- // part 1, searching
- //---------------------------------------------------------------------------------//
- seek_path.set_attack_range_para(maxRange);
- search(targetXLoc, targetYLoc, 1, searchMode, miscNo);
- seek_path.reset_attack_range_para();
- //search(targetXLoc, targetYLoc, 1, searchMode, maxRange);
- if(result_node_array==NULL || result_node_count==0)
- return 0;
- //---------------------------------------------------------------------------------//
- // part 2, editing result path
- //---------------------------------------------------------------------------------//
- Location *locPtr = world.get_loc(next_x_loc(), next_y_loc());
- err_when(!locPtr);
- int regionId = locPtr->region_id; // the region_id this unit in
- //----------------------------------------------------//
- err_when(result_node_count<2);
- ResultNode* editNode1 = result_node_array + result_node_count - 1;
- ResultNode* editNode2 = editNode1-1;
- int vecX = editNode1->node_x - editNode2->node_x;
- int vecY = editNode1->node_y - editNode2->node_y;
- if(vecX)
- vecX = ((vecX>0) ? 1 : -1)*move_step_magn();
- if(vecY)
- vecY = ((vecY>0) ? 1 : -1)*move_step_magn();
- int x = editNode1->node_x;
- int y = editNode1->node_y;
- int i, found=0, removedStep=0, preX, preY;
- for(i=result_node_count; i>1; i--)
- {
- while(x!=editNode2->node_x || y!=editNode2->node_y)
- {
- locPtr = world.get_loc(x, y);
- if(locPtr->region_id == regionId)
- {
- found = i;
- preX = x;
- preY = y;
- break;
- }
-
- x -= vecX;
- y -= vecY;
- removedStep++;
- }
- if(found)
- break;
- editNode1 = editNode2;
- editNode2--;
-
- vecX = editNode1->node_x - editNode2->node_x;
- vecY = editNode1->node_y - editNode2->node_y;
- if(vecX)
- vecX = ((vecX>0) ? 1 : -1)*move_step_magn();
- if(vecY)
- vecY = ((vecY>0) ? 1 : -1)*move_step_magn();
-
- x = editNode1->node_x;
- y = editNode1->node_y;
- }
- //---------------------------------------------------------------------------//
- // update unit parameters
- //---------------------------------------------------------------------------//
- if(found)
- {
- result_node_count = found;
- ResultNode* lastNode = result_node_array + result_node_count - 1;
- int goX = go_x>>ZOOM_X_SHIFT_COUNT;
- int goY = go_y>>ZOOM_Y_SHIFT_COUNT;
- //---------------------------------------------------------------------//
- // note: build?Loc-1, build?Loc+width, build?Loc+height may <0 or
- // >MAX_WORLD_?_LOC. To prevent errors from occuring, goX, goY
- // must not be outside the map boundary
- //---------------------------------------------------------------------//
- if(goX==editNode1->node_x && goY==editNode1->node_y)
- {
- go_x = preX*ZOOM_LOC_WIDTH;
- go_y = preY*ZOOM_LOC_HEIGHT;
- }
- else if(result_node_count==2)
- {
- int magnCG = m.points_distance(cur_x, cur_y, go_x, go_y);
- int magnNG = m.points_distance(next_x, next_y, go_x, go_y);
- err_when(magnCG==0 && magnNG==0);
- if(magnCG && magnNG)
- {
- //---------- lie on the same line -----------//
- if( (go_x-cur_x)/magnCG==(go_x-next_x)/magnNG && (go_y-cur_y)/magnCG==(go_y-next_y)/magnNG )
- {
- go_x = preX*ZOOM_LOC_WIDTH;
- go_y = preY*ZOOM_LOC_HEIGHT;
- }
- }
- }
- lastNode->node_x = preX;
- lastNode->node_y = preY;
- move_to_x_loc = lastNode->node_x;
- move_to_y_loc = lastNode->node_y;
-
- result_path_dist -= (removedStep)*move_step_magn();
- err_when((cur_x!=next_x || cur_y!=next_y) && // is not blocked
- (check_unit_dir1=get_dir(cur_x, cur_y, next_x, next_y))!=(check_unit_dir2=get_dir(cur_x, cur_y, go_x, go_y)));
- }
- return found;
- }
- //----------- End of function Unit::move_to_range_attack -----------//
- //--------- Begin of function Unit::can_attack_different_type_target ---------//
- // return 1 if able to use range_attack
- // return 0 otherwise
- //
- int Unit::can_attack_different_target_type()
- {
- int maxRange = max_attack_range();
- if(mobile_type==UNIT_LAND && !maxRange)
- return 0; // unable to do range attack or cannot attack
-
- if(maxRange>1)
- return maxRange;
- else
- return 0;
- }
- //----------- End of function Unit::can_attack_different_type_target -----------//
- //--------- Begin of function Unit::possible_place_for_range_attack ---------//
- // check whether there is any place for this unit to attack the target
- //
- // <int> targetXLoc - target x location
- // <int> targetYLoc - target y location
- // <int> targetWidth - target width
- // <int> targetHeight - target height
- // <int> maxRange - max attack range of this unit
- //
- // return 1 if place found
- // return 0 otherwise
- //
- int Unit::possible_place_for_range_attack(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, int maxRange)
- {
- err_when(targetXLoc<0 || targetXLoc>=MAX_WORLD_X_LOC || targetYLoc<0 || targetYLoc>=MAX_WORLD_Y_LOC);
- err_when(maxRange==0);
- if(mobile_type==UNIT_AIR)
- return 1; // air unit can reach any region
-
- int curXLoc = next_x_loc();
- int curYLoc = next_y_loc();
- if(abs(curXLoc-targetXLoc)<=maxRange && abs(curYLoc-targetYLoc)<=maxRange) // inside the attack range
- return 1;
- //----------------- init parameters -----------------//
- Location *locPtr = world.get_loc(curXLoc, curYLoc);
- int regionId = locPtr->region_id;
- int xLoc1 = max(targetXLoc-maxRange, 0);
- int yLoc1 = max(targetYLoc-maxRange, 0);
- int xLoc2 = min(targetXLoc+targetWidth-1+maxRange, MAX_WORLD_X_LOC-1);
- int yLoc2 = min(targetYLoc+targetHeight-1+maxRange, MAX_WORLD_Y_LOC-1);
- int checkXLoc, checkYLoc;
- //--------- do adjustment for UNIT_SEA and UNIT_AIR ---------//
- if(mobile_type!=UNIT_LAND)
- {
- if(xLoc1%2)
- xLoc1++;
- if(yLoc1%2)
- yLoc1++;
- if(xLoc2%2)
- xLoc2--;
- if(yLoc2%2)
- yLoc2--;
- }
- //-------- checking for surrounding location ----------//
- switch(mobile_type)
- {
- case UNIT_LAND:
- for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
- {
- locPtr = world.get_loc(checkXLoc, yLoc1);
- if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
- return 1;
- locPtr = world.get_loc(checkXLoc, yLoc2);
- if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
- return 1;
- }
- for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
- {
- locPtr = world.get_loc(xLoc1, checkYLoc);
- if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
- return 1;
- locPtr = world.get_loc(xLoc2, checkYLoc);
- if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
- return 1;
- }
- break;
- case UNIT_SEA:
- for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
- {
- if(checkXLoc%2==0 && yLoc1%2==0)
- {
- locPtr = world.get_loc(checkXLoc, yLoc1);
- if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
- return 1;
- }
- if(checkXLoc%2==0 && yLoc2%2==0)
- {
- locPtr = world.get_loc(checkXLoc, yLoc2);
- if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
- return 1;
- }
- }
- for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
- {
- if(xLoc1%2==0 && checkYLoc%2==0)
- {
- locPtr = world.get_loc(xLoc1, checkYLoc);
- if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
- return 1;
- }
- if(xLoc2%2==0 && checkYLoc%2==0)
- {
- locPtr = world.get_loc(xLoc2, checkYLoc);
- if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
- return 1;
- }
- }
- break;
- case UNIT_AIR:
- for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
- {
- if(checkXLoc%2==0 && yLoc1%2==0)
- {
- locPtr = world.get_loc(checkXLoc, yLoc1);
- if(locPtr->is_accessible(mobile_type))
- return 1;
- }
- if(checkXLoc%2==0 && yLoc2%2==0)
- {
- locPtr = world.get_loc(checkXLoc, yLoc2);
- if(locPtr->is_accessible(mobile_type))
- return 1;
- }
- }
- for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
- {
- if(xLoc1%2==0 && checkYLoc%2==0)
- {
- locPtr = world.get_loc(xLoc1, checkYLoc);
- if(locPtr->is_accessible(mobile_type))
- return 1;
- }
- if(xLoc2%2==0 && checkYLoc%2==0)
- {
- locPtr = world.get_loc(xLoc2, checkYLoc);
- if(locPtr->is_accessible(mobile_type))
- return 1;
- }
- }
- break;
- default: err_here();
- break;
- }
- return 0;
- }
- //----------- End of function Unit::possible_place_for_range_attack -----------//
- //=====================================================================================//
- //--------- Begin of function Unit::space_for_attack ---------//
- // check whether there is any place for the unit to attack target.
- //
- // <int> targetXLoc - target x location
- // <int> targetYLoc - target y location
- // <char> targetMobileType - target mobile type
- // <int> targetWidth - target width
- // <int> targetHeight - target height
- //
- int Unit::space_for_attack(int targetXLoc, int targetYLoc, char targetMobileType, int targetWidth, int targetHeight)
- {
- if(mobile_type==UNIT_LAND && targetMobileType==UNIT_LAND)
- return space_around_target(targetXLoc, targetYLoc, targetWidth, targetHeight);
- if((mobile_type==UNIT_SEA && targetMobileType==UNIT_SEA) ||
- (mobile_type==UNIT_AIR && targetMobileType==UNIT_AIR))
- return space_around_target_ver2(targetXLoc, targetYLoc, targetWidth, targetHeight);
- //-------------------------------------------------------------------------//
- // mobile_type is differet from that of target unit
- //-------------------------------------------------------------------------//
- Location *locPtr = world.get_loc(next_x_loc(), next_y_loc());
- if(mobile_type==UNIT_LAND && targetMobileType==UNIT_SEA &&
- !can_attack_different_target_type() &&
- ship_surr_has_free_land(targetXLoc, targetYLoc, locPtr->region_id))
- return 1;
- int maxRange = max_attack_range();
- if(maxRange==1)
- return 0;
- if(free_space_for_range_attack(targetXLoc, targetYLoc, targetWidth, targetHeight, targetMobileType, maxRange))
- return 1;
- return 0;
- }
- //----------- End of function Unit::space_for_attack -----------//
- //--------- Begin of function Unit::space_around_target ---------//
- // check the surroundung location around a square, and the result is
- // stored in the blocked_edge[] by bit
- //
- // <int> squareXLoc - upper left x location of target
- // <int> squareYLoc - upper left y location of target
- // <int> width - target width
- // <int> height - target height
- //
- // return 1 if the surrounding location that can_move is not equal to
- // the result in the blocked_edge stored previously.
- // return 0 otherwise (i.e. all location situation is same as before)
- //
- int Unit::space_around_target(int squareXLoc, int squareYLoc, int width, int height)
- {
- err_when(width<=0 || height<=0);
- // edge 1
- // 1 1 4
- // edge 2 2 x 4 edge 4
- // 2 3 3
- // edge3
- Location *locPtr;
- Unit *unitPtr;
- char sum, locWeight;
- int testXLoc, testYLoc, i, equal=1;
- //------------------ top edge ---------------//
- sum = 0;
- if((testYLoc=squareYLoc-1) >= 0)
- {
- if(squareXLoc>=1) // have upper left corner
- {
- i=-1;
- locWeight = 1;
- }
- else
- {
- i = 0;
- locWeight = 2;
- }
-
- for(; i<width; i++, locWeight<<=1)
- {
- locPtr = world.get_loc(squareXLoc+i, testYLoc);
- if(locPtr->can_move(mobile_type))
- sum ^= locWeight;
- else if(locPtr->has_unit(mobile_type))
- {
- unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
- if(unitPtr->cur_action!=SPRITE_ATTACK)
- sum ^= locWeight;
- }
- }
- }
- if(blocked_edge[0]!=sum)
- {
- blocked_edge[0] = sum;
- equal = 0;
- }
- //----------------- left edge -----------------//
- sum = 0;
- if((testXLoc=squareXLoc-1) >= 0)
- {
- if(squareYLoc+height<=MAX_WORLD_Y_LOC-1) // have lower left corner
- {
- i = height;
- locWeight = 1;
- }
- else
- {
- i = height - 1;
- locWeight = 2;
- }
- for(; i>=0; i--, locWeight<<=1)
- {
- locPtr = world.get_loc(testXLoc, squareYLoc+i);
- if(locPtr->can_move(mobile_type))
- sum ^= locWeight;
- else if(locPtr->has_unit(mobile_type))
- {
- unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
- if(unitPtr->cur_action!=SPRITE_ATTACK)
- sum ^= locWeight;
- }
- }
- }
- if(blocked_edge[1]!=sum)
- {
- blocked_edge[1] = sum;
- equal = 0;
- }
- //------------------- bottom edge ------------------//
- sum = 0;
- if((testYLoc=squareYLoc+height) <= MAX_WORLD_Y_LOC-1)
- {
- if(squareXLoc+width<=MAX_WORLD_X_LOC-1) // have lower right corner
- {
- i = width;
- locWeight = 1;
- }
- else
- {
- i = width - 1;
- locWeight = 2;
- }
- for(; i>=0; i--, locWeight<<=1)
- {
- locPtr = world.get_loc(squareXLoc+i, testYLoc);
- if(locPtr->can_move(mobile_type))
- sum ^= locWeight;
- else if(locPtr->has_unit(mobile_type))
- {
- unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
- if(unitPtr->cur_action!=SPRITE_ATTACK)
- sum ^= locWeight;
- }
- }
- }
- if(blocked_edge[2]!=sum)
- {
- blocked_edge[2] = sum;
- equal = 0;
- }
- //---------------------- right edge ----------------------//
- sum = 0;
- if((testXLoc=squareXLoc+width) <= MAX_WORLD_X_LOC-1)
- {
- if(squareYLoc>=1) // have upper right corner
- {
- i = -1;
- locWeight = 1;
- }
- else
- {
- i = 0;
- locWeight = 2;
- }
- for(; i<height; i++, locWeight<<=1)
- {
- locPtr = world.get_loc(testXLoc, squareYLoc+i);
- if(locPtr->can_move(mobile_type))
- sum ^= locWeight;
- else if(locPtr->has_unit(mobile_type))
- {
- unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
- if(unitPtr->cur_action!=SPRITE_ATTACK)
- sum ^= locWeight;
- }
- }
- }
- if(blocked_edge[3]!=sum)
- {
- blocked_edge[3] = sum;
- equal = 0;
- }
- return !equal;
- }
- //----------- End of function Unit::space_around_target -----------//
- //--------- Begin of function Unit::space_around_target_ver2 ---------//
- // similar function as space_around_target()
- // This version is for sea unit and air unit only
- //
- int Unit::space_around_target_ver2(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight)
- {
- err_when(targetWidth<=0 || targetHeight<=0);
- Location *locPtr;
- Unit *unitPtr;
- char sum, locWeight;
- int xLoc1, yLoc1, xLoc2, yLoc2;
- int i, equal=1;
- //int testXLoc, testYLoc,
- xLoc1 = targetXLoc%2 ? targetXLoc-1 : targetXLoc-2;
- yLoc1 = targetYLoc%2 ? targetYLoc-1 : targetYLoc-2;
- xLoc2 = (targetXLoc+targetWidth-1)%2 ? targetXLoc+targetWidth : targetXLoc+targetWidth+1;
- yLoc2 = (targetYLoc+targetHeight-1)%2 ? targetYLoc+targetHeight : targetYLoc+targetHeight+1;
- //------------------------ top edge ------------------------//
- sum = 0;
- if(yLoc1>=0)
- {
- if(xLoc1>=0)
- {
- i = xLoc1;
- locWeight = 1;
- }
- else
- {
- i = xLoc1 + 2;
- err_when(i<0);
- locWeight = 2;
- }
- for(; i<=xLoc2; i+=2, locWeight<<=1)
- {
- locPtr = world.get_loc(i, yLoc1);
- if(locPtr->can_move(mobile_type))
- sum ^= locWeight;
- else if(locPtr->has_unit(mobile_type))
- {
- unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
- if(unitPtr->cur_action!=SPRITE_ATTACK)
- sum ^= locWeight;
- }
- }
- }
-
- if(blocked_edge[0]!=sum)
- {
- blocked_edge[0] = sum;
- equal = 0;
- }
- //---------------------- left edge -----------------------//
- sum = 0;
- if(xLoc1>=0)
- {
- if(yLoc2<=MAX_WORLD_Y_LOC-1)
- {
- i = yLoc2;
- locWeight = 1;
- }
- else
- {
- i = yLoc2-2;
- err_when(i>=MAX_WORLD_Y_LOC);
- locWeight = 2;
- }
- for(; i>yLoc1; i-=2, locWeight<<=1)
- {
- locPtr = world.get_loc(xLoc1, i);
- if(locPtr->can_move(mobile_type))
- sum ^= locWeight;
- else if(locPtr->has_unit(mobile_type))
- {
- unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
- if(unitPtr->cur_action!=SPRITE_ATTACK)
- sum ^= locWeight;
- }
- }
- }
- if(blocked_edge[1]!=sum)
- {
- blocked_edge[1] = sum;
- equal = 0;
- }
- //----------------------- bottom edge ---------------------------//
- sum = 0;
- if(yLoc2<=MAX_WORLD_Y_LOC-1)
- {
- if(xLoc2<=MAX_WORLD_X_LOC-1)
- {
- i = xLoc2;
- locWeight = 1;
- }
- else
- {
- i = xLoc2-2;
- err_when(i>=MAX_WORLD_X_LOC);
- locWeight = 2;
- }
- for(; i>xLoc1; i-=2, locWeight<<=1)
- {
- locPtr = world.get_loc(i, yLoc2);
- if(locPtr->can_move(mobile_type))
- sum ^= locWeight;
- else if(locPtr->has_unit(mobile_type))
- {
- unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
- if(unitPtr->cur_action!=SPRITE_ATTACK)
- sum ^= locWeight;
- }
- }
- }
- if(blocked_edge[2]!=sum)
- {
- blocked_edge[2] = sum;
- equal = 0;
- }
- //---------------------- right edge ------------------------//
- sum = 0;
- if(xLoc2<=MAX_WORLD_X_LOC-1)
- {
- if(yLoc1>=0)
- {
- i = yLoc1;
- locWeight = 1;
- }
- else
- {
- i = yLoc1+2;
- err_when(i<0);
- locWeight = 2;
- }
- for(; i<yLoc2; i+=2, locWeight<<=1)
- {
- locPtr = world.get_loc(xLoc2, i);
- if(locPtr->can_move(mobile_type))
- sum ^= locWeight;
- else if(locPtr->has_unit(mobile_type))
- {
- unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
- if(unitPtr->cur_action!=SPRITE_ATTACK)
- sum ^= locWeight;
- }
- }
- }
- if(blocked_edge[3]!=sum)
- {
- blocked_edge[3] = sum;
- equal = 0;
- }
- return !equal;
- }
- //----------- End of function Unit::space_around_target_ver2 -----------//
- //--------- Begin of function Unit::ship_surr_has_free_land ---------//
- // check surrounding place for close attack by land units
- //
- // <int> targetXLoc - target x loc
- // <int> targetYLoc - target y loc
- // <UCHAR> regionId - region id
- //
- // return 1 if there is space for the land unit to move to ship surrounding for close attack
- // return 0 otherwise
- //
- int Unit::ship_surr_has_free_land(int targetXLoc, int targetYLoc, UCHAR regionId)
- {
- err_when(mobile_type!=UNIT_LAND);
- Location *locPtr;
- int xShift, yShift, checkXLoc, checkYLoc;
- for(int i=2; i<9; i++)
- {
- m.cal_move_around_a_point(i, 3, 3, xShift, yShift);
- checkXLoc = targetXLoc+xShift;
- checkYLoc = targetYLoc+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->region_id==regionId && locPtr->can_move(mobile_type))
- return 1;
- }
- return 0;
- }
- //----------- End of function Unit::ship_surr_has_free_land -----------//
- //--------- Begin of function Unit::free_space_for_range_attack ---------//
- // similar to possible_place_for_range_attack() but checking can_move() rather than is_accessible()
- //
- int Unit::free_space_for_range_attack(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, int targetMobileType, int maxRange)
- {
- err_when(targetXLoc<0 || targetXLoc>=MAX_WORLD_X_LOC || targetYLoc<0 || targetYLoc>=MAX_WORLD_Y_LOC);
- err_when(maxRange==0);
- //if(mobile_type==UNIT_AIR)
- // return 1; // air unit can reach any region
-
- int curXLoc = next_x_loc();
- int curYLoc = next_y_loc();
- if(abs(curXLoc-targetXLoc)<=maxRange && abs(curYLoc-targetYLoc)<=maxRange) // inside the attack range
- return 1;
- Location *locPtr = world.get_loc(curXLoc, curYLoc);
- int regionId = locPtr->region_id;
- int xLoc1 = max(targetXLoc-maxRange, 0);
- int yLoc1 = max(targetYLoc-maxRange, 0);
- int xLoc2 = min(targetXLoc+targetWidth-1+maxRange, MAX_WORLD_X_LOC-1);
- int yLoc2 = min(targetYLoc+targetHeight-1+maxRange, MAX_WORLD_Y_LOC-1);
- int checkXLoc, checkYLoc;
- //--------- do adjustment for UNIT_SEA and UNIT_AIR ---------//
- if(mobile_type!=UNIT_LAND)
- {
- if(xLoc1%2)
- xLoc1++;
- if(yLoc1%2)
- yLoc1++;
- if(xLoc2%2)
- xLoc2--;
- if(yLoc2%2)
- yLoc2--;
- }
- //-------- checking for surrounding location ----------//
- switch(mobile_type)
- {
- case UNIT_LAND:
- for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
- {
- locPtr = world.get_loc(checkXLoc, yLoc1);
- if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
- return 1;
- locPtr = world.get_loc(checkXLoc, yLoc2);
- if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
- return 1;
- }
- for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
- {
- locPtr = world.get_loc(xLoc1, checkYLoc);
- if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
- return 1;
- locPtr = world.get_loc(xLoc2, checkYLoc);
- if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
- return 1;
- }
- break;
- case UNIT_SEA:
- for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
- {
- if(checkXLoc%2==0 && yLoc1%2==0)
- {
- locPtr = world.get_loc(checkXLoc, yLoc1);
- if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
- return 1;
- }
- if(checkXLoc%2==0 && yLoc2%2==0)
- {
- locPtr = world.get_loc(checkXLoc, yLoc2);
- if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
- return 1;
- }
- }
- for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
- {
- if(xLoc1%2==0 && checkYLoc%2==0)
- {
- locPtr = world.get_loc(xLoc1, checkYLoc);
- if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
- return 1;
- }
- if(xLoc2%2==0 && checkYLoc%2==0)
- {
- locPtr = world.get_loc(xLoc2, checkYLoc);
- if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
- return 1;
- }
- }
- break;
- case UNIT_AIR:
- for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
- {
- if(checkXLoc%2==0 && yLoc1%2==0)
- {
- locPtr = world.get_loc(checkXLoc, yLoc1);
- if(locPtr->can_move(mobile_type))
- return 1;
- }
- if(checkXLoc%2==0 && yLoc2%2==0)
- {
- locPtr = world.get_loc(checkXLoc, yLoc2);
- if(locPtr->can_move(mobile_type))
- return 1;
- }
- }
- for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
- {
- if(xLoc1%2==0 && checkYLoc%2==0)
- {
- locPtr = world.get_loc(xLoc1, checkYLoc);
- if(locPtr->can_move(mobile_type))
- return 1;
- }
- if(xLoc2%2==0 && checkYLoc%2==0)
- {
- locPtr = world.get_loc(xLoc2, checkYLoc);
- if(locPtr->can_move(mobile_type))
- return 1;
- }
- }
- break;
- default: err_here();
- break;
- }
- return 0;
- }
- //----------- End of function Unit::free_space_for_range_attack -----------//
|