Пример #1
0
void CMilitary::remove(ARegistrar &group) {
	LOG_II("CMilitary::remove group(" << group.key << ")")
	
	// NOTE: we do not destory groups to prevent unnecessary memory allocations
	free.push(lookup[group.key]); // remember index of free group
	
	lookup.erase(group.key);
	activeScoutGroups.erase(group.key);
	activeAttackGroups.erase(group.key);
	mergeScouts.erase(group.key);
	mergeGroups.erase(group.key);
	
	for (std::map<int,CGroup*>::iterator i = assemblingGroups.begin(); i != assemblingGroups.end(); i++) {
		if (i->second->key == group.key) {
			assemblingGroups.erase(group.key);
			break;
		}
	}
	
	// NOTE: CMilitary is registered inside group, so the next lines 
	// are senseless because records.size() == 0 always
	std::list<ARegistrar*>::iterator i;
	for (i = records.begin(); i != records.end(); i++)
		(*i)->remove(group);

	group.unreg(*this);
}
Пример #2
0
void CIntel::onEnemyCreated(int enemy) {
	const UnitDef* ud = ai->cbc->GetUnitDef(enemy);
	if (ud) {
		LOG_II("CIntel::onEnemyCreated Unit(" << enemy << ")")
		//assert(ai->cbc->GetUnitTeam(enemy) != ai->team);
		enemies.addUnit(UT(ud->id), enemy);
	}
}
Пример #3
0
void AssistTask::remove() {
    LOG_II("AssistTask::remove " << (*this))

    // NOTE: we have to remove manually because assisting tasks are not
    // completely built upon ARegistrar pattern
    assist->assisters.remove(this);

    ATask::remove();
}
Пример #4
0
void CEconomy::addUnitOnFinished(CUnit &unit) {
	LOG_II("CEconomy::addUnitOnFinished " << unit)

	unitCategory c = unit.type->cats;

	if ((c&BUILDER).any() || ((c&ASSISTER).any() && (c&MOBILE).any())) {
		CGroup *group = requestGroup();
		group->addUnit(unit);
	}
}
Пример #5
0
void CEconomy::remove(ARegistrar &object) {
	CGroup *group = dynamic_cast<CGroup*>(&object);
	LOG_II("CEconomy::remove " << (*group))

	activeGroups.erase(group->key);
	takenMexes.erase(group->key);
	takenGeo.erase(group->key);

	group->unreg(*this);
	
	ReusableObjectFactory<CGroup>::Release(group);
}
Пример #6
0
int CConfigParser::determineState(int metalIncome, int energyIncome) {
	int previous = state;
	state = 0;
	std::map<int, std::map<std::string, int> >::iterator i;
	for (i = states.begin(); i != states.end(); ++i) {
		if (metalIncome >= i->second["metalIncome"] 
		&& energyIncome >= i->second["energyIncome"])
			state = i->first;
	}
	if (state != previous)
		LOG_II("CConfigParser::determineState(mIncome=" << metalIncome << ", eIncome=" << energyIncome << ") activated state(" << state << ")")
	return state;
}
Пример #7
0
void CMilitary::onEnemyDestroyed(int enemy, int attacker) {
	std::map<int, CGroup*> *activeGroups;
	std::map<int, CGroup*>::iterator itGroup;
	std::map<MilitaryGroupBehaviour, std::map<int, CGroup*>* >::iterator itGroups;

	for (itGroups = groups.begin(); itGroups != groups.end(); ++itGroups) {
		activeGroups = itGroups->second;
		for (itGroup = activeGroups->begin(); itGroup != activeGroups->end(); ++itGroup) {
			if (!itGroup->second->badTargets.empty()) {
				LOG_II("CMilitary::onEnemyDestroyed bad target Unit(" << enemy << ") destroyed for " << (*(itGroup->second)))
				itGroup->second->badTargets.erase(enemy);
			}
		}
	}
}
Пример #8
0
void CUnitTable::remove(ARegistrar &unit) {
	LOG_II("CUnitTable::remove unit(" << unit.key << ")")
	free.push(lookup[unit.key]);
	lookup.erase(unit.key);
	builders.erase(unit.key);
	idle.erase(unit.key);
	metalMakers.erase(unit.key);
	factoriesBuilding.erase(unit.key);
	activeUnits.erase(unit.key);
	factories.erase(unit.key);
	defenses.erase(unit.key);
	unitsAliveTime.erase(unit.key);
	energyStorages.erase(unit.key);
	unitsUnderPlayerControl.erase(unit.key);
	unit.unreg(*this);
}
Пример #9
0
bool CConfigParser::parseConfig(std::string filename) {
	std::string dirfilename = util::GetAbsFileName(ai->cb, std::string(CFG_FOLDER)+filename, true);
	std::ifstream file(dirfilename.c_str());

	if (file.good() && file.is_open()) {
		unsigned int linenr = 0;
		std::vector<std::string> splitted;
		
		templt = false;
		
		while(!file.eof()) {
			linenr++;
			std::string line;

			std::getline(file, line);
			line = line.substr(0, line.find('#') - 1);
			util::RemoveWhiteSpaceInPlace(line);

			if (line.empty() || line[0] == '#')
				continue;

			if (line == "TEMPLATE") {
				templt = true;
				continue;
			}

			if (util::StringContainsChar(line, '{')) {
				/* New state block */
				line.substr(0, line.size() - 1);
				util::StringSplit(line, ':', splitted);
				state = atoi(splitted[1].c_str());
				states[state] = stateVariables;
			}
			else if (util::StringContainsChar(line, '}')) {
				/* Close state block */
				if (states[state].size() == stateVariables.size())
					LOG_II("CConfigParser::parseConfig State("<<state<<") parsed successfully")
				else
					LOG_EE("CConfigParser::parseConfig State("<<state<<") parsed unsuccessfully")
			}
			else {
				/* Add var to curState */
				util::StringSplit(line, ':', splitted);
				states[state][splitted[0]] = atoi(splitted[1].c_str());
			}
		}
Пример #10
0
void MergeTask::onUpdate() {
	/* See which groups can be merged already */
	std::list<CGroup*>::iterator it;
	for (it = groups.begin(); it != groups.end(); ++it) {
		CGroup *g = *it;
		
		if (g->isMicroing())
			continue;
		
		if (pos.distance2D(g->pos()) < range) {
			mergable[g->key] = g;
			g->micro(true);
		}
	}
	
	/* We have at least two groups, now we can merge */
	if (mergable.size() >= 2) {
		std::vector<int> keys;
		std::map<int, CGroup*>::iterator it;
		
		// get keys because while merging "mergable" is reducing...
		for (it = mergable.begin(); it != mergable.end(); ++it) {
			keys.push_back(it->first);
		}
		
		for (int i = 0; i < keys.size(); i++) {
			int key = keys[i];
			if (key != masterGroup->key) {
				CGroup *g = mergable[key];
				LOG_II("MergeTask::update merging " << (*g) << " with " << (*masterGroup))
				// NOTE: group being merged is automatically removed
				masterGroup->merge(*g);
			}
		}
		
		assert(mergable.size() == 1);
		mergable.clear();
		masterGroup->micro(false);
	}

	// if only one (or none) group remains, merging is no longer possible,
	// remove the task, unreg groups...
	if (groups.size() <= 1)
		ATask::remove();
}
Пример #11
0
bool CMilitary::addUnit(CUnit& unit) {
	LOG_II("CMilitary::addUnit " << unit)
	
	assert(unit.group == NULL);

	unitCategory c = unit.type->cats;

	if ((c&ATTACKER).any() && (c&MOBILE).any() && (c&DEFENSE).none()) {
		unitCategory wishedCats = ai->unittable->unitsUnderConstruction[unit.key];
		CGroup* group;
		
		if ((c&SCOUTER).any() && wishedCats.any() && (wishedCats&SCOUTER).none())
			c &= ~SCOUTER; // scout was not requested

		if ((c&SCOUTER).any()) {
			group = requestGroup(SCOUT);
		}
		else if((c&AIR).any() && (c&ARTILLERY).any()) {
			group = requestGroup(BOMBER);
		}
		else if((c&AIR).any() && (c&ASSAULT).none()) {
			group = requestGroup(AIRFIGHTER);
		}
		else {
			/* If there is a new factory, or the current group is busy, request
			   a new group */
			std::map<int,CGroup*>::iterator i = assemblingGroups.find(unit.builtBy);
			if (i == assemblingGroups.end()	|| i->second->busy || !i->second->canAdd(&unit)) {
				group = requestGroup(ENGAGE);
				assemblingGroups[unit.builtBy] = group;
			} else {
				group = i->second;
			}
		}
		group->addUnit(unit);

		return true;
	}

	return false;
}
Пример #12
0
void CCoverageHandler::addUnit(CUnit* unit) {
	LOG_II("CCoverageHandler::addUnit " << (*unit))

	CCoverageCell::NType coreType = getCoreType(unit->type);

	if (coreType != CCoverageCell::UNDEFINED) {
		if (coreUnits.find(unit->key) == coreUnits.end()) {
			// register new core...
			CCoverageCell* c = ReusableObjectFactory<CCoverageCell>::Instance();
			c->ai = ai;
			c->type = coreType;
			c->setCore(unit);
			c->reg(*this);
			layers[c->type].push_back(c);
			coreUnits[unit->key] = c;

			addUncoveredUnits(c);

			LOG_II((*c))
		}
	}
Пример #13
0
void CMilitary::remove(ARegistrar &object) {
	CGroup *group = dynamic_cast<CGroup*>(&object);
	
	LOG_II("CMilitary::remove " << (*group))
	
	activeScoutGroups.erase(group->key);
	activeAttackGroups.erase(group->key);
	activeBomberGroups.erase(group->key);
	activeAirFighterGroups.erase(group->key);
	mergeGroups.erase(group->key);
	
	for (std::map<int,CGroup*>::iterator i = assemblingGroups.begin(); i != assemblingGroups.end(); ++i) {
		if (i->second->key == group->key) {
			assemblingGroups.erase(i->first);
			break;
		}
	}

	group->unreg(*this);

	ReusableObjectFactory<CGroup>::Release(group);
}
Пример #14
0
#include "CWishList.h"

#include "CAI.h"
#include "CUnitTable.h"
#include "CUnit.h"
#include "CConfigParser.h"
#include "CEconomy.h"


CWishList::CWishList(AIClasses *ai) {
	this->ai = ai;
	maxWishlistSize = 0;
}

CWishList::~CWishList() {
	LOG_II("CWishList::Stats MaxWishListSize = " << maxWishlistSize)
}

void CWishList::push(unitCategory include, unitCategory exclude, Wish::NPriority p) {
	std::map<int, CUnit*>::iterator itFac = ai->unittable->factories.begin();
	UnitType *fac;
	for (;itFac != ai->unittable->factories.end(); ++itFac) {
		fac = itFac->second->type;
		std::multimap<float, UnitType*> candidates;
		ai->unittable->getBuildables(fac, include, exclude, candidates);
		if (!candidates.empty()) {
			/* Initialize new std::vector */
			if (wishlist.find(fac->def->id) == wishlist.end()) {
				std::vector<Wish> L;
				wishlist[fac->def->id] = L;
			}
Пример #15
0
void CEconomy::updateIncomes() {
	const int currentFrame = ai->cb->GetCurrentFrame();

	// FIXME:
	// 1) algo sucks when game is started without initial resources
	// 2) these values should be recalculated each time AI has lost almost
	// all of its units (it is like another game start)
	// 3) these values should slowly decay to zero
	if (!stallThresholdsReady) {
		if ((utCommander->cats&FACTORY).any()) {
			mStart = utCommander->def->metalMake;
			eStart = 0.0f;
		}
		else {
			bool oldAlgo = true;
			unitCategory initialFactory = getNextTypeToBuild(utCommander, FACTORY, MIN_TECHLEVEL);
			if (initialFactory.any()) {
				UnitType* facType = ai->unittable->canBuild(utCommander, initialFactory);
				if (facType != NULL) {
					float buildTime = facType->def->buildTime / utCommander->def->buildSpeed;
					float mDrain = facType->def->metalCost / buildTime;
					float eDrain = facType->def->energyCost / buildTime;
					float mTotalIncome = utCommander->def->metalMake * buildTime;
		
					mStart = (1.5f * facType->def->metalCost - ai->cb->GetMetal() - mTotalIncome) / buildTime;
					if (mStart < 0.0f)
						mStart = 0.0f;
					eStart = 0.9f * eDrain;
				
					oldAlgo = false;
				}
			}
		
			if (oldAlgo) {
				mStart = 2.0f * utCommander->def->metalMake;
				eStart = 1.5f * utCommander->def->energyMake;
			}
		}	

		LOG_II("CEconomy::updateIncomes Metal stall threshold: " << mStart)
		LOG_II("CEconomy::updateIncomes Energy stall threshold: " << eStart)
		
		stallThresholdsReady = true;
	}

	incomes++;

	mUsageSummed  += ai->cb->GetMetalUsage();
	eUsageSummed  += ai->cb->GetEnergyUsage();
	mStorage       = ai->cb->GetMetalStorage();
	eStorage       = ai->cb->GetEnergyStorage();

	mNow     = ai->cb->GetMetal();
	eNow     = ai->cb->GetEnergy();
	mIncome  = ai->cb->GetMetalIncome();
	eIncome  = ai->cb->GetEnergyIncome();
	mUsage   = alpha*(mUsageSummed / incomes) + (1.0f-alpha)*(ai->cb->GetMetalUsage());
	eUsage   = beta *(eUsageSummed / incomes) + (1.0f-beta) *(ai->cb->GetEnergyUsage());

	//LOG_II("mIncome = " << mIncome << "; mNow = " << mNow << "; mStorage = " << mStorage)
	//LOG_II("eIncome = " << eIncome << "; eNow = " << eNow << "; eStorage = " << eStorage)

	// FIXME: think smth better to avoid hardcoding, e.g. implement decaying

	if (mIncome < EPS && currentFrame > 32) {
		mstall = (mNow < (mStorage*0.1f));
	}
	else {
		if (ai->unittable->activeUnits.size() < 5)
			mstall = (mNow < (mStorage*0.1f) && mUsage > mIncome) || mIncome < mStart;
		else
			mstall = (mNow < (mStorage*0.1f) && mUsage > mIncome);
	}

	if (eIncome < EPS && currentFrame > 32) {
	    estall = (eNow < (eStorage*0.1f));
	}
	else {
		if (ai->unittable->activeUnits.size() < 5)
			estall = (eNow < (eStorage*0.1f) && eUsage > eIncome) || eIncome < eStart;
		else
			estall = (eNow < (eStorage*0.1f) && eUsage > eIncome);
	}

	mexceeding = (mNow > (mStorage*0.9f) && mUsage < mIncome);
	eexceeding = (eNow > (eStorage*0.9f) && eUsage < eIncome);

	mRequest = (mNow < (mStorage*0.5f) && mUsage > mIncome);
	eRequest = (eNow < (eStorage*0.5f) && eUsage > eIncome);

	int tstate = ai->cfgparser->determineState(mIncome, eIncome);
	if (tstate != state) {
		char buf[64];
		sprintf(buf, "State changed to %d, activated techlevel %d", tstate, ai->cfgparser->getMaxTechLevel());
		LOG_II(buf);
		state = tstate;
	}
}
Пример #16
0
void CIntel::onEnemyDestroyed(int enemy, int attacker) {
	LOG_II("CIntel::onEnemyDestroyed Unit(" << enemy << ")")
	enemies.removeUnit(enemy);
}
Пример #17
0
void CIntel::init() {
	if (initialized) return;
	
	resetCounters();
	updateRoulette();
	
	updateEnemyVector();
	
	/* FIXME:
		I faced situation that on maps with less land there is a direct
		path to enemy unit, but algo below starts to play a non-land game. 
		I could not think up an appropriate algo to avoid this. I thought about
		tracing a path in the beginning of the game from my commander to enemy 
		would be ok, but commander is an amphibious unit. It is not trivial 
		stuff without external helpers in config files or terrain analysis.
	*/
	if(ai->gamemap->IsWaterMap()) {
		allowedFactories.push_back(NAVAL);
		allowedFactories.push_back(HOVER);
	} 
	else {
		unitCategory nextFactory;
		if (ai->gamemap->IsKbotMap()) {
			allowedFactories.push_back(KBOT);
			nextFactory = VEHICLE;
		} 
		else {
			allowedFactories.push_back(VEHICLE);
			nextFactory = KBOT;
		}
		
		if (ai->gamemap->IsHooverMap()) {
			if (ai->gamemap->GetAmountOfWater() > 0.5) {
				allowedFactories.push_back(HOVER);
			}
			else {
				allowedFactories.push_back(nextFactory);
				nextFactory = HOVER;
			}
		}
		
		allowedFactories.push_back(nextFactory);
	}
	// TODO: do not build air on too small maps?
	allowedFactories.push_back(AIRCRAFT);

	// vary first factory among allied AIs...
	int i = ai->allyIndex;
	while (i > 1) {
		allowedFactories.push_back(allowedFactories.front());
		allowedFactories.pop_front();
		i--;
	}
	
	// FIXME: engineer better decision algo
	if (ai->gamemap->IsMetalMap())
		strategyTechUp = true;
	else
		// NOTE: clock() gives much better results than rng.RndFloat() (at least under MSVC)
		strategyTechUp = ((clock() % 3) == 0);

	LOG_II("CIntel::init Tech-up strategy: " << strategyTechUp)

	initialized = true;
}
Пример #18
0
void AttackTask::onEnemyDestroyed(int enemy, int attacker) {
	if (target == enemy) {
		LOG_II("AttackTask::onEnemyDestroyed")
		remove();
	}
}
Пример #19
0
CPathfinder::CPathfinder(AIClasses *ai): ARegistrar(600, std::string("pathfinder")) {
	this->ai   = ai;
	// NOTE: X and Z are in slope map resolution units
	this->X    = int(ai->cb->GetMapWidth()/HEIGHT2SLOPE);
	this->Z    = int(ai->cb->GetMapHeight()/HEIGHT2SLOPE);
	// NOTE: XX and ZZ are in pathgraph map resolution units
	this->XX   = this->X / I_MAP_RES;
	this->ZZ   = this->Z / I_MAP_RES;
	graphSize = XX * ZZ;
	update      = 0;
	repathGroup = -1;
	drawPaths   = false;

	hm = ai->cb->GetHeightMap();
	sm = ai->cb->GetSlopeMap();

	if (CPathfinder::graph.empty()) {
		const std::string cacheVersion(CACHE_VERSION);

		bool readOk = false;
		unsigned int N;
		std::string modname(ai->cb->GetModName());
		modname.resize(modname.size()-4);
		std::string filename = modname + "/" + std::string(ai->cb->GetMapName());
		std::string cacheMarker;

		cacheMarker.resize(cacheVersion.size());

		filename = std::string(CACHE_FOLDER) + filename.substr(0, filename.size()-4) + "-graph.bin";
		filename = util::GetAbsFileName(ai->cb, filename);

		/* See if we can read from binary */
		std::ifstream fin;
		fin.open(filename.c_str(), std::ios::binary | std::ios::in);
		if (fin.good() && fin.is_open()) {
			LOG_II("CPathfinder reading graph from " << filename)
			fin.read(&cacheMarker[0], cacheMarker.size());
			if (!fin.eof() && cacheMarker == cacheVersion) {
				fin.read((char*)&N, sizeof(N));
				if(N == graphSize) {
					for (unsigned int i = 0; i < N; i++) {
						Node *n = Node::unserialize(fin);
						CPathfinder::graph.push_back(n);
					}
					LOG_II("CPathfinder parsed " << CPathfinder::graph.size() << " nodes")
					readOk = true;
				}
			}
			fin.close();
			if(!readOk)
				// TODO: explain for user why?
				LOG_WW("CPathfinder detected invalid cache data")
		}

		if (!readOk)
		{
			std::ofstream fout;

			LOG_II("CPathfinder creating graph at " << filename)
			
			calcGraph();
			
			fout.open(filename.c_str(), std::ios::binary | std::ios::out);
			N = CPathfinder::graph.size();
			fout.write(&cacheVersion[0], cacheVersion.size());
			fout.write((char*)&N, sizeof(N));
			for (unsigned int i = 0; i < N; i++)
				CPathfinder::graph[i]->serialize(fout);
			fout.close();
		}
	}