• Civilization 7 has been announced. For more info please check the forum here .

Multiple array questions (for corporation like building effect)

Pickly

Prince
Joined
Jun 5, 2009
Messages
535
I've been trying to add an building property that allows buildings to produce commerce and/or yields from resources, but this version would allow different amounts of resources to be produced for different bonuses. The additions at the moment aren't working (I'm testing using a capital building with these properties, and either the game crashes when the capital is founded, or doesn't do anything, depending on how I try it), and thus, this thread to try and sort out the issues.

Starting with CvInfos, does the code written below appear right, and when using a "getNumber(number 1, number 2)" function, are bonuses the first number and the type of commerce the second number, or the reverse? (I do kind of see what this function is doing in general, but by specifics it is harder to tell.). the code was just copied and adjusted from specialist yield changes on buildings.

Spoiler :
Code:
pXML->Init2DIntList(&m_ppiCommerceFromBonus, GC.getNumBonusInfos(), NUM_COMMERCE_TYPES);
	if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"CommercesFromBonus"))
	{
		iNumChildren = gDLL->getXMLIFace()->GetNumChildren(pXML->GetXML());
		if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"CommerceFromBonus"))
		{
			for(j=0;j<iNumChildren;j++)
			{
				pXML->GetChildXmlValByName(szTextVal, "BonusConsumed");
				k = pXML->FindInInfoClass(szTextVal);
				SAFE_DELETE_ARRAY(m_ppiCommerceFromBonus[k]);
				if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"iCommerce") && (k > -1))
				{
					pXML->SetCommerce(&m_ppiCommerceFromBonus[k]);
					gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
				}
				else
				{
					pXML->InitList(&m_ppiCommerceFromBonus[k], NUM_COMMERCE_TYPES);
				}
				if (!gDLL->getXMLIFace()->NextSibling(pXML->GetXML()))
				{
					break;
				}
			}
			gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
		}
		gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
	}

	pXML->Init2DIntList(&m_ppiYieldFromBonus, GC.getNumSpecialistInfos(), NUM_YIELD_TYPES);
	if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"YieldsFromBonus"))
	{
		iNumChildren = gDLL->getXMLIFace()->GetNumChildren(pXML->GetXML());
		if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"YieldFromBonus"))
		{
			for(j=0;j<iNumChildren;j++)
			{
				pXML->GetChildXmlValByName(szTextVal, "BonusConsumed");
				k = pXML->FindInInfoClass(szTextVal);
				SAFE_DELETE_ARRAY(m_ppiYieldFromBonus[k]);
				if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"iCommerce") && (k > -1))
				{
					pXML->SetCommerce(&m_ppiYieldFromBonus[k]);
					gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
				}
				else
				{
					pXML->InitList(&m_ppiYieldFromBonus[k], NUM_YIELD_TYPES);
				}
				if (!gDLL->getXMLIFace()->NextSibling(pXML->GetXML()))
				{
					break;
				}
			}
			gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
		}
		gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
	}
 
try to create a Debug DLL and then attach it to the running process. It will then show you the location in the code where the crash happens.
 
Something similiar was made before by davidlallen here. Even if it isn't exactly what you want, maybe his code holds some hints for you.

Also there is a thread about Troubles with Arrays and Arrays of Arrays. That might also be of interest for you I guess (but I'm not sure thou because I didn't make many SDK modifications myself :crazyeye:)
 
Debug DLL related question:

When splitting the CyCityInterface1 file, do any of you know if/where it might be referenced in other files? (Creating a debug DLL is admittedly something I probably should be using anyway, but haven't thanks to whichever error is caused by too much stuff in a file. ) Checking through the other DLL files, it seems none link to the CyCityInterface one, but before making some big changes, I'm doing a quick check if anyone else has done something similar.
 
Strangely, while the debug DLL caught some other things, it didn't actually spit out anything when the game crashed again on founding a city. Is this the sort of thing that might be solved by running the program through Visual C++ (which means I'll than read up on that and figure it out), or might something else be happening?
 
did you attach visual studio to the process?(you find it under debug) It will then listen to the programm and stop when the crash occurs and point you to the code where the crash happened.
 
I didn't end up doing that, although looking around some other threads did, plus looking around the program, does seem to point ot solving the issue.

I did get the crash part sorted out (the longer way of just commenting out different pieces of code and running the program), though now am back to the problem of the additions not actually having any effect. Thanks for the advice, though, I'll probably be trying it out on the next run of attempts to get this working.
 
A couple of debugger questions:

1. Sort of a low level question, but when the debugger stops at a breakpoint, how do I allow the game to continue working after the output?

2. If I'm looking to see if the XML is loading properly (which seems to be a possible reason these new XML tags aren't working), would I be attaching before the mod gets loaded, and hoping the debugger trips during the loading process, or would something else need to be tried?
 
A couple of debugger questions:

1. Sort of a low level question, but when the debugger stops at a breakpoint, how do I allow the game to continue working after the output?

You can continue running with F5 (or the 'play' button' at the tool bar at the top - which looks like a green triangle).

2. If I'm looking to see if the XML is loading properly (which seems to be a possible reason these new XML tags aren't working), would I be attaching before the mod gets loaded, and hoping the debugger trips during the loading process, or would something else need to be tried?

Take a look at my DLL tutorial, in the debugging sections. You can run the game from within VS so it is attached from the start.
 
Edit: Turns out the issue doesn't seem to be with the XML part of these changes after all, I hadn't actually thought out the city parts of the changes right. Still having some issues, but they aren't the ones I thought I was looking for.
 
Am still having some very frustrating problems with these changes. I'm considering just copying DavidAllen's linked solution and adjusting it somewhat to fit my own plans for this, but am still wondering about some issues that aren't making a lot of sense at the moment.


1. When is the Processbonus function regularly used?

I've been trying to have the buildings update their yields and commerce during this function, since from the code it seems to get used if bonuses are changed, and the other things it does seem to fit this as well. However, when running with the debugger, the processbonus function seems to update a bunch of times during the first few turns, but didn't seem update when cultural borders captured another resource.


2. Direct code question

The code I was trying earlier to update the bonuses is below. For some reason the code below sets the yield and commerce changes to zero when using setBuildingCommercechange or setBuildingYieldChange, but when using ChangeBuildingCommerceChange of ChangeBuildingYieldChange, it updates properly when the building is built (though afterwards the yields and commerce build up quickly as expected)

Is this some basic coding mistake involving putting the veriable in the wrong place, or something along those lines, or am I not understanding somethign else about what everything does?

Code:
void CvCity::processBonus(BonusTypes eBonus, int iChange)
{
        [I]bunch of other stuff here[/I]

	for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
	{
        [I]Bunch of other stuff here[/I]

		//Acetum Cucumbis:  Added by Pickly, May 1, 2011
		for (int iCommerce = 0; iCommerce < NUM_COMMERCE_TYPES; ++iCommerce)
		{
			int iCommerceChange = 0;
//			for (int iBonus = 0; iBonus < GC.getNumBonusInfos(); ++iBonus)
                        {
			       iCommerceChange += GC.getBuildingInfo((BuildingTypes)iI).getCommerceFromBonus((BonusTypes)eBonus, CommerceTypes(iCommerce)) * iChange;
                        }
			changeBuildingCommerceChange((BuildingClassTypes)GC.getBuildingInfo((BuildingTypes)iI).getBuildingClassType(), CommerceTypes(iCommerce), iCommerceChange);
                        [B]or[/B]
                        setBuildingCommerceChange((BuildingClassTypes)GC.getBuildingInfo((BuildingTypes)iI).getBuildingClassType(), CommerceTypes(iCommerce), iCommerceChange);
		}
		for (int iYield = 0; iYield < NUM_YIELD_TYPES; ++iYield)
		{
			int iYieldChange = 0;
			for (int iBonus = 0; iBonus < GC.getNumBonusInfos(); ++iBonus)
                        {
			      iYieldChange += GC.getBuildingInfo((BuildingTypes)iI).getYieldFromBonus(eBonus, YieldTypes(iYield)) * iChange;
                        }
			changeBuildingYieldChange((BuildingClassTypes)GC.getBuildingInfo((BuildingTypes)iI).getBuildingClassType(), YieldTypes(iYield), iYieldChange);
                        [B]or[/B]
                        setBuildingYieldChange((BuildingClassTypes)GC.getBuildingInfo((BuildingTypes)iI).getBuildingClassType(), YieldTypes(iYield), iYieldChange);
		}
 
Usually you should use the change...() functions, not the set...() ones, because you are adding to exisiting commerce or yields. Think of the change functions being like +=, and the set functions being like =.

Changes to plots do cause bonus related checks to be done - you have to follow through the CvPlotGroup logic - just search for the function changeNumBonuses. In case you don't know, PlotGroups are sets of plots which are connected - so trade routes can go through them. This is why the bonus code uses them.

Hope this helps.
 
those loops with iBonus look wrong. iBonus isn't even used in the loop
 
no, that would be even worse. eBonus is the Param of processBonus and what you want to use.

I don't understand CommerceTypes(iCommerce) in your code either.


instead of the loops just use
Code:
        bunch of other stuff here

	for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
	{
        Bunch of other stuff here

		for (int iCommerce = 0; iCommerce < NUM_COMMERCE_TYPES; ++iCommerce)
		{

int iCommerceChange = GC.getBuildingInfo((BuildingTypes)iI).getCommerceFromBonus(eBonus, (CommerceTypes)iCommerce) * iChange;
changeBuildingCommerceChange((BuildingClassTypes)GC.getBuildingInfo((BuildingTypes)iI).getBuildingClassType(),(CommerceTypes)iCommerce, iCommerceChange);
}

and similar for the yields.
 
I don't understand CommerceTypes(iCommerce) in your code either.

It's the same as (CommerceTypes)iCommerce, only a different notation for casting.
 
Hi, I didn't actually check your code before (the CODE spoiler thing really makes posted code really hard to read), but I've tidied up your code and got rid of the dodgy loops - but there is still one other thing you need to do I think - nothing refers to how many of a building the city actually has - check out the original function and you'll see how it calls getNumActiveBuilding((BuildingTypes)iI) to take into account whether you have the building and if so, how many of them. - this will always be one or zero in the unmodded game.

Hope that helps.

Code:
void CvCity::processBonus(BonusTypes eBonus, int iChange)
{
  //bunch of other stuff here

  for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
  {
    //Bunch of other stuff here

    //Acetum Cucumbis:  Added by Pickly, May 1, 2011
    const CvBuildingInfo& buildingInfo = GC.getBuildingInfo((BuildingTypes)iI);
    BuildingClassTypes buildingClassType = (BuildingClassTypes)buildingInfo.getBuildingClassType();
    for (int iCommerce = 0; iCommerce < NUM_COMMERCE_TYPES; ++iCommerce)
    {
      int iCommerceChange = buildingInfo.getCommerceFromBonus(eBonus, (CommerceTypes)iCommerce) * iChange;
      changeBuildingCommerceChange(buildingClassType, (CommerceTypes)iCommerce, iCommerceChange);
    }

    for (int iYield = 0; iYield < NUM_YIELD_TYPES; ++iYield)
    {
      int iYieldChange = buildingInfo.getYieldFromBonus(eBonus, (YieldTypes)iYield) * iChange;
      changeBuildingYieldChange(buildingClassType, (YieldTypes)iYield, iYieldChange);
    }
  }
}
 
Probably should have updated this earlier, but I ended up going back and doing this code a somewhat different way, and have it working now. (It's a lot less clunky, both for reasons you guys mentioned, and a few others)

About the extra loops: The original idea for those loops was for fractional increases in bonuses (which I would change the code for after making sure the basic structure worked), where, say, a change of just 1 for the number of certain bonuses might get rounded away using this system, while redoing the entire bonus will reduce potential issues here. I did realize that doing it this way would create other issues, (Which is probably a part of DavidAllen using the corporation variable), so just went with a new variable in the method in the mod now.


Thanks for the advice and help, everyone. (Now to figure out how to do the text for these in a way that doesn't take up too much space.)
 
Top Bottom