本文整理汇总了C++中CUnit类的典型用法代码示例。如果您正苦于以下问题:C++ CUnit类的具体用法?C++ CUnit怎么用?C++ CUnit使用的例子?那么, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了CUnit类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: Finish
static void Finish(COrder_Built &order, CUnit &unit)
{
const CUnitType &type = *unit.Type;
CPlayer &player = *unit.Player;
DebugPrint("%d: Building %s(%s) ready.\n" _C_ player.Index _C_ type.Ident.c_str() _C_ type.Name.c_str());
// HACK: the building is ready now
player.UnitTypesCount[type.Slot]++;
if (unit.Active) {
player.UnitTypesAiActiveCount[type.Slot]++;
}
unit.Constructed = 0;
if (unit.Frame < 0) {
unit.Frame = -1;
} else {
unit.Frame = 0;
}
CUnit *worker = order.GetWorkerPtr();
if (worker != NULL) {
if (type.BoolFlag[BUILDERLOST_INDEX].value) {
// Bye bye worker.
LetUnitDie(*worker);
worker = NULL;
} else { // Drop out the worker.
worker->ClearAction();
DropOutOnSide(*worker, LookingW, &unit);
// If we can harvest from the new building, do it.
if (worker->Type->ResInfo[type.GivesResource]) {
CommandResource(*worker, unit, 0);
}
// If we can reurn goods to a new depot, do it.
if (worker->CurrentResource && worker->ResourcesHeld > 0 && type.CanStore[worker->CurrentResource]) {
CommandReturnGoods(*worker, &unit, 0);
}
}
}
if (type.GivesResource && type.StartingResources != 0) {
// Has StartingResources, Use those
unit.ResourcesHeld = type.StartingResources;
}
player.Notify(NotifyGreen, unit.tilePos, _("New %s done"), type.Name.c_str());
if (&player == ThisPlayer) {
if (type.MapSound.Ready.Sound) {
PlayUnitSound(unit, VoiceReady);
} else if (worker) {
PlayUnitSound(*worker, VoiceWorkCompleted);
} else {
PlayUnitSound(unit, VoiceBuilding);
}
}
if (player.AiEnabled) {
/* Worker can be NULL */
AiWorkComplete(worker, unit);
}
// FIXME: Vladi: this is just a hack to test wall fixing,
// FIXME: also not sure if the right place...
// FIXME: Johns: hardcoded unit-type wall / more races!
if (&type == UnitTypeOrcWall || &type == UnitTypeHumanWall) {
Map.SetWall(unit.tilePos, &type == UnitTypeHumanWall);
unit.Remove(NULL);
UnitLost(unit);
UnitClearOrders(unit);
unit.Release();
return ;
}
UpdateForNewUnit(unit, 0);
// Set the direction of the building if it supports them
if (type.NumDirections > 1 && type.BoolFlag[NORANDOMPLACING_INDEX].value == false) {
if (type.BoolFlag[WALL_INDEX].value) { // Special logic for walls
CorrectWallDirections(unit);
CorrectWallNeighBours(unit);
} else {
unit.Direction = (MyRand() >> 8) & 0xFF; // random heading
}
UnitUpdateHeading(unit);
}
if (IsOnlySelected(unit) || &player == ThisPlayer) {
SelectedUnitChanged();
}
MapUnmarkUnitSight(unit);
unit.CurrentSightRange = unit.Stats->Variables[SIGHTRANGE_INDEX].Max;
MapMarkUnitSight(unit);
order.Finished = true;
}
示例2: SCOPED_TIMER
CUnit* CUnitLoader::LoadUnit(const UnitLoadParams& cparams)
{
CUnit* unit = NULL;
UnitLoadParams& params = const_cast<UnitLoadParams&>(cparams);
SCOPED_TIMER("UnitLoader::LoadUnit");
{
GML_RECMUTEX_LOCK(sel); // LoadUnit - for anti deadlock purposes.
GML_RECMUTEX_LOCK(quad); // LoadUnit - make sure other threads cannot access an incomplete unit
const UnitDef* ud = params.unitDef;
if (ud == NULL)
return unit;
// need to check this BEFORE creating the instance
if (!unitHandler->CanAddUnit(cparams.unitID))
return unit;
if (params.teamID < 0) {
// FIXME use gs->gaiaTeamID ? (once it is always enabled)
if ((params.teamID = teamHandler->GaiaTeamID()) < 0)
throw content_error("Invalid team and no gaia team to put unit in");
}
if (ud->IsTransportUnit()) {
unit = new CTransportUnit();
} else if (ud->IsFactoryUnit()) {
// special static builder structures that can always be given
// move orders (which are passed on to all mobile buildees)
unit = new CFactory();
} else if (ud->IsMobileBuilderUnit() || ud->IsStaticBuilderUnit()) {
// all other types of non-structure "builders", including hubs and
// nano-towers (the latter should not have any build-options at all,
// whereas the former should be unable to build any mobile units)
unit = new CBuilder();
} else if (ud->IsBuildingUnit()) {
// static non-builder structures
if (ud->IsExtractorUnit()) {
unit = new CExtractorBuilding();
} else {
unit = new CBuilding();
}
} else {
// regular mobile unit
unit = new CUnit();
}
unit->PreInit(params);
if (ud->IsTransportUnit()) {
new CTransportCAI(unit);
} else if (ud->IsFactoryUnit()) {
new CFactoryCAI(unit);
} else if (ud->IsMobileBuilderUnit() || ud->IsStaticBuilderUnit()) {
new CBuilderCAI(unit);
} else if (ud->IsNonHoveringAirUnit()) {
// non-hovering fighter or bomber aircraft; coupled to StrafeAirMoveType
new CAirCAI(unit);
} else if (ud->IsAirUnit()) {
// all other aircraft; coupled to HoverAirMoveType
new CMobileCAI(unit);
} else if (ud->IsGroundUnit()) {
new CMobileCAI(unit);
} else {
new CCommandAI(unit);
}
}
unit->PostInit(params.builder);
(eventBatchHandler->GetUnitCreatedDestroyedBatch()).enqueue(EventBatchHandler::UD(unit, unit->isCloaked));
if (params.flattenGround) {
FlattenGround(unit);
}
return unit;
}
示例3: FireInternal
void CBeamLaser::FireInternal(float3 curDir)
{
float actualRange = range;
float rangeMod = 1.0f;
if (!owner->unitDef->IsImmobileUnit()) {
// help units fire while chasing
rangeMod = 1.3f;
}
if (owner->UnderFirstPersonControl()) {
rangeMod = 0.95f;
}
bool tryAgain = true;
bool doDamage = true;
float maxLength = range * rangeMod;
float curLength = 0.0f;
float3 curPos = weaponMuzzlePos;
float3 hitPos;
float3 newDir;
// objects at the end of the beam
CUnit* hitUnit = NULL;
CFeature* hitFeature = NULL;
CPlasmaRepulser* hitShield = NULL;
CollisionQuery hitColQuery;
if (!sweepFireState.IsSweepFiring()) {
curDir += (gs->randVector() * SprayAngleExperience());
curDir.SafeNormalize();
// increase range if targets are searched for in a cylinder
if (cylinderTargeting > 0.01f) {
const float verticalDist = owner->radius * cylinderTargeting * curDir.y;
const float maxLengthModSq = maxLength * maxLength + verticalDist * verticalDist;
maxLength = math::sqrt(maxLengthModSq);
}
// adjust range if targetting edge of hitsphere
if (targetType == Target_Unit && targetUnit != NULL && targetBorder != 0.0f) {
maxLength += (targetUnit->radius * targetBorder);
}
} else {
// restrict the range when sweeping
maxLength = std::min(maxLength, sweepFireState.GetTargetDist3D() * 1.125f);
}
for (int tries = 0; tries < 5 && tryAgain; ++tries) {
float beamLength = TraceRay::TraceRay(curPos, curDir, maxLength - curLength, collisionFlags, owner, hitUnit, hitFeature, &hitColQuery);
if (hitUnit != NULL && teamHandler->AlliedTeams(hitUnit->team, owner->team)) {
if (sweepFireState.IsSweepFiring() && !sweepFireState.DamageAllies()) {
doDamage = false; break;
}
}
if (!weaponDef->waterweapon) {
// terminate beam at water surface if necessary
if ((curDir.y < 0.0f) && ((curPos.y + curDir.y * beamLength) <= 0.0f)) {
beamLength = curPos.y / -curDir.y;
}
}
// if the beam gets intercepted, this modifies newDir
//
// we do more than one trace-iteration and set dir to
// newDir only in the case there is a shield in our way
const float shieldLength = interceptHandler.AddShieldInterceptableBeam(this, curPos, curDir, beamLength, newDir, hitShield);
if (shieldLength < beamLength) {
beamLength = shieldLength;
tryAgain = hitShield->BeamIntercepted(this, salvoDamageMult);
} else {
tryAgain = false;
}
// same as hitColQuery.GetHitPos() if no water or shield in way
hitPos = curPos + curDir * beamLength;
{
const float baseAlpha = weaponDef->intensity * 255.0f;
const float startAlpha = (1.0f - (curLength ) / maxLength);
const float endAlpha = (1.0f - (curLength + beamLength) / maxLength);
ProjectileParams pparams = GetProjectileParams();
pparams.pos = curPos;
pparams.end = hitPos;
pparams.ttl = weaponDef->beamLaserTTL;
pparams.startAlpha = Clamp(startAlpha * baseAlpha, 0.0f, 255.0f);
pparams.endAlpha = Clamp(endAlpha * baseAlpha, 0.0f, 255.0f);
WeaponProjectileFactory::LoadProjectile(pparams);
}
curPos = hitPos;
curDir = newDir;
curLength += beamLength;
//.........这里部分代码省略.........
示例4: TraceRay
// called by {CRifle, CBeamLaser, CLightningCannon}::Fire(), CWeapon::HaveFreeLineOfFire(), and Skirmish AIs
float TraceRay(
const float3& start,
const float3& dir,
float length,
int collisionFlags,
const CUnit* owner,
CUnit*& hitUnit,
CFeature*& hitFeature
) {
const bool ignoreEnemies = ((collisionFlags & Collision::NOENEMIES ) != 0);
const bool ignoreAllies = ((collisionFlags & Collision::NOFRIENDLIES) != 0);
const bool ignoreFeatures = ((collisionFlags & Collision::NOFEATURES ) != 0);
const bool ignoreNeutrals = ((collisionFlags & Collision::NONEUTRALS ) != 0);
const bool ignoreGround = ((collisionFlags & Collision::NOGROUND ) != 0);
const bool ignoreUnits = ignoreEnemies && ignoreAllies && ignoreNeutrals;
hitFeature = NULL;
hitUnit = NULL;
if (dir == ZeroVector) {
return -1.0f;
}
if (!ignoreFeatures || !ignoreUnits) {
GML_RECMUTEX_LOCK(quad); // TraceRay
CollisionQuery cq;
int* begQuad = NULL;
int* endQuad = NULL;
qf->GetQuadsOnRay(start, dir, length, begQuad, endQuad);
// feature intersection
if (!ignoreFeatures) {
for (int* quadPtr = begQuad; quadPtr != endQuad; ++quadPtr) {
const CQuadField::Quad& quad = qf->GetQuad(*quadPtr);
for (std::list<CFeature*>::const_iterator ui = quad.features.begin(); ui != quad.features.end(); ++ui) {
CFeature* f = *ui;
// NOTE:
// if f is non-blocking, ProjectileHandler will not test
// for collisions with projectiles so we can skip it here
if (!f->blocking)
continue;
if (CCollisionHandler::DetectHit(f, start, start + dir * length, &cq, true)) {
const float3& intPos = (cq.b0)? cq.p0: cq.p1;
const float len = (intPos - start).dot(dir); // same as (intPos - start).Length()
// we want the closest feature (intersection point) on the ray
if (len < length) {
length = len;
hitFeature = f;
}
}
}
}
}
// unit intersection
if (!ignoreUnits) {
for (int* quadPtr = begQuad; quadPtr != endQuad; ++quadPtr) {
const CQuadField::Quad& quad = qf->GetQuad(*quadPtr);
for (std::list<CUnit*>::const_iterator ui = quad.units.begin(); ui != quad.units.end(); ++ui) {
CUnit* u = *ui;
if (u == owner)
continue;
if (ignoreAllies && u->allyteam == owner->allyteam)
continue;
if (ignoreNeutrals && u->IsNeutral())
continue;
if (ignoreEnemies && u->allyteam != owner->allyteam)
continue;
if (CCollisionHandler::DetectHit(u, start, start + dir * length, &cq, true)) {
const float3& intPos = (cq.b0)? cq.p0: cq.p1;
const float len = (intPos - start).dot(dir); // same as (intPos - start).Length()
// we want the closest unit (intersection point) on the ray
if (len < length) {
length = len;
hitUnit = u;
}
}
}
}
if (hitUnit)
hitFeature = NULL;
}
}
if (!ignoreGround) {
// ground intersection
const float groundLength = ground->LineGroundCol(start, start + dir * length);
if (length > groundLength && groundLength > 0) {
//.........这里部分代码省略.........
示例5: ShowScriptError
int CUnitScript::GetUnitVal(int val, int p1, int p2, int p3, int p4)
{
// may happen in case one uses Spring.GetUnitCOBValue (Lua) on a unit with CNullUnitScript
if (!unit) {
ShowScriptError("Error: no unit (in GetUnitVal)");
return 0;
}
#ifndef _CONSOLE
switch (val)
{
case ACTIVATION:
if (unit->activated)
return 1;
else
return 0;
break;
case STANDINGMOVEORDERS:
return unit->moveState;
break;
case STANDINGFIREORDERS:
return unit->fireState;
break;
case HEALTH: {
if (p1 <= 0)
return int((unit->health / unit->maxHealth) * 100.0f);
const CUnit* u = uh->GetUnit(p1);
if (u == NULL)
return 0;
else
return int((u->health / u->maxHealth) * 100.0f);
}
case INBUILDSTANCE:
if (unit->inBuildStance)
return 1;
else
return 0;
case BUSY:
if (busy)
return 1;
else
return 0;
break;
case PIECE_XZ: {
if (!PieceExists(p1)) {
ShowScriptError("Invalid piecenumber for get piece_xz");
break;
}
float3 relPos = GetPiecePos(p1);
float3 pos = unit->pos + unit->frontdir * relPos.z + unit->updir * relPos.y + unit->rightdir * relPos.x;
return PACKXZ(pos.x, pos.z);
}
case PIECE_Y: {
if (!PieceExists(p1)) {
ShowScriptError("Invalid piecenumber for get piece_y");
break;
}
float3 relPos = GetPiecePos(p1);
float3 pos = unit->pos + unit->frontdir * relPos.z + unit->updir * relPos.y + unit->rightdir * relPos.x;
return int(pos.y * COBSCALE);
}
case UNIT_XZ: {
if (p1 <= 0)
return PACKXZ(unit->pos.x, unit->pos.z);
const CUnit* u = uh->GetUnit(p1);
if (u == NULL)
return PACKXZ(0, 0);
else
return PACKXZ(u->pos.x, u->pos.z);
}
case UNIT_Y: {
if (p1 <= 0)
return int(unit->pos.y * COBSCALE);
const CUnit* u = uh->GetUnit(p1);
if (u == NULL)
return 0;
else
return int(u->pos.y * COBSCALE);
}
case UNIT_HEIGHT: {
if (p1 <= 0)
return int(unit->radius * COBSCALE);
const CUnit* u = uh->GetUnit(p1);
if (u == NULL)
return 0;
else
return int(u->radius * COBSCALE);
}
case XZ_ATAN:
return int(RAD2TAANG*atan2((float)UNPACKX(p1), (float)UNPACKZ(p1)) + 32768 - unit->heading);
case XZ_HYPOT:
return int(hypot((float)UNPACKX(p1), (float)UNPACKZ(p1)) * COBSCALE);
//.........这里部分代码省略.........
示例6: getNearest
//Based on function @ 0x004E8320
CUnit* UnitFinder::getNearest(int x, int y, int left, int top, int right, int bottom,
UnitFinderCallbackMatchInterface &callback) {
// Obtain finder indexes for all bounds
UnitFinderData* const p_xbegin = unitOrderingX;
UnitFinderData* const p_ybegin = unitOrderingY;
UnitFinderData* const p_xend = unitOrderingX + *unitOrderingCount;
UnitFinderData* const p_yend = unitOrderingY + *unitOrderingCount;
// Create UnitFinderData elements for compatibility with stl functions
UnitFinderData finderVal;
// Search for the values using built-in binary search algorithm and comparator
finderVal.position = x;
UnitFinderData *pLeft = std::lower_bound(p_xbegin, p_xend, finderVal);
UnitFinderData *pRight = pLeft + 1;
finderVal.position = y;
UnitFinderData *pTop = std::lower_bound(p_ybegin, p_yend, finderVal);
UnitFinderData *pBottom = pTop + 1;
CUnit *bestUnit = NULL;
int bestDistance = 999999;
bool canContinue, canNarrowSearchBounds;
bool isUnitVisited[UNIT_ARRAY_LENGTH + 1] = {false};
do {
canContinue = false;
canNarrowSearchBounds = false;
if (pLeft >= p_xbegin && pLeft->position >= left) {
if (!isUnitVisited[pLeft->unitIndex]) {
isUnitVisited[pLeft->unitIndex] = true;
CUnit *unit = CUnit::getFromIndex(pLeft->unitIndex);
if (left <= unit->getX() && unit->getX() < right
&& top <= unit->getY() && unit->getY() < bottom
&& callback.match(unit)) {
int distance = scbw::getDistanceFast(x, y, unit->getX(), unit->getY());
if (distance < bestDistance) {
bestUnit = unit;
bestDistance = distance;
canNarrowSearchBounds = true;
}
}
}
--pLeft;
canContinue = true;
}
if (pRight < p_xend && pRight->position <= right) {
if (!isUnitVisited[pRight->unitIndex]) {
isUnitVisited[pRight->unitIndex] = true;
CUnit *unit = CUnit::getFromIndex(pRight->unitIndex);
if (left <= unit->getX() && unit->getX() < right
&& top <= unit->getY() && unit->getY() < bottom
&& callback.match(unit)) {
int distance = scbw::getDistanceFast(x, y, unit->getX(), unit->getY());
if (distance < bestDistance) {
bestUnit = unit;
bestDistance = distance;
canNarrowSearchBounds = true;
}
}
}
++pRight;
canContinue = true;
}
if (pTop >= p_ybegin && pTop->position >= top) {
if (!isUnitVisited[pTop->unitIndex]) {
isUnitVisited[pTop->unitIndex] = true;
CUnit *unit = CUnit::getFromIndex(pTop->unitIndex);
if (left <= unit->getX() && unit->getX() < right
&& top <= unit->getY() && unit->getY() < bottom
&& callback.match(unit)) {
int distance = scbw::getDistanceFast(x, y, unit->getX(), unit->getY());
if (distance < bestDistance) {
bestUnit = unit;
bestDistance = distance;
canNarrowSearchBounds = true;
}
}
}
--pTop;
canContinue = true;
}
if (pBottom < p_yend && pBottom->position < bottom) {
if (!isUnitVisited[pBottom->unitIndex]) {
isUnitVisited[pBottom->unitIndex] = true;
CUnit *unit = CUnit::getFromIndex(pBottom->unitIndex);
if (left <= unit->getX() && unit->getX() < right
&& top <= unit->getY() && unit->getY() < bottom
&& callback.match(unit)) {
int distance = scbw::getDistanceFast(x, y, unit->getX(), unit->getY());
if (distance < bestDistance) {
bestUnit = unit;
bestDistance = distance;
canNarrowSearchBounds = true;
}
//.........这里部分代码省略.........
示例7: FireInternal
void CBeamLaser::FireInternal(float3 dir, bool sweepFire)
{
float rangeMod = 1.0f;
if (dynamic_cast<CBuilding*>(owner) == NULL) {
// help units fire while chasing
rangeMod = 1.3f;
}
#ifdef DIRECT_CONTROL_ALLOWED
if (owner->directControl) {
rangeMod = 0.95f;
}
#endif
float maxLength = range * rangeMod;
float curLength = 0.0f;
float3 curPos = weaponMuzzlePos;
float3 hitPos;
dir += gs->randVector() * sprayAngle * (1 - owner->limExperience * 0.7f);
dir.ANormalize();
bool tryAgain = true;
// unit at the end of the beam
CUnit* hit = 0;
// increase range if targets are searched for in a cylinder
if (cylinderTargetting > 0.01f) {
// const float3 up(0, owner->radius*cylinderTargetting, 0);
// const float uplen = up.dot(dir);
const float uplen = owner->radius * cylinderTargetting * dir.y;
maxLength = streflop::sqrtf(maxLength * maxLength + uplen * uplen);
}
// increase range if targetting edge of hitsphere
if (targetType == Target_Unit && targetUnit && targetBorder != 0) {
maxLength += targetUnit->radius * targetBorder;
}
for (int tries = 0; tries < 5 && tryAgain; ++tries) {
tryAgain = false;
hit = 0;
float length = helper->TraceRay(
curPos,
dir,
maxLength - curLength,
weaponDef->damages[0],
owner,
hit,
collisionFlags
);
if (hit && hit->allyteam == owner->allyteam && sweepFire) {
// never damage friendlies with sweepfire
lastFireFrame = 0;
return;
}
float3 newDir;
CPlasmaRepulser* shieldHit = 0;
const float shieldLength = interceptHandler.AddShieldInterceptableBeam(this, curPos, dir, length, newDir, shieldHit);
if (shieldLength < length) {
length = shieldLength;
if (shieldHit->BeamIntercepted(this, damageMul)) {
// repulsed
tryAgain = true;
}
}
hitPos = curPos + dir * length;
const float baseAlpha = weaponDef->intensity * 255.0f;
const float startAlpha = (1.0f - (curLength ) / (range * 1.3f)) * baseAlpha;
const float endAlpha = (1.0f - (curLength + length) / (range * 1.3f)) * baseAlpha;
if (weaponDef->largeBeamLaser) {
new CLargeBeamLaserProjectile(curPos, hitPos, color, weaponDef->visuals.color2, owner, weaponDef);
} else {
new CBeamLaserProjectile(
curPos, hitPos,
startAlpha, endAlpha,
color, weaponDef->visuals.color2,
owner,
weaponDef->thickness,
weaponDef->corethickness,
weaponDef->laserflaresize,
weaponDef,
weaponDef->visuals.beamttl,
weaponDef->visuals.beamdecay
);
}
curPos = hitPos;
curLength += length;
dir = newDir;
//.........这里部分代码省略.........
示例8: Assert
/**
** Stop gathering from the resource, go home.
**
** @param unit Poiner to unit.
**
** @return TRUE if ready, otherwise FALSE.
*/
int COrder_Resource::StopGathering(CUnit &unit)
{
CUnit *source = 0;
const ResourceInfo &resinfo = *unit.Type->ResInfo[this->CurrentResource];
//Wyrmgus start
// if (!resinfo.TerrainHarvester) {
if (!Map.Info.IsPointOnMap(this->goalPos)) {
//Wyrmgus end
//Wyrmgus start
// if (resinfo.HarvestFromOutside) {
if (this->GetGoal() && this->GetGoal()->Type->BoolFlag[HARVESTFROMOUTSIDE_INDEX].value) {
//Wyrmgus end
source = this->GetGoal();
this->ClearGoal();
} else {
source = unit.Container;
}
source->Resource.Active--;
Assert(source->Resource.Active >= 0);
//Store resource position.
this->Resource.Mine = source;
if (Preference.MineNotifications && unit.Player->Index == ThisPlayer->Index
&& source->IsAlive()
&& !source->MineLow
&& source->ResourcesHeld * 100 / source->Variable[GIVERESOURCE_INDEX].Max <= 10
//Wyrmgus start
// && source->Variable[GIVERESOURCE_INDEX].Max > DefaultIncomes[this->CurrentResource]) {
&& source->Variable[GIVERESOURCE_INDEX].Max > (DefaultIncomes[this->CurrentResource] * 10)) {
//Wyrmgus end
//Wyrmgus start
// unit.Player->Notify(NotifyYellow, source->tilePos, _("%s is running low!"), source->Type->Name.c_str());
unit.Player->Notify(NotifyYellow, source->tilePos, _("Our %s is nearing depletion!"), source->Type->Name.c_str());
//Wyrmgus end
source->MineLow = 1;
}
if (source->Type->MaxOnBoard) {
int count = 0;
CUnit *worker = source->Resource.Workers;
CUnit *next = NULL;
for (; NULL != worker; worker = worker->NextWorker) {
Assert(worker->CurrentAction() == UnitActionResource);
COrder_Resource &order = *static_cast<COrder_Resource *>(worker->CurrentOrder());
if (worker != &unit && order.IsGatheringWaiting()) {
count++;
if (next) {
if (next->Wait > worker->Wait) {
next = worker;
}
} else {
next = worker;
}
}
}
if (next) {
if (!unit.Player->AiEnabled) {
DebugPrint("%d: Worker %d report: Unfreez resource gathering of %d <Wait %d> on %d [Assigned: %d Waiting %d].\n"
_C_ unit.Player->Index _C_ UnitNumber(unit)
_C_ UnitNumber(*next) _C_ next->Wait
_C_ UnitNumber(*source) _C_ source->Resource.Assigned
_C_ count);
}
next->Wait = 0;
//source->Data.Resource.Waiting = count - 1;
//Assert(source->Data.Resource.Assigned >= source->Data.Resource.Waiting);
//StartGathering(next);
}
}
} else {
// Store resource position.
this->Resource.Pos = unit.tilePos;
Assert(this->Resource.Mine == NULL);
}
#ifdef DEBUG
if (!unit.ResourcesHeld) {
DebugPrint("Unit %d is empty???\n" _C_ UnitNumber(unit));
}
#endif
// Find and send to resource deposit.
CUnit *depot = FindDeposit(unit, 1000, unit.CurrentResource);
if (!depot || !unit.ResourcesHeld || this->Finished) {
//Wyrmgus start
// if (!(resinfo.HarvestFromOutside || resinfo.TerrainHarvester)) {
if (!((source && source->Type->BoolFlag[HARVESTFROMOUTSIDE_INDEX].value) || Map.Info.IsPointOnMap(this->goalPos))) {
//Wyrmgus end
Assert(unit.Container);
DropOutOnSide(unit, LookingW, source);
}
CUnit *mine = this->Resource.Mine;
//.........这里部分代码省略.........
示例9: Command
//.........这里部分代码省略.........
}
}
else if (curResurrect != NULL && f3SqDist(curResurrect->pos, pos) < Square(buildDistance + curResurrect->radius) && inBuildStance) {
const UnitDef* ud = curResurrect->udef;
if (fCommand.GetID() == CMD_WAIT) {
StopBuild();
} else {
if (ud != NULL) {
if ((modInfo.reclaimMethod != 1) && (curResurrect->reclaimLeft < 1)) {
// This corpse has been reclaimed a little, need to restore
// the resources before we can let the player resurrect it.
curResurrect->AddBuildPower(this, repairSpeed);
} else {
// Corpse has been restored, begin resurrection
const float step = resurrectSpeed / ud->buildTime;
const bool resurrectAllowed = eventHandler.AllowFeatureBuildStep(this, curResurrect, step);
const bool canExecResurrect = (resurrectAllowed && UseEnergy(ud->energy * step * modInfo.resurrectEnergyCostFactor));
if (canExecResurrect) {
curResurrect->resurrectProgress += step;
curResurrect->resurrectProgress = std::min(curResurrect->resurrectProgress, 1.0f);
CreateNanoParticle(curResurrect->midPos, curResurrect->radius * 0.7f, (gs->randInt() & 1));
}
if (curResurrect->resurrectProgress >= 1.0f) {
if (curResurrect->tempNum != (gs->tempNum - 1)) {
// resurrect finished and we are the first
curResurrect->UnBlock();
UnitLoadParams resurrecteeParams = {ud, this, curResurrect->pos, ZeroVector, -1, team, curResurrect->buildFacing, false, false};
CUnit* resurrectee = unitLoader->LoadUnit(resurrecteeParams);
assert(ud == resurrectee->unitDef);
if (!ud->canBeAssisted) {
resurrectee->soloBuilder = this;
resurrectee->AddDeathDependence(this, DEPENDENCE_BUILDER);
}
// TODO: make configurable if this should happen
resurrectee->health *= 0.05f;
for (CUnitSet::iterator it = cai->resurrecters.begin(); it != cai->resurrecters.end(); ++it) {
CBuilder* bld = static_cast<CBuilder*>(*it);
CCommandAI* bldCAI = bld->commandAI;
if (bldCAI->commandQue.empty())
continue;
Command& c = bldCAI->commandQue.front();
if (c.GetID() != CMD_RESURRECT || c.params.size() != 1)
continue;
if ((c.params[0] - unitHandler->MaxUnits()) != curResurrect->id)
continue;
if (!teamHandler->Ally(allyteam, bld->allyteam))
continue;
// all units that were rezzing shall assist the repair too
bld->lastResurrected = resurrectee->id;
// prevent FinishCommand from removing this command when the
示例10: StartGathering
/**
** Start harvesting the resource.
**
** @param unit Pointer to unit.
**
** @return TRUE if ready, otherwise FALSE.
*/
int COrder_Resource::StartGathering(CUnit &unit)
{
CUnit *goal;
const ResourceInfo &resinfo = *unit.Type->ResInfo[this->CurrentResource];
Assert(!unit.IX);
Assert(!unit.IY);
//Wyrmgus start
// if (resinfo.TerrainHarvester) {
if (Map.Info.IsPointOnMap(this->goalPos)) {
//Wyrmgus end
// This shouldn't happened?
#if 0
if (!Map.IsTerrainResourceOnMap(unit.Orders->goalPos, this->CurrentResource)) {
DebugPrint("Wood gone, just like that?\n");
return 0;
}
#endif
UnitHeadingFromDeltaXY(unit, this->goalPos - unit.tilePos);
if (resinfo.WaitAtResource) {
this->TimeToHarvest = std::max<int>(1, resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId]);
} else {
this->TimeToHarvest = 1;
}
this->DoneHarvesting = 0;
if (this->CurrentResource != unit.CurrentResource) {
DropResource(unit);
unit.CurrentResource = this->CurrentResource;
}
return 1;
}
goal = this->GetGoal();
// Target is dead, stop getting resources.
if (!goal || goal->IsVisibleAsGoal(*unit.Player) == false) {
// Find an alternative, but don't look too far.
this->goalPos.x = -1;
this->goalPos.y = -1;
if ((goal = UnitFindResource(unit, unit, 15, this->CurrentResource, unit.Player->AiEnabled))) {
this->State = SUB_START_RESOURCE;
this->SetGoal(goal);
} else {
this->ClearGoal();
this->Finished = true;
}
return 0;
}
// FIXME: 0 can happen, if to near placed by map designer.
Assert(unit.MapDistanceTo(*goal) <= 1);
// Update the heading of a harvesting unit to looks straight at the resource.
//Wyrmgus start
// UnitHeadingFromDeltaXY(unit, goal->tilePos - unit.tilePos + goal->Type->GetHalfTileSize());
UnitHeadingFromDeltaXY(unit, Vec2i(goal->tilePos.x * PixelTileSize.x, goal->tilePos.y * PixelTileSize.y) - Vec2i(unit.tilePos.x * PixelTileSize.x, unit.tilePos.y * PixelTileSize.y) + goal->Type->GetHalfTilePixelSize() - unit.Type->GetHalfTilePixelSize());
//Wyrmgus end
// If resource is still under construction, wait!
if ((goal->Type->MaxOnBoard && goal->Resource.Active >= goal->Type->MaxOnBoard)
|| goal->CurrentAction() == UnitActionBuilt) {
// FIXME: Determine somehow when the resource will be free to use
// FIXME: Could we somehow find another resource? Think minerals
// FIXME: We should add a flag for that, and a limited range.
// However the CPU usage is really low (no pathfinding stuff).
unit.Wait = 10;
return 0;
}
// Place unit inside the resource
//Wyrmgus start
// if (!resinfo.HarvestFromOutside) {
if (!goal->Type->BoolFlag[HARVESTFROMOUTSIDE_INDEX].value) {
//Wyrmgus end
if (goal->Variable[MAXHARVESTERS_INDEX].Value == 0 || goal->Variable[MAXHARVESTERS_INDEX].Value > goal->InsideCount) {
this->ClearGoal();
int selected = unit.Selected;
unit.Remove(goal);
if (selected && !Preference.DeselectInMine) {
unit.Removed = 0;
SelectUnit(unit);
SelectionChanged();
unit.Removed = 1;
}
} else if (goal->Variable[MAXHARVESTERS_INDEX].Value <= goal->InsideCount) {
//Resource is full, wait
unit.Wait = 10;
return 0;
}
}
if (this->CurrentResource != unit.CurrentResource) {
DropResource(unit);
//.........这里部分代码省略.........
示例11: AnimateActionHarvest
/**
** Gather the resource
**
** @param unit Pointer to unit.
**
** @return non-zero if ready, otherwise zero.
*/
int COrder_Resource::GatherResource(CUnit &unit)
{
CUnit *source = 0;
const ResourceInfo &resinfo = *unit.Type->ResInfo[this->CurrentResource];
int addload;
//Wyrmgus start
bool harvest_from_outside = (this->GetGoal() && this->GetGoal()->Type->BoolFlag[HARVESTFROMOUTSIDE_INDEX].value);
// if (resinfo.HarvestFromOutside || resinfo.TerrainHarvester) {
if (harvest_from_outside || Map.Info.IsPointOnMap(this->goalPos)) {
//Wyrmgus end
AnimateActionHarvest(unit);
} else {
unit.Anim.CurrAnim = NULL;
}
this->TimeToHarvest--;
if (this->DoneHarvesting) {
//Wyrmgus start
// Assert(resinfo.HarvestFromOutside || resinfo.TerrainHarvester);
Assert(harvest_from_outside || Map.Info.IsPointOnMap(this->goalPos));
//Wyrmgus end
return !unit.Anim.Unbreakable;
}
// Target gone?
//Wyrmgus start
// if (resinfo.TerrainHarvester && !Map.Field(this->goalPos)->IsTerrainResourceOnMap(this->CurrentResource)) {
if (Map.Info.IsPointOnMap(this->goalPos) && !Map.Field(this->goalPos)->IsTerrainResourceOnMap(this->CurrentResource)) {
//Wyrmgus end
if (!unit.Anim.Unbreakable) {
// Action now breakable, move to resource again.
this->State = SUB_MOVE_TO_RESOURCE;
// Give it some reasonable look while searching.
// FIXME: which frame?
unit.Frame = 0;
}
return 0;
// No wood? Freeze!!!
}
while (!this->DoneHarvesting && this->TimeToHarvest < 0) {
//FIXME: rb - how should it look for WaitAtResource == 0
if (resinfo.WaitAtResource) {
// Wyrmgus start
// this->TimeToHarvest += std::max<int>(1, resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId]);
int wait_at_resource = resinfo.WaitAtResource;
int resource_harvest_speed = unit.Player->SpeedResourcesHarvest[resinfo.ResourceId];
if (!Map.Info.IsPointOnMap(this->goalPos) && !harvest_from_outside) {
wait_at_resource = resinfo.WaitAtResource * 100 / resinfo.ResourceStep;
}
if (this->GetGoal()) {
resource_harvest_speed += this->GetGoal()->Variable[TIMEEFFICIENCYBONUS_INDEX].Value;
}
this->TimeToHarvest += std::max<int>(1, wait_at_resource * SPEEDUP_FACTOR / resource_harvest_speed);
//Wyrmgus end
} else {
this->TimeToHarvest += 1;
}
// Calculate how much we can load.
//Wyrmgus start
// if (resinfo.ResourceStep) {
if (resinfo.ResourceStep && (harvest_from_outside || Map.Info.IsPointOnMap(this->goalPos))) {
//Wyrmgus end
addload = resinfo.ResourceStep;
} else {
addload = resinfo.ResourceCapacity;
}
// Make sure we don't bite more than we can chew.
if (unit.ResourcesHeld + addload > resinfo.ResourceCapacity) {
addload = resinfo.ResourceCapacity - unit.ResourcesHeld;
}
//Wyrmgus start
// if (resinfo.TerrainHarvester) {
if (Map.Info.IsPointOnMap(this->goalPos)) {
//Wyrmgus end
//Wyrmgus start
CMapField &mf = *Map.Field(this->goalPos);
if (addload > mf.Value) {
addload = mf.Value;
}
mf.Value -= addload;
//Wyrmgus end
unit.ResourcesHeld += addload;
//Wyrmgus start
// if (addload && unit.ResourcesHeld == resinfo.ResourceCapacity) {
if (mf.Value <= 0) {
//Wyrmgus end
//Wyrmgus start
//.........这里部分代码省略.........
示例12: Execute
/**
** Control the unit action: getting a resource.
**
** This the generic function for oil, gold, ...
**
** @param unit Pointer to unit.
*/
void COrder_Resource::Execute(CUnit &unit)
{
// can be different by Cloning (trained unit)...
this->worker = &unit;
if (unit.Wait) {
if (!unit.Waiting) {
unit.Waiting = 1;
unit.WaitBackup = unit.Anim;
}
//Wyrmgus start
// UnitShowAnimation(unit, unit.Type->Animations->Still);
UnitShowAnimation(unit, unit.GetAnimations()->Still);
//Wyrmgus end
unit.Wait--;
return;
}
if (unit.Waiting) {
unit.Anim = unit.WaitBackup;
unit.Waiting = 0;
}
// Let's start mining.
if (this->State == SUB_START_RESOURCE) {
if (ActionResourceInit(unit) == false) {
ResourceGiveUp(unit);
return;
}
}
// Move to the resource location.
if (SUB_MOVE_TO_RESOURCE <= this->State && this->State < SUB_UNREACHABLE_RESOURCE) {
const int ret = MoveToResource(unit);
switch (ret) {
case -1: { // Can't Reach
this->State++;
unit.Wait = 5;
return;
}
case 1: { // Reached
this->State = SUB_START_GATHERING;
break;
}
case 0: // Move along.
return;
default: {
Assert(0);
break;
}
}
}
// Resource seems to be unreachable
if (this->State == SUB_UNREACHABLE_RESOURCE) {
if (this->FindAnotherResource(unit) == false) {
ResourceGiveUp(unit);
return;
}
}
// Start gathering the resource
if (this->State == SUB_START_GATHERING) {
if (StartGathering(unit)) {
this->State = SUB_GATHER_RESOURCE;
} else {
return;
}
}
// Gather the resource.
if (this->State == SUB_GATHER_RESOURCE) {
if (GatherResource(unit)) {
this->State = SUB_STOP_GATHERING;
} else {
return;
}
}
// Stop gathering the resource.
if (this->State == SUB_STOP_GATHERING) {
if (StopGathering(unit)) {
this->State = SUB_MOVE_TO_DEPOT;
unit.pathFinderData->output.Cycles = 0; //moving counter
} else {
return;
}
}
// Move back home.
if (SUB_MOVE_TO_DEPOT <= this->State && this->State < SUB_UNREACHABLE_DEPOT) {
const int ret = MoveToDepot(unit);
//.........这里部分代码省略.........
示例13: ResourceDepositOnMap
/**
** Wait in depot, for the resources stored.
**
** @param unit Pointer to unit.
**
** @return TRUE if ready, otherwise FALSE.
*/
bool COrder_Resource::WaitInDepot(CUnit &unit)
{
const ResourceInfo &resinfo = *unit.Type->ResInfo[this->CurrentResource];
const CUnit *depot = ResourceDepositOnMap(unit.tilePos, resinfo.ResourceId);
//Assert(depot);
// Range hardcoded. don't stray too far though
//Wyrmgus start
// if (resinfo.TerrainHarvester) {
if (!this->Resource.Mine) {
//Wyrmgus end
Vec2i pos = this->Resource.Pos;
//Wyrmgus start
// if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 10, *unit.Player, pos, &pos)) {
if ((this->CurrentResource == WoodCost && FindTerrainType(unit.Type->MovementMask, MapFieldForest, 10, *unit.Player, pos, &pos)) || (this->CurrentResource == StoneCost && FindTerrainType(unit.Type->MovementMask, MapFieldRocks, 10, *unit.Player, pos, &pos))) {
//Wyrmgus end
if (depot) {
DropOutNearest(unit, pos, depot);
}
this->goalPos = pos;
//Wyrmgus start
if (this->CurrentResource == WoodCost) { //tree tiles can regrow, so we need to check if any have regrown closer to the worker
Vec2i forestPos;
int max_forest_range = std::max<int>(abs(unit.tilePos.x - this->goalPos.x), abs(unit.tilePos.y - this->goalPos.y));
if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, max_forest_range, *unit.Player, unit.tilePos, &forestPos)) {
if (PlaceReachable(unit, forestPos, 1, 1, 0, 1, max_forest_range * 4)) {
this->goalPos = forestPos;
}
}
}
//Wyrmgus end
} else {
if (depot) {
DropOutOnSide(unit, LookingW, depot);
}
this->Finished = true;
return false;
}
} else {
const unsigned int tooManyWorkers = 15;
CUnit *mine = this->Resource.Mine;
const int range = 15;
CUnit *newdepot = NULL;
CUnit *goal = NULL;
const bool longWay = unit.pathFinderData->output.Cycles > 500;
//Wyrmgus start
// if (unit.Player->AiEnabled && AiPlayer && AiPlayer->BuildDepots) {
if (depot && unit.Player->AiEnabled && AiPlayer && AiPlayer->BuildDepots) { //check if the depot is valid
//Wyrmgus end
// If the depot is overused, we need first to try to switch into another depot
// Use depot's ref counter for that
if (longWay || !mine || (depot->Refs > tooManyWorkers)) {
newdepot = AiGetSuitableDepot(unit, *depot, &goal);
if (newdepot == NULL && longWay) {
// We need a new depot
AiNewDepotRequest(unit);
}
}
}
// If goal is not NULL, then we got it in AiGetSuitableDepot
if (!goal) {
goal = UnitFindResource(unit, newdepot ? *newdepot : (mine ? *mine : unit), mine ? range : 1000,
this->CurrentResource, unit.Player->AiEnabled, newdepot ? newdepot : depot);
}
if (goal) {
if (depot) {
DropOutNearest(unit, goal->tilePos + goal->Type->GetHalfTileSize(), depot);
}
if (goal != mine) {
if (mine) {
unit.DeAssignWorkerFromMine(*mine);
}
unit.AssignWorkerToMine(*goal);
this->Resource.Mine = goal;
}
this->SetGoal(goal);
this->goalPos.x = this->goalPos.y = -1;
} else {
#ifdef DEBUG
const Vec2i &pos = mine ? mine->tilePos : unit.tilePos;
DebugPrint("%d: Worker %d report: [%d,%d] Resource gone near [%d,%d] in range %d. Sit and play dumb.\n"
_C_ unit.Player->Index _C_ UnitNumber(unit)
_C_ unit.tilePos.x _C_ unit.tilePos.y
_C_ pos.x _C_ pos.y _C_ range);
#endif // DEBUG
if (depot) {
DropOutOnSide(unit, LookingW, depot);
//.........这里部分代码省略.........
示例14: PROFILE
void CFactory::CreateComputerUnit(int nType)
{
PROFILE("CFactory::CreateComputerUnit(int)");
//static float xPos = 100;
//static float yPos = 50;
CUnit* unit = new CUnit(nType);
// Use default shallow copy since no dynamic info in creation
CUnit temp = CGame::GetInstance()->GetCPUUnitInfo(nType);
unit->SetAttackPower(temp.GetAttackPower());
unit->SetAttackSpeed(temp.GetAttackSpeed());
unit->SetMaxHP(temp.GetMaxHP());
unit->SetCurrentHP(temp.GetMaxHP());
unit->SetRange(temp.GetRange());
unit->SetSpeed(temp.GetSpeed());
unit->SetState(IDLE);
unit->SetDirection(NORTH_WEST);
unit->SetIsPlayerUnit(false);
// Register Events
unit->SetAttackSoundID(CGame::GetInstance()->GetAttackSound(unit->GetType()));
unit->SetDeathSoundID(CGame::GetInstance()->GetDeathSound(unit->GetType()));
switch(CGame::GetInstance()->GetSelectedCity()->GetID())
{
case KCITY1:
break;
case KCITY2:
unit->SetAttackPower(unit->GetAttackPower()+2);
break;
case KCITY3:
unit->SetAttackPower(unit->GetAttackPower()+2);
unit->SetAttackSpeed(unit->GetAttackSpeed()-(unit->GetAttackSpeed()*.2f));
unit->SetSpeed(unit->GetSpeed()-(unit->GetSpeed()*.5f));
break;
case XCITY1:
break;
case XCITY2:
unit->SetAttackPower(unit->GetAttackPower()+2);
break;
case XCITY3:
unit->SetAttackPower(unit->GetAttackPower()+2);
unit->SetAttackSpeed(unit->GetAttackSpeed()-(unit->GetAttackSpeed()*.2f));
unit->SetSpeed(unit->GetSpeed()-(unit->GetSpeed()*.5f));
break;
case JCITY1:
break;
case JCITY2:
unit->SetAttackPower(unit->GetAttackPower()+2);
break;
case JCITY3:
unit->SetAttackPower(unit->GetAttackPower()+2);
unit->SetAttackSpeed(unit->GetAttackSpeed()-(unit->GetAttackSpeed()*.2f));
unit->SetSpeed(unit->GetSpeed()-(unit->GetSpeed()*.5f));
break;
}
// Add to manager
ObjectManager::GetInstance()->AddObject(unit);
// Let it know we aren't hanging on to it
unit->Release();
STOP("CFactory::CreateComputerUnit(int)");
}
示例15: StopBuild
bool CBuilder::StartBuild(BuildInfo& buildInfo, CFeature*& feature, bool& waitStance)
{
StopBuild(false);
TempHoldFire(-1);
buildInfo.pos = CGameHelper::Pos2BuildPos(buildInfo, true);
// Pass -1 as allyteam to behave like we have maphack.
// This is needed to prevent building on top of cloaked stuff.
const CGameHelper::BuildSquareStatus tbs = CGameHelper::TestUnitBuildSquare(buildInfo, feature, -1, true);
switch (tbs) {
case CGameHelper::BUILDSQUARE_OPEN:
break;
case CGameHelper::BUILDSQUARE_BLOCKED:
case CGameHelper::BUILDSQUARE_OCCUPIED: {
// the ground is blocked at the position we want
// to build at; check if the blocking object is
// of the same type as our buildee (which means
// another builder has already started it)
// note: even if construction has already started,
// the buildee is *not* guaranteed to be the unit
// closest to us
CSolidObject* o = groundBlockingObjectMap->GroundBlocked(buildInfo.pos);
CUnit* u = NULL;
if (o != NULL) {
u = dynamic_cast<CUnit*>(o);
} else {
// <pos> might map to a non-blocking portion
// of the buildee's yardmap, fallback check
u = CGameHelper::GetClosestFriendlyUnit(NULL, buildInfo.pos, buildDistance, allyteam);
}
if (u != NULL && CanAssistUnit(u, buildInfo.def)) {
curBuild = u;
AddDeathDependence(u, DEPENDENCE_BUILD);
ScriptStartBuilding(u->pos, false);
return true;
}
return false;
}
case CGameHelper::BUILDSQUARE_RECLAIMABLE:
// caller should handle this
return false;
}
if ((waitStance = !ScriptStartBuilding(buildInfo.pos, true))) {
return false;
}
const UnitDef* buildeeDef = buildInfo.def;
const UnitLoadParams buildeeParams = {buildeeDef, this, buildInfo.pos, ZeroVector, -1, team, buildInfo.buildFacing, true, false};
CUnit* buildee = unitLoader->LoadUnit(buildeeParams);
// floating structures don't terraform the seabed
const float groundheight = CGround::GetHeightReal(buildee->pos.x, buildee->pos.z);
const bool onWater = (buildeeDef->floatOnWater && groundheight <= 0.0f);
if (mapDamage->disabled || !buildeeDef->levelGround || onWater ||
buildeeDef->IsAirUnit() || !buildeeDef->IsImmobileUnit()
) {
// skip the terraforming job
buildee->terraformLeft = 0;
buildee->groundLevelled = true;
} else {
tx1 = (int)max( 0.0f, (buildee->pos.x - (buildeeDef->xsize * 0.5f * SQUARE_SIZE)) / SQUARE_SIZE);
tx2 = min(gs->mapx, tx1 + buildeeDef->xsize );
tz1 = (int)max( 0.0f, (buildee->pos.z - (buildeeDef->zsize * 0.5f * SQUARE_SIZE)) / SQUARE_SIZE);
tz2 = min(gs->mapy, tz1 + buildeeDef->zsize );
buildee->terraformLeft = CalculateBuildTerraformCost(buildInfo);
buildee->groundLevelled = false;
terraforming = true;
terraformType = Terraform_Building;
terraformRadius = (tx2 - tx1) * SQUARE_SIZE;
terraformCenter = buildee->pos;
}
if (!this->unitDef->canBeAssisted) {
buildee->soloBuilder = this;
buildee->AddDeathDependence(this, DEPENDENCE_BUILDER);
}
AddDeathDependence(buildee, DEPENDENCE_BUILD);
curBuild = buildee;
/* The ground isn't going to be terraformed.
* When the building is completed, it'll 'pop'
* into the correct height for the (un-flattened)
* terrain it's on.
*
* To prevent this visual artifact, put the building
* at the 'right' height to begin with.
*/
//.........这里部分代码省略.........