Author Topic: unit creation  (Read 3677 times)

discodowney

  • Guest
unit creation
« on: 15 November 2010, 19:35:02 »
so im looking at how the AI decides to build units and which ones to build. There are several line of code along the lines of:

if(warriorCount<10) ai->addTask(new ProduceTask(UnitClass::WARRIOR));

How does the game know which unit type to build from that since Warrior is just an enum? Where is it in the code where the AI decides which unit type is made?

Also there is:

if(workerCount>=10) ai->addTask(new ProduceTask(UnitClass::WARRIOR));

why does the number of workers have any bearing on whether or not to build a warrior?

Omega

  • MegaGlest Team
  • Dragon
  • ********
  • Posts: 6,167
  • Professional bug writer
    • View Profile
    • Personal site
Re: unit creation
« Reply #1 on: 15 November 2010, 21:42:15 »
so im looking at how the AI decides to build units and which ones to build. There are several line of code along the lines of:

if(warriorCount<10) ai->addTask(new ProduceTask(UnitClass::WARRIOR));

How does the game know which unit type to build from that since Warrior is just an enum? Where is it in the code where the AI decides which unit type is made?

Also there is:

if(workerCount>=10) ai->addTask(new ProduceTask(UnitClass::WARRIOR));

why does the number of workers have any bearing on whether or not to build a warrior?
The unit's "type" is determined based on their commands. "Warriors" have an attack command, "workers" have a harvest command, etc etc. Also, the AI seems to determine play style based on commands. For example, if the "worker" unit has a morph command, it is played like magic (emphasis on morphing) instead of like tech (emphasis on production).
Edit the MegaGlest wiki: http://docs.megaglest.org/

My personal projects: http://github.com/KatrinaHoffert

discodowney

  • Guest
Re: unit creation
« Reply #2 on: 16 November 2010, 01:38:11 »
I get that, but how does it decide between a swordman, archer and guard. Im assuming all 3 are classed as Warriors. So then how does it decide which of these to build?

Omega

  • MegaGlest Team
  • Dragon
  • ********
  • Posts: 6,167
  • Professional bug writer
    • View Profile
    • Personal site
Re: unit creation
« Reply #3 on: 16 November 2010, 04:05:57 »
I get that, but how does it decide between a swordman, archer and guard. Im assuming all 3 are classed as Warriors. So then how does it decide which of these to build?
No clue. Randomness perhaps? Oh silnaaaarm... ;)
Edit the MegaGlest wiki: http://docs.megaglest.org/

My personal projects: http://github.com/KatrinaHoffert

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: unit creation
« Reply #4 on: 16 November 2010, 04:28:13 »
No clue. Randomness perhaps? Oh silnaaaarm... ;)

Correct, random.

I get that, but how does it decide between a swordman, archer and guard. Im assuming all 3 are classed as Warriors. So then how does it decide which of these to build?

ProduceTask has three data members, resourceType, unitClass and unitType. Only one may be valid, and in AiRuleProduce::execute() the task is funnelled to either AiRuleProduce::produceResources(), AiRuleProduce::produceGeneric() or AiRuleProduce::produceSpecific() depending on which is valid.

If a ProduceTask has a valid UnitClass, then it is sent to AiRuleProduce::produceGeneric() and a random warrior is chosen from those currently available. The task is then thrown away, and a new ProduceTask is added with the specific unit type.

So, in a nutshell, produceGeneric() looks at what can be produced and selects one (at random) and posts a new task.  Later, the new task is processed by produceSpecific(), which looks at what units can can produce it, selects the 'best' one to do so (the best being the one with the least commands on queue) and issues the command.
Glest Advanced Engine - Code Monkey

Timeline | Downloads

discodowney

  • Guest
Re: unit creation
« Reply #5 on: 17 November 2010, 18:07:23 »
You say if it has a valid UnitClass. How would it have an invalid one?

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: unit creation
« Reply #6 on: 18 November 2010, 10:59:53 »
Have a look at the three constructors for ProduceTask, the two that don't take a UnitClass as a param, set the unitClass data member to UnitClas::INVALID.

INVALID and COUNT are added to all our WRAPPED_ and STRINGY_ ENUMs automatically.
Glest Advanced Engine - Code Monkey

Timeline | Downloads

discodowney

  • Guest
Re: unit creation
« Reply #7 on: 18 November 2010, 22:06:27 »
Cool. Thanks. Looking at the code i can see how its done now.

A question about the AI. is there a way for the AI to know how many/what units the player has at any given time?

discodowney

  • Guest
Re: unit creation
« Reply #8 on: 6 December 2010, 16:24:04 »
so the code picks a unit at random. For the tech side, how does the AI make a catapult for example? Since the Catapult is made by morphing.

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: unit creation
« Reply #9 on: 8 December 2010, 08:11:02 »
AiRuleProduce checks both produce and morph commands, they are handled together.
Glest Advanced Engine - Code Monkey

Timeline | Downloads

discodowney

  • Guest
Re: unit creation
« Reply #10 on: 12 December 2010, 15:31:43 »
Cool.
So can someone tell me what is the deal with the AI in regards to resources. I know in some RTS games the AI gets additional resources to help them. Does that happen here?
So for a human player you need x amount of gold and y amount of wood for unit z. Is it the same coast for the AI?

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: unit creation
« Reply #11 on: 12 December 2010, 15:56:55 »
The 'regular' CPU is the same as for human players, Ultra get a multiplier of 3 (ie, if they harvest 20 gold, they get 60), and the Mega has a multiplier of 4.

Glest Advanced Engine - Code Monkey

Timeline | Downloads

discodowney

  • Guest
Re: unit creation
« Reply #12 on: 12 December 2010, 16:02:23 »
Cheers.

Another question (Im afraid i dont think these will be ending soon, if you dont mind) is about the following method

int Ai::getCountOfType(const UnitType *ut)

This gets the number of instances of a specific unit type. But is there any way to specify ut? When its called in the code it is as something like:
Code: [Select]

for (int i=0; i < factionType->getUnitTypeCount(); ++i) {
const UnitType *ut = factionType->getUnitType(i);
if (!ai->getCountOfType(ut)) {
continue;
}

So it goes through all the types and gets the numbers for each. If i wanted to just check the number of, say archers, is there a way to do that?


silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: unit creation
« Reply #13 on: 13 December 2010, 13:24:11 »
You need to get a pointer to the actual UnitType, this could be done in a few ways, if you already have a pointer to the factionType, it would be,
Code: [Select]
factionType->getUnitType("archer");

Use Ai::unitTypeCount to get a possibly (but not likely) out-of-date version of the same information, much cheaper (is updated in Ai::updateStatistics(), which I believe is called once a second).
Glest Advanced Engine - Code Monkey

Timeline | Downloads

discodowney

  • Guest
Re: unit creation
« Reply #14 on: 13 December 2010, 18:25:26 »
Yeah okay. Thats how i thought it was to be done but wasnt sure if it just using a string like you say. Cheers

discodowney

  • Guest
Re: unit creation
« Reply #15 on: 14 December 2010, 14:53:10 »
Just need confirmation here, but im assuming that in the following:
Code: [Select]
const Resource *r = aiInterface->getResource(*it);
if (r->getAmount() < amount) {

r->getAmount() returns the amout of that resource that is available to a player?

discodowney

  • Guest
Re: unit creation
« Reply #16 on: 14 December 2010, 23:25:29 »
The 'regular' CPU is the same as for human players, Ultra get a multiplier of 3 (ie, if they harvest 20 gold, they get 60), and the Mega has a multiplier of 4.


Ive a question about this aswell. In the ai_rule class there is the following:
Code: [Select]
if(warriorCount<10) ai->addTask(new ProduceTask(UnitClass::WARRIOR));
if(warriorRatio<0.20) ai->addTask(new ProduceTask(UnitClass::WARRIOR));
if(warriorRatio<0.30) ai->addTask(new ProduceTask(UnitClass::WARRIOR));
if(workerCount>=10) ai->addTask(new ProduceTask(UnitClass::WARRIOR));
if(workerCount>=15) ai->addTask(new ProduceTask(UnitClass::WARRIOR));

When is the resources taken away? It doesnt seem to be taken right away anyway, so if the above ifs are all true and 5 warriors are put in the tasklist. What happens if the money isnt there to create them? Are they just left on the produce list until the money is available? Do cheaper ones get done first then or is it in the order they get created?

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: unit creation
« Reply #17 on: 15 December 2010, 08:35:49 »
Just need confirmation here, but im assuming that in the following:
Code: [Select]
const Resource *r = aiInterface->getResource(*it);
if (r->getAmount() < amount) {

r->getAmount() returns the amout of that resource that is available to a player?

Yes, this is correct. The class Resource is unfortunately used for a few different purposes, and should really be refactored. In this case, Faction::getResource() it is the amount of that resource the faction currently has stored.

Ive a question about this aswell. In the ai_rule class there is the following:
Code: [Select]
if(warriorCount<10) ai->addTask(new ProduceTask(UnitClass::WARRIOR));
if(warriorRatio<0.20) ai->addTask(new ProduceTask(UnitClass::WARRIOR));
if(warriorRatio<0.30) ai->addTask(new ProduceTask(UnitClass::WARRIOR));
if(workerCount>=10) ai->addTask(new ProduceTask(UnitClass::WARRIOR));
if(workerCount>=15) ai->addTask(new ProduceTask(UnitClass::WARRIOR));

When is the resources taken away? It doesnt seem to be taken right away anyway, so if the above ifs are all true and 5 warriors are put in the tasklist. What happens if the money isnt there to create them? Are they just left on the produce list until the money is available? Do cheaper ones get done first then or is it in the order they get created?

The costs are applied when an actual command is given, via AiRuleProduce::execute(), if the resource costs are not met, 'generic' produce tasks are thrown away, specific produce tasks are re-posted to be tried later.

Glest Advanced Engine - Code Monkey

Timeline | Downloads

discodowney

  • Guest
Re: unit creation
« Reply #18 on: 16 December 2010, 14:15:15 »
Cool.

For the resources how do you differentiate between the different classes?
Code: [Select]
for (int i=0; i < m_resourceTypes.size(); ++i) {
     const ResourceType* &rt = m_resourceTypes[i];
     const Resource *res = m_faction->getResource(rt); // amount & balance

Theres the above thats used. to go through the resources, but how do i know which is gold or wood? Theres the ResourceType but that is one of

TECHTREE,
TILESET,
STATIC,
CONSUMABLE

I dont see how i can tell which is gold and which is wood from this?


hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: unit creation
« Reply #19 on: 17 December 2010, 06:56:21 »
ResourceTypes inherits from DisplayableType which inherits from NameIdPair. So you can call rt.getName() and compare with a string (it would be best not to use a hardcoded string, though).
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: unit creation
« Reply #20 on: 17 December 2010, 13:24:36 »
rt.getName()

Code: [Select]
error C2228: left of '.getName' must have class/struct/union
        type is 'const Glest::ProtoTypes::ResourceType *'
        did you intend to use '->' instead?
:P

Theres the above thats used. to go through the resources, but how do i know which is gold or wood? Theres the ResourceType but that is one of

Just to clarify, a ResourceType represents a resource available in the techtree, the 'tech', 'tileset', 'static', 'consumable' thing is a ResourceClass (and each ResourceType is of exactly one ResourceClass).

As hailstone pointed out, you can get the name as a string and compare that, but it seems very specific, as hailstone also hinted at. I realise you have a time-frame to work within, and want to keep things as simple as possible, but I would suggest treating all resources of class tech-tree and tileset the same. They are resources you can harvest, when you look at the 'costs' for units (in code), you will end up looking at the same things, const ResourceType*.

So there is really no need know which is 'gold' or 'stone' or whatever, you need X amount of Y to produce something you want to produce, so make harvesting Y a priority.
That's obviously a simplification, in reality you will need two or three different resource types to build something, and you will be considering building more than one thing, but adding all those costs up, you will get an idea of what 'balance' of harvesting you need to do. And you wont need to know which is 'gold'  ;)

Stop thinking like a human !  :O
Glest Advanced Engine - Code Monkey

Timeline | Downloads

discodowney

  • Guest
Re: unit creation
« Reply #21 on: 17 December 2010, 13:29:16 »
I need to know because the method im using, a svm, needs to check the values of certain "vectors" each time its called. 2 of them are the amount of gold and the amount of wood. So i do definiately need to know the specific amount of each available.

Ive got them now. Cheers.

discodowney

  • Guest
Re: unit creation
« Reply #22 on: 5 January 2011, 20:15:22 »
So im trying to get the AI to create a specific unit, for now, just Archer. So if removed the code

Code: [Select]
*if(warriorCount<10) ai->addTask(new ProduceTask(UnitClass::WARRIOR));
if(warriorRatio<0.20) ai->addTask(new ProduceTask(UnitClass::WARRIOR));
if(warriorRatio<0.30) ai->addTask(new ProduceTask(UnitClass::WARRIOR));
if(workerCount>=10) ai->addTask(new ProduceTask(UnitClass::WARRIOR));
if(workerCount>=15) ai->addTask(new ProduceTask(UnitClass::WARRIOR));

And inserted the lines

Code: [Select]
const UnitType *archer= factionType->getUnitType("archer");
ai->addTask(new ProduceTask(archer));

Archers are mostly made but one or two swordman units are still being created. Can anyone explain why this is happening?

P.S. This is just at the start when only Archers and Swordmen are available.


Coldfusionstorm

  • Golem
  • ******
  • Posts: 868
    • View Profile
Re: unit creation
« Reply #23 on: 5 January 2011, 21:22:52 »
WiP Game developer.
I do danish translations.
"i break stuff"

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: unit creation
« Reply #24 on: 8 January 2011, 22:58:26 »
...
Archers are mostly made but one or two swordman units are still being created. Can anyone explain why this is happening?

Look for more code that adds produce tasks, there must be some 'generic' ones (with UnitClass::WARRIOR) slipping in from somewhere.

Perhaps set a break point in the constructor (the one for UnitClass) and when it hits just look at the next step up the stack to find where it is coming from.

Glest Advanced Engine - Code Monkey

Timeline | Downloads