Mod-Modders Guide to Fall Further

Orcs spawn in groups, not sure if they collate themselves outside of the spawning though, or if they still do individual considerations and/or split the groups set upon spawning.

yeah, I just checked it, those barbs seem fine. Demons on larger maps are probably a bigger issue unless they merge. I sometimes see AI players with lots of 2 size groups, don't know yet what is going on there. In the last game, one of the AI had 600 units in over 300 selectiongroups.
 
I don't track my changes. But I do have a constant backup in the SVN repository since I have to merge from my copy into that copy to upload to the rest of the team, and THAT maintains a backup of all versions, so technically I can revert to lots of previous points. But I try to only submit things which are stable, and undoing stable code is a massive headache because then you assume something you wrote exists, and it doesn't, and problems happen. Occasionally it'd be nice to have more frequent backups of my work while I am doing big projects like the Barbarians and am not stable for a VERY long time, but typically then I just zip my files at "milestone" points.


Sephi: I know there is a function to request units to form groups in CvUnitAI. For the most part this is only used by the Settlers though. I have occasionally seen Stack of Death logic, but I don't think it triggers very often or properly with the modifications FfH has made to how units interact and possibly the dagger work as well later on. I haven't looked at the SoD logic at all, might be a good place to start. Alternatively you can have a check early in CvUnitAI::AI_update or whatever it is that all units pass through at the start of the turn which tests how many units the player has compared to how many groups and attempts to keep that ratio at a reasonable number if possible. If the ratio is violated, then have it do the grouping code as the first step in their AI instead of almost the last step. It could potentially work well.
 
there is AI_group and groupmerge or something. I think SOD is just a flag that allows bigger groups and probably removes a few other checks for UNITAI, etc.
 
Hm, I get these errors when trying to compile (for Orbis, remember):
||=== CvGameCoreDLL, Final Release ===|
CvGameTextMgr.cpp|4079|warning C4101: 'iAbsHappiness' : unreferenced local variable|
CvPlayer.obj||error LNK2019: unresolved external symbol "public: void __thiscall CvPlayer::setLeaderAttitudeChange(enum LeaderHeadTypes,int)" (?setLeaderAttitudeChange@CvPlayer@@QAEXW4LeaderHeadTypes@@H@Z) referenced in function "public: void __thiscall CvPlayer::init(enum PlayerTypes)" (?init@CvPlayer@@QAEXW4PlayerTypes@@@Z)|
Final Release\CvGameCoreDLL.dll||fatal error LNK1120: 1 unresolved externals|
||=== Build finished: 2 errors, 1 warnings ===|
I know what the problem with the warning is but I don't understand the 2 errors :confused:

Edit: Resolved. I missed some line in WinMerge... Can't see the yellow in a sea of grey :lol:
 
However, something else appeared. I added a new tag, HatedCivic, which works like FavoriteCivic, with a divisor and all. Problem: it seems that it is no longer considered when the leader which give the malus change its civics. Example:

I made it so Sabathiel hates Despotism (this is for debugging!) and gives it -2, max. -4 with a divisor of -5. Classical start, I have Despotism, so he gives me a penalty of -2. Note that, for now, he also has Despotism. Then, he switches to God King and I don't leave Despotism... the malus is gone.

I may understand incorrectly my code... What should I change in order to solve this issue?
Code:
int CvPlayerAI::AI_getHatedCivicAttitude(PlayerTypes ePlayer)
{
	int iAttitudeChange;

	int iAttitude;

	iAttitude = 0;

	if (GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivic() != NO_CIVIC)
	{
		if (isCivic((CivicTypes)(GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivic())) && GET_PLAYER(ePlayer).isCivic((CivicTypes)(GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivic())))
		{
			iAttitude += GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivicAttitudeChange();

			if (GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivicAttitudeDivisor() != 0)
			{
				iAttitudeChange = (AI_getHatedCivicCounter(ePlayer) / GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivicAttitudeDivisor());
				iAttitude += range(iAttitudeChange, -(abs(GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivicAttitudeChangeLimit())), abs(GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivicAttitudeChangeLimit()));
			}
		}
	}

	return iAttitude;
}
I guess it's the isCivic part of the second if. I thought it was only checking if the value of HatedCivic is actually a civic...
 
isCivic doesn't refer to anything else (ie - something(DOT)isCivic), so it is calling within CvPlayer. So you are asking this leader if he "isCivic(Despotism)"

If it was checking that the civic exists, you would be checking get____Infos.(something)


So what isCivic does is it finds out if that player is following that civic. So as it is written here, you only get the penalty when you AND the other leader follow that civic (which made sense for Favorite, but not for Hated. In this case you would want a NOT isCivic check for yourself, and a normal isCivic check for the other player, then you give the penalty if they use the civic, unless you yourself also use it)
 
Alternatively you can have a check early in CvUnitAI::AI_update or whatever it is that all units pass through at the start of the turn which tests how many units the player has compared to how many groups and attempts to keep that ratio at a reasonable number if possible. If the ratio is violated, then have it do the grouping code as the first step in their AI instead of almost the last step. It could potentially work well.

CvUnitAI::AI_update runs only for the headunits of selectionsgroups. I have added a flag for groups now and wrote a new grouping function that checks for the groupflag rather than UNITAI. The groups will also use their own move function instead of using the move function of the grouphead UNITAI. In theory once this is finished it should be pretty easy to set up a HIDDEN NATIONALITY type of group for the AI.
 
Huh. I start a game, it's autosaved. I try to load the autosave, it says "failed to uncompress game data" and crashes. What change I made could cause a save to autobreak during the game??

(Of course, you don't know what change I made but you could have an idea...)

I messed with those files:
Spoiler :
CvEnums.h
CvGameTextMgr.cpp
CvGlobals.cpp
CvGlobals.h
CvInfos.cpp
CvInfos.h
CvPlayer.cpp
CvPlayer.h
CvPlayerAI.cpp
CvPlayerAI.h
CvTeamAI.cpp
CvXMLLoadUtilitySet.cpp
CyEnumsInterface.cpp
CyGlobalContext.cpp
CyGlobalContext.h
CyGlobalContextInterface4.cpp
CyInfoInterface3.cpp

Looking at those name and thinking "failed loading" makes me guess it's from CvXMLLoadUtilitySet...
 
Yeah, I figured that out after a bit of research... I have one bit of code which is Write and that doesn't have its Read counterpart. However, it's imported from another mod... which doesn't have the Read counterpart. Anyway, I tried to create it but failed...

Write part:
Code:
    pStream->Write(aLeaderAttitudeChange.size());
	for (std::map<LeaderHeadTypes, int>::iterator it = aLeaderAttitudeChange.begin(); it != aLeaderAttitudeChange.end(); ++it)
	{
		pStream->Write(it->first);
		pStream->Write(it->second);
	}

Read part I created:
Code:
    pStream->Read(aLeaderAttitudeChange.size());
	for (std::map<LeaderHeadTypes, int>::iterator it = aLeaderAttitudeChange.begin(); it != aLeaderAttitudeChange.end(); ++it)
	{
		pStream->Read(it->first);
		pStream->Read(it->second);
	}

The error I got:
CvPlayer.cpp
CvPlayer.cpp(17732) : error C2664: 'void FDataStreamBase::Read(char *)' : cannot convert parameter 1 from 'std::_Tree<_Traits>::size_type' to 'char *'
with
[
_Traits=std::_Tmap_traits<LeaderHeadTypes,int,std::less<LeaderHeadTypes>,std::allocator<std::pair<const LeaderHeadTypes,int>>,false>
]
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
CvPlayer.cpp(17735) : error C2664: 'void FDataStreamBase::Read(char *)' : cannot convert parameter 1 from 'const LeaderHeadTypes' to 'char *'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
CvPlayer.cpp(17736) : error C2664: 'void FDataStreamBase::Read(char *)' : cannot convert parameter 1 from 'int' to 'char *'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
Process terminated with status 2 (0 minutes, 6 seconds)
3 errors, 0 warnings
 
Huh. Found it. I'm ashamed. I will go hide myself :blush:
Spoiler :
Overlooked some code when searching with PRGRep...
 
Yeah I didn't get on fast enough to say it, but that message almost ALWAYS means that your ::read(stream) and ::write don't match properly. And itterators work best when they already exist, so they are a bit tricky to reverse engineer how to write them (as in, that Read bit you missed sure was different, wasn't it? :))


Just as a heads up on my own progress toward making 051 a mod-modder's paradise, I have a few XML files with new fields I still have to write default statements for:

CvBuildingInfo
CvCivilizationInfo
CvHandicapInfo
CvGoodyInfo
CvImprovementInfo
CvBonusInfo
CvFeatureInfo
CvTerrainInfo
CvLeaderHeadInfo
CvProjectInfo
CvReligionInfo
CvTraitInfo
CvStateNameInfo


Once those are done, I JUST have to figure out why it is currently an instant crash upon attempting to load a savegame and I can start writing code for the toys that the rest of the team wanted to play with for this next release.
 
Yeah I didn't get on fast enough to say it, but that message almost ALWAYS means that your ::read(stream) and ::write don't match properly. And itterators work best when they already exist, so they are a bit tricky to reverse engineer how to write them (as in, that Read bit you missed sure was different, wasn't it? :))
Yes, it was terribly different. Nothing I could have done myself, given my current skills :lol:

Just as a heads up on my own progress toward making 051 a mod-modder's paradise, I have a few XML files with new fields I still have to write default statements for:

CvBuildingInfo
CvCivilizationInfo
CvHandicapInfo
CvGoodyInfo
CvImprovementInfo
CvBonusInfo
CvFeatureInfo
CvTerrainInfo
CvLeaderHeadInfo
CvProjectInfo
CvReligionInfo
CvTraitInfo
CvStateNameInfo


Once those are done, I JUST have to figure out why it is currently an instant crash upon attempting to load a savegame and I can start writing code for the toys that the rest of the team wanted to play with for this next release.
Interesting :) That reminds that I've got to import the StateNames in my mod... What new tags are you planning for it? If you want to tell, of course... :p
 
I'm not even doing new tags right now, I have to re-write some things for the tags already created outside of BtS. Mind-numbingly boring work, lots of tedium. I'll be glad when it is through, but if I can't solve the crash I might have to go through and undo all of it :(


No clue on when next release will wind up being at this point. Need to circumvent the crash or nobody will be too happy to get their hands on it at all (well, those people who always do a full game in a single sitting might, but none of the others)
 
However, something else appeared. I added a new tag, HatedCivic, which works like FavoriteCivic, with a divisor and all. Problem: it seems that it is no longer considered when the leader which give the malus change its civics. Example:

I made it so Sabathiel hates Despotism (this is for debugging!) and gives it -2, max. -4 with a divisor of -5. Classical start, I have Despotism, so he gives me a penalty of -2. Note that, for now, he also has Despotism. Then, he switches to God King and I don't leave Despotism... the malus is gone.

I may understand incorrectly my code... What should I change in order to solve this issue?
Code:
int CvPlayerAI::AI_getHatedCivicAttitude(PlayerTypes ePlayer)
{
	int iAttitudeChange;

	int iAttitude;

	iAttitude = 0;

	if (GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivic() != NO_CIVIC)
	{
		if (isCivic((CivicTypes)(GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivic())) && GET_PLAYER(ePlayer).isCivic((CivicTypes)(GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivic())))
		{
			iAttitude += GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivicAttitudeChange();

			if (GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivicAttitudeDivisor() != 0)
			{
				iAttitudeChange = (AI_getHatedCivicCounter(ePlayer) / GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivicAttitudeDivisor());
				iAttitude += range(iAttitudeChange, -(abs(GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivicAttitudeChangeLimit())), abs(GC.getLeaderHeadInfo(getPersonalityType()).getHatedCivicAttitudeChangeLimit()));
			}
		}
	}

	return iAttitude;
}
I guess it's the isCivic part of the second if. I thought it was only checking if the value of HatedCivic is actually a civic...


Oh I love it when you speak Hatecode. How about including HateCivic (such as Slavery)? Ooh yeah I got your mutations handy in about a week or so...oh yeah
 
Something in AI_retreattoCity seems broken for workers.

I Added this to CvUnitAI::AI_workermove() to make workers retreat

Code:
/*********************************************************************/
/** BETTER UNITAI Sephi ERAMOD **/

	bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 1) > 0);
	if (bDanger)
	{
        CvCity* pLoopCity;
        int iPathTurns;
        int iBestValue=100;
        int iLoop;
        int iValue;
        CvPlot* pBestPlot=NULL;
		for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
		{
			if (AI_plotValid(pLoopCity->plot()))
			{
				if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
				{
/*********************************************************************/
/** SPEED TWEAK Sephi ERAMOD **/
/** We only check for cities not that far away **/
                    int XDist=pLoopCity->plot()->getX_INLINE() - plot()->getX_INLINE();
                    int YDist=pLoopCity->plot()->getY_INLINE() - plot()->getY_INLINE();
                    if (((XDist*XDist)+(YDist*YDist))<100 || (GC.getDefineINT("USE_ERAMOD_SPEED_TWEAK")==0))
                    {
                        if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), MOVE_SAFE_TERRITORY, true, &iPathTurns))
                        {
                            iValue = iPathTurns;
                            if (iValue < iBestValue)
                            {
                                iBestValue = iValue;
                                pBestPlot = getPathEndTurnPlot();
                                FAssert(!atPlot(pBestPlot));
                            }
                        }
                    }

/** SPEED TWEAK End **/
/*********************************************************************/
				}
			}
		}
		if (pBestPlot!=NULL)
		{
            getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY);
            return;
		}
	}
/** BETTER UNITAI End **/
/*********************************************************************/
 
Back
Top Bottom