/** ** Change missile heading from x,y. ** ** @param delta Delta movement ** ** @internal We have : SpriteFrame / (2 * (Numdirection - 1)) == DirectionToHeading / 256. */ void Missile::MissileNewHeadingFromXY(const PixelPos &delta) { if (this->Type->NumDirections == 1 || (delta.x == 0 && delta.y == 0)) { return; } if (this->SpriteFrame < 0) { this->SpriteFrame = -this->SpriteFrame - 1; } this->SpriteFrame /= this->Type->NumDirections / 2 + 1; this->SpriteFrame *= this->Type->NumDirections / 2 + 1; const int nextdir = 256 / this->Type->NumDirections; Assert(nextdir != 0); const int dir = ((DirectionToHeading(delta) + nextdir / 2) & 0xFF) / nextdir; if (dir <= LookingS / nextdir) { // north->east->south this->SpriteFrame += dir; } else { this->SpriteFrame += 256 / nextdir - dir; this->SpriteFrame = -this->SpriteFrame - 1; } }
/** ** Change missile heading from x,y. ** Do not change the animation step. ** ** @param missile Missile pointer. ** @param dx Delta in x. ** @param dy Delta in y. ** @internal We have : SpriteFrame / (2 * (Numdirection - 1)) == DirectionToHeading / 256. */ static void MissileNewHeadingFromXY(Missile *missile, int dx, int dy) { int dir; int nextdir; // If the heading cannot be changed, return right away. if (missile->Type->NumDirections == 1 || (dx == 0 && dy == 0)) { return; } // Compute the number of the first frame of the current // animation step, discarding the previous heading. if (missile->SpriteFrame < 0) { missile->SpriteFrame = -missile->SpriteFrame - 1; } missile->SpriteFrame /= missile->Type->NumDirections / 2 + 1; missile->SpriteFrame *= missile->Type->NumDirections / 2 + 1; // How many heading units there are per frame. // This assumes NumDirections is a power of 2; otherwise, // nextdir is truncated and dir can get out of range. nextdir = 256 / missile->Type->NumDirections; Assert(nextdir != 0); // Compute the frame number relative to the current animation // step, as if flipping were not used. Add nextdir/2 so the // quotient is rounded, not truncated. dir = ((DirectionToHeading(10 * dx, 10 * dy) + nextdir / 2) & 0xFF) / nextdir; // Compute the absolute frame number, with both the animation // step and the heading. if (dir <= LookingS / nextdir) { // north->east->south missile->SpriteFrame += dir; } else { missile->SpriteFrame += 256 / nextdir - dir; missile->SpriteFrame = -missile->SpriteFrame - 1; } }
bool COrder_Build::StartBuilding(CUnit &unit, CUnit &ontop) { const CUnitType &type = this->GetUnitType(); unit.Player->SubUnitType(type); CUnit *build = MakeUnit(const_cast<CUnitType &>(type), unit.Player); // If unable to make unit, stop, and report message if (build == NULL) { // FIXME: Should we retry this? unit.Player->Notify(NotifyYellow, unit.tilePos, _("Unable to create building %s"), type.Name.c_str()); if (unit.Player->AiEnabled) { AiCanNotBuild(unit, type); } return false; } build->Constructed = 1; build->CurrentSightRange = 0; // Building on top of something, may remove what is beneath it if (&ontop != &unit) { CBuildRestrictionOnTop *b; b = static_cast<CBuildRestrictionOnTop *>(OnTopDetails(*build, ontop.Type)); Assert(b); if (b->ReplaceOnBuild) { build->ResourcesHeld = ontop.ResourcesHeld; // We capture the value of what is beneath. build->Variable[GIVERESOURCE_INDEX].Value = ontop.Variable[GIVERESOURCE_INDEX].Value; build->Variable[GIVERESOURCE_INDEX].Max = ontop.Variable[GIVERESOURCE_INDEX].Max; build->Variable[GIVERESOURCE_INDEX].Enable = ontop.Variable[GIVERESOURCE_INDEX].Enable; ontop.Remove(NULL); // Destroy building beneath UnitLost(ontop); UnitClearOrders(ontop); ontop.Release(); } } // Must set action before placing, otherwise it will incorrectly mark radar delete build->CurrentOrder(); build->Orders[0] = COrder::NewActionBuilt(unit, *build); UpdateUnitSightRange(*build); // Must place after previous for map flags build->Place(this->goalPos); // HACK: the building is not ready yet build->Player->UnitTypesCount[type.Slot]--; if (build->Active) { build->Player->UnitTypesAiActiveCount[type.Slot]--; } // We need somebody to work on it. if (!type.BoolFlag[BUILDEROUTSIDE_INDEX].value) { UnitShowAnimation(unit, unit.Type->Animations->Still); unit.Remove(build); this->State = State_BuildFromInside; if (unit.Selected) { SelectedUnitChanged(); } } else { this->State = State_BuildFromOutside; this->BuildingUnit = build; unit.Direction = DirectionToHeading(build->tilePos - unit.tilePos); UnitUpdateHeading(unit); } return true; }