示例#1
0
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();
}
示例#2
0
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);
}