CTAAirMoveType::CTAAirMoveType(CUnit* owner) : AAirMoveType(owner), flyState(FLY_CRUISING), loadingUnits(false), bankingAllowed(true), orgWantedHeight(0.0f), circlingPos(ZeroVector), goalDistance(1), waitCounter(0), wantToStop(false), // we want to take off in direction of factory facing wantedHeading(owner? GetHeadingFromFacing(owner->buildFacing): 0), wantedSpeed(ZeroVector), deltaSpeed(ZeroVector), currentBank(0), currentPitch(0), turnRate(1), accRate(1), decRate(1), altitudeRate(3.0f), brakeDistance(1), dontLand(false), lastMoveRate(0), forceHeading(false), forceHeadingTo(wantedHeading), maxDrift(1) { if (owner) { owner->dontUseWeapons = true; } }
float CTransportUnit::GetLoadUnloadHeading(const CUnit* unit) const { if (unit->transporter == NULL) { return unit->heading; } if (dynamic_cast<CHoverAirMoveType*>(moveType) == NULL) { return unit->heading; } if (dynamic_cast<const CBuilding*>(unit) == NULL) { return unit->heading; } // transported structures want to face a cardinal direction return (GetHeadingFromFacing(unit->buildFacing)); }
void CBuilding::ForcedMove(const float3& newPos, int facing) { buildFacing = facing; pos = helper->Pos2BuildPos(BuildInfo(unitDef, newPos, buildFacing)); speed = ZeroVector; heading = GetHeadingFromFacing(buildFacing); frontdir = GetVectorFromHeading(heading); CUnit::ForcedMove(pos); unitLoader.FlattenGround(this); }
void CBuilding::ForcedMove(const float3& newPos) { heading = GetHeadingFromFacing(buildFacing); frontdir = GetVectorFromHeading(heading); SetVelocity(ZeroVector); Move(CGameHelper::Pos2BuildPos(BuildInfo(unitDef, newPos, buildFacing), true), false); UpdateMidAndAimPos(); CUnit::ForcedMove(pos); unitLoader->FlattenGround(this); }
void CBuilding::ForcedMove(const float3& newPos) { // heading might have changed if building was dropped from transport // (always needs to be axis-aligned because yardmaps are not rotated) heading = GetHeadingFromFacing(buildFacing); UpdateDirVectors(false); SetVelocity(ZeroVector); // update quadfield, etc. CUnit::ForcedMove(CGameHelper::Pos2BuildPos(BuildInfo(unitDef, newPos, buildFacing), true)); unitLoader->FlattenGround(this); }
CHoverAirMoveType::CHoverAirMoveType(CUnit* owner) : AAirMoveType(owner), flyState(FLY_CRUISING), bankingAllowed(true), airStrafe(owner != nullptr ? owner->unitDef->airStrafe : false), wantToStop(false), goalDistance(1), // we want to take off in direction of factory facing currentBank(0), currentPitch(0), turnRate(1), maxDrift(1.0f), maxTurnAngle(math::cos((owner != nullptr ? owner->unitDef->turnInPlaceAngleLimit : 0.0f) * (PI / 180.0f)) * -1.0f), wantedSpeed(ZeroVector), deltaSpeed(ZeroVector), circlingPos(ZeroVector), randomWind(ZeroVector), forceHeading(false), dontLand(false), wantedHeading(owner != nullptr ? GetHeadingFromFacing(owner->buildFacing) : 0), forceHeadingTo(wantedHeading), waitCounter(0), lastMoveRate(0) { // creg if (owner == nullptr) return; assert(owner->unitDef != nullptr); turnRate = owner->unitDef->turnRate; wantedHeight = owner->unitDef->wantedHeight + gs->randFloat() * 5.0f; orgWantedHeight = wantedHeight; dontLand = owner->unitDef->DontLand(); collide = owner->unitDef->collide; bankingAllowed = owner->unitDef->bankingAllowed; useSmoothMesh = owner->unitDef->useSmoothMesh; // prevent weapons from being updated and firing while on the ground owner->dontUseWeapons = true; }
CHoverAirMoveType::CHoverAirMoveType(CUnit* owner) : AAirMoveType(owner), flyState(FLY_CRUISING), loadingUnits(false), bankingAllowed(true), airStrafe(owner->unitDef->airStrafe), circlingPos(ZeroVector), goalDistance(1), waitCounter(0), wantToStop(false), // we want to take off in direction of factory facing wantedHeading(GetHeadingFromFacing(owner->buildFacing)), wantedSpeed(ZeroVector), deltaSpeed(ZeroVector), currentBank(0), currentPitch(0), turnRate(1), accRate(1), decRate(1), altitudeRate(3.0f), brakeDistance(1), dontLand(false), lastMoveRate(0), forceHeading(false), forceHeadingTo(wantedHeading), maxDrift(1) { assert(owner != NULL); assert(owner->unitDef != NULL); turnRate = owner->unitDef->turnRate; accRate = std::max(0.01f, owner->unitDef->maxAcc); decRate = std::max(0.01f, owner->unitDef->maxDec); wantedHeight = owner->unitDef->wantedHeight + gs->randFloat() * 5.0f; orgWantedHeight = wantedHeight; dontLand = owner->unitDef->DontLand(); collide = owner->unitDef->collide; altitudeRate = owner->unitDef->verticalSpeed; bankingAllowed = owner->unitDef->bankingAllowed; useSmoothMesh = owner->unitDef->useSmoothMesh; // prevent weapons from being updated and firing while on the ground owner->dontUseWeapons = true; }
void CFactory::UpdateBuild(CUnit* buildee) { if (stunned) return; // factory not under construction and // nanolathing unit: continue building lastBuildUpdateFrame = gs->frameNum; // buildPiece is the rotating platform const int buildPiece = GetBuildPiece(); const float3& buildPos = CalcBuildPos(buildPiece); const CMatrix44f& mat = script->GetPieceMatrix(buildPiece); const int h = GetHeadingFromVector(mat[2], mat[10]); //! x.z, z.z float3 buildeePos = buildPos; // rotate unit nanoframe with platform buildee->heading = (-h + GetHeadingFromFacing(buildFacing)) & (SPRING_CIRCLE_DIVS - 1); if (buildee->unitDef->floatOnWater && (buildeePos.y <= 0.0f)) buildeePos.y = -buildee->unitDef->waterline; buildee->Move3D(buildeePos, false); buildee->UpdateDirVectors(false); buildee->UpdateMidAndAimPos(); const CCommandQueue& queue = commandAI->commandQue; if (!queue.empty() && (queue.front().GetID() == CMD_WAIT)) { buildee->AddBuildPower(0, this); } else { if (buildee->AddBuildPower(buildSpeed, this)) { CreateNanoParticle(); } } }
void CFactory::Update() { if (beingBuilt) { // factory under construction CUnit::Update(); return; } if (quedBuild && !opening && !stunned) { script->Activate(); groundBlockingObjectMap->OpenBlockingYard(this, curYardMap); opening = true; } if (quedBuild && inBuildStance && !stunned) { // start building a unit const float3 buildPos = CalcBuildPos(); const CSolidObject* solidObj = groundBlockingObjectMap->GroundBlocked(buildPos); if (solidObj == NULL || (dynamic_cast<const CUnit*>(solidObj) == this)) { quedBuild = false; CUnit* b = unitLoader.LoadUnit(nextBuild, buildPos + float3(0.01f, 0.01f, 0.01f), team, true, buildFacing, this); if (!unitDef->canBeAssisted) { b->soloBuilder = this; b->AddDeathDependence(this); } AddDeathDependence(b); curBuild = b; script->StartBuilding(); int soundIdx = unitDef->sounds.build.getRandomIdx(); if (soundIdx >= 0) { Channels::UnitReply.PlaySample( unitDef->sounds.build.getID(soundIdx), pos, unitDef->sounds.build.getVolume(0)); } } else { helper->BuggerOff(buildPos - float3(0.01f, 0, 0.02f), radius + 8, true, true, NULL); } } if (curBuild && !beingBuilt) { if (!stunned) { // factory not under construction and // nanolathing unit: continue building lastBuild = gs->frameNum; // buildPiece is the rotating platform const int buildPiece = GetBuildPiece(); const CMatrix44f& mat = script->GetPieceMatrix(buildPiece); const int h = GetHeadingFromVector(mat[2], mat[10]); //! x.z, z.z // rotate unit nanoframe with platform curBuild->heading = (h + GetHeadingFromFacing(buildFacing)) & 65535; const float3 buildPos = CalcBuildPos(buildPiece); curBuild->pos = buildPos; if (curBuild->floatOnWater) { float waterline = ground->GetHeight(buildPos.x, buildPos.z) - curBuild->unitDef->waterline; if (waterline > curBuild->pos.y) curBuild->pos.y = waterline; } curBuild->midPos = curBuild->pos + (UpVector * curBuild->relMidPos.y); const CCommandQueue& queue = commandAI->commandQue; if(!queue.empty() && (queue.front().id == CMD_WAIT)) { curBuild->AddBuildPower(0, this); } else { if (curBuild->AddBuildPower(buildSpeed, this)) { CreateNanoParticle(); } } } if (!curBuild->beingBuilt && (!unitDef->fullHealthFactory || (curBuild->health >= curBuild->maxHealth))) { if (group && curBuild->group == 0) { curBuild->SetGroup(group); } bool userOrders = true; if (curBuild->commandAI->commandQue.empty() || (dynamic_cast<CMobileCAI*>(curBuild->commandAI) && ((CMobileCAI*)curBuild->commandAI)->unimportantMove)) { userOrders = false; AssignBuildeeOrders(curBuild); waitCommandsAI.AddLocalUnit(curBuild, this); } eventHandler.UnitFromFactory(curBuild, this, userOrders); StopBuild(); } } if (((lastBuild + 200) < gs->frameNum) && !stunned && !quedBuild && opening && groundBlockingObjectMap->CanCloseYard(this)) { // close the factory after inactivity groundBlockingObjectMap->CloseBlockingYard(this, curYardMap); opening = false; script->Deactivate(); } CBuilding::Update(); }
CUnit* CUnitLoader::LoadUnit(const UnitDef* ud, float3 pos, int team, bool build, int facing, const CUnit* builder) { GML_RECMUTEX_LOCK(sel); // LoadUnit - for anti deadlock purposes. GML_RECMUTEX_LOCK(quad); // LoadUnit - make sure other threads cannot access an incomplete unit SCOPED_TIMER("Unit loader"); CUnit* unit; std::string type = ud->type; // clamp to map if (pos.x < 0) pos.x = 0; if (pos.x >= gs->mapx * SQUARE_SIZE) pos.x = gs->mapx-1; if (pos.z < 0) pos.z = 0; if (pos.z >= gs->mapy * SQUARE_SIZE) pos.z = gs->mapy-1; if (!build) { pos.y = ground->GetHeight2(pos.x, pos.z); if (ud->floater && pos.y < 0.0f) { // adjust to waterline iif we are submerged pos.y = -ud->waterline; } } if (team < 0) { team = teamHandler->GaiaTeamID(); // FIXME use gs->gaiaTeamID ? (once it is always enabled) if (team < 0) throw content_error("Invalid team and no gaia team to put unit in"); } if (type == "GroundUnit") { unit = new CUnit; } else if (type == "Transport") { unit = new CTransportUnit; } else if (type == "Building") { unit = new CBuilding; } else if (type == "Factory") { unit = new CFactory; } else if (type == "Builder") { unit = new CBuilder; } else if (type == "Bomber" || type == "Fighter") { unit = new CUnit; } else if (type == "MetalExtractor") { unit = new CExtractorBuilding; } else { LogObject() << "Unknown unit type " << type.c_str() << "\n"; return NULL; } unit->UnitInit(ud, team, pos); unit->beingBuilt = build; unit->buildFacing = abs(facing) % 4; unit->xsize = ((unit->buildFacing & 1) == 0) ? ud->xsize : ud->zsize; unit->zsize = ((unit->buildFacing & 1) == 1) ? ud->xsize : ud->zsize; unit->power = ud->power; unit->maxHealth = ud->health; unit->health = ud->health; //unit->metalUpkeep = ud->metalUpkeep*16.0f/GAME_SPEED; //unit->energyUpkeep = ud->energyUpkeep*16.0f/GAME_SPEED; unit->controlRadius = (int)(ud->controlRadius / SQUARE_SIZE); unit->losHeight = ud->losHeight; unit->metalCost = ud->metalCost; unit->energyCost = ud->energyCost; unit->buildTime = ud->buildTime; unit->aihint = ud->aihint; unit->tooltip = ud->humanName + " - " + ud->tooltip; unit->armoredMultiple = std::max(0.0001f, ud->armoredMultiple); //armored multiple of 0 will crash spring unit->wreckName = ud->wreckName; unit->realLosRadius = (int) (ud->losRadius); unit->realAirLosRadius = (int) (ud->airLosRadius); unit->upright = ud->upright; unit->radarRadius = ud->radarRadius / (SQUARE_SIZE * 8); unit->sonarRadius = ud->sonarRadius / (SQUARE_SIZE * 8); unit->jammerRadius = ud->jammerRadius / (SQUARE_SIZE * 8); unit->sonarJamRadius = ud->sonarJamRadius / (SQUARE_SIZE * 8); unit->seismicRadius = ud->seismicRadius / (SQUARE_SIZE * 8); unit->seismicSignature = ud->seismicSignature; unit->hasRadarCapacity = unit->radarRadius || unit->sonarRadius || unit->jammerRadius || unit->sonarJamRadius || unit->seismicRadius; unit->stealth = ud->stealth; unit->sonarStealth = ud->sonarStealth; unit->category = ud->category; unit->armorType = ud->armorType; unit->floatOnWater = ud->floater || (ud->movedata && ((ud->movedata->moveType == MoveData::Hover_Move) || (ud->movedata->moveType == MoveData::Ship_Move))); unit->maxSpeed = ud->speed / GAME_SPEED; unit->decloakDistance = ud->decloakDistance; unit->flankingBonusMode = ud->flankingBonusMode; unit->flankingBonusDir = ud->flankingBonusDir; unit->flankingBonusMobility = ud->flankingBonusMobilityAdd * 1000; unit->flankingBonusMobilityAdd = ud->flankingBonusMobilityAdd; unit->flankingBonusAvgDamage = (ud->flankingBonusMax + ud->flankingBonusMin) * 0.5f; unit->flankingBonusDifDamage = (ud->flankingBonusMax - ud->flankingBonusMin) * 0.5f; if(ud->highTrajectoryType==1) unit->useHighTrajectory=true; if(ud->fireState >= 0) unit->fireState = ud->fireState; if(build){ unit->ChangeLos(1,1); unit->health=0.1f; } else { unit->ChangeLos((int)(ud->losRadius),(int)(ud->airLosRadius)); } if (type == "GroundUnit") { new CMobileCAI(unit); } else if (type == "Transport") { new CTransportCAI(unit); } else if (type == "Factory") { new CFactoryCAI(unit); } else if (type == "Builder") { new CBuilderCAI(unit); } else if (type == "Bomber") { if (ud->hoverAttack) { new CMobileCAI(unit); } else { new CAirCAI(unit); } } else if(type == "Fighter"){ if (ud->hoverAttack) { new CMobileCAI(unit); } else { new CAirCAI(unit); } } else { new CCommandAI(unit); } if (ud->canmove && !ud->canfly && (type != "Factory")) { CGroundMoveType* mt = new CGroundMoveType(unit); mt->maxSpeed = ud->speed / GAME_SPEED; mt->maxWantedSpeed = ud->speed / GAME_SPEED; mt->turnRate = ud->turnRate; mt->baseTurnRate = ud->turnRate; if (mt->accRate <= 0.0f) { LogObject() << "acceleration of unit-type " << ud->name.c_str() << " is zero or negative!\n"; mt->accRate = 0.01f; } mt->accRate = ud->maxAcc; mt->decRate = ud->maxDec; mt->floatOnWater = (ud->movedata->moveType == MoveData::Hover_Move || ud->movedata->moveType == MoveData::Ship_Move); if (!unit->beingBuilt) { // otherwise set this when finished building instead unit->mass = ud->mass; } unit->moveType = mt; // Ground-mobility unit->mobility = new MoveData(ud->movedata); } else if (ud->canfly) { // Air-mobility unit->mobility = new MoveData(ud->movedata); if (!unit->beingBuilt) { // otherwise set this when finished building instead unit->mass = ud->mass; } if ((type == "Builder") || ud->hoverAttack || ud->transportCapacity) { CTAAirMoveType* mt = new CTAAirMoveType(unit); mt->turnRate = ud->turnRate; mt->maxSpeed = ud->speed / GAME_SPEED; mt->accRate = ud->maxAcc; mt->decRate = ud->maxDec; mt->wantedHeight = ud->wantedHeight + gs->randFloat() * 5; mt->orgWantedHeight = mt->wantedHeight; mt->dontLand = ud->DontLand(); mt->collide = ud->collide; mt->altitudeRate = ud->verticalSpeed; mt->bankingAllowed = ud->bankingAllowed; unit->moveType = mt; } else { CAirMoveType *mt = new CAirMoveType(unit); if(type=="Fighter") mt->isFighter=true; mt->collide = ud->collide; mt->wingAngle = ud->wingAngle; mt->crashDrag = 1 - ud->crashDrag; mt->invDrag = 1 - ud->drag; mt->frontToSpeed = ud->frontToSpeed; mt->speedToFront = ud->speedToFront; mt->myGravity = ud->myGravity; mt->maxBank = ud->maxBank; mt->maxPitch = ud->maxPitch; mt->turnRadius = ud->turnRadius; mt->wantedHeight = (ud->wantedHeight * 1.5f) + ((gs->randFloat() - 0.3f) * 15 * (mt->isFighter ? 2 : 1)); mt->maxAcc = ud->maxAcc; mt->maxAileron = ud->maxAileron; mt->maxElevator = ud->maxElevator; mt->maxRudder = ud->maxRudder; unit->moveType = mt; } } else { unit->moveType = new CMoveType(unit); unit->upright = true; } unit->energyTickMake = ud->energyMake; if (ud->tidalGenerator > 0) unit->energyTickMake += ud->tidalGenerator * mapInfo->map.tidalStrength; unit->model = ud->LoadModel(); unit->SetRadius(unit->model->radius); modelParser->CreateLocalModel(unit); // copy the UnitDef volume instance // // aircraft still get half-size spheres for coldet purposes // iif no custom volume is defined (unit->model->radius and // unit->radius themselves are no longer altered) unit->collisionVolume = new CollisionVolume(ud->collisionVolume, unit->model->radius * ((ud->canfly)? 0.5f: 1.0f)); if (unit->model->radius <= 60.0f) { // the interval-based method fails too easily for units // with small default volumes, force use of raytracing unit->collisionVolume->SetTestType(COLVOL_TEST_CONT); } if (ud->floater) { // restrict our depth to our waterline unit->pos.y = std::max(-ud->waterline, ground->GetHeight2(unit->pos.x, unit->pos.z)); } else { unit->pos.y = ground->GetHeight2(unit->pos.x, unit->pos.z); } unit->script = CUnitScriptFactory::CreateScript(ud->scriptPath, unit); unit->weapons.reserve(ud->weapons.size()); for (unsigned int i = 0; i < ud->weapons.size(); i++) { unit->weapons.push_back(LoadWeapon(ud->weapons[i].def, unit, &ud->weapons[i])); } // Call initializing script functions unit->script->Create(); unit->heading = GetHeadingFromFacing(facing); unit->frontdir = GetVectorFromHeading(unit->heading); unit->updir = UpVector; unit->rightdir = unit->frontdir.cross(unit->updir); unit->yardMap = ud->yardmaps[facing]; unit->Init(builder); if (!build) { unit->FinishedBuilding(); } return unit; }
CUnit* CUnitLoader::LoadUnit(const string& name, float3 pos, int team, bool build, int facing, const CUnit* builder) { // GML_RECMUTEX_LOCK(unit); // LoadUnit. Unitinit puts unit in the quadfield and activeUnits - GML_RECMUTEX_LOCK(sel); // LoadUnit. For anti deadlock purposes. GML_RECMUTEX_LOCK(quad); // LoadUnit. - make sure other threads cannot access an incomplete unit CUnit* unit; SCOPED_TIMER("Unit loader"); const UnitDef* ud = unitDefHandler->GetUnitByName(name); if (!ud) { throw content_error("Couldn't find unittype " + name); } string type = ud->type; if (!build) { pos.y = ground->GetHeight2(pos.x, pos.z); if (ud->floater && pos.y < 0.0f) { // adjust to waterline iif we are submerged pos.y = -ud->waterline; } } if (team < 0) { team = MAX_TEAMS - 1; // FIXME use gs->gaiaTeamID ? (once it is always enabled) } if (type == "GroundUnit") { unit = SAFE_NEW CUnit; } else if (type == "Transport") { unit = SAFE_NEW CTransportUnit; } else if (type == "Building") { unit = SAFE_NEW CBuilding; } else if (type == "Factory") { unit = SAFE_NEW CFactory; } else if (type == "Builder") { unit = SAFE_NEW CBuilder; } else if (type == "Bomber" || type == "Fighter") { unit = SAFE_NEW CUnit; } else if (type == "MetalExtractor") { unit = SAFE_NEW CExtractorBuilding; } else { logOutput << "Unknown unit type " << type.c_str() << "\n"; return NULL; } unit->UnitInit(ud, team, pos); unit->beingBuilt = build; unit->xsize = ((facing & 1) == 0) ? ud->xsize : ud->zsize; unit->zsize = ((facing & 1) == 1) ? ud->xsize : ud->zsize; unit->buildFacing = facing; unit->power = ud->power; unit->maxHealth = ud->health; unit->health = ud->health; //unit->metalUpkeep = ud->metalUpkeep*16.0f/GAME_SPEED; //unit->energyUpkeep = ud->energyUpkeep*16.0f/GAME_SPEED; unit->controlRadius = (int)(ud->controlRadius / SQUARE_SIZE); unit->losHeight = ud->losHeight; unit->metalCost = ud->metalCost; unit->energyCost = ud->energyCost; unit->buildTime = ud->buildTime; unit->aihint = ud->aihint; unit->tooltip = ud->humanName + " - " + ud->tooltip; unit->armoredMultiple = std::max(0.0001f, ud->armoredMultiple); //armored multiple of 0 will crash spring unit->wreckName = ud->wreckName; unit->realLosRadius = (int) (ud->losRadius); unit->realAirLosRadius = (int) (ud->airLosRadius); unit->upright = ud->upright; unit->radarRadius = ud->radarRadius / (SQUARE_SIZE * 8); unit->sonarRadius = ud->sonarRadius / (SQUARE_SIZE * 8); unit->jammerRadius = ud->jammerRadius / (SQUARE_SIZE * 8); unit->sonarJamRadius = ud->sonarJamRadius / (SQUARE_SIZE * 8); unit->seismicRadius = ud->seismicRadius / (SQUARE_SIZE * 8); unit->seismicSignature = ud->seismicSignature; unit->hasRadarCapacity = unit->radarRadius || unit->sonarRadius || unit->jammerRadius || unit->sonarJamRadius || unit->seismicRadius; unit->stealth = ud->stealth; unit->sonarStealth = ud->sonarStealth; unit->category = ud->category; unit->armorType = ud->armorType; unit->floatOnWater = ud->floater || (ud->movedata && ((ud->movedata->moveType == MoveData::Hover_Move) || (ud->movedata->moveType == MoveData::Ship_Move))); unit->maxSpeed = ud->speed / 30.0f; unit->decloakDistance = ud->decloakDistance; unit->flankingBonusMode = ud->flankingBonusMode; unit->flankingBonusDir = ud->flankingBonusDir; unit->flankingBonusMobility = ud->flankingBonusMobilityAdd * 1000; unit->flankingBonusMobilityAdd = ud->flankingBonusMobilityAdd; unit->flankingBonusAvgDamage = (ud->flankingBonusMax + ud->flankingBonusMin) * 0.5f; unit->flankingBonusDifDamage = (ud->flankingBonusMax - ud->flankingBonusMin) * 0.5f; if(ud->highTrajectoryType==1) unit->useHighTrajectory=true; if(ud->fireState >= 0) unit->fireState = ud->fireState; if(build){ unit->ChangeLos(1,1); unit->health=0.1f; } else { unit->ChangeLos((int)(ud->losRadius),(int)(ud->airLosRadius)); } if (type == "GroundUnit") { SAFE_NEW CMobileCAI(unit); } else if (type == "Transport") { SAFE_NEW CTransportCAI(unit); } else if (type == "Factory") { SAFE_NEW CFactoryCAI(unit); } else if (type == "Builder") { SAFE_NEW CBuilderCAI(unit); } else if (type == "Bomber") { if (ud->hoverAttack) { SAFE_NEW CMobileCAI(unit); } else { SAFE_NEW CAirCAI(unit); } } else if(type == "Fighter"){ if (ud->hoverAttack) { SAFE_NEW CMobileCAI(unit); } else { SAFE_NEW CAirCAI(unit); } } else { SAFE_NEW CCommandAI(unit); } if (ud->canmove && !ud->canfly && (type != "Factory")) { CGroundMoveType* mt = SAFE_NEW CGroundMoveType(unit); mt->maxSpeed = ud->speed / GAME_SPEED; mt->maxWantedSpeed = ud->speed / GAME_SPEED; mt->turnRate = ud->turnRate; mt->baseTurnRate = ud->turnRate; if (!mt->accRate) { logOutput << "acceleration of " << ud->name.c_str() << " is zero!!\n"; } mt->moveType = ud->moveType; mt->accRate = ud->maxAcc; mt->decRate = ud->maxDec; mt->floatOnWater = (ud->movedata->moveType == MoveData::Hover_Move || ud->movedata->moveType == MoveData::Ship_Move); if (!unit->beingBuilt) { // otherwise set this when finished building instead unit->mass = ud->mass; } unit->moveType = mt; // Ground-mobility unit->mobility = SAFE_NEW MoveData(ud->movedata, GAME_SPEED); } else if (ud->canfly) { // Air-mobility unit->mobility = SAFE_NEW MoveData(ud->movedata, GAME_SPEED); if (!unit->beingBuilt) { // otherwise set this when finished building instead unit->mass = ud->mass; } if ((type == "Builder") || ud->hoverAttack || ud->transportCapacity) { CTAAirMoveType* mt = SAFE_NEW CTAAirMoveType(unit); mt->turnRate = ud->turnRate; mt->maxSpeed = ud->speed / GAME_SPEED; mt->accRate = ud->maxAcc; mt->decRate = ud->maxDec; mt->wantedHeight = ud->wantedHeight + gs->randFloat() * 5; mt->orgWantedHeight = mt->wantedHeight; mt->dontLand = ud->DontLand(); mt->collide = ud->collide; mt->altitudeRate = ud->verticalSpeed; mt->bankingAllowed = ud->bankingAllowed; unit->moveType = mt; } else { CAirMoveType *mt = SAFE_NEW CAirMoveType(unit); if(type=="Fighter") mt->isFighter=true; mt->collide = ud->collide; mt->wingAngle = ud->wingAngle; mt->crashDrag = 1 - ud->crashDrag; mt->invDrag = 1 - ud->drag; mt->frontToSpeed = ud->frontToSpeed; mt->speedToFront = ud->speedToFront; mt->myGravity = ud->myGravity; mt->maxBank = ud->maxBank; mt->maxPitch = ud->maxPitch; mt->turnRadius = ud->turnRadius; mt->wantedHeight = (ud->wantedHeight * 1.5f) + ((gs->randFloat() - 0.3f) * 15 * (mt->isFighter ? 2 : 1)); mt->maxAcc = ud->maxAcc; mt->maxAileron = ud->maxAileron; mt->maxElevator = ud->maxElevator; mt->maxRudder = ud->maxRudder; unit->moveType = mt; } } else { unit->moveType = SAFE_NEW CMoveType(unit); unit->upright = true; } unit->energyTickMake = ud->energyMake; if (ud->tidalGenerator > 0) unit->energyTickMake += ud->tidalGenerator * mapInfo->map.tidalStrength; unit->model = LoadModel(ud); unit->SetRadius(unit->model->radius); // copy the UnitDef volume archetype data unit->collisionVolume = SAFE_NEW CollisionVolume(ud->collisionVolume); // if no "collisionVolumeScales" tag was defined in UnitDef, // the default scale for this volume will be a ZeroVector if (unit->collisionVolume->GetScale(COLVOL_AXIS_X) <= 1.0f && unit->collisionVolume->GetScale(COLVOL_AXIS_Y) <= 1.0f && unit->collisionVolume->GetScale(COLVOL_AXIS_Z) <= 1.0f) { // aircraft still get half-size spheres for coldet purposes // if no custom volume is defined (unit->model->radius and // unit->radius themselves are no longer altered) const float scaleFactor = (ud->canfly)? 0.5f: 1.0f; unit->collisionVolume->SetDefaultScale(unit->model->radius * scaleFactor); if (unit->collisionVolume->GetBoundingRadius() <= 30.0f) { // the interval-based method fails too easily for units // with small default volumes, force use of raytracing unit->collisionVolume->SetTestType(COLVOL_TEST_CONT); } } if (ud->floater) { // restrict our depth to our waterline unit->pos.y = std::max(-ud->waterline, ground->GetHeight2(unit->pos.x, unit->pos.z)); } else { unit->pos.y = ground->GetHeight2(unit->pos.x, unit->pos.z); } modelParser->CreateLocalModel(unit); unit->cob = SAFE_NEW CCobInstance(GCobEngine.GetCobFile("scripts/" + ud->cobFilename), unit); unit->weapons.reserve(ud->weapons.size()); for (unsigned int i = 0; i < ud->weapons.size(); i++) { unit->weapons.push_back(LoadWeapon(ud->weapons[i].def, unit, &ud->weapons[i])); } // Calculate the max() of the available weapon reloadtimes int relMax = 0; for (vector<CWeapon*>::iterator i = unit->weapons.begin(); i != unit->weapons.end(); ++i) { if ((*i)->reloadTime > relMax) relMax = (*i)->reloadTime; if (dynamic_cast<CBeamLaser*>(*i)) relMax = 150; } // convert ticks to milliseconds relMax *= 30; // TA does some special handling depending on weapon count if (unit->weapons.size() > 1) { relMax = std::max(relMax, 3000); } // Call initializing script functions unit->cob->Call(COBFN_Create); unit->cob->Call("SetMaxReloadTime", relMax); unit->heading = GetHeadingFromFacing(facing); unit->frontdir = GetVectorFromHeading(unit->heading); unit->updir = UpVector; unit->rightdir = unit->frontdir.cross(unit->updir); unit->yardMap = ud->yardmaps[facing]; unit->Init(builder); if (!build) { unit->FinishedBuilding(); } return unit; }
void CFactory::Update() { if (beingBuilt) { // factory under construction CUnit::Update(); return; } if (quedBuild && !opening && !stunned) { cob->Call(COBFN_Activate); groundBlockingObjectMap->OpenBlockingYard(this, yardMap); opening = true; } if (quedBuild && inBuildStance && !stunned) { // start building a unit float3 buildPos = CalcBuildPos(); bool canBuild = true; std::vector<CUnit*> units = qf->GetUnitsExact(buildPos, 16); for (std::vector<CUnit*>::iterator ui = units.begin(); ui != units.end(); ++ui) { if ((*ui) != this) canBuild = false; } if (canBuild) { quedBuild = false; CUnit* b = unitLoader.LoadUnit(nextBuild, buildPos + float3(0.01f, 0.01f, 0.01f), team, true, buildFacing, this); b->lineage = this->lineage; if (!unitDef->canBeAssisted) { b->soloBuilder = this; b->AddDeathDependence(this); } AddDeathDependence(b); curBuild = b; cob->Call("StartBuilding"); int soundIdx = unitDef->sounds.build.getRandomIdx(); if (soundIdx >= 0) { sound->PlaySample( unitDef->sounds.build.getID(soundIdx), pos, unitDef->sounds.build.getVolume(0)); } } else { helper->BuggerOff(buildPos - float3(0.01f, 0, 0.02f), radius + 8); } } if (curBuild && !beingBuilt) { if (!stunned) { // factory not under construction and // nanolathing unit: continue building lastBuild = gs->frameNum; // buildPiece is the rotating platform const int buildPiece = GetBuildPiece(); CMatrix44f mat = localmodel->GetPieceMatrix(buildPiece); const int h = GetHeadingFromVector(mat[2], mat[10]); // rotate unit nanoframe with platform curBuild->heading = (h + GetHeadingFromFacing(buildFacing)) & 65535; const float3 buildPos = CalcBuildPos(buildPiece); curBuild->pos = buildPos; if (curBuild->floatOnWater) { curBuild->pos.y = ground->GetHeight(buildPos.x, buildPos.z); curBuild->pos.y -= curBuild->unitDef->waterline; } curBuild->midPos = curBuild->pos + (UpVector * curBuild->relMidPos.y); const CCommandQueue& queue = commandAI->commandQue; if(!queue.empty() && (queue.front().id == CMD_WAIT)) { curBuild->AddBuildPower(0, this); } else { if (curBuild->AddBuildPower(buildSpeed, this)) { CreateNanoParticle(); } } } if (!curBuild->beingBuilt && (!unitDef->fullHealthFactory || (curBuild->health >= curBuild->maxHealth))) { if (group && curBuild->group == 0) { curBuild->SetGroup(group); } bool userOrders = true; if (curBuild->commandAI->commandQue.empty() || (dynamic_cast<CMobileCAI*>(curBuild->commandAI) && ((CMobileCAI*)curBuild->commandAI)->unimportantMove)) { userOrders = false; const CFactoryCAI* facAI = (CFactoryCAI*) commandAI; const CCommandQueue& newUnitCmds = facAI->newUnitCommands; if (newUnitCmds.empty()) { SendToEmptySpot(curBuild); } else { // XXX the pathfinder sometimes... makes mistakes, try to hack around it // XXX note this qualifies as HACK HACK HACK float3 testpos = curBuild->pos + frontdir * (this->radius - 1.0f); Command c; c.id = CMD_MOVE; c.params.push_back(testpos.x); c.params.push_back(testpos.y); c.params.push_back(testpos.z); curBuild->commandAI->GiveCommand(c); for (CCommandQueue::const_iterator ci = newUnitCmds.begin(); ci != newUnitCmds.end(); ++ci) { c = *ci; c.options |= SHIFT_KEY; curBuild->commandAI->GiveCommand(c); } } waitCommandsAI.AddLocalUnit(curBuild, this); } eventHandler.UnitFromFactory(curBuild, this, userOrders); StopBuild(); } } if (((lastBuild + 200) < gs->frameNum) && !stunned && !quedBuild && opening && groundBlockingObjectMap->CanCloseYard(this)) { // close the factory after inactivity groundBlockingObjectMap->CloseBlockingYard(this, yardMap); opening = false; cob->Call(COBFN_Deactivate); } CBuilding::Update(); }