void CBuilder::Update() { CBuilderCAI* cai = static_cast<CBuilderCAI*>(commandAI); const CCommandQueue& cQueue = cai->commandQue; const Command& fCommand = (!cQueue.empty())? cQueue.front(): Command(CMD_STOP); nanoPieceCache.Update(); if (!beingBuilt && !IsStunned()) { if (terraforming && inBuildStance) { assert(!mapDamage->disabled); // The map should not be deformed in the first place. const float* heightmap = readmap->GetCornerHeightMapSynced(); float terraformScale = 0.1; switch (terraformType) { case Terraform_Building: if (curBuild != NULL) { if (curBuild->terraformLeft <= 0) terraformScale = 0.0f; else terraformScale = (terraformSpeed + terraformHelp) / curBuild->terraformLeft; curBuild->terraformLeft -= (terraformSpeed + terraformHelp); terraformHelp = 0; terraformScale = std::min(terraformScale, 1.0f); // prevent building from timing out while terraforming for it curBuild->AddBuildPower(0.0f, this); for (int z = tz1; z <= tz2; z++) { for (int x = tx1; x <= tx2; x++) { int idx = z * gs->mapxp1 + x; float ch = heightmap[idx]; readmap->AddHeight(idx, (curBuild->pos.y - ch) * terraformScale); } } if (curBuild->terraformLeft <= 0.0f) { terraforming = false; mapDamage->RecalcArea(tx1, tx2, tz1, tz2); curBuild->groundLevelled = true; if (luaRules && luaRules->TerraformComplete(this, curBuild)) { StopBuild(); } } } break; case Terraform_Restore: if (myTerraformLeft <= 0.0f) terraformScale = 0.0f; else terraformScale = (terraformSpeed + terraformHelp) / myTerraformLeft; myTerraformLeft -= (terraformSpeed + terraformHelp); terraformHelp = 0; terraformScale = std::min(terraformScale, 1.0f); for (int z = tz1; z <= tz2; z++) { for (int x = tx1; x <= tx2; x++) { int idx = z * gs->mapxp1 + x; float ch = heightmap[idx]; float oh = readmap->GetOriginalHeightMapSynced()[idx]; readmap->AddHeight(idx, (oh - ch) * terraformScale); } } if (myTerraformLeft <= 0.0f) { terraforming = false; mapDamage->RecalcArea(tx1, tx2, tz1, tz2); StopBuild(); } break; } ScriptDecloak(true); CreateNanoParticle(terraformCenter, terraformRadius * 0.5f, false); for (int z = tz1; z <= tz2; z++) { // smooth the borders x for (int x = 1; x <= 3; x++) { if (tx1 - 3 >= 0) { const float ch3 = heightmap[z * gs->mapxp1 + tx1 ]; const float ch = heightmap[z * gs->mapxp1 + tx1 - x]; const float ch2 = heightmap[z * gs->mapxp1 + tx1 - 3]; const float amount = ((ch3 * (3 - x) + ch2 * x) / 3 - ch) * terraformScale; readmap->AddHeight(z * gs->mapxp1 + tx1 - x, amount); } if (tx2 + 3 < gs->mapx) { const float ch3 = heightmap[z * gs->mapxp1 + tx2 ]; const float ch = heightmap[z * gs->mapxp1 + tx2 + x]; const float ch2 = heightmap[z * gs->mapxp1 + tx2 + 3]; const float amount = ((ch3 * (3 - x) + ch2 * x) / 3 - ch) * terraformScale; readmap->AddHeight(z * gs->mapxp1 + tx2 + x, amount); } } } for (int z = 1; z <= 3; z++) { // smooth the borders z for (int x = tx1; x <= tx2; x++) { if (tz1 - 3 >= 0) { const float ch3 = heightmap[(tz1 ) * gs->mapxp1 + x]; const float ch = heightmap[(tz1 - z) * gs->mapxp1 + x]; const float ch2 = heightmap[(tz1 - 3) * gs->mapxp1 + x]; const float adjust = ((ch3 * (3 - z) + ch2 * z) / 3 - ch) * terraformScale; readmap->AddHeight((tz1 - z) * gs->mapxp1 + x, adjust); } if (tz2 + 3 < gs->mapy) { const float ch3 = heightmap[(tz2 ) * gs->mapxp1 + x]; const float ch = heightmap[(tz2 + z) * gs->mapxp1 + x]; const float ch2 = heightmap[(tz2 + 3) * gs->mapxp1 + x]; const float adjust = ((ch3 * (3 - z) + ch2 * z) / 3 - ch) * terraformScale; readmap->AddHeight((tz2 + z) * gs->mapxp1 + x, adjust); } } } } else if (helpTerraform != NULL && inBuildStance) { if (helpTerraform->terraforming) { ScriptDecloak(true); helpTerraform->terraformHelp += terraformSpeed; CreateNanoParticle(helpTerraform->terraformCenter, helpTerraform->terraformRadius * 0.5f, false); } else { DeleteDeathDependence(helpTerraform, DEPENDENCE_TERRAFORM); helpTerraform = NULL; StopBuild(true); } } else if (curBuild != NULL && cai->IsInBuildRange(curBuild)) { if (fCommand.GetID() == CMD_WAIT) { if (curBuild->buildProgress < 1.0f) { // prevent buildee from decaying (we cannot call StopBuild here) curBuild->AddBuildPower(0.0f, this); } else { // stop repairing (FIXME: should be much cleaner to let BuilderCAI // call this instead when a wait command is given?) StopBuild(); } } else { if (curBuild->soloBuilder != NULL && (curBuild->soloBuilder != this)) { StopBuild(); } else { if (inBuildStance || true) { // NOTE: // technically this block of code should be guarded by // "if (inBuildStance)", but doing so can create zombie // guarders because scripts might not set inBuildStance // to true when guard or repair orders are executed and // SetRepairTarget does not check for it // // StartBuild *does* ensure construction will not start // until inBuildStance is set to true by the builder's // script, and there are no cases during construction // when inBuildStance can become false yet the buildee // should be kept from decaying, so this is free from // serious side-effects (when repairing, a builder might // start adding build-power before having fully finished // its opening animation) // ScriptDecloak(true); // adjusted build-speed: use repair-speed on units with // progress >= 1 rather than raw build-speed on buildees // with progress < 1 float adjBuildSpeed = 0.0f; if (curBuild->buildProgress >= 1.0f) { adjBuildSpeed = std::min(repairSpeed, unitDef->maxRepairSpeed * 0.5f - curBuild->repairAmount); // repair } else { adjBuildSpeed = buildSpeed; // build } if (adjBuildSpeed > 0.0f && curBuild->AddBuildPower(adjBuildSpeed, this)) { CreateNanoParticle(curBuild->midPos, curBuild->radius * 0.5f, false); } else { // check if buildee finished construction if (!curBuild->beingBuilt && curBuild->health >= curBuild->maxHealth) { StopBuild(); } } } } } } else if (curReclaim != NULL && f3SqDist(curReclaim->pos, pos)<Square(buildDistance+curReclaim->radius) && inBuildStance) { if (fCommand.GetID() == CMD_WAIT) { StopBuild(); } else { ScriptDecloak(true); if (curReclaim->AddBuildPower(-reclaimSpeed, this)) { CreateNanoParticle(curReclaim->midPos, curReclaim->radius * 0.7f, true, (reclaimingUnit && curReclaim->team != team)); } } } 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(repairSpeed, this); } else { // Corpse has been restored, begin resurrection if (UseEnergy(ud->energy * resurrectSpeed / ud->buildTime * modInfo.resurrectEnergyCostFactor)) { curResurrect->resurrectProgress += (resurrectSpeed / ud->buildTime); CreateNanoParticle(curResurrect->midPos, curResurrect->radius * 0.7f, (gs->randInt() & 1)); } if (curResurrect->resurrectProgress > 1) { // resurrect finished curResurrect->UnBlock(); UnitLoadParams resurrecteeParams = {ud, this, curResurrect->pos, ZeroVector, -1, team, curResurrect->buildFacing, false, false}; CUnit* resurrectee = unitLoader->LoadUnit(resurrecteeParams); if (!this->unitDef->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 = (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; const int cmdFeatureId = c.params[0]; if (cmdFeatureId - unitHandler->MaxUnits() == curResurrect->id && teamHandler->Ally(allyteam, bld->allyteam)) { bld->lastResurrected = resurrectee->id; // all units that were rezzing shall assist the repair too c.params[0] = INT_MAX / 2; // prevent FinishCommand from removing this command when the feature is deleted, since it is needed to start the repair } } curResurrect->resurrectProgress = 0; featureHandler->DeleteFeature(curResurrect); StopBuild(true); } } } else { StopBuild(true); } } } else if (curCapture != NULL && f3SqDist(curCapture->pos, pos)<Square(buildDistance+curCapture->radius) && inBuildStance) { if (fCommand.GetID() == CMD_WAIT) { StopBuild(); } else { if (curCapture->team != team) { const float captureMagicNumber = (150 + curCapture->buildTime / captureSpeed * (curCapture->health + curCapture->maxHealth) / curCapture->maxHealth * 0.4f); const float captureProgressTemp = std::min(curCapture->captureProgress + 1.0f / captureMagicNumber, 1.0f); const float captureFraction = captureProgressTemp - curCapture->captureProgress; const float energyUseScaled = curCapture->energyCost * captureFraction * modInfo.captureEnergyCostFactor; if (!UseEnergy(energyUseScaled)) { teamHandler->Team(team)->energyPull += energyUseScaled; } else { curCapture->captureProgress = captureProgressTemp; CreateNanoParticle(curCapture->midPos, curCapture->radius * 0.7f, false, true); if (curCapture->captureProgress >= 1.0f) { if (!curCapture->ChangeTeam(team, CUnit::ChangeCaptured)) { // capture failed if (team == gu->myTeam) { LOG_L(L_WARNING, "%s: Capture failed, unit type limit reached", unitDef->humanName.c_str()); eventHandler.LastMessagePosition(pos); } } curCapture->captureProgress = 0.0f; StopBuild(true); } } } else { StopBuild(true); } } } } CUnit::Update(); }
void CSelectedUnits::Draw() { glDisable(GL_TEXTURE_2D); glDepthMask(false); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); // for line smoothing glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glLineWidth(cmdColors.UnitBoxLineWidth()); GML_RECMUTEX_LOCK(sel); // Draw GML_RECMUTEX_LOCK(group); // Draw if (cmdColors.unitBox[3] > 0.0f) { glColor4fv(cmdColors.unitBox); const CUnitSet* unitSet; if (selectedGroup != -1) { unitSet = &grouphandlers[gu->myTeam]->groups[selectedGroup]->units; } else { unitSet = &selectedUnits; } glBegin(GL_QUADS); CUnitSet::const_iterator ui; for (ui = unitSet->begin(); ui != unitSet->end(); ++ui) { const CUnit* unit = *ui; if (unit->isIcon) { continue; } glVertexf3(unit->drawPos + float3( unit->xsize * 4, 0, unit->zsize * 4)); glVertexf3(unit->drawPos + float3(-unit->xsize * 4, 0, unit->zsize * 4)); glVertexf3(unit->drawPos + float3(-unit->xsize * 4, 0, -unit->zsize * 4)); glVertexf3(unit->drawPos + float3( unit->xsize * 4, 0, -unit->zsize * 4)); } glEnd(); } // highlight queued build sites if we are about to build something // (or old-style, whenever the shift key is being held down) if (cmdColors.buildBox[3] > 0.0f) { if (!selectedUnits.empty() && ((cmdColors.BuildBoxesOnShift() && keys[SDLK_LSHIFT]) || ((guihandler->inCommand >= 0) && (guihandler->inCommand < int(guihandler->commands.size())) && (guihandler->commands[guihandler->inCommand].id < 0)))) { GML_STDMUTEX_LOCK(cai); // Draw bool myColor = true; glColor4fv(cmdColors.buildBox); std::list<CBuilderCAI*>::const_iterator bi; for (bi = uh->builderCAIs.begin(); bi != uh->builderCAIs.end(); ++bi) { CBuilderCAI* builder = *bi; if (builder->owner->team == gu->myTeam) { if (!myColor) { glColor4fv(cmdColors.buildBox); myColor = true; } builder->DrawQuedBuildingSquares(); } else if (teamHandler->AlliedTeams(builder->owner->team, gu->myTeam)) { if (myColor) { glColor4fv(cmdColors.allyBuildBox); myColor = false; } builder->DrawQuedBuildingSquares(); } } } } glLineWidth(1.0f); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); glDepthMask(true); glEnable(GL_TEXTURE_2D); }
void CSelectedUnits::Draw() { glDisable(GL_TEXTURE_2D); glDepthMask(false); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); // for line smoothing glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glLineWidth(cmdColors.UnitBoxLineWidth()); GML_RECMUTEX_LOCK(grpsel); // Draw if (cmdColors.unitBox[3] > 0.05f) { const CUnitSet* unitSet; if (selectedGroup != -1) { unitSet = &grouphandlers[gu->myTeam]->groups[selectedGroup]->units; } else { unitSet = &selectedUnits; } CVertexArray* va = GetVertexArray(); va->Initialize(); va->EnlargeArrays(unitSet->size() * 8, 0, VA_SIZE_C); for (CUnitSet::const_iterator ui = unitSet->begin(); ui != unitSet->end(); ++ui) { const CUnit* unit = *ui; if (unit->isIcon) { continue; } const int uhxsize = (unit->xsize * SQUARE_SIZE) >> 1, uhzsize = (unit->zsize * SQUARE_SIZE) >> 1, mhxsize = (unit->mobility == NULL)? uhxsize: ((unit->mobility->xsize * SQUARE_SIZE) >> 1), mhzsize = (unit->mobility == NULL)? uhzsize: ((unit->mobility->zsize * SQUARE_SIZE) >> 1); const float3 verts[8] = { // UnitDef footprint corners float3(unit->drawPos.x + uhxsize, unit->drawPos.y, unit->drawPos.z + uhzsize), float3(unit->drawPos.x - uhxsize, unit->drawPos.y, unit->drawPos.z + uhzsize), float3(unit->drawPos.x - uhxsize, unit->drawPos.y, unit->drawPos.z - uhzsize), float3(unit->drawPos.x + uhxsize, unit->drawPos.y, unit->drawPos.z - uhzsize), // MoveDef footprint corners float3(unit->drawPos.x + mhxsize, unit->drawPos.y, unit->drawPos.z + mhzsize), float3(unit->drawPos.x - mhxsize, unit->drawPos.y, unit->drawPos.z + mhzsize), float3(unit->drawPos.x - mhxsize, unit->drawPos.y, unit->drawPos.z - mhzsize), float3(unit->drawPos.x + mhxsize, unit->drawPos.y, unit->drawPos.z - mhzsize), }; const unsigned char colors[2][4] = { {(0.0f + cmdColors.unitBox[0]) * 255, (0.0f + cmdColors.unitBox[1]) * 255, (0.0f + cmdColors.unitBox[2] * 255), cmdColors.unitBox[3] * 255}, {(1.0f - cmdColors.unitBox[0]) * 255, (1.0f - cmdColors.unitBox[1]) * 255, (1.0f - cmdColors.unitBox[2] * 255), cmdColors.unitBox[3] * 255}, }; va->AddVertexQC(verts[0], colors[0]); va->AddVertexQC(verts[1], colors[0]); va->AddVertexQC(verts[2], colors[0]); va->AddVertexQC(verts[3], colors[0]); if (globalRendering->drawdebug && (mhxsize != uhxsize || mhzsize != uhzsize)) { va->AddVertexQC(verts[4], colors[1]); va->AddVertexQC(verts[5], colors[1]); va->AddVertexQC(verts[6], colors[1]); va->AddVertexQC(verts[7], colors[1]); } } va->DrawArrayC(GL_QUADS); } // highlight queued build sites if we are about to build something // (or old-style, whenever the shift key is being held down) if (cmdColors.buildBox[3] > 0.0f) { if (!selectedUnits.empty() && ((cmdColors.BuildBoxesOnShift() && keyInput->IsKeyPressed(SDLK_LSHIFT)) || ((guihandler->inCommand >= 0) && (guihandler->inCommand < int(guihandler->commands.size())) && (guihandler->commands[guihandler->inCommand].id < 0)))) { GML_STDMUTEX_LOCK(cai); // Draw bool myColor = true; glColor4fv(cmdColors.buildBox); std::list<CBuilderCAI*>::const_iterator bi; for (bi = uh->builderCAIs.begin(); bi != uh->builderCAIs.end(); ++bi) { CBuilderCAI* builder = *bi; if (builder->owner->team == gu->myTeam) { if (!myColor) { glColor4fv(cmdColors.buildBox); myColor = true; } builder->DrawQuedBuildingSquares(); } else if (teamHandler->AlliedTeams(builder->owner->team, gu->myTeam)) { if (myColor) { glColor4fv(cmdColors.allyBuildBox); myColor = false; } builder->DrawQuedBuildingSquares(); } } } } glLineWidth(1.0f); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); glDepthMask(true); glEnable(GL_TEXTURE_2D); }