Adding a tech requirenment for the Mountains: Back to Service Modcomp.

And you're learning programming atm? -> Modding this Dll is probably the best practice you can have.
Yeah, I'm a freshman (Sophomore really, but that's a long story) at Central Michigan University. I believe my profile here at CFC says I'm 18, and a student, so put 2 and 2 together...

I plan on majoring in CS, and you can't believe how much Civ4 modding has helped. I had already learned all the datatypes, basic functions etc... So far, my classes have been a snap.
 
Okay, I'm compiling, and I get a strange error. Maybe I missed something...

CvPlot.cpp(4179) : error C2039: 'isCanPassPeaks' : is not a member of 'CvTeamAI'
 
BtW, in Python you can write a function, which can take different numbers of variables, so what EF wrote doesn't count for every language ;).

You can do that in C/C++ as well using the "..." operator, but it's a whole lot easier in Python. However, Python shares C++'s requirement that every parameter following one with a default must also have a default. Or maybe I misunderstood what you meant?

I just learned about overloading on Friday, so it's pretty new to me. + and - are pretty obvious examples of this, correct?

That's called operator overloading and is a special case of function overloading. As C++ is a typed language (you must specify the type of every variable), a function's signature is determined by the number and type of its parameters along with its name.

Code:
void max(int x, int y) { return x >= y ? x : y; }

and

Code:
void max(float x, float y) { return x >= y ? x : y; }

have different signatures. This isn't used much in the SDK, but it's very handy.

Okay, I'm compiling, and I get a strange error. Maybe I missed something...

Did you declare isCanPassPeaks() in CvTeam.h?
 
Did you declare isCanPassPeaks() in CvTeam.h?

Yep. I just checked, and even recompiled.

Just looking at things, and maybe it's because CvPlot doesn't import CvTeam normally...

Any other thoughts?
 
CvTeamAI is a subclass of CvTeam, and CvPlot is definitely calling isCanPassPeaks() on CvTeamAI (look at the compiler error), so this makes me think you need to rebuild.
 
CvTeamAI is a subclass of CvTeam, and CvPlot is definitely calling isCanPassPeaks() on CvTeamAI (look at the compiler error), so this makes me think you need to rebuild.

No, it's because I'm an idiot!

I forgot to capitalize the functions in the header, even after you warned me earlier that capitalization matters!
 
Don't worry about it. You'll continue making this mistake long into your software career because computers are very stupid when it comes to understanding intent, something us mere humans can do intuitively. With practice you'll do it less often, but I still get bitten by that to this day.

The best way to combat this is by picking a naming standard and sticking to it religiously. This is why I was harping on your before (it was you, wasn't it?) about naming a function getsomemultiwordvalue() in all lowercase. :mischief:
 
The best way to combat this is by picking a naming standard and sticking to it religiously. This is why I was harping on your before (it was you, wasn't it?) about naming a function getsomemultiwordvalue() in all lowercase. :mischief:

Yep. It was really bad too. populationthresholdmodifier i believe. :lol:
 
Okay, I've compiled it, but haven't made the changes to the other isimpassibles yet, so my peaks are just impassible always, for the moment. You mentioned that CvUnit would have some issues, could you elaborate?
 
I just picked the first example I saw where you must pass in a valid TeamTypes to get any value out of your change. Really, you should be leery of any call to isImpassable() that cannot pass in a valid team because Peaks are not always impassable, but isImpassable() will always return true without a valid team.
 
Forgive my ignorance, but when you say
I suppose you would ignore the tech thing for those cases, pass in NO_PLAYER, and return true.

What do you mean by pass in NO_PLAYER?
 
NO_TEAM, actually, which is the default value for eTeam in your modified isImpassable(), right?

If the function calling isImpassable() doesn't have a TeamTypes or PlayerTypes already, it cannot pass in a valid TeamTypes to isImpassable(). In that case, isImpassable() will get NO_TEAM (the default value) and return true because it cannot check a team to see if they know the tech that makes mountains passable.
 
NO_TEAM, actually, which is the default value for eTeam in your modified isImpassable(), right?

Yes...

If the function calling isImpassable() doesn't have a TeamTypes or PlayerTypes already, it cannot pass in a valid TeamTypes to isImpassable(). In that case, isImpassable() will get NO_TEAM (the default value) and return true because it cannot check a team to see if they know the tech that makes mountains passable.

Okay, I think I understand. If the function doesn't need me to specify a player, and it doesn't really matter, like functions in CvMapGenerator. I should be checking functions in CvUnit, and CvUnitAI and coding it so that the function finds the player, and passes that player through IsImpassible?
 
Exactly right.

Glad that I understand it, at least conceptually.

Lets check and see if I'm doing this right. Here is the original code:

Code:
bool CvUnit::canMoveInto(const CvPlot* pPlot, bool bAttack, bool bDeclareWar, bool bIgnoreLoad) const
{
    FAssertMsg(pPlot != NULL, "Plot is not assigned a valid value");

    if (atPlot(pPlot))
    {
        return false;
    }

    if (pPlot->isImpassable())
    {
        if (!canMoveImpassable())
        {
            return false;
        }
    }


And here is the new code:
Code:
bool CvUnit::canMoveInto(const CvPlot* pPlot, bool bAttack, bool bDeclareWar, bool bIgnoreLoad) const
{
    FAssertMsg(pPlot != NULL, "Plot is not assigned a valid value");

    if (atPlot(pPlot))
    {
        return false;
    }

    
    if (pPlot->isImpassable())
    {
      [B]  if (eTeam == NO_TEAM || !GET_TEAM(eTeam).isCanPassPeaks())[/B]
        {
            if (!canMoveImpassable())
            {
                return false;
            }
        }
    }

Or am I doing it incorrectly and really it should look like the spy code I just noticed...
Code:
	if (GC.getUSE_SPIES_NO_ENTER_BORDERS())
	{
		if (isSpy() && NO_PLAYER != pPlot->getOwnerINLINE())
		{
			[B]if (!GET_PLAYER(getOwnerINLINE()).canSpiesEnterBorders(pPlot->getOwnerINLINE()))[/B]
			{
				return false;
			}
		}
	}
 
The goal is to be able to pass a TeamTypes to isImpassable(). CyUnit has getTeam() to get the team that owns the unit.

Code:
    if (pPlot->isImpassable([B]getTeam()[/B]))
    {
        if (!canMoveImpassable())
        {
            return false;
        }
    }

When the team that owns the unit has the tech that allows peak passage, isImpassable() will detect this and return false for peaks.
 
Okay, I have this 90% working. I just have one problem. The CvGameTextMgr won't take the argument getTeam().
error C3861: 'getTeam': identifier not found, even with argument-dependent lookup

All I did was add it to two functions so that when you research the appropriate tech, the Impassible text went away.

Here's one of them.

Code:
void CvGameTextMgr::setTerrainHelp(CvWStringBuffer &szBuffer, TerrainTypes eTerrain, bool bCivilopediaText)
{...

if (pPlot->isImpassable([B]getTeam()[/B]))
		{
			szString.append(NEWLINE);
			szString.append(gDLL->getText("TXT_KEY_PLOT_IMPASSABLE"));
		}
...
}
 
Each function receives parameters and has access to global variables and functions. That is the only data on which it may operate or make decisions. Since this function is used to display hover text to the active player sitting at the computer, it makes sense to use the active team.

Code:
if (pPlot->isImpassable([B]GC.getGameINLINE().getActiveTeam()[/B]))
{
	szString.append(NEWLINE);
	szString.append(gDLL->getText("TXT_KEY_PLOT_IMPASSABLE"));
}

"getTeam()" works in CvUnit member functions because they can access CvUnit::getTeam() via the implied "this" pointer defined by every member function. A member function is a non-static function defined inside a "class <foo> { ... }" block. It must be called for a specific object of that class type.

Code:
if ([I]CvPlayerAI::getPlayer[/I]([I]CvGlobals::getInstance[/I]().[B]getGameINLINE[/B]().[B]getActivePlayer[/B]()).[B]isHuman[/B]())
    ...

The two italic functions CvPlayerAI::getPlayer() and CvGlobals::getInstace() are static functions. These are essentially global functions that you can call without an object. The three bold functions are member functions. CvGlobals::getInstance() returns the single CvGlobals object created by the game. Its getGameINLINE() function returns the current CvGame object whose getActivePlayer() function returns the active player ID tracked by the CvGame which is passed to CvPlayerAI::getPlayer() which returns a reference (like a pointer) to the CvPlayer object attached to the given ID. Finally, the reference is used to call its isHuman() member function.

To show the objects returned by each function, the above code could be rewritten verbosely as

Code:
CvGlobals& globals = [I]CvGlobals::getInstance[/I]();
CvGame& game = globals.[B]getGameINLINE[/B]();
PlayerTypes ePlayer = game.[B]getActivePlayer[/B]();
CvPlayer& player = [I]CvPlayerAI::getPlayer[/I](ePlayer);

if (player.[B]isHuman[/B]())
    ...

Inside every member function is an automatic local variable called "this" which is a pointer to the object that received the function call. You can use "this->" to reference any other member function or variable or omit it to let the compiler figure it out. In CvUnit::canMoveInto(), "getTeam()" becomes "this->getTeam()".

Since the CvGameTextMgr object (the game creates only one, but it could create any number of them just like CvPlayer and CvUnit) doesn't track any particular team or player, it doesn't define a getTeam() member function. This is why you need to come up with a team yourself, and the active team makes sense when it comes to hover text that will be displayed on-screen, always to the active player/team.
 
Okay thanks. It's working perfectly now. One last minor detail. I need my original function CanPassPeaks to show up in the civilopedia. However, I haven't the first clue to editing the CvGameTextMgr. Can you give me some pointers?
 
Insert a line into CvGameTextMgr::setTechHelp() wherever you want it to show up in the tech hover in relation to other things a tech can enable. The best way is to think of the tech that will enable peak passage, pick another benefit to the tech yours should come after, and place it there.

For example, say you want this to be enabled with Engineering and show up right after "+1 Road Movement".

Code:
//	Route movement change...
buildMoveString(szBuffer, eTech, true, bPlayerContext);

[B]//	Peak passability...
buildCanPassPeaksString(szBuffer, eTech, true, bPlayerContext);[/B]

//	Creates a free unit...
buildFreeUnitString(szBuffer, eTech, true, bPlayerContext);

Now add CvGameTextMgr::buildCanPassPeaksString(). I used buildWorkerRateString() as a base since it does what you want: add a single static message if the tech makes peaks passable.

Code:
void CvGameTextMgr::buildCanPassPeaksString(CvWStringBuffer &szBuffer, TechTypes eTech, bool bList, bool bPlayerContext)
{
	if (GC.getTechInfo(eTech).isCanPassPeaks() && (!bPlayerContext || !(GET_TEAM(GC.getGameINLINE().getActiveTeam()).isCanPassPeaks())))
	{
		if (bList)
		{
			szBuffer.append(NEWLINE);
		}
		szBuffer.append(gDLL->getText("TXT_KEY_CAN_PASS_PEAKS"));
	}
}

Finally, create the associated <TEXT> entry.

Code:
	<TEXT>
		<Tag>TXT_KEY_CAN_PASS_PEAKS</Tag>
		<English>[ICON_BULLET]Can move onto Peaks</English>
		<French>[ICON_BULLET]Can move onto Peaks</French>
		<German>[ICON_BULLET]Can move onto Peaks</German>
		<Italian>[ICON_BULLET]Can move onto Peaks</Italian>
		<Spanish>[ICON_BULLET]Can move onto Peaks</Spanish>
	</TEXT>
 
Back
Top Bottom