//
// Apply
//
void ExplosionObjType::Apply(const Vector &location, UnitObj *unit, Team *team)
{
  MapObjIter::All i(NULL, MapObjIter::FilterData(location, areaOuter));
  MapObj *obj;

  while ((obj = i.Next()) != NULL)
  {
    // Is the object within the full damage area
    F32 dist2 = i.GetProximity2() - areaInner2;
    S32 deltaHp;

    //Vector dir = obj->WorldMatrix().posit - location;
    //dir.Normalize();

    if (dist2 <= 0.0f)
    {
      // Apply the full damage to this object
      deltaHp = -damage.GetAmount(obj->MapType()->GetArmourClass());
      obj->ModifyHitPoints(deltaHp, unit, team/*, &dir*/);
    }
    else
    {
      F32 mod = 1.0f - (dist2 * areaDiff2Inv);
      ASSERT(mod >= 0 && mod <= 1.0f)

      // Apply a proportional damage to this object
      //Vector v = dir * mod;
      deltaHp = -(S32) (((F32) damage.GetAmount(obj->MapType()->GetArmourClass())) * mod);
      obj->ModifyHitPoints(deltaHp, unit, team/*, &v*/);
    }

    // Apply hit modifiers
    if (ArmourClass::Lookup(damage.GetDamageId(), obj->MapType()->GetArmourClass()))
    {
      damage.GetModifiers().Apply(obj);

      // Set blind target time
      if (blindTargetTime)
      {
        UnitObj *unitObj = Promote::Object<UnitObjType, UnitObj>(obj);

        if (unitObj)
        {
          unitObj->FlushTasks();
          unitObj->StartBlindTarget(blindTargetTime);
        }
      }

      // Apply the generic effect
      StartGenericFX(obj, 0x32FBA304); // "ExplosionObj::ApplyTarget"
    }

    // Is there an action to execute
    if (action && team)
    {
      Action::Execute(team, action);
    }
  }
}
    //
    // Execute
    //
    U32 Store::Execute(const U8 *data, Player &player)
    {
      const Data *d = (Data *) data;

      // Create an iterator
      for (UnitObjList::Iterator i(&player.GetSelectedList()); *i; i++)
      {
        // Get the unit
        UnitObj *unit = **i;

        // Is this a collector ?
        if (Tasks::UnitCollect *task = TaskCtrl::PromoteIdle<Tasks::UnitCollect>(unit))
        {
          // Should we search for a place to store the resource
          if (d->search)
          {
            task->Store();
          }
          else
          {
            // Convert ID into a pointer
            if (UnitObj *storeObj = Resolver::Object<UnitObj, UnitObjType>(d->object))
            {
              // If not updating the position, flush tasks incase moving or something
              if (!d->update && unit->GetActiveTask())
              {
                unit->FlushTasks();
              }

              // Tell this task about the new storage point
              task->SetStorageObject(storeObj, d->update);
            }
          }
        }
      }

      return (sizeof (Data));
    }
  //
  // Initial state
  //
  void SquadMoveTogether::StateInit()
  {
    LOG_DIAG(("SquadMoveTogether: Init"))

    // Find the slowest unit in the squad and use their traction type
    U8 traction = 0;
    F32 bottomSpeed = F32_MAX;

    // Work out the centre position of the squad
    Vector location(0.0f, 0.0f, 0.0f);
    U32 count = 0;
    SquadObj::UnitList::Iterator i(&subject->GetList());
    for (!i; *i; i++)
    {
      if ((*i)->Alive())
      {
        // Take this oportunity to reset the units node
        (*i)->completed = TRUE;
        (*i)->data = 0;

        if ((**i)->CanEverMove())
        {
          // Grab the unit so we don't need to continually pound the iterator
          UnitObj *unit = **i;

          // Flush its tasks
          unit->FlushTasks(Tasks::UnitMove::GetConfigBlockingPriority());

          // Add its position to the total
          location.x += unit->WorldMatrix().posit.x;
          location.z += unit->WorldMatrix().posit.z;
          count++;

          // Is this the slowest unit in the squad
          F32 speed = unit->GetMaxSpeed();
          if (speed < bottomSpeed)
          {
            bottomSpeed = speed;
            traction = unit->MapType()->GetTractionIndex(unit->MapType()->GetDefaultLayer());
          }
        }
      }
    }

    if (!count)
    {
      Quit();
      return;
    }

    // Work out the averate location
    location.x /= count;
    location.z /= count;
    location.y = TerrainData::FindFloor(location.x, location.z);

    // What is the direction from the source (location) to the dest (destination)
    VectorDir dir;
    Vector(destination - location).Convert(dir);
    direction = dir.u;

    // Build a formation from the units using the direction to the destination
    Formation::Create(location, direction, subject, 16.0f);

    // Get the source and destination in terms of cells
    Point<F32> avg(location.x, location.z);

    Point<U32> srcCell;
    WorldCtrl::MetresToCellPoint(avg, srcCell);

    Point<U32> destCell;
    WorldCtrl::MetresToCellPoint(Point<F32>(destination.x, destination.z), destCell);

    switch (subject->GetPathFinder().RequestPath(srcCell.x, srcCell.z, destCell.x, destCell.z, traction))
    {
      case PathSearch::Finder::RR_SUBMITTED:
        NextState(0xFDE9D5E3); // "Pathing"
        break;

      case PathSearch::Finder::RR_SAMECELL:
      case PathSearch::Finder::RR_OFFMAP:
        Quit();
        return;

      default:
        ERR_FATAL(("Unknown path request result"))
    }
  }
  //
  // StateInit
  //
  void SquadBoard::StateInit()
  {
    // Get each of the units in the squad to board transports
    SquadObj::UnitList::Iterator u(&subject->GetList());

    // We could enhance this to use units which are closest to transports etc.

    // Clear the squad's completed flags
    for (!u; *u; u++)
    {
      (*u)->completed = FALSE;
      (*u)->task = 0;
    }

    // Reset squad iterator
    !u;

    for (TransportObjList::Iterator t(&transports); *t; t++)
    {
      if ((*t)->Alive())
      {
        TransportObj *transport = **t;
        U32 slots = transport->TransportType()->GetSpaces();
        U32 added = 0;

        while (slots--)
        {
          UnitObjPtr *unitPtr = *u;

          if (unitPtr)
          {
            ASSERT(unitPtr->Alive())
            UnitObj *unit = *unitPtr;

            if (unit->CanEverMove())
            {
              // Tell the unit to board
              unit->FlushTasks(Tasks::UnitBoard::GetConfigBlockingPriority());

              Task *task;

              // Is this a telepad
              if (TaskCtrl::PromoteIdle<Tasks::TransportPad>(transport))
              {
                unit->PrependTask(task = new Tasks::UnitMove(unit, transport), GetFlags());
              }
              else
              {
                unit->PrependTask(task = new Tasks::UnitBoard(unit, transport), GetFlags());
              }

              (*u)->task = task->GetTaskId();

              added++;
            }
            else
            {
              // This unit can't move so complete it
              (*u)->completed = TRUE;
            }
          }
          else
          {
            break;
          }

          // Increment iterator
          u++;
        }

        if (!added)
        {
          // No units were added
          break;
        }
      }
    }

    // Complete those units which missed out
    for (; *u; u++)
    {
      (*u)->completed = TRUE;
    }

    NextState(0x09E5F977); // "Boarding"
  }