void UnitB::process_wait() { err_when(cur_action != SPRITE_WAIT); //move if the next tile is ready int stepMagn = move_step_magn(); if(can_move((cur_x+stepMagn*move_x_pixel_array[final_dir])/LOCATE_WIDTH, (cur_y+stepMagn*move_y_pixel_array[final_dir])/LOCATE_WIDTH)) { wait_state = 0; cur_action = SPRITE_MOVE; return; } else //find a new path if the thing occupying the next tile no longer move { /* int occUnitNum; Unit* occStuff; occUnitNum = checking_who_occupy_my_next_tile((cur_x+stepMagn*move_x_pixel_array[final_dir])/LOCATE_WIDTH, (cur_y+stepMagn*move_y_pixel_array[final_dir])/LOCATE_WIDTH); //##### begin trevor 21/1 #####// enum{ SEARCH_NEW_PATH_PROBABILITY = 10 }; if( (!occUnitNum || (occUnitNum && (occStuff=unit_array[occUnitNum]) && (occStuff->cur_action != SPRITE_MOVE && occStuff->cur_action != SPRITE_WAIT))) || (SEARCH_NEW_PATH_PROBABILITY > m.random(100) && sprite_speed() <= occStuff->sprite_speed() && !is_in_formation()) ) { wait_state = 0; move_to(move_to_loc_x, move_to_loc_y); // retry_state++; return; } //##### end trevor 21/1 #####//*/ } //find a new path if wait too long // ####### begin Gilbert 28/4 ########// if(wait_state++ > (retry_state <= MAX_UNIT_WAIT_STATE ? retry_state+MAX_UNIT_WAIT_STATE_FIRST : MAX_UNIT_WAIT_STATE) ) { wait_state = 0; int backupRetryState = retry_state; move_to(move_to_loc_x, move_to_loc_y); retry_state = backupRetryState + 1; // restore and increase } // ####### end Gilbert 28/4 ########// //if retrying too many times, stop move if(retry_state > MAX_RETRY_STATE) { stop_move(); retry_state = 0; } }
//--------- Begin of function Sprite::sprite_move --------// // // <int> desX, desY - the destination coordination // void Sprite::sprite_move(int desX, int desY) { if( cur_action != SPRITE_MOVE ) { cur_action = SPRITE_MOVE; cur_frame = 1; } err_when(desX<0 || desY<0 || desX>=MAX_WORLD_X_LOC*LOCATE_WIDTH || desY>=MAX_WORLD_Y_LOC*LOCATE_HEIGHT); #ifdef DEBUG short vectorX=desX-next_x; short vectorY=desY-next_y; if(vectorX && vectorY) // both are non-zero { err_if(abs(vectorX) != abs(vectorY)) err_here(); } #endif go_x = desX; go_y = desY; //----------- determine the movement direction ---------// set_dir(cur_x, cur_y, go_x, go_y); //------ set the next tile to move towards -------// /* next_x = cur_x; next_y = cur_y; */ int stepMagn = move_step_magn(); set_next(cur_x+stepMagn*move_x_pixel_array[final_dir], cur_y+stepMagn*move_y_pixel_array[final_dir], -stepMagn); err_when(cur_action==SPRITE_MOVE && (cur_x!=next_x || cur_y!=next_y) && final_dir!=(check_dir1=get_dir(cur_x, cur_y, next_x, next_y))); }
//--------- Begin of function Unit::ship_to_beach_path_edit ---------// // find a path to the beach // // <int&> resultXLoc - reference to return final x location the ship move to // <int&> resultYLoc - reference to return final y location the ship move to // <UCHAR> regionId - region id of the destination location // // return 1 if normal execution // return 0 if calling move_to() instead // int Unit::ship_to_beach_path_edit(int& resultXLoc, int& resultYLoc, UCHAR regionId) { int curXLoc = next_x_loc(); int curYLoc = next_y_loc(); if(abs(curXLoc-resultXLoc)<=1 && abs(curYLoc-resultYLoc)<=1) return 1; //--------------- find a path to land area -------------------// UnitMarine *shipPtr = (UnitMarine*) this; int result = search(resultXLoc, resultYLoc, 1, SEARCH_MODE_TO_LAND_FOR_SHIP, regionId); if(!result) return 1; //----------- update cur location --------// curXLoc = next_x_loc(); curYLoc = next_y_loc(); err_when(shipPtr->extra_move_in_beach!=NO_EXTRA_MOVE); //------------------------------------------------------------------------------// // edit the result path to get a location for embarking //------------------------------------------------------------------------------// err_when(result_node_array==NULL && result_node_count); if(result_node_array && result_node_count) { err_when(result_node_count<2); ResultNode *curNodePtr = result_node_array; ResultNode *nextNodePtr = curNodePtr + 1; int moveScale = move_step_magn(); int nodeCount = result_node_count; Location *locPtr; int i, j, found, pathDist; int preXLoc, preYLoc; int checkXLoc = curXLoc; int checkYLoc = curYLoc; int hasMoveStep = 0; if(checkXLoc!=curNodePtr->node_x || checkYLoc!=curNodePtr->node_y) { err_when(abs(checkXLoc-curNodePtr->node_x)>moveScale || abs(checkYLoc-curNodePtr->node_y)>moveScale); hasMoveStep += moveScale; checkXLoc = curNodePtr->node_x; checkYLoc = curNodePtr->node_y; } //-----------------------------------------------------------------// // find the pair of points that one is in ocean and one in land //-----------------------------------------------------------------// err_when(terrain_res[world.get_loc(curNodePtr->node_x, curNodePtr->node_y)->terrain_id]->average_type!=TERRAIN_OCEAN); int vecX, vecY, xMagn, yMagn, magn; #ifdef DEBUG int debugLoop1=0, debugLoop2=0; #endif for(pathDist=0, found=0, i=1; i<nodeCount; ++i, curNodePtr++, nextNodePtr++) { #ifdef DEBUG err_when(++debugLoop1>10000); #endif vecX = nextNodePtr->node_x - curNodePtr->node_x; vecY = nextNodePtr->node_y - curNodePtr->node_y; magn = ((xMagn=abs(vecX)) > (yMagn=abs(vecY))) ? xMagn : yMagn; if(xMagn) { vecX /= xMagn; vecX *= moveScale; } if(yMagn) { vecY /= yMagn; vecY *= moveScale; } err_when(abs(vecX)>moveScale && abs(vecY)>moveScale); //------------- check each location bewteen editNode1 and editNode2 -------------// for(j=0; j<magn; j+=moveScale) { #ifdef DEBUG err_when(++debugLoop2>10000); #endif preXLoc = checkXLoc; preYLoc = checkYLoc; checkXLoc += vecX; checkYLoc += vecY; locPtr = world.get_loc(checkXLoc, checkYLoc); if(terrain_res[locPtr->terrain_id]->average_type!=TERRAIN_OCEAN) // found { found++; break; } } if(found) { //------------ a soln is found ---------------// if(!j) // end node should be curNodePtr pointed at { pathDist -= hasMoveStep; result_node_count = i; result_path_dist = pathDist; } else { nextNodePtr->node_x = checkXLoc; nextNodePtr->node_y = checkYLoc; if(i==1) // first editing { ResultNode *firstNodePtr = result_node_array; if(cur_x==firstNodePtr->node_x*ZOOM_LOC_WIDTH && cur_y==firstNodePtr->node_y*ZOOM_LOC_HEIGHT) { go_x = checkXLoc * ZOOM_LOC_WIDTH; go_y = checkYLoc * ZOOM_LOC_HEIGHT; } } pathDist += (j+moveScale); pathDist -= hasMoveStep; result_node_count = i+1; result_path_dist = pathDist; } move_to_x_loc = preXLoc; move_to_y_loc = preYLoc; locPtr = world.get_loc((preXLoc+checkXLoc)/2, (preYLoc+checkYLoc)/2); if(terrain_res[locPtr->terrain_id]->average_type!=TERRAIN_OCEAN) { resultXLoc = (preXLoc+checkXLoc)/2; resultYLoc = (preYLoc+checkYLoc)/2; } else { resultXLoc = checkXLoc; resultYLoc = checkYLoc; } break; } else pathDist += magn; } if(!found) { ResultNode *endNodePtr = result_node_array + result_node_count - 1; if(abs(endNodePtr->node_x-resultXLoc)>1 || abs(endNodePtr->node_y-resultYLoc)>1) { move_to(resultXLoc, resultYLoc, -1); return 0; } } } else { //------------- scan for the surrounding for a land location -----------// int xShift, yShift, checkXLoc, checkYLoc; Location *locPtr; for(int i=2; i<=9; ++i) { misc.cal_move_around_a_point(i, 3, 3, xShift, yShift); checkXLoc = curXLoc + xShift; checkYLoc = curYLoc + yShift; if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC) continue; locPtr = world.get_loc(checkXLoc, checkYLoc); if(locPtr->region_id!=regionId) continue; if(terrain_res[locPtr->terrain_id]->average_type!=TERRAIN_OCEAN && locPtr->can_move(UNIT_LAND)) { resultXLoc = checkXLoc; resultYLoc = checkYLoc; return 1; } } return 0; } return 1; }
//------ Begin of function Unit::handle_blocked_move_s11 -------// // both blocked and blocking are size 1 // void Unit::handle_blocked_move_s11(Unit *unitPtr) { err_when( world.get_unit_recno(next_x_loc(), next_y_loc(), mobile_type) != sprite_recno ); err_when( world.get_unit_recno(unitPtr->next_x_loc(), unitPtr->next_y_loc(), unitPtr->mobile_type) != unitPtr->sprite_recno ); err_when(cur_x!=next_x || cur_y!=next_y); int waitTerm; int moveStep = move_step_magn(); switch(unitPtr->cur_action) { //------------------------------------------------------------------------------------// // handle blocked for units belonging to the same nation. For those belonging to other // nations, wait for it moving to other locations or search for another path. //------------------------------------------------------------------------------------// case SPRITE_WAIT: // the blocking unit is waiting err_when(unitPtr->go_x==unitPtr->cur_x && unitPtr->go_y==unitPtr->cur_y); case SPRITE_TURN: if(unitPtr->nation_recno==nation_recno) handle_blocked_wait(unitPtr); // check for cycle wait for our nation else if(waiting_term>=MAX_WAITING_TERM_DIFF) { search_or_stop(move_to_x_loc, move_to_y_loc, 1); // recall searching waiting_term = 0; } else // wait set_wait(); return; //------------------------------------------------------------------------------------// // We know from the cur_action of the blocking unit it is moving to another locations, // the blocked unit wait for a number of terms or search again. //------------------------------------------------------------------------------------// case SPRITE_MOVE: case SPRITE_READY_TO_MOVE: case SPRITE_SHIP_EXTRA_MOVE: if(unit_id!=UNIT_CARAVAN && unitPtr->unit_id==UNIT_CARAVAN) // don't wait for caravans, and caravans don't wait for other units { search(move_to_x_loc, move_to_y_loc, 1, SEARCH_MODE_A_UNIT_IN_GROUP); } else { waitTerm = (nation_recno==unitPtr->nation_recno) ? MAX_WAITING_TERM_SAME : MAX_WAITING_TERM_DIFF; if(waiting_term>=waitTerm) { search_or_wait(); waiting_term = 0; } else set_wait(); } return; //------------------------------------------------------------------------------------// // handling blocked for idle unit //------------------------------------------------------------------------------------// case SPRITE_IDLE: err_when(unitPtr->result_node_array!=NULL); if(unitPtr->action_mode==ACTION_SHIP_TO_BEACH) { //----------------------------------------------------------------------// // the blocking unit is trying to move to beach, so wait a number of terms, // or call searching again //----------------------------------------------------------------------// if(abs(unitPtr->next_x_loc()-unitPtr->action_x_loc2)<=moveStep && abs(unitPtr->next_y_loc()-unitPtr->action_y_loc2)<=moveStep && terrain_res[world.get_loc(unitPtr->action_x_loc2, unitPtr->action_y_loc2)->terrain_id]->average_type !=TERRAIN_OCEAN) { if(action_mode2==ACTION_SHIP_TO_BEACH && action_x_loc2==unitPtr->action_x_loc2 && action_y_loc2==unitPtr->action_y_loc2) { int tempX, tempY; ship_to_beach(action_x_loc2, action_y_loc2, tempX, tempY); } else { waitTerm = (nation_recno==unitPtr->nation_recno) ? MAX_WAITING_TERM_SAME : MAX_WAITING_TERM_DIFF; if(waiting_term>=waitTerm) stop2(); else set_wait(); } return; } } if(unitPtr->nation_recno==nation_recno) //-------- same nation { //------------------------------------------------------------------------------------// // units from our nation //------------------------------------------------------------------------------------// if(unitPtr->unit_group_id==unit_group_id) { //--------------- from the same group -----------------// if(way_point_count && !unitPtr->way_point_count) { //------------ reset way point --------------// stop2(); reset_way_point_array(); } else if((unitPtr->next_x_loc() != move_to_x_loc || unitPtr->next_y_loc() != move_to_y_loc) && (unitPtr->cur_action==SPRITE_IDLE && unitPtr->action_mode2==ACTION_STOP)) move_to_my_loc(unitPtr); // push the blocking unit and exchange their destination else if(unitPtr->action_mode == ACTION_SETTLE) set_wait(); // wait for the settler else if(waiting_term>MAX_WAITING_TERM_SAME) { //---------- stop if wait too long ----------// terminate_move(); waiting_term = 0; } else set_wait(); } else if(unitPtr->action_mode2==ACTION_STOP) handle_blocked_by_idle_unit(unitPtr); else if(way_point_count && !unitPtr->way_point_count) { stop2(); reset_way_point_array(); } else search_or_stop(move_to_x_loc, move_to_y_loc, 1); // recall A* algorithm by default mode } else // different nation { //------------------------------------------------------------------------------------// // units from other nations //------------------------------------------------------------------------------------// if(unitPtr->next_x_loc() == move_to_x_loc && unitPtr->next_y_loc() == move_to_y_loc) { terminate_move(); // destination occupied by other unit if(action_mode==ACTION_ATTACK_UNIT && unitPtr->nation_recno!=nation_recno && unitPtr->sprite_recno==action_para) { err_when(action_x_loc!=unitPtr->next_x_loc() || action_y_loc!=unitPtr->next_y_loc()); err_when(action_mode2!=ACTION_ATTACK_UNIT && action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET); err_when(action_para2!=action_para); err_when(action_x_loc!=action_x_loc2 || action_y_loc!=action_y_loc2); set_dir(next_x, next_y, unitPtr->next_x, unitPtr->next_y); if(is_dir_correct()) attack_unit(action_para); else set_turn(); cur_frame = 1; } } else search_or_stop(move_to_x_loc, move_to_y_loc, 1); // recall A* algorithm by default mode } return; //------------------------------------------------------------------------------------// // don't wait for attackers from other nations, search for another path. //------------------------------------------------------------------------------------// case SPRITE_ATTACK: //----------------------------------------------------------------// // don't wait for other nation unit, call searching again //----------------------------------------------------------------// if(nation_recno!=unitPtr->nation_recno) { search_or_stop(move_to_x_loc, move_to_y_loc, 1); return; } //------------------------------------------------------------------------------------// // for attackers owned by our commander, handled blocked case by case as follows. //------------------------------------------------------------------------------------// switch(unitPtr->action_mode) { case ACTION_ATTACK_UNIT: if(action_para && !unit_array.is_deleted(action_para)) { Unit *targetPtr = unit_array[action_para]; handle_blocked_attack_unit(unitPtr, targetPtr); } else search_or_stop(move_to_x_loc, move_to_y_loc, 1, SEARCH_MODE_A_UNIT_IN_GROUP); break; case ACTION_ATTACK_FIRM: if(!unitPtr->action_para || firm_array.is_deleted(unitPtr->action_para)) set_wait(); else handle_blocked_attack_firm(unitPtr); break; case ACTION_ATTACK_TOWN: if(!unitPtr->action_para || town_array.is_deleted(unitPtr->action_para)) set_wait(); else handle_blocked_attack_town(unitPtr); break; case ACTION_ATTACK_WALL: if(unitPtr->action_para) set_wait(); else handle_blocked_attack_wall(unitPtr); break; case ACTION_GO_CAST_POWER: set_wait(); break; default: err_here(); break; } return; //------------------------------------------------------------------------------------// // the blocked unit can pass after the blocking unit disappears in air. //------------------------------------------------------------------------------------// case SPRITE_DIE: set_wait(); // assume this unit will not wait too long return; default: err_here(); break; } err_when(cur_x==go_x && cur_y==go_y && (cur_x!=next_x || cur_y!=next_y)); }
void Sprite::process_move() { #ifdef DEBUG int debugStepMagn1 = move_step_magn(); err_when(abs(cur_x-next_x)>LOCATE_WIDTH*debugStepMagn1 || abs(cur_y-next_y)>LOCATE_HEIGHT*debugStepMagn1); #endif //---- for some sprite (e.g. elephant), move one step per a few frames ----// if( --remain_frames_per_step > 0 ) return; else remain_frames_per_step = sprite_info->frames_per_step; err_when(cur_x < 0 || cur_y < 0 || cur_x >= MAX_WORLD_X_LOC * LOCATE_WIDTH || cur_y >= MAX_WORLD_Y_LOC * LOCATE_HEIGHT); err_when(cur_x-next_x!=0 && cur_y-next_y!=0 && abs(next_x-cur_x)!=abs(next_y-cur_y)); //----- if the sprite has reach the destintion ----// if( cur_x==go_x && cur_y==go_y) { cur_action = SPRITE_IDLE; int rc = set_next(cur_x, cur_y); //********* BUGHERE err_when( !rc ); #ifdef DEBUG char h, w, blocked=0; short x, y; for(h=0, y=next_y_loc(); h<sprite_info->loc_height&&!blocked; h++, y++) { for(w=0, x=next_x_loc(); w<sprite_info->loc_width&&!blocked; w++, x++) blocked = world.get_loc(x, y)->unit_recno(mobile_type) != sprite_recno; } err_if(blocked) err_here(); #endif cur_frame = 1; return; } err_when(cur_x-next_x!=0 && cur_y-next_y!=0 && abs(next_x-cur_x)!=abs(next_y-cur_y)); //---- set the next tile the sprite will be moving towards ---// static short vector_x_array[] = { 0, 1, 1, 1, 0, -1, -1, -1 }; // default vectors, temporary only static short vector_y_array[] = { -1, -1, 0, 1, 1, 1, 0, -1 }; // short stepX = sprite_info->speed; // short stepY = sprite_info->speed; short stepX, stepY; stepX = stepY = sprite_speed(); if( final_dir & 1 ) // diagonal direction slower { if( stepX >=8 ) { stepY = (stepX -= (unsigned)stepX /4 ); // slightly fast for unsigned division } else if( stepX >= 3 ) { --stepX; --stepY; } } //------------------------------------------// if( next_x != go_x || next_y != go_y ) // if next_x==go_x & next_y==go_y, reach destination already, don't move further. { if( abs(cur_x-next_x) <= stepX && abs(cur_y-next_y) <= stepY ) { int stepMagn = move_step_magn(); if( !set_next(next_x+stepMagn*move_x_pixel_array[final_dir], next_y+stepMagn*move_y_pixel_array[final_dir], -stepMagn) ) return; } } err_when(cur_x-next_x!=0 && cur_y-next_y!=0 && abs(next_x-cur_x)!=abs(next_y-cur_y)); //---- if the is blocked, cur_action is changed to SPRITE_WAIT, return now ----// if( cur_action != SPRITE_MOVE ) return; //-------------- update position -----------------// // // If it gets very close to the destination, fit it // to the destination ingoring the normal vector. // //------------------------------------------------// short vectorX = vector_x_array[final_dir] * stepX; // cur_dir may be changed in the above set_next() call short vectorY = vector_y_array[final_dir] * stepY; if( abs(cur_x-go_x) <= stepX ) cur_x = go_x; else cur_x += vectorX; if( abs(cur_y-go_y) <= stepY ) cur_y = go_y; else cur_y += vectorY; err_when(cur_x-next_x!=0 && cur_y-next_y!=0 && abs(next_x-cur_x)!=abs(next_y-cur_y)); // is a better checking if speed in all direction is equal #ifdef DEBUG int debugStepMagn2 = move_step_magn(); err_when(abs(cur_x-next_x)>LOCATE_WIDTH*debugStepMagn1 || abs(cur_y-next_y)>LOCATE_HEIGHT*debugStepMagn1); #endif //-------- check boundary ---------// err_when(cur_x < 0 || cur_y < 0 || cur_x >= MAX_WORLD_X_LOC * LOCATE_WIDTH || cur_y >= MAX_WORLD_Y_LOC * LOCATE_HEIGHT); //------- update frame id. --------// if( ++cur_frame > cur_sprite_move()->frame_count ) cur_frame = 1; }