Graded Invisibility Mod

this mod offer a lot of possibilities for modding, to have "specialists of invisibility".
I like the idea of promotion, and think we can add some "spy experience" for spies and others units in this type (for exemple, if a spy realize some mission, he gain some experience, and can gain a new promotion or invisibility level...).
The possibility to "view" invisible units with improvement is good, but can is possible to have a tag in Cvi4BuildingInfo.xml, that give the same ability to a building ? (i think about starcraft game). Teach the AI is not necessary, because in current version, the AI use a lot (and very well) these invisible units.
 
Yes it is possible to build such a tag in a building. I will be releasing my next addition to Invisibility/visibility this week... it will allow for visible improvements as you mention.

I can of course add a tag that would allow seeing invisible units into a building that would make it possible to see "invisible" units. Easily done. The question is would other modders find this useful. If so, I will do it. If not, I can do it for our mod dub.
 
Wow, I am impressed. I had been looking for something similar to this for a while. The main difference with what I had in mind is that I thought that it should be possible to set a probabilistic ability to see the invisible units. For instance, destroyers with a SeeInvisibleSubmarine tag might have only a 50% chance of seeing a sub within its field of vision. I've always thought it is boring and limiting that the probability of seeing an invisible unit is 100% for units with the SeeInvisible ability.

Civ is certainly very lacking in its implementation of invisibility, and the graded system could open up many new possibilities.

Incidentally, I just found out that invisible submarines in Civ cannot blockade a coastal city, while visible naval units can. This is another example of the lameness of the implementation of invisibility in Civ 4. One of the main uses of Subs in real life is precisely to blockade.
 
1. The first is that I would like to build in a slightly better feedback system for XML errors for the new XML file (Currently there is no checking for bad “links” to missing Invisible types for example.)


I noticed that you appear to be using some sort of chain to determine what units can see which invisible units. Wouldn't it be easier to, say, allow one to define which specific invisible types it can see?

For example, one could have something like this in the xml defined for each unit:

<SeeInvisibles>

<SeeInvisible>
SeeInvisibleSubmarine
</SeeInvisible>

<SeeInvisible>
SeeInvisibleUboat
</SeeInvisible>

</SeeInvisibles>

So then you could put in as many "SeeInvisible" as you wanted for any unit (or define them for any arbitrary SeeInvisible type, if one doesn't want to touch the units xml file). And better, the SeeInvisibles would not have to be tied to an ordered hierarchy. You could have a unit see the best invisible units, and the worst, but not the ones in-between.

This would seem to be more flexible, and would also avoid the possibility of infinite loops being introduced through incorrect xml coding.​
 
NP300 said:
For instance, destroyers with a SeeInvisibleSubmarine tag might have only a 50% chance of seeing a sub within its field of vision

That is a great idea...not hard to implement either! I will think about it.

Incidentally, I just found out that invisible submarines in Civ cannot blockade a coastal city, while visible naval units can
.

Another thing I can look into... I am not sure if I have run into this but I will look into it. I end up modding more than I play :crazyeye: ! (Not that I mind... right now it's actually more fun if not quite as relaxing).


Wouldn't it be easier to, say, allow one to define which specific invisible types it can see?

No... it would not be easier at all, though it would be possible to do (I could do it if I saw a significant). In the end I am not sure the performance tradeoff would be worth it. The way it's being done is very simple and straightforward in implementing what can and cannot be seen. Here is why I did not think it would be worth it:

I have thought about doing something similar to what you suggest but I rejected the idea because from what I understand of it, the world of "stealth" is technology related, the higher the tech, the more you can see. There are of course exceptions but they are rare and ususually have more to do with stationary objects than units. With such a system as your suggestion, the possibilities of "networking" invisibility could potentially get complicated in who can see what (though maybe I could think of a way to minimize this) and in the end, would probably significantly increase the time needed to move units from one plot to another. Remember that every time the unit moves, each plot in close proximity must be updated with the correct visibility settings.
 
That is a great idea...not hard to implement either! I will think about it.

:cool:

Another thing I can look into... I am not sure if I have run into this but I will look into it. I end up modding more than I play :crazyeye: ! (Not that I mind... right now it's actually more fun if not quite as relaxing).

I think it may actually be a bug or a design flaw/poor implementation. I posted a bug report about it:

http://forums.civfanatics.com/showthread.php?t=206397

I ran into it when blockading an enemy civ with subs in an attempt to deprive it of strategic resources. I noticed that even though I had all the enemy ports blockaded, they were still trading strategic resources (and this was before airports). At first I thought it was that naval units could not blockade, but I recently discovered that only subs are unable to blockade.

I suspect that the function that implements the blockade may be requesting data on whether there are any naval units from a function that determines if the units are visible; and subs, being invisible, do not show up and thus the function may incorrectly be reporting that there are no enemy units on the coastal/ocean tiles.

I know what you mean about spending more time modding than playing. Sometimes it happens to me, even though I am mostly limited to XML. If I knew C++ I might have taken a stab at making a mod component like this one. I know some programming but I never learned any object-oriented programming, nor any C programming, and so the source code for Civ looks daunting to me.

No... it would not be easier at all, though it would be possible to do (I could do it if I saw a significant). In the end I am not sure the performance tradeoff would be worth it. The way it's being done is very simple and straightforward in implementing what can and cannot be seen. Here is why I did not think it would be worth it:

Well in that case, it is probably best to use your system. Personally, I actually don't have any use for a non-hierarchical invisibility system. It's just the first way that I would have thought of implementing it because it is more flexible, and was wondering why you chose to use a hierarchical system.
 
myself said:
(I could do it if I saw a significant).

ooops... that should be significant benefit :blush: !
 
That is a great idea...not hard to implement either! I will think about it.

I imagine that the easiest way would be to put in some random generator, giving say 50&#37; odds, for the SeeInvisible ability.

The way I had originally thought of implementing it was to have integer tags, say iInvisible and iSeeInvisible. Their values could range from 0 to 10,000.

Now, the probability of seeing an invisible unit (in percentages) could be determined by calculating

Probability = 1 - (iInvisible - iSeeInvisible)

Now a Submarine could have an iInvisible=100 and a normal ship could have an iSeeInvisible=0. So the odds of the ship seeing the sub would always be 0.

A Destroyer could have an iSeeInvisible=50. So it would have 50% odds of seeing the Sub. And an advanced destroyer could have an iSeeInvisible=100, and so would have 100% odds of seeing the sub. Whenever iInvisible exceeds iSeeInvisible, the odds of detection become 0%. Conversely, when iSeeInvisible is greater than or equal to iInvisible, the odds of detection become 100%.

Now you see, this system is inherently graded. One could improve the invisible abilities of units by changing the integer tags. The cases of seeing units with 100% certainty would be special cases. With a range of 10,000 you could have 100 levels invisibility, which as you mentioned, should be more than enough for anyone.

ooops... that should be significant benefit :blush: !

Of course, I understood you perfectly. I don't see a significant benefit to it myself. As you pointed out, invisibility usually tends to be graded, be it for spies or submarines.
 
I assume you mean:
iProbability = 100 - (iInvisible - iSeeInvisible) and then using 100 as the random max. :) (or some variation thereof).

These are some good ideas. I may work on a second incarnation of this and my latest release (see next post) after I am done my first incarnation of my current (very large) project which I hope to release in March or April (may be longer because it is very involved). If you want to play with it a bit go right ahead!
 
I have released another mod component that is a great addon to this mod... I will post the combined source code in this forum in a couple of days. Meanwhile... here is the link to the Vision Improvements mod component.
 
I assume you mean:
iProbability = 100 - (iInvisible - iSeeInvisible) and then using 100 as the random max. :) (or some variation thereof).

Ah, yes. I forgot they had to be integers, and was thinking of proportions in terms of 50%=0.50. It was just meant to give the general idea. It could be done in many different ways, of course.

Meanwhile... here is the link to the Vision Improvements mod component.

That one also seems like it could be very useful. Good mods!
 
Thanks again.
 
Hello everyone,

I have been learning a bit of C++ in order to take a stab at implementing my own suggestions above. My aim is to create a graded invisibility system that is probabilistic&#8212;that is, you get a probability of seeing an invisible unit, but not usually with 100&#37; odds. Think of how boring it would be if combat between units were deterministic and the stronger unit defeated the weaker unit 100% of the time! Well, this is the current situation with the invisibility system, and it doesn't look like it will be fixed with Beyond the Sword.

I have made a few attempts at modding primem0ver's code, and have come upon something that seems workable. Now, I am a novice at C++(only a few days of self-study so far), so it is not really a very good mod, nor is it how I would like to implement it. But, it is the best I have come up with so far with my very limited C++. My implementation also has a minor bug that I am attempting to squash, which is why I post here now.

My changes are in the CvPlot section. I shall post primem0ver's code, with my modifications in red:

/*******************************************************************************/
/** Added by primem0ver, 27/10/06 */
/** So that units with graded visibility can see all units with a lower grade */
/*******************************************************************************/
// local variables added by primem0ver
CvInvisibleInfo * invType;
if (eSeeInvisible != NO_INVISIBLE) invType = &GC.getInvisibleInfo(eSeeInvisible);
int iLoopCount = 100; // do not go through grade loop more than 100 times
// while this theoretically limits the number of
// links (grades) in a grade chain, it will prevent
// accidental circular chains
// end local variables
srand((unsigned)time(0));

while (iLoopCount > 0)
{
/*************************************************************************/
/* ORIGINAL CODE STARTS BELOW: */
/*************************************************************************/

if (iRange == 0)
{
changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), eSeeInvisible);
return;
}

for (iDX = -(iRange - 1); iDX <= (iRange - 1); iDX++)
{
for (iDY = -(iRange - 1); iDY <= (iRange - 1); iDY++)
{
pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

if (pLoopPlot != NULL)
{
pLoopPlot->changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), eSeeInvisible);

iLevel = pLoopPlot->seeFromLevel(eTeam);

for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));

if (pAdjacentPlot != NULL)
{
pAdjacentPlot->changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), eSeeInvisible);
pAdjacentPlot->changeSeeFromSight(eTeam, ((DirectionTypes)iI), iLevel, bIncrement, eSeeInvisible);
pAdjacentPlot->changeSeeFromSight(eTeam, GC.getTurnLeftDirection(iI), iLevel, bIncrement, eSeeInvisible);
pAdjacentPlot->changeSeeFromSight(eTeam, GC.getTurnRightDirection(iI), iLevel, bIncrement, eSeeInvisible);
}
}
}
}
}
/*******************************************************************************/
/** Added by primem0ver, 27/10/06 */
/** Section controls loop and picks next lower invisibility grade type */
/*******************************************************************************/
if ((eSeeInvisible == NO_INVISIBLE) || ( ( (rand()) % 2 )< 1) ) iLoopCount = 0; // if we have hit the end of a chain, set the loopcount to end of loop
else
{
eSeeInvisible = (InvisibleTypes) invType->getNextInvisibleGrade();
if (eSeeInvisible != NO_INVISIBLE) invType = &GC.getInvisibleInfo(eSeeInvisible);
}
--iLoopCount;

} // THIS IS AN EXTRA BRACE THAT CLOSES while loop... by primem0ver
/*************************************************************************/
/*************************************************************************/

The first line in red simply sets a seed for the random number generator.

The second (and last) line in red, tells the function that controls whether the loop continues to a deeper level to stop IF it has encountered the end of the chain OR if a random number appears. The chance of the random number appearing is currently set to 50% for testing purposes. So what happens is that the loop stops 50% of the time, even if it has not hit the end of the chain. Since the loops are nested, the odds are 25% that it will have stopped by the second loop, 12.5% by the third, and so on and so forth. This has the effect that units lower in the invisibility chain become harder and harder to see (exponentially so) to units further up in the chain.

Now, here is how I set it up to be workable... I set up 8 invisible grades, from INVISIBLE_00 to INVISIBLE_07. I set the uboat to have Invisible_02 for invisibility and invisible_06 for SeeInvisible. I set the submarine to have Invisible_01 for invisibility and invisibile_04 for SeeInvisible. And the silent sub is set to have Invisible_00 invisibility and Invisible_03 for SeeInvisible.

This all has the effect that the uboats have 1/16 odds of seeing each other, 1/32 odds of seeing a submarine, and 1/64 odds of seeing a Silent Sub. The Submarines have 1/4 odds of seeing Uboats, 1/8 odds of seeing other submarines, and 1/16 odds of seeing Silent Subs. Finally, the Silent Subs have 1/2 odds of seeing uboats, 1/4 odds of seeing submarines, and 1/8 odds of seeing other silent Subs.

It all works fine as long as you do not set a unit to have a SeeInvisible lower than the highest Invisibility. For example, if I set the Silent Sub to have a SeeInvisible=00, then they would not be able to see Submarines or Uboats at all! This is because in the original graded invisibility mod, the higher invisibility levels are supposed to be the better ones.

In any case, my mod seems to be working well so far, except for one little detail. Sometimes, some plots become completely invisible&#8212;even when I have a unit in them. However, this happens probabilistically. I assume that the code I inserted is somehow interfering with the plotting code contained in the loop (code which I do not really understand) and preventing it from properly percolating down the levels. It only appears to happen when units that have the ability to see invisible units start overlapping each other's paths. It does not happen with units that have no SeeInvisible abilities. It also does not happen with units with SeeInvisible if it has SeeInvisible=00 (at the end of the chain).

I attach a screenshot of an invisible destroyer to illustrate.

So, I am wondering if anyone can enlighten this C++ novice as to any better ways to implement the probabilistic graded invisibility system, or any ways to resolve this specific problem. In any case, so far this mod seems good enough to use. I can live with this minor bug if it will give me probabilistic invisibility, although I wonder if this little bug might cause serious problems for the AI. I do not post the C++ files yet as I have not fully tested this yet.
 

Attachments

  • VD.PNG
    VD.PNG
    380.9 KB · Views: 109
Alright, I think I quashed the bug that I alluded to above. Once more, here is the code with my changes/additions in red:

/*******************************************************************************************************************************/
/*******************************************************************************************************************************/
{
// original local variables
CvPlot* pLoopPlot;
CvPlot* pAdjacentPlot;
int iLevel;
int iDX, iDY;
int iI;

/*******************************************************************************/
/** Added by primem0ver, 27/10/06 */
/** So that units with graded visibility can see all units with a lower grade */
/*******************************************************************************/
// local variables added by primem0ver
CvInvisibleInfo * invType;
if (eSeeInvisible != NO_INVISIBLE) invType = &GC.getInvisibleInfo(eSeeInvisible);
int iLoopCount = 100; // do not go through grade loop more than 100 times
// while this theoretically limits the number of
// links (grades) in a grade chain, it will prevent
// accidental circular chains
// end local variables
int num = 5;
int den = 5;
int pastden = 3;
int nextden = 8;
srand((unsigned)time(0));


while (iLoopCount > 0)
{
/*************************************************************************/
/* ORIGINAL CODE STARTS BELOW: */
/*************************************************************************/


if (iRange == 0)
{
changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), eSeeInvisible);
return;
}

for (iDX = -(iRange - 1); iDX <= (iRange - 1); iDX++)
{
for (iDY = -(iRange - 1); iDY <= (iRange - 1); iDY++)
{
pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

if (pLoopPlot != NULL)
{
pLoopPlot->changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), eSeeInvisible);

iLevel = pLoopPlot->seeFromLevel(eTeam);

for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));

if (pAdjacentPlot != NULL)
{
if (( (rand()) &#37; den )< num)
pAdjacentPlot->changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), eSeeInvisible);
else
pAdjacentPlot->changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), NO_INVISIBLE);
pAdjacentPlot->changeSeeFromSight(eTeam, ((DirectionTypes)iI), iLevel, bIncrement, eSeeInvisible);
pAdjacentPlot->changeSeeFromSight(eTeam, GC.getTurnLeftDirection(iI), iLevel, bIncrement, eSeeInvisible);
pAdjacentPlot->changeSeeFromSight(eTeam, GC.getTurnRightDirection(iI), iLevel, bIncrement, eSeeInvisible);
}
}
}
}
}
/*******************************************************************************/
/** Added by primem0ver, 27/10/06 */
/** Section controls loop and picks next lower invisibility grade type */
/*******************************************************************************/
if ((eSeeInvisible == NO_INVISIBLE) ) iLoopCount = 0; // if we have hit the end of a chain, set the loopcount to end of loop
else
{
eSeeInvisible = (InvisibleTypes) invType->getNextInvisibleGrade();
if (eSeeInvisible != NO_INVISIBLE) invType = &GC.getInvisibleInfo(eSeeInvisible);
}
pastden = den;
den = nextden;
nextden = pastden + den;

--iLoopCount;

} // THIS IS AN EXTRA BRACE THAT CLOSES while loop... by primem0ver
/*************************************************************************/
/*************************************************************************/

Apparently the line that controls whether or not a unit can see an invisible unit is this one:

pAdjacentPlot->changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), eSeeInvisible);

But it seems to also control some plotting code. So, I had to use the random number generator to control whether the original line or the one substituting NO_INVISIBLE for invisible is used. This seems to have completely eliminated the plotting problems.

Now, to gradually reduce the odds of spotting a unit lower on the chain, I gradually increase the denominator (den) in my random function, with each repetition of the loop.

I just wanted to let you know that I seem to have solved the problem. I will continue testing to see if any other bugs come up. It's amazing but I am actually starting to understand this portion of SDK code.
 
This is an interesting idea and I remember you mentioning it a while back. Two things:

1. Civ4 has its own random number generator so it isn't necessary to seed your own.

2. The only possible problem I can see (but I would have to look into it further and I am not going to argue with success if it is working ok) is that it should be remembered (if I am remembering correctly) that this loop is executed when the invisible unit changes position. If you do not finish the loop and the sub stays still, it will NEVER see another unit if I remember correctly... but I would have to double check.
 
1. Civ4 has its own random number generator so it isn't necessary to seed your own.

I am aware of this, but I do not know how to use Civ4's PRNG. I am new at this.

2. The only possible problem I can see (but I would have to look into it further and I am not going to argue with success if it is working ok) is that it should be remembered (if I am remembering correctly) that this loop is executed when the invisible unit changes position. If you do not finish the loop and the sub stays still, it will NEVER see another unit if I remember correctly... but I would have to double check.

I am not exactly sure what you are referring to here. Are you refering to a unit with a "SeeInvisible" ability (say a destroyer) or to a unit that is itself invisible (subs)? Are you referring to the whole while loop that you inserted, or to one of the smaller plotting loops?

I have experimented in the world builder by putting many subs in a starting position. Then I would place subs from another civ in range of this starting position. The subs were able to see the other subs within their initial range (according to the odds that I set), before they had made any moves. I have also tested if the AI can see my subs, by moving them near their units with SeeInvisible. Sometimes the AI civ would contact me (because it could see me), but other times it would not (because it could not see me).

Now, as far as I have been able to tell, the following loop is executed every time a unit with SeeInvisible moves, for each tile where invisible units are located:

if (( (rand()) &#37; den )< num)
pAdjacentPlot->changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), eSeeInvisible);
else
pAdjacentPlot->changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), NO_INVISIBLE); pAdjacentPlot->changeSeeFromSight(eTeam, ((DirectionTypes)iI), iLevel, bIncrement, eSeeInvisible);
pAdjacentPlot->changeSeeFromSight(eTeam, GC.getTurnLeftDirection(iI), iLevel, bIncrement, eSeeInvisible);
pAdjacentPlot->changeSeeFromSight(eTeam, GC.getTurnRightDirection(iI), iLevel, bIncrement, eSeeInvisible);

So, even though I might give the unit 50% odds of seeing the invisible units, in practice they have better than 50% odds because the odds are recalculated on every move. Is this recalculation on every move, for units with SeeInvisible, what you were alluding to?

However, I did see some problems when I did not let the main loop complete through to the lowest level. Those problems disappeared when I changed the code such that the loop always completes through to the lowest level.
 
Want a better invisible system for your mod? Do you want spies who can see lesser spies or units that can see invisible units of a lesseer invisible "technology?" without the lower units seeing the better units? Tired of your units being only able to see one invisible type?

Yup very much.

You had red in my minds cause you even did that certaind units could be invisible only on peaks or in forests. So when partisants would leave forest they're would be more vulnerable for enemy patrols.

I'm adding this to WW2 1939 - definettelly one of the interesting modcomps, good work, and thank you :)

About ideas. I don't know if it's possible to implement them or they are interesting enough to be added - but you may concider adding them:

- Perhaps some promotions system would be fine
so unit can gain invisibility after reachin woodsman ii promotion he can get another promotion making it invisible in mods.
-The units shouldn't be always 100% invisible
Because you can sometimes spot partisants or snipers - so there should be small chance to spot invisible units - higher in open fields (plains, grass, tundra, snow) and smaller in forests, jungles, cities, mountains and peaks.
The unit that stays one turn more on the field could get more of % of invisiblity - imagine sniper that waits to hunt down soldiers, and the sniper that changes position.
 
About ideas. I don't know if it's possible to implement them or they are interesting enough to be added - but you may concider adding them:

- Perhaps some promotions system would be fine
so unit can gain invisibility after reachin woodsman ii promotion he can get another promotion making it invisible in mods.

I'm in the final stages of completing just such a mod.

In the new mod, units will be able to have multiple invisible types. You can set one as default in the UnitInfos or you can add new ones with promotions.

You will also be able to add promotions that allow you to see invisibles.

I've already merged the Graded Invisibility Mod into my promotions mod, so you wouldn't have to do that.

I want to use this to give promotions for units to hide in certain terrain/features and then add another promotion called Tracking that allows you to see them. But it could also be used to give units a Sonar promotion to see subs or something like that... some interesting possibilities.
 
Back
Top Bottom