Modify resources discovered on farms

Racc00n

Chieftain
Joined
Jun 12, 2010
Messages
33
I modified the farm improvement so there is a small chance to discover either corn, wheat or rice on the tile (similar to mines). It works, but currently without regard to the underlying terrain. So rice or corn, usually found on grass terrain only, also appear on plains, flood plains or even tundra. But I'd like these resources to be discovered on grass farms only (and wheat on plains farms only). Is there a way to do this?

Thanks for any help!
 
You could make two (or more) different improvements, both still called "farm", each of which is restricted by terrain. One (or more) can be built where the crops can be found, has the chance to find them, and is restricted to only appear there, and the other one is restricted to not appear there. This is a bit messy as they would all appear in the 'pedia.

The other solution is to add data to the improvement XML and modify the DLL to load and use it to do what you want (probably something like a TerrainTypes tag added to the BonusTypeStruct which applies to the iDiscoverRand chance such that the chance only applies if the terrain is on the list, if there is a list). This can make it function exactly how you want it to, but requires modding the DLL so it is more work.
 
I say the DLL solution is way better. Adding plenty of improvements will be quite messy, both in pedia and XML. The DLL should be fairly simple to mod for this once you have found the right place. I think the best solution would be to make a list of possible bonuses and then pick a random one based on likelihood of that bonus appearing on the plot in question (terrain/feature/hill combo). That way without writing a restriction specifically, it will appear because the probability will be 0%.

Depending on how the code is written, it might be possible to do in python, which is slower, but you don't have to compile. Since new bonuses are such a rare event, performance when it happens isn't really an issue.
 
I would disagree, hard coding stuff in the DLL is rather inelegant (I am a hypocrite).

The only part that makes it ugly is multiple pedia entries which can be solved rather easily. Most XML definitions, including improvements and build types, have a bGraphicalOnly tag (in fact it is part of the CvInfoBase class in the DLL).

It is currently unused, but you could easily extend the civilopedia to not show improvements that are bGraphicalOnly. It's an easy way to deal with additional XML definitions that you don't want the player to be aware of for some reason, I'm using it a lot.
 
I didn't mean to hardcode anything in the DLL. What I meant was looping through all possible new bonuses and at runtime make a list of valid bonuses for the plot in question. After that it can pick a random one from that list.

I totally agree that naming specific bonuses in the DLL is not the way to go. The DLL should be as generic as possible and the setup should be in XML. In fact the DLL shouldn't even mention what kind of terrain or improvement it is about. That's the job of the XML.

I'm not sure I like the idea of using bGraphicalOnly. The one improvement, which does show up in the pedia will then not list the bonuses, which are in the hidden improvements.
 
The XML method will fail, not just because of multiple pedia entries.
Global warming is another reason.

A plot could have been grassland, and a "grassland" farm was built which can spawn "grassland" crops. Global warming strikes and it turned to desert. The farm itself is still a "grassland" farm, rather than a "desert farm".

Other reasons could be performance, since gc.getNumImprovementInfos() would be suddenly inflated by gc.getNumTerrainInfos() for no apparent advantage. So any looping done would take more time, although for this case, chances are it is insignificant.
 
Thanks for the suggestions so far. Unfortunately my experience in modding the game is rather limited. Most of the modifications I've done so far were XML, and I just started to mess around with the CvRandomEventInterface.py to get the hang of Python.

So I gave the XML method a quick try and it seems a bit messy indeed, at least the way I did it: I created four copies of the farm improvement, each with its own build command. I also had to modify a couple of farm references in LeaderHeadInfos.xml, hopefully this won't mess up AI handling. Some of the events would need to be modified as well, skipped this for now. It seems to work so far, except farms on tundra currently aren't limited to fresh water tiles anymore. It's not very elegant, though, considering how little this actually does.

As for DLL... I haven't done any DLL modding yet and probably it'll take me a while to get into it. I took a quick look at the source code, though, and it seems CvPlot::doImprovement() is the function that "discovers" new resources.

Spoiler :
Code:
void CvPlot::doImprovement()
{
	PROFILE_FUNC();

	CvCity* pCity;
	CvWString szBuffer;
	int iI;

	FAssert(isBeingWorked() && isOwned());

	if (getImprovementType() != NO_IMPROVEMENT)
	{
		if (getBonusType() == NO_BONUS)
		{
			FAssertMsg((0 < GC.getNumBonusInfos()), "GC.getNumBonusInfos() is not greater than zero but an array is being allocated in CvPlot::doImprovement");
			for (iI = 0; iI < GC.getNumBonusInfos(); ++iI)
			{
				if (GET_TEAM(getTeam()).isHasTech((TechTypes)(GC.getBonusInfo((BonusTypes) iI).getTechReveal())))
				{
					if (GC.getImprovementInfo(getImprovementType()).getImprovementBonusDiscoverRand(iI) > 0)
					{
						if (GC.getGameINLINE().getSorenRandNum(GC.getImprovementInfo(getImprovementType()).getImprovementBonusDiscoverRand(iI), "Bonus Discovery") == 0)
						{
							setBonusType((BonusTypes)iI);

							pCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE(), NO_TEAM, false);

							if (pCity != NULL)
							{
								szBuffer = gDLL->getText("TXT_KEY_MISC_DISCOVERED_NEW_RESOURCE", GC.getBonusInfo((BonusTypes) iI).getTextKeyWide(), pCity->getNameKey());
								gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MINOR_EVENT, GC.getBonusInfo((BonusTypes) iI).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), getX_INLINE(), getY_INLINE(), true, true);
							}

							break;
						}
					}
				}
			}
		}
	}

	doImprovementUpgrade();
}
Just an idea, would it be possible to get the terrain of the plot and add another check, whether the resource can appear on this type of terrain? This would affect resources discovered in mines as well, but I'm fine with that, actually it'd be more consistent anyway.
 
Without modifying the dll, a simpler solution is to add a new event, which can be activated on a plot with a farm, provided there are resources available based on the terrain.

Thus, when the event is activated, a suitable resource can be placed based on the terrain, which can be done via python.

The drawback is of course, this will not activate in games without events activated.
 
I didn't mean to hardcode anything in the DLL. What I meant was looping through all possible new bonuses and at runtime make a list of valid bonuses for the plot in question. After that it can pick a random one from that list.

I totally agree that naming specific bonuses in the DLL is not the way to go. The DLL should be as generic as possible and the setup should be in XML. In fact the DLL shouldn't even mention what kind of terrain or improvement it is about. That's the job of the XML.
Looks like I misread you then :)
 
Code:
for (iI = 0; iI < GC.getNumBonusInfos(); ++iI)
{
	if ([COLOR="Red"][B]canHaveBonus((BonusTypes) iI) &&[/B][/COLOR] GET_TEAM(getTeam()).isHasTech((TechTypes)(GC.getBonusInfo((BonusTypes) iI).getTechReveal())))
I think adding the red code should do it. It will make the code ignore bonuses, which can't be on the plot in question (terrain, latitude etc). I think that is the simplest solution we can come up with, which should work just fine.
 
Code:
for (iI = 0; iI < GC.getNumBonusInfos(); ++iI)
{
	if ([COLOR="Red"][B]canHaveBonus((BonusTypes) iI) &&[/B][/COLOR] GET_TEAM(getTeam()).isHasTech((TechTypes)(GC.getBonusInfo((BonusTypes) iI).getTechReveal())))
I think adding the red code should do it. It will make the code ignore bonuses, which can't be on the plot in question (terrain, latitude etc). I think that is the simplest solution we can come up with, which should work just fine.

Thanks, will give it a try once I manage to get the SDK up and running :)
 
Back
Top Bottom