Jump to content

adding Supply


niektb
 Share

Recommended Posts

I wanted to create a new gameplay aspect: Supplies

What I actually want is that whenever a certain unit comes out of a certain area (own territory + supply aura's) his stats a reduced (whether that would be lower health, lower battle stats or a degeneration of it's stats, deciding that would require playtesting)

I had in mind of coding some stuff doing the following:

Selecting own territory + supply aura area and invert the selection. Check if the unit is in the latter selected area and if so apply actions.

I think I need some code from the Territory decay and the aura part, correct?

Can anyone help me with the start? (Since I've got no idea of how this stuff works in 0 A.D.)

Edited by niektb
Link to comment
Share on other sites

You don't need auras. Auras are made to be bound to an "aura giver", like a temple, hero ...

Also, the way you want it (checking the territory every turn from JS) will cause a lot of extra lag.

You will have to mess with C++ to make it perform well. The best would be if from the CCmpPosition component, you check store the current territory, and compare it with the new territory every time the unit moved. When the territory changed, send a message you created to that unit. When you have a patch for this, it can be included in the main repo, as I see there's a problem now: moving entities don't update their territory decay when they move out of the territory. In the message, you can add a "from" and "to" territory, which will make further checking easier.

After that (small bug for us, feature needed for you) is solved, you can implement a different "value modifying" component (like auras and technologies currently).

First of all, that component needs to detect if some statistic changed. So it needs to listen to the message you created above, and for the actual stat changes, you can look at the Auras component. When there's a possibility a stat changed, you need to advertise it by sending a ValueModification message to that entity.

Next to checking if the stat changed, you also need to make the new value available. All stats that can be changed to through one of the methods of the ValueModification helper script (in simulation/helpers). The ApplyValueModificationsToEntity method will be enough. You won't edit player stats (as a player has no position), nor template stats (which are used to display the stats of units in the production queue, so only when all units stats are changed). You get the original value, and you can use that to calculate the new value which you have to return. You'll certainly have to work on top of the technology change (so call your code after that), else the caching of technologies becomes useless. But you can either apply it after or before aura changes.

You will also need a cache. For some values (like the attack values), the ApplyValueModificationsToEntity code is called every turn when you have a unit selected. In the technology component, the resulting value is calculated once, and cached after that. That's a good caching method for things that don't change often, and for which the base almost never changes. For your component, I suggest to use the same caching as Auras, that only caches the difference.

Maybe it's possible to reuse parts of the code (like you could reuse the AuraManager for the caching, but you will most likely need a new component to detect the territory changes.

Link to comment
Share on other sites

I was merely talking about auras because there would be entities like supply cart who have a supply area around them in which that decay effect wouldn't happen.

Oh, and I'm afraid I won't be able to do the C++ part since my knowledge of C++ is only absolute basic.

Edited by niektb
Link to comment
Share on other sites

But basically you're saying that in the CCmpPosition.cpp the territory should be checked and then a message send to the JS-part that the territory is changed, only if it's changed (and preferably some extra info to state what was the former territory and what is the current). On message fire the appropriate values are modified and cached, the same way as is happening with the auras.

Am I right?

Link to comment
Share on other sites

Yes. You need that message because the JS part can't check every turn if some unit now has a different territory under it.

Adding the message won't be that much work. You can look at the PositionChanged message (ack is your friend), and try to copy it entirely. After that, you only change the condition on which the message gets send (when the territory under it is different from the old one).

Link to comment
Share on other sites

You mean this one?

void AdvertisePositionChanges(){	if (m_InWorld)	{		CMessagePositionChanged msg(GetEntityId(), true, m_X, m_Z, m_RotY);		GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg);	}	else	{		CMessagePositionChanged msg(GetEntityId(), false, entity_pos_t::Zero(), entity_pos_t::Zero(), entity_angle_t::Zero());		GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg);	}}
Link to comment
Share on other sites

Yes, and the definition of the message http://trac.wildfiregames.com/browser/ps/trunk/source/simulation2/MessageTypes.h

I think it's all what's needed.

Then in the JS components, you can just listen to the message by implementing the On... method (like OnPositionChanged for the PositionChanged message).

And of course, the arguments of the PositionChanged message are the new position (that's the data that gets send with the message), while your data should be the old and the new territory.

  • Like 1
Link to comment
Share on other sites

Should a certain approach work?

virtual void TerritoryCheck(){	current_Territory = CCmpTerritoryManager.GetOwner(GetPosition2D);	If (current_Territory != last_Territory){		AdvertiseTerritoryChanges();	}	last_Territory = current_Territory;}

Of course I need to pass some parameters along, but that I'll do later on.

I'm only struggling with the results of the CCmpTerritoryManager.GetOwner() call. What are these?

Link to comment
Share on other sites

The CCmpTerritoryManager.GetOwner(pos, pos) method returns the player id of the x-z position you gave in the argument. So if you call it with the position of the entity you're checking, it returns the owner of the territory the unit is on. The return type (player_id_t) is a type we have defined in C++ to denoter player ids (usuall 0 to 8 for all players + gaia). When you send the message with the player ids, and listen to it with JS, JS will only see a number (0 to 8).

You'll also have to decide what happens when units move out of the world (this happens when they die, or when they get garrisoned). I suggest changing it to INVALID_PLAYER as owner (which is represented with -1 IIRC).

For the code, you should do something like this:

CmpPtr<ICmpTerritoryManager> cmpTerritoryManager(GetGetSystemEntity());player_id_t newTerritory = cmpTerritoryManager->GetOwner(m_X, m_Z);if (newTerritory != lastTerritory){    CMessageTerritoryPositionChanged(GetEntityId(), lastTerritory, newTerritory);    GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg);    lastTerritory = newTerritory;}

You can just include it inside the existing AdvertisePositionChanges. As it's also advertising a certain position change, and you're sure it gets called at the right times.

Link to comment
Share on other sites

Since the C++ part is included in the main repo I started to work on the JS-part. However some questions were raised during the process.

1. How do I advertise to engine messages? This way?

certainFunction.prototype.On[messagename] = function(msg) {}

When there's a possibility a stat changed, you need to advertise it by sending a ValueModification message to that entity.

2. How do I do advertising a message to a entity? Just by calling this function from within my own component?

function ApplyValueModificationsToEntity(tech_type, current_value, entity){	var cmpTechMan = QueryOwnerInterface(entity, IID_TechnologyManager);	if (cmpTechMan)		var value = cmpTechMan.ApplyModifications(tech_type, current_value, entity);	else		var value = current_value;	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);	if (!cmpAuraManager)	    return value;	return cmpAuraManager.ApplyModifications(tech_type, value, entity);}

3. Check whether the entity is in range of a supply giver. How is that currently done with aura's?

4. How do I make sure my script is loaded and ran?

5.

You'll certainly have to work on top of the technology change (so call your code after that), else the caching of technologies becomes useless. But you can either apply it after or before aura changes.

How do I control the sequence scripts are run in 0 A.D.?

Link to comment
Share on other sites

Since the C++ part is included in the main repo I started to work on the JS-part. However some questions were raised during the process.

1. How do I advertise to engine messages? This way?

certainFunction.prototype.On[messagename] = function(msg) {}
That's right.

2. How do I do advertising a message to a entity? Just by calling this function from within my own component?

function ApplyValueModificationsToEntity(tech_type, current_value, entity){	var cmpTechMan = QueryOwnerInterface(entity, IID_TechnologyManager);	if (cmpTechMan)		var value = cmpTechMan.ApplyModifications(tech_type, current_value, entity);	else		var value = current_value;	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);	if (!cmpAuraManager)	    return value;	return cmpAuraManager.ApplyModifications(tech_type, value, entity);}
By posting or broadcasting a message. Posting sends it to a specific entity. Broadcasting sends it to everything that listens (every entity that has a component with the right On... method).

See AuraManager.js:49

Or if you use the AruaManager for the caching, you can also use it to send the messages I guess.

3. Check whether the entity is in range of a supply giver. How is that currently done with aura's?

Via the rangemanager component. In the rangemanager, you can register a query, and it will advertise any changes to the right entity (via the OnRangeUpdate message).

See Auras.js:130 and 201

4. How do I make sure my script is loaded and ran?

Euh, Every script in the simulation directory is ran on the start of the game. This means, for normal components, that the functions are initialised at that point. To use the functions, it needs to be called by other functions, or listen to messages.

5.

How do I control the sequence scripts are run in 0 A.D.?

I mean in simulation/helpers/ValueModification.js. That file just contains 3 functions that are used to call the technologies and aura modifications. Including yours there isn't that hard.

  • Like 1
Link to comment
Share on other sites

I need some thoughts on the best way to implement supplies.

First a question:

Should the stats be restored (in case of hitpoints) if the unit moves into a supply range, or should the unit keep the degenerated values unless he is being healed by a healer?

Currently I see two ways of implementing supplies:

1. All units (at least all unit who are going to be dependent on supplies) receive a initial degeneration value of hitpoints. This is being prevented by moving the unit in own/ally territory or a supply range (from supply carts etc.)

pros: relatively easy to implement I guess.

cons: Not really flexible: only possible to change hitpoints,

2. No initial degeneration value. Units receive a decay effect when they move out of own/ally territory into neutral/enemy.

pros: flexible: not only hitpoints can be changed, also armor/attack and other unit stats.

cons: Hard to create a degeneration effect and harder to implement.

Other than that:

How do I create a new tag in a XML-file (okay, that is not so hard) and make sure that it gets readed in the JS-script(That is my actual question)?

A stated above supply carts will be created, possible extensions might include limiting the amount of supply a cart can offer (the rate is determined by the amount of supply requiring soldiers in range) and create supply lines by creating additional units who are capable of gathering supplies at certain buildings/places and then moving it to the supply cart. It also enables some additional strategic features in battle. (think of your soldiers destroying the other cart and that way making sure that the stats of the enemies' soldiers are lowered and therefore get easily beaten if there is no other supply giver available. In case of supply lines it is also needed to watch your rear and intercept eventual raiders trying to starve your army)

Edited by niektb
  • Like 1
Link to comment
Share on other sites

I need some thoughts on the best way to implement supplies.

First a question:

Should the stats be restored (in case of hitpoints) if the unit moves into a supply range, or should the unit keep the degenerated values unless he is being healed by a healer?

Restoring the health will be rather hard to do. It also lessens the punishment for going out of the supply range, while it enforces micromanagement (getting your people back into the supply range at the exact right time). So I think you can guess what my opinion is ;)

Currently I see two ways of implementing supplies:

1. All units (at least all unit who are going to be dependent on supplies) receive a initial degeneration value of hitpoints. This is being prevented by moving the unit in own/ally territory or a supply range (from supply carts etc.)

pros: relatively easy to implement I guess.

cons: Not really flexible: only possible to change hitpoints,

2. No initial degeneration value. Units receive a decay effect when they move out of own/ally territory into neutral/enemy.

pros: flexible: not only hitpoints can be changed, also armor/attack and other unit stats.

cons: Hard to create a degeneration effect and harder to implement.

With number 1, you mean an immediate subtraction of the health (as in a single subtraction of 20hp for example)? I think that's not very nice for the users. They can walk out of the supply range by accident once (or multiple times), while it hardly punishes the player when they deliberately leave the supply range.

For a degeneration rate, you can set the regenRate in the Health component to something negative.

Other than that:

How do I create a new tag in a XML-file (okay, that is not so hard) and make sure that it gets readed in the JS-script(That is my actual question)?

A stated above supply carts will be created, possible extensions might include limiting the amount of supply a cart can offer (the rate is determined by the amount of supply requiring soldiers in range) and create supply lines by creating additional units who are capable of gathering supplies at certain buildings/places and then moving it to the supply cart. It also enables some additional strategic features in battle. (think of your soldiers destroying the other cart and that way making sure that the stats of the enemies' soldiers are lowered and therefore get easily beaten if there is no other supply giver available. In case of supply lines it is also needed to watch your rear and intercept eventual raiders trying to starve your army)

The XML tags are defined in the component's schema (the first few lines of every component script). And when the component is initiated, the information is available under the this.template variable (as strings). So to add new XML tags to an existing component, you need to adapt the schema. If you add a new component, you automatically have the base tag (with the name of the component), and you can add sub-tags in the schema of that component.

Link to comment
Share on other sites

I would say you should wait until you've tested it before you worry about that. More healers means less fighting units after all, and the other player should have the benefit of being in their own territory and thus not need as many healers so they could use more fighting units.

Link to comment
Share on other sites

  • 2 weeks later...

Well limit the max number of healers then ;)

PLZ don't limit anything (I'm already annoyed with limited towers/fortresses).

Balance things instead, please.

(even a population cap would become unneeded if we had some kind of "upkeep" system e.g. gather rate decreases with population/number of buildings to simulate payment and administration costs)

Edited by FeXoR
  • Like 2
Link to comment
Share on other sites

PLZ don't limit anything (I'm already annoyed with limited towers/fortresses).

Balance things instead, please.

(even a population cap would become unneeded if we had some kind of "upkeep" system e.g. gather rate decreases with population/number of buildings to simulate payment and administration costs)

Really, I agree.

Link to comment
Share on other sites

(even a population cap would become unneeded if we had some kind of "upkeep" system e.g. gather rate decreases with population/number of buildings to simulate payment and administration costs)

It reminds me of one of our planned features that is not yet in our list. Thanks!

(units will need resources, so the more units, the more difficult to feed, though the administrative and management idea sounds promising too - we have this for fields already where more units start hindering/decreasing gather rates)

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...