Example #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);
}
Example #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);
	}
}
Example #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();
}
Example #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);
	}
}
Example #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);
}
Example #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;
}
Example #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);
			}
		}
	}
}
Example #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);
}
Example #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());
			}
		}
Example #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();
}
Example #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;
}
Example #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))
		}
	}
Example #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);
}
Example #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;
			}
Example #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;
	}
}
Example #16
0
void CIntel::onEnemyDestroyed(int enemy, int attacker) {
	LOG_II("CIntel::onEnemyDestroyed Unit(" << enemy << ")")
	enemies.removeUnit(enemy);
}
Example #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;
}
Example #18
0
void AttackTask::onEnemyDestroyed(int enemy, int attacker) {
	if (target == enemy) {
		LOG_II("AttackTask::onEnemyDestroyed")
		remove();
	}
}
Example #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();
		}
	}