Exemple #1
0
void AttackTask::onUpdate() {
	CGroup *group = firstGroup();

	if (group->isMicroing() && group->isIdle()) {
		targetAlt = -1; // for sure
		group->micro(false);
	}

	if (isMoving) {
		/* Keep tracking the target */
		pos = ai->cbc->GetUnitPos(target);

		float3 gpos = group->pos();
		float dist = gpos.distance2D(pos);
		float range = group->getRange();

		/* See if we can attack our target already */
		if (dist <= range) {
			bool canAttack = true;

			/*
			// for ground units prevent shooting across hill...
			if ((group->cats&AIR).none()) {
				// FIXME: improve
				dist = ai->pathfinder->getPathLength(*group, pos);
				canAttack = (dist <= range * 1.1f);
			}
			*/

			if (canAttack) {
				if ((group->cats&BUILDER).any())
					group->reclaim(target);
				else
					group->attack(target);
				isMoving = false;
				ai->pathfinder->remove(*group);
				group->micro(true);
			}
		}
	}

	/* See if we can attack a target we found on our path */
	if (!(group->isMicroing() || urgent())) {
		if ((group->cats&BUILDER).any())
			resourceScan(); // builders should not be too aggressive
		else
			enemyScan(targetAlt);
	}
}
Exemple #2
0
void AssistTask::onUpdate() {
    CGroup *group = firstGroup();

    if (group->isMicroing() && group->isIdle()) {
        targetAlt = -1; // for sure
        group->micro(false);
    }

    if (!assisting) {
        if (isMoving) {
            /* Keep tracking the target */
            pos = assist->pos;

            float3 gpos = group->pos();
            float dist = gpos.distance2D(pos);
            float range = group->getRange();

            if (dist <= range) {
                bool canAssist = true;
                /*
                // for ground units prevent assisting across hill...
                if ((group->cats&AIR).none()) {
                	dist = ai->pathfinder->getPathLength(*group, pos);
                	canAssist = (dist <= range * 1.1f);
                }
                */
                if (canAssist) {
                    isMoving = false;
                    ai->pathfinder->remove(*group);
                }
            }
        }

        if (!isMoving) {
            group->assist(*assist);
            group->micro(true);
            assisting = true;
        }
    }

    if (!group->isMicroing()) {
        if ((group->cats&BUILDER).any())
            resourceScan(); // builders should not be too aggressive
        else if ((group->cats&AIR).none()) {
            enemyScan(targetAlt);
        }
    }
}
Exemple #3
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();
}
Exemple #4
0
void CEconomy::update() {
	int buildersCount = 0;
	int assistersCount = 0;
	int maxTechLevel = ai->cfgparser->getMaxTechLevel();

	/* See if we can improve our eco by controlling metalmakers */
	controlMetalMakers();

	/* If we are stalling, do something about it */
	preventStalling();

	/* Update idle worker groups */
	std::map<int, CGroup*>::iterator i;
	for (i = activeGroups.begin(); i != activeGroups.end(); ++i) {
		CGroup *group = i->second;
		CUnit *unit = group->firstUnit();

		if ((group->cats&MOBILE).any() && (group->cats&BUILDER).any())
			buildersCount++;
		if ((group->cats&MOBILE).any() && (group->cats&ASSISTER).any() && (group->cats&BUILDER).none())
			assistersCount++;

		if (group->busy || !group->canPerformTasks())
			continue;

		if ((group->cats&FACTORY).any()) {
			ai->tasks->addTask(new FactoryTask(ai, *group));
			continue;
		}
		
		if ((group->cats&STATIC).any() && (group->cats&BUILDER).none()) {
			// we don't have a task for current unit type yet (these types are:
			// MEXTRACTOR & geoplant)
			continue;
		}

		float3 pos = group->pos();

		// NOTE: we're using special algo for commander to prevent
		// it walking outside the base
		if ((unit->type->cats&COMMANDER).any()) {
			tryFixingStall(group);
			if (group->busy) continue;
			
			/* If we don't have a factory, build one */
			if (ai->unittable->factories.empty() || mexceeding) {
				unitCategory factory = getNextTypeToBuild(unit, FACTORY, maxTechLevel);
				if (factory.any())
					buildOrAssist(*group, BUILD_FACTORY, factory);
				if (group->busy) continue;
			}

			/* If we are exceeding and don't have estorage yet, build estorage */
			if (eexceeding && !ai->unittable->factories.empty()) {
				if (ai->unittable->energyStorages.size() < ai->cfgparser->getMaxTechLevel())
					buildOrAssist(*group, BUILD_ESTORAGE, ESTORAGE);
				if (group->busy) continue;
			}
			
			// NOTE: in NOTA only static commanders can build TECH1 factories
			if ((unit->type->cats&STATIC).any()) {
				/* See if this unit can build desired factory */
				unitCategory factory = getNextTypeToBuild(unit, FACTORY, maxTechLevel);
				if (factory.any())
					buildOrAssist(*group, BUILD_FACTORY, factory);
				if (group->busy) continue;

				factory = getNextTypeToBuild(unit, BUILDER|STATIC, maxTechLevel);
				if (factory.any())
					// TODO: invoke BUILD_ASSISTER building algo instead of
					// BUILD_FACTORY to properly place static builders?
					buildOrAssist(*group, BUILD_FACTORY, factory);
				if (group->busy) continue;
			}
			
			// build nearby metal extractors if possible...
			if (mstall && !ai->gamemap->IsMetalMap()) {
				// NOTE: there is a special hack withing buildOrAssist() 
				// to prevent building unnecessary MMAKERS
				buildOrAssist(*group, BUILD_MPROVIDER, MEXTRACTOR);
				if (group->busy) continue;
			}
			
			// see if we can build defense
			tryBuildingDefense(group);
			if (group->busy) continue;
			
			tryAssistingFactory(group);
			if (group->busy) continue;
		}
		else if ((unit->type->cats&BUILDER).any()) {
			tryFixingStall(group);
			if (group->busy) continue;
    		
    		/* See if this unit can build desired factory */
    		unitCategory factory = getNextTypeToBuild(unit, FACTORY, maxTechLevel);
    		if (factory.any())
    			buildOrAssist(*group, BUILD_FACTORY, factory);
    		if (group->busy) continue;
    		
    		/* If we are overflowing energy build an estorage */
    		if (eexceeding && !mRequest) {
    			if (ai->unittable->energyStorages.size() < ai->cfgparser->getMaxTechLevel())
    				buildOrAssist(*group, BUILD_ESTORAGE, ESTORAGE);
    			if (group->busy) continue;
    		}

    		/* If we are overflowing metal build an mstorage */
    		if (mexceeding && !eRequest) {
    			buildOrAssist(*group, BUILD_MSTORAGE, MSTORAGE);
    			if (group->busy) continue;
    		}

    		/* If both requested, see what is required most */
    		if (eRequest && mRequest) {
    			if ((mNow / mStorage) > (eNow / eStorage))
    				buildOrAssist(*group, BUILD_EPROVIDER, EMAKER);
    			else
    				buildOrAssist(*group, BUILD_MPROVIDER, MEXTRACTOR);
    			if (group->busy) continue;
    		}
    		
    		/* See if we can build defense */
    		tryBuildingDefense(group);
    		if (group->busy) continue;
    		
    		tryBuildingAntiNuke(group);
    		if (group->busy) continue;
    		
			tryBuildingJammer(group);
			if (group->busy) continue;
    		
    		tryBuildingStaticAssister(group);
    		if (group->busy) continue;
    		
    		/* Else just provide what is requested */
    		if (eRequest) {
    			buildOrAssist(*group, BUILD_EPROVIDER, EMAKER);
    			if (group->busy) continue;
    		}
    		
    		if (mRequest) {
    			buildOrAssist(*group, BUILD_MPROVIDER, MEXTRACTOR);
    			if (group->busy) continue;
    		}

    		tryAssistingFactory(group);
    		if (group->busy) continue;
    		
    		tryBuildingShield(group);
    		if (group->busy) continue;

    		/* Otherwise just expand */
    		if (!ai->gamemap->IsMetalMap()) {
    			if ((mNow / mStorage) > (eNow / eStorage))
    				buildOrAssist(*group, BUILD_EPROVIDER, EMAKER);
    			else
    				buildOrAssist(*group, BUILD_MPROVIDER, MEXTRACTOR);
    		}
		}
		else if ((unit->type->cats&ASSISTER).any()) {
			// TODO: repair damaged buildings (& non-moving units?)
			// TODO: finish unfinished bulidings
			tryAssist(group, BUILD_IMP_DEFENSE);
			if (group->busy) continue;
    		tryAssistingFactory(group);
    		if (group->busy) continue;
			tryAssist(group, BUILD_AG_DEFENSE);
			if (group->busy) continue;
			tryAssist(group, BUILD_AA_DEFENSE);
			if (group->busy) continue;
			tryAssist(group, BUILD_UW_DEFENSE);
			if (group->busy) continue;
			tryAssist(group, BUILD_MISC_DEFENSE);
			if (group->busy) continue;
		}
	}

	// TODO: consider assistersCount & military groups count for
	// requesting assisters

	if (buildersCount < ai->cfgparser->getMaxWorkers()
	&& (buildersCount < ai->cfgparser->getMinWorkers()))
		ai->wishlist->push(BUILDER, 0, Wish::HIGH);
	else {
		if (buildersCount < ai->cfgparser->getMaxWorkers())
			ai->wishlist->push(BUILDER, 0, Wish::NORMAL);
	}
}
Exemple #5
0
float3 CEconomy::getBestSpot(CGroup& group, std::list<float3>& resources, std::map<int, float3>& tracker, bool metal) {
	bool staticBuilder = (group.cats&STATIC).any();
	bool canBuildUnderWater = (group.cats&(SEA|SUB|AIR)).any();
	bool canBuildAboveWater = (group.cats&(LAND|AIR)).any();
	float bestDist = std::numeric_limits<float>::max();
	float3 bestSpot = ERRORVECTOR;
	float3 gpos = group.pos();
	float radius;
	
	if (metal)
		radius = ai->cb->GetExtractorRadius();
	else
		radius = 16.0f;

	std::list<float3>::iterator i;
	std::map<int, float3>::iterator j;
	for (i = resources.begin(); i != resources.end(); ++i) {
		if (i->y < 0.0f) {
			if (!canBuildUnderWater)
				continue;
		}
		else {
			if (!canBuildAboveWater)
				continue;
		}
		
		bool taken = false;
		for (j = tracker.begin(); j != tracker.end(); ++j) {
			if (i->distance2D(j->second) < radius) {
				taken = true;
				break;
			}
		}
		if (taken) continue; // already taken or scheduled by current AI

		int numUnits = ai->cb->GetFriendlyUnits(&ai->unitIDs[0], *i, 1.1f * radius);
		for (int u = 0; u < numUnits; u++) {
			const int uid = ai->unitIDs[u];
			const UnitDef *ud = ai->cb->GetUnitDef(uid);
			if (metal)
				taken = (UC(ud->id) & MEXTRACTOR).any();
			else
				taken = ud->needGeo;
			if (taken) break;
		}
		if (taken) continue; // already taken by ally team

		float dist = gpos.distance2D(*i);

		if (staticBuilder) {
			if (dist > group.buildRange)
				continue; // spot is out of range
		}
		
		/*
		// NOTE: getPathLength() also considers static units
		float dist = ai->pathfinder->getPathLength(group, *i);
		if (dist < 0.0f)
			continue; // spot is out of build range or unreachable
		*/

		// TODO: actually any spot with any threat should be skipped; 
		// to implement this effectively we need to refactor tasks, cause
		// builder during approaching should scan target place for threat
		// periodically; currently it does not, so skipping dangerous spot
		// has no real profit
		
		dist += 1000.0f * group.getThreat(*i, 300.0f);
		if (dist < bestDist) {
			bestDist = dist;
			bestSpot = *i;
		}
	}

	if (bestSpot != ERRORVECTOR)
		// TODO: improper place for this
		tracker[group.key] = bestSpot;

	return bestSpot;
}
Exemple #6
0
void CEconomy::buildOrAssist(CGroup& group, buildType bt, unitCategory include, unitCategory exclude) {
	ATask* task = canAssist(bt, group);
	if (task != NULL) {
		ai->tasks->addTask(new AssistTask(ai, *task, group));
		return;
	}
	
	if ((group.cats&BUILDER).none())
		return;

	float3 pos = group.pos();
	float3 goal = pos;
	unitCategory catsWhere = canBuildWhere(group.cats);
	unitCategory catsWhereStrict = canBuildWhere(group.cats, true);

	if (bt == BUILD_EPROVIDER) {
		if (!windmap)
			exclude |= WIND;
		if (!worthBuildingTidal)
			exclude |= TIDAL;
	}
	else if (bt == BUILD_MPROVIDER) {
		if ((include&MEXTRACTOR).any()) {
			goal = getClosestOpenMetalSpot(group);
			if (goal != ERRORVECTOR)
				if (goal.y < 0.0f)
					exclude |= (LAND|AIR);
				else
					exclude |= (SEA|SUB);
		}
	}

	const CUnit* unit = group.firstUnit();
	bool isComm = (unit->type->cats&COMMANDER).any();
	std::multimap<float, UnitType*> candidates;
	
	// retrieve the allowed buildable units...
	if ((include&MEXTRACTOR).any())
		ai->unittable->getBuildables(unit->type, include|catsWhereStrict, exclude, candidates);
	else		
		ai->unittable->getBuildables(unit->type, include|catsWhere, exclude, candidates);
	
   	std::multimap<float, UnitType*>::iterator i = candidates.begin();
   	int iterations = candidates.size() / (ai->cfgparser->getTotalStates() - state + 1);
   	bool affordable = false;

	if (!candidates.empty()) {
    	/* Determine which of these we can afford */
    	while(iterations >= 0) {
    		if (canAffordToBuild(unit->type, i->second))
    			affordable = true;
    		else
    			break;

    		if (i == --candidates.end())
    			break;
    		iterations--;
    		i++;
    	}
	}
	else if (bt != BUILD_MPROVIDER) {
		return;
	}
	else {
		goal = ERRORVECTOR;
	}
	
	/* Perform the build */
	switch(bt) {
		case BUILD_EPROVIDER: {
			if (i->second->def->needGeo) {
				goal = getClosestOpenGeoSpot(group);
				if (goal != ERRORVECTOR) {
					// TODO: prevent commander walking?
					if (!eRequest && ai->pathfinder->getETA(group, goal) > 450.0f) {
						goal = ERRORVECTOR;
					}
				}
			}
			else if ((i->second->cats&EBOOSTER).any()) {
				goal = ai->coverage->getNextClosestBuildSite(unit, i->second);
			}

			if (goal == ERRORVECTOR) {
				goal = pos;
				if (i != candidates.begin())
					--i;
				else
					++i;
			}
			
			if (i != candidates.end())
				ai->tasks->addTask(new BuildTask(ai, bt, i->second, group, goal));

			break;
		}

		case BUILD_MPROVIDER: {
			bool canBuildMMaker = (eIncome - eUsage) >= METAL2ENERGY || eexceeding;
			
			if (goal != ERRORVECTOR) {
				bool allowDirectTask = true;
				
				// TODO: there is a flaw in logic because when spot is under
				// threat we anyway send builders there
				
				if (isComm) {
					int numOtherBuilders = ai->unittable->builders.size() - ai->unittable->factories.size();
					// if commander can build mmakers and there is enough
					// ordinary builders then prevent it walking for more than 
					// 20 sec...
					if (numOtherBuilders > 2 && ai->unittable->canBuild(unit->type, MMAKER))
						allowDirectTask = ai->pathfinder->getETA(group, goal) < 600.0f;
				}

				if (allowDirectTask) {
					ai->tasks->addTask(new BuildTask(ai, bt, i->second, group, goal));
				}
				else if (mstall && (isComm || areMMakersEnabled) && canBuildMMaker) {
					UnitType* mmaker = ai->unittable->canBuild(unit->type, MMAKER);
					if (mmaker != NULL)
						ai->tasks->addTask(new BuildTask(ai, bt, mmaker, group, pos));
				}
			}
			else if (mstall && areMMakersEnabled && canBuildMMaker) {
				UnitType* mmaker = ai->unittable->canBuild(unit->type, MMAKER);
				if (mmaker != NULL)
					ai->tasks->addTask(new BuildTask(ai, bt, mmaker, group, pos));
			}
			else if (!eexceeding) {
				buildOrAssist(group, BUILD_EPROVIDER, EMAKER);
			}
			break;
		}

		case BUILD_MSTORAGE: case BUILD_ESTORAGE: {
			/* Start building storage after enough ingame time */
			if (!taskInProgress(bt) && ai->cb->GetCurrentFrame() > 30*60*7) {
				pos = ai->defensematrix->getBestDefendedPos(0);
				ai->tasks->addTask(new BuildTask(ai, bt, i->second, group, pos));
			}
			break;
		}

		case BUILD_FACTORY: {
			if (!taskInProgress(bt)) {
				int numFactories = ai->unittable->factories.size();

				bool build = numFactories <= 0;
				
				// TODO: add some delay before building next factory

				if (!build && affordable && !eRequest) {
					float m = mNow / mStorage;
			
					switch(state) {
						case 0: {
							build = (m > 0.45f);
							break;
						}
						case 1: {
							build = (m > 0.40f);
							break;
						}
						case 2: {
							build = (m > 0.35f);
							break;
						}
						case 3: {
							build = (m > 0.3f);
							break;
						}
						case 4: {
							build = (m > 0.25f);
							break;
						}
						case 5: {
							build = (m > 0.2f);
							break;
						}
						case 6: {
							build = (m > 0.15f);
							break;
						}
						default: {
							build = (m > 0.1f);
						}
					}
				}

				if (build) {
					// TODO: fix getBestDefendedPos() for static builders
					if (numFactories > 1 && (unit->type->cats&MOBILE).any()) {
						goal = ai->coverage->getClosestDefendedPos(pos);
						if (goal == ERRORVECTOR) {
							goal = pos;
						}
					}
					ai->tasks->addTask(new BuildTask(ai, bt, i->second, group, goal));
				}
			}
			break;
		}
		
		case BUILD_IMP_DEFENSE: {
			// NOTE: important defense placement selects important place,
			// not closest one as other BUILD_XX_DEFENSE algoes do
			if (!taskInProgress(bt)) {
				bool allowTask = true;
				
				// TODO: implement in getNextXXXBuildSite() "radius" argument
				// and fill it for static builders
            	goal = ai->coverage->getNextImportantBuildSite(i->second);
				
				allowTask = (goal != ERRORVECTOR);

				if (allowTask && isComm)
					allowTask = ai->pathfinder->getETA(group, goal) < 300.0f;
				
				if (allowTask)
					ai->tasks->addTask(new BuildTask(ai, bt, i->second, group, goal));
			}
			break;
		}
		
		case BUILD_AG_DEFENSE: case BUILD_AA_DEFENSE: case BUILD_UW_DEFENSE: case BUILD_MISC_DEFENSE: {
			if (affordable && !taskInProgress(bt)) {
				bool allowTask = true;
				
				// TODO: implement in getNextBuildSite() "radius" argument
				// and fill it for static builders
				goal = ai->coverage->getNextClosestBuildSite(unit, i->second);
				
				allowTask = (goal != ERRORVECTOR);

				if (allowTask && isComm)
					allowTask = ai->pathfinder->getETA(group, goal) < 300.0f;
				
				if (allowTask)
					ai->tasks->addTask(new BuildTask(ai, bt, i->second, group, goal));
			}
			break;
		}

		default: {
			if (affordable && !taskInProgress(bt))
				ai->tasks->addTask(new BuildTask(ai, bt, i->second, group, goal));
			break;
		}
	}
}