unithandler.cpp

来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 642 行 · 第 1/2 页

CPP
642
字号
// UnitHandler.cpp: implementation of the CUnitHandler class.
//
//////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "UnitHandler.h"
#include "Unit.h"
#include "Rendering/GL/myGL.h"
#include "Game/Team.h"
#include "TimeProfiler.h"
#include "myMath.h"
#include "Map/Ground.h"
#include "Map/ReadMap.h"
#include "Platform/ConfigHandler.h"
#include "Rendering/FartextureHandler.h"
#include "UnitDefHandler.h"
#include "Sim/Misc/QuadField.h"
#include "CommandAI/BuilderCAI.h"
#include "Game/SelectedUnits.h"
#include "FileSystem/FileHandler.h"
#include "LogOutput.h"
#include "Game/SelectedUnits.h"
#include "Sim/Misc/Feature.h"
#include "Sim/Misc/FeatureHandler.h"
#include "Sim/Units/Unit.h"
#include "LoadSaveInterface.h"
#include "UnitLoader.h"
#include "Sync/SyncTracer.h"
#include "Game/GameSetup.h"
#include "Sim/Units/CommandAI/Command.h"
#include "Sim/Misc/AirBaseHandler.h"
#include "creg/STL_List.h"
#include "creg/STL_Deque.h"
#include "creg/STL_Set.h"
#include "mmgr.h"

BuildInfo::BuildInfo(const std::string& name, const float3& p, int facing)
{
	def = unitDefHandler->GetUnitByName(name);
	pos = p;
	buildFacing = facing;
}

void BuildInfo::FillCmd(Command& c) const
{
	c.id=-def->id;
	c.params.resize(4);
	c.params[0]=pos.x;
	c.params[1]=pos.y;
	c.params[2]=pos.z;
	c.params[3]=(float)buildFacing;
}

bool BuildInfo::Parse(const Command& c)
{
	if (c.params.size() >= 3) {
		pos = float3(c.params[0],c.params[1],c.params[2]);

		if(c.id < 0) {
			def = unitDefHandler->GetUnitByID(-c.id);

			buildFacing = 0;
			if (c.params.size()==4)
				buildFacing = int(c.params[3]);

			return true;
		}
	}
	return false;
}


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CUnitHandler* uh;
using namespace std;

CR_BIND(CUnitHandler, (true));
CR_REG_METADATA(CUnitHandler, (
	CR_MEMBER(activeUnits),
	CR_MEMBER(units),
	CR_MEMBER(freeIDs),
	CR_MEMBER(waterDamage),
	CR_MEMBER(maxUnits),
	CR_MEMBER(maxUnitRadius),
	CR_MEMBER(lastDamageWarning),
	CR_MEMBER(lastCmdDamageWarning),
	CR_MEMBER(limitDgun),
	CR_MEMBER(dgunRadius),
	CR_MEMBER(diminishingMetalMakers),
	CR_MEMBER(metalMakerIncome),
	CR_MEMBER(metalMakerEfficiency),
	CR_MEMBER(toBeRemoved),
	CR_MEMBER(morphUnitToFeature),
	CR_MEMBER(toBeRemoved),
	CR_MEMBER(builderCAIs),
	CR_MEMBER(unitsByDefs),
	CR_POSTLOAD(PostLoad),
	CR_SERIALIZER(Serialize)
	));

void CUnitHandler::Serialize(creg::ISerializer& s)
{
}

void CUnitHandler::PostLoad()
{
	// reset any synced stuff that is not saved
	slowUpdateIterator = activeUnits.end();
}

CUnitHandler::CUnitHandler(bool serializing)
:
	maxUnits(500),
	maxUnitRadius(0.0f),
	lastDamageWarning(0),
	lastCmdDamageWarning(0),
	metalMakerIncome(0),
	metalMakerEfficiency(1),
	diminishingMetalMakers(false),
	limitDgun(false),
	morphUnitToFeature(true)
{
	//unitModelLoader=SAFE_NEW CUnit3DLoader;
	for (int a = 1; a < MAX_UNITS; a++) {
		freeIDs.push_back(a);
		units[a] = 0;
	}
	units[0] = 0;

	slowUpdateIterator = activeUnits.end();

	waterDamage=atof(readmap->mapDefParser.SGetValueDef("0","MAP\\WATER\\WaterDamage").c_str())*(16.0f/30.0f);

	if (gameSetup) {
		maxUnits = gameSetup->maxUnits;
	}
	if (maxUnits > ((MAX_UNITS / gs->activeTeams) - 5)) {
		maxUnits = (MAX_UNITS / gs->activeTeams) -5;
	}

	if (gameSetup) {
		if (gameSetup->limitDgun) {
			limitDgun = true;
			dgunRadius = gs->mapx * 3;
		}
		if (gameSetup->diminishingMMs) {
			diminishingMetalMakers = true;
		}
	}

	if (!serializing) {
		airBaseHandler = SAFE_NEW CAirBaseHandler;

		for (int i = 0; i < MAX_TEAMS; i++) {
			unitsByDefs[i].resize(unitDefHandler->numUnitDefs + 1);
		}
	}
}


CUnitHandler::~CUnitHandler()
{
	list<CUnit*>::iterator usi;
	for (usi = activeUnits.begin(); usi != activeUnits.end(); usi++) {
		delete (*usi);
	}

	delete airBaseHandler;

}

int CUnitHandler::AddUnit(CUnit *unit)
{
	ASSERT_SYNCED_MODE;
	int num=(int)(gs->randFloat())*((int)activeUnits.size()-1);
	std::list<CUnit*>::iterator ui=activeUnits.begin();
	for(int a=0;a<num;++a){
		++ui;
	}
	activeUnits.insert(ui,unit);		//randomize this to make the order in slowupdate random (good if one build say many buildings at once and then many mobile ones etc)

	unit->id=freeIDs.front();
	freeIDs.pop_front();

	units[unit->id]=unit;
	gs->Team(unit->team)->AddUnit(unit,CTeam::AddBuilt);
	unitsByDefs[unit->team][unit->unitDef->id].insert(unit);

	maxUnitRadius = max(unit->radius, maxUnitRadius);

	return unit->id;
}

void CUnitHandler::DeleteUnit(CUnit* unit)
{
	ASSERT_SYNCED_MODE;
	toBeRemoved.push_back(unit);
}

void CUnitHandler::Update()
{
	ASSERT_SYNCED_MODE;

	SCOPED_TIMER("Unit handler");

	while(!toBeRemoved.empty()){
		CUnit* delUnit=toBeRemoved.back();
		toBeRemoved.pop_back();

		int delTeam = 0;
		int delType = 0;
		list<CUnit*>::iterator usi;
		for(usi=activeUnits.begin();usi!=activeUnits.end();++usi){
			if(*usi==delUnit){
				if (slowUpdateIterator!=activeUnits.end() && *usi==*slowUpdateIterator) {
					slowUpdateIterator++;
				}
				delTeam = delUnit->team;
				delType = delUnit->unitDef->id;

				activeUnits.erase(usi);
				units[delUnit->id] = 0;
				freeIDs.push_back(delUnit->id);
				gs->Team(delTeam)->RemoveUnit(delUnit, CTeam::RemoveDied);

				unitsByDefs[delTeam][delType].erase(delUnit);

				delete delUnit;

				break;
			}
		}
		//debug
		for (usi = activeUnits.begin(); usi != activeUnits.end(); /* no post-op */) {
			if (*usi == delUnit){
				logOutput.Print("Error: Duplicated unit found in active units on erase");
				usi = activeUnits.erase(usi);
			} else {
				++usi;
			}
		}
	}

	list<CUnit*>::iterator usi;
	for (usi = activeUnits.begin(); usi != activeUnits.end(); usi++) {
		(*usi)->Update();
	}

	{
		SCOPED_TIMER("Unit slow update");
		if (!(gs->frameNum & 15)) {
			slowUpdateIterator=activeUnits.begin();
		}

		int numToUpdate=activeUnits.size()/16+1;
		for(;slowUpdateIterator!=activeUnits.end() && numToUpdate!=0;++slowUpdateIterator){
			(*slowUpdateIterator)->SlowUpdate();
			numToUpdate--;
		}
	} // for timer destruction

	if(!(gs->frameNum&15)){
		if(diminishingMetalMakers)
			metalMakerEfficiency=8.0f/(8.0f+max(0.0f,sqrtf(metalMakerIncome/gs->activeTeams)-4));
		metalMakerIncome=0;
	}
}

float CUnitHandler::GetBuildHeight(float3 pos, const UnitDef* unitdef)
{
	float minh=-5000;
	float maxh=5000;
	int numBorder=0;
	float borderh=0;
	float* heightmap=readmap->GetHeightmap();

	int xsize=1;
	int ysize=1;

	float maxDif=unitdef->maxHeightDif;
	int x1 = (int)max(0.f,(pos.x-(xsize*0.5f*SQUARE_SIZE))/SQUARE_SIZE);
	int x2 = min(gs->mapx,x1+xsize);
	int z1 = (int)max(0.f,(pos.z-(ysize*0.5f*SQUARE_SIZE))/SQUARE_SIZE);
	int z2 = min(gs->mapy,z1+ysize);

	if (x1 > gs->mapx) x1 = gs->mapx;
	if (x2 < 0) x2 = 0;
	if (z1 > gs->mapy) z1 = gs->mapy;
	if (z2 < 0) z2 = 0;

	for(int x=x1; x<=x2; x++){
		for(int z=z1; z<=z2; z++){
			float orgh=readmap->orgheightmap[z*(gs->mapx+1)+x];
			float h=heightmap[z*(gs->mapx+1)+x];
			if(x==x1 || x==x2 || z==z1 || z==z2){
				numBorder++;
				borderh+=h;
			}
			if(minh<min(h,orgh)-maxDif)
				minh=min(h,orgh)-maxDif;
			if(maxh>max(h,orgh)+maxDif)
				maxh=max(h,orgh)+maxDif;
		}
	}
	float h=borderh/numBorder;

	if(h<minh && minh<maxh)
		h=minh+0.01f;
	if(h>maxh && maxh>minh)
		h=maxh-0.01f;

	return h;
}

int CUnitHandler::TestUnitBuildSquare(const BuildInfo& buildInfo, CFeature *&feature, int allyteam)
{
	feature=0;
	int xsize=buildInfo.GetXSize();

⌨️ 快捷键说明

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