Examine City at Conquest

ExMachina

Warlord
Joined
Jun 5, 2008
Messages
203
Normally when you conquer a city, a screen pops up giving you two choices: 1) Keep it, or 2) Raze it. What I would like to do is add just one more option: Examine City. This way you could check what's inside the city, i.e. wonders/buildings/great people/etc. before deciding whether to raze it.

If it's not been done before, could someone help me figure out how to implement this? It seems like a simple enough change, I have no idea why it's not already this way in the vanilla game.
 
Thats a good idea, but i think its in the Civ4EventManager, which controls all the events.
 
You might be able to get something to work with onCityAcquired. I'm not sure when it is called relative to the popup screen. If it is just before the popup, you could at least display some information about the city before the popup occurs.
 
So I'd like to get this going, it seems a fairly simple bit of programming. For someone who knows a bit more than me though about programming! I hope someone can whip this up or provide directions and I'll attempt to muddle through it.

Anyhow I guess the code would be this in CvDLLButtonPopup.cpp

Code:
	case BUTTONPOPUP_RAZECITY:
		if (pPopupReturn->getButtonClicked() == 1)
		{
			gDLL->sendDoTask(info.getData1(), TASK_RAZE, -1, -1, false, false, false, false);
		}
		else if (pPopupReturn->getButtonClicked() == 2)
		{
			CvCity* pCity = GET_PLAYER(GC.getGameINLINE().getActivePlayer()).getCity(info.getData1());
			if (NULL != pCity)
			{
				gDLL->getEventReporterIFace()->cityAcquiredAndKept(GC.getGameINLINE().getActivePlayer(), pCity);
			}

			gDLL->sendDoTask(info.getData1(), TASK_GIFT, info.getData2(), -1, false, false, false, false);
		}
		else if (pPopupReturn->getButtonClicked() == 0)
		{
			CvCity* pCity = GET_PLAYER(GC.getGameINLINE().getActivePlayer()).getCity(info.getData1());
			if (NULL != pCity)
			{
				pCity->chooseProduction();
				gDLL->getEventReporterIFace()->cityAcquiredAndKept(GC.getGameINLINE().getActivePlayer(), pCity);
			}
		}
		break;

What I guess you'd want to do it add another ""else if" option for the "examine city" option.

After that I'd suggest maybe taking temporary control over the conquested city, having the city screen popup, then returning control to the losing civ, and getting the popup menu back to raze, take over, examine etc. There are surely other ways to do this, I'd even be happy if the city screen just popped up automatically in the background everytime you took over a city before you had to raze or take over it.

Can someone walk through making this happen?

Also, not sure if this will help but it seems that python screens can be called as popups, so perhaps "option 2" of just having the screen popup automatically would be possible maybe? See post 10 in this thread: http://forums.civfanatics.com/showthread.php?t=183126
 
I had looked at doing this and couldn't find a nice method for making the popup persistent. I mean: It was trivial to add a button "Examine City" which let you zoom in to city view. Problem was, that as soon as you did that you completely lost your popup offering a chance to raze. It just wouldn't come back.

Possibly you could define a new attribute in CvCity to flag something as razeable, then in the game update function you can cause a persistent popup if not in city view offering the chance to raze. I hadn't decided to go that far. Instead, I just made the "Raze it?" popup show up minimized, then you weren't forced to make a decision unless you had no other units to give commands to, and could view the city personally, THEN click on the icon and choose to raze or not.

By the time you get the popup, the city already belongs to you by the way. As soon as you move onto the tile, a new city under your control is created, all data from the old city is copied over, and the old city is deleted. Then a popup appears requesting Raze/Keep decision.


Never thought about having the city view auto-pop. That could be a favorable option, and isn't too hard to accomplish either, you don't need to run it as a python screen, there are commands within the DLL to drop your current selection, zoom to city, and set it as actively selected.
 
By the time you get the popup, the city already belongs to you by the way. 1. As soon as you move onto the tile, a new city under your control is created, 2. all data from the old city is copied over, and 3. the old city is deleted. 4. Then a popup appears requesting Raze/Keep decision.

Xienwolf, would it be possible to insert before step 4 (I numbered the list of steps in your reply (see quote above)) to have the city screen pop up with the new civ, then the raze/keep show up on top of that? So...

1. take city
2. city processed:destroyed/recreated over to you
3. popup of new city screen
4. The big question

Its probably a good thing you see the "after" version of the conquest so you don't think you'll be getting some buildings only to be destroyed in the takeover for example
 
Yes, you can put a call there pretty easily to zoom the city, but the complication which arises at that point is that you don't know where the city is (for cultural conversion cases) since you don't see the main or minimap. And I don't know how it will handle the popup, will it generate the popup while you are looking at the city, obstructing your ability to scroll and/or mouseover various items, will it take you right out of city zoom to handle the popup, or will it wait to show the popup at all until you leave city zoom?

Overall, it's something you would need to get into the DLL and play with to test how it will react to any given arrangement.


What I did to make things work, was in:

bool CvDLLButtonPopup::launchRazeCityPopup(CvPopup* pPopup, CvPopupInfo &info)


I changed:

Code:
	gDLL->getInterfaceIFace()->popupLaunch(pPopup, false, POPUPSTATE_IMMEDIATE);

	gDLL->getInterfaceIFace()->playGeneralSound("AS2D_CITYCAPTURE");

	return (true);

To

Code:
	gDLL->getInterfaceIFace()->popupSetPopupType(pPopup, POPUPEVENT_RAZE_CITY, ARTFILEMGR.getInterfaceArtInfo("INTERFACE_BUTTONS_CITYSELECTION")->getPath());
	gDLL->getInterfaceIFace()->popupLaunch(pPopup, false, POPUPSTATE_MINIMIZED);

	gDLL->getInterfaceIFace()->playGeneralSound("AS2D_CITYCAPTURE");

	return (true);

This requires that you also add the new PopupState to the list in CvEnums.h
Code:
enum DllExport PopupEventTypes
{
	POPUPEVENT_NONE,
	POPUPEVENT_PRODUCTION,
	POPUPEVENT_TECHNOLOGY,
	POPUPEVENT_RELIGION,
	POPUPEVENT_WARNING,
	POPUPEVENT_CIVIC,
	POPUPEVENT_RAZE_CITY,
};

And it helps to provide a mouseover text for it in:
void CvGameTextMgr::setMinimizePopupHelp(CvWString& szString, const CvPopupInfo & info)

so just add a case:
Code:
	case BUTTONPOPUP_RAZECITY:
		pCity = GET_PLAYER(GC.getGameINLINE().getActivePlayer()).getCity(info.getData1());
		if (pCity != NULL)
		{
			szString += gDLL->getText("TXT_KEY_MINIMIZED_RAZE_CITY", pCity->getNameKey());
		}
		break;



Anyway, you can use this for what I have set up, or look for where "launchRazeCityPopup" is called from to add in calls to open the city screen

To open the city screen, look in "CvGame::doControl" for "CONTROL_SELECTCITY" and the ones following that, those deal with selecting and opening a city.
 
The downside to asking as soon as you open the city screen is that you cannot scroll the list of buildings (if it's long) or switch the Raw Yields view (if using BUG). Better than what we have now (nothing), but it would be nice if you got the popup after exiting the city screen.

That might be tricky, though. From the city screen you can switch to other cities or open other windows. I don't know if you can trap all those maneuverings.
 
If you use what I posted, the popup is minimized, so you can choose to view the city and whatever else you want and completely ignore the Keep/Raze decision until you are ready for it, or have no more units who can make further moves (as soon as you DO open the popup though then you MUST make your decision). Works perfectly so far.
 
I suppose you could add the "Examine City" as an option to the popup and recreate the minimized popup after opening the city screen. This would allow them to keep looking and decide later.
 
I tried to test the code you've got above, xienwolf. I'm getting a undeclared identifed from line 1395,

Code:
gDLL->getInterfaceIFace()->popupSetPopupType(pPopup, POPUPEVENT_RAZE_CITY,ARTFILEMGR.getInterfaceArtInfo("INTERFACE_BUTTONS_CITYSELECTION")->getPath());

I did add it to civenums.h

Code:
enum DllExport PopupEventTypes
{
	POPUPEVENT_NONE,
	POPUPEVENT_PRODUCTION,
	POPUPEVENT_TECHNOLOGY,
	POPUPEVENT_RELIGION,
	POPUPEVENT_WARNING,
	POPUPEVENT_CIVIC,
	POPUPEVENT_RAZE_CITY,
};

edit: rebuilt the project and it seemed to work, messing around with it now

edit edit: didn't see anything different when testing with wolrdbuilder
 
I found a simpler solution.

I added

gDLL->getInterfaceIFace()->selectCity(pNewCity)

to
Code:
void CvPlayer::acquireCity(CvCity* pOldCity, bool bConquest, bool bTrade, bool bUpdatePlotGroups)
{
	....................
	pNewCity = initCity(pCityPlot->getX_INLINE(), pCityPlot->getY_INLINE(), !bConquest, false);
	....................
	if (bConquest)
	{
		....................
			//auto raze based on game rules
			if (pNewCity->isAutoRaze())
			{
				....................
				pNewCity->doTask(TASK_RAZE);
			}
			else if (!isHuman())
			{
				AI_conquerCity(pNewCity); // could delete the pointer...
			}
			else
			{
			    // mod start
			    gDLL->getInterfaceIFace()->selectCity(pNewCity);
			    // mod end

				//popup raze option
		....................
	}
}

Then the city screen of the captured city will be showed before raze city popup.

But there might be a minor defect.
If the captured city has been selected, you can do something via the city screen and then choose to raze the city. Fortunately, the captured city would be affected by anarchy if it can be razed.
Thus, this problem can be neglected.
 
Sweet, tried it and it worked as advertised. I'd like the raze popup to appear on the city screen for the new city though.

Yeah, it'd be annoying in that you can't totally scroll the building list or check the PLEs as Emperorfool mentioned but this would be much better than what there was built in, which was nothing. I think it's okay if you can't scroll the buildings as you should be able to see all the important buildings and if you wanted to raze a city with so many buildings that it scrolled, well that crazy choice is up to you :D
 
I'd like the raze popup to appear on the city screen for the new city though.

Isn't that what dilandau's code does? I haven't tried it yet, but I thought it merely popped up the city screen right before showing the popup.
 
Can you switch cities using the numpad while the screen is up? If not, then this is perfect. Just add the "Examine City" button to the popup and show it. If they click that, select the city to show the city screen and bring up the popup again. It will appear once they close the city screen. :goodjob:
 
Yes you can switch cities. I'm not sure that is a deal breaker though, have to see how it behaves. I *think* it will recenter on the conquested city once you exit the city screen regardless of if you switch or not, will need to check it.

So I'm going to try to add the examine city button then. I'm not really sure how to do this but I'll get in there and try.
 
edit:

I think adding the new option would be this in CvDLLButtonPopup.cpp

Code:
	case BUTTONPOPUP_RAZECITY:
		if (pPopupReturn->getButtonClicked() == 1)
		{
			gDLL->sendDoTask(info.getData1(), TASK_RAZE, -1, -1, false, false, false, false);
		}
		else if (pPopupReturn->getButtonClicked() == 2)
		{
			CvCity* pCity = GET_PLAYER(GC.getGameINLINE().getActivePlayer()).getCity(info.getData1());
			if (NULL != pCity)
			{
				gDLL->getEventReporterIFace()->cityAcquiredAndKept(GC.getGameINLINE().getActivePlayer(), pCity);
			}

			gDLL->sendDoTask(info.getData1(), TASK_GIFT, info.getData2(), -1, false, false, false, false);
		}
		else if (pPopupReturn->getButtonClicked() == 0)
		{
			CvCity* pCity = GET_PLAYER(GC.getGameINLINE().getActivePlayer()).getCity(info.getData1());
			if (NULL != pCity)
			{
				pCity->chooseProduction();
				gDLL->getEventReporterIFace()->cityAcquiredAndKept(GC.getGameINLINE().getActivePlayer(), pCity);
			}
		}
		break;

just need to add an
else if (pPopupReturn->getButtonClicked() == 3...

I tried this before and got an error. Maybe I just recompiled wrong or something. I am on the right track though no?
 
Top Bottom