Missionary XP's

stolenrays

Deity
Joined
Aug 2, 2009
Messages
2,061
I'd like to make it so that Missionaries gain XP after spreading their religion. I'm still learning SDK, so I'd appreciate any suggestions. I figure I'd have to add some info in the CvCity.cpp file and then any relevant corresponding .cpp/.h files. I've been messing around with it any used super spies as an example, but I really am unsure of how to do it.

CvCity.cpp Code:
Spoiler :
Code:
void CvCity::setHasReligion(ReligionTypes eIndex, bool bNewValue, bool bAnnounce, bool bArrows)
{
	
	FAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	FAssertMsg(eIndex < GC.getNumReligionInfos(), "eIndex expected to be < GC.getNumReligionInfos()");
	PlayerTypes eTargetPlayer = plot()->getOwnerINLINE();

	if (isHasReligion(eIndex) != bNewValue)
	{
		for (int iVoteSource = 0; iVoteSource < GC.getNumVoteSourceInfos(); ++iVoteSource)
		{
			processVoteSourceBonus((VoteSourceTypes)iVoteSource, false);
		}

		m_pabHasReligion[eIndex] = bNewValue;

		for (int iVoteSource = 0; iVoteSource < GC.getNumVoteSourceInfos(); ++iVoteSource)
		{
			processVoteSourceBonus((VoteSourceTypes)iVoteSource, true);
		}

		GET_PLAYER(getOwnerINLINE()).changeHasReligionCount(eIndex, ((isHasReligion(eIndex)) ? 1 : -1));

		updateMaintenance();
		updateReligionHappiness();
		updateReligionCommerce();

		AI_setAssignWorkDirty(true);

		setInfoDirty(true);

		if (isHasReligion(eIndex))
		{
			GC.getGameINLINE().makeReligionFounded(eIndex, getOwnerINLINE());

			if (bAnnounce)
			{
				if (GC.getGameINLINE().getHolyCity(eIndex) != this)
				{
					for (int iI = 0; iI < MAX_PLAYERS; iI++)
					{
						if (GET_PLAYER((PlayerTypes)iI).isAlive())
						{
							if (isRevealed(GET_PLAYER((PlayerTypes)iI).getTeam(), false))
							{
								if ((getOwnerINLINE() == iI) || (GET_PLAYER((PlayerTypes)iI).getStateReligion() == eIndex) || GET_PLAYER((PlayerTypes)iI).hasHolyCity(eIndex))
								{
									CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_RELIGION_SPREAD", GC.getReligionInfo(eIndex).getTextKeyWide(), getNameKey());
									gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)iI), false, GC.getDefineINT("EVENT_MESSAGE_TIME_LONG"), szBuffer, GC.getReligionInfo(eIndex).getSound(), MESSAGE_TYPE_MAJOR_EVENT, GC.getReligionInfo(eIndex).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), getX_INLINE(), getY_INLINE(), bArrows, bArrows);
								}
								//TSHEEP Give spies xp for successful missions
								awardMissionaryExperience(GET_PLAYER(eTargetPlayer).getTeam(),GC.getReligionInfo(eIndex));
								//TSHEEP end
							}
 
I dont have the code open and its late (my time), but I would suspect you should look in unit.cpp and unitai.cpp instead of the city files. There should be a spreadreligion function or something along those lines.
 
Here's what I found in CvUnit.cpp:

I think that the following code just allows the spread religion mission to be available.
Code:
bool CvUnit::canSpread(const CvPlot* pPlot, ReligionTypes eReligion, bool bTestVisible) const
{
	CvCity* pCity;

	if (GC.getUSE_USE_CANNOT_SPREAD_RELIGION_CALLBACK())
	{
		CyArgsList argsList;
		argsList.add(getOwnerINLINE());
		argsList.add(getID());
		argsList.add((int) eReligion);
		argsList.add(pPlot->getX());
		argsList.add(pPlot->getY());
		long lResult=0;
		gDLL->getPythonIFace()->callFunction(PYGameModule, "cannotSpreadReligion", argsList.makeFunctionArgs(), &lResult);
		if (lResult > 0)
		{
			return false;
		}
	}

	if (eReligion == NO_RELIGION)
	{
		return false;
	}

	if (m_pUnitInfo->getReligionSpreads(eReligion) <= 0)
	{
		return false;
	}

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (pCity->isHasReligion(eReligion))
	{
		return false;
	}

	if (!canEnterArea(pPlot->getTeam(), pPlot->area()))
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (pCity->getTeam() != getTeam())
		{
			if (GET_PLAYER(pCity->getOwnerINLINE()).isNoNonStateReligionSpread())
			{
				if (eReligion != GET_PLAYER(pCity->getOwnerINLINE()).getStateReligion())
				{
					return false;
				}
			}
		}
	}

	return true;
}

This other code block I believe helps spread religion as well. I searched all files and only found the TXT_MISC_RELIGION_SPREAD in any other files except CvCity.cpp so I assumed that was the file to mod.

Code:
bool CvUnit::spread(ReligionTypes eReligion)
{
	CvCity* pCity;
	CvWString szBuffer;
	int iSpreadProb;

	if (!canSpread(plot(), eReligion))
	{
		return false;
	}

	pCity = plot()->getPlotCity();

	if (pCity != NULL)
	{
		iSpreadProb = m_pUnitInfo->getReligionSpreads(eReligion);

		if (pCity->getTeam() != getTeam())
		{
			iSpreadProb /= 2;
		}

		bool bSuccess;

		iSpreadProb += (((GC.getNumReligionInfos() - pCity->getReligionCount()) * (100 - iSpreadProb)) / GC.getNumReligionInfos());

		if (GC.getGameINLINE().getSorenRandNum(100, "Unit Spread Religion") < iSpreadProb)
		{
			pCity->setHasReligion(eReligion, true, true, false);
			bSuccess = true;
		}
		else
		{
			szBuffer = gDLL->getText("TXT_KEY_MISC_RELIGION_FAILED_TO_SPREAD", getNameKey(), GC.getReligionInfo(eReligion).getChar(), pCity->getNameKey());
			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_NOSPREAD", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pCity->getX_INLINE(), pCity->getY_INLINE());
			bSuccess = false;
		}

		// Python Event
		CvEventReporter::getInstance().unitSpreadReligionAttempt(this, eReligion, bSuccess);
	}

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_SPREAD);
	}

	kill(true);

	return true;
}
 
bool CvUnit::spread is what you want. If you look down near the end you'll see the kill(true); statement. I assume you'll want to comment that out, since giving XP to a dead unit is kind of useless. In it's place you'll want to put your code for giving experience. It could be as simple as changeExperience(x); where x is the amount of experience you want to give the unit.

Edit: Actually, you'll want to put the experience gain under the bSuccess = true; statement so that they only gain experience for a successful spread.
 
Good idea, really.

CvUnit::canSpread checks if the unit is able to spread, i.e. whether to show the spread button or allow the AI do launch it - so ignore it.

CvUnit::spread is the actual action and you should be able to do all the modding there.

I'd just remove the kill(true); part and replace it with:
Code:
if (bSuccess) 
{
	changeExperience(1);
	CvCity* pCapital = GET_PLAYER(getOwnerINLINE()).getCapitalCity();
	if (NULL != pCapital)
	{
		setXY(pCapital->getX_INLINE(), pCapital->getY_INLINE(), false, false, false);
	}
}
else
{
	kill(true);
}

You can spice it up with info messages & sounds from CvUnit::espionage. Addtionally, if you want missionaries to gain promotions, you have to give them a new combat type, like in SuperSpies. I'd also recommend ALN BetterSpyEscape modmod (I found it in DuneWars) which is great for SuperSpies and could be also used for Missionaries. Basically it makes the spies escape to one of three nearest cities, rather than to the capital.
 
awesome help people. They now receive XP for spreading their religion. the If bSuccess statement needs to be initialized so I will do that migration to the captial function a little later. I'll check out Dune Wars too.

I figure I'll add some new religion spread promotions to the units as well.
 
You can just move the initialization out of the if clause and make it false by default, i.e. bool bSuccess = false;
 
Thanks, I also figured out how to make workers gain XP as well after they build improvements with just iChangeExperience(1). Should be just as easy for executives. Now I'm adding a religionspreadspercent tag to promotions to give them a reason to amass XP's.

BTW, is BetterSpyEscape modmod the search string for the C++ or is the modmod a standalone/download?
 
Well,I added promotion tags for workratemodify and religionspreadspercent. The workratemodify changes the work rate successfully. I'm just not sure how to check if the religionspreads promotion is working though.

Also, worker gain experience after every turn they are building! I think I put my code snippit in the wrong place?

Code:
bool CvUnit::build(BuildTypes eBuild)
{
	bool bFinished;

	FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");


	if (!canBuild(plot(), eBuild))
	{
		return false;
	}

	// Note: notify entity must come before changeBuildProgress - because once the unit is done building,
	// that function will notify the entity to stop building.
	NotifyEntity((MissionTypes)GC.getBuildInfo(eBuild).getMissionType());

	GET_PLAYER(getOwnerINLINE()).changeGold(-(GET_PLAYER(getOwnerINLINE()).getBuildCost(plot(), eBuild)));

	bFinished = plot()->changeBuildProgress(eBuild, workRate(false), getTeam());

	finishMoves(); // needs to be at bottom because movesLeft() can affect workRate()...

	if (bFinished)

	{
		if (GC.getBuildInfo(eBuild).isKill())
		{
			kill(true);
		}
	}
/************************************/
/*           Unit Experience Mod    */
/************************************/
	changeExperience(1);
/************************************/
/*           Unit Experience Mod    */
/************************************/
	// Python Event
	CvEventReporter::getInstance().unitBuildImprovement(this, eBuild, bFinished);

	return bFinished;
}

What I'm gonna do is release this Modcomponent with XP/Promotions for Missionaries, Workers, and Execs.
 
Here is what I added to the missionary/executive missions. They gain one experience for spreading, lose all movement points, and return back to the capital upon success. However, the missionary does his little victory prayer at the capital now.

Code:
bool CvUnit::spread(ReligionTypes eReligion)
{
	CvCity* pCity;
	CvWString szBuffer;
	int iSpreadProb;

	if (!canSpread(plot(), eReligion))
	{
		return false;
	}

	pCity = plot()->getPlotCity();

	if (pCity != NULL)
	{
		iSpreadProb = m_pUnitInfo->getReligionSpreads(eReligion);

		if (pCity->getTeam() != getTeam())
		{
			iSpreadProb /= 2;
		}
/***************************************/
/*          Unit Experience Mod  START */
/***************************************/
		bool bSuccess = false;

		iSpreadProb += (((GC.getNumReligionInfos() - pCity->getReligionCount()) * (100 - iSpreadProb)) / GC.getNumReligionInfos());

		if (GC.getGameINLINE().getSorenRandNum(100, "Unit Spread Religion") < iSpreadProb)
		{
			pCity->setHasReligion(eReligion, true, true, false);
			changeExperience(1);
			finishMoves();
			CvCity* pCapital = GET_PLAYER(getOwnerINLINE()).getCapitalCity();
			if (NULL != pCapital)
			{
				setXY(pCapital->getX_INLINE(), pCapital->getY_INLINE(), false, false, false);
			}
/***************************************/
/*          Unit Experience Mod   END  */
/***************************************/
		}
		else
		{
			szBuffer = gDLL->getText("TXT_KEY_MISC_RELIGION_FAILED_TO_SPREAD", getNameKey(), GC.getReligionInfo(eReligion).getChar(), pCity->getNameKey());
			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_NOSPREAD", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pCity->getX_INLINE(), pCity->getY_INLINE());
			bSuccess = false;
			kill(true);
		}

		// Python Event
		CvEventReporter::getInstance().unitSpreadReligionAttempt(this, eReligion, bSuccess);
	}

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_SPREAD);
	}
/***************************************/
/*          Unit Experience Mod  START */
/***************************************/
    //kill(true);
/***************************************/
/*          Unit Experience Mod   END  */
/***************************************/
	return true;
}

I still don't don't know how to tell if my new missionary/exec promotions increase the spread?
 
Top Bottom