Civic Attitude Modifier

Can you also post an example civic that you're testing?

Did you try adding some debugging output (into the log or the hover text) inside that code, or using the interactive debugger?
 
Can you also post an example civic that you're testing?

Did you try adding some debugging output (into the log or the hover text) inside that code, or using the interactive debugger?

I just tacked this onto base BTS despotism, at the end:

Code:
<CivicAttitudeChanges>
                <CivicAttitudeChange>
                    <CivicType>CIVIC_SLAVERY</CivicType>
                    <iAttitudeChange>-5</iAttitudeChange>
                    <Description>%d1: We Hate Slaves!</Description>
                </CivicAttitudeChange>
            </CivicAttitudeChanges>

I haven't tried debugging yet, I'm studying for Exams... :(
 
Now this puzzles me. I added text for every possibility, and yet, NONE of them showed up, despite the fact that the leader was clearly annoyed with me.

Here's the CvGameTextMgr code I have,

Code:
	CivicTypes eTargetCivic;
	CivicTypes eCivic;
	for (int iJ = 0; iJ < GC.getNumCivicOptionInfos(); iJ++)
	{
		eTargetCivic = GET_PLAYER(eTargetPlayer).getCivics((CivicOptionTypes)iJ);
		eCivic = GET_PLAYER(ePlayer).getCivics((CivicOptionTypes)iJ);
		if (GC.getCivicInfo(eCivic).getCivicAttitudeChange(eTargetCivic) != 0)
		{
			szBuffer.append(NEWLINE);
			szBuffer.append(GC.getCivicInfo(eTargetCivic).getCivicAttitudeReason(eCivic));
			szBuffer.append(gDLL->getText("If you se this, the if1 check passed").GetCString());
		}
		else if (GC.getCivicInfo(eCivic).getCivicAttitudeChange(eTargetCivic) != 0)
		{
			szBuffer.append(NEWLINE);
			szBuffer.append(GC.getCivicInfo(eCivic).getCivicAttitudeReason(eTargetCivic));
			szBuffer.append(gDLL->getText("If you se this, the if2 check passed").GetCString());
		}
		else if (GC.getCivicInfo(eTargetCivic).getCivicAttitudeChange(eCivic) != 0)
		{
			szBuffer.append(NEWLINE);
			szBuffer.append(GC.getCivicInfo(eTargetCivic).getCivicAttitudeReason(eCivic));
			szBuffer.append(gDLL->getText("If you se this, the if3 check passed").GetCString());
		}
		else if (GC.getCivicInfo(eTargetCivic).getCivicAttitudeChange(eCivic) != 0)
		{
			szBuffer.append(NEWLINE);
			szBuffer.append(GC.getCivicInfo(eCivic).getCivicAttitudeReason(eTargetCivic));
			szBuffer.append(gDLL->getText("If you se this, the if4 check passed").GetCString());
		}
		
	}

If it is failing all 4 possible checks.... then I'm totally confused.
 
What's the difference between 1 and 2 and again between 3 and 4? You forgot

Code:
else
{
    ... message that you failed all checks ... just to be thorough ...
}
 
What's the difference between 1 and 2 and again between 3 and 4? You forgot

Code:
else
{
    ... message that you failed all checks ... just to be thorough ...
}[/QUOTE]

I did add a test message earlier that I didn't mention inside the loop but outside of the if statements, and it appeared fine. 

However, I get the feeling that the failed check will appear just fine.
 
I am also curious what the intended difference was between the first 2, and again between the last 2. Maybe you meant to check != and then == ? that would cover all cases and appropriately leave you confused why it didn't pass any of them. Though it would also make it impossible to ever REACH the 3rd and 4th checks.
 
I am also curious what the intended difference was between the first 2, and again between the last 2. Maybe you meant to check != and then == ? that would cover all cases and appropriately leave you confused why it didn't pass any of them. Though it would also make it impossible to ever REACH the 3rd and 4th checks.

It checks all the possible civic combinations, etargetcivic and ecivic are switched in each one.

At this point, I think eTargetCivic and eCivic are not the correct civics, because I know that it is working, so the civics I'm checking against must not be.
 
Ok, I see now, it isn't that the IF checks change between 1 & 2 and then again between 3 & 4, it is that the output text changes. In that case you should eliminate the 2nd and 4th ELIF, and instead just output 3 lines within each IF check, as it is impossible for the 2nd and 4th to fire as written. But the first and third aren't hitting anyway, so the point is semi-moot. Strange that they would work, but the checks here wouldn't. Post the functional code for comparison maybe?

EDIT: How about doing a loop over Civics instead of CivicOptions, and just display every modifier which exists, just to test things? This code relies upon the players following civics which give these modifiers, which I assume is the case during your test, but it'd be nice to just flat out check all combinations once anyway.
 
Ok, I see now, it isn't that the IF checks change between 1 & 2 and then again between 3 & 4, it is that the output text changes. In that case you should eliminate the 2nd and 4th ELIF, and instead just output 3 lines within each IF check, as it is impossible for the 2nd and 4th to fire as written. But the first and third aren't hitting anyway, so the point is semi-moot. Strange that they would work, but the checks here wouldn't. Post the functional code for comparison maybe?

No... You're still missing it. Let me highlight it for you.

Code:
    CivicTypes eTargetCivic;
    CivicTypes eCivic;
    for (int iJ = 0; iJ < GC.getNumCivicOptionInfos(); iJ++)
    {
      [COLOR=Red]  eTargetCivic[/COLOR] = GET_PLAYER(eTargetPlayer).getCivics((CivicOptionTypes)iJ);
        [COLOR=Blue]eCivic[/COLOR] = GET_PLAYER(ePlayer).getCivics((CivicOptionTypes)iJ);
        if (GC.getCivicInfo([COLOR=Blue]eCivic[/COLOR]).getCivicAttitudeChange([COLOR=Red]eTargetCivic[/COLOR]) != 0)
        {
            szBuffer.append(NEWLINE);
            szBuffer.append(GC.getCivicInfo([COLOR=Red]eTargetCivic[/COLOR]).getCivicAttitudeReason([COLOR=Blue]eCivic[/COLOR]));
            szBuffer.append(gDLL->getText("If you se this, the if1 check passed").GetCString());
        }
        if (GC.getCivicInfo([COLOR=Blue]eCivic[/COLOR]).getCivicAttitudeChange([COLOR=Red]eTargetCivic[/COLOR]) != 0)
        {
            szBuffer.append(NEWLINE);
            szBuffer.append(GC.getCivicInfo([COLOR=Blue]eCivic[/COLOR]).getCivicAttitudeReason([COLOR=Red]eTargetCivic)[/COLOR]);
            szBuffer.append(gDLL->getText("If you se this, the if2 check passed").GetCString());
        }
        if (GC.getCivicInfo([COLOR=Red]eTargetCivic[/COLOR]).getCivicAttitudeChange([COLOR=Blue]eCivic[/COLOR]) != 0)
        {
            szBuffer.append(NEWLINE);
            szBuffer.append(GC.getCivicInfo([COLOR=Red]eTargetCivic[/COLOR]).getCivicAttitudeReason([COLOR=Blue]eCivic[/COLOR]));
            szBuffer.append(gDLL->getText("If you se this, the if3 check passed").GetCString());
        }
        if (GC.getCivicInfo([COLOR=Red]eTargetCivic[/COLOR]).getCivicAttitudeChange([COLOR=Blue]eCivic[/COLOR]) != 0)
        {
            szBuffer.append(NEWLINE);
            szBuffer.append(GC.getCivicInfo([COLOR=Blue]eCivic[/COLOR]).getCivicAttitudeReason([COLOR=Red]eTargetCivic[/COLOR]));
            szBuffer.append(gDLL->getText("If you se this, the if4 check passed").GetCString());
        }
        
    }

It's simply a standard 2x2 search pattern, which SHOULD have yielded some result.

Oh, I did remove all the Else checks and recompiled, same result.

EDIT: How about doing a loop over Civics instead of CivicOptions, and just display every modifier which exists, just to test things? This code relies upon the players following civics which give these modifiers, which I assume is the case during your test, but it'd be nice to just flat out check all combinations once anyway.

I tried this:

Code:
    for (int iJ = 0; iJ < GC.getNumCivicInfos(); iJ++)
    {
        for (int iK = 0; iK < GC.getNumCivicInfos(); iK++)
        {
            if (GC.getCivicInfo((CivicTypes)iJ).getCivicAttitudeChange((CivicTypes)iK) != 0)
            {
                szBuffer.append(NEWLINE);
                szBuffer.append(GC.getCivicInfo((CivicTypes)iK).getCivicAttitudeReason((CivicTypes)iJ));
                szBuffer.append(gDLL->getText("If you se this, the if5 check passed").GetCString());
            }
            if (GC.getCivicInfo((CivicTypes)iJ).getCivicAttitudeChange((CivicTypes)iK) != 0)
            {
                szBuffer.append(NEWLINE);
                szBuffer.append(GC.getCivicInfo((CivicTypes)iJ).getCivicAttitudeReason((CivicTypes)iK));
                szBuffer.append(gDLL->getText("If you se this, the if6 check passed").GetCString());
            }
            if (GC.getCivicInfo((CivicTypes)iK).getCivicAttitudeChange((CivicTypes)iJ) != 0)
            {
                szBuffer.append(NEWLINE);
                szBuffer.append(GC.getCivicInfo((CivicTypes)iK).getCivicAttitudeReason((CivicTypes)iJ));
                szBuffer.append(gDLL->getText("If you se this, the if7 check passed").GetCString());
            }
            if (GC.getCivicInfo((CivicTypes)iK).getCivicAttitudeChange((CivicTypes)iJ) != 0)
            {
                szBuffer.append(NEWLINE);
                szBuffer.append(GC.getCivicInfo((CivicTypes)iJ).getCivicAttitudeReason((CivicTypes)iK));
                szBuffer.append(gDLL->getText("If you se this, the if8 check passed").GetCString());
            }
            
        }
    }

But I got an instant CTD when I tried to enter diplomacy... what did I do wrong?
 
Either I'm missing it too, or you're missing what we're saying. Here are the two pairs of if tests. AFAICT, the first two are identical character-for-character. So are the second two. If the first one fails, the second must fail as well, and the same for the third and fourth.

Code:
        if (GC.getCivicInfo([COLOR=Blue]eCivic[/COLOR]).getCivicAttitudeChange([COLOR=Red]eTargetCivic[/COLOR]) != 0)
        if (GC.getCivicInfo([COLOR=Blue]eCivic[/COLOR]).getCivicAttitudeChange([COLOR=Red]eTargetCivic[/COLOR]) != 0)

        if (GC.getCivicInfo([COLOR=Red]eTargetCivic[/COLOR]).getCivicAttitudeChange([COLOR=Blue]eCivic[/COLOR]) != 0)
        if (GC.getCivicInfo([COLOR=Red]eTargetCivic[/COLOR]).getCivicAttitudeChange([COLOR=Blue]eCivic[/COLOR]) != 0)

In effect what you're doing is this:

Code:
if (x == 5)
    ...
if (x == 5)
    ...

I understand that the code you have in the ... differs between the two tests, but the tests themselves are what matter in this case since they are not passing. Having two failed tests is the same as having one or none or 517,274.

Your next block of code looks okay, though it suffers the same anti-logic as above. I see nothing that should cause a CTD. Do you get the CTD when you hover over the rival in the scoreboard? If not, then this code isn't to blame since it's called for that as well.

I hate to sound like a broken record, but my advice is the same: step though your code using the debugger to find what's happening. Staring at code only gets you so far. As well, if you were running the debugger on this, a CTD would instead drop you into the code that caused it.
 
Either I'm missing it too, or you're missing what we're saying. Here are the two pairs of if tests. AFAICT, the first two are identical character-for-character. So are the second two. If the first one fails, the second must fail as well, and the same for the third and fourth.

Code:
        if (GC.getCivicInfo([COLOR=Blue]eCivic[/COLOR]).getCivicAttitudeChange([COLOR=Red]eTargetCivic[/COLOR]) != 0)
        if (GC.getCivicInfo([COLOR=Blue]eCivic[/COLOR]).getCivicAttitudeChange([COLOR=Red]eTargetCivic[/COLOR]) != 0)

        if (GC.getCivicInfo([COLOR=Red]eTargetCivic[/COLOR]).getCivicAttitudeChange([COLOR=Blue]eCivic[/COLOR]) != 0)
        if (GC.getCivicInfo([COLOR=Red]eTargetCivic[/COLOR]).getCivicAttitudeChange([COLOR=Blue]eCivic[/COLOR]) != 0)
In effect what you're doing is this:

Code:
if (x == 5)
    ...
if (x == 5)
    ...
I understand that the code you have in the ... differs between the two tests, but the tests themselves are what matter in this case since they are not passing. Having two failed tests is the same as having one or none or 517,274.

Oh, I see what you are saying... you're right, it could be merged into 2 if blocks instead of 4...

Your next block of code looks okay, though it suffers the same anti-logic as above. I see nothing that should cause a CTD. Do you get the CTD when you hover over the rival in the scoreboard? If not, then this code isn't to blame since it's called for that as well.

Yes, It CTD's when hovering over the scoreboard.

I hate to sound like a broken record, but my advice is the same: step though your code using the debugger to find what's happening. Staring at code only gets you so far. As well, if you were running the debugger on this, a CTD would instead drop you into the code that caused it.

I just compiled and run a debug build. You're right... (of course), what is happening is that it is comparing civicOPTION types against one another. So it works if I have someone with slaveyr hate someone with Free Market, but anything outside of that type isn't checked. (I need to run another loop...)

However, when I changed the code to look like this:

Code:
    CivicTypes eTargetCivic;
    CivicTypes eCivic;
    for (int iJ = 0; iJ < GC.getNumCivicOptionInfos(); iJ++)
    {
        eTargetCivic = GET_PLAYER(eTargetPlayer).getCivics((CivicOptionTypes)iJ);
        for (int iK = 0; iK < GC.getNumCivicOptionInfos(); iK++)
        {
            eCivic = GET_PLAYER(ePlayer).getCivics((CivicOptionTypes)iK);
            if (GC.getCivicInfo(eCivic).getCivicAttitudeChange(eTargetCivic) != 0)
            {
                szBuffer.append(NEWLINE);
                szBuffer.append(GC.getCivicInfo(eTargetCivic).getCivicAttitudeReason(eCivic));
                szBuffer.append(gDLL->getText("If you se this, the if1 check passed").GetCString());
            }
            if (GC.getCivicInfo(eTargetCivic).getCivicAttitudeChange(eCivic) != 0)
            {
                szBuffer.append(NEWLINE);
                szBuffer.append(GC.getCivicInfo(eCivic).getCivicAttitudeReason(eTargetCivic));
                szBuffer.append(gDLL->getText("If you se this, the if2 check passed").GetCString());
            }
        }
    }

I get a CTD when hovering over the scoreboard. A debug dll reveals that the reason it is CTD'ing is because it is WORKING, and trying to access the string, which it seems unable to do, and crashes, pointing right here:

Code:
CvString CvCivicInfo::getCivicAttitudeReason(int i) const
{
    FAssertMsg(i < GC.getNumCivicInfos(), "Index out of bounds");
    FAssertMsg(i > -1, "Index out of bounds");
 [COLOR=Red]   return m_pszCivicAttitudeReason[i];[/COLOR]
}

What exactly is the problem with this code?
 
That means m_pszCivicAttitudeReason is NULL--hasn't been created with "new". Gotta go validate your XML-parsing code and copying code. That's where the problem lies.
 
That means m_pszCivicAttitudeReason is NULL--hasn't been created with "new". Gotta go validate your XML-parsing code and copying code. That's where the problem lies.

Yep, stupid null pointer crashes... That was the issue. I now have everything working. Kinda. I still need some help formatting the text to look like green or red correctly, I changed it to this, but now I get two red (null) modifiers in the leaderhead box. It's probably a stupid error, since I'm tired...
Code:
CivicTypes eTargetCivic;
        CivicTypes eCivic;
        for (int iJ = 0; iJ < GC.getNumCivicOptionInfos(); iJ++)
        {
            eTargetCivic = GET_PLAYER(eTargetPlayer).getCivics((CivicOptionTypes)iJ);
            for (int iK = 0; iK < GC.getNumCivicOptionInfos(); iK++)
            {
                eCivic = GET_PLAYER(ePlayer).getCivics((CivicOptionTypes)iK);
                if (GC.getCivicInfo(eCivic).getCivicAttitudeChange(eTargetCivic) != 0)
                {
                    szBuffer.append(NEWLINE);
                    szTempBuffer.Format(SETCOLR L"%s" ENDCOLR, TEXT_COLOR((iAttitudeChange > 0) ? "COLOR_POSITIVE_TEXT" : "COLOR_NEGATIVE_TEXT"), gDLL->getText(GC.getCivicInfo(eCivic).getCivicAttitudeReason(eTargetCivic), iAttitudeChange));
                    szBuffer.append(szTempBuffer);
                }
            }
        }
 
You're not assigning the modifier to iAttitudeChange, but you're using it in the message.

Code:
eCivic = GET_PLAYER(ePlayer).getCivics((CivicOptionTypes)iK);
[B][COLOR="Red"]int iAttitudeChange = GC.getCivicInfo(eCivic).getCivicAttitudeChange(eTargetCivic)[/COLOR][/B]

if ([B][COLOR="Red"]iAttitudeChange[/COLOR][/B] != 0)
{
    ...
}
 
You're not assigning the modifier to iAttitudeChange, but you're using it in the message.

Code:
eCivic = GET_PLAYER(ePlayer).getCivics((CivicOptionTypes)iK);
[B][COLOR=Red]int iAttitudeChange = GC.getCivicInfo(eCivic).getCivicAttitudeChange(eTargetCivic)[/COLOR][/B]

if ([B][COLOR=Red]iAttitudeChange[/COLOR][/B] != 0)
{
    ...
}

Oops, forgot about that. Here's what it looks like now:

Code:
        if (iPass == 0)
        {
            CivicTypes eTargetCivic;
            CivicTypes eCivic;
            for (int iJ = 0; iJ < GC.getNumCivicOptionInfos(); iJ++)
            {
                eTargetCivic = GET_PLAYER(eTargetPlayer).getCivics((CivicOptionTypes)iJ);
                for (int iK = 0; iK < GC.getNumCivicOptionInfos(); iK++)
                {
                    eCivic = GET_PLAYER(ePlayer).getCivics((CivicOptionTypes)iK);
                    iAttitudeChange = GC.getCivicInfo(eCivic).getCivicAttitudeChange(eTargetCivic);
                    if (iAttitudeChange != 0)
                    {
                        szBuffer.append(NEWLINE);
                        szTempBuffer.Format(SETCOLR L"%s" ENDCOLR, TEXT_COLOR((iAttitudeChange > 0) ? "COLOR_POSITIVE_TEXT" : "COLOR_NEGATIVE_TEXT"), (GC.getCivicInfo(eCivic).getCivicAttitudeReason(eTargetCivic), iAttitudeChange));
                        szBuffer.append(szTempBuffer);
                    }
                }
            }
        }

But I'm still getting a CTD when hovering over the scoreboard.
 
Run a check to ensure that eCivic and eTargetCivic are each != -1 before you use them for any lookups, though I don't think it is possible to have no civic selected in any category, even if you are currently in anarchy.
 
Run it in the debugger.

It breaks in CvString.h, pointing here:

Code:
inline bool CvWString::formatv(std::wstring & out, const wchar * fmt, va_list args)
{
    wchar buf[2048];
    wchar * pbuf = buf;
    int len = 0;
    int attempts = 0;
    bool success = false;
    const int kMaxAttempts = 40;

    do
    {
        int maxlen = 2047+2048*attempts;
[COLOR=Red]        len = _vsnwprintf(pbuf,maxlen,fmt,args);[/COLOR]
        attempts++;
        success = (len>=0 && len<=maxlen);
        if (!success)
        {
            if (pbuf!=buf)
                delete [] pbuf;
            pbuf = new wchar[2048+2048*attempts];
        }
    }
    while (!success && attempts<kMaxAttempts);

    if ( attempts==kMaxAttempts )
    {
        // dxPrintNL( "CvString::formatv - Max reallocs occurred while formatting string. Result is likely truncated!", 0 );
    }

    if (success)
        out = pbuf;
    else
        out = L"";

    if (pbuf!=buf)
        delete [] pbuf;

    return success;
}
 
My guess is that the value coming from the reason array is NULL. Try assigning it to a temporary variable first and checking its value in the debugger:

Code:
[B][COLOR="Red"]wchar*[/COLOR][/B] szReason = GC.getCivicInfo(eCivic).getCivicAttitudeReason(eTargetCivic);

Use whatever type getCivicAttitudeReason returns in place of wchar* above. Then put a breakpoint on that line. When you get there, step into the function call and follow until you get back to that line. Then check the value of szReason.
 
My guess is that the value coming from the reason array is NULL. Try assigning it to a temporary variable first and checking its value in the debugger:

Code:
[B][COLOR=Red]wchar*[/COLOR][/B] szReason = GC.getCivicInfo(eCivic).getCivicAttitudeReason(eTargetCivic);
Use whatever type getCivicAttitudeReason returns in place of wchar* above. Then put a breakpoint on that line. When you get there, step into the function call and follow until you get back to that line. Then check the value of szReason.

I'm not sure why it's crashing, it is crashing before it even checks slavery against despotism.
I had it working before I was formatting the tempbuffer, but... The szReason is null when it crashes, but it's pointing back to this line again:

Code:
CvString CvCivicInfo::getCivicAttitudeReason(int i) const
{
    FAssertMsg(i < GC.getNumCivicInfos(), "Index out of bounds");
    FAssertMsg(i > -1, "Index out of bounds");
    [COLOR=Red]return m_pszCivicAttitudeReason[i];[/COLOR]
}

It shouldn't even be doing anything, it's checking civic 0 against civic 25 when it crashes, which has no attitude change at all. It's civic 10 and 11 that have it.
 
Back
Top Bottom