123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291 |
- /*
- * 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 : OSPATH.CPP
- //Description : Object SeekPath
- //Owner :
- #include <math.h>
- #include <stdlib.h>
- #include <ALL.h>
- #include <OWORLD.h>
- #include <OSPATH.h>
- #include <OFIRM.h>
- #include <OTOWN.h>
- #include <OUNIT.h>
- #include <OSYS.h>
- #include <ONATION.h>
- #ifdef NO_DEBUG_SEARCH
- #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
- #define ZOOM_LOC_HALF_WIDTH ZOOM_LOC_WIDTH/2
- #define ZOOM_LOC_HALF_HEIGHT ZOOM_LOC_HEIGHT/2
- //----------- Define static variables -----------//
- static Location* world_loc_matrix;
- static int cur_stack_pos=0;
- static Node* stack_array[MAX_STACK_NUM];
- static DWORD group_id;
- static short search_mode;
- static char mobile_type;
- static char seek_nation_recno;
- static int attack_range; // used in search_mode = SEARCH_MODE_ATTACK_UNIT_BY_RANGE
- static short target_recno; // used in search_mode = SEARCH_MODE_TO_ATTACK or SEARCH_MODE_TO_VEHICLE, get from miscNo
- static UCHAR region_id; // used in search_mode = SEARCH_MODE_TO_LAND_FOR_SHIP
- static short building_id; // used in search_mode = SEARCH_MODE_TO_FIRM or SEARCH_MODE_TO_TOWN, get from miscNo
- //======================================================================//
- // 1) if search_mode = SEARCH_MODE_TO_FIRM or SEARCH_MODE_TO_TOWN
- // the building top_left to bottom_right positions
- // 2) if search_mode = SEARCH_MODE_ATTACK_UNIT_BY_RANGE,
- // the effective attacking region top_left to bottom_right positions
- //======================================================================//
- static int building_x1, building_y1, building_x2, building_y2;
- static FirmInfo *search_firm_info;
- static int max_node_num;
- static short *reuse_node_matrix_ptr;
- static Node *reuse_result_node_ptr;
- static short final_dest_x; // in search_mode SEARCH_MODE_REUSE, dest_x and dest_y may set to a different value.
- static short final_dest_y; // i.e. the value used finally may not be the real dest_? given.
- //------- aliasing class member vars for fast access ------//
- static SeekPath* cur_seek_path;
- static short cur_dest_x, cur_dest_y;
- static short* cur_node_matrix;
- static Node* cur_node_array;
- static short cur_border_x1, cur_border_y1, cur_border_x2, cur_border_y2;
- static char nation_passable[MAX_NATION+1] = {0}; // Note: position 0 is not used for faster access
- static char search_sub_mode;
- //----------- Define static functions -----------//
- static void stack_push(Node *nodePtr);
- static Node* stack_pop();
- //-***************************************************************************-//
- //-*************************** for debuging **********************************-//
- //-***************************************************************************-//
- #ifdef DEBUG
- static int is_yielding = 0;
- static ResultNode *debugNode1, *debugNode2;
- static int dcount;
- static int vX, vY; // for debug only
- //---------- function debug_check() ------------//
- void debug_check(ResultNode *nodeArray, int count)
- {
- debugNode1 = nodeArray;
- debugNode2 = nodeArray+1;
-
- for(dcount=1; dcount<count; dcount++, debugNode1++, debugNode2++)
- {
- err_when(debugNode1->node_x<0 || debugNode1->node_x>=MAX_WORLD_X_LOC ||
- debugNode1->node_y<0 || debugNode1->node_y>=MAX_WORLD_Y_LOC);
- vX = debugNode2->node_x - debugNode2->node_x;
- vY = debugNode2->node_y - debugNode2->node_y;
- err_when(vX!=0 && vY!=0 && (abs(vX)!=abs(vY)));
- }
- err_when(debugNode1->node_x<0 || debugNode1->node_x>=MAX_WORLD_X_LOC ||
- debugNode1->node_y<0 || debugNode1->node_y>=MAX_WORLD_Y_LOC);
- }
- //----------- function debug_check_smode_exclude_hostile() -------------//
- void debug_check_smode_exclude_hostile(ResultNode *nodeArray, int count)
- {
- ResultNode *curNode = nodeArray;
- ResultNode *nextNode = nodeArray+1;
- Location *locPtr;
- int checkXLoc, checkYLoc, vecX, vecY, magn;
- for(int ij=1; ij<count; ij++, curNode++, nextNode++)
- {
- checkXLoc = curNode->node_x;
- checkYLoc = curNode->node_y;
- vecX = nextNode->node_x-curNode->node_x;
- vecY = nextNode->node_y-curNode->node_y;
- magn = (abs(vecX)>=abs(vecY)) ? abs(vecX) : abs(vecY);
- if(vecX) vecX /= abs(vecX);
- if(vecY) vecY /= abs(vecY);
- for(int jk=0; jk<magn; jk++)
- {
- checkXLoc += vecX;
- checkYLoc += vecY;
- locPtr = world.get_loc(checkXLoc, checkYLoc);
- err_when(locPtr->power_nation_recno && !nation_passable[locPtr->power_nation_recno]);
- }
- }
- }
- //-------------- function debug_check_sailable_path() --------------//
- void debug_check_sailable_path(ResultNode *nodeArray, int count)
- {
- ResultNode *debugPtr1 = nodeArray;
- ResultNode *debugPtr2 = nodeArray+1;
- int di=1, dj, dvecX, dvecY, magn;
- while(di<count)
- {
- dvecX = debugPtr2->node_x-debugPtr1->node_x;
- dvecY = debugPtr2->node_y-debugPtr1->node_y;
- magn = (abs(dvecX) > abs(dvecY)) ? abs(dvecX) : abs(dvecY);
- dvecX /= magn;
- dvecY /= magn;
- for(dj=1; dj<=magn; dj++)
- err_when(!world.get_loc(debugPtr1->node_x+dvecX*dj, debugPtr1->node_y+dvecY*dj)->sailable());
-
- di++;
- debugPtr1++;
- debugPtr2++;
- }
- }
- #endif
- #ifdef DEBUG
- #define debug_check_path(nodeArray, count) debug_check((nodeArray), (count))
- #define debug_check_sub_mode(nodeArray, count) debug_check_smode_exclude_hostile((nodeArray), (count))
- #define debug_check_sea_sailable(nodeArray, count) debug_check_sailable_path((nodeArray), (count))
- #else
- #define debug_check_path(nodeArray, count)
- #define debug_check_sub_mode(nodeArray, count)
- #define debug_check_sea_sailable(nodeArray, count)
- #endif
- //-***************************************************************************-//
- //-**************************** end debuging *********************************-//
- //-***************************************************************************-//
- //------- Begin of static function sys_yield ------//
- static void sys_yield()
- {
- #ifdef DEBUG
- is_yielding++;
- #endif
-
- //sys.yield();
-
- #ifdef DEBUG
- is_yielding = 0;
- #endif
- }
- //-------- End of static function sys_yield ------//
- //------- Begin of static function can_move_to ------//
- static int can_move_to(int xLoc, int yLoc)
- {
- Location *locPtr = world_loc_matrix+yLoc*MAX_WORLD_X_LOC+xLoc;
- Unit *unitPtr;
- short recno;
- char powerNationRecno;
- UCHAR unitCurAction;
- //------ check terrain id. -------//
- switch(mobile_type)
- {
- case UNIT_LAND:
- if(search_sub_mode==SEARCH_SUB_MODE_PASSABLE && (powerNationRecno=locPtr->power_nation_recno) &&
- !nation_passable[powerNationRecno])
- return 0;
- if(search_mode<SEARCH_MODE_TO_FIRM) //------ be careful for the checking for search_mode>=SEARCH_MODE_TO_FIRM
- {
- //------------------------------------------------------------------------//
- if(!locPtr->walkable())
- return 0;
-
- recno = locPtr->cargo_recno;
- if(!recno)
- return 1;
- switch(search_mode)
- {
- case SEARCH_MODE_IN_A_GROUP: // group move
- case SEARCH_MODE_REUSE: // path-reuse
- break;
- case SEARCH_MODE_A_UNIT_IN_GROUP: // a unit in a group
- unitPtr = unit_array[recno];
- return unitPtr->cur_action==SPRITE_MOVE && unitPtr->unit_id!=UNIT_CARAVAN;
- case SEARCH_MODE_TO_ATTACK: // to attack target
- case SEARCH_MODE_TO_VEHICLE: // move to a vehicle
- if(recno==target_recno)
- return 1;
- break;
- case SEARCH_MODE_BLOCKING: // 2x2 unit blocking
- unitPtr = unit_array[recno];
- return unitPtr->unit_group_id==group_id && (unitPtr->cur_action==SPRITE_MOVE || unitPtr->cur_action==SPRITE_READY_TO_MOVE);
-
- default: err_here();
- break;
- }
- }
- else
- {
- //--------------------------------------------------------------------------------//
- // for the following search_mode, location may be treated as walkable although it is not.
- //--------------------------------------------------------------------------------//
- switch(search_mode)
- {
- case SEARCH_MODE_TO_FIRM: // move to a firm, (location may be not walkable)
- case SEARCH_MODE_TO_TOWN: // move to a town zone, (location may be not walkable)
- if(!locPtr->walkable())
- return (xLoc>=building_x1 && xLoc<=building_x2 && yLoc>=building_y1 && yLoc<=building_y2);
- break;
- case SEARCH_MODE_TO_WALL_FOR_GROUP: // move to wall for a group, (location may be not walkable)
- if(!locPtr->walkable())
- return (xLoc==final_dest_x && yLoc==final_dest_y);
- break;
- case SEARCH_MODE_TO_WALL_FOR_UNIT: // move to wall for a unit only, (location may be not walkable)
- return (locPtr->walkable() && locPtr->cargo_recno==0) || (xLoc==final_dest_x && yLoc==final_dest_y);
- case SEARCH_MODE_ATTACK_UNIT_BY_RANGE: // same as that used in SEARCH_MODE_TO_FIRM
- case SEARCH_MODE_ATTACK_FIRM_BY_RANGE:
- case SEARCH_MODE_ATTACK_TOWN_BY_RANGE:
- case SEARCH_MODE_ATTACK_WALL_BY_RANGE:
- if(!locPtr->walkable())
- return (xLoc>=building_x1 && xLoc<=building_x2 && yLoc>=building_y1 && yLoc<=building_y2);
- break;
-
- default: err_here();
- break;
- }
- recno = (mobile_type!=UNIT_AIR) ? locPtr->cargo_recno : locPtr->air_cargo_recno;
- if(!recno)
- return 1;
- }
- //------- checking for unit's group_id, cur_action, nation_recno and position --------//
- unitPtr = unit_array[recno];
- unitCurAction = unitPtr->cur_action;
- return (unitPtr->unit_group_id==group_id && unitCurAction!=SPRITE_ATTACK) ||
- (unitCurAction==SPRITE_MOVE && unitPtr->cur_x-unitPtr->next_x<=ZOOM_LOC_HALF_WIDTH &&
- unitPtr->cur_y-unitPtr->next_y<=ZOOM_LOC_HALF_HEIGHT) ||
- (unitPtr->nation_recno==seek_nation_recno && unitCurAction==SPRITE_IDLE);
- break;
- case UNIT_SEA:
- if(search_mode<SEARCH_MODE_TO_FIRM) //--------- be careful for the search_mode>=SEARCH_MODE_TO_FIRM
- {
- if(!locPtr->sailable())
- return 0;
- recno = locPtr->cargo_recno;
- if(!recno)
- return 1;
- switch(search_mode)
- {
- case SEARCH_MODE_IN_A_GROUP: // group move
- case SEARCH_MODE_REUSE: // path-reuse
- break;
- case SEARCH_MODE_A_UNIT_IN_GROUP: // a unit in a group
- return unit_array[recno]->cur_action==SPRITE_MOVE;
- case SEARCH_MODE_TO_ATTACK:
- if(recno==target_recno)
- return 1;
- break;
- default: err_here();
- break;
- }
- }
- else
- {
- //--------------------------------------------------------------------------------//
- // for the following search_mode, location may be treated as sailable although it is not.
- //--------------------------------------------------------------------------------//
- switch(search_mode)
- {
- case SEARCH_MODE_TO_FIRM: // move to a firm, (location may be not walkable)
- case SEARCH_MODE_TO_TOWN: // move to a town zone, (location may be not walkable)
- if(!locPtr->sailable())
- return (xLoc>=building_x1 && xLoc<=building_x2 && yLoc>=building_y1 && yLoc<=building_y2);
- break;
-
- //case SEARCH_MODE_TO_WALL_FOR_GROUP: // move to wall for a group, (location may be not walkable)
- //case SEARCH_MODE_TO_WALL_FOR_UNIT: // move to wall for a unit only, (location may be not walkable)
- case SEARCH_MODE_ATTACK_UNIT_BY_RANGE: // same as that used in SEARCH_MODE_TO_FIRM
- case SEARCH_MODE_ATTACK_FIRM_BY_RANGE:
- case SEARCH_MODE_ATTACK_TOWN_BY_RANGE:
- case SEARCH_MODE_ATTACK_WALL_BY_RANGE:
- if(!locPtr->sailable())
- return (xLoc>=building_x1 && xLoc<=building_x2 && yLoc>=building_y1 && yLoc<=building_y2);
- break;
- case SEARCH_MODE_TO_LAND_FOR_SHIP:
- if(locPtr->sailable())
- {
- recno = locPtr->cargo_recno;
- if(!recno)
- return 1;
- unitPtr = unit_array[recno];
- unitCurAction = unitPtr->cur_action;
- return (unitPtr->unit_group_id==group_id && unitCurAction!=SPRITE_ATTACK &&
- unitPtr->action_mode2!=ACTION_SHIP_TO_BEACH) ||
- (unitPtr->unit_group_id!=group_id && unitCurAction==SPRITE_MOVE);
- }
- else if(locPtr->walkable() && locPtr->region_id==region_id)
- return 1;
- else
- return 0;
- default: err_here();
- break;
- }
- recno = locPtr->cargo_recno;
- if(!recno)
- return 1;
- }
-
- //------- checking for unit's group_id, cur_action, nation_recno and position --------//
- unitPtr = unit_array[recno];
- unitCurAction = unitPtr->cur_action;
- return (unitPtr->unit_group_id==group_id && unitCurAction!=SPRITE_ATTACK) ||
- unitCurAction==SPRITE_MOVE ||
- (unitPtr->nation_recno==seek_nation_recno && unitCurAction==SPRITE_IDLE);
- break;
- case UNIT_AIR:
- recno = locPtr->air_cargo_recno;
- if(!recno)
- return 1;
- switch(search_mode)
- {
- case SEARCH_MODE_IN_A_GROUP:
- case SEARCH_MODE_REUSE:
- case SEARCH_MODE_TO_ATTACK:
- case SEARCH_MODE_TO_FIRM:
- case SEARCH_MODE_TO_TOWN:
- case SEARCH_MODE_TO_WALL_FOR_GROUP:
- case SEARCH_MODE_TO_WALL_FOR_UNIT:
- case SEARCH_MODE_ATTACK_UNIT_BY_RANGE:
- case SEARCH_MODE_ATTACK_FIRM_BY_RANGE:
- case SEARCH_MODE_ATTACK_TOWN_BY_RANGE:
- case SEARCH_MODE_ATTACK_WALL_BY_RANGE:
- unitPtr = unit_array[recno];
- unitCurAction = unitPtr->cur_action;
- return (unitPtr->unit_group_id==group_id && unitCurAction!=SPRITE_ATTACK) ||
- unitCurAction==SPRITE_MOVE ||
- (unitPtr->nation_recno==seek_nation_recno && unitCurAction==SPRITE_IDLE);
- case SEARCH_MODE_A_UNIT_IN_GROUP: // a unit in a group
- return unit_array[recno]->cur_action==SPRITE_MOVE;
- default: err_here();
- break;
- }
- break;
- }
- return 0;
- }
- //-------- End of static function can_move_to ------//
- //-------- Begin of function SeekPath::bound_check_x ---------//
- inline void SeekPath::bound_check_x(short ¶X)
- {
- if(paraX<0)
- paraX = 0;
- else if(paraX>=MAX_WORLD_X_LOC-1)
- paraX = MAX_WORLD_X_LOC-1;
- }
- //-------- End of static function bound_check_x ------//
- //-------- Begin of function SeekPath::bound_check_y ---------//
- inline void SeekPath::bound_check_y(short ¶Y)
- {
- if(paraY<0)
- paraY = 0;
- else if(paraY>=MAX_WORLD_Y_LOC-1)
- paraY = MAX_WORLD_Y_LOC-1;
- }
- //-------- End of static function bound_check_y ------//
- //-------- Begin of function SeekPath::result_node_distance ---------//
- inline short SeekPath::result_node_distance(ResultNode *node1, ResultNode *node2)
- {
- short xDist = abs(node1->node_x - node2->node_y);
- #ifdef DEBUG
- short yDist = abs(node1->node_y-node2->node_y);
- #endif
- if(xDist)
- {
- err_when(yDist && xDist!=yDist);
- return xDist;
- }
- else // xDist = 0;
- {
- err_when(yDist==0);
- return abs(node1->node_y-node2->node_y);
- }
- }
- //-------- End of static function result_node_distance ------//
- //-------- Begin of function SeekPath::init ---------//
- void SeekPath::init(int maxNode)
- {
- max_node = maxNode;
- node_array = (Node*) mem_add( max_node * sizeof(Node) );
- node_matrix = (short*) mem_add(sizeof(short)*MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC/4);
- path_status = PATH_WAIT;
- open_node_list.reset_priority_queue();
- closed_node_list.reset_priority_queue();
- reset_total_node_avail();
- }
- //--------- End of function SeekPath::init ---------//
- //-------- Begin of function SeekPath::deinit ---------//
- void SeekPath::deinit()
- {
- if( node_array )
- {
- mem_del(node_array);
- node_array = NULL;
- }
- if( node_matrix )
- {
- mem_del(node_matrix);
- node_matrix = NULL;
- }
- }
- //--------- End of function SeekPath::deinit ---------//
- //-------- Begin of function SeekPath::set_node_matrix ---------//
- void SeekPath::set_node_matrix(short reuseNodeMatrix[])
- {
- reuse_node_matrix_ptr = reuseNodeMatrix;
- }
- //--------- End of function SeekPath::set_node_matrix ---------//
- //-------- Begin of function SeekPath::reset ---------//
- void SeekPath::reset()
- {
- path_status=PATH_WAIT;
- open_node_list.reset_priority_queue();
- closed_node_list.reset_priority_queue();
- }
- //--------- End of function SeekPath::reset ---------//
- //-------- Begin of function SeekPath::reset_total_node_used ---------//
- void SeekPath::reset_total_node_avail()
- {
- total_node_avail = MAX_BACKGROUND_NODE;
- }
- //--------- End of function SeekPath::reset_total_node_used ---------//
- //-------- Begin of function SeekPath::set_attack_range_para ---------//
- void SeekPath::set_attack_range_para(int attackRange)
- {
- attack_range = attackRange;
- }
- //--------- End of function SeekPath::set_attack_range_para ---------//
- //-------- Begin of function SeekPath::reset_attack_range_para ---------//
- void SeekPath::reset_attack_range_para()
- {
- attack_range = 0;
- }
- //--------- End of function SeekPath::reset_attack_range_para ---------//
- //-------- Begin of function SeekPath::set_nation_recno ---------//
- // store the nation_recno of the unit calling searching
- //
- void SeekPath::set_nation_recno(char nationRecno)
- {
- seek_nation_recno = nationRecno;
- }
- //--------- End of function SeekPath::set_nation_recno ---------//
- //-------- Begin of function SeekPath::set_nation_passable ---------//
- void SeekPath::set_nation_passable(char nationPassable[])
- {
- memcpy(nation_passable+1, nationPassable, sizeof(char)*MAX_NATION);
- }
- //--------- End of function SeekPath::set_nation_passable ---------//
- //-------- Begin of function SeekPath::set_sub_mode ---------//
- void SeekPath::set_sub_mode(char subMode)
- {
- search_sub_mode = subMode;
- }
- //--------- End of function SeekPath::set_sub_mode ---------//
- //-------- Begin of function SeekPath::add_result_node ---------//
- inline void SeekPath::add_result_node(int x, int y, ResultNode** curPtr, ResultNode** prePtr, int& count)
- {
- (*curPtr)->node_x = x;
- (*curPtr)->node_y = y;
- err_when(count>1 && (abs((*curPtr)->node_x-(*prePtr)->node_x)>1 || abs((*curPtr)->node_y-(*prePtr)->node_y)>1));
- *prePtr = *curPtr;
- (*curPtr)++;
- count++;
- }
- //--------- End of function SeekPath::add_result_node ---------//
- //-------- Begin of function SeekPath::seek ---------//
- //
- // <int> sx, sy - the starting world location.
- // <int> dx, dy - the destination world location.
- // <DWORD> groupId - unit group id.
- // <char> mobileType - mobile type, can be UNIT_AIR, UNIT_LAND or UNIT_SEA
- //
- // [int] searchMode - 1 SEARCH_MODE_IN_A_GROUP for one group with an unique group id (default)
- // 2 SEARCH_MODE_A_UNIT_IN_GROUP for one sprite in a group
- // 3 SERACH_MODE_TO_ATTACK for the searching that one sprite is ordered to attack its target
- // 4 SEARCH_MODE_REUSE for path-reuse
- // 5 SEARCH_MODE_BLOCKING for 2x2 unit blocking search
- // 6 SEARCH_MODE_TO_FIRM for moving to a firm
- // 7 SEARCH_MODE_TO_TOWN for moving to a town zone
- // 8 SEARCH_MODE_TO_VEHICLE for moving to a vehicle
- // 9 SEARCH_MODE_TO_WALL_FOR_GROUP for moving to a wall location
- // 10 SEARCH_MODE_TO_WALL_FOR_UNIT for moving to a wall location
- // 11 SEARCH_MODE_ATTACK_UNIT_BY_RANGE for range attacking target
- // 12 SEARCH_MODE_ATTACK_FIRM_BY_RANGE ditto
- // 13 SEARCH_MODE_ATTACK_TOWN_BY_RANGE ditto
- // 14 SEARCH_MODE_ATTACK_WALL_BY_RANGE ditto
- // 15 SEARCH_MODE_TO_LAND_FOR_SHIP for ships to move to land
- // (default: 1)
- //
- // [int] miscNo - if searchMode = SEARCH_MODE_TO_ATTACK, meaning target_recno
- // - if searchMode = SEARCH_MODE_TO_FIRM, meaning firm_id
- // - if searchMode = SEARCH_MODE_TO_LAND_FOR_SHIP, meaning the region_id of the land moving to
- // (default: 0)
- //
- // [int] numOfPath - for group assign, group settle. It is used to generate more set of virtual
- // destination in the firm/town for searching.
- //
- // [int] maxTries - maximum no. of tries in the first seek action.
- // this refer to the maximum no. of nodes created.
- // (default : max_node)
- //
- // [int] borderX1, borderY1, - borders of the seek area in the world map
- // borderX2, borderY2 (default: the whole map)
- //
- // Note: if maxTries==max_node, incremental seek (PATH_SEEKING) won't happen.
- //
- // return : <int> seekStatus - PATH_FOUND, PATH_SEEKING, PATH_NODE_USED_UP, or PATH_IMPOSSIBLE
- // if PATH_FOUND, or PATH_NODE_USED_UP, can call get_result() to retrieve the result.
- //
- int SeekPath::seek(int sx,int sy,int dx,int dy, DWORD groupId, char mobileType,
- short searchMode, short miscNo, short numOfPath, int maxTries,
- int borderX1,int borderY1,int borderX2,int borderY2)
- {
- err_when(is_yielding);
- if(total_node_avail<=0)
- return PATH_FOUND; // checking
- border_x1 = short(borderX1/2); // change to 2x2 node format
- border_y1 = short(borderY1/2);
- border_x2 = short(borderX2/2);
- border_y2 = short(borderY2/2);
- //-------- initialize vars --------------//
- current_search_node_used = 0; // count the number of nodes used in each searching
- path_status = PATH_SEEKING;
- world_loc_matrix = world.loc_matrix;
- open_node_list.reset_priority_queue();
- closed_node_list.reset_priority_queue();
- search_mode = searchMode;
- group_id = groupId;
- mobile_type = mobileType;
- err_when(search_mode!=searchMode || group_id!=groupId || mobile_type!=mobileType);
- //------------------------------------------------------------------------------//
- // using another searching for unit sea or unit air
- //------------------------------------------------------------------------------//
- if(mobile_type!=UNIT_LAND)
- return seek2(sx, sy, dx, dy, miscNo, numOfPath, maxTries); // redirect entry of UNIT_SEA or UNIT_AIR
- //------------------------------------------------------------------------------//
- // extract informaton from the parameter "miscNo"
- //------------------------------------------------------------------------------//
- target_recno = building_id = 0;
- building_x1 = building_y1 = building_x2 = building_y2 = -1;
- switch(search_mode)
- {
- case SEARCH_MODE_TO_ATTACK:
- case SEARCH_MODE_TO_VEHICLE:
- target_recno = miscNo;
- break;
- case SEARCH_MODE_TO_FIRM:
- building_id = miscNo;
- building_x1 = dx; // upper left corner location
- building_y1 = dy;
- search_firm_info = firm_res[building_id];
- building_x2 = dx+search_firm_info->loc_width-1;
- building_y2 = dy+search_firm_info->loc_height-1;
- break;
- case SEARCH_MODE_TO_TOWN:
- building_id = miscNo;
- building_x1 = dx; // upper left corner location
- building_y1 = dy;
- if(miscNo != -1)
- {
- Location* buildPtr = world.get_loc(dx, dy);
- Town* targetTown = town_array[buildPtr->town_recno()];
- building_x2 = targetTown->loc_x2;
- building_y2 = targetTown->loc_y2;
- }
- else // searching to settle. Detail explained in function set_move_to_surround()
- {
- building_x2 = building_x1+STD_TOWN_LOC_WIDTH-1;
- building_y2 = building_y1+STD_TOWN_LOC_HEIGHT-1;
- }
- break;
- case SEARCH_MODE_ATTACK_UNIT_BY_RANGE:
- case SEARCH_MODE_ATTACK_WALL_BY_RANGE:
- building_id = miscNo;
- building_x1 = max(dx-attack_range, 0);
- building_y1 = max(dy-attack_range, 0);
- building_x2 = min(dx+attack_range, MAX_WORLD_X_LOC-1);
- building_y2 = min(dy+attack_range, MAX_WORLD_Y_LOC-1);
- break;
- case SEARCH_MODE_ATTACK_FIRM_BY_RANGE:
- building_id = miscNo;
- building_x1 = max(dx-attack_range, 0);
- building_y1 = max(dy-attack_range, 0);
- search_firm_info = firm_res[building_id];
- building_x2 = min(dx+search_firm_info->loc_width-1+attack_range, MAX_WORLD_X_LOC-1);
- building_y2 = min(dy+search_firm_info->loc_height-1+attack_range, MAX_WORLD_Y_LOC-1);
- break;
- case SEARCH_MODE_ATTACK_TOWN_BY_RANGE:
- building_id = miscNo;
- building_x1 = max(dx-attack_range, 0);
- building_y1 = max(dy-attack_range, 0);
- building_x2 = min(dx+STD_TOWN_LOC_WIDTH-1+attack_range, MAX_WORLD_X_LOC-1);
- building_y2 = min(dy+STD_TOWN_LOC_HEIGHT-1+attack_range, MAX_WORLD_Y_LOC-1);
- break;
- }
- //------------------------------------------------------------------------------//
- // set start location and destination location
- //------------------------------------------------------------------------------//
- real_sour_x = sx;
- real_sour_y = sy;
- //---------- adjust destination for some kind of searching ------------//
- int xShift, yShift, area;
- short pathNum;
- switch(search_mode)
- {
- case SEARCH_MODE_TO_FIRM:
- case SEARCH_MODE_TO_TOWN:
- final_dest_x = (building_x1+building_x2)/2; // the destination is set to be the middle of the building
- final_dest_y = (building_y1+building_y2)/2;
- //---------------------------------------------------------------------------------//
- // for group assign/settle, the final destination is adjusted by the value of numOfPath
- //---------------------------------------------------------------------------------//
- if(search_mode==SEARCH_MODE_TO_TOWN)
- area = STD_TOWN_LOC_WIDTH*STD_TOWN_LOC_HEIGHT;
- else // search_mode == SEARCH_MODE_TO_FIRM
- area = search_firm_info->loc_width*search_firm_info->loc_height;
- pathNum = (numOfPath>area) ? (numOfPath-1)%area + 1 : numOfPath;
- if(search_mode==SEARCH_MODE_TO_TOWN)
- m.cal_move_around_a_point(pathNum, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, xShift, yShift);
- else
- m.cal_move_around_a_point(pathNum, search_firm_info->loc_width, search_firm_info->loc_height, xShift, yShift);
- final_dest_x += xShift;
- final_dest_y += yShift;
- bound_check_x(final_dest_x);
- bound_check_y(final_dest_y);
- break;
- case SEARCH_MODE_ATTACK_UNIT_BY_RANGE:
- case SEARCH_MODE_ATTACK_FIRM_BY_RANGE:
- case SEARCH_MODE_ATTACK_TOWN_BY_RANGE:
- case SEARCH_MODE_ATTACK_WALL_BY_RANGE:
- final_dest_x = (building_x1+building_x2)/2; // the destination is set to be the middle of the building
- final_dest_y = (building_y1+building_y2)/2;
- break;
-
- default:
- final_dest_x = real_dest_x = dx;
- final_dest_y = real_dest_y = dy;
- break;
- }
- //--------------------------------------------------------------//
- // change to 2x2 node format
- //--------------------------------------------------------------//
- int sourceX = short(sx/2); // the upper left corner is used
- int sourceY = short(sy/2);
- dest_x = short(final_dest_x/2);
- dest_y = short(final_dest_y/2);
- //-----------------------------------------//
- // reset node_matrix
- //-----------------------------------------//
- if(search_mode!=SEARCH_MODE_REUSE)
- {
- max_node_num = 0xFFFF;
- memset(node_matrix, 0, sizeof(short)*MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC/4);
- }
- else
- {
- max_node_num = max_node;
- memcpy(node_matrix, reuse_node_matrix_ptr, sizeof(short)*MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC/4);
- }
- //--------- create the first node ---------//
- node_count = 0;
- result_node_ptr = NULL;
- Node *nodePtr = node_array + node_count++;
- memset(nodePtr, 0, sizeof(Node));
- //-------- store the upper left coordinate of the node ----------//
- upper_left_x = sourceX<<1;
- upper_left_y = sourceY<<1;
- //---------- calculate the node type -----------//
- nodePtr->node_type = 0;
- nodePtr->node_type = (can_move_to(upper_left_x,upper_left_y))+(can_move_to(upper_left_x+1,upper_left_y)<<1)+
- (can_move_to(upper_left_x,upper_left_y+1)<<2)+(can_move_to(upper_left_x+1,upper_left_y+1)<<3);
- if(searchMode==SEARCH_MODE_A_UNIT_IN_GROUP || searchMode==SEARCH_MODE_TO_WALL_FOR_UNIT) // plus the self-location
- nodePtr->node_type += (real_sour_x>upper_left_x)?2+(real_sour_y-upper_left_y)*6:1+(real_sour_y-upper_left_y)*3;
- else
- {
- /*if(searchMode==SEARCH_MODE_TO_FIRM || searchMode==SEARCH_MODE_TO_TOWN) // plus the self-location
- {
- if(real_sour_x<building_x1 || real_sour_x>building_x2 ||
- real_sour_y<building_y1 || real_sour_y>building_y2)
- nodePtr->node_type += (real_sour_x>upper_left_x)?2+(real_sour_y-upper_left_y)*6:1+(real_sour_y-upper_left_y)*3;
- }*/
- }
- err_when(nodePtr->node_type>15 || nodePtr->node_type <0);
- int destUpperLeftX = dest_x<<1;
- int destUpperLeftY = dest_y<<1;
- is_dest_blocked = !((can_move_to(destUpperLeftX,destUpperLeftY))+(can_move_to(destUpperLeftX+1,destUpperLeftY)<<1)+
- (can_move_to(destUpperLeftX,destUpperLeftY+1)<<2)+(can_move_to(destUpperLeftX+1,destUpperLeftY+1)<<3));
- // whether the destination is blocked, if so, only search till the destination's neighbor locations
- nodePtr->node_g = 0;
- nodePtr->node_h = (sourceX-dest_x)*(sourceX-dest_x)+(sourceY-dest_y)*(sourceY-dest_y); // should really use sqrt().
- nodePtr->node_f = nodePtr->node_g + nodePtr->node_h;
- nodePtr->node_x = sourceX;
- nodePtr->node_y = sourceY;
- nodePtr->enter_direction = 0;
- open_node_list.insert_node(nodePtr); // make Open List point to first node
- //--- if the destination is the current postion or next to it & the dest is occupied ---//
- if( sourceX==dest_x && sourceY==dest_y )
- {
- path_status = PATH_FOUND;
- result_node_ptr = nodePtr;
- return path_status;
- }
- //------------ seek now ------------------//
- int maxNode = (!maxTries) ? max_node : maxTries;
- return continue_seek(maxNode, 1); // 1-first seek session of the current seek order
- }
- //-------- End of function SeekPath::seek ---------//
- //---- Begin of function SeekPath::continue_seek ---------//
- //
- // If the last seek operation does not find the whole path,
- // continue the search.
- //
- // <int> maxTries - maximum path seeking tries
- // [char] firstSeek - whether it's the first seek session of the seek order.
- // (default: 0)
- //
- // return : <int> seekStatus - PATH_FOUND, PATH_SEEKING, PATH_NODE_USED_UP,
- // or PATH_IMPOSSIBLE
- //
- // You can call get_result() to retrieve the result.
- //
- int SeekPath::continue_seek(int maxTries, char firstSeek)
- {
- if( path_status != PATH_SEEKING )
- return path_status;
- //------- aliasing class member vars for fast access ------//
- cur_seek_path = this;
- cur_dest_x = dest_x;
- cur_dest_y = dest_y;
- cur_node_matrix = node_matrix;
- cur_node_array = node_array;
- cur_border_x1 = border_x1;
- cur_border_y1 = border_y1;
- cur_border_x2 = border_x2;
- cur_border_y2 = border_y2;
- //------ seek the path using the A star algorithm -----//
- int maxNode = (total_node_avail<maxTries) ? total_node_avail : maxTries;
- maxNode -= MAX_CHILD_NODE; // generate_successors() can generate a max of MAX_CHILD_NODE new nodes per call
- Node *bestNodePtr;
- int i;
- for(i=0; i<maxNode; i++)
- {
- bestNodePtr = return_best_node();
- //if(i%20==0)
- // sys_yield(); // update cursor position
- //---- even if the path is impossible, get the closest path ----//
- if( !bestNodePtr )
- {
- path_status = PATH_IMPOSSIBLE;
- break;
- }
- //----- exceed the object's max's node limitation, return the closest path ----//
- if( node_count >= maxNode )
- {
- path_status = PATH_NODE_USED_UP;
- break;
- }
- //---------------------------------------------------------------//
- // If the path is found OR If the destination is blocked,
- // consider it done when we are next to it.
- //---------------------------------------------------------------//
- if( (bestNodePtr->node_x==dest_x && bestNodePtr->node_y==dest_y) ||
- ( is_dest_blocked && abs(bestNodePtr->node_x-dest_x)<=0 && abs(bestNodePtr->node_y-dest_y)<=0 ) )
- {
- path_status = PATH_FOUND;
- result_node_ptr = bestNodePtr;
- break;
- }
- //--------- generate successors -------//
- if(bestNodePtr->generate_successors(bestNodePtr->enter_direction, real_sour_x, real_sour_y))
- {
- path_status = PATH_REUSE_FOUND;
- result_node_ptr = reuse_result_node_ptr;
- break;
- }
- }
- err_when( cur_stack_pos!=0 ); // it should be zero all the times, all pushes should have been poped
- current_search_node_used = i+1; // store the number of nodes used in this searching
- return path_status;
- }
- //------ End of function SeekPath::continue_seek ---------//
- //---- Begin of function SeekPath::get_result ---------//
- //
- // Compile the seek result nodes using results processed by
- // seek() and continue_seek() and store the results in
- // an array of ResultNode.
- //
- // <int&> resultNodeCount - a reference var for returning the no. of result nodes.
- // <short&> pathDist - a reference var for returning the total distance of the result path
- //
- // return : <ResultNode*> an array of ResultNode.
- // the caller function is responsible for
- // freeing the memory of the array.
- //
- ResultNode* SeekPath::get_result(int& resultNodeCount, short& pathDist)
- {
- if(mobile_type!=UNIT_LAND)
- return get_result2(resultNodeCount, pathDist); // redirect entry point for UNIT_SEA or UNIT_AIR
- resultNodeCount = pathDist = 0;
- if(total_node_avail<=0)
- return NULL;
-
- total_node_avail -= current_search_node_used;
- short useClosestNode = 0; // indicate whether closest node is returned instead of the actual node
- if(!result_node_ptr) // if PATH_IMPOSSIBLE or PATH_NODE_USED_UP, result_node_ptr is NULL, we need to call get_closest_node() to get the closest node.
- {
- result_node_ptr = return_closest_node();
- useClosestNode = 1;
- if(!result_node_ptr)
- return NULL;
- }
- //--------------------------------------------------//
- // Trace backwards to the starting node, and rationalize
- // nodes (i.e. group nodes of the same direction into
- // single nodes.)
- //--------------------------------------------------//
- Node* nodePtr = result_node_ptr; // the node current being processed
- Node* baseNodePtr = result_node_ptr; // the first end node for connecting the other end node for the path in that direction.
- Node* parentNode = nodePtr->parent_node; // the parent node of nodePtr
- Node* childNodePtr = nodePtr; // it should point to the children node of nodePtr
- //------------------------------------------------------------------------
- // there are only one node, source & destination within the same 2x2 node
- //------------------------------------------------------------------------
- if(!parentNode) // parentNode==0 when the source location is the desination already
- {
- if((real_sour_x!=final_dest_x || real_sour_y!=final_dest_y) && abs(real_sour_x-final_dest_x)<=1 &&
- abs(real_sour_y-final_dest_y)<=1 && can_move_to(final_dest_x, final_dest_y))
- {
- pathDist = 1;
- ResultNode* resultNodeArray1 = (ResultNode*) mem_add(sizeof(ResultNode)*2);
- ResultNode* resultNodePtr1 = resultNodeArray1;
- resultNodeCount=2;
- resultNodePtr1->node_x = real_sour_x;
- resultNodePtr1->node_y = real_sour_y;
- resultNodePtr1++;
- resultNodePtr1->node_x = final_dest_x;
- resultNodePtr1->node_y = final_dest_y;
- return resultNodeArray1;
- }
- else
- return NULL;
- }
- resultNodeCount=1; // including the current node
- //===================================
- // count the number of 2x2 node
- //===================================
- int numOfNode=0;
- Node* curPtr = result_node_ptr;
- while(curPtr != NULL)
- {
- curPtr = curPtr->parent_node;
- numOfNode++;
- }
- //sys_yield(); // update cursor position
- //---------------------------------
- // otherwise, there are more than one node
- //---------------------------------
- node_count=0;
- ResultNode* maxSizeResultNodeArray; // store all the result node in the reverse order, the turning point will be extracted later
- int nodeAllocated = (numOfNode+1)<<1;//numOfNode*2+2; // the additional 2 is for the starting node
-
- maxSizeResultNodeArray = (ResultNode*) mem_add(nodeAllocated*sizeof(ResultNode));
- max_size_result_node_ptr = maxSizeResultNodeArray;
- parent_result_node_ptr = maxSizeResultNodeArray;
- //----------------------------------
- // start from the destination point
- //----------------------------------
- memset(max_size_result_node_ptr, 0, sizeof(ResultNode)*nodeAllocated);
- int upper_left_x = nodePtr->node_x<<1;
- int upper_left_y = nodePtr->node_y<<1;
- short xCount, yCount; // for counting
- if(!useClosestNode && (search_mode==SEARCH_MODE_TO_ATTACK || search_mode==SEARCH_MODE_TO_VEHICLE ||
- can_move_to(final_dest_x, final_dest_y)))
- {
- max_size_result_node_ptr->node_x = final_dest_x;
- max_size_result_node_ptr->node_y = final_dest_y;
- }
- else
- { // use closest node
- max_size_result_node_ptr->node_x = MAX_WORLD_X_LOC;
- max_size_result_node_ptr->node_y = MAX_WORLD_Y_LOC;
-
- int newValue, xSquare, yDiff;
- int compareValue = 0x7FFFFFFF; // should > 199^2 + 199^2
-
- for(xCount=upper_left_x+1; xCount>=upper_left_x; xCount--)
- {
- xSquare = int(final_dest_x-xCount)*(final_dest_x-xCount);
- for(yCount=upper_left_y+1, yDiff=final_dest_y-yCount; yCount>=upper_left_y; yCount--, yDiff++)
- {
- if(can_move_to(xCount, yCount) && (newValue = xSquare + yDiff*yDiff)<compareValue)
- {
- max_size_result_node_ptr->node_x = xCount;
- max_size_result_node_ptr->node_y = yCount;
- compareValue = newValue;
- }
- }
- }
- err_when(max_size_result_node_ptr->node_x==MAX_WORLD_X_LOC &&
- max_size_result_node_ptr->node_y==MAX_WORLD_Y_LOC);
-
- final_dest_x = max_size_result_node_ptr->node_x;
- final_dest_y = max_size_result_node_ptr->node_y;
- }
- xCount = max_size_result_node_ptr->node_x;
- yCount = max_size_result_node_ptr->node_y;
- max_size_result_node_ptr++; // note: parent_result_node_ptr don't move for this case
- node_count++;
- //---------------------------------------------------
- // process the end node if passing through two points
- //---------------------------------------------------
- int xLoc, yLoc;
- switch(nodePtr->enter_direction)
- {
- case 1:
- if(upper_left_x < xCount)
- {
- yLoc = can_move_to(upper_left_x, yCount) ? yCount : ((yCount>upper_left_y)?upper_left_y:upper_left_y+1);
- add_result_node(upper_left_x, yLoc, &max_size_result_node_ptr, &parent_result_node_ptr, node_count);
- }
- break;
- case 2: if((upper_left_x!=xCount) || ((upper_left_y+1)!=yCount))
- add_result_node(upper_left_x, upper_left_y+1, &max_size_result_node_ptr, &parent_result_node_ptr, node_count);
- break;
- case 3:
- if(upper_left_y == yCount)
- {
- xLoc = can_move_to(xCount,upper_left_y+1) ? xCount : ((xCount>upper_left_x)?upper_left_x:(upper_left_x+1));
- add_result_node(xLoc, upper_left_y+1, &max_size_result_node_ptr, &parent_result_node_ptr, node_count);
- }
- break;
- case 4: if(((upper_left_x+1)!=xCount) || ((upper_left_y+1)!=yCount))
- add_result_node(upper_left_x+1, upper_left_y+1, &max_size_result_node_ptr, &parent_result_node_ptr, node_count);
- break;
- case 5:
- if(upper_left_x == final_dest_x)
- {
- yLoc = can_move_to(upper_left_x+1,yCount) ? yCount : ((yCount>upper_left_y)?upper_left_y:(upper_left_y+1));
- add_result_node(upper_left_x+1, yLoc, &max_size_result_node_ptr, &parent_result_node_ptr, node_count);
- }
- break;
-
- case 6: if(((upper_left_x+1)!=xCount) || (upper_left_y!=yCount))
- add_result_node(upper_left_x+1, upper_left_y, &max_size_result_node_ptr, &parent_result_node_ptr, node_count);
- break;
- case 7:
- if(upper_left_y != yCount)
- {
- xLoc = can_move_to(xCount,upper_left_y) ? xCount : ((xCount>upper_left_x)?upper_left_x:(upper_left_x+1));
- add_result_node(xLoc, upper_left_y, &max_size_result_node_ptr, &parent_result_node_ptr, node_count);
- }
- break;
- case 8: if((upper_left_x!=xCount) || (upper_left_y!=yCount))
- add_result_node(upper_left_x, upper_left_y, &max_size_result_node_ptr, &parent_result_node_ptr, node_count);
- break;
- default:
- err_now("error in processing the end node");
- break;
- }
- nodePtr = nodePtr->parent_node; // next 2x2 node
-
- //preNodeCount = node_count;
- err_when(node_count+nodePtr->node_g+2 > nodeAllocated);
-
- //--------------------------------------------------
- // get the actual path, process from the second node
- //--------------------------------------------------
- //int yieldCount = 0;
- while( (parentNode=nodePtr->parent_node) != NULL )
- {
- upper_left_x = nodePtr->node_x<<1;
- upper_left_y = nodePtr->node_y<<1;
- get_real_result_node(node_count, nodePtr->enter_direction,(childNodePtr->enter_direction+3)%8+1,
- nodePtr->node_type, upper_left_x, upper_left_y);
- childNodePtr = nodePtr;
- nodePtr = parentNode;
- err_when(node_count+nodePtr->node_g+2 > nodeAllocated);
- //yieldCount++;
- //if(yieldCount%30==0)
- // sys_yield();
- }
- //sys_yield(); // update cursor position
-
- //----------------------------------------------------
- // process the starting node
- // nodePtr points at the starting node now
- //----------------------------------------------------
- if(abs(parent_result_node_ptr->node_x-real_sour_x)>1 || abs(parent_result_node_ptr->node_y-real_sour_y)>1)
- { // passing through two points
- upper_left_x = nodePtr->node_x<<1;
- upper_left_y = nodePtr->node_y<<1;
- switch(childNodePtr->enter_direction)
- {
- case 1:
- max_size_result_node_ptr->node_x = upper_left_x+1;
- if((can_move_to(upper_left_x+1, real_sour_y)&&(real_sour_y==upper_left_y)) ||
- (!can_move_to(upper_left_x+1, real_sour_y)&&(real_sour_y>upper_left_y)))
- max_size_result_node_ptr->node_y = upper_left_y;
- else
- max_size_result_node_ptr->node_y = (upper_left_y+1);
- break;
- case 2:
- max_size_result_node_ptr->node_x = upper_left_x+1;
- max_size_result_node_ptr->node_y = upper_left_y;
- break;
- case 3:
- max_size_result_node_ptr->node_y = upper_left_y;
- if((can_move_to(real_sour_x, upper_left_y)&&(real_sour_x==upper_left_x)) ||
- (!can_move_to(real_sour_x, upper_left_y)&&(real_sour_x>upper_left_x)))
- max_size_result_node_ptr->node_x = upper_left_x;
- else
- max_size_result_node_ptr->node_x = upper_left_x+1;
- break;
- case 4:
- max_size_result_node_ptr->node_x = upper_left_x;
- max_size_result_node_ptr->node_y = upper_left_y;
- break;
- case 5:
- max_size_result_node_ptr->node_x = upper_left_x;
- if((can_move_to(upper_left_x, real_sour_y)&&(real_sour_y==upper_left_y)) ||
- (!can_move_to(upper_left_x, real_sour_y)&&(real_sour_y>upper_left_y)))
- max_size_result_node_ptr->node_y = upper_left_y;
- else
- max_size_result_node_ptr->node_y = upper_left_y+1;
- break;
- case 6:
- max_size_result_node_ptr->node_x = upper_left_x;
- max_size_result_node_ptr->node_y = upper_left_y+1;
- break;
- case 7:
- max_size_result_node_ptr->node_y = upper_left_y+1;
- if((can_move_to(real_sour_x, upper_left_y+1)&&(real_sour_x==upper_left_x)) ||
- (!can_move_to(real_sour_x, upper_left_y+1)&&(real_sour_x>upper_left_x)))
- max_size_result_node_ptr->node_x = upper_left_x;
- else
- max_size_result_node_ptr->node_x = upper_left_x+1;
- break;
- case 8:
- max_size_result_node_ptr->node_x = upper_left_x+1;
- max_size_result_node_ptr->node_y = upper_left_y+1;
- break;
- default:
- err_now("error in processing the start node");
- break;
-
- }
- err_when((max_size_result_node_ptr->node_x==real_sour_x) && (max_size_result_node_ptr->node_y==real_sour_y));
- parent_result_node_ptr++;
- max_size_result_node_ptr++;
- node_count++;
- }
- max_size_result_node_ptr->node_x = real_sour_x;
- max_size_result_node_ptr->node_y = real_sour_y;
- node_count++;
- err_when(nodePtr->node_g || node_count>nodeAllocated);
- debug_check_path(maxSizeResultNodeArray, node_count); //*** debug only
- ResultNode* result_node_pointer;
- maxSizeResultNodeArray = smooth_the_path(maxSizeResultNodeArray, resultNodeCount);
- //sys_yield(); // update cursor position
- debug_check_path(maxSizeResultNodeArray, resultNodeCount); //*** debug only
- //-------------------------------------------------------------------//
- // After the above process, here we will have a link of rationalize
- // nodes. Retrieve them in the backwards order
- //-------------------------------------------------------------------//
- ResultNode *resultNodeArray = (ResultNode*) mem_add( sizeof(ResultNode) * resultNodeCount );
- ResultNode *resultNodePtr = resultNodeArray+resultNodeCount-1;
- int processCount = 1;
-
- ResultNode *preNodePtr = maxSizeResultNodeArray;
- *resultNodePtr = *preNodePtr;
- resultNodePtr--;
- result_node_pointer = maxSizeResultNodeArray+1;
- err_when(pathDist!=0);
- int xDist, yDist;
- //yieldCount = 0;
- while(processCount++ < resultNodeCount)
- {
- err_when(result_node_pointer->node_x<0 || result_node_pointer->node_x>=MAX_WORLD_X_LOC ||
- result_node_pointer->node_y<0 || result_node_pointer->node_y>=MAX_WORLD_Y_LOC);
- *resultNodePtr = *result_node_pointer;
- resultNodePtr--;
-
- xDist = abs(result_node_pointer->node_x-preNodePtr->node_x);
- yDist = abs(result_node_pointer->node_y-preNodePtr->node_y);
- err_when((!xDist && !yDist) || (xDist && yDist && xDist!=yDist));
- pathDist += (xDist) ? xDist : yDist;
- preNodePtr++;
- result_node_pointer++;
-
- //yieldCount++;
- //if(yieldCount%35==0)
- // sys_yield();
- }
- err_when(nodeAllocated<node_count);
- mem_del(maxSizeResultNodeArray);
- //======================================================================//
- #ifdef DEBUG
- if(search_sub_mode==SEARCH_SUB_MODE_PASSABLE && resultNodeCount>1)
- {
- err_when(mobile_type!=UNIT_LAND);
- debug_check_sub_mode(resultNodeArray, resultNodeCount);
- }
- #endif
- //======================================================================//
- return resultNodeArray;
- }
- //------ End of function SeekPath::get_result ---------//
- //---- Begin of function SeekPath::get_real_result_node ---------//
- //
- // called by get_result to extract the point in a 2x2 node that is
- // used in the shortest path
- //
- // <int&> count - a reference var for counting number of node in
- // max_size_result_node_ptr
- //
- void SeekPath::get_real_result_node( int &count, short enterDirection, short exitDirection,
- short nodeType, short xCoord, short yCoord)
- {
- short ma, mb, mc, md; // | a b | four elements of a 2x2 matrix
- // | c d | these values are either 0 or 1
- short mTmp; // used in swapping
- short atEdge; // at_edge = 1 if exitDirection is at the edge, otherwise 0 for corner
- short rotateAngle; // rotate angle clockwisely = its value*90 degree, value ranges from 0 to 3
- short furtherCheck; // indicate further checking is needed in finding a path in the node
- short rotatedEnterDirection; // reference enter direction after rotation
-
- ma = nodeType&0x1;
- mb = (nodeType&0x2)>>1;
- mc = (nodeType&0x4)>>2;
- md = (nodeType&0x8)>>3;
-
- err_when((ma+(mb<<1)+(mc<<2)+(md<<3)) != nodeType);
- atEdge = exitDirection%2;
- rotateAngle = short((exitDirection-1)/2);
- furtherCheck = 0; // may be used only if enterDirection and exitDirection are opposite to each other
-
- int exitArrowLeft = 0;
- int exitArrowRight = 0;
- int enterArrowLeft = 0;
- int enterArrowRight = 0;
- if(atEdge) // exit at the edge
- {
- //---------------------------------------------------------------------//
- // -------
- // exitArrowRight |1 |2 |
- // <--------|-------|
- // exitArrowLeft |3 |4 |
- // -------
- // There are 2 possible choice for the previous node to select. One is
- // the point left of 1, and the other is the point left of 3. Since there
- // are four possible edge exiting cases, it call be represented by rotated
- // the above figure by 90 degree each.
- //
- // if the point left of 1 is chosen, exitArrowRight = 1
- // if the point left of 3 is chosen, exitArrowLeft = 1
- // the flag exitArrowLeft and exitArrowRight is used to generate a better
- // result path shape.
- //---------------------------------------------------------------------//
- switch(exitDirection)
- {
- case 1: if(parent_result_node_ptr->node_y%2)
- exitArrowLeft = 1;
- else
- exitArrowRight = 1;
- break;
- case 3: if(parent_result_node_ptr->node_x%2)
- exitArrowLeft = 1;
- else
- exitArrowRight = 1;
- break;
- case 5: if(parent_result_node_ptr->node_y%2)
- exitArrowRight = 1;
- else
- exitArrowLeft = 1;
- break;
- case 7: if(parent_result_node_ptr->node_x%2)
- exitArrowRight = 1;
- else
- exitArrowLeft = 1;
- break;
- default: err_here();
- break;
- }
- }
- else // exit at edge
- {
- if(enterDirection%2) // enter at the edge
- {
- //---------------------------------------------------------------------//
- // -------
- // enterArrowLeft |1 |2 |
- // -------->|-------|
- // enterArrowRight|3 |4 |
- // -------
- // There are 2 possible choice for the next node to select. One is
- // the point left of 1, and the other is the point left of 3. Since there
- // are four possible edge entering cases, it call be represented by rotated
- // the above figure by 90 degree each time.
- //
- // if the point left of 1 is chosen, enterArrowLeft = 1
- // if the point left of 3 is chosen, enterArrowRight = 1
- // the flag enterArrowLeft and enterArrowRight is used to generate a better
- // result path shape.
- //---------------------------------------------------------------------//
-
- switch(enterDirection)
- {
- case 1: if(can_move_to(xCoord-1, yCoord))
- enterArrowLeft = 1;
- if(can_move_to(xCoord-1, yCoord+1))
- enterArrowRight = 1;
- break;
- case 3: if(can_move_to(xCoord, yCoord+2))
- enterArrowLeft = 1;
- if(can_move_to(xCoord+1, yCoord+2))
- enterArrowRight = 1;
- break;
- case 5: if(can_move_to(xCoord+2, yCoord+1))
- enterArrowLeft = 1;
- if(can_move_to(xCoord+2, yCoord))
- enterArrowRight = 1;
- break;
- case 7: if(can_move_to(xCoord+1, yCoord-1))
- enterArrowLeft = 1;
- if(can_move_to(xCoord, yCoord-1))
- enterArrowRight = 1;
- break;
- default: err_here();
- break;
- }
- }
- }
- //----------------------------------------------------------------
- // perform rotation such that the exit direction is either 1 or 2
- //----------------------------------------------------------------
- switch(exitDirection)
- { case 1: case 2:
- break;
- case 3: case 4: // rotate clockwise 90 degree
- //(((mTmp = mb), mb = ma), ma = mc), mc = md;
- mTmp = mb;
- mb = ma;
- ma = mc;
- mc = md;
- md = mTmp;
- break;
- case 5: case 6: // rotate clockwise 180 degree
- mTmp = md;
- md = ma;
- ma = mTmp;
- mTmp = mb;
- mb = mc;
- mc = mTmp;
- break;
- case 7: case 8: // rotate clockwise 270 degree
- mTmp = ma;
- ma = mb;
- mb = md;
- md = mc;
- mc = mTmp;
- break;
- default:
- err_now("exitDirection error");
- break;
- }
-
- rotatedEnterDirection = (enterDirection-(rotateAngle<<1)+7)%8+1; // store angle rotated for reverse rotation later
- err_when(rotatedEnterDirection>8 || rotatedEnterDirection <1);
- //-----------------------------------------
- // set the value of the matrix element to
- // 1 for the possible answer, the rest is 0
- //-----------------------------------------
- if(atEdge) // the case for the exit direction at 1
- { //------------------- at edge ------------------------//
- switch(rotatedEnterDirection)
- {
- case 1:
- err_now("unexpected case at edge");
- break;
- case 2:
- err_when(!mc);
- mc = 1; // must be
- ma = mb = md = 0;
- break;
- case 3:
- // there are two possible paths
- if(mc) // check for the perfered path
- ma = mb = md = 0;
- else
- {
- err_when((!ma) || (!md));
- mb = 0;
- }
- // ma, md should be 1
- break;
- case 4:
- err_when(!md); // md should be 1
- mb = 0;
- err_when((!mc) && (!ma));
- if(exitArrowLeft)
- ma = 1-mc; // either one is used, prefer mc
- else // should be exitArrowRight
- mc = 1-ma; // either one is used, prefer ma
- break;
- case 5:
- if(ma&&mb)
- { // one path (bar state) exists
- if(mc&&md)
- furtherCheck = 1;// both paths exist
- else
- mc = md = 0; // choose ma, mb
- }
- else if(mc&&md)
- ma = mb = 0; // choose mc, md
- else
- err_when(((!ma)&&(!mc)) && ((!mb)&&(!md)));
- // else, only one path exists, do nothing
- break;
- case 6: // similar to case 4
- err_when(!mb); // mb should be 1
- md = 0;
- err_when((!ma)&&(!mc));
- if(exitArrowLeft)
- ma = 1-mc; // either one is used, prefer mc
- else // should be exitArrowRight
- mc = 1-ma; // either one is used, prefer ma
- break;
- case 7: // similar to case 3
- if(ma)
- mb = mc = md = 0;
- else
- {
- err_when((!mb)||(!mc));
- md = 0; // mb, mc should be 1
- }
- break;
- case 8:
- err_when(!ma);
- ma = 1; // must be
- mb = mc = md = 0;
- break;
- default:
- err_now("at edge error");
- break;
- }
- }
- else
- { //---------------------------- at corner-------------------------//
- // the case for the exit direction at 2
- switch(rotatedEnterDirection)
- {
- case 1: case 3:
- err_when(!mc);
- mc = 1; // must be
- ma = mb = md = 0;
- break;
- case 2:
- err_now("unexpected case at corner");
- break;
- case 4:
- err_when((!mc)||(!md));
- mc = md = 1; // must be
- ma = mb = 0;
- break;
- case 5:
- err_when(!mc);
- mc = 1; // must be
- ma = 0;
- err_when((!mb)&&(!md));
- if(!enterArrowLeft) // the enter arrow left location canot be walked
- md = 1-mb; // either one is used, prefer mb
- else
- mb = 1-md; // either one is used, prefer md
- break;
- case 6:
- err_when((!mb)||(!mc));
- mb = mc = 1;
- ma = md = 0;
- break;
- case 7:
- err_when(!mc);
- mc = 1; // must be
- md = 0;
- err_when((!ma)&&(!mb));
- if(!enterArrowRight)
- ma = 1-mb; // either one is used, prefer mb
- else
- mb = 1-ma; // either one is used, prefer ma
- break;
- case 8:
- err_when((!ma)||(!mc));
- ma = mc = 1; // must be
- mb = md = 0;
- break;
- default:
- err_now("at corner error");
- break;
- }
- }
- //--------------------------- reverse rotation ----------------------------//
- switch(exitDirection)
- { case 1: case 2:
- break;
- case 3: case 4: // rotate clockwise 270 degree
- mTmp = ma;
- ma = mb;
- mb = md;
- md = mc;
- mc = mTmp;
- break;
- case 5: case 6: // rotate clockwise 180 degree
- mTmp = md;
- md = ma;
- ma = mTmp;
- mTmp = mb;
- mb = mc;
- mc = mTmp;
- break;
- case 7: case 8: // rotate clockwise 90 degree
- mTmp = mb;
- mb = ma;
- ma = mc;
- mc = md;
- md = mTmp;
- break;
- default:
- err_now("exitDirection error");
- break;
- }
- //------------------- get the answer ----------------------//
- switch(exitDirection)
- {
- case 1:
- if(!furtherCheck)
- {
- add_result_node(xCoord, yCoord+1-ma, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- err_when(mb && md);
- if(mb||md) // at most one is 1
- add_result_node(xCoord+1, yCoord+1-mb, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- }
- else
- {
- if(parent_result_node_ptr->node_y == yCoord)
- { // use upper path
- add_result_node(xCoord, yCoord, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- add_result_node(xCoord+1, yCoord, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- }
- else
- { // use lower path
- add_result_node(xCoord, yCoord+1, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- add_result_node(xCoord+1, yCoord+1, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- }
- }
- break;
-
- case 2:
- err_when(!mc);
- if(mc)
- add_result_node(xCoord, yCoord+1, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- // else, error
- err_when(ma+mb+md>1); //(ma&&mb) || (ma&&md) || (mb&&md))
- if(ma||mb||md) // at most one is 1
- add_result_node(xCoord+1-ma, yCoord+md, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- break;
-
- case 3:
- if(!furtherCheck)
- {
- add_result_node(xCoord+1-mc, yCoord+1, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- err_when(ma&&mb);
- if(ma||mb) // at most one is 1
- add_result_node(xCoord+1-ma, yCoord, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- }
- else
- {
- if(parent_result_node_ptr->node_x == xCoord)
- { // use left path
- add_result_node(xCoord, yCoord+1, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- add_result_node(xCoord, yCoord, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- }
- else
- { // use right path
- add_result_node(xCoord+1, yCoord+1, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- add_result_node(xCoord+1, yCoord, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- }
- }
- break;
- case 4:
- err_when(!md);
- if(md)
- add_result_node(xCoord+1, yCoord+1, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- // else, error
- err_when(ma+mb+mc>1); //(ma&&mb) || (ma&&mc) || (mb&&mc))
- if(ma||mb||mc) // at most one is 1
- add_result_node(xCoord+mb, yCoord+mc, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- break;
- case 5:
- if(!furtherCheck)
- {
- add_result_node(xCoord+1, yCoord+1-mb, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- err_when(ma&&mc);
- if(ma||mc) // at most one is 1
- add_result_node(xCoord, yCoord+1-ma, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- }
- else
- {
- if(parent_result_node_ptr->node_y == yCoord)
- { // use upper path
- add_result_node(xCoord+1, yCoord, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- add_result_node(xCoord, yCoord, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- }
- else
- { // use lower path
- add_result_node(xCoord+1, yCoord+1, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- add_result_node(xCoord, yCoord+1, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- }
- }
- break;
-
- case 6:
- err_when(!mb);
- if(mb)
- add_result_node(xCoord+1, yCoord, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- // else, error
- err_when(ma+mc+md>1);//(ma&&mc) || (ma&&md) || (mc&&md))
- if(ma||mc||md) // at most one is 1
- add_result_node(xCoord+md, yCoord+1-ma, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- break;
- case 7:
- if(!furtherCheck)
- {
- add_result_node(xCoord+1-ma, yCoord, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- err_when(mc&&md);
- if(mc||md) // at most one is 1
- add_result_node(xCoord+1-mc, yCoord+1, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- }
- else
- {
- if(parent_result_node_ptr->node_x == xCoord)
- { // use left path
- add_result_node(xCoord, yCoord, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- add_result_node(xCoord, yCoord+1, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- }
- else
- { // use right path
- add_result_node(xCoord+1, yCoord, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- add_result_node(xCoord+1, yCoord+1, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- }
- }
- break;
-
- case 8:
- err_when(!ma);
- if(ma)
- add_result_node(xCoord, yCoord, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- // else, error
- err_when(mb+mc+md>1);//(mb&&mc) || (mb&&md) || (mc&&md))
- if(mb||mc||md) // at most one is 1
- add_result_node(xCoord+1-mc, yCoord+1-mb, &max_size_result_node_ptr, &parent_result_node_ptr, count);
- break;
- default:
- err_now("error in extracting answer");
- break;
- }
- }
- //------ End of function SeekPath::get_real_result_node ---------//
- //-------- Begin of function SeekPath::smooth_the_path ---------//
- ResultNode* SeekPath::smooth_the_path(ResultNode* nodeArray, int& nodeCount)
- {
- //------------------------------------------------------------//
- // smoothing the path and get the turning point
- //------------------------------------------------------------//
- //---------- declare variables ---------------//
- int i, j, checkedNodeCount, curNodeCount;
- short vectorX, vectorY, newVectorX, newVectorY, newVectorX2, newVectorY2;
- short changed, caseNum, processed;
- ResultNode *curUsefulNodePtr = nodeArray+1;
- ResultNode *preCheckingNodePtr = nodeArray;
- ResultNode *ptr1;
- ResultNode *ptr2;
- ResultNode *ptr3;
- ResultNode *ptr4;
- parent_result_node_ptr = nodeArray;
- max_size_result_node_ptr = nodeArray+1;
- //--------------------------------------------------//
- // to remove the duplicated or useless node near the
- // destination node
- //
- // note: preCheckingNodePtr points at the previous node of
- // max_size_result_node_ptr pointed at
- //--------------------------------------------------//
- i = 1;
- while(abs(parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x)<=1 &&
- abs(parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y)<=1)
- {
- max_size_result_node_ptr++;
- preCheckingNodePtr++;
- i++;
- if(i>=node_count)
- break;
- //if(i%40==0)
- // sys_yield();
- }
- max_size_result_node_ptr = preCheckingNodePtr;
-
- //--------------------------------------------------//
- // to smooth the path
- //--------------------------------------------------//
- changed = 1;
- checkedNodeCount = 1;
- curNodeCount = node_count-i+2;
- ptr1 = parent_result_node_ptr;
- ptr2 = max_size_result_node_ptr;
- ptr3 = max_size_result_node_ptr+1;
- #ifdef DEBUG
- int countEnterWhile = 0;
- #endif
- //int yieldCount = 0;
- while(changed && curNodeCount>=3)
- {
- #ifdef DEBUG
- countEnterWhile++;
- #endif
-
- //yieldCount++;
- //if(yieldCount%30==0)
- // sys_yield();
- vectorX = ptr2->node_x - ptr1->node_x;
- vectorY = ptr2->node_y - ptr1->node_y;
- changed = 0;
- curUsefulNodePtr = nodeArray+1;
- checkedNodeCount = 1;
-
- for(j=1; j<curNodeCount-1; j++)
- {
- processed = 0;
- newVectorX= ptr3->node_x - ptr2->node_x;
- newVectorY= ptr3->node_y - ptr2->node_y;
-
- //------ turning at 90 degree clockwise / anti-clockwise --------//
- if((vectorX==0 && vectorY!=0 && newVectorX!=0 && newVectorY==0) || // + case
- (vectorX!=0 && vectorY==0 && newVectorX==0 && newVectorY!=0))
- {
- ptr2++;
- err_when(abs(ptr1->node_x-ptr2->node_x)>1 || abs(ptr1->node_y-ptr2->node_y)>1);
- ptr3++;
- err_when(j<curNodeCount-2 && ptr3->node_x && ptr3->node_y &&
- (abs(ptr3->node_x-ptr2->node_x)>1 || abs(ptr3->node_y-ptr2->node_y)>1));
- vectorX = ptr2->node_x - ptr1->node_x;
- vectorY = ptr2->node_y - ptr1->node_y;
- processed = 1;
- continue;
- }
- if((vectorX!=0 && vectorY!=0 && newVectorX!=0 && newVectorY!=0) && // x case
- ((vectorX==newVectorX && vectorY==-newVectorY) || (vectorX==-newVectorX && vectorY==newVectorY)) &&
- can_move_to((ptr1->node_x+ptr3->node_x)/2, (ptr1->node_y+ptr3->node_y)/2))
- {
- err_when(ptr1->node_x==ptr3->node_x && ptr1->node_y==ptr3->node_y);
- ptr2->node_x = (ptr1->node_x+ptr3->node_x)/2;
- ptr2->node_y = (ptr1->node_y+ptr3->node_y)/2;
- *curUsefulNodePtr = *ptr2;
- err_when(abs(ptr1->node_x-curUsefulNodePtr->node_x)>1 || abs(ptr1->node_y-curUsefulNodePtr->node_y)>1);
- curUsefulNodePtr++;
- checkedNodeCount++;
- ptr1 = ptr2;
- ptr2 = ptr3;
- err_when(abs(ptr1->node_x-ptr2->node_x)>1 || abs(ptr1->node_y-ptr2->node_y)>1);
- ptr3++;
- err_when(j<curNodeCount-2 && ptr3->node_x && ptr3->node_y &&
- (abs(ptr3->node_x-ptr2->node_x)>1 || abs(ptr3->node_y-ptr2->node_y)>1));
- vectorX = ptr2->node_x - ptr1->node_x;
- vectorY = ptr2->node_y - ptr1->node_y;
- processed = 1;
- continue;
- }
- if(j<curNodeCount-2) // check for the 4-point case
- {
- ptr4 = ptr3+1;
- newVectorX2 = ptr4->node_x - ptr3->node_x;
- newVectorY2 = ptr4->node_y - ptr3->node_y;
- caseNum = 0;
- if(vectorX==-1 && vectorY==0 && newVectorX==-1 && newVectorX2==0)
- {
- if(newVectorY==1 && newVectorY2==1 && can_move_to(ptr2->node_x, ptr3->node_y))
- caseNum = 1; //-------- (0,0), (-1,0), (-2,1), (-2,2) --------//
- else if(newVectorY==-1 && newVectorY2==-1 && can_move_to(ptr2->node_x, ptr3->node_y))
- caseNum = 5; //-------- (0,0), (-1,0), (-2,-1), (-2,-2) --------//
- }
- else if(vectorX==1 && vectorY==0 && newVectorX==1 && newVectorX2==0)
- {
- if(newVectorY==1 && newVectorY2==1 && can_move_to(ptr2->node_x, ptr3->node_y))
- caseNum = 3; //-------- (0,0), (1,0), (2,1), (2,2) --------//
- else if(newVectorY==-1 && newVectorY2==-1 && can_move_to(ptr2->node_x, ptr3->node_y))
- caseNum = 7; //-------- (0,0), (1,0), (2,-1), (2,-2) --------//
- }
- else if(vectorX==0 && vectorY==-1 && newVectorY==-1 && newVectorY2==0)
- {
- if(newVectorX==1 && newVectorX2==1 && can_move_to(ptr3->node_x, ptr2->node_y))
- caseNum = 2; //-------- (0,0), (0,-1), (1,-2), (2,-2) --------//
- else if(newVectorX==-1 && newVectorX2==-1 && can_move_to(ptr3->node_x, ptr2->node_y))
- caseNum = 4; //-------- (0,0), (0,-1), (-1,-2), (-2,-2) --------//
- }
- else if(vectorX==0 && vectorY==1 && newVectorY==1 && newVectorY2==0)
- {
- if(newVectorX==1 && newVectorX2==1 && can_move_to(ptr3->node_x, ptr2->node_y))
- caseNum = 6; //-------- (0,0), (0,1), (1,2), (2,2) --------//
- else if(newVectorX==-1 && newVectorX2==-1 && can_move_to(ptr3->node_x, ptr2->node_y))
- caseNum = 8; //-------- (0,0), (0,1), (-1,2), (-2,2) --------//
- }
- if(caseNum)
- {
- if(caseNum%2) // case 1, 3, 5 7
- ptr2->node_y = ptr3->node_y;
- else // case 2, 4, 6, 8
- ptr2->node_x = ptr3->node_x;
- ptr3++; //ptr3 = ptr4;
- *curUsefulNodePtr = *ptr2;
- err_when(abs(ptr1->node_x-curUsefulNodePtr->node_x)>1 || abs(ptr1->node_y-curUsefulNodePtr->node_y)>1);
- curUsefulNodePtr++;
- checkedNodeCount++;
- ptr1 = ptr2;
- ptr2 = ptr3;
- err_when(abs(ptr1->node_x-ptr2->node_x)>1 || abs(ptr1->node_y-ptr2->node_y)>1);
- ptr3++;
- err_when(j<curNodeCount-2 && ptr3->node_x && ptr3->node_y &&
- (abs(ptr3->node_x-ptr2->node_x)>1 || abs(ptr3->node_y-ptr2->node_y)>1));
- j++;
- vectorX = ptr2->node_x - ptr1->node_x;
- vectorY = ptr2->node_y - ptr1->node_y;
- processed = 1;
- continue;
- }
- }
- //------ none of the above case ---------//
- if(!processed)
- {
- *curUsefulNodePtr = *ptr2;
- err_when(abs(ptr1->node_x-curUsefulNodePtr->node_x)>1 || abs(ptr1->node_y-curUsefulNodePtr->node_y)>1);
- curUsefulNodePtr++;
- checkedNodeCount++;
- }
- else
- changed = 1;
- ptr1 = ptr2;
- ptr2 = ptr3;
- err_when(abs(ptr1->node_x-ptr2->node_x)>1 || abs(ptr1->node_y-ptr2->node_y)>1);
- ptr3++;
- err_when(j<curNodeCount-2 && ptr3->node_x && ptr3->node_y &&
- (abs(ptr3->node_x-ptr2->node_x)>1 || abs(ptr3->node_y-ptr2->node_y)>1));
- vectorX = ptr2->node_x - ptr1->node_x;
- vectorY = ptr2->node_y - ptr1->node_y;
- }
- //---- end checking and then reset parameters----//
- if(processed)
- changed = 1;
-
- *curUsefulNodePtr = *ptr2;
- err_when(abs(ptr1->node_x-curUsefulNodePtr->node_x)>1 || abs(ptr1->node_y-curUsefulNodePtr->node_y)>1);
- curUsefulNodePtr++;
- checkedNodeCount++;
-
- curNodeCount = checkedNodeCount;
- checkedNodeCount = 1;
- ptr1 = parent_result_node_ptr;
- ptr2 = ptr1+1;
- err_when(abs(ptr1->node_x-ptr2->node_x)>1 || abs(ptr1->node_y-ptr2->node_y)>1);
- ptr3 = ptr2+1;
- err_when(j<curNodeCount-2 && ptr3->node_x && ptr3->node_y &&
- (abs(ptr3->node_x-ptr2->node_x)>1 || abs(ptr3->node_y-ptr2->node_y)>1));
- debug_check_path(nodeArray, nodeCount); //*** debug only
- }
- node_count = curNodeCount;
- //--------------------------------------------------//
- // to remove the duplicated destination node
- //--------------------------------------------------//
- parent_result_node_ptr = nodeArray;
- max_size_result_node_ptr = nodeArray+1;
- ResultNode* result_node_pointer = max_size_result_node_ptr;
- //----------------------------------
- // get the turning point
- //----------------------------------
- vectorX = max_size_result_node_ptr->node_x - parent_result_node_ptr->node_x;
- vectorY = max_size_result_node_ptr->node_y - parent_result_node_ptr->node_y;
- for(i=1; i<node_count-1; i++)
- {
- parent_result_node_ptr = max_size_result_node_ptr; // don't use parent_result_node_ptr++, if the above code of removing duplication is used.
- max_size_result_node_ptr++;
- newVectorX=(max_size_result_node_ptr->node_x-parent_result_node_ptr->node_x);
- newVectorY=(max_size_result_node_ptr->node_y-parent_result_node_ptr->node_y);
- err_when(newVectorY!=0 && newVectorX!=0 && abs(newVectorX)!=abs(newVectorY));
- //------ turning to another direction at this point ------//
- if(vectorX!=newVectorX || vectorY!=newVectorY)
- {
- err_when(abs(newVectorX)>1 || abs(newVectorY)>1);// || (newVectorX==0 && newVectorY==0))
- if(newVectorX!=0 || newVectorY!=0)
- {
- *result_node_pointer = *parent_result_node_ptr;
- result_node_pointer++;
- nodeCount++;
- vectorX = newVectorX;
- vectorY = newVectorY;
- }
- }
- //if(i%30==0)
- // sys_yield();
- }
- result_node_pointer->node_x = real_sour_x;
- result_node_pointer->node_y = real_sour_y;
- result_node_pointer++;
- nodeCount++;
- return nodeArray;
- }
- //------- End of function SeekPath::smooth_the_path -------//
- //-------- Begin of function Node::generate_successors ---------//
- // Note: In fact, the cost of the starting node should be 0 or 1
- // and the parentEnterDirection is 0. Now the cost in this
- // case is set to 2. The difference can be ignored as it will
- // not affect the search after generating the second level
- // children.
- // The advantage to ignore this case is that less comparsion
- // effort in checking parentEnterDirection.
- //
- short Node::generate_successors(short parentEnterDirection, short realSourX, short realSourY)
- {
- int hasLeft = node_x > cur_border_x1;
- int hasRight = node_x < cur_border_x2;
- int hasUp = node_y > cur_border_y1;
- int hasDown = node_y < cur_border_y2;
- int upperLeftX,upperLeftY;
- short cost;
- upperLeftX = node_x<<1;
- upperLeftY = node_y<<1;
- //-------------------------------------------
- // enter_direction = (exit_direction+3)%8+1
- //-------------------------------------------
- if( hasLeft )
- {
- //--------- Left, exit_direction=1 --------//
- if ((node_type&0x05) && (can_move_to(upperLeftX-1,upperLeftY) || can_move_to(upperLeftX-1,upperLeftY+1)))
- {
- if(parentEnterDirection==2 || parentEnterDirection==8 ||
- (node_type&0x1 && parentEnterDirection==7) || (node_type&0x4 && parentEnterDirection==3) ||
- (!parentEnterDirection && realSourX == upperLeftX))
- cost = 1;
- else
- cost = 2;
- if(generate_succ(node_x-1,node_y,5,cost))
- return 1;
- }
- if( hasUp )
- {
- //------- Upper-Left, exit_direction=8 ---------//
- if ((node_type&0x1) && can_move_to(upperLeftX-1,upperLeftY-1))
- {
- if(parentEnterDirection==7 || parentEnterDirection==1 ||
- (!parentEnterDirection && realSourX==upperLeftX && realSourY==upperLeftY))
- cost = 1;
- else cost = 2;
- if(generate_succ(node_x-1,node_y-1,4,cost))
- return 1;
- }
- }
- if( hasDown )
- {
- //--------- Lower-Left, exit_direction=2 ----------//
- if ((node_type&0x4) && can_move_to(upperLeftX-1,upperLeftY+2))
- { if(parentEnterDirection==1 || parentEnterDirection==3 ||
- (!parentEnterDirection && realSourX==upperLeftX && realSourY==(upperLeftY+1)))
- cost = 1;
- else cost = 2;
- if(generate_succ(node_x-1,node_y+1,6,cost))
- return 1;
- }
- }
- }
- if( hasRight )
- {
- //----------- Right, exit_direction=5 -----------//
- if ((node_type&0xA) && (can_move_to(upperLeftX+2,upperLeftY) || can_move_to(upperLeftX+2,upperLeftY+1)))
- {
- if(parentEnterDirection==4 || parentEnterDirection==6 ||
- (node_type&0x02 && parentEnterDirection==7) || (node_type&0x08 && parentEnterDirection==3) ||
- (!parentEnterDirection && realSourX==(upperLeftX+1)))
- cost = 1;
- else cost = 2;
- if(generate_succ(node_x+1,node_y,1,cost))
- return 1;
- }
- if( hasUp )
- {
- //-------- Upper-Right, exit_direction=6 ---------//
- if ((node_type&0x2)&&can_move_to(upperLeftX+2,upperLeftY-1))
- {
- if(parentEnterDirection==5 || parentEnterDirection==7 ||
- (!parentEnterDirection && realSourX==(upperLeftX+1) && realSourY==upperLeftY))
- cost = 1;
- else cost = 2;
- if(generate_succ(node_x+1,node_y-1,2,cost))
- return 1;
- }
- }
- if( hasDown )
- {
- //--------- Lower-Right, exit_direction=4 ---------//
- if ((node_type&0x8)&&can_move_to(upperLeftX+2,upperLeftY+2))
- {
- if(parentEnterDirection==3 || parentEnterDirection==5 ||
- (!parentEnterDirection && realSourX==(upperLeftX+1) && realSourY==(upperLeftY+1)))
- cost = 1;
- else cost = 2;
- if(generate_succ(node_x+1,node_y+1,8,cost))
- return 1;
- }
- }
- }
- if( hasUp )
- {
- //---------- Upper, exit_direction=7 -----------//
- if ((node_type&0x03) && (can_move_to(upperLeftX,upperLeftY-1) || can_move_to(upperLeftX+1,upperLeftY-1)))
- {
- if(parentEnterDirection==6 || parentEnterDirection==8 ||
- (node_type&0x01 && parentEnterDirection==1) || (node_type&0x02 && parentEnterDirection==5) ||
- (!parentEnterDirection && realSourY==upperLeftY))
- cost = 1;
- else cost = 2;
- if(generate_succ(node_x,node_y-1,3,cost))
- return 1;
- }
- }
-
- if( hasDown )
- {
- //---------- Lower, exit_direction=3 -----------//
- if ((node_type&0xC) && ( can_move_to(upperLeftX,upperLeftY+2) || can_move_to(upperLeftX+1,upperLeftY+2) ) )
- {
- if(parentEnterDirection==2 || parentEnterDirection==4 ||
- (node_type&0x4 && parentEnterDirection==1) || (node_type&0x8 && parentEnterDirection==5) ||
- (!parentEnterDirection && realSourY==(upperLeftY+1)))
- cost = 1;
- else cost = 2;
- if(generate_succ(node_x,node_y+1,7,cost))
- return 1;
- }
- }
- return 0;
- }
- //------- End of function Node::generate_successors -------//
- //-------- Begin of function Node::generate_succ ---------//
- short Node::generate_succ(short x, short y, short enter_direct,short cost)
- {
- //----- if it points back to this node's parent ----//
- if( parent_node )
- {
- if( parent_node->node_x==x && parent_node->node_y==y )
- return 0;
- }
- //----- if there is an existing node at the given position ----//
- int upperLeftX, upperLeftY;
- //int cost;
- short c, g = node_g+cost; // g(Successor)=g(BestNode)+cost of getting from BestNode to Successor
- short nodeRecno;
- if( (nodeRecno=cur_node_matrix[y*MAX_WORLD_X_LOC/2+x]) > 0 &&
- nodeRecno<max_node_num)
- {
- Node* oldNode = cur_node_array+nodeRecno-1;
- //------ Add oldNode to the list of BestNode's child_noderen (or Successors).
- for(c=0 ; c<MAX_CHILD_NODE && child_node[c] ; c++);
- child_node[c]=oldNode;
- //---- if our new g value is < oldNode's then reset oldNode's parent to point to BestNode
- if(g < oldNode->node_g)
- {
- oldNode->parent_node = this;
- oldNode->node_g = g;
- oldNode->node_f = g+oldNode->node_h;
- oldNode->enter_direction = (char)enter_direct;
- //-------- if it's a closed node ---------//
- if(oldNode->child_node[0] )
- {
- //-------------------------------------------------//
- // Since we changed the g value of oldNode, we need
- // to propagate this new value downwards, i.e.
- // do a Depth-First traversal of the tree!
- //-------------------------------------------------//
- oldNode->propagate_down();
- //sys_yield();
- }
- }
- }
- else //------------ add a new node -----------//
- {
- Node* succNode = cur_node_array + cur_seek_path->node_count++;
- memset(succNode, 0, sizeof(Node));
- succNode->parent_node = this;
- succNode->node_g = g;
- succNode->node_h = (x-cur_dest_x)*(x-cur_dest_x)+(y-cur_dest_y)*(y-cur_dest_y); // should do sqrt(), but since we don't really
- succNode->node_f = g+succNode->node_h; // care about the distance but just which branch looks
- succNode->node_x = x; // better this should suffice. Anyayz it's faster.
- succNode->node_y = y;
- succNode->enter_direction = (char)enter_direct;
- upperLeftX = x<<1;
- upperLeftY = y<<1;
- succNode->node_type = can_move_to(upperLeftX,upperLeftY)+(can_move_to(upperLeftX+1,upperLeftY)<<1)+
- (can_move_to(upperLeftX,upperLeftY+1)<<2)+(can_move_to(upperLeftX+1,upperLeftY+1)<<3);
- if(search_mode==SEARCH_MODE_REUSE && nodeRecno>max_node_num) // path-reuse node found, but checking of can_walk(final_dest_?) is requested
- {
- int destIndex = nodeRecno - max_node_num;
- switch(destIndex)
- {
- case 1: final_dest_x = x<<1;
- final_dest_y = y<<1;
- break;
- case 2: final_dest_x = (x<<1) + 1;
- final_dest_y = y<<1;
- break;
- case 3: final_dest_x = x<<1;
- final_dest_y = (y<<1) + 1;
- break;
- case 4: final_dest_x = (x<<1) + 1;
- final_dest_y = (y<<1) + 1;
- break;
- default: err_here();
- break;
- }
- if(can_move_to(final_dest_x, final_dest_y)) // can_walk the connection point, accept this case
- {
- reuse_result_node_ptr = succNode;
- return 1;
- } // else continue until reuse node is found and connection point can be walked
- }
- cur_node_matrix[y*MAX_WORLD_X_LOC/2+x] = cur_seek_path->node_count;
- cur_seek_path->open_node_list.insert_node(succNode);
- for(c=0 ; c<MAX_CHILD_NODE && child_node[c] ; c++); // Add oldNode to the list of BestNode's child_noderen (or succNodes).
- child_node[c]=succNode;
- }
- return 0;
- }
- //------- End of function Node::generate_succ -------//
- //-------- Begin of function Node::propagate_down ---------//
- void Node::propagate_down()
- {
- Node *childNode, *fatherNode;
- int c, g=node_g; // alias.
- short cost;
- char xShift, yShift; // the x, y difference between parent and child nodes
- char childEnterDirection;
- char exitDirection;
- char testResult;
-
- for(c=0;c<8;c++)
- {
- if ((childNode=child_node[c])==NULL) // create alias for faster access.
- break;
- cost = 2; // in fact, may be 1 or 2
- if (g+cost <= childNode->node_g) // first checking
- {
- xShift = childNode->node_x-node_x;
- yShift = childNode->node_y-node_y;
- err_when(abs(xShift)>1 || abs(yShift)>1);
- //---------- calulate the new enter direction ------------//
- switch(yShift)
- {
- case -1:
- childEnterDirection = char(3-xShift);
- break;
- case 0:
- childEnterDirection = char(3-(xShift<<1));
- break;
- case 1:
- childEnterDirection = char(7+xShift);
- break;
- }
- exitDirection = (childEnterDirection+3)%8+1;
-
- if(enter_direction > exitDirection)
- {
- if((enter_direction==8 && (exitDirection==1 || exitDirection==2)) ||
- (enter_direction==7 && exitDirection==1))
- testResult = exitDirection + 8 - enter_direction;
- else
- testResult = enter_direction - exitDirection;
- }
- else
- {
- if((exitDirection==8 && (enter_direction==1 || enter_direction==2)) ||
- (exitDirection==7 && enter_direction==1))
- testResult = enter_direction + 8 - exitDirection;
- else
- testResult = exitDirection - enter_direction;
- }
- if(exitDirection%2 && testResult==2)
- {
- int upperLeftX = 2*node_x;
- int upperLeftY = 2*node_y;
- // this case only occurs at the edge
- switch(childEnterDirection)
- {
- case 1: if((exitDirection==3 && can_move_to(upperLeftX, upperLeftY+1)) ||
- (exitDirection==7 && can_move_to(upperLeftX, upperLeftY)))
- cost = 1;
- break;
- case 3: if((exitDirection==1 && can_move_to(upperLeftX, upperLeftY+1)) ||
- (exitDirection==5 && can_move_to(upperLeftX+1, upperLeftY+1)))
- cost = 1;
- break;
- case 5: if((exitDirection==3 && can_move_to(upperLeftX+1, upperLeftY+1)) ||
- (exitDirection==7 && can_move_to(upperLeftX+1, upperLeftY)))
- cost = 1;
- break;
-
- case 7: if((exitDirection==1 && can_move_to(upperLeftX, upperLeftY)) ||
- (exitDirection==5 && can_move_to(upperLeftX+1, upperLeftY)))
- cost = 1;
- break;
- default: err_here();
- break;
- }
- }
- else
- cost = 2 - (testResult <= 1); //if(testResult <= 1) cost = 1;
-
- err_when(cost>2 || cost<1);
- if(g+cost < childNode->node_g) // second checking, mainly for cost = 2;
- {
- childNode->node_g = g+cost;
- childNode->node_f = childNode->node_g+childNode->node_h;
- childNode->parent_node = this;// reset parent to new path.
- childNode->enter_direction = childEnterDirection;
- stack_push(childNode); // Now the childNode's branch need to be checked out. Remember the new cost must be propagated down.
- }
- }
- }
- while(cur_stack_pos>0)
- {
- fatherNode=stack_pop();
- g = fatherNode->node_g;
- for(c=0;c<8;c++)
- {
- if((childNode=fatherNode->child_node[c])==NULL) // we may stop the propagation 2 ways: either
- break;
- cost = 2; // in fact, may be 1 or 2
- if(g+cost <= childNode->node_g) // first checking
- // there are no children, or that the g value of the child is equal or better than the cost we're propagating
- {
- xShift = childNode->node_x-fatherNode->node_x;
- yShift = childNode->node_y-fatherNode->node_y;
- err_when(abs(xShift)>1 || abs(yShift)>1);
- //---------- calulate the new enter direction ------------//
- switch(yShift)
- {
- case -1:
- childEnterDirection = char(3-xShift);
- break;
- case 0:
- childEnterDirection = char(3-(xShift<<1));
- break;
- case 1:
- childEnterDirection = char(7+xShift);
- break;
- }
- exitDirection = (childEnterDirection+3)%8+1;
-
- char fatherEnterDirection = fatherNode->enter_direction;
- if(fatherEnterDirection > exitDirection)
- {
- if((fatherEnterDirection==8 && (exitDirection==1 || exitDirection==2)) ||
- (fatherEnterDirection==7 && exitDirection==1))
- testResult = exitDirection + 8 - fatherEnterDirection;
- else
- testResult = fatherEnterDirection - exitDirection;
- }
- else
- {
- if((exitDirection==8 && (fatherEnterDirection==1 || fatherEnterDirection==2)) ||
- (exitDirection==7 && fatherEnterDirection==1))
- testResult = fatherEnterDirection + 8 - exitDirection;
- else
- testResult = exitDirection - fatherEnterDirection;
- }
- if(exitDirection%2 && testResult==2)
- {
- int upperLeftX = 2*fatherNode->node_x;
- int upperLeftY = 2*fatherNode->node_y;
- // this case only occurs at the edge
- switch(childEnterDirection)
- {
- case 1: if((exitDirection==3 && can_move_to(upperLeftX, upperLeftY+1)) ||
- (exitDirection==7 && can_move_to(upperLeftX, upperLeftY)))
- cost = 1;
- break;
- case 3: if((exitDirection==1 && can_move_to(upperLeftX, upperLeftY+1)) ||
- (exitDirection==5 && can_move_to(upperLeftX+1, upperLeftY+1)))
- cost = 1;
- break;
- case 5: if((exitDirection==3 && can_move_to(upperLeftX+1, upperLeftY+1)) ||
- (exitDirection==7 && can_move_to(upperLeftX+1, upperLeftY)))
- cost = 1;
- break;
-
- case 7: if((exitDirection==1 && can_move_to(upperLeftX, upperLeftY)) ||
- (exitDirection==5 && can_move_to(upperLeftX+1, upperLeftY)))
- cost = 1;
- break;
- default: err_here();
- break;
- }
- }
- else
- cost = 2 - (testResult <= 1); //if(testResult <= 1) cost = 1;
- err_when(cost>2 || cost<1);
- if(g+cost < childNode->node_g) // second checking, mainly for cost = 2;
- {
- childNode->node_g = g+cost;
- childNode->node_f = childNode->node_g+childNode->node_h;
- childNode->parent_node = fatherNode;
- childNode->enter_direction = childEnterDirection;
- stack_push(childNode);
- }
- }
- }
- }
- }
- //------- End of function Node::propagate_down -------//
- //-------- Begin of static function stack_push ---------//
- static void stack_push(Node *nodePtr)
- {
- stack_array[cur_stack_pos++] = nodePtr;
- err_when( cur_stack_pos >= MAX_STACK_NUM );
- }
- //--------- End of static function stack_push ---------//
- //-------- Begin of static function stack_pop ---------//
- static Node* stack_pop()
- {
- return stack_array[--cur_stack_pos];
- }
- //--------- End of static function stack_pop ---------//
- //-********************************************************************************-//
- // for UNIT_SEA and UNIT_AIR, the scale used is double that of UNIT_LAND
- //-********************************************************************************-//
- //-------- Begin of static function SeekPath::seek2 ---------//
- int SeekPath::seek2(int sx, int sy, int dx, int dy, short miscNo, short numOfPath, int maxTries)
- {
- err_when(mobile_type==UNIT_LAND);
- //---------------------------------------------------------------------------//
- // target_recno, building_id is not implemented for this version of seek2()
- //---------------------------------------------------------------------------//
- target_recno = building_id = 0;
- building_x1 = building_y1 = building_x2 = building_y2 = -1;
- switch(search_mode)
- {
- case SEARCH_MODE_TO_FIRM:
- building_id = miscNo;
- building_x1 = dx; // upper left corner location
- building_y1 = dy;
- search_firm_info = firm_res[building_id];
- building_x2 = dx+search_firm_info->loc_width-1;
- building_y2 = dy+search_firm_info->loc_height-1;
- break;
- case SEARCH_MODE_TO_TOWN:
- building_id = miscNo;
- building_x1 = dx; // upper left corner location
- building_y1 = dy;
- if(miscNo != -1)
- {
- Location* buildPtr = world.get_loc(dx, dy);
- Town* targetTown = town_array[buildPtr->town_recno()];
- building_x2 = targetTown->loc_x2;
- building_y2 = targetTown->loc_y2;
- }
- else // searching to settle. Detail explained in function set_move_to_surround()
- {
- building_x2 = building_x1+STD_TOWN_LOC_WIDTH-1;
- building_y2 = building_y1+STD_TOWN_LOC_HEIGHT-1;
- }
- break;
- case SEARCH_MODE_ATTACK_UNIT_BY_RANGE:
- case SEARCH_MODE_ATTACK_WALL_BY_RANGE:
- err_when(attack_range==0);
- building_id = miscNo;
- building_x1 = max(dx-attack_range, 0);
- building_y1 = max(dy-attack_range, 0);
- building_x2 = min(dx+attack_range, MAX_WORLD_X_LOC-1);
- building_y2 = min(dy+attack_range, MAX_WORLD_Y_LOC-1);
- break;
- case SEARCH_MODE_ATTACK_FIRM_BY_RANGE:
- building_id = miscNo;
- building_x1 = max(dx-attack_range, 0);
- building_y1 = max(dy-attack_range, 0);
- search_firm_info = firm_res[building_id];
- building_x2 = min(dx+search_firm_info->loc_width-1+attack_range, MAX_WORLD_X_LOC-1);
- building_y2 = min(dy+search_firm_info->loc_height-1+attack_range, MAX_WORLD_Y_LOC-1);
- break;
- case SEARCH_MODE_ATTACK_TOWN_BY_RANGE:
- building_id = miscNo;
- building_x1 = max(dx-attack_range, 0);
- building_y1 = max(dy-attack_range, 0);
- building_x2 = min(dx+STD_TOWN_LOC_WIDTH-1+attack_range, MAX_WORLD_X_LOC-1);
- building_y2 = min(dy+STD_TOWN_LOC_HEIGHT-1+attack_range, MAX_WORLD_Y_LOC-1);
- break;
-
- case SEARCH_MODE_TO_LAND_FOR_SHIP:
- region_id = (UCHAR)miscNo;
- break;
- }
-
- //------------------------------------------------------------------------------//
- // set start location and destination location
- //------------------------------------------------------------------------------//
- real_sour_x = sx;
- real_sour_y = sy;
- //final_dest_x = real_dest_x = dx;
- //final_dest_y = real_dest_y = dy;
- real_dest_x = dx;
- real_dest_y = dy;
-
- int xShift, yShift, area;
- short pathNum;
- switch(search_mode)
- {
- case SEARCH_MODE_TO_FIRM:
- case SEARCH_MODE_TO_TOWN:
- final_dest_x = (building_x1+building_x2)/2;
- final_dest_y = (building_y1+building_y2)/2;
- //---------------------------------------------------------------------------------//
- // for group assign, the final destination is adjusted by the value of numOfPath
- //---------------------------------------------------------------------------------//
- if(search_mode==SEARCH_MODE_TO_TOWN)
- area = STD_TOWN_LOC_WIDTH*STD_TOWN_LOC_HEIGHT;
- else // search_mode == SEARCH_MODE_TO_FIRM
- area = search_firm_info->loc_width*search_firm_info->loc_height;
- pathNum = (numOfPath>area) ? (numOfPath-1)%area + 1 : numOfPath;
- if(search_mode==SEARCH_MODE_TO_TOWN)
- m.cal_move_around_a_point(pathNum, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, xShift, yShift);
- else
- m.cal_move_around_a_point(pathNum, search_firm_info->loc_width, search_firm_info->loc_height, xShift, yShift);
- final_dest_x += xShift;
- final_dest_y += yShift;
- if(final_dest_x<0)
- final_dest_x = 0;
- else if(final_dest_x>=MAX_WORLD_X_LOC)
- final_dest_x = MAX_WORLD_X_LOC-1;
- if(final_dest_y<0)
- final_dest_y = 0;
- else if(final_dest_y>=MAX_WORLD_Y_LOC)
- final_dest_y = MAX_WORLD_Y_LOC-1;
- break;
- case SEARCH_MODE_ATTACK_UNIT_BY_RANGE:
- case SEARCH_MODE_ATTACK_FIRM_BY_RANGE:
- case SEARCH_MODE_ATTACK_TOWN_BY_RANGE:
- case SEARCH_MODE_ATTACK_WALL_BY_RANGE:
- final_dest_x = (building_x1+building_x2)/2;
- final_dest_y = (building_y1+building_y2)/2;
- break;
-
- default:
- final_dest_x = real_dest_x;
- final_dest_y = real_dest_y;
- break;
- }
- //--------------------------------------------------------------//
- // change to 2x2 node format
- //--------------------------------------------------------------//
- int sourceX = short(sx/2); // the upper left corner is used
- int sourceY = short(sy/2);
- dest_x = short(final_dest_x/2);
- dest_y = short(final_dest_y/2);
- //-----------------------------------------//
- // reset node_matrix
- //-----------------------------------------//
- if(search_mode!=SEARCH_MODE_REUSE)
- {
- max_node_num = 0xFFFF;
- memset(node_matrix, 0, sizeof(short)*MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC/4);
- }
- else
- {
- max_node_num = max_node;
- memcpy(node_matrix, reuse_node_matrix_ptr, sizeof(short)*MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC/4);
- }
- //--------- create the first node ---------//
- node_count = 0;
- result_node_ptr = NULL;
- Node *nodePtr = node_array + node_count++;
- memset(nodePtr, 0, sizeof(Node));
- //-------- store the upper left coordinate of the node ----------//
- int destUpperLeftX = dest_x<<1;
- int destUpperLeftY = dest_y<<1;
- is_dest_blocked = !can_move_to(destUpperLeftX, destUpperLeftY);
- // whether the destination is blocked, if so, only search till the destination's neighbor locations
- //### begin alex 25/9 ###//
- //------------ do some adjustment for ship to beach if destination is blocked ----------------//
- if(is_dest_blocked && search_mode==SEARCH_MODE_TO_LAND_FOR_SHIP &&
- (final_dest_x%2 || final_dest_y%2)) // either is odd location
- {
- if(final_dest_x%2 && final_dest_y%2==0)
- {
- if(destUpperLeftX+2<MAX_WORLD_X_LOC-1 && can_move_to(destUpperLeftX+2, destUpperLeftY))
- {
- is_dest_blocked = 0;
- destUpperLeftX += 2;
- dest_x++;
- }
- }
- else if(final_dest_x%2==0 && final_dest_y%2)
- {
- if(destUpperLeftY+2<MAX_WORLD_Y_LOC-1 && can_move_to(destUpperLeftX, destUpperLeftY+2))
- {
- is_dest_blocked = 0;
- destUpperLeftY += 2;
- dest_y++;
- }
- }
- else
- {
- if(destUpperLeftX+2<MAX_WORLD_X_LOC-1 && can_move_to(destUpperLeftX+2, destUpperLeftY))
- {
- is_dest_blocked = 0;
- destUpperLeftX += 2;
- dest_x++;
- }
- else if(destUpperLeftX+2<MAX_WORLD_X_LOC-1 && destUpperLeftY+2<MAX_WORLD_Y_LOC-1 &&
- can_move_to(destUpperLeftX+2, destUpperLeftY+2))
- {
- is_dest_blocked = 0;
- destUpperLeftX += 2;
- destUpperLeftY += 2;
- dest_x++;
- dest_y++;
- }
- else if(destUpperLeftY+2<MAX_WORLD_Y_LOC-1 && can_move_to(destUpperLeftX, destUpperLeftY+2))
- {
- is_dest_blocked = 0;
- destUpperLeftY += 2;
- dest_y++;
- }
- }
- }
- //#### end alex 25/9 ####//
- nodePtr->node_g = 0;
- nodePtr->node_h = (sourceX-dest_x)*(sourceX-dest_x)+(sourceY-dest_y)*(sourceY-dest_y); // should really use sqrt().
- nodePtr->node_f = nodePtr->node_g + nodePtr->node_h;
- nodePtr->node_x = sourceX;
- nodePtr->node_y = sourceY;
- open_node_list.insert_node(nodePtr); // make Open List point to first node
- //--- if the destination is the current postion or next to it & the dest is occupied ---//
- if(sourceX==dest_x && sourceY==dest_y)
- {
- path_status = PATH_FOUND;
- result_node_ptr = NULL;
- return path_status;
- }
- //------------ seek now ------------------//
- int maxNode = (!maxTries) ? max_node : maxTries;
- return continue_seek2(maxNode, 1); // 1-first seek session of the current seek order
- }
- //--------- End of static function SeekPath::seek2 ---------//
- //-------- Begin of static function SeekPath::continue_seek2 ---------//
- int SeekPath::continue_seek2(int maxTries, char firstSeek)
- {
- if( path_status != PATH_SEEKING )
- return path_status;
- //------- aliasing class member vars for fast access ------//
- cur_seek_path = this;
- cur_dest_x = dest_x;
- cur_dest_y = dest_y;
- cur_node_matrix = node_matrix;
- cur_node_array = node_array;
- cur_border_x1 = border_x1;
- cur_border_y1 = border_y1;
- cur_border_x2 = border_x2;
- cur_border_y2 = border_y2;
- //------ seek the path using the A star algorithm -----//
- int maxNode = (total_node_avail<maxTries) ? total_node_avail : maxTries;
- maxNode -= MAX_CHILD_NODE; // generate_successors() can generate a max of MAX_CHILD_NODE new nodes per call
- Node *bestNodePtr;
- int i;
- for(i=0; i<maxNode; i++)
- {
- bestNodePtr = return_best_node();
- //if(i%20==0)
- // sys_yield(); // update cursor position
- //---- even if the path is impossible, get the closest path ----//
- if( !bestNodePtr )
- {
- path_status = PATH_IMPOSSIBLE;
- break;
- }
- //----- exceed the object's max's node limitation, return the closest path ----//
- if( node_count >= maxNode )
- //if( i >= maxNode )
- {
- path_status = PATH_NODE_USED_UP;
- break;
- }
- //------------------------------------------//
- // If the path is found OR
- //
- // If the destination is blocked,
- // consider it done when we are next to it.
- //------------------------------------------//
- if( (bestNodePtr->node_x==dest_x && bestNodePtr->node_y==dest_y) ||
- ( is_dest_blocked && abs(bestNodePtr->node_x-dest_x)<=1 && abs(bestNodePtr->node_y-dest_y)<=1 ) )
- {
- path_status = PATH_FOUND;
- result_node_ptr = bestNodePtr;
- break;
- }
- //--------- generate successors -------//
- if(bestNodePtr->generate_successors2(real_sour_x, real_sour_y))
- {
- path_status = PATH_REUSE_FOUND;
- result_node_ptr = reuse_result_node_ptr;
- break;
- }
- }
- err_when( cur_stack_pos!=0 ); // it should be zero all the times, all pushes should have been poped
- current_search_node_used = i+1; // store the number of nodes used in this searching
- return path_status;
- }
- //--------- End of static function SeekPath::continue_seek2 ---------//
- //---- Begin of function SeekPath::get_result2 ---------//
- ResultNode* SeekPath::get_result2(int& resultNodeCount, short& pathDist)
- {
- resultNodeCount = pathDist = 0;
- if(total_node_avail<=0)
- return NULL;
- total_node_avail -= current_search_node_used;
- short useClosestNode = 0; // indicate whether closest node is returned instead of the actual node
- if(!result_node_ptr || !result_node_ptr->parent_node) // if PATH_IMPOSSIBLE or PATH_NODE_USED_UP, result_node_ptr is NULL, we need to call get_closest_node() to get the closest node.
- {
- if(path_status==PATH_FOUND)
- return NULL; // the current location is already the destination
-
- err_when(path_status==PATH_FOUND);
- result_node_ptr = return_closest_node();
- useClosestNode = 1;
- if(!result_node_ptr)
- return NULL;
- }
- //--------------------------------------------------//
- // Trace backwards to the starting node, and rationalize
- // nodes (i.e. group nodes of the same direction into
- // single nodes.)
- //--------------------------------------------------//
- Node* nodePtr = result_node_ptr; // the node current being processed
- Node* baseNodePtr = result_node_ptr; // the first end node for connecting the other end node for the path in that direction.
- Node* parentNode = nodePtr->parent_node; // the parent node of nodePtr
- if(!parentNode)
- return NULL;
-
- resultNodeCount=1; // the current node
- err_when( !parentNode ); // the desination node must have a parent node
- //--- if the following nodes are going at the same direction, rationalize them ---//
- short vectorX = parentNode->node_x - nodePtr->node_x; // the vector at which the sprite is going
- short vectorY = parentNode->node_y - nodePtr->node_y;
- short newVectorX, newVectorY;
- nodePtr = parentNode;
- //sys_yield(); // update cursor position
- err_when(vectorX && vectorY && abs(vectorX)!=abs(vectorY));
- while((parentNode=nodePtr->parent_node) != NULL)
- {
- err_when(abs(vectorX)>1 || abs(vectorY)>1);
- //------ turning to another direction at this point ------//
- newVectorX = parentNode->node_x-nodePtr->node_x;
- newVectorY = parentNode->node_y-nodePtr->node_y;
- if(vectorX != newVectorX || vectorY != newVectorY)
- {
- err_when(abs(newVectorX)>1 || abs(newVectorY)>1);
- err_when(newVectorX && newVectorY && abs(newVectorX)!=abs(newVectorY));
- err_when(baseNodePtr->node_x-nodePtr->node_x && baseNodePtr->node_y-nodePtr->node_y &&
- abs(baseNodePtr->node_x-nodePtr->node_x)!=abs(baseNodePtr->node_y-nodePtr->node_y));
- baseNodePtr->parent_node = nodePtr; // skip the in-between ones which are in the same direction
- baseNodePtr = nodePtr; // prepare for the next line.
- resultNodeCount++;
- vectorX = newVectorX;
- vectorY = newVectorY;
- }
- nodePtr = parentNode;
- }
- baseNodePtr->parent_node = nodePtr; // finish off the last one
- resultNodeCount++;
- //----------------------------------------------------------------------------//
- // After the above process, here we will have a link of rationalize nodes.
- // Retrieve them in the backwards order
- //----------------------------------------------------------------------------//
- //sys_yield(); // update cursor position
- ResultNode *resultNodeArray = (ResultNode*) mem_add( sizeof(ResultNode) * resultNodeCount );
- ResultNode *resultNodePtr = resultNodeArray+resultNodeCount-1;
- int processCount = 1;
- Node *preNodePtr = result_node_ptr;
- resultNodePtr->node_x = preNodePtr->node_x;
- resultNodePtr->node_y = preNodePtr->node_y;
- resultNodePtr--;
- Node *curNodePtr = result_node_ptr->parent_node;
- err_when(pathDist!=0);
- int xDist, yDist;
- while(processCount++ < resultNodeCount)
- {
- err_when(curNodePtr->node_x<0 || curNodePtr->node_x>=MAX_WORLD_X_LOC ||
- curNodePtr->node_y<0 || curNodePtr->node_y>=MAX_WORLD_Y_LOC);
- resultNodePtr->node_x = curNodePtr->node_x;
- resultNodePtr->node_y = curNodePtr->node_y;
- resultNodePtr--;
- xDist = abs(curNodePtr->node_x-preNodePtr->node_x);
- yDist = abs(curNodePtr->node_y-preNodePtr->node_y);
- err_when((!xDist && !yDist) || (xDist && yDist && xDist!=yDist));
- pathDist += (xDist) ? xDist : yDist;
- preNodePtr = curNodePtr;
- curNodePtr = curNodePtr->parent_node;
- }
- //sys_yield(); // update cursor position
- //------------------------------------------------//
- // multipy all the node by scale 2
- //------------------------------------------------//
- for(processCount=0, resultNodePtr=resultNodeArray; processCount<resultNodeCount; processCount++, resultNodePtr++)
- {
- resultNodePtr->node_x <<= 1;
- resultNodePtr->node_y <<= 1;
- err_when(resultNodePtr->node_x<0 || resultNodePtr->node_x>=MAX_WORLD_X_LOC ||
- resultNodePtr->node_y<0 || resultNodePtr->node_y>=MAX_WORLD_Y_LOC);
- }
- pathDist <<= 1;
- #ifdef DEBUG
- //------------------------------------------------------------------------//
- // used to debug for the path of UNIT_SEA
- //------------------------------------------------------------------------//
- if(search_mode==SEARCH_MODE_IN_A_GROUP || search_mode==SEARCH_MODE_REUSE || search_mode==SEARCH_MODE_A_UNIT_IN_GROUP)
- if(mobile_type==UNIT_SEA && resultNodeCount>1 && search_mode!=SEARCH_MODE_TO_LAND_FOR_SHIP)
- debug_check_sea_sailable(resultNodeArray, resultNodeCount);
- #endif
- return resultNodeArray;
- }
- //------- End of function SeekPath::get_result2 -------//
- //-------- Begin of function Node::generate_successors2 ---------//
- short Node::generate_successors2(short realSourX, short realSourY)
- {
- int hasLeft = node_x > cur_border_x1;
- int hasRight = node_x < cur_border_x2;
- int hasUp = node_y > cur_border_y1;
- int hasDown = node_y < cur_border_y2;
- int upperLeftX, upperLeftY;
- short cost = 2;
- upperLeftX = node_x<<1;
- upperLeftY = node_y<<1;
- if(hasLeft)
- {
- //--------- Left --------//
- if(can_move_to(upperLeftX-2, upperLeftY) && can_move_to(upperLeftX-1, upperLeftY))
- {
- if(generate_succ2(node_x-1, node_y))
- return 1;
- }
- //------- Upper-Left ---------//
- if(hasUp)
- {
- if(can_move_to(upperLeftX-2, upperLeftY-2) && can_move_to(upperLeftX-1, upperLeftY-1)) // can pass through the tile
- {
- if(generate_succ2(node_x-1, node_y-1))
- return 1;
- }
- }
- //--------- Lower-Left ----------//
- if(hasDown)
- {
- if(can_move_to(upperLeftX-2, upperLeftY+2) && can_move_to(upperLeftX-1, upperLeftY+1))
- {
- if(generate_succ2(node_x-1, node_y+1))
- return 1;
- }
- }
- }
- if(hasRight)
- {
- //----------- Right -----------//
- if(can_move_to(upperLeftX+2, upperLeftY) && can_move_to(upperLeftX+1, upperLeftY))
- {
- if(generate_succ2(node_x+1, node_y))
- return 1;
- }
- //-------- Upper-Right ---------//
- if(hasUp)
- {
- if(can_move_to(upperLeftX+2, upperLeftY-2) && can_move_to(upperLeftX+1, upperLeftY-1))
- {
- if(generate_succ2(node_x+1, node_y-1))
- return 1;
- }
- }
- //--------- Lower-Right ---------//
- if(hasDown)
- {
- if(can_move_to(upperLeftX+2, upperLeftY+2) && can_move_to(upperLeftX+1, upperLeftY+1))
- {
- if(generate_succ2(node_x+1, node_y+1))
- return 1;
- }
- }
- }
- //---------- Upper -----------//
- if(hasUp)
- {
- if(can_move_to(upperLeftX, upperLeftY-2) && can_move_to(upperLeftX, upperLeftY-1))
- {
- if(generate_succ2(node_x, node_y-1))
- return 1;
- }
- }
- //---------- Lower -----------//
- if(hasDown)
- {
- if(can_move_to(upperLeftX, upperLeftY+2) && can_move_to(upperLeftX, upperLeftY+1))
- {
- if(generate_succ2(node_x, node_y+1))
- return 1;
- }
- }
- return 0;
- }
- //------- End of function Node::generate_successors2 -------//
- //-------- Begin of function Node::generate_succ2 ---------//
- short Node::generate_succ2(short x, short y, short cost)
- {
- //----- if it points back to this node's parent ----//
- if(parent_node)
- {
- if(parent_node->node_x==x && parent_node->node_y==y)
- return 0;
- }
- //----- if there is an existing node at the given position ----//
- //int upperLeftX, upperLeftY;
- short c, g = node_g+1; // g(Successor)=g(BestNode)+cost of getting from BestNode to Successor
- short nodeRecno;
- if((nodeRecno=cur_node_matrix[y*MAX_WORLD_X_LOC/2+x]) > 0 && nodeRecno<max_node_num)
- {
- Node* oldNode = cur_node_array+nodeRecno-1;
- //------ Add oldNode to the list of BestNode's child_noderen (or Successors).
- for(c=0 ; c<MAX_CHILD_NODE && child_node[c] ; c++);
- child_node[c]=oldNode;
- //---- if our new g value is < oldNode's then reset oldNode's parent to point to BestNode
- if(g < oldNode->node_g)
- {
- oldNode->parent_node = this;
- oldNode->node_g = g;
- oldNode->node_f = g+oldNode->node_h;
- //-------- if it's a closed node ---------//
- if(oldNode->child_node[0] )
- {
- //-------------------------------------------------//
- // Since we changed the g value of oldNode, we need
- // to propagate this new value downwards, i.e.
- // do a Depth-First traversal of the tree!
- //-------------------------------------------------//
- oldNode->propagate_down();
- //sys_yield();
- }
- }
- }
- else //------------ add a new node -----------//
- {
- Node* succNode = cur_node_array + cur_seek_path->node_count++;
- memset(succNode, 0, sizeof(Node));
- succNode->parent_node = this;
- succNode->node_g = g;
- succNode->node_h = (x-cur_dest_x)*(x-cur_dest_x)+(y-cur_dest_y)*(y-cur_dest_y); // should do sqrt(), but since we don't really
- succNode->node_f = g+succNode->node_h; // care about the distance but just which branch looks
- succNode->node_x = x; // better this should suffice. Anyayz it's faster.
- succNode->node_y = y;
- if(search_mode==SEARCH_MODE_REUSE && nodeRecno>max_node_num) // path-reuse node found, but checking of can_walk(final_dest_?) is requested
- {
- final_dest_x = x<<1;
- final_dest_y = y<<1;
- if(can_move_to(final_dest_x, final_dest_y)) // can_walk the connection point, accept this case
- {
- reuse_result_node_ptr = succNode;
- return 1;
- } // else continue until reuse node is found and connection point can be walked
- }
- cur_node_matrix[y*MAX_WORLD_X_LOC/2+x] = cur_seek_path->node_count;
- cur_seek_path->open_node_list.insert_node(succNode);
- for(c=0 ; c<MAX_CHILD_NODE && child_node[c] ; c++); // Add oldNode to the list of BestNode's child_noderen (or succNodes).
- child_node[c]=succNode;
- }
- return 0;
- }
- //------- End of function Node::generate_succ2 -------//
- //-------- Begin of function Node::propagate_down2 --------//
- void Node::propagate_down2()
- {
- Node* childNode, *fatherNode;
- int c, g=node_g; // alias.
- int cost = 1;
- #ifdef DEBUG
- int middleXLoc, middleYLoc;
- #endif
- for(c=0;c<8;c++)
- {
- if((childNode=child_node[c])==NULL) // create alias for faster access.
- break;
- if(g+cost < childNode->node_g)
- {
- #ifdef DEBUG
- middleXLoc = (node_x + childNode->node_x); // calculate real coordinate
- middleYLoc = (node_y + childNode->node_y);
- if(can_move_to(middleXLoc, middleYLoc))
- #else
- if(can_move_to(node_x+childNode->node_x, node_y+childNode->node_y))
- #endif
- {
- childNode->node_g = g+cost;
- childNode->node_f = childNode->node_g+childNode->node_h;
- childNode->parent_node = this; // reset parent to new path.
- stack_push(childNode); // Now the childNode's branch need to be
- }
- } // checked out. Remember the new cost must be propagated down.
- }
- while(cur_stack_pos>0)
- {
- fatherNode=stack_pop();
- g = fatherNode->node_g;
- for(c=0;c<8;c++)
- {
- if ((childNode=fatherNode->child_node[c])==NULL) // we may stop the propagation 2 ways: either
- break;
- if(g+cost < childNode->node_g) // there are no children, or that the g value of
- { // the child is equal or better than the cost we're propagating
- #ifdef DEBUG
- middleXLoc = (node_x + childNode->node_x); // calculate real coordinate
- middleYLoc = (node_y + childNode->node_y);
- if(can_move_to(middleXLoc, middleYLoc))
- #else
- if(can_move_to(node_x+childNode->node_x, node_y+childNode->node_y))
- #endif
- {
- childNode->node_g = g+cost;
- childNode->node_f = childNode->node_g+childNode->node_h;
- childNode->parent_node = fatherNode;
- stack_push(childNode);
- }
- }
- }
- }
- }
- //------- End of function Node::propagate_down2 -------//
|