⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unithandler.cpp

📁 这是整套横扫千军3D版游戏的源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
#include "UnitHandler.h"
#include "MetalMaker.h"


CR_BIND(CUnitHandler, (NULL));
CR_REG_METADATA(CUnitHandler, (
	CR_MEMBER(IdleUnits),
	CR_MEMBER(BuildTasks),
	CR_MEMBER(TaskPlans),
	CR_MEMBER(AllUnitsByCat),
	CR_MEMBER(AllUnitsByType),

	CR_MEMBER(Factories),
	CR_MEMBER(NukeSilos),
	CR_MEMBER(MetalExtractors),

	CR_MEMBER(Limbo),
	CR_MEMBER(BuilderTrackers),

	CR_MEMBER(metalMaker),

	CR_MEMBER(ai),
	CR_MEMBER(taskPlanCounter),
	CR_RESERVED(16)
));


CUnitHandler::CUnitHandler(AIClasses* ai) {
	this->ai = ai;
	taskPlanCounter = 1;
	IdleUnits.resize(LASTCATEGORY);
	BuildTasks.resize(LASTCATEGORY);
	TaskPlans.resize(LASTCATEGORY);
	AllUnitsByCat.resize(LASTCATEGORY);

	if (ai) {
		AllUnitsByType.resize(ai->cb->GetNumUnitDefs() + 1);
		metalMaker = new CMetalMaker(ai);
	}
}

CUnitHandler::~CUnitHandler() {
	for (list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) {
		delete *i;
	}
}



void CUnitHandler::IdleUnitUpdate(int frame) {
	list<integer2> limboremoveunits;

	for (list<integer2>::iterator i = Limbo.begin(); i != Limbo.end(); i++) {
		if (i->y > 0) {
			i->y--;
		}
		else {
			if (ai->cb->GetUnitDef(i->x) == NULL) {
				// ignore dead unit
			} else {
				IdleUnits[ai->ut->GetCategory(i->x)].push_back(i->x);
			}

			limboremoveunits.push_back(*i);
		}
	}

	if (limboremoveunits.size()) {
		for (list<integer2>::iterator i = limboremoveunits.begin(); i != limboremoveunits.end(); i++) {
			Limbo.remove(*i);
		}
	}

	// make sure that all the builders are in action (hack?)
	if (frame % 15 == 0) {
		for (list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) {
			// the new test
			if ((*i)->idleStartFrame != -2) {
				// the brand new builders must be filtered still
				bool ans = VerifyOrder(*i);
				const CCommandQueue* mycommands = ai->cb->GetCurrentUnitCommands((*i)->builderID);
				Command c;

				if (mycommands->size() > 0)
					c = mycommands->front();

				// two sec delay is ok
				if (((*i)->commandOrderPushFrame + LAG_ACCEPTANCE) < frame) {
					if (!ans) {
						char text[512];
						float3 pos = ai->cb->GetUnitPos((*i)->builderID);
						sprintf(text, "builder %i VerifyOrder failed ", (*i)->builderID);

						ClearOrder(*i, false);

						if (!mycommands->empty())
							DecodeOrder(*i, true);
						else
							IdleUnitAdd((*i)->builderID, frame);
					}
				}
			}
		}
	}
}




void CUnitHandler::UnitMoveFailed(int unit) {
	unit = unit;
}

// called when unit nanoframe first created
// (CEconomyTracker deals with UnitFinished())
void CUnitHandler::UnitCreated(int unit) {
	int category = ai->ut->GetCategory(unit);
	const UnitDef* newUnitDef = ai->cb->GetUnitDef(unit);

	if (category != -1) {
		AllUnitsByCat[category].push_back(unit);
		AllUnitsByType[newUnitDef->id].push_back(unit);

		if (category == CAT_FACTORY) {
			FactoryAdd(unit);
		}

		BuildTaskCreate(unit);

		if (category == CAT_BUILDER) {
			// add the new builder
			BuilderTracker* builderTracker = new BuilderTracker;
			builderTracker->builderID = unit;
			builderTracker->buildTaskId = 0;
			builderTracker->taskPlanId = 0;
			builderTracker->factoryId = 0;
			builderTracker->stuckCount = 0;
			builderTracker->customOrderId = 0;
			// under construction
			builderTracker->commandOrderPushFrame = -2;
			builderTracker->categoryMaker = -1;
			// wait for the first idle call, as this unit might be under construction
			builderTracker->idleStartFrame = -2;
			BuilderTrackers.push_back(builderTracker);
		}

		if (category == CAT_MMAKER) {
			MMakerAdd(unit);
		}
		if (category == CAT_MEX) {
			MetalExtractorAdd(unit);
		}

		if (category == CAT_NUKE) {
			NukeSiloAdd(unit);
		}
	}
}

void CUnitHandler::UnitDestroyed(int unit) {
	int category = ai->ut->GetCategory(unit);
	const UnitDef* unitDef = ai->cb->GetUnitDef(unit);

	if (category != -1) {
		AllUnitsByType[unitDef->id].remove(unit);
		AllUnitsByCat[category].remove(unit);
		IdleUnitRemove(unit);
		BuildTaskRemove(unit);

		if (category == CAT_DEFENCE) {
			ai->dm->RemoveDefense(ai->cb->GetUnitPos(unit), unitDef);
		}
		if (category == CAT_MMAKER) {
			MMakerRemove(unit);
		}
		if (category == CAT_FACTORY) {
			FactoryRemove(unit);
		}

		if (category == CAT_BUILDER) {
			// remove the builder
			for (list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) {
				if ((*i)->builderID == unit) {
					if ((*i)->buildTaskId)
						BuildTaskRemove(*i);
					if ((*i)->taskPlanId)
						TaskPlanRemove(*i);
					if ((*i)->factoryId)
						FactoryBuilderRemove(*i);

					BuilderTracker* builderTracker = *i;
					BuilderTrackers.erase(i);
					delete builderTracker;
					break;
				}
			}
		}

		if (category == CAT_MEX) {
			MetalExtractorRemove(unit);
		}
		if (category == CAT_NUKE) {
			NukeSiloRemove(unit);
		}
	}
}


void CUnitHandler::IdleUnitAdd(int unit, int frame) {
	int category = ai->ut->GetCategory(unit);

	if (category != -1) {
		const CCommandQueue* mycommands = ai->cb->GetCurrentUnitCommands(unit);

		if (mycommands->empty()) {
			if (category == CAT_BUILDER) {
				BuilderTracker* builderTracker = GetBuilderTracker(unit);
				// add clear here
				ClearOrder(builderTracker, true);

				if (builderTracker->idleStartFrame == -2) {
					// it was in the idle list already?
					IdleUnitRemove(builderTracker->builderID);
				}

				builderTracker->idleStartFrame = -2;

				if (builderTracker->commandOrderPushFrame == -2) {
					// make sure that if the unit was just built
					// it will have some time to leave the factory
					builderTracker->commandOrderPushFrame = frame + 30 * 3;
				}
			}

			integer2 myunit(unit, LIMBOTIME);
			Limbo.remove(myunit);
			Limbo.push_back(myunit);
		}
		else {
			// the unit has orders still
			if (category == CAT_BUILDER) {
				if (false) {
					// KLOOTNOTE: somehow we are now reaching this branch
					// on initialization when USE_CREG is not defined,
					// mycommands->size() returns garbage?
					BuilderTracker* builderTracker = GetBuilderTracker(unit);
					DecodeOrder(builderTracker, true);
				}
			}
		}
	}
}





bool CUnitHandler::VerifyOrder(BuilderTracker* builderTracker) {
	// if it's without orders then try to find the lost command (TODO)
	const CCommandQueue* mycommands = ai->cb->GetCurrentUnitCommands(builderTracker->builderID);
	bool commandFound = false;
	bool hit = false;

	if (mycommands->size() > 0) {
		// it has orders
		const Command* c = &mycommands->front();

		if (mycommands->size() == 2) {
			// it might have a reclaim order, or terrain change order
			// take command nr. 2
			c = &mycommands->back();
		}

		if (builderTracker->buildTaskId != 0) {
			hit = true;
			// test that this builder is on repair on this unit
			BuildTask* buildTask = GetBuildTask(builderTracker->buildTaskId);

			if (c->id == CMD_REPAIR && c->params[0] == builderTracker->buildTaskId
				|| (c->id == -buildTask->def->id && c->params[0] == buildTask->pos.x && c->params[2] == buildTask->pos.z))
				commandFound = true;
			else
				return false;
		}

		if (builderTracker->taskPlanId != 0) {
			assert(!hit);
			hit = true;
			TaskPlan* taskPlan = GetTaskPlan(builderTracker->taskPlanId);

			if (c->id == -taskPlan->def->id && c->params[0] == taskPlan->pos.x && c->params[2] == taskPlan->pos.z)
				commandFound = true;
			else
				return false;
		}

		if (builderTracker->factoryId != 0) {
			assert(!hit);
			hit = true;
			if (c->id == CMD_GUARD && c->params[0] == builderTracker->factoryId)
				commandFound = true;
			else
				return false;
		}

		if (builderTracker->customOrderId != 0) {
			assert(!hit);
			hit = true;
			// CMD_MOVE is for human control stuff, CMD_REPAIR is for repairs of just made stuff
			// CMD_GUARD... ?
			if (c->id == CMD_RECLAIM || c->id == CMD_MOVE || c->id == CMD_REPAIR)
				commandFound = true;
			else {
				return false;
			}
		}

		if (hit && commandFound) {
			// it's on the right job
			return true;
		}
	}

	else  {
		if (builderTracker->idleStartFrame == -2) {
			return true;
		}
	}

	return false;
}




// use this only if the unit does not have any orders at the moment
void CUnitHandler::ClearOrder(BuilderTracker* builderTracker, bool reportError) {
	bool hit = false;
	const CCommandQueue* mycommands = ai->cb->GetCurrentUnitCommands(builderTracker->builderID);
	assert(mycommands->empty() || !reportError);

	if (builderTracker->buildTaskId != 0) {
		// why is this builder idle?
		hit = true;
		BuildTask* buildTask = GetBuildTask(builderTracker->buildTaskId);
		char text[512];
		sprintf(text, "builder %i: was idle, but it is on buildTaskId: %i  (stuck?)", builderTracker->builderID, builderTracker->buildTaskId);

		if (buildTask->builderTrackers.size() > 1) {
			BuildTaskRemove(builderTracker);
		} else {
			// only builder of this thing, and now idle
			BuildTaskRemove(builderTracker);
		}
	}

	if (builderTracker->taskPlanId != 0) {
		assert(!hit);
		hit = true;
		// why is this builder idle?
		TaskPlan* taskPlan = GetTaskPlan(builderTracker->taskPlanId);
		char text[512];
		sprintf(text, "builder %i: was idle, but it is on taskPlanId: %s (masking this spot)", builderTracker->builderID, taskPlan->def->humanName.c_str());

		ai->dm->MaskBadBuildSpot(taskPlan->pos);
		// TODO: fix this, remove all builders from this plan

		if (reportError) {
			list<BuilderTracker*> builderTrackers = taskPlan->builderTrackers;
			for (list<BuilderTracker*>::iterator i = builderTrackers.begin(); i != builderTrackers.end(); i++) {
				TaskPlanRemove(*i);
				ai->MyUnits[(*i)->builderID]->Stop();
			}
		} else {
			TaskPlanRemove(builderTracker);
		}
	}

	if (builderTracker->factoryId != 0) {
		assert(!hit);
		hit = true;
		// why is this builder idle?
		char text[512];
		sprintf(text, "builder %i: was idle, but it is on factoryId: %i (removing the builder from the job)", builderTracker->builderID, builderTracker->factoryId);

		FactoryBuilderRemove(builderTracker);
	}

	if (builderTracker->customOrderId != 0) {
		assert(!hit);
		hit = true;
		// why is this builder idle?
		// no tracking of custom orders yet
		// char text[512];
		// sprintf(text, "builder %i: was idle, but it is on customOrderId: %i (removing the builder from the job)", unit, builderTracker->customOrderId);
		builderTracker->customOrderId = 0;
	}

	assert(builderTracker->buildTaskId == 0);
	assert(builderTracker->taskPlanId == 0);
	assert(builderTracker->factoryId == 0);
	assert(builderTracker->customOrderId == 0);
}




void CUnitHandler::DecodeOrder(BuilderTracker* builderTracker, bool reportError) {
	// take a look and see what it's doing
	const CCommandQueue* mycommands = ai->cb->GetCurrentUnitCommands(builderTracker->builderID);

	if (mycommands->size() > 0) {
		// builder has orders
		const Command* c = &mycommands->front();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -