Fallout: Tame The Wastes bug reports

Ok I have put up a request in the SDK forum for some help with figuring out the solution to this, check it out HERE

With your fix flitz, does opp fire still trigger for the 'right' circumstances?

Also again good discovery, this is a big help! I knew we had not got opp fire right yet :)

I am gonna trry out your solution and see how it goes, and then we can see if we can find a more comprehensive solution that makes opp fire work exactly as I want it to.

Nice work!
 
Ok I have put up a request in the SDK forum for some help with figuring out the solution to this, check it out HERE

With your fix flitz, does opp fire still trigger for the 'right' circumstances?

Also again good discovery, this is a big help! I knew we had not got opp fire right yet :)

I am gonna trry out your solution and see how it goes, and then we can see if we can find a more comprehensive solution that makes opp fire work exactly as I want it to.

Nice work!

Thanks, I would gladly help out further.
I can take a closer look at the units involved in the CTD and see why the iTheirStrength returns 0. The called function is very long so I just skimmed it.

If I understand you correctly, you want non-melee units to do something like ranged bombardment with their base-strength, is that correct ?
 
Basically, we have a system set up where we have a melee (icombat) and a ranged strength (iaircombat). Opp fire is supposed to work with those that have an iaircombat value, or to put it another way, those with an iairrange of 1+ (those that have a ranged strength). So I want the attacker to use his iaircombat to attack with opp fire (if they have a range strength) and the defender to use his icombat (melee strength) {Which in Fallout terms would be the equivalent of strength and endurance, it represents both health and melee strength).

So the event would run something like this.

Baddie enters range of opp fire,
check goodie(attacker) has iaircombat OR iairrange greater than 0
if true
then attacker uses iaircombat vs defender's icombat to determine damage
defender (baddie) takes damage.
if false
then nothing happens.

that is basically it.

Also using your current fix I still get a CTD which could be our slaver related issue. Which archid is hopefully looking into when he can.
 
Do you have a savegame of this CTD with the fix ?

I also took your explanation and took another look at the doOpportunityFire() function.
I think something might have been incorrectly switched there.
It says:
iOurStrength = airCurrCombatStr(pDefender);
and later:
iTheirStrength = pDefender->maxCombatStr(pPlot, this);

I think "pDefender" and "this" in those two calls should be the other way around because we need the iaircombatstrength of the attacker for which doOpportunityFire() has been called and then iTheirStrength should be calculated for the defending unit.
I swapped those two for the calculation and it resulted in the iOurStrength still being 0 (will check why) but the iTheirStrength was now 500, which looks better to me.

More things I noticed:
  • You use airCurrCombatStr() for the attacker but maxCombatStr() for the defender. Is it intentional that one uses the max strength and the other the current strength ?
  • for the unit doing the opportunity fire, you loop over all directions. It looks to me as this could result in up to 8 opportunity fire attacks for a single unit during one turn. Is this supposed to happen ?

_______________________________________________________________________________________________________________

I added the two checks you mentioned for the attacker's iAirCombat and iAirRange. When one the two is > 0, then opportunity fire is engaged, otherwise the whole function is skipped.

I upload the corresponding source file for you to look at. When you specify the 2 things above, it shouldn't be hard to implement the function to do what it should.
 

Attachments

  • CvUnit.7z
    66.3 KB · Views: 176
As far as I remember, maxcombatstr references icombat (health melee strength) which is what we want the defender to use, and iaircombat is for the attacker to use. Now to clarify attacker and defender, the attacker is using oppfire. I think it is defined as pdefender, because the 'attacking' unit is fortified

ok, I think I have the solution, check here
 
As far as I remember, maxcombatstr references icombat (health melee strength) which is what we want the defender to use, and iaircombat is for the attacker to use. Now to clarify attacker and defender, the attacker is using oppfire. I think it is defined as pdefender, because the 'attacking' unit is fortified

ok, I think I have the solution, check here

You're right, I see now what it means. From the definition of the function:
Code:
int CvUnit::maxCombatStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails) const
The second parameter is supposed to be the attacker so giving it "this" there in your call is correct.

I also looked at the proposed solution and compared it with the code you already have and it is basically the same.
You have in doOppFire():
Code:
	iOurStrength = airCurrCombatStr(pDefender);
	FAssertMsg(iOurStrength > 0, "Combat strength is expected to be greater than zero");
	iTheirStrength = pDefender->maxCombatStr(pPlot, this);

	iStrengthFactor = ((iOurStrength + iTheirStrength + 1) / 2);

	iDamage = std::max(1, ((GC.getDefineINT("RANGE_COMBAT_DAMAGE")) * (iOurStrength) / (iTheirStrength)));

	return iDamage;

The rangeCombatDamage() function has:
Code:
	iOurStrength = airCurrCombatStr(pDefender);
	FAssertMsg(iOurStrength > 0, "Combat strength is expected to be greater than zero");
	iTheirStrength = pDefender->maxCombatStr(pPlot, this);

	iStrengthFactor = ((iOurStrength + iTheirStrength + 1) / 2);

	iDamage = std::max(1, ((GC.getDefineINT("RANGE_COMBAT_DAMAGE")) * (iOurStrength) / (iTheirStrength)));

	return iDamage;

So it is doing exactly the same (aside from the unused variable iStrengthFactor). So I wouldn't expect any fixes by using this function, it's just a wrapper for what is already there.

Also, this code doesn't prevent the division-by-zero, because it also doesn't test the iTheirStrength-value before doing the division.
 
I also got a new CTD. As it looks, it happens because some AI unit is trying to bombard a city but there is a nullpointer for the city to bombard. I will see why that happens.

The problem was that in line 5410 of CvUnit.cpp, function bool CvUnit::bombard() a nullpointer to pBombardCity was dereferenced for some reason.

If you check the function, you can see that the pointer is tested for null at several occasions. But then almost at the end of the function, the pointer is just used for a method call, regardless of being null or not. This is really an oversight, I added the necessary test.

The fixes to the doOpportunityFire() function are also in this file, just lookup the string "/** flitz" to find them all.
 

Attachments

  • CvUnit.7z
    66.3 KB · Views: 182
hmm, that is strange.. I guess it could be a conflict between the range attack and the city bombard (reduce defence bonus) attack, and the ai must be confusing them or something... maybe?

It could also be something from Super forts, as i think there is some ai about attacking forts like they are cities, i.e. bombarding, maybe something in the ai is conflicting there too. We had some difficulty merging SF and K-mod ai code, so it could be related to that..

We probably have different .dlls now so chances are the save conflict and crash
 
Ok, there are more problems. The savegame which crashed due to the city bombard still crashes after my fix. During the same end-turn-calculations but at a later point.

This time it is related to a stack attack. It seems that again the city is referenced by a nullpointer, so there is a stack attack being executed on an invalid location or something. Should be a similar fix at a different location. I am looking for it right now.

Edit:
Seems to be coming from K-Mod this time...
The code is this (CvUnitAI.cpp : 25927 - CvUnitAI::AI_stackAttackCity(int iPowerThreshold)):
Code:
CvCity* pCity = pLoopPlot->getPlotCity();
// This automatic threshold calculation is used by AI_follow; and so we can't assume this unit is the head of the group.
// ... But I think it's fair to assume that if our group has any bombard, it the head unit will have it.
if (getGroup()->getHeadUnit()->bombardRate() > 0)
{
  // if we can bombard, then we should do a rough calculation to give us a 'skip bombard' threshold.
  iPowerThreshold = ((GC.getMAX_CITY_DEFENSE_DAMAGE()-pCity->getDefenseDamage())

So there is the calculation for pCity which isn't checked for null before it is used which gives an access violation in my case. I don't know by which means this case is supposed to be prevented normally, but this way, it doesn't look good.
I will wrap it in another !=NULL test and see if there are more problems of this kind.

Edit2:
Fortunately, the second fix was sufficient and the game continued to run normally afterwards.
 
ok, my guess is this was introduced when merging superfort and kmod, as there were a lot of problems merging these ais.

I am too tired to figure out what you have said and your solutions, but it certainly sounds good.

do you know about running ai games?

if you set the cheat code to Chipotle in the config file in my document you can run ai turns with ctrl+shift+x, it has been what I have been using to test for breaks lately
 
Ok, I can give that a try.
So far I had just been playing normally and debugged the crashes that occurred along the way.
 
I got another CTD and found another reason for it (another division-by-zero at another line of code).

The concerned code comes from K-Mod.
It's line 1246 from CvUnitAI.cpp:
Code:
iValue /= (100 + cityDefenseModifier());
I checked and in my case cityDefenseModifier() happens to give the result -100, so the righthand side of the expression is 0 here.

In the same functions there are more expressions which look similar. I wonder whether K-Mod runs stable when it has expressions like these ...

The stupid thing is: I can just fix this issue by testing for zero before doing the division, but I don't know the context of this, so what would be the desired value to have here.
I will try to see why citiyDefenseModifier() gives the result -100 here before doing anything.


Edit:
Ah I think I know

You changed the city defense modifier of slavers to -100 to prevent the ai from using them, didn't you ? This is probably not expected by the game.

In my case, there must be an AI-slaver sitting in a city of his own nation (just by accident) when this calculation is done.
When I reset the slaver's citydefensemod to 0, the crash is gone, without having to modify the source code.
 
Yeah I was gonna say that may be the issue, I probably went a bit overboard with the -100, I think the slaaver issue has another ai problem somewhere which archid said he would look into for me.

So I will probably set it back to 0 anyway.

I think the CTD code problems are coming from imperfect merges between mod comp ai's and k-mods new ai formulae.

As this was an issue with pretty much every mod comp I added with an ai element, because kmod rewrote the ai codes and functions to be smarter and have greater flexibility and variation
 
Hey mate! First of all nice work so far!

And now to the point, few things that I found:

1)Sniper has the Strength of 1.

2)Tandi and Ironhead leaderheads are missing noshader entries in CIV4ArtDefines_Leaderheads (files themselves are present) causing crash to desktop as soon as someone with weak machine sees them :D

3) I'm not sure if it's a bug or not, but the costs to upgrade units are extremely high. Town Guard -> Metal Armor Town Guard costs 1460 gold, and Militia -> Metal Armor Militia over 1700 gold. With gigantic production that each city can achieve, basically building any unit in a single turn, prices like that make unit upgrading totally redundant.
 
Welcome Kaaven!

1) yes Sniper is supposed to have strength 1, look at his ranged strength(if it is working right!!) it should be something like 12 (Head shot!) the point is a sniper is great at range (look at his range attack distance :D) but if you catch him up close and personal he is a deadman! Unless he has been upgraded and is in something like a fort or a city, then he can be quite nasty too!

2) Oh really, thanks for the find, I will look into this ASAP :) (FIXED!)

3) Yes this is not technically a bug but it is also not right... I am still working out the mechanics of upgrading, how the price is generated and what effects it etc. All the commerce stuff still needs to be worked on and balanced (always looking for new playtesters) I am also hoping to add in extra things around unit production to make it 'less effective'. things like making units more expensive to build, having them cost population to build, stuff like that.. Upgrading will also be useful for high exp units that have lots of promos.

I am impressed you managed to get to sniper without a lot of CTDs, our stabilising efforts must be bearing fruit :D
 
Maybe my success at playing so long was due to the fact I am using an ancient machine right now (when I turn on Civ4 it shows pop-up telling me my system is too weak to play it) and so my settings are down to the lowest possible...

Anyway, that game where I reached Sniper (and Power Armors; around turn 290) played nice and with no problems until it crashed one turn after two computer players started war with each other - so the problems are definitely with some higher end fighting mechanics (my struggles with monsters and barbarians caused no errors).

And if you need some play-testing observations, I can send some if you like (just tell where to post it) :D
 
HOPEFULLY, we now have a stable version in the works, I tested out to 1000 turns today at I think marathon speed without a crash, so that was promising, I intend to do some more fixing and sprucing and testing before I release the next version, but early signs are promising!

Non bug related feedback goes here!
 
Top Bottom