Logo Search packages:      
Sourcecode: 7kaa version File versions  Download package

OUNITAC.cpp

/*
 * 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    : OUNITM.CPP
//Description : Object Unit misc. actions excluding attacking and moving functions
//Owner             : Alex

#include <ALL.h>
#include <OWORLD.h>
#include <OFIRM.h>
#include <ONATION.h>
#include <ORACERES.h>
#include <OTOWN.h>
#include <OU_MARI.h>
#include <OF_CAMP.h>
#include <OREMOTE.h>
#include <OF_MONS.h>
#include <OU_GOD.h>
#include <OF_HARB.h>

#ifdef NO_DEBUG_UNIT
#undef err_when
#undef err_here
#undef err_if
#undef err_else
#undef err_now
#define err_when(cond)
#define err_here()
#define err_if(cond)
#define err_else
#define err_now(msg)
#undef DEBUG
#endif

//--------- Begin of function Unit::build_firm ---------//
// Build a firm.
//
// <int> buildXLoc, buildYLoc - the location to build
// <int> firmId               - id. of the firm to build
//
// [char] remoteAction
//
void Unit::build_firm(int buildXLoc, int buildYLoc, int firmId, char remoteAction)
{
      err_when(sprite_info->loc_width>1 || sprite_info->loc_height>1);

      if(!remoteAction && remote.is_enable() )
      {
            // packet structure : <unit recno> <xLoc> <yLoc> <firmId>
            short *shortPtr =(short *)remote.new_send_queue_msg(MSG_UNIT_BUILD_FIRM, 4*sizeof(short) );
            shortPtr[0] = sprite_recno;
            shortPtr[1] = buildXLoc;
            shortPtr[2] = buildYLoc;
            shortPtr[3] = firmId;
            return;
      }

      //----------------------------------------------------------------//
      // return if the unit is dead
      //----------------------------------------------------------------//
      if(hit_points<=0 || action_mode==ACTION_DIE || cur_action==SPRITE_DIE)
            return;

      //----------------------------------------------------------------//
      // location is blocked, cannot build. so move there instead
      //----------------------------------------------------------------//
      if(!world.can_build_firm(buildXLoc, buildYLoc, firmId, sprite_recno))
      {
            //reset_action_para2();
            move_to(buildXLoc, buildYLoc);
            return;
      }

      //----------------------------------------------------------------//
      // different territory
      //----------------------------------------------------------------//

      int harborDir = world.can_build_firm(buildXLoc, buildYLoc, firmId, sprite_recno);
      int goX = buildXLoc, goY = buildYLoc;
      if( firm_res[firmId]->tera_type == 4)
      {
            switch(harborDir)
            {
            case 1:           // north exit
                  goX += 1;
                  goY += 2;
                  break;
            case 2:           // south exit
                  goX += 1;
                  break;
            case 4:           // west exit
                  goX += 2;
                  goY += 1;
                  break;
            case 8:           // east exit
                  goY += 1;
                  break;
            default:
                  err_here();
                  move_to(buildXLoc, buildYLoc);
                  return;
            }
            if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=world.get_loc(goX,goY)->region_id)
            {
                  move_to(buildXLoc, buildYLoc);
                  return;
            }
      }
      else
      {
            if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=world.get_loc(buildXLoc, buildYLoc)->region_id)
            {
                  move_to(buildXLoc, buildYLoc);
                  return;
            }
      }
      
      //----------------------------------------------------------------//
      // action_mode2: checking for equal action or idle action
      //----------------------------------------------------------------//
      if(action_mode2==ACTION_BUILD_FIRM && action_para2==firmId && action_x_loc2==buildXLoc && action_y_loc2==buildYLoc)
      {
            if(cur_action!=SPRITE_IDLE)
                  return;
      }
      else
      {
            //----------------------------------------------------------------//
            // action_mode2: store new order
            //----------------------------------------------------------------//
            action_mode2  = ACTION_BUILD_FIRM;
            action_para2  = firmId;
            action_x_loc2 = buildXLoc;
            action_y_loc2 = buildYLoc;
      }

      //----- order the sprite to stop as soon as possible -----//
      stop();     // new order

      //---------------- define parameters -------------------//
      FirmInfo* firmInfo = firm_res[firmId];
      int firmWidth = firmInfo->loc_width;
      int firmHeight = firmInfo->loc_height;

      if(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, buildXLoc, buildYLoc, firmWidth, firmHeight))
      {
            //----------- not in the firm surrounding ---------//
            set_move_to_surround(buildXLoc, buildYLoc, firmWidth, firmHeight, BUILDING_TYPE_FIRM_BUILD, firmId);
      }
      else
      {
            //------- the unit is in the firm surrounding -------//
            set_cur(next_x, next_y);
            set_dir(move_to_x_loc, move_to_y_loc, buildXLoc+firmWidth/2, buildYLoc+firmHeight/2);
      }

      //----------- set action to build the firm -----------//
      action_mode  = ACTION_BUILD_FIRM;
      action_para  = firmId;
      action_x_loc = buildXLoc;
      action_y_loc = buildYLoc;
}
//----------- End of function Unit::build_firm -----------//


//--------- Begin of function Unit::burn ---------//
//
// Burn a locaiton
//
// <int> burnXLoc, burnYLoc - the location to burn
//
void Unit::burn(int burnXLoc, int burnYLoc, char remoteAction)
{
      err_when(sprite_info->loc_width>1 || sprite_info->loc_height>1);

      if( !remoteAction && remote.is_enable() )
      {
            // packet structure : <unit recno> <xLoc> <yLoc>
            short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNIT_BURN, 3*sizeof(short) );
            shortPtr[0] = sprite_recno;
            shortPtr[1] = burnXLoc;
            shortPtr[2] = burnYLoc;
            return;
      }

      if(move_to_x_loc==burnXLoc && move_to_y_loc==burnYLoc)
            return;     // should not burn the unit itself

      //----------------------------------------------------------------//
      // return if the unit is dead
      //----------------------------------------------------------------//
      if(hit_points<=0 || action_mode==ACTION_DIE || cur_action==SPRITE_DIE)
            return;

      //----------------------------------------------------------------//
      // move there instead if ordering to different territory
      //----------------------------------------------------------------//
      if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=world.get_loc(burnXLoc, burnYLoc)->region_id)
      {
            move_to(burnXLoc, burnYLoc);
            return;
      }

      //----------------------------------------------------------------//
      // action_mode2: checking for equal action or idle action
      //----------------------------------------------------------------//
      if(action_mode2==ACTION_BURN && action_x_loc2==burnXLoc && action_y_loc2==burnYLoc)
      {
            if(cur_action!=SPRITE_IDLE)
                  return;
      }
      else
      {
            //----------------------------------------------------------------//
            // action_mode2: store new order
            //----------------------------------------------------------------//
            action_mode2  = ACTION_BURN;
            action_para2  = 0;
            action_x_loc2 = burnXLoc;
            action_y_loc2 = burnYLoc;
      }

      //----- order the sprite to stop as soon as possible -----//
      stop();     // new order
      
      if(abs(burnXLoc-next_x_loc())>1 || abs(burnYLoc-next_y_loc())>1)
      {
            //--- if the unit is not in the burning surrounding location, move there first ---//
            search(burnXLoc, burnYLoc, 1, SEARCH_MODE_A_UNIT_IN_GROUP);

            if(move_to_x_loc != burnXLoc || move_to_y_loc != burnYLoc)  // cannot reach the destination
            {
                  action_mode  = ACTION_BURN;
                  action_para  = 0;
                  action_x_loc = burnXLoc;
                  action_y_loc = burnYLoc;
                  return;     // just move to the closest location returned by shortest path searching
            }
      }
      else
      {
            if(cur_x==next_x && cur_y==next_y)
                  set_dir(next_x_loc(), next_y_loc(), burnXLoc, burnYLoc);

            err_when((cur_x!=next_x || cur_y!=next_y) && (check_unit_dir1=get_dir(cur_x,cur_y,next_x,next_y))!=final_dir);
            err_when(result_node_array || result_node_count || result_path_dist);
      }

      //--------------------------------------------------------//
      // edit the result path such that the unit can reach the
      // burning location surrounding
      //--------------------------------------------------------//
      if(result_node_array && result_node_count)
      {
            //--------------------------------------------------------//
            // there should be at least two nodes, and should take at
            // least two steps to the destination
            //--------------------------------------------------------//
            err_when(move_to_x_loc!=burnXLoc || move_to_y_loc!=burnYLoc);
            err_when(result_node_count<2);

            ResultNode* lastNode1 = result_node_array+result_node_count-1;    // the last node
            ResultNode* lastNode2 = result_node_array+result_node_count-2;    // the node before the last node

            int vX = lastNode1->node_x-lastNode2->node_x;   // get the vectors direction
            int vY = lastNode1->node_y-lastNode2->node_y;
            int vDirX = (vX) ? vX/abs(vX) : 0;
            int vDirY = (vY) ? vY/abs(vY) : 0;

            if(result_node_count>2) // go_? should not be the burning location 
            {
                  err_when(go_x>>ZOOM_X_SHIFT_COUNT==burnXLoc && go_y>>ZOOM_Y_SHIFT_COUNT==burnYLoc);
                  err_when(vX!=0 && vY!=0 && abs(vX)!=abs(vY));

                  if(abs(vX)>1 || abs(vY)>1)
                  {
                        lastNode1->node_x -= vDirX;
                        lastNode1->node_y -= vDirY;

                        move_to_x_loc = lastNode1->node_x;
                        move_to_y_loc = lastNode1->node_y;
                  }
                  else  // move only one step
                  {
                        result_node_count--;    // remove a node
                        move_to_x_loc = lastNode2->node_x;
                        move_to_y_loc = lastNode2->node_y;
                  }
            }
            else  // go_? may be the burning location
            {
                  err_when(result_node_count!=2);

                  lastNode1->node_x -= vDirX;
                  lastNode1->node_y -= vDirY;

                  if(go_x>>ZOOM_X_SHIFT_COUNT==burnXLoc && go_y>>ZOOM_Y_SHIFT_COUNT==burnYLoc)  // go_? is the burning location
                  {
                        //--- edit parameters such that only moving to the nearby location to do the action ---//
                        err_when(abs(vX)<=1 && abs(vY)<=1); // this case should be handled before
                        
                        go_x = lastNode1->node_x * ZOOM_LOC_WIDTH;
                        go_y = lastNode1->node_y * ZOOM_LOC_HEIGHT;
                  }
                  //else the unit is still doing sthg else, no action here

                  move_to_x_loc = lastNode1->node_x;
                  move_to_y_loc = lastNode1->node_y;
            }

            //--------------------------------------------------------------//
            // reduce the result_path_dist by 1
            //--------------------------------------------------------------//
            result_path_dist--;
            
            #ifdef DEBUG
                  ResultNode *preNode = result_node_array;
                  ResultNode *curNode = result_node_array+1;
                  int debugCount=1;
                  int debugDist = 0;
                  int xDist = abs(next_x_loc()-preNode->node_x);
                  int yDist = abs(next_y_loc()-preNode->node_y);
                  debugDist -= (xDist) ? xDist : yDist;

                  while(debugCount++ < result_node_count)
                  {
                        err_when(debugCount>1000);
                        xDist = abs(preNode->node_x - curNode->node_x);
                        yDist = abs(preNode->node_y - curNode->node_y);
                        debugDist += (xDist) ? xDist : yDist;
                        preNode++;
                        curNode++;
                  }

                  err_when(result_path_dist!=debugDist);
            #endif

            err_when((cur_x!=next_x || cur_y!=next_y) &&    // is not blocked
                              (check_unit_dir1=get_dir(cur_x, cur_y, next_x, next_y))!=(check_unit_dir2=get_dir(cur_x, cur_y, go_x, go_y)));
      }

      err_when(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, burnXLoc, burnYLoc, 1, 1));

      //-- set action if the burning location can be reached, otherwise just move nearby --//
      action_mode  = ACTION_BURN;
      action_para  = 0;
      action_x_loc = burnXLoc;
      action_y_loc = burnYLoc;
}
//----------- End of function Unit::burn -----------//


//--------- Begin of function Unit::settle ---------//
//
// settle to a town
//
// <int> settleXLoc, settleYLoc - the location to settle
// [short] curSettleUnitNum - the number to call this function by
//                                                          a group of unit. (default: 1)
//
void Unit::settle(int settleXLoc, int settleYLoc, short curSettleUnitNum)
{
      err_when(sprite_info->loc_width>1 || sprite_info->loc_height>1);

      //----------------------------------------------------------------//
      // return if the unit is dead
      //----------------------------------------------------------------//
      if(hit_points<=0 || action_mode==ACTION_DIE || cur_action==SPRITE_DIE)
            return;

      //---------- no settle for non-human -----------//
      if(unit_res[unit_id]->unit_class!=UNIT_CLASS_HUMAN)
            return;

      //----------------------------------------------------------------//
      // move there if cannot settle
      //----------------------------------------------------------------//
      if(!world.can_build_town(settleXLoc, settleYLoc, sprite_recno))
      {
            Location *locPtr = world.get_loc(settleXLoc, settleYLoc);
            if(locPtr->is_town() && town_array[locPtr->town_recno()]->nation_recno==nation_recno)
                  assign(settleXLoc, settleYLoc);
            else
                  move_to(settleXLoc, settleYLoc);
            return;
      }

      //----------------------------------------------------------------//
      // move there if location is in different territory
      //----------------------------------------------------------------//
      if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=world.get_loc(settleXLoc, settleYLoc)->region_id)
      {
            move_to(settleXLoc, settleYLoc);
            return;
      }

      //----------------------------------------------------------------//
      // action_mode2: checking for equal action or idle action
      //----------------------------------------------------------------//
      if(action_mode2==ACTION_SETTLE && action_x_loc2==settleXLoc && action_y_loc2==settleYLoc)
      {
            if(cur_action!=SPRITE_IDLE)
                  return;
      }
      else
      {
            //----------------------------------------------------------------//
            // action_mode2: store new order
            //----------------------------------------------------------------//
            action_mode2  = ACTION_SETTLE;
            action_para2  = 0;
            action_x_loc2 = settleXLoc;
            action_y_loc2 = settleYLoc;
      }

      //----- order the sprite to stop as soon as possible -----//
      stop();     // new order
      
      if(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, settleXLoc, settleYLoc,
            STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT))
      {
            //------------ not in the town surrounding ------------//
            set_move_to_surround(settleXLoc, settleYLoc, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, BUILDING_TYPE_SETTLE, 0, 0, curSettleUnitNum);
      }
      else
      {
            //------- the unit is within the settle location -------//
            set_cur(next_x, next_y);
            set_dir(move_to_x_loc, move_to_y_loc, settleXLoc+STD_TOWN_LOC_WIDTH/2, settleYLoc+STD_TOWN_LOC_HEIGHT/2);
      }

      //----------- set action to settle -----------//
      action_mode  = ACTION_SETTLE;
      action_para  = 0;
      action_x_loc = settleXLoc;
      action_y_loc = settleYLoc;
}
//----------- End of function Unit::settle -----------//


//--------- Begin of function Unit::assign ---------//
//
// Assign an unit to :
//
// - a firm as an overseer, as a worker
// - a town as a citizen
// - a vehicle
//
// <int> buildXLoc, buildYLoc - the location to build
//
void Unit::assign(int assignXLoc, int assignYLoc, short curAssignUnitNum)
{
      err_when(sprite_info->loc_width>1 || sprite_info->loc_height>1);

      //----------------------------------------------------------------//
      // return if the unit is dead
      //----------------------------------------------------------------//
      if(hit_points<=0 || action_mode==ACTION_DIE || cur_action==SPRITE_DIE)
            return;

      //----------- cannot assign for caravan -----------//
      if(unit_id==UNIT_CARAVAN)
            return;

      //----------------------------------------------------------------//
      // move there if the destination in other territory
      //----------------------------------------------------------------//
      Location    *locPtr = world.get_loc(assignXLoc, assignYLoc);
      UCHAR unitRegionId = world.get_loc(next_x_loc(), next_y_loc())->region_id;
      if(locPtr->is_firm())
      {
            Firm *firmPtr = firm_array[locPtr->firm_recno()];
            int quit = 0;
            
            if(firmPtr->firm_id==FIRM_HARBOR)
            {
                  FirmHarbor *harborPtr = (FirmHarbor*) firmPtr;
                  switch(unit_res[unit_id]->unit_class)
                  {
                        case UNIT_CLASS_HUMAN:
                              if(unitRegionId != harborPtr->land_region_id)
                                    quit = 1;
                              break;

                        case UNIT_CLASS_SHIP:
                              if(unitRegionId != harborPtr->sea_region_id)
                                    quit = 1;
                              break;

                        default: err_here();
                                          break;
                  }
            }
            else if(unitRegionId!=locPtr->region_id)
                  quit = 1;

            if(quit)
            {
                  move_to_firm_surround(assignXLoc, assignYLoc, sprite_info->loc_width, sprite_info->loc_height, firmPtr->firm_id);
                  return;
            }
      }
      else if(unitRegionId!=locPtr->region_id)
      {
            if(locPtr->is_town())
                  move_to_town_surround(assignXLoc, assignYLoc, sprite_info->loc_width, sprite_info->loc_height);
            /*else if(locPtr->has_unit(UNIT_LAND))
            {
                  Unit *unitPtr = unit_array[locPtr->unit_recno(UNIT_LAND)];
                  move_to_unit_surround(assignXLoc, assignYLoc, sprite_info->loc_width, sprite_info->loc_height, unitPtr->sprite_recno);
            }*/
            
            return;
      }

      //---------------- define parameters --------------------//
      int         width, height;
      int         buildingType=0; // 1 for Firm, 2 for TownZone
      short       recno;
      int         firmNeedUnit=1;
      
      if(locPtr->is_firm())
      {
            //-------------------------------------------------------//
            // the location is firm
            //-------------------------------------------------------//
            recno = locPtr->firm_recno();

            //----------------------------------------------------------------//
            // action_mode2: checking for equal action or idle action
            //----------------------------------------------------------------//
            if(action_mode2==ACTION_ASSIGN_TO_FIRM && action_para2==recno && action_x_loc2==assignXLoc && action_y_loc2==assignYLoc)
            {
                  if(cur_action!=SPRITE_IDLE)
                        return;
            }
            else
            {
                  //----------------------------------------------------------------//
                  // action_mode2: store new order
                  //----------------------------------------------------------------//
                  action_mode2  = ACTION_ASSIGN_TO_FIRM;
                  action_para2  = recno;
                  action_x_loc2 = assignXLoc;
                  action_y_loc2 = assignYLoc;
            }
            
            Firm        *firmPtr = firm_array[recno];
            FirmInfo *firmInfo = firm_res[firmPtr->firm_id];

            if(!firm_can_assign(recno))
            {
                  //firmNeedUnit = 0; // move to the surrounding of the firm
                  move_to_firm_surround(assignXLoc, assignYLoc, sprite_info->loc_width, sprite_info->loc_height, firmPtr->firm_id);
                  return;
            }

            width  = firmInfo->loc_width;
            height = firmInfo->loc_height;
            buildingType = BUILDING_TYPE_FIRM_MOVE_TO;
      }
      else if(locPtr->is_town())    // there is town
      {
            if(unit_res[unit_id]->unit_class != UNIT_CLASS_HUMAN)
                  return;

            //-------------------------------------------------------//
            // the location is town
            //-------------------------------------------------------//
            recno = locPtr->town_recno();
            
            //----------------------------------------------------------------//
            // action_mode2: checking for equal action or idle action
            //----------------------------------------------------------------//
            if(action_mode2==ACTION_ASSIGN_TO_TOWN && action_para2==recno && action_x_loc2==assignXLoc && action_y_loc2==assignYLoc)
            {
                  if(cur_action!=SPRITE_IDLE)
                        return;
            }
            else
            {
                  //----------------------------------------------------------------//
                  // action_mode2: store new order
                  //----------------------------------------------------------------//
                  action_mode2  = ACTION_ASSIGN_TO_TOWN;
                  action_para2  = recno;
                  action_x_loc2 = assignXLoc;
                  action_y_loc2 = assignYLoc;
            }

            Town *targetTown = town_array[recno];
            if(town_array[recno]->nation_recno != nation_recno)
            {
                  move_to_town_surround(assignXLoc, assignYLoc, sprite_info->loc_width, sprite_info->loc_height);
                  return;
            }

            width = targetTown->loc_width();
            height = targetTown->loc_height();
            buildingType = BUILDING_TYPE_TOWN_MOVE_TO;
      }
      /*else if(locPtr->has_unit(UNIT_LAND)) // there is vehicle
      {
            //-------------------------------------------------------//
            // the location is vehicle
            //-------------------------------------------------------//
            Unit* vehicleUnit = unit_array[locPtr->unit_recno(UNIT_LAND)];
            if( vehicleUnit->unit_id!=unit_res[unit_id]->vehicle_id )
                  return;

            recno = vehicleUnit->sprite_recno;

            //----------------------------------------------------------------//
            // action_mode2: checking for equal action or idle action
            //----------------------------------------------------------------//
            if(action_mode2==ACTION_ASSIGN_TO_VEHICLE && action_para2==recno && action_x_loc2==assignXLoc && action_y_loc2==assignYLoc)
            {
                  if(cur_action!=SPRITE_IDLE)
                        return;
            }
            else
            {
                  //----------------------------------------------------------------//
                  // action_mode2: store new order
                  //----------------------------------------------------------------//
                  action_mode2  = ACTION_ASSIGN_TO_VEHICLE;
                  action_para2  = recno;
                  action_x_loc2 = assignXLoc;
                  action_y_loc2 = assignYLoc;
            }

            SpriteInfo* spriteInfo = vehicleUnit->sprite_info;
            width  = spriteInfo->loc_width;
            height = spriteInfo->loc_height;
            buildingType = BUILDING_TYPE_VEHICLE;
      }*/
      else
      {
            stop2(KEEP_DEFENSE_MODE);
            return;
      }

      //-----------------------------------------------------------------//
      // order the sprite to stop as soon as possible (new order)
      //-----------------------------------------------------------------//
      stop();
      set_move_to_surround(assignXLoc, assignYLoc, width, height, buildingType, 0, 0, curAssignUnitNum);

      //-----------------------------------------------------------------//
      // able to reach building surrounding, set action parameters
      //-----------------------------------------------------------------//
      action_para  = recno;
      action_x_loc = assignXLoc;
      action_y_loc = assignYLoc;

      switch(buildingType)
      {
            case BUILDING_TYPE_FIRM_MOVE_TO:
                        action_mode = ACTION_ASSIGN_TO_FIRM;
                        break;

            case BUILDING_TYPE_TOWN_MOVE_TO:
                        action_mode = ACTION_ASSIGN_TO_TOWN;
                        break;

            case BUILDING_TYPE_VEHICLE:
                        action_mode = ACTION_ASSIGN_TO_VEHICLE;
                        break;
      }

      //##### begin trevor 9/10 #######//

//    force_move_flag = 1;          // don't stop and fight back on an assign mission

      //##### end trevor 9/10 #######//

      //-----------------------------------------------------------------//
      // edit parameters for those firms don't need unit
      //-----------------------------------------------------------------//
      /*if(!firmNeedUnit)
      {
            action_mode2 = action_mode = ACTION_MOVE;
            action_para2 = action_para = 0;
            action_x_loc2 = action_x_loc = move_to_x_loc;
            action_y_loc2 = action_y_loc = move_to_y_loc;
      }*/
}
//----------- End of function Unit::assign -----------//


//--------- Begin of function Unit::firm_can_assign ---------//
// return 1 for true, i.e. unit can assign to the firm
// return 2 for assigning leader
// return 3 for repair
// return 4 for spy assigning to inn
// return 5 for capture (not used)
// return 0 otherwise
//
int Unit::firm_can_assign(short firmRecno)
{
      Firm *firmPtr = firm_array[firmRecno];
      FirmInfo *firmInfo = firm_res[firmPtr->firm_id];

      switch( unit_res[unit_id]->unit_class )
      {
      case UNIT_CLASS_HUMAN:
            if( nation_recno == firmPtr->nation_recno )
            {
                  if( skill.skill_id == SKILL_CONSTRUCTION && firmPtr->firm_id != FIRM_MONSTER)
                  {
                        return 3;
                  }

                  // ###### begin Gilbert 22/10 #######//
                  //----------------------------------------//
                  // If this is a spy, then he can only be
                  // assigned to an enemy firm when there is
                  // space for the unit.
                  //----------------------------------------//

                  //if( spy_recno && true_nation_recno() != firmPtr->nation_recno )
                  //{
                  //    if( rank_id == RANK_GENERAL )
                  //    {
                  //          if( firmPtr->overseer_recno )
                  //                return 0;
                  //    }
                  //    else
                  //    {
                  //          if( firmPtr->worker_count == MAX_WORKER )
                  //                return 0;
                  //    }
                  //}
                  //--------------------------------------//
                  // ###### end Gilbert 22/10 #######//

                  switch( firmPtr->firm_id )
                  {
                  case FIRM_CAMP:
                        return rank_id == RANK_SOLDIER ? 1 : 2;

                  case FIRM_BASE:
                        if(race_id == firmPtr->race_id)
                        {
                              if( !skill.skill_id || skill.skill_id==SKILL_PRAYING) // non-skilled worker
                                    return 1;
                              if( rank_id != RANK_SOLDIER )
                                    return 2;
                        }
                        break;

                  //case FIRM_INN:
                        // shealthed soldier spy can assign to inn
                  //    return rank_id == RANK_SOLDIER && nation_recno != true_nation_recno() ? 4 : 0;

                  default:
                        return rank_id == RANK_SOLDIER && firmInfo->need_unit() ? 1 : 0;
                  }
            }
            break;

      case UNIT_CLASS_WEAPON:
            if(firmPtr->firm_id == FIRM_CAMP && nation_recno == firmPtr->nation_recno)
                  return 1;
            break;

      case UNIT_CLASS_SHIP:
            if(firmPtr->firm_id == FIRM_HARBOR && nation_recno == firmPtr->nation_recno)
                  return 1;
            break;

      case UNIT_CLASS_MONSTER:
            if(firmPtr->firm_id == FIRM_MONSTER && mobile_type == UNIT_LAND)
            { 
                  // BUGHERE : suppose only land monster can assign
                  return rank_id == RANK_SOLDIER ? 1 : 2;
            }
            break;

      case UNIT_CLASS_GOD:
      case UNIT_CLASS_CARAVAN:
            break;
      default:
            err_here();       // undefined unit class
      }

      return 0;
}
//----------- End of function Unit::firm_can_assign -----------//


//--------- Begin of function Unit::set_move_to_surround ---------//
// Mode 1:
//          return 1 if the unit can reach the surrounding of the firm
//          return 0 otherwise.
//
// Mode 2:
//          In this mode, the unit calling this function is ordered to move to
// location a little bit away from the surrounding of the object.
//
// return 1 if the unit can move to there
// return 0 otherwise
//
// <int> buildXLoc                        - upper left x location of the building (firm/town)
// <int> buildYLoc                        - upper left y location of the building
// <int> width                                  - width of the building
// <int> height                           - height of the building
// <int> buildingType               - used to determine how searching is processed
// [int] miscNo                           - firm_id of firm if buildingType==BUILDING_TYPE_FIRM_BUILD
//                                                          - 0 for group search  (for wall, firm)
//                                                          - 1 for a unit search
// [short] readyDist                      - the extra distance the unit stands from the building
//                                                                (default 0, i.e. the surrounding of the building)
// [short] curProcessUnitNum  - the cur unit no. in a group calling this function
//                                                                (default 1)
//
//============================================================================//
// Note:    This funcion should not change any action parameters
//============================================================================//
//
int Unit::set_move_to_surround(int buildXLoc, int buildYLoc, int width, int height, int buildingType, int miscNo, int readyDist, short curProcessUnitNum)
{
      err_when(hit_points<=0 || action_mode==ACTION_DIE || cur_action==SPRITE_DIE);

      //--------------------------------------------------------------//
      // calculate the distance from the object
      //--------------------------------------------------------------//
      int found=0, foundAgain=0;
      int distance = cal_distance(buildXLoc, buildYLoc, width, height); // 0 for inside, 1 for surrounding, >1 for the rest
      
      //--------------------------------------------------------------//
      // inside the building
      //--------------------------------------------------------------//
      if(!distance)
      {
            reset_path();
            if(cur_x==next_x && cur_y==next_y)
                  set_idle();

            return 1;
      }

      if(distance>1)
      {
            //--------------------------------------------------------------//
            // the searching is divided into 2 parts.
            //
            // part 1 using the firm_type and firm_id to find a shortest path.
            // 
            // part 2
            //    if the width and height is the actual width and height of the
            // firm, the unit move to the surrounding of the firm.
            //
            // if the width and height > the actual width and height of the
            // firm, the unit move to a location far away from the surrounding
            // of the firm.
            //--------------------------------------------------------------//

            //====================================================================//
            // part 1
            //====================================================================//
            
            Location    *locPtr = world.get_loc( buildXLoc, buildYLoc );
            Firm        *firmPtr = NULL;
            Town        *targetTown = NULL;
            int         searchResult;

            switch(buildingType)
            {
                  case BUILDING_TYPE_FIRM_MOVE_TO:    // (assign) firm is on the location
                                    firmPtr = firm_array[locPtr->firm_recno()];
                                    searchResult = search(buildXLoc, buildYLoc, 1, SEARCH_MODE_TO_FIRM, firmPtr->firm_id, curProcessUnitNum);
                                    break;

                  case BUILDING_TYPE_FIRM_BUILD:      // (build firm) no firm on the location
                                    err_when(sprite_info->loc_width>1);
                                    searchResult = search(buildXLoc, buildYLoc, 1, SEARCH_MODE_TO_FIRM, miscNo);
                                    break;

                  case BUILDING_TYPE_TOWN_MOVE_TO:    // (assign) town is on the location
                                    targetTown = town_array[locPtr->town_recno()];
                                    searchResult = search(buildXLoc, buildYLoc, 1, SEARCH_MODE_TO_TOWN, targetTown->town_recno, curProcessUnitNum);
                                    break;

                  case BUILDING_TYPE_SETTLE:                // (settle, first unit) no town on the location
                                    //---------------------------------------------------------------------//
                                    // the record number sent to the searching algorithm is used to determine
                                    // the width and the height of the building.  However, the standard
                                    // dimension for settling is used and the building built is a type of
                                    // town.  Thus, passing -1 as the recno. to show that "settle" is
                                    // processed
                                    //---------------------------------------------------------------------//
                                    err_when(sprite_info->loc_width>1);
                                    searchResult = search(buildXLoc, buildYLoc, 1, SEARCH_MODE_TO_TOWN, -1, curProcessUnitNum);
                                    break;

                  case BUILDING_TYPE_VEHICLE:
                                    err_when(sprite_info->loc_width>1);
                                    searchResult = search(buildXLoc, buildYLoc, 1, SEARCH_MODE_TO_VEHICLE, (short)world.get_loc(buildXLoc, buildYLoc)->cargo_recno);
                                    break;

                  case BUILDING_TYPE_WALL:                  // wall is on the location
                                    err_when(miscNo!=0 && miscNo!=1);
                                    searchResult = search(buildXLoc, buildYLoc, 1, miscNo?SEARCH_MODE_TO_WALL_FOR_UNIT:SEARCH_MODE_TO_WALL_FOR_GROUP);
                                    break;

                  default:    err_here();
                                    break;
            }

            if(!searchResult)
                  return 0; // incomplete searching
            
            //====================================================================//
            // part 2
            //====================================================================//
            if(result_node_array && result_node_count)
                  return edit_path_to_surround(buildXLoc, buildYLoc, buildXLoc+width-1, buildYLoc+height-1, readyDist);
            else
                  return 0;
      }
      else  // in the surrounding, no need to move
      {
            reset_path();
            err_when(distance!=1);

            if(cur_x==next_x && cur_y==next_y)
            {
                  move_to_x_loc = next_x_loc();
                  move_to_y_loc = next_y_loc();
                  go_x = cur_x;
                  go_y = cur_y;
                  set_idle();
                  set_dir(move_to_x_loc, move_to_y_loc, buildXLoc + width/2, buildYLoc + height/2);

                  err_when(result_node_array!=NULL);
            }

            err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
            err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
            return 1;
      }
}
//----------- End of function Unit::set_move_to_surround -----------//


//--------- Begin of function Unit::edit_path_to_surround ---------//
// edit the path such that the unit only move to the surrounding of the firm
//
// <int> objectXLoc1, objectYLoc1 - object top_left position
// <int> objectXLoc2, objectYLoc2 - object bottom_right position
// <short> readyDist                      - the extra distance the unit stands from the building
//                                                                (default 0, i.e. the surrounding of the building)
//
// return 1 if able to reach object surrounding
// return 0 otherwise
//
int Unit::edit_path_to_surround(int objectXLoc1, int objectYLoc1, int objectXLoc2, int objectYLoc2, int readyDist)
{
      err_when(!result_node_array || !result_node_count);
      if(result_node_count<2)
            return 0;

      //----------------------------------------------------------------------------//
      // At this moment, the unit generally has a path to the location inside the object,
      // walk through it and extract a path to the surrounding of the object.
      //----------------------------------------------------------------------------//

      //------- calculate the surrounding top-left and bottom-right points ------//
      int moveScale = move_step_magn();
      int xLoc1 = objectXLoc1 - readyDist - 1;
      int yLoc1 = objectYLoc1 - readyDist - 1;
      int xLoc2 = objectXLoc2 + readyDist + 1;
      int yLoc2 = objectYLoc2 + readyDist + 1;

      //------------------- boundary checking -------------------//
      if(xLoc1<0) xLoc1 = 0;
      if(yLoc1<0) yLoc1 = 0;
      if(xLoc2>=MAX_WORLD_X_LOC) yLoc1 = MAX_WORLD_X_LOC - moveScale;
      if(yLoc2>=MAX_WORLD_Y_LOC) xLoc2 = MAX_WORLD_Y_LOC - moveScale;

      //--------------- adjust for air and sea units -----------------//
      if(mobile_type!=UNIT_LAND)
      {
            //------ assume even x, y coordinate is used for UNIT_SEA and UNIT_AIR -------//
            if(xLoc1%2) xLoc1--;
            if(yLoc1%2) yLoc1--;
            if(xLoc2%2) xLoc2++;
            if(yLoc2%2) yLoc2++;

            if(xLoc2>MAX_WORLD_X_LOC-moveScale)
                  xLoc2 = MAX_WORLD_X_LOC-moveScale;
            if(yLoc2>MAX_WORLD_Y_LOC-moveScale)
                  yLoc2 = MAX_WORLD_Y_LOC-moveScale;

            err_when(xLoc1<0 || yLoc1<0);
            err_when(xLoc2>MAX_WORLD_X_LOC-moveScale || yLoc2>MAX_WORLD_Y_LOC-moveScale);
      }

      int checkXLoc = next_x_loc();
      int checkYLoc = next_y_loc();
      ResultNode *editNode1 = result_node_array;            // alias the unit's result_node_array
      ResultNode *editNode2 = result_node_array + 1;  // ditto


      int hasMoveStep = 0;
      if(checkXLoc!=editNode1->node_x || checkYLoc!=editNode1->node_y)
      {
            err_when(abs(checkXLoc-editNode1->node_x)>moveScale || abs(checkYLoc-editNode1->node_y)>moveScale);
            hasMoveStep += moveScale;
            checkXLoc = editNode1->node_x;
            checkYLoc = editNode1->node_y;
      }
      
      int i, j;
      int pathDist=0, found=0; // pathDist - counts the disitance of the generated path, found - whether a path to the surrounding is found
      int vecX, vecY, xMagn, yMagn, magn;

      #ifdef DEBUG
            int debugLoop1 = 0;
            int debugLoop2 = 0;
      #endif
      
      //------- find the first node that is on the surrounding of the object -------//
      for(i=1; i<result_node_count; ++i, editNode1++, editNode2++)
      {
            #ifdef DEBUG
            err_when(++debugLoop1>10000);
            #endif

            //------------ calculate parameters for checking ------------//
            vecX = editNode2->node_x - editNode1->node_x;
            vecY = editNode2->node_y - editNode1->node_y;
            err_when(vecX==0 && vecY==0);

            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);

            #ifdef DEBUG
                  debugLoop2 = 0;
            #endif
            //------------- check each location bewteen editNode1 and editNode2 -------------//
            for(j=0; j<magn; j+=moveScale)
            {
                  #ifdef DEBUG
                  err_when(++debugLoop2>10000);
                  #endif

                  checkXLoc += vecX;
                  checkYLoc += vecY;

                  if(checkXLoc>=xLoc1 && checkXLoc<=xLoc2 && checkYLoc>=yLoc1 && checkYLoc<=yLoc2)
                  {
                        found++;
                        break;
                  }
            }

            //-------------------------------------------------------------------------------//
            // a path is found, then set unit's parameters for its movement
            //-------------------------------------------------------------------------------//
            if(found)
            {
                  editNode2->node_x = checkXLoc;
                  editNode2->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 = checkXLoc;
                  move_to_y_loc = checkYLoc;
                  break;
            }
            else
                  pathDist += magn;
      }

      return found;
}
//----------- End of function Unit::edit_path_to_surround -----------//


//--------- Begin of function Unit::is_in_surrounding ---------//
// Test whether the location (checkXLoc, checkYLoc) is in the surrounding of an object
//
// <int> checkXLoc, checkYLoc       - location to check
// <int> width                                        - the width of the caller
// <int> ObjectXLoc, objectYLoc     - object location
// <int> objectWidth                            - object width
// <int>    objectHeight                        - object height
//
// Note: assume the width and the height of the caller is equal
// return 1 if in object surrounding
// return 0 otherwise
//
int Unit::is_in_surrounding(int checkXLoc, int checkYLoc, int width, int objectXLoc, int objectYLoc,
                                                       int objectWidth, int objectHeight)
{
      switch(move_step_magn())
      {
            case 1:
                  if(checkXLoc>=objectXLoc-width && checkXLoc<=objectXLoc+objectWidth &&
                        checkYLoc>=objectYLoc-width && checkYLoc<=objectYLoc+objectHeight)
                        return 1;
                  break;

            case 2:
                  if(checkXLoc>=objectXLoc-width-1 && checkXLoc<=objectXLoc+objectWidth+1 &&
                        checkYLoc>=objectYLoc-width-1 && checkYLoc<=objectYLoc+objectHeight+1)
                        return 1;
                  break;

            default: err_here();
                              break;
      }

      return 0;
}
//----------- End of function Unit::is_in_surrounding -----------//


//--------- Begin of function Unit::process_build_firm ---------//
// process action of building firms
//
void Unit::process_build_firm()
{
      err_when(sprite_info->loc_width>1 || sprite_info->loc_height>1);
      err_when(action_x_loc<0 || action_x_loc>=MAX_WORLD_X_LOC || action_y_loc<0 || action_y_loc>=MAX_WORLD_Y_LOC);

      err_when(action_x_loc<0 || action_x_loc>=MAX_WORLD_X_LOC);
      err_when(action_y_loc<0 || action_y_loc>=MAX_WORLD_Y_LOC);

      if( cur_action == SPRITE_IDLE )  // the unit is at the build location now
      {
            // **BUGHERE, the unit shouldn't be hidden when building structures
            // otherwise, it's cargo_recno will be conflict with the structure's
            // cargo_recno

            int succeedFlag=0;

            if( cur_x_loc()==move_to_x_loc && cur_y_loc()==move_to_y_loc )
            {
                  FirmInfo *firmInfo = firm_res[action_para];
                  int width = firmInfo->loc_width;
                  int height = firmInfo->loc_height;

                  //---------------------------------------------------------//
                  // check whether the unit in the building surrounding
                  //---------------------------------------------------------//
                  if(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, action_x_loc, action_y_loc, width, height))
                  {
                        //---------- not in the building surrounding ---------//
                        return;
                  }

                  //---------------------------------------------------------//
                  // the unit in the firm surrounding
                  //---------------------------------------------------------//
                  Nation* nationPtr;

                  if(nation_recno)
                  {
                        nationPtr = nation_array[nation_recno];

                        if(nationPtr->cash < firmInfo->setup_cost)
                              return; // out of cash
                  }
                  else
                        nationPtr = NULL;

                  //---------------------------------------------------------//
                  // check whether the firm can be built in the specified location
                  //---------------------------------------------------------//
                  if( world.can_build_firm(action_x_loc, action_y_loc, action_para, sprite_recno) &&
                         firm_res[action_para]->can_build(sprite_recno) )
                  {
                        int aiUnit              = ai_unit;
                        int actionXLoc          = action_x_loc;
                        int actionYLoc          = action_y_loc;
                        short unitRecno   = sprite_recno;

                        //---------------------------------------------------------------------------//
                        // if unit inside the firm location, deinit the unit to free the space for
                        // building firm
                        //---------------------------------------------------------------------------//
                        if(move_to_x_loc>=action_x_loc && move_to_x_loc<action_x_loc+width &&
                              move_to_y_loc>=action_y_loc && move_to_y_loc<action_y_loc+height)
                              deinit_sprite(0); // 0-if the unit is currently selected, deactivate it.

                        if( firm_array.build_firm(action_x_loc, action_y_loc, nation_recno,
                                                                        action_para, sprite_info->sprite_code, sprite_recno) ) // action_para = firm id.
                        {
                              //--------- able to the firm --------//

                              reset_action_para2();
                              succeedFlag = 1;
                        }
                  }
            }

            //----- call action finished/failure -----//

            if( ai_action_id && nation_recno )
            {
                  if( succeedFlag )
                        nation_array[nation_recno]->action_finished(ai_action_id, sprite_recno);
                  else
                        nation_array[nation_recno]->action_failure(ai_action_id, sprite_recno);
            }

            //---------------------------------------//

            reset_action_para();
      }
}
//----------- End of function Unit::process_build_firm -----------//


//--------- Begin of function Unit::process_assign ---------//
// process action of assigning
//
void Unit::process_assign()
{
      err_when(sprite_info->loc_width>1 || sprite_info->loc_height>1);

      if(cur_action!=SPRITE_IDLE)
      {
            //------------------------------------------------------------------//
            // change units' action if the firm/town/unit assign to has been deleted
            // or has changed its nation
            //------------------------------------------------------------------//
            switch(action_mode2)
            {
                  case ACTION_ASSIGN_TO_FIRM:
                  case ACTION_AUTO_DEFENSE_BACK_CAMP:
                  case ACTION_MONSTER_DEFEND_BACK_FIRM:
                              if(firm_array.is_deleted(action_para))
                              {
                                    stop2();
                                    return;
                              }
                              else
                              {
                                    Firm *firmPtr = firm_array[action_para];
                  //###### begin trevor 21/6 #######//
                                    if(firmPtr->nation_recno!=nation_recno && !firmPtr->can_assign_capture())
                                    {
                                          stop2();
                                          return;
                                    }
                                    //###### end trevor 21/6 #######//
                              }
                              break;

                  case ACTION_ASSIGN_TO_TOWN:
                  case ACTION_DEFEND_TOWN_BACK_TOWN:
                              if(town_array.is_deleted(action_para))
                              {
                                    stop2();
                                    return;
                              }
                              else if(town_array[action_para]->nation_recno!=nation_recno)
                              {
                                    stop2();
                                    return;
                              }
                              break;

                  case ACTION_ASSIGN_TO_VEHICLE:
                              if(unit_array.is_deleted(action_para))
                              {
                                    stop2();
                                    return;
                              }
                              else if(unit_array[action_para]->nation_recno!=nation_recno)
                              {
                                    stop2();
                                    return;
                              }
                              break;

                  default:    err_here();
                                    break;
            }
      }
      else //--------------- unit is idle -----------------//
      {
            if( cur_x_loc()==move_to_x_loc && cur_y_loc()==move_to_y_loc )
            {
                  //----- first check if there is firm in the given location ------//
                  Location* locPtr = world.get_loc( action_x_loc, action_y_loc );

                  if( locPtr->is_firm() && locPtr->firm_recno() == action_para )
                  {
                        //---------------- a firm on the location -----------------//
                        Firm* firmPtr = firm_array[action_para];
                        FirmInfo *firmInfo = firm_res[firmPtr->firm_id];

                        //---------- resume action if the unit has not reached the firm surrounding ----------//
                        if(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, action_x_loc, action_y_loc,
                              firmInfo->loc_width, firmInfo->loc_height))
                        {
                              //------------ not in the surrounding -----------//
                              if(action_mode!=action_mode2) // for defense mode
                                    set_move_to_surround(action_x_loc, action_y_loc, firmInfo->loc_width, firmInfo->loc_height, BUILDING_TYPE_FIRM_MOVE_TO);
                              return;
                        }

                        //------------ in the firm surrounding ------------//
                        if(!firmPtr->under_construction)
                        {
                              //-------------------------------------------------------//
                              // if in defense mode, update parameters in military camp
                              //-------------------------------------------------------//
                              if(action_mode2==ACTION_AUTO_DEFENSE_BACK_CAMP)
                              {
                                    FirmCamp *campPtr = firmPtr->cast_to_FirmCamp();
                                    campPtr->update_defense_unit(sprite_recno);
                              }
                              
                              //---------------------------------------------------------------//
                              // remainder useful parameters to do reaction to Nation.
                              // These parameters will be destroyed after calling assign_unit()
                              //---------------------------------------------------------------//
                              int   nationRecno = nation_recno;
                              short unitRecno = sprite_recno;
                              int   actionXLoc = action_x_loc;
                              int   actionYLoc = action_y_loc;
                              short aiActionId = ai_action_id;
                              char  aiUnit = ai_unit;

                              reset_action_para2();

                              firmPtr->assign_unit(sprite_recno);

                              //----------------------------------------------------------//
                              // firm_array[]->assign_unit() must be done first.  Then a
                              // town will be created and the reaction to build other firms
                              // requires the location of the town.
                              //----------------------------------------------------------//

                              if(aiActionId)
                                    nation_array[nationRecno]->action_finished(aiActionId, unitRecno);

                              if( unit_array.is_deleted(unitRecno) )
                                    return;

                              //--- else the firm is full, the unit's skill level is lower than those in firm, or no space to create town ---//
                        }
                        else
                        {
                              //---------- change the builder ------------//
                              if(ai_unit && firmPtr->under_construction)
                                    return; // not allow AI to change firm builder

                              reset_action_para2();
                              if(skill.get_skill(SKILL_CONSTRUCTION) || skill.get_skill(firmPtr->firm_skill_id))
                                    firmPtr->set_builder(sprite_recno);
                        }

                        //------------ update unit_array's selected parameters ------------//
                        reset_action_para();
                        if(selected_flag)
                        {
                              selected_flag = 0;
                              unit_array.selected_count--;
                        }
                  }
                  else if( locPtr->is_town() && locPtr->town_recno() == action_para )
                  {
                        //---------------- a town on the location -----------------//
                        if(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, action_x_loc, action_y_loc,
                              STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT))
                        {
                              //----------- not in the surrounding ------------//
                              return;
                        }
                        
                        short actionPara = action_para;
                        short spriteRecno = sprite_recno;

                        if(ai_action_id)
                              nation_array[nation_recno]->action_finished(ai_action_id, sprite_recno);

                        //------------ update unit_array's selected parameters ------------//
                        reset_action_para2();
                        reset_action_para();
                        if(selected_flag)
                        {
                              selected_flag = 0;
                              unit_array.selected_count--;
                        }

                        //-------------- assign the unit to the town -----------------//
                        town_array[actionPara]->assign_unit(spriteRecno);
                  }

                  //####### begin trevor 18/8 #########// the following code was called wrongly and causing bug
/*
         //------ embarking a ground vehicle/animal ------//

                  else if(locPtr->has_unit(UNIT_LAND) && locPtr->unit_recno(UNIT_LAND) == action_para)
                  {
                        reset_action_para2();
                        reset_action_para();
                        if(selected_flag)
                        {
                              selected_flag = 0;
                              unit_array.selected_count--;
                        }

                        embark(action_para);
                  }
*/
                  //####### end trevor 18/8 #########//

                  //------ embarking a sea vehicle/animal ------//

                  else if(locPtr->has_unit(UNIT_SEA) && locPtr->unit_recno(UNIT_SEA) == action_para)
                  {
                        //------------ update unit_array's selected parameters ------------//
                        reset_action_para2();
                        reset_action_para();
                        if(selected_flag)
                        {
                              selected_flag = 0;
                              unit_array.selected_count--;
                        }

                        //----------------- load the unit to the marine -----------------//
                        ((UnitMarine*)unit_array[action_para])->load_unit(sprite_recno);
                  }
                  else
                  {
                        //------------------------------------------------------------------//
                        // abort actions for ai_unit since the target location has nothing
                        //------------------------------------------------------------------//

                        if( ai_action_id )
                              nation_array[nation_recno]->action_failure(ai_action_id, sprite_recno);
                  }
            }

            //-***** don't place codes here as unit may be removed above *****-//
            //reset_action_para();
            //selected_flag = 0;
      }
}
//----------- End of function Unit::process_assign -----------//


//--------- Begin of function Unit::process_burn ---------//
// process action of burning to a specified location
//
void Unit::process_burn()
{
      err_when(sprite_info->loc_width>1 || sprite_info->loc_height>1);

      if( cur_action == SPRITE_IDLE )  // the unit is at the build location now
      {
            if( next_x_loc()==action_x_loc && next_y_loc()==action_y_loc )
            {
                  reset_action_para2();
                  set_dir(move_to_x_loc, move_to_y_loc, action_x_loc, action_y_loc);
                  world.setup_fire( action_x_loc, action_y_loc );
            }

            reset_action_para();
      }
}
//----------- End of function Unit::process_burn -----------//


//--------- Begin of function Unit::process_settle ---------//
// process action of settling to an existing town
//
void Unit::process_settle()
{
      err_when(sprite_info->loc_width>1 || sprite_info->loc_height>1);

      if( cur_action == SPRITE_IDLE )  // the unit is at the build location now
      {
            reset_path();

            if( cur_x_loc()==move_to_x_loc && cur_y_loc()==move_to_y_loc )
            {
                  if(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, action_x_loc, action_y_loc,
                        STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT))
                        return;

                  Location* locPtr = world.get_loc(action_x_loc, action_y_loc);
                  if(!locPtr->is_town())
                  {
                        //##### begin trevor 1/9 ########//
                        int unitRecno = sprite_recno;

                        reset_action_para2();
                        //------------ settle the unit now -------------//
                        town_array.settle(sprite_recno, action_x_loc, action_y_loc);

                        if( unit_array.is_deleted(unitRecno) )
                              return;

                        reset_action_para();
                        //##### end trevor 1/9 ########//
                  }
                  else if(town_array[locPtr->town_recno()]->nation_recno == nation_recno)
                  {
                        //---------- a town zone already exists ---------//
                        assign(action_x_loc, action_y_loc);
                        return;
                  }
            }
            else
                  reset_action_para();
      }
}
//----------- End of function Unit::process_settle -----------//


//--------- Begin of function Unit::go_cast_power ---------//
// do action of god casting
//
void Unit::go_cast_power(int castXLoc, int castYLoc, char castPowerType, char remoteAction)
{
      err_when(mobile_type!=UNIT_AIR);

      //----------------------------------------------------------------//
      // return if the unit is dead
      //----------------------------------------------------------------//
      if(hit_points<=0 || action_mode==ACTION_DIE || cur_action==SPRITE_DIE)
            return;

      if(!remoteAction && remote.is_enable() )
      {
            //------------ process multiplayer calling ---------------//
            // packet structure : <unit recno> <xLoc> <yLoc> <power type>
            short *shortPtr =(short *)remote.new_send_queue_msg(MSG_U_GOD_CAST, 4*sizeof(short) );
            shortPtr[0] = sprite_recno;
            shortPtr[1] = castXLoc;
            shortPtr[2] = castYLoc;
            shortPtr[3] = castPowerType;
            return;
      }

      UnitGod *unitGod = (UnitGod *)this;

      //----------------------------------------------------------------//
      // action_mode2: checking for equal action or idle action
      //----------------------------------------------------------------//
      if(action_mode2==ACTION_GO_CAST_POWER && action_para2==0 && action_x_loc2==castXLoc && action_y_loc2==castYLoc
            && unitGod->cast_power_type==castPowerType)
      {
            if(cur_action!=SPRITE_IDLE)
                  return;
      }
      else
      {
            //----------------------------------------------------------------//
            // action_mode2: store new order
            //----------------------------------------------------------------//
            action_mode2  = ACTION_GO_CAST_POWER;
            action_para2  = 0;
            action_x_loc2 = castXLoc;
            action_y_loc2 = castYLoc;
      }

      //----- order the sprite to stop as soon as possible -----//
      stop();     // new order

      //------------- do searching if neccessary -------------//
      if(m.points_distance(next_x_loc(), next_y_loc(), castXLoc, castYLoc)>DO_CAST_POWER_RANGE)
            search(castXLoc, castYLoc, 1);

      //----------- set action to build the firm -----------//
      action_mode  = ACTION_GO_CAST_POWER;
      action_para  = 0;
      action_x_loc = castXLoc;
      action_y_loc = castYLoc;

      unitGod->cast_power_type = castPowerType;
      unitGod->cast_origin_x = next_x_loc();
      unitGod->cast_origin_y = next_y_loc();
      unitGod->cast_target_x = castXLoc;
      unitGod->cast_target_y = castYLoc;
}
//----------- End of function Unit::go_cast_power -----------//


//--------- Begin of function Unit::process_go_cast_power ---------//
// process action of god casting
//
void Unit::process_go_cast_power()
{
      err_when(mobile_type!=UNIT_AIR);
      err_when(action_x_loc2<0 || action_x_loc2>=MAX_WORLD_X_LOC);
      err_when(action_y_loc2<0 || action_y_loc2>=MAX_WORLD_Y_LOC);

      UnitGod *unitGod = (UnitGod *)this;
      if(cur_action==SPRITE_IDLE)
      {
            //----------------------------------------------------------------------------------------//
            // Checking condition to do casting power, Or resume action
            //----------------------------------------------------------------------------------------//
            if(m.points_distance(cur_x_loc(), cur_y_loc(), action_x_loc2, action_y_loc2)<=DO_CAST_POWER_RANGE)
            {
                  if( next_x_loc() != action_x_loc2 ||
                        next_y_loc() != action_y_loc2 )
                  {
                        set_dir(next_x_loc(), next_y_loc(), action_x_loc2, action_y_loc2);
                  }
                  set_attack(); // set cur_action=sprite_attack to cast power 
                  cur_frame = 1;
            }
            else
            {
                  err_when(action_mode2!=ACTION_GO_CAST_POWER || action_para2);
                  go_cast_power(action_x_loc2, action_y_loc2, unitGod->cast_power_type, COMMAND_AUTO);
            }
      }
      else if(cur_action==SPRITE_ATTACK)
      {
            //----------------------------------------------------------------------------------------//
            // do casting power now
            //----------------------------------------------------------------------------------------//
            AttackInfo *attackInfo = attack_info_array + cur_attack;
            if(cur_frame == attackInfo->bullet_out_frame)
            {
                  // add effect
                  add_close_attack_effect();

                  unitGod->cast_power(action_x_loc2, action_y_loc2);
                  set_remain_attack_delay();
                  // stop2();
            }

            if( cur_frame == 1 && remain_attack_delay == 0 )                // last frame of delaying
                  stop2();
      }
}
//----------- End of function Unit::process_go_cast_power -----------//

Generated by  Doxygen 1.6.0   Back to index