Strange events - possible reason? (SDK)

c.fe

Warlord
Joined
Sep 20, 2003
Messages
133
Location
Germany
Some people were complaining, that events always choose the same unit. This is some code from the unmodded BtS-SDK, form CvPlayer.cpp (I suppose that Kael didn't change this):

Code:
CvUnit* CvPlayer::pickTriggerUnit(EventTriggerTypes eTrigger, CvPlot* pPlot, bool bPickPlot) const
{
	CvUnit* pUnit = NULL;
	std::vector<CvUnit*> apUnits;
	int iLoop;
	int iBestValue = MIN_INT;
	for (CvUnit* pLoopUnit = firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = nextUnit(&iLoop))
	{
		int iValue = pLoopUnit->getTriggerValue(eTrigger, pPlot, bPickPlot);

		if (iValue > iBestValue)
		{
			if (NULL != pUnit)
			{
				apUnits.push_back(pUnit);
			}

			iBestValue = iValue;
			pUnit = pLoopUnit;
		}
		else if (MIN_INT != iValue)
		{
			apUnits.push_back(pLoopUnit);
		}
	}

	if (NULL == pUnit && apUnits.size() > 0)
	{
		int iChosen = GC.getGameINLINE().getSorenRandNum(apUnits.size(), "Event pick unit");
		pUnit = apUnits[iChosen];
	}

	return pUnit;
}

If you can read C++-code try to simulate this code an suppose that getTriggerValue always returns 0 (or always the same number). If I'm not mistaken the result will be that pUnit will point to the first unit and apUnits will contain all the others. So the last if-statement wont get executed and pUnit (= the first unit) will be picked.
That seems to be consistent with what some people have reported.

The whole thing doesn't make a lot of sense to me. I suppose that they want to put all units that get the same value in the array and then pick one.
I think it should look like this:

Code:
CvUnit* CvPlayer::pickTriggerUnit(EventTriggerTypes eTrigger, CvPlot* pPlot, bool bPickPlot) const
{
	CvUnit* pUnit = NULL;
	std::vector<CvUnit*> apUnits;
	int iLoop;
	int iBestValue = MIN_INT;
	for (CvUnit* pLoopUnit = firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = nextUnit(&iLoop))
	{
		int iValue = pLoopUnit->getTriggerValue(eTrigger, pPlot, bPickPlot);
		
		if (iValue != MIN_INT)
		{
			
			if (iValue > iBestValue)
			{
				apUnits.clear;
				iBestValue = iValue;
				pUnit = pLoopUnit;
			}
			else if (iValue == iBestValue)
			{
				if (pUnit != NULL)
				{
					apUnits.push_back(pUnit);
					pUnit = NULL;
				}
				apUnits.push_back(pLoopUnit);
			}
		}
	}

	if (NULL == pUnit && apUnits.size() > 0)
	{
		int iChosen = GC.getGameINLINE().getSorenRandNum(apUnits.size(), "Event pick unit");
		pUnit = apUnits[iChosen];
	}

	return pUnit;
}

By the way: The same applies to pickTriggerCity.
 
I think that if getTriggerValue always returns the same number, and it's always greater than MIN_INT (since that's what bestValue is initialized to) then the LAST unit will be pUnit.

Of course if it adds units by pushing then that means the first unit you created (or first one built still left alive) will always be the one picked.

I'm gonna go look at the code and see what getTrigger actually does, if it's just returning a value set for each unit then I could see that being the case.

As far as what to replace, I would say it should be completely random, but needing a way to make sure a unit doesn't get an event it shouldn't get (not sure if there are any events where that would be the case off the top of my head)

EDIT: Yes, looks like getTriggerValue should return 0 if there are no factors involved in the event(factors that can weigh in include health,xp,distance it looks like, but I think there are a lot of events which should just be completely random). Which means it would always pick the first unit built in those cases.

And I think your code would fix it too.
 
First unit off the top of my head that actually needs a specific condition for an event is the Healing Salve only goes to an injured unit. I think there is also an event where people shelter an injured unit, so that one too.

But the cities and improvements are where there are lots of "must fit the condition" issues. Having a collapsed mine event in your Hamlet doesn't work so well, nor having Farm Bandits in your Quarry.
 
Well, I bet you can add some code to the getTriggerValue in cvCity to return the same number based on whether there's a mine/cottage/farm in the city's radius (MAX_INT to make sure it's the bestValue?), then have the event pick the right plot in the city's radius. Also saw a function that looked like it returned whether the city was applicable to the event or not I thought, that may get rid of the problem of having events happening on wrong plots/cities (I'll admint I haven't looked into that as much though). You would still need to change the code to have it randomly pick from among a list of valid objects though I believe.

I think the problem is that in BTS I can't think of any events that just randomly picked a city/unit, can anyone else? Think they were all ones like the rioting, where it would basically just pick the city with the lowest happiness, which is fine because you wouldn't necessarily have one city always having the lowest happiness. However there are a bunch of events in FFH where it should work more like "get a list of all the applicable units/cities" -> "pick a random one from the list" rather than pick the "best" one.
 
BTS had the mine collapse events which I think weren't very random either.
 
This explains why I got the "Calabim refugee" event five times in my capital city, even when it was already starving.
 
I actually put the code in my version of ffh and it does seem to work. The only time it didn't is when I had two cities and I got events in the same city five or so times. I guess it could have been coincidence, but seems like a lot for that. After I expanded more though I was definitely getting the events in all of my cities instead of just one.
 
Could someone post a modded file of Civplayer.cpp, please? I don't have a C++ compiler, but I would really like to implement this change in my game...Can I do it in a text editor?

Even if I can, I don't know enough C++ to mod the city section myself, and that's the one I'm most interested in. If someone who's added BOTH changes in could post the file, I would greatly appreciate it.
 
No help for the modificationally challenged? :(

Mu-Dog has the modded file, so I know it's out there...Can't someone please just post it for me to download?
 
I can give you the cpp I edited but you would still need to compile it to get the dll. The dll I have after I compile is 6 mbs, so I can't post that here. Plus it has some other modifications in it as well (just other fixes though). If you want it though, pm me and we can work something out.
 
Mu-Dog: Looking to try this out, attempting to set things up so I can compile on my own using the links you provided. But wanted to say that you COULD upload the DLL here. Instead of attaching it to a message you click on the UPLOAD portion of the menu bar at the top (Same bar as My Account). The limit there is 10MB per file.
 
ah, didn't know that. The other reason I didn't necessarily want to do it though was that I had some other code changes as well that people may not have wanted. Here's a dll with it for patch H though, it does have one other change in it, it lets resources appear closer together with the double resources option enabled (to fix the no reagents bug from happening). And actually it didnt let me upload the dll straight up had to zip, still over a mb though.

http://forums.civfanatics.com/uploads/134977/CvGameCoreDLL.zip
 
Back
Top Bottom