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

OUNITAAC.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    : OUNITAAC.CPP
//Description : Object UnitArray - misc functions

#include <math.h>

#include <ALL.h>
#include <OVGA.h>
#include <OSYS.h>
#include <OSTR.h>
#include <OREMOTE.h>
#include <OWORLD.h>
#include <ONATION.h>
#include <OFIRM.h>
#include <OTOWN.h>
#include <OTERRAIN.h>
#include <OU_MARI.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 UnitArray::divide_array ---------//
// divide units into arrays by their mobile_type 
//
// <int> excludeSelectedLocUnit     -     (default 0)
//
void UnitArray::divide_array(int locX, int locY, short* selectedArray, int selectedCount, int excludeSelectedLocUnit)
{
      err_when( selectedCount < 0 );

      selected_land_unit_count = 0;
      selected_sea_unit_count = 0;
      selected_air_unit_count = 0;
      selected_land_unit_array = NULL;
      selected_sea_unit_array = NULL;
      selected_air_unit_array = NULL;

      int unitRecno;
      if(excludeSelectedLocUnit)
      {
            Location *locPtr = world.get_loc(locX, locY);
            short targetMobileType = locPtr->has_any_unit();
            unitRecno = targetMobileType ? locPtr->unit_recno(targetMobileType) : 0;
      }
      
      selected_land_unit_array = (short*) mem_add(sizeof(short)*selectedCount);
      selected_sea_unit_array = (short*) mem_add(sizeof(short)*selectedCount);
      selected_air_unit_array = (short*) mem_add(sizeof(short)*selectedCount);
      memset(selected_land_unit_array, 0, sizeof(short)*selectedCount);
      memset(selected_sea_unit_array, 0, sizeof(short)*selectedCount);
      memset(selected_air_unit_array, 0, sizeof(short)*selectedCount);

      Unit *unitPtr;
      int curRecno;
      for(int i=0; i<selectedCount; i++)
      {
            curRecno = selectedArray[i];
            if(excludeSelectedLocUnit && curRecno==unitRecno)
                  continue;

            unitPtr = (Unit*) get_ptr(curRecno);
            switch(unitPtr->mobile_type)
            {
                  case UNIT_LAND:
                              selected_land_unit_array[selected_land_unit_count++] = curRecno;
                              break;

                  case UNIT_SEA:
                              selected_sea_unit_array[selected_sea_unit_count++] = curRecno;
                              break;

                  case UNIT_AIR:
                              selected_air_unit_array[selected_air_unit_count++] = curRecno;
                              break;

                  default:    err_here();
                                    break;
            }
      }
}
//----------- End of function UnitArray::divide_array -----------//     


//--------- Begin of function UnitArray::set_group_id ---------//
// Set group id for the selected units
//
void UnitArray::set_group_id(short* selectedArray, int selectedCount)
{
      //-------------------------------------------------//
      // set unit cur_action and unit_group_id
      //-------------------------------------------------//
      DWORD curGroupId = unit_array.cur_group_id++;

      for(int j=0; j<selectedCount; j++)
      {
            Unit* unitPtr = (Unit*) get_ptr(selectedArray[j]);
            err_when(!unitPtr);
            err_when(!unitPtr->is_visible());
            err_when(unitPtr->hit_points<=0);

            unitPtr->unit_group_id = curGroupId;
            err_if(unitPtr->cur_action==SPRITE_IDLE && (unitPtr->cur_x!=unitPtr->next_x || unitPtr->cur_y!=unitPtr->next_y))
                  err_here();

            if( unitPtr->cur_action == SPRITE_IDLE )                    //**maybe need to include SPRITE_ATTACK as well
                  unitPtr->set_ready();
      }
}
//----------- End of function UnitArray::set_group_id -----------//     


//--------- Begin of function UnitArray::stop ---------//
//
// <short*> selectedUnitArray  - an array of recno of selected units.
//                                                                (the array should be terminated with 0)
// <int>    selectedCount            - no. of selected units.
// [char]   remoteAction          - whether this is an action carried out by a remote machine or not.
//                                                                (default: 0)
//
void UnitArray::stop(short* selectedUnitArray, int selectedCount, char remoteAction)
{
      //-------- if it's a multiplayer game --------//
      //
      // Queue the action.
      //
      // Local: this action will be processed when all action messages of all
      //                 remote players are ready from the next frame.
      //
      // Remote: this action will be processed when the remote has received
      //                  frame sync notification from all other players.
      //
      //--------------------------------------------//

      if( !remoteAction && remote.is_enable() )
      {
            short* shortPtr = (short*) remote.new_send_queue_msg(MSG_UNIT_STOP,
                                                sizeof(short) * (1+selectedCount) );

            shortPtr[0] = selectedCount;

            memcpy( shortPtr+1, selectedUnitArray, sizeof(short) * selectedCount );
      }
      else
      {
            DWORD curGroupId = unit_array.cur_group_id++;

            //-------------- stop now ---------------//

            err_when( selectedCount > 10000 );        // error

            Unit* unitPtr;

            for( int i=0 ; i<selectedCount ; i++ )
            {
                  unitPtr = (Unit*) get_ptr(selectedUnitArray[i]);
                  unitPtr->unit_group_id = curGroupId;
                  unitPtr->stop2();
            }
      }
}
//----------- End of function UnitArray::stop -----------//


//--------- Begin of function UnitArray::stop_all_war ---------//
// Stop all the units that is in war with the specified nation
// and stop all the units of the specified nation that is in war
// with other nations
//
// <short>  oldNationReno     -     the nation_renco of the specified nation
//
void UnitArray::stop_all_war(short oldNationRecno)
{
      Unit  *unitPtr, *targetUnit;
      Firm  *targetFirm;
      Town  *targetTown;
      Location    *targetLoc;
      char  targetType;
      short targetRecno;
      int   targetXLoc, targetYLoc;

      for(int i=size(); i>0; --i)
      {
            if(is_deleted(i))
                  continue;

            unitPtr = operator[](i);

            if(!unitPtr->is_visible())
                  continue;

            if(unitPtr->nation_recno==oldNationRecno)
            {
                  //------ stop all attacking unit with nation_recno = oldNationRecno -----//
                  if(unitPtr->is_action_attack())
                        unitPtr->stop2(KEEP_DEFENSE_MODE);
            }
            else if(unitPtr->is_action_attack())
            {
                  //---- stop all attacking unit with target's nation_recno = oldNationRecno ----//
                  if(unitPtr->action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET)
                  {
                        targetType = unitPtr->action_mode;
                        targetRecno = unitPtr->action_para;
                        targetXLoc = unitPtr->action_x_loc;
                        targetYLoc = unitPtr->action_y_loc;
                  }
                  else
                  {
                        targetType = unitPtr->action_mode2;
                        targetRecno = unitPtr->action_para2;
                        targetXLoc = unitPtr->action_x_loc2;
                        targetYLoc = unitPtr->action_y_loc2;
                  }

                  switch(targetType)
                  {
                        case ACTION_ATTACK_UNIT:
                        case ACTION_DEFEND_TOWN_ATTACK_TARGET:
                        case ACTION_MONSTER_DEFEND_ATTACK_TARGET:
                                    if(is_deleted(targetRecno))
                                          continue;

                                    targetUnit = operator[](targetRecno);
                                    if(targetUnit->nation_recno==oldNationRecno)
                                          unitPtr->stop2(KEEP_DEFENSE_MODE);
                                    break;

                        case ACTION_ATTACK_FIRM:
                                    if(firm_array.is_deleted(targetRecno))
                                          continue;

                                    targetFirm = firm_array[targetRecno];
                                    if(targetFirm->nation_recno==oldNationRecno)
                                          unitPtr->stop2(KEEP_DEFENSE_MODE);
                                    break;

                        case ACTION_ATTACK_TOWN:
                                    if(town_array.is_deleted(targetRecno))
                                          continue;

                                    targetTown = town_array[targetRecno];
                                    if(targetTown->nation_recno==oldNationRecno)
                                          unitPtr->stop2(KEEP_DEFENSE_MODE);
                                    break;

                        case ACTION_ATTACK_WALL:
                                    targetLoc = world.get_loc(targetXLoc, targetYLoc);
                                    if(targetLoc->wall_nation_recno()==oldNationRecno)
                                          unitPtr->stop2(KEEP_DEFENSE_MODE);
                                    break;
                  }
            }
      }
}
//----------- End of function UnitArray::stop_all_war -----------//


//--------- Begin of function UnitArray::stop_war_between ---------//
// stop the war between the two nations specified
//
// <short>  nationReno1 -     the nation_renco of one of the nation
// <short>  nationReno2 -     the nation_renco of the other nation
//
void UnitArray::stop_war_between(short nationRecno1, short nationRecno2)
{
      Unit  *unitPtr, *targetUnit;
      Firm  *targetFirm;
      Town  *targetTown;
      Location    *targetLoc;
      char  targetType;
      short targetRecno;
      int   targetXLoc, targetYLoc;

      for(int i=size(); i>0; --i)
      {
            if(is_deleted(i))
                  continue;

            unitPtr = operator[](i);

            if(!unitPtr->is_visible())
                  continue;

            if(unitPtr->nation_recno!=nationRecno1 && unitPtr->nation_recno!=nationRecno2)
                  continue;

            if(unitPtr->is_action_attack())
            {
                  //---- stop all attacking unit with target's nation_recno = oldNationRecno ----//
                  if(unitPtr->action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET)
                  {
                        targetType = unitPtr->action_mode;
                        targetRecno = unitPtr->action_para;
                        targetXLoc = unitPtr->action_x_loc;
                        targetYLoc = unitPtr->action_y_loc;
                  }
                  else
                  {
                        targetType = unitPtr->action_mode2;
                        targetRecno = unitPtr->action_para2;
                        targetXLoc = unitPtr->action_x_loc2;
                        targetYLoc = unitPtr->action_y_loc2;
                  }

                  switch(targetType)
                  {
                        case ACTION_ATTACK_UNIT:
                        case ACTION_DEFEND_TOWN_ATTACK_TARGET:
                        case ACTION_MONSTER_DEFEND_ATTACK_TARGET:
                                    if(is_deleted(targetRecno))
                                          continue;

                                    targetUnit = operator[](targetRecno);
                                    if(targetUnit->nation_recno==nationRecno1 || targetUnit->nation_recno==nationRecno2)
                                          unitPtr->stop2(KEEP_DEFENSE_MODE);
                                    break;

                        case ACTION_ATTACK_FIRM:
                                    if(firm_array.is_deleted(targetRecno))
                                          continue;

                                    targetFirm = firm_array[targetRecno];
                                    if(targetFirm->nation_recno==nationRecno1 || targetFirm->nation_recno==nationRecno2)
                                          unitPtr->stop2(KEEP_DEFENSE_MODE);
                                    break;

                        case ACTION_ATTACK_TOWN:
                                    if(town_array.is_deleted(targetRecno))
                                          continue;

                                    targetTown = town_array[targetRecno];
                                    if(targetTown->nation_recno==nationRecno1 || targetTown->nation_recno==nationRecno2)
                                          unitPtr->stop2(KEEP_DEFENSE_MODE);
                                    break;

                        case ACTION_ATTACK_WALL:
                                    targetLoc = world.get_loc(targetXLoc, targetYLoc);
                                    if(targetLoc->wall_nation_recno()==nationRecno1 || targetLoc->wall_nation_recno()==nationRecno2)
                                          unitPtr->stop2(KEEP_DEFENSE_MODE);
                                    break;
                  }
            }
      }
}
//----------- End of function UnitArray::stop_war_between -----------//


//--------- Begin of function UnitArray::stop_attack_unit ---------//
// stop all units that is attacking the specified unit
//
// <short>  unitRecno   -     unit_recno of the specified unit
//
void UnitArray::stop_attack_unit(short unitRecno)
{
      if(nation_hand_over_flag)
            return;

      Unit  *unitPtr;

      for(int i=size(); i>0; --i)
      {
            if(is_deleted(i))
                  continue;

            unitPtr = operator[](i);

            if(!unitPtr->is_visible())
                  continue;

            if((unitPtr->action_para==unitRecno && unitPtr->action_mode==ACTION_ATTACK_UNIT) ||
                  (unitPtr->action_para2==unitRecno && unitPtr->action_mode2==ACTION_ATTACK_UNIT))
                  unitPtr->stop2(KEEP_DEFENSE_MODE);
      }
}
//----------- End of function UnitArray::stop_attack_unit -----------//


//--------- Begin of function UnitArray::stop_attack_firm ---------//
// stop all units that is attacking the specified firm
//
// <short> firmRecno    -     the firm_recno of the firm
//
void UnitArray::stop_attack_firm(short firmRecno)
{
      if(nation_hand_over_flag)
            return;

      Unit  *unitPtr;

      for(int i=size(); i>0; --i)
      {
            if(is_deleted(i))
                  continue;

            unitPtr = operator[](i);

            if(!unitPtr->is_visible())
                  continue;

            if((unitPtr->action_para==firmRecno && unitPtr->action_mode==ACTION_ATTACK_FIRM) ||
                  (unitPtr->action_para2==firmRecno && unitPtr->action_mode2==ACTION_ATTACK_FIRM))
                  unitPtr->stop2(KEEP_DEFENSE_MODE);
      }
}
//----------- End of function UnitArray::stop_attack_firm -----------//


//--------- Begin of function UnitArray::stop_attack_town ---------//
// stop all units that is attacking the specified town
//
// <short> townRecno    -     the town_recno of the specified town
//
void UnitArray::stop_attack_town(short townRecno)
{
      if(nation_hand_over_flag)
            return;

      Unit  *unitPtr;

      for(int i=size(); i>0; --i)
      {
            if(is_deleted(i))
                  continue;

            unitPtr = operator[](i);

            if(!unitPtr->is_visible())
                  continue;

            if((unitPtr->action_para==townRecno && unitPtr->action_mode==ACTION_ATTACK_TOWN) ||
                  (unitPtr->action_para2==townRecno && unitPtr->action_mode2==ACTION_ATTACK_TOWN))
                  unitPtr->stop2(KEEP_DEFENSE_MODE);
      }
}
//----------- End of function UnitArray::stop_attack_town -----------//


//--------- Begin of function UnitArray::assign ---------//
// group assign to firm/town/unit
//
// <int>          destX                   -     x location assigned to
// <int>          destY                   -     y location assigned to
//    <int>       divided                 -     whether the array is divied by divide_array(...) (1 - divided, 0 not)
//    <char>      remoteAction      -
//    [short*]    selectedArray     -     unit_recno of the selected units    (default: NULL)
// [int]          selectedCount     -     number of selected units      (default: 0)
//
void UnitArray::assign(int destX, int destY, int divided, char remoteAction, short* selectedArray, int selectedCount)
{
      err_when(destX<0 || destY<0 || destX>MAX_WORLD_X_LOC-1 || destY>MAX_WORLD_Y_LOC-1);

      //###### begin trevor 25/8 #######//

      //--- set the destination to the top left position of the town/firm ---//

      Location* locPtr = world.get_loc(destX, destY);

      //---- if there is a firm on this location -----//

      if( locPtr->is_firm() )
      {
            Firm* firmPtr = firm_array[locPtr->firm_recno()];

            destX = firmPtr->loc_x1;
            destY = firmPtr->loc_y1;
      }

      //---- if there is a town on this location -----//

      else if( locPtr->is_town() )
      {
            Town* townPtr = town_array[locPtr->town_recno()];

            destX = townPtr->loc_x1;
            destY = townPtr->loc_y1;
      }

      //###### end trevor 25/8 #######//

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

      Unit*       unitPtr;
      int         freeMemory = 0;

      if( selectedArray == NULL)
      {
            selectedArray = (short*) mem_add(sizeof(short)*size());
            selectedCount = 0;
            freeMemory = 1;

            // find myself
            for(int i=size(); i>0; i--)
            {
                  if(is_deleted(i))
                        continue;

                  unitPtr = operator[](i);
                  //err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);
                  if(!unitPtr->is_visible())
                        continue;
                  
                  if( unitPtr->selected_flag && unitPtr->is_own() )
                  {
                        err_when(unitPtr->hit_points<=0 || unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode==ACTION_DIE);
                        selectedArray[selectedCount++] = i;
                  }
            }
      }

      if(!remoteAction && remote.is_enable())
      {
            // packet structure : <xLoc> <yLoc> <no. of units> <unit recno ...>
            short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNIT_ASSIGN,
                  sizeof(short) * (4+selectedCount));
            shortPtr[0] = destX;
            shortPtr[1] = destY;
            shortPtr[2] = selectedCount;
            shortPtr[3] = divided;
            memcpy(shortPtr+4, selectedArray, sizeof(short)*selectedCount);
      }
      else
      {
            if(!divided)
            {
                  for(int j=0; j< selectedCount; ++j)
                  {
                        int i = selectedArray[j];

                        if(is_deleted(i))
                              continue;

                        unitPtr = operator[](i);      //unit_array[i];

                        //### begin trevor 7/7#######//
                        err_when(!unitPtr->is_visible() );
                        err_when( unitPtr->hit_points<=0 );
                        //### end trevor 7/7#######//

                        unitPtr->stop2();
                  }

                  //--------- divide the unit by their mobile_type ------------//
                  divide_array(destX, destY, selectedArray, selectedCount);
                  
                  if(selected_land_unit_count)
                        assign(destX, destY, 1, remoteAction, selected_land_unit_array, selected_land_unit_count);

                  if(selected_sea_unit_count)
                  {
                        Location *locPtr = world.get_loc(destX, destY);
                        if(locPtr->is_firm())
                        {
                              err_when(firm_array.is_deleted(locPtr->firm_recno()));
                              Firm *firmPtr = firm_array[locPtr->firm_recno()];
                              if(firmPtr->firm_id==FIRM_HARBOR) // recursive call
                                    assign(destX, destY, 1, remoteAction, selected_sea_unit_array, selected_sea_unit_count);
                              else
                                    ship_to_beach(destX, destY, 1, selected_sea_unit_array, selected_sea_unit_count, remoteAction);
                        }
                        //else if(locPtr->is_town())
                        else
                        {
                              err_when(town_array.is_deleted(locPtr->town_recno()));
                              ship_to_beach(destX, destY, 1, selected_sea_unit_array, selected_sea_unit_count, remoteAction);
                        }
                  }

                  if(selected_air_unit_count) // no assign for air units
                        move_to(destX, destY, 1, selected_air_unit_array, selected_air_unit_count, remoteAction);

                  //------------ deinit static variables ------------//
                  selected_land_unit_count = selected_sea_unit_count = selected_air_unit_count = 0;
                  mem_del(selected_land_unit_array);
                  mem_del(selected_sea_unit_array);
                  mem_del(selected_air_unit_array);
            }
            else
            {
                  //---------- set unit to assign -----------//
                  if(selectedCount<2)
                  {
                        unitPtr = (Unit*) get_ptr(selectedArray[0]);
                        err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);

                        if(unitPtr->sprite_info->loc_width<=1)
                        {
                              unitPtr->unit_group_id = unit_array.cur_group_id++;
                              unitPtr->assign(destX, destY);
                        }
                        else // move to object surrounding
                        {
                              Location *locPtr = world.get_loc(destX, destY);
                              if(locPtr->is_firm())
                                    unitPtr->move_to_firm_surround(destX, destY, unitPtr->sprite_info->loc_width, unitPtr->sprite_info->loc_height, locPtr->firm_recno());
                              else if(locPtr->is_town())
                                    unitPtr->move_to_town_surround(destX, destY, unitPtr->sprite_info->loc_width, unitPtr->sprite_info->loc_height);
                              else if(locPtr->has_unit(UNIT_LAND))
                                    unitPtr->move_to_unit_surround(destX, destY, unitPtr->sprite_info->loc_width, unitPtr->sprite_info->loc_height, locPtr->unit_recno(UNIT_LAND));
                        }
                  }
                  else // for more than one unit selecting, call group_assign() to take care of it
                  {
                        set_group_id(selectedArray, selectedCount);
                        group_assign(destX, destY, selectedArray, selectedCount);
                  }
            }
      }

      if( freeMemory )
            mem_del(selectedArray);
}
//----------- End of function UnitArray::assign -----------//


//--------- Begin of function UnitArray::group_assign ---------//
// <int>          destX                   -     x location assigned to
// <int>          destY                   -     y location assigned to
// <short*> selectedArray     -     unit recno of the selected units
// <int>          selectedCount     -     num of selected units
//
void UnitArray::group_assign(int destX, int destY, short* selectedArray, int selectedCount)
{
      enum  {     ASSIGN_TYPE_UNIT = 1,
                        ASSIGN_TYPE_FIRM,
                        ASSIGN_TYPE_TOWN,
                  };

      Location *locPtr = world.get_loc(destX, destY);

      int assignType = 0;     // 1 for unit, 2 for firm, 3 for town
      int miscNo = 0;         // usedd to store the recno of the object
      if(locPtr->has_unit(UNIT_LAND))
      {
            assignType = ASSIGN_TYPE_UNIT;
            miscNo = locPtr->unit_recno(UNIT_LAND);
      }
      else if(locPtr->is_firm())
      {
            assignType = ASSIGN_TYPE_FIRM;
            miscNo = firm_array[locPtr->firm_recno()]->firm_id;
      }
      else if(locPtr->is_town())
      {
            assignType = ASSIGN_TYPE_TOWN;
            miscNo = 0;
      }
      else
            err_here();

      Unit* unitPtr;
      for(int i=0; i<selectedCount; i++)
      {
            unitPtr = operator[](selectedArray[i]);
            err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);
            if(unitPtr->sprite_info->loc_width<=1)
                  unitPtr->assign(destX, destY, i+1); // the thrid parameter is used to generate different result for the searching
            else
            {
                  //-----------------------------------------------------------------//
                  // for 2x2 unit, unable to assign, so move to the surrounding
                  //-----------------------------------------------------------------//
                  switch(assignType)
                  {
                        case ASSIGN_TYPE_UNIT:
                                          unitPtr->move_to_unit_surround(destX, destY, unitPtr->sprite_info->loc_width,
                                                                                                       unitPtr->sprite_info->loc_height, miscNo);
                                          break;      // is a unit

                        case ASSIGN_TYPE_FIRM:
                                          unitPtr->move_to_firm_surround(destX, destY, unitPtr->sprite_info->loc_width,
                                                                                                       unitPtr->sprite_info->loc_height, miscNo);
                                          break;      // is a firm

                        case ASSIGN_TYPE_TOWN:
                                          unitPtr->move_to_town_surround(destX, destY, unitPtr->sprite_info->loc_width,
                                                                                                       unitPtr->sprite_info->loc_height);
                                          break;      // is a town

                        default:    err_here();
                                          break;
                  }
            }
      }
}
//----------- End of function UnitArray::group_assign -----------//


//--------- Begin of function UnitArray::assign_to_camp ---------//
// <int>          destX                         -     x location where the camp is
// <int>          destY                         -     y location where the camp is
// <char>   remoteAction            -
// [short*] selectedUnitArray -     recno of the selected units (default: NULL)
// [int]          selectedCount           -     number of selected units  (default: 0)
//
void UnitArray::assign_to_camp(int destX, int destY, char remoteAction, short* selectedUnitArray, int selectedCount)
{
      divide_array(destX, destY, selectedUnitArray, selectedCount);
      
      if(selected_land_unit_count)
      {
            int assignCount=0, moveCount=0;
            short *assignArray = (short*) mem_add(sizeof(short)*selected_land_unit_count);
            short *moveArray = (short*) mem_add(sizeof(short)*selected_land_unit_count);
            char unitClass;
            Unit *unitPtr;
            memset(assignArray, 0, sizeof(short)*selected_land_unit_count);
            memset(moveArray, 0, sizeof(short)*selected_land_unit_count);

            //----------------------------------------------------------------//
            // Only human and weapon can be assigned to the camp. Others are
            // ordered to move to camp as close as possible.
            //----------------------------------------------------------------//
            for(int i=0; i<selectedCount; i++)
            {
                  err_when(unit_array.is_deleted(selectedUnitArray[i]));
                  unitPtr = operator[](selectedUnitArray[i]);
                  unitClass = unit_res[unitPtr->unit_id]->unit_class;
                  if(unitClass==UNIT_CLASS_HUMAN || unitClass==UNIT_CLASS_WEAPON)
                        assignArray[assignCount++] = selectedUnitArray[i];
                  else
                        moveArray[moveCount++] = selectedUnitArray[i];
            }

            if(assignCount)
                  assign(destX, destY, 1, remoteAction, assignArray, assignCount);
            if(moveCount)
                  move_to(destX, destY, 1, moveArray, moveCount, remoteAction);

            mem_del(assignArray);
            mem_del(moveArray);
      }

      if(selected_sea_unit_count)
            ship_to_beach(destX, destY, 1, selected_sea_unit_array, selected_sea_unit_count, remoteAction);

      if(selected_air_unit_count)
            move_to(destX, destY, 1, selected_air_unit_array, selected_air_unit_count, remoteAction);

      //---------------- deinit static parameters ---------------//
      selected_land_unit_count = selected_sea_unit_count = selected_air_unit_count = 0;
      mem_del(selected_land_unit_array);
      mem_del(selected_sea_unit_array);
      mem_del(selected_air_unit_array);
}
//----------- End of function UnitArray::assign_to_camp -----------//


//--------- Begin of function UnitArray::settle ---------//
//    <int>       destX                   -     x location settle to
//    <int>       destY                   -     y location settle to
//    <int>       divided                 -     whether the selected is divided into subgroup, (1 = divided, 0 = not)
//    <char>      remoteAction      -
//    [short*]    selectedArray     -     the recno of the selected units (default: NULL)
//    [int]       selectedCount     -     num of selected units (default: 0)
//
void UnitArray::settle(int destX, int destY, int divided, char remoteAction, short* selectedArray, int selectedCount)
{
      Unit*       unitPtr;
      int         freeMemory = 0;

      if(selectedArray == NULL)
      {
            selectedArray = (short*) mem_add(sizeof(short)*size());
            selectedCount = 0;
            freeMemory = 1;

            // find myself
            for(int i=size(); i>0; i--)
            {
                  if(is_deleted(i))
                        continue;

                  unitPtr = operator[](i);
                  //err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);
                  if(!unitPtr->is_visible())
                        continue;
                  
                  if( unitPtr->selected_flag && unitPtr->is_own() )
                  {
                        err_when(unitPtr->hit_points<=0 || unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode==ACTION_DIE);
                        selectedArray[selectedCount++] = i;
                  }
            }
      }

      if(!remoteAction && remote.is_enable())
      {
            // packet structure : <xLoc> <yLoc> <no. of units> <divided> <unit recno ...>
            short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNITS_SETTLE, sizeof(short)*(4+selectedCount));
            shortPtr[0] = destX;
            shortPtr[1] = destY;
            shortPtr[2] = selectedCount;
            shortPtr[3] = divided;
            memcpy(shortPtr+4, selectedArray, sizeof(short)*selectedCount);
      }
      else
      {
            if(!divided)
            {
                  for(int j=0; j< selectedCount; ++j)
                  {
                        int i = selectedArray[j];

                        if(is_deleted(i))
                              continue;

                        unitPtr = operator[](i);      //unit_array[i];
                        err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);
                        unitPtr->stop2();
                  }

                  divide_array(destX, destY, selectedArray, selectedCount);

                  if(selected_land_unit_count)
                        settle(destX, destY, 1, remoteAction, selected_land_unit_array, selected_land_unit_count);
                  
                  if(selected_sea_unit_count)
                        ship_to_beach(destX, destY, 1, selected_sea_unit_array, selected_sea_unit_count, remoteAction);

                  if(selected_air_unit_count)
                        move_to(destX, destY, 1, selected_air_unit_array, selected_air_unit_count, remoteAction);

                  //-------------- deinit static parameters --------------//
                  selected_land_unit_count = selected_sea_unit_count = selected_air_unit_count = 0;
                  mem_del(selected_land_unit_array);
                  mem_del(selected_sea_unit_array);
                  mem_del(selected_air_unit_array);
            }
            else
            {
                  //---------- set unit to settle -----------//
                  if(selectedCount<2)
                  {
                        unitPtr = (Unit*) get_ptr(selectedArray[0]);
                        err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);
                        unitPtr->unit_group_id = unit_array.cur_group_id++;
                        unitPtr->settle(destX, destY);
                  }
                  else
                  {
                        set_group_id(selectedArray, selectedCount);
                        group_settle(destX, destY, selectedArray, selectedCount);
                  }
            }
      }

      if(freeMemory)
            mem_del(selectedArray);
}
//----------- End of function UnitArray::settle -----------//


//--------- Begin of function UnitArray::group_settle ---------//
//    <int>       destX                   -     x location to settle to
// <int>          destY                   -     y location to settle to
// <short*> selectedArray     -     recno. of selected units
//    <int>       selectedCount     -     num. of selected units
//
void UnitArray::group_settle(int destX, int destY, short* selectedArray, int selectedCount)
{
      #ifdef DEBUG
            DWORD debugGroupId = (operator[](selectedArray[0]))->unit_group_id;
      #endif

      Unit* unitPtr;

      for(int i=0; i<selectedCount; i++)
      {
            unitPtr = operator[](selectedArray[i]);
            err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);
            
            #ifdef DEBUG
                  err_when(unitPtr->unit_group_id!=debugGroupId);
            #endif

            unitPtr->settle(destX, destY, i+1);
      }
}
//----------- End of function UnitArray::group_settle -----------//


//--------- Begin of function UnitArray::assign_to_ship ---------//
// <int>          shipXLoc                -     x location of the ship
// <int>          shipYLoc                -     y location of the ship
// <int>          divided                 -     whether the selected groups is divided (1 - divided, 0 - not)
// <short*> selectedArray     -     recno of selected units
// <int>          selectedCount     -     num. of selected units
// <char>   remoteAction      -
//
void UnitArray::assign_to_ship(int shipXLoc, int shipYLoc, int divided, short* selectedArray, int selectedCount, char remoteAction, int shipRecno)
{
      err_when(terrain_res[world.get_loc(shipXLoc, shipYLoc)->terrain_id]->average_type!=TERRAIN_OCEAN);
      err_when(!selectedCount || selectedCount>1000);

      if( !remoteAction && remote.is_enable() )
      {
            // packet structure : <xLoc> <yLoc> <ship recno> <no. of units> <divided> <unit recno ...>
            short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNITS_ASSIGN_TO_SHIP,
                  sizeof(short) * (5+selectedCount));
            shortPtr[0] = shipXLoc;
            shortPtr[1] = shipYLoc;
            shortPtr[2] = shipRecno;
            shortPtr[3] = selectedCount;
            shortPtr[4] = divided;
            memcpy(shortPtr+5, selectedArray, sizeof(short)*selectedCount);

            return;
      }

      if(!divided)
      {
            divide_array(shipXLoc, shipYLoc, selectedArray, selectedCount);

            if(selected_sea_unit_count) // Note: the order to call ship unit first
                  move_to(shipXLoc, shipYLoc, 1, selected_sea_unit_array, selected_sea_unit_count, remoteAction);

            if(selected_land_unit_count)
                  assign_to_ship(shipXLoc, shipYLoc, 1, selected_land_unit_array, selected_land_unit_count, remoteAction, shipRecno);

            if(selected_air_unit_count)
                  move_to(shipXLoc, shipYLoc, 1, selected_air_unit_array, selected_air_unit_count, remoteAction);

            //---------------- deinit static parameters -----------------//
            selected_land_unit_count = selected_sea_unit_count = selected_air_unit_count = 0;
            mem_del(selected_land_unit_array);
            mem_del(selected_sea_unit_array);
            mem_del(selected_air_unit_array);
            return;
      }
      else
      {
            // ###### begin Gilbert 5/8 ##########//
            // ----- dont not use shipXLoc, shipYLoc passed, use shipRecno --------//

            UnitMarine *shipPtr = (UnitMarine*) get_ptr(shipRecno);

            if( shipPtr && shipPtr->is_visible() )
            {
                  shipXLoc = shipPtr->next_x_loc();
                  shipYLoc = shipPtr->next_y_loc();
            }
            else
                  return;
            // ##### patch end Gilbert 5/8 #######//

            //------------------------------------------------------------------------------------//
            // find the closest unit to the ship
            //------------------------------------------------------------------------------------//
            int   minDist=0x7FFFFF, dist, distX, distY;
            int   closestUnitRecno = -1;
            Unit  *unitPtr;
            int i;
            for(i=0; i<selectedCount; i++)
            {
                  unitPtr = (Unit*) get_ptr(selectedArray[i]);
                  distX = abs(shipXLoc - unitPtr->next_x_loc());
                  distY = abs(shipYLoc - unitPtr->next_y_loc());
                  dist = (distX>distY) ? distX : distY;
                  if(dist < minDist)
                  {
                        minDist = dist;
                        closestUnitRecno = i;
                  }
            }
            err_when(closestUnitRecno==-1);

            //------------------------------------------------------------------------------------//
            // If the seleceted units are distributed on different territories, select those unit
            // on the same territory as the closet unit for processing, there will be no action for
            // the rest units.
            //------------------------------------------------------------------------------------//
            DWORD                   curGroupId = unit_array.cur_group_id++;
            Unit                    *closestUnit = (Unit*) get_ptr(selectedArray[closestUnitRecno]);
            int                     closestUnitXLoc = closestUnit->next_x_loc();
            int                     closestUnitYLoc = closestUnit->next_y_loc();
            unsigned char     defaultRegionId = world.get_loc(closestUnitXLoc, closestUnitYLoc)->region_id;
            short                   *newSelectedArray;
            int                     newSelectedCount = 0;

            if(selectedCount>1)
            {
                  newSelectedArray = (short*) mem_add(sizeof(short)*selectedCount);
                  memset(newSelectedArray, 0, sizeof(short)*selectedCount);

                  for(i=0; i<selectedCount; i++)
                  {
                        unitPtr = (Unit*) get_ptr(selectedArray[i]);
                        if(world.get_loc(unitPtr->next_x_loc(), unitPtr->next_y_loc())->region_id == defaultRegionId)
                        {
                              newSelectedArray[newSelectedCount++] = selectedArray[i]; // on the same territory
                              unitPtr->unit_group_id = curGroupId;
                        }

                        if(unitPtr->cur_action==SPRITE_IDLE)
                              unitPtr->set_ready();
                  }
                  err_when(newSelectedCount > selectedCount);
            }
            else
            {
                  err_when(closestUnit->sprite_recno!=selectedArray[0]);
                  newSelectedArray = (short*) mem_add(sizeof(short)); // only one unit
                  newSelectedArray[0] = selectedArray[0];
                  newSelectedCount = 1;
                  closestUnit->unit_group_id = curGroupId;
            }
              
            //-------------- ordering the ship move near the coast ----------------//
            int curXLoc = closestUnit->next_x_loc();
            int curYLoc = closestUnit->next_y_loc();
            
            // ##### patch begin Gilbert 5/8 #######//
            // UnitMarine *shipPtr = (UnitMarine*) get_ptr(world.get_unit_recno(shipXLoc, shipYLoc, UNIT_SEA));
            // ##### patch end Gilbert 5/8 #######//

            int landX, landY;
            shipPtr->unit_group_id = curGroupId;
            shipPtr->ship_to_beach(curXLoc, curYLoc, landX, landY);

            if(landX!=-1 && landY!=-1)
            {
                  //-------------- ordering the units ---------------//
                  #define TRY_SIZE 5
                  int countLimit = TRY_SIZE*TRY_SIZE;
                  //### begin alex 30/10 ###//
                  int j, k, xShift, yShift, checkXLoc, checkYLoc;
                  UCHAR regionId = world.get_loc(landX, landY)->region_id;
                  Location *locPtr;
                  for(i=0, k=0; i<newSelectedCount; i++)
                  {
                        for(j=1; j<countLimit; j++)
                        {
                              if(++k>countLimit)
                                    k = 1;
                              m.cal_move_around_a_point(k, TRY_SIZE, TRY_SIZE, xShift, yShift);
                              checkXLoc = landX+xShift;
                              checkYLoc = landY+yShift;
                              if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC)
                                    continue;

                              locPtr = world.get_loc(checkXLoc, checkYLoc);
                              if(locPtr->region_id!=regionId || !locPtr->can_move(UNIT_LAND))
                                    continue;

                              unitPtr = (Unit*) get_ptr(newSelectedArray[i]);
                              unitPtr->assign_to_ship(landX, landY, shipPtr->sprite_recno, k);
                              break;
                        }
                  }
                  //#### end alex 30/10 ####//
            }

            mem_del(newSelectedArray);
      }
}
//----------- End of function UnitArray::assign_to_ship -----------//


//--------- Begin of function UnitArray::ship_to_beach ---------//
// <int>          destX                   -     x location the ship move to
//    <int>       destY                   -     y location the ship move to
//    <int>       divided                 -     whether the units are divided (1 - divided, 0 - not)
//    <short*>    selectedArray     -     the recno. of the selected units
//    <int>       selectedCount     -     num. of selected units
//    <char>      remoteAction      -
//
void UnitArray::ship_to_beach(int destX, int destY, int divided, short* selectedArray, int selectedCount, char remoteAction)
{
      Unit *unitPtr;

      if( !remoteAction && remote.is_enable() )
      {
            // packet structure : <xLoc> <yLoc> <no. of units> <divided> <unit recno ...>
            short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNITS_SHIP_TO_BEACH,
                  sizeof(short) * (4+selectedCount));
            shortPtr[0] = destX;
            shortPtr[1] = destY;
            shortPtr[2] = selectedCount;
            shortPtr[3] = divided;
            memcpy(shortPtr+4, selectedArray, sizeof(short)*selectedCount);

            return;
      }

      set_group_id(selectedArray, selectedCount);

      //--------------------------------------------------------------------//
      //--------------------------------------------------------------------//
      #define CHECK_SEA_DIMENSION   50
      #define CHECK_SEA_SIZE              CHECK_SEA_DIMENSION*CHECK_SEA_DIMENSION
      Location *locPtr = world.get_loc(destX, destY);
      UCHAR regionId = locPtr->region_id;
      int xShift, yShift, checkXLoc, checkYLoc;
      int landX, landY, seaX, seaY, tempX, tempY;

      int j=1, k, found;
      
      //--------------------------------------------------------------------//
      // find a unit that can carrying units.  Let it to do the first searching.
      // Use the returned reference parameters (landX, landY) for the other
      // ships to calculate their final location to move to
      //--------------------------------------------------------------------//
      int i;
      for(i=0; i<selectedCount; i++) // for first unit
      {
            unitPtr = (Unit*) get_ptr(selectedArray[i]);
            if(unit_res[unitPtr->unit_id]->carry_unit_capacity>0)
            {
                  unitPtr->ship_to_beach(destX, destY, landX, landY); // landX=landY=-1 if calling move_to() instead
                  i++;
                  break;
            }
            else
                  unitPtr->move_to(destX, destY, 1);
      }

      int totalCheck = 0;
      for(; i<selectedCount; i++) // for the rest units
      {
            unitPtr = (Unit*) get_ptr(selectedArray[i]);
            if(unit_res[unitPtr->unit_id]->carry_unit_capacity>0 && landX!=-1 && landY!=-1)
            {
                  for(found=0; j<=CHECK_SEA_SIZE; j++, totalCheck++)
                  {
                        m.cal_move_around_a_point(j, CHECK_SEA_DIMENSION, CHECK_SEA_DIMENSION, xShift, yShift);

                        if(j>=CHECK_SEA_SIZE)
                              j = 1;

                        if(totalCheck == CHECK_SEA_SIZE)
                        {
                              //--------------------------------------------------------------------//
                              // can't handle this case
                              //--------------------------------------------------------------------//
                              unitPtr->ship_to_beach(landX, landY, tempX, tempY);
                              totalCheck = 0;
                              break;
                        }

                        seaX = landX+xShift;
                        seaY = landY+yShift;
                        if(seaX<0 || seaX>=MAX_WORLD_X_LOC || seaY<0 || seaY>=MAX_WORLD_Y_LOC)
                              continue;

                        locPtr = world.get_loc(seaX, seaY);
                        if(terrain_res[locPtr->terrain_id]->average_type!=TERRAIN_OCEAN)
                              continue;

                        //--------------------------------------------------------------------//
                        // if it is able to find a location around the surrounding location with
                        // same region id we prefer, order the unit to move there.
                        //--------------------------------------------------------------------//
                        for(k=2; k<=9; k++)
                        {
                              m.cal_move_around_a_point(k, 3, 3, xShift, yShift);
                              checkXLoc = seaX+xShift;
                              checkYLoc = seaY+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;

                              unitPtr->ship_to_beach(checkXLoc, checkYLoc, tempX, tempY);
                              found++;
                              err_when(unitPtr->result_node_array && unitPtr->result_node_count==unitPtr->result_node_recno &&
                                                (unitPtr->result_node_array[unitPtr->result_node_count-1].node_x!=unitPtr->go_x>>ZOOM_X_SHIFT_COUNT ||
                                                unitPtr->result_node_array[unitPtr->result_node_count-1].node_y!=unitPtr->go_y>>ZOOM_Y_SHIFT_COUNT));
                              break;
                        }

                        if(found)
                        {
                              totalCheck = 0;
                              break;
                        }
                  }
            }
            else // cannot carry units
                  unitPtr->move_to(destX, destY, 1);
      }
}
//----------- End of function UnitArray::ship_to_beach -----------//


//----------- Begin of function UnitArray::divide_attack_by_nation -----------//
//
// units which can be controlled by nationRecno to attack are moved
// to the front of the selectedArray, return is number of units passed
//
int UnitArray::divide_attack_by_nation(short nationRecno, short *selectedArray, int selectedCount)
{
      // elements before i are pass, elements on or after passCount are not pass
      int loopCount = selectedCount+2;
      int passCount = selectedCount;
      for( int i = 0; i < passCount;  )
      {
            err_when(--loopCount == 0);
            short unitRecno = selectedArray[i];

            // a clocked spy cannot be commanded by original nation to attack
            if( !is_deleted(unitRecno) && operator[](unitRecno)->nation_recno == nationRecno )
            {
                  // pass
                  ++i;
            }
            else
            {
                  // fail, swap [i] with [passCount-1]
                  --passCount;

                  selectedArray[i] = selectedArray[passCount];
                  selectedArray[passCount] = unitRecno;
            }
      }
      return passCount;
}
//----------- End of function UnitArray::divide_attack_by_nation -----------//


//----------- Begin of function UnitArray::add_way_point -----------//
// <int>          pointX                  -     x location of the point to be added
//    <int>       pointY                  -     y location of the point to be added
// <short*> selectedArray     -     recno. of selected units
//    <int>       selectedCount     -     num. of selected units
//    <char>      remoteAction      -
//
void UnitArray::add_way_point(int pointX, int pointY, short* selectedArray, int selectedCount, char remoteAction)
{
      if(!remoteAction && remote.is_enable())
      {
            // packet structure : <xLoc> <yLoc> <no. of units> <unit recno ...>
            short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNIT_ADD_WAY_POINT,
                  sizeof(short) * (3+selectedCount));
            shortPtr[0] = pointX;
            shortPtr[1] = pointY;
            shortPtr[2] = selectedCount;
            memcpy(shortPtr+3, selectedArray, sizeof(short)*selectedCount);
      }
      else
      {
            DWORD groupId = unit_array.cur_group_id;
            Unit *unitPtr;

            int i;
            for(i=0; i<selectedCount; ++i)
            {
                  unitPtr = unit_array[selectedArray[i]];
                  unitPtr->unit_group_id = groupId;
            }

            unit_array.cur_group_id++;
      
            for(i=0; i<selectedCount; ++i)
            {
                  unitPtr = unit_array[selectedArray[i]];
                  unitPtr->add_way_point(pointX, pointY);
            }
      }
}
//----------- End of function UnitArray::add_way_point -----------//

Generated by  Doxygen 1.6.0   Back to index