A Question about pointers...

Afforess

The White Wizard
Joined
Jul 31, 2007
Messages
12,239
Location
Austin, Texas
I'm very new to pointers. I don't understand them very much, so keep that in mind in any explanations.

Now, I'm trying to get a city's ID in CvDeal.cpp, but can't seem to get it to work. I'm sure it's very simple, but I always have trouble with simple tasks. This is the line of code I used:

Code:
CvCity* pHQCity = pNewHQCity->getID();

The compiler says it can not convert an int to CvCity*.

For reference, the rest of the code block is:
Spoiler :
Code:
  case TRADE_CORPORATION:
        if (GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_DIPLOMACY))
        {
            CvCity* pOldHeadquarters = GC.getGameINLINE().getHeadquarters((CorporationTypes)trade.m_iData);
            pNewHQCity = GET_PLAYER(eToPlayer).getBestHQCity((CorporationTypes)trade.m_iData);
           [COLOR="Red"] CvCity* pHQCity = pNewHQCity->getID();[/COLOR]
            GC.getGameINLINE().setHeadquarters((CorporationTypes)trade.m_iData, pNewHQCity, true);
            GET_PLAYER(eToPlayer).updateCorporation();
            GET_PLAYER(eFromPlayer).updateCorporation();
            if (pOldHeadquarters != NULL && pHQCity != NULL)
            {
                pNewHQCity->isActiveCorporation((CorporationTypes)trade.m_iData);
                //The old HQ city still has the corporation, just not the HQ. 
                pOldHeadquarters->setHasCorporation((CorporationTypes)trade.m_iData, true, false, false);
            }
            for (int i = 0; i < MAX_PLAYERS; i++)
            {
                if (GET_TEAM(GET_PLAYER((PlayerTypes)i).getTeam()).isHasMet(GET_PLAYER(eToPlayer).getTeam()) || GET_TEAM(GET_PLAYER((PlayerTypes)i).getTeam()).isHasMet(GET_PLAYER(eFromPlayer).getTeam()))
                {
                    szBuffer = gDLL->getText("TXT_KEY_MISC_CORPORATION_TRADE", GC.getCorporationInfo((CorporationTypes)trade.m_iData).getDescription(), GET_PLAYER(eFromPlayer).getCivilizationDescriptionKey(), GET_PLAYER(eToPlayer).getCivilizationDescriptionKey()).GetCString();
                    gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)i), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_GOLDAGESTART", MESSAGE_TYPE_MAJOR_EVENT, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_HIGHLIGHT_TEXT"));
                }
            }
        }
        break;

And because CvPlayer::getBestHQCity() is a new function , I'll post that too:

Spoiler :
Code:
CvCity* CvPlayer::getBestHQCity(CorporationTypes eCorporation) const
{
    CvCity* pCurrentHQ = GC.getGameINLINE().getHeadquarters(eCorporation);
    CvCity* pLoopCity;
    CvCity* pBestCity;
    int iValue;
    int iBestValue = 0;

    int iLoop;
    for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
    {
        iValue = 0;
        if (!pLoopCity->isHasCorporation(eCorporation))
        {
            if (pLoopCity->isConnectedTo(pCurrentHQ))
            {
                for (int iCorporation = 0; iCorporation < GC.getNumCorporationInfos(); ++iCorporation)
                {
                    if (pLoopCity->isHeadquarters((CorporationTypes)iCorporation))
                    {
                        if (GC.getGameINLINE().isCompetingCorporation((CorporationTypes)iCorporation, eCorporation))
                        {
                            continue;
                        }
                        iValue -= 25;
                    }
                }

                bool bFoundBonus = false;
                for (int i = 0; i < GC.getNUM_CORPORATION_PREREQ_BONUSES(); ++i)
                {
                    BonusTypes eBonus = (BonusTypes)GC.getCorporationInfo(eCorporation).getPrereqBonus(i);
                    if (NO_BONUS != eBonus)
                    {
                        if (pLoopCity->hasBonus(eBonus))
                        {
                            bFoundBonus = true;
                            iValue += 50;
                        }
                    }
                }

                if (!bFoundBonus)
                {
                    continue;
                }

                iValue += 100;
            }
        }
        else
        {
            iValue = 300;

            if (pLoopCity->isConnectedTo(pCurrentHQ))
            {
                iValue += 100;
            }

            for (int i = 0; i < GC.getNUM_CORPORATION_PREREQ_BONUSES(); ++i)
            {
                BonusTypes eBonus = (BonusTypes)GC.getCorporationInfo(eCorporation).getPrereqBonus(i);
                if (NO_BONUS != eBonus)
                {
                    if (pLoopCity->hasBonus(eBonus))
                    {
                        iValue += 50;
                    }
                }
            }

            for (int iCorporation = 0; iCorporation < GC.getNumCorporationInfos(); ++iCorporation)
            {
                if (pLoopCity->isHeadquarters((CorporationTypes)iCorporation))
                {
                    iValue -= 25;
                }
            }
        }

        if (iValue > iBestValue)
        {
            iBestValue = iValue;
            pBestCity = pLoopCity;
        }
    }

    return pBestCity;
}
 
Do you want a pointer or an int? pNewHQCity is already a CvCity*, so if you want a pointer just use it. If you want an int, then declare your variable as an int.
 
Do you want a pointer or an int? pNewHQCity is already a CvCity*, so if you want a pointer just use it. If you want an int, then declare your variable as an int.

No, I want a pointer. Could you clarify what you mean by "just use it"? As I said in the OP, I don't understand what I'm really dealing with yet.
 
You wrote:

CvCity* pHQCity = pNewHQCity->getID();

pNewHQCity and pHQCity are both CvCity*. getID is a function which returns an int. So you could write pHQCity = pNewHQCity and it would compile. It would be redundant, but it would compile. Instead, anyplace you are using pHQCity, just use pNewHQCity.
 
pNewHQCity IS a pointer. You can ask it for values, like the ID.

The ID is just an Integer. You use that to save a pointer, and then once you load the int you immediately convert it to a pointer again.


So if you want to be able to ask things like: pHQCity->getCivilizationType()

Then you want to write:

CvCity* pHQCity = pNewHQCity;

Otherwise, if you are looking to save an integer to minimize memory footprint, you would use:

int iHQCityID = pNewHQCity->getID();



But most importantly, I see nothing in your larger code block which justifies a new pointer. You can just query directly to pNewHQCity in each place you tried to use pHQCity
 
For further education, a pointer is simply an address in memory. Memory (RAM) is a giant array of bytes (numbers with 8 binary bits that can range from 0 to 255). Everything in a program--from PlayerTypes numbers to CvWString text strings to int IDs to CvCity objects--is stored in this giant array. Each slot in the array has a numeric address which starts at 0 for the first byte and increments by 1 for the next slot.

A simple value like an int requires 4 bytes in the SDK and thus it requires 4 slots in the giant memory array. You can store a pointer to it using the & (address) operator:

Code:
int x;
int* pointerToX = &x;

Pointers are useful for allowing a function to modify the value of a variable passed to it. Normally in C and C++ everything is passed by value which means the value of the variable is copied into a temporary variable for the function to use. If the function changes it, the original variable doesn't change.

Code:
void addTwo(int value) {
    value += 2;
}

int x = 5;
addTwo(x);
print(x);

The above code prints 5 because addTwo() only gets a copy of x's value, in this case 5. Adding 2 to its local copy of 5 doesn't change the original value of x. But you can use a pointer to allow addTwo() to change the original value:

Code:
void reallyAddTwo(int* value) {
    (*value) += 2;
}

int x = 5;
reallyAddTwo(&x);
print(x);

Here addTwo() expects a pointer to an int, and the caller takes the address of x to pass a pointer to it to addTwo(). (*value) just means "follow this pointer" and allows you to set the value. It's similar to the -> you see a lot in the SDK, for example "pCity->getID()".

Pointers to CvCity and CvPlayer objects are no different. If you were to write a function that took a CvCity, calling it would make a complete copy of the CvCity before calling the function. First, this would be expensive in runtime cost, but more importantly it wouldn't allow the function to modify the original CvCity.

One thing to keep in mind is that pointers are just numbers. On 32-bit systems they are 4 bytes just like an int. When you pass a pointer to a function such as reallyAddTwo() above, you are actually passing a copy of the pointer. But since a pointer and its copy both point to the same memory address (they have the same value) it doesn't matter.
 
For further education, a pointer is simply an address in memory. Memory (RAM) is a giant array of bytes (numbers with 8 binary bits that can range from 0 to 255). Everything in a program--from PlayerTypes numbers to CvWString text strings to int IDs to CvCity objects--is stored in this giant array. Each slot in the array has a numeric address which starts at 0 for the first byte and increments by 1 for the next slot.

A simple value like an int requires 4 bytes in the SDK and thus it requires 4 slots in the giant memory array. You can store a pointer to it using the & (address) operator:

Code:
int x;
int* pointerToX = &x;
Pointers are useful for allowing a function to modify the value of a variable passed to it. Normally in C and C++ everything is passed by value which means the value of the variable is copied into a temporary variable for the function to use. If the function changes it, the original variable doesn't change.

Code:
void addTwo(int value) {
    value += 2;
}

int x = 5;
addTwo(x);
print(x);
The above code prints 5 because addTwo() only gets a copy of x's value, in this case 5. Adding 2 to its local copy of 5 doesn't change the original value of x. But you can use a pointer to allow addTwo() to change the original value:

Code:
void reallyAddTwo(int* value) {
    (*value) += 2;
}

int x = 5;
reallyAddTwo(&x);
print(x);
Here addTwo() expects a pointer to an int, and the caller takes the address of x to pass a pointer to it to addTwo(). (*value) just means "follow this pointer" and allows you to set the value. It's similar to the -> you see a lot in the SDK, for example "pCity->getID()".

Pointers to CvCity and CvPlayer objects are no different. If you were to write a function that took a CvCity, calling it would make a complete copy of the CvCity before calling the function. First, this would be expensive in runtime cost, but more importantly it wouldn't allow the function to modify the original CvCity.

One thing to keep in mind is that pointers are just numbers. On 32-bit systems they are 4 bytes just like an int. When you pass a pointer to a function such as reallyAddTwo() above, you are actually passing a copy of the pointer. But since a pointer and its copy both point to the same memory address (they have the same value) it doesn't matter.

Ohh... That makes sense. It's a way of "remotely" access variables in functions, right?


However, now that this compiles, I have another problem. I get an automatic CTD when someone trades a corporation.

The code is in
Code:
bool CvDeal::startTrade(TradeData trade, PlayerTypes eFromPlayer, PlayerTypes eToPlayer)
{
...
  case TRADE_CORPORATION:
        if (GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_DIPLOMACY))
        {
           	[COLOR="Red"]CvCity* pOldHeadquarters = GC.getGameINLINE().getHeadquarters((CorporationTypes)trade.m_iData);[/COLOR]
	        pNewHQCity = GET_PLAYER(eToPlayer).getBestHQCity((CorporationTypes)trade.m_iData);	
	        GC.getGameINLINE().setHeadquarters((CorporationTypes)trade.m_iData, pNewHQCity, true);
			
		[COLOR="Red"]pNewHQCity->setHasCorporation((CorporationTypes)trade.m_iData, true, false, false);
		//The old HQ city still has the corporation, just not the HQ. 
		pOldHeadquarters->setHasCorporation((CorporationTypes)trade.m_iData, true, false, false);[/COLOR]
			
			
		GET_PLAYER(eToPlayer).updateCorporation();
		GET_PLAYER(eFromPlayer).updateCorporation();
            for (int i = 0; i < MAX_PLAYERS; i++)
            {
                if (GET_TEAM(GET_PLAYER((PlayerTypes)i).getTeam()).isHasMet(GET_PLAYER(eToPlayer).getTeam()) || GET_TEAM(GET_PLAYER((PlayerTypes)i).getTeam()).isHasMet(GET_PLAYER(eFromPlayer).getTeam()))
                {
                    szBuffer = gDLL->getText("TXT_KEY_MISC_CORPORATION_TRADE", GC.getCorporationInfo((CorporationTypes)trade.m_iData).getDescription(), GET_PLAYER(eFromPlayer).getCivilizationDescriptionKey(), GET_PLAYER(eToPlayer).getCivilizationDescriptionKey()).GetCString();
                    gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)i), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_GOLDAGESTART", MESSAGE_TYPE_MAJOR_EVENT, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_HIGHLIGHT_TEXT"));
                }
            }
        }
        break;

Most of the code is just cut-n-pasted from Dom Pedro's test of time. His code worked, kinda. It didn't CTD anyway, but it didn't have the desired effect. When you traded a corporation HQ, a city of yours received it okay, but the game never set that city to an active corporation, so you couldn't build executives from that city, despite it being the HQ. Also, the city that lost the HQ lost the corporation completely, which I would prefer it keep the corporation, and just lose the HQ status. That's why I added those three lines, but it doesn't work, it just CTD's. Can someone tell me what I did wrong?

Edit: wait, I think I know why. Give me a second...

Edit2: NVM, I updated the code, but it still crashes...
 
Hopefully obvious question: did you try running it with a debug DLL so it would crash into Visual Studio so you could see where it crashed?
 
Back
Top Bottom