Development Thread

Spoiler :
Hopefully this new BULL feature will help. It's actually two related features. The first feature shades the tiles controlled by the first selected city, similar to how all cities' controlled tiles are shaded when you select a Settler.

The second feature operates on every selected city. It places a colored circle over each workable tile to indicate its working and improvability status:

  • None: City tile, unworkable tile, or unimprovable tile not being worked
  • Black: Improved tile being worked
  • Green: Improved tile not being worked
  • Yellow: Unimprovable tile being worked
  • Red: Improvable tile being worked
  • Cyan: Improvable tile not being worked
Unimprovable tiles are those bare tiles on which no available improvement can be built at this time. For example, any Hill before Mining, a Forest before Replaceable Parts, etc.


Now, this still needs a little adjusting. First, the black circles are a bit too hard to see. Since you don't need to take action for improved tiles the city is working, they shouldn't stand out, but they fade into the roads and get lost. I'm thinking a shade of median gray. I started with white to match the look of the City Screen, but they stood out too much and were hard to distinguish from the cyan (improvable) circles.
Second, Forests are not handled consistently. I determine if a tile is improvable by checking the AI's best selected build which varies depending on circumstances. A Forest on a Hill will have a Mine as the best improvement while a Forest on a non-riverside Plains Flatland will have none. My thinking is to never consider improvements that would clear a Forest.

Third, what about Jungle? Should they be highlighted as improvable via clearing?
A forest on a non-riverside plains flatland doesn't even have BUILD_REMOVE_FOREST as best plot build? Then there really isn't much you can do. As for the jungle I think you should just follow the simple principle: if there is a best plot build != NO_BUILD then that plot is improvable, otherwise it isn't. BUILD_REMOVE_JUNGLE might not create a tile improvement by itself but that shouldn't matter.

As for the colors, I'd use a dark green instead of black if you have such a color at your disposal.
 
A forest on a non-riverside plains flatland doesn't even have BUILD_REMOVE_FOREST as best plot build?

IIRC there was a best build for a riverside Plains Forest but not for a non-riverside tile. I didn't check, but perhaps it was probably suggesting a Farm. My main goal is to provide something generic that will work in mods that add new features, improvements, or terrain types.

Right now I ignore any best build that does not produce an improvement. That means ignoring routes and explicitly clearing features.

I considered building a way to detect "only bad" features so I can show them as improvable, but I'm tempted to leave it. If you left Jungle near your cities, you're either saving it for Forest Preserves or you're beyond help. :p Seriously though, if I can write (or be given) an algorithm that determines good vs. bad features, I'm happy to use it.

Another annoyance is that it highlights Oases as unimproved tiles. I think most people consider an Oasis to be an acceptable tile to work (3:food: 2:commerce: is okay, but the positive :food: is the real bonus). That's actually fairly easy, but is it sufficient?

Rule: If a tile is :food:-positive, it won't be flagged as unimproved.​

If it can be improved, it will be flagged of course. This means that Flood Plains will be flagged once you acquire a Worker tech such as Irrigation or Pottery.

As for the colors, I'd use a dark green instead of black if you have such a color at your disposal.

I can use any RGBA combination desired. Dark green might go well with the bright green for improved tiles you're not working yet. Should I make the other related tiles use light/dark colors then?

  • Improvable Tile - Worked: yellow, else dark yellow
  • Unimprovable Tile - Worked: red, else no circle
I'll try it, but I suspect that won't be good. We want all improvable tiles to be highlighted since you can do something about them.

Bah, hard to theorize without seeing it in-game. I could also let the player configure the colors via XML, but that would limit them to the specific values in CIV4ColorVals.xml. Hmm, I think you can have strings in GlobalDefines.xml. I'll check at home.
 
I was playing a game for the past hour and trying to look at this anew, and I think most players will expect brighter colors to mean tiles that are being worked rather than tiles that need attention. With that, I'm going to now try a new color scheme:

Code:
                Worked    Not Worked
--------------------------------------
Improved        green     dark green
Improvable      cyan      dark cyan
Unimprovable    red       none

Hopefully these colors work out. They're definitely not good for color blindness. :( The main color that I think needs to be what it is is cyan for improvable tiles as it's already used to mean exactly that in the game. Red makes sense for "bad" and green for "good". Let's give it a shot . . .
 
That color sheme would work too but for me, this would be more than enough:
  • # Yellow: Unimprovable tile being worked
  • # Red: Improvable tile being worked
What you are trying to do is circling almost every tile. I think that's a bit overkill. I can see without circles if a tile is improved, and I'm not sure if you really need to encircle tiles that were already taken care of. Marking unimproved worked tiles makes sense though, since that means that the current situation is not optimal and that some action (worker/research) is required from the player.

The Oasis: A tile shouldn't count is unimprovable* if there's a good feature in place that doesn't allow improvements (isNoImprovement()), which would be true only for Oasis. Flood Plains are good but allow improvements and Fallout is a bad feature. That good/bad differentiation is normally done via health% and sum of yield changes, if both are negative the feature is bad (fallout, jungle).
I mean, the Oasis definitely is unimprovable but it shouldn't be displayed as such, since the yellow/red circle should normally indicate that the player needs to research some tech that enables a build for that tile. In the case of the Oasis, there will never be such a build so no need for the color circle.

Right now I ignore any best build that does not produce an improvement. That means ignoring routes and explicitly clearing features.
If there is a best plot build, it is always something good - since it needs at least a value > 0 to be even considered. Roads are never best plot builds, they don't get constructed from best plot builds but from the route_to missionai. Same goes for forts.
To sum it up, I really think all plots with a a best build should be considered "improvable". It will always be up to the player to decide if he really wants to clear that forest right now but there's no reason to disregard the forst clearing build. Even more so that jungle clearing or fallout scrapping, both builds are very obviously improving the tile.
 
I'm not sure if you really need to encircle tiles that were already taken care of.

That makes a certain amount of sense. If it's too hard to spot which tiles are which, it's not useful anymore. I do think it's helpful to circle improved tiles that aren't being worked, though. If a city has a bunch of unimproved tiles you might think to send a worker there, but if it still has four improved tiles that aren't being worked it isn't so important yet.

I'll try removing the circle from improved tiles being worked and possibly unimprovable tiles not being worked.

The Oasis: . . .

I agree that it should not be marked; I just need a way to tell. isNoImprovement() should help here, thanks, but doesn't Fallout also return true for this? I'll poke around some more.

That good/bad differentiation is normally done via health% and sum of yield changes

I was pressed for time and hoping for something quick and dirty. ;) Also, summing these up may not work for a mod with a feature that has +1:food: and +1:yuck:, which is worth more? But if I can rely on the best build, this is moot.

Roads are never best plot builds, they don't get constructed from best plot builds but from the route_to missionai.

Hmm, I'm pretty sure tiles with improvements but no routes were giving me a best build, but I did not dump out that build. I know I added a check for improvement on the build and those disappeared, but maybe I made more than that change at the same time.

To sum it up, I really think all plots with a a best build should be considered "improvable".

In general I agree. What I don't like is two forests in the same city showing one as improvable and the other not. It makes you have to stop and think which is what this feature is trying to avoid. :lol:

I'll keep tweaking it. Thanks a ton for your input so far! BTW, I haven't committed it because I know you pull in changes right away, and this is definitely not ready for prime time. If you wanna give it a try, however, here's the file.

Spoiler CvGameInterface.cpp :
Code:
void CvGame::updateColoredPlots()
{
	...

	pHeadSelectedCity = gDLL->getInterfaceIFace()->getHeadSelectedCity();
	pHeadSelectedUnit = gDLL->getInterfaceIFace()->getHeadSelectedUnit();

	if (pHeadSelectedCity != NULL)
	{
		if (gDLL->getInterfaceIFace()->isCityScreenUp())
		{
			...
		}
		else
		{
// BUG - City Controlled Plots - start
			if (getBugOptionBOOL("CityBar__CityControlledPlots", true, "BUG_CITY_CONTROLLED_PLOTS"))
			{
				for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
				{
					pLoopPlot = pHeadSelectedCity->getCityIndexPlot(iI);

					if (pLoopPlot != NULL && pLoopPlot->getWorkingCity() == pHeadSelectedCity)
					{
						NiColorA color(GC.getColorInfo((ColorTypes)GC.getInfoTypeForString("COLOR_HIGHLIGHT_TEXT")).getColor());
						color.a = 1.0f;
						gDLL->getEngineIFace()->fillAreaBorderPlot(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), color, AREA_BORDER_LAYER_CITY_RADIUS);
					}
				}
			}
// BUG - City Controlled Plots - end

// BUG - City Plot Status - start
			if (getBugOptionBOOL("CityBar__CityPlotStatus", true, "BUG_CITY_PLOT_STATUS"))
			{
				NiColorA improvedWorkedTile(GC.getColorInfo((ColorTypes)GC.getInfoTypeForString("COLOR_GREEN")).getColor());
				//improvedWorkedTile.a = 0.7f;
				const NiColorA& improvedUnworkedTile = GC.getColorInfo((ColorTypes)GC.getInfoTypeForString("COLOR_PLAYER_DARK_GREEN")).getColor();
				const NiColorA& canImproveWorkedTile = GC.getColorInfo((ColorTypes)GC.getInfoTypeForString("COLOR_CYAN")).getColor();
				const NiColorA& canImproveUnworkedTile = GC.getColorInfo((ColorTypes)GC.getInfoTypeForString("COLOR_PLAYER_MIDDLE_CYAN")).getColor();
				const NiColorA& cannotImproveWorkedTile = GC.getColorInfo((ColorTypes)GC.getInfoTypeForString("COLOR_RED")).getColor();

				pSelectedCityNode = gDLL->getInterfaceIFace()->headSelectedCitiesNode();

				while (pSelectedCityNode != NULL)
				{
					pSelectedCity = ::getCity(pSelectedCityNode->m_data);
					pSelectedCityNode = gDLL->getInterfaceIFace()->nextSelectedCitiesNode(pSelectedCityNode);

					if (pSelectedCity != NULL)
					{
						for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
						{
							pLoopPlot = pSelectedCity->getCityIndexPlot(iI);

							if (pLoopPlot != NULL && pLoopPlot->getWorkingCity() == pSelectedCity)
							{
								bool bImproved = false;
								bool bCanBeImproved = false;

								if (pLoopPlot == pSelectedCity->plot())
								{
									bImproved = true;
								}
								else if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT && pLoopPlot->getImprovementType() != GC.getDefineINT("RUINS_IMPROVEMENT"))
								{
									bImproved = true;
								}
								else
								{
									BuildTypes eBestBuild = pSelectedCity->AI_getBestBuild(iI);

									if (eBestBuild != NO_BUILD && GC.getBuildInfo(eBestBuild).getImprovement() != NO_IMPROVEMENT)
									{
										bCanBeImproved = true;
									}
								}

								if (pSelectedCity->plot() == pLoopPlot)
								{
									// don't highlight city itself
								}
								else if (pSelectedCity->isWorkingPlot(pLoopPlot))
								{
									if (bImproved)
									{
										gDLL->getEngineIFace()->addColoredPlot(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), improvedWorkedTile, PLOT_STYLE_CIRCLE, PLOT_LANDSCAPE_LAYER_RECOMMENDED_PLOTS);
									}
									else if (bCanBeImproved)
									{
										gDLL->getEngineIFace()->addColoredPlot(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), canImproveWorkedTile, PLOT_STYLE_CIRCLE, PLOT_LANDSCAPE_LAYER_RECOMMENDED_PLOTS);
									}
									else
									{
										gDLL->getEngineIFace()->addColoredPlot(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), cannotImproveWorkedTile, PLOT_STYLE_CIRCLE, PLOT_LANDSCAPE_LAYER_RECOMMENDED_PLOTS);
									}
								}
								else if (pSelectedCity->canWork(pLoopPlot))
								{
									if (bImproved)
									{
										gDLL->getEngineIFace()->addColoredPlot(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), improvedUnworkedTile, PLOT_STYLE_CIRCLE, PLOT_LANDSCAPE_LAYER_RECOMMENDED_PLOTS);
									}
									else if (bCanBeImproved)
									{
										gDLL->getEngineIFace()->addColoredPlot(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), canImproveUnworkedTile, PLOT_STYLE_CIRCLE, PLOT_LANDSCAPE_LAYER_RECOMMENDED_PLOTS);
									}
								}
							}
						}
					}
				}
			}
// BUG - City Plot Status - end

			pSelectedCityNode = gDLL->getInterfaceIFace()->headSelectedCitiesNode();
 
Have I mentioned that I love this idea yet? :D
 
Haha, nice. Let's hope it's well received once it's complete. :) I'm still hoping I can make the colors configurable without too much trouble. I haven't tried exposing string type options from BUG, but it shouldn't be any harder than booleans and integers.
 
Here are my current changes:

  • Improved tiles being worked are not highlighted.
  • Switched the red/yellow: red for improvable.
  • Improvable tiles not being worked are highlighted in cyan: bright if the tile has a bonus, dark if not. Is the dark cyan subtle enough? Too subtle?

Next I'd like to make it check for routes on bonus tiles, showing them in red (?) or cyan if they don't have a route and you can build one.

Finally, I want to highlight tiles that will gain yields from a route.

Unfortunately the code that would really help these last two features is on CvUnit instead of CvPlot. :(
 
I'm not sure if you really need to encircle tiles that were already taken care of.
That makes a certain amount of sense. If it's too hard to spot which tiles are which, it's not useful anymore. I do think it's helpful to circle improved tiles that aren't being worked, though. If a city has a bunch of unimproved tiles you might think to send a worker there, but if it still has four improved tiles that aren't being worked it isn't so important yet.
It's good to know we think alike here :) If you circle improvable unworked tiles, you must circle improved unworked tiles, I agree 100%. I suggested circling neither of those, only worked unimproved tiles, which would reduce the number of circled tiles drastically - to zero even in most cases. Because less is more.
..And because I can see even without circles if a tile has an improvement or not, even if the improvement is worked is visible if I look closely enough. Only with unimproved tiles it's sometimes harder to see if it is worked, and that's exactly the one situation where a player action is direly needed.


I agree that [Oasis] should not be marked; I just need a way to tell. isNoImprovement() should help here, thanks, but doesn't Fallout also return true for this? I'll poke around some more.
That good/bad differentiation is normally done via health% and sum of yield changes
I was pressed for time and hoping for something quick and dirty. ;) Also, summing these up may not work for a mod with a feature that has +1:food: and +1:yuck:, which is worth more? But if I can rely on the best build, this is moot.
I didn't say sum, I said both: yields sum <= 0 && health% <= 0. The example you gave is not a bad feature by that definition. The point is moot for all features where a best plot build exists, it is not moot for the isNoImprovement features Fallout & Oasis: Fallout needs to be detected as bad feature so it would be shown as "unimprovable" as long as scrubbing is impossible, whereas Oasis (good feature && isNoImprovement()) would be exempt.

Hmm, I'm pretty sure tiles with improvements but no routes were giving me a best build, but I did not dump out that build. I know I added a check for improvement on the build and those disappeared, but maybe I made more than that change at the same time.
You are right, there is a possibility for roads to pop up as best plot build: When the route adds tile yield like railroads for mines and lumbermill, and when there is a bonus tile that is not connected to capital. But that is all, as far as I can see, and in both cases building that route makes sense.
The problem with best plot build is just that it will sometimes return an improvement for a tile that already has one. How do you want to handle a build that would destroy an existing improvement? Happens frequently with cottages around the time when workshops get interesting.

I'll keep tweaking it. Thanks a ton for your input so far! BTW, I haven't committed it because I know you pull in changes right away, and this is definitely not ready for prime time. If you wanna give it a try, however, here's the file.
No need yet, I can see this is not yet ready. At least the circles part, the shanding of city tiles is good to go I say.:goodjob:
 
If you circle improvable unworked tiles, you must circle improved unworked tiles, I agree 100%. I suggested circling neither of those, only worked unimproved tiles, which would reduce the number of circled tiles drastically - to zero even in most cases.
Nevermind that, it's useful info, show it.

What route code is in CvUnit?
 
I was looking at CvUnit::isActionRecommended() which highlights the build buttons for a unit. But if Build Railroad is given as a best build on a tile with a Mine, I won't need to do anything to handle routes. I'll do some testing with different game years tonight.
 
I didn't say sum, I said both: yields sum <= 0 && health% <= 0.

I was thinking that if either is negative, the feature is bad, and both for sure. But my point is what if the yields are negative while the health bonus is positive? In that case I'd probably consider it "not bad." So "bad" means obviously bad--no question.

You are right, there is a possibility for roads to pop up as best plot build: When the route adds tile yield like railroads for mines and lumbermill, and when there is a bonus tile that is not connected to capital.

Tiles that have an improvement and a best build that is a route are now considered improvable. Otherwise I ignore tiles with an improvement. This keeps it from being tricked by the whole swapping improvement thing.

For some reason, though, the game is returning a route build for improved seafood tiles! :lol: I'll have to ignore water tiles for routes.
 
For some reason, though, the game is returning a route build for improved seafood tiles! :lol: I'll have to ignore water tiles for routes.
And what build would that be? I didn't even know there was a build that adds sea routes ..

edit[: nvm, I misread a part..
Code:
				[COLOR="Green"]//road up bonuses if sort of bored.[/COLOR]
				if ((eOldRoute == NO_ROUTE) && (eBonus != NO_BONUS))
				{
					iTempValue += (pPlot->isConnectedToCapital() ? [U]10[/U] : 30);
				}
+10 even if the bonus is alreayd connected. That's what's causing this.
Which means, for bonus tiles that are already connected to the capital, best plot build is not reliable after all, roads will be built out of boredom too.
I have yet to find out why it's trying to build them on water too though, roads are not supposed to be valid there, I hope.

edit2: Builds are not limited to domains, only to units. It's probably best to simply check if the route gves a yield bonus, and to ignore it if not.
 
I had it ignore water tiles for routes, but are you saying that a Plantation (no bonus for Railroad) on a flatland tile with a road will have a best build when railroad becomes available?
 
No, I'm saying a plantation next to a river and thus already connected would have road as best build even though it doesn't gain any yield or connectivity. The routes of boredom appear on bonus tiles only if (eOldRoute == NO_ROUTE), see my post above.
I recommend ignoring routes that don't add yield, even though I can see it's obviously simpler (to code) to just ignore water.
 
The route yield improvement detection works great. Can you think of any more cases where a tile with an improvement should be considered improvable?
 
A tile that already has an improvement can have a best build from
  • from a different improvement that is worth more (ignored, as it should be).
  • from route
  • from clearFeatureValue: after building a camp for jungle ivory, the plot can still be improved by removing the jungle. It's not impossible that removing the feature would remove the improvement on the plot too but isuch a build is very unlikely to have a value above zero then because it gets a huge penality for that. You might still want to check though.
    if (GC.getImprovementInfo(pPlot->getImprovementType()).isRequiresFeature()) then ignore the build that removes the feature.
 
I added CvFeatureInfo::isOnlyBad() which returns false if it has a positive health effect, provides fresh water, or has at least one positive base yield change. I ignore river and hills yield changes since they relate more to the terrain than the feature I think. For the normal game this works just as you would expect for every feature (Flood Plains returns false due to its +3:food:), but it hopefully leaves it open for mods to exploit with weird features.

This is used for builds that remove the feature. I think this covers everything now. Oh, if there's no improvement on the tile I ignore all route builds entirely. If the tile has a bonus, and you have the tech that enables the improvement, I expect the improvement build to have a higher value than the route build. Plus, this feature is about improving tile yields for cities--not providing access to resources. I'll leave that for some other empire-wide feature.
 
Oh, if there's no improvement on the tile I ignore all route builds entirely.
Not sure how exactly your code looks like, but I believe ignoring routes for unimproved tiles is already implied by ignoring routes that don't add tile yield, since routes can only ever add yield in conjunction with an improvement.

Code:
bool bIsRouteHasYieldChange = false;
RouteTypes eRoute = GC.getBuildInfo(eBuild).getRoute();
RouteTypes eOldRoute = pPlot->getRouteType();

if (eRoute != eOldRoute)
{
	if (pPlot->getImprovementType() != NO_IMPROVEMENT)
	{
		if ((eOldRoute == NO_ROUTE) || (GC.getRouteInfo(eRoute).getValue() > GC.getRouteInfo(eOldRoute).getValue()))
		{
			for (int iI = 0; iI < NUM_YIELD_TYPES; iI++)
			{
				if (GC.getImprovementInfo(pPlot->getImprovementType()).getRouteYieldChanges(eRoute, iI) > 0)
				{
					bIsRouteHasYieldChange = true;
				}
			}
		}
	}
}


I agree, I think you covered everything now.
 
Well, the tile is checked for an improvement first as the main branch. If it does, a route build is accepted if it adds a yield. If not, a route build is ignored entirely. It all works out in the end. :)
 
Top Bottom