Modders Guide to FfH2

RIGHT, here's me hacking the SDK.

in CvUnit.cpp, took out all the work in the function at 10501-> so it looks like:
Code:
if (pLoopUnit != NULL)
	{

	// MARNOK
	// TEST
	 pLoopUnit->jumpToNearestValidPlot(); // can kill unit
	 }
Every unit in the plot, friend or foe, will be booted out.
This works as I expected.

So, there must be something wrong in the rest of it. Can I see if I have the logic right?

Check each unit in the plot our newunit is being moved to (loopunit).
If the loopunit is hostile* to newunit:
- If both units can co-exist@, no action.
- If newunit can capture+ loopunit, capture it.
- If loopunit can capture newunit, capture it. (I don't think this is in at present?)
- Anything else, boot it out of the plot (which may kill it).
If loopunit is not hostile to newunit:
- no action.

* units will be hostile if :
owners are at war; or
unit is always hostile; or
unit is HN and not owned by same player (not sure if this is in at present?)

@ units can co-exist if:
either is invisible to the other; or
either unit has special flag to allow it to coexists with enemy units (?)

+ unit can capture if:
target is a capturable type and potential capturer has the ability to capture; or
target is a piece of equipment, regardless of what potential capturer is.

Is that the whole of the logic? If I can understand that I can try to figure out why what I am trying to do does not work right.


EDIT:
doing more testing. Looks like the
if (!isInvisible(pLoopUnit->getTeam(), false))
line may be the one causing the problem. I'll test some more...

EDIT 2:
yep, tested with the invisibility check in, I get an unidentifable C++ error every time I create a hostile unit in the plot.

EDIT 3:
commented out the works for CvUnit::isInvisible and just made it return False, no error. I think the fault is in this function.

EDIT 4:

int iTemp;
iTemp = (plot()->isInvisibleVisible(eTeam, getInvisibleType()));

when I put these lines into isInvisible I get the error.
anyone got any idea why?
 
Your problem is that all of this checking for invisibility is happening BEFORE you update the visibility on the plot. So the barbarians can't see that tile yet and EVERYTHING is invisible to them (well, more accurately, nothing is visible).

Any check for visibility has to happen AFTER the line reading:
Code:
		pNewPlot->changeAdjacentSight(getTeam(), visibilityRange(), true, this, true); // needs to be here so that the square is considered visible when we move into it...

So either move that line up before this check, or move this check down after that line.
 
Your problem is that all of this checking for invisibility is happening BEFORE you update the visibility on the plot. So the barbarians can't see that tile yet and EVERYTHING is invisible to them (well, more accurately, nothing is visible).

Any check for visibility has to happen AFTER the line reading:
Code:
		pNewPlot->changeAdjacentSight(getTeam(), visibilityRange(), true, this, true); // needs to be here so that the square is considered visible when we move into it...

So either move that line up before this check, or move this check down after that line.

aha! thanks! That makes sense.
So if I revert to the original downloaded SDK, put that line at the top of CvUnit::setXY and recompile, it ought to work? I'll try that in a while.
 
First impulse is to say that updating visibility sooner shouldn't cause issues. But be sure to check each line of the code you are placing it in front of to be certain of that. Could be there is a good reason to have it come later. I am relatively certain that you won't have any issues placing the updatesight for the new plot before the update sight for the old plot, but that one might be an area where problems arise. (update sight OUGHT to just add 1 to the count of your visibility for all tiles in range, and to all invisible types the unit can see, but it might do more, I'm not checking atm, gotta get ready to head out for the day)
 
Well I suppose all I can do is test it and see, I'm surprised I'm the only one with this problem! I suppose now I'll have to distribute a dll with my modmod just to fix this one issue. If indeed I manage to fix it.
 
To avoid as many errors as possible, I would say that you ought to remember to encase the check in a (pNewPlot != NULL) statement, possibly even a (pOldPlot == NULL) since it will be fairly rare that the issue arises when that isn't the case.... Hrm... actually it'll happen almost all the time with Portals now being in the game...

Overall, I imagine this is something which Kael might wind up fixing when he gets to it. But if you find a definite method which clears the issue without making new ones it'd help.
 
Yes there's a handy one at 10470 I am hijacking for my test, which I shall carry out as soon as I shake off this odd compulsion to read the whole of tvtropes.
 
The call CyMessageControl().sendApplyEvent(5013, EventContextTypes.EVENTCONTEXT_ALL, (iPlayer,gc.getInfoTypeForString('TRAIT_AGGRESSIVE'),True)) giving the Illians their Aggresive trait from Letum Frigus is found in C:\Program Files\Firaxis Games\Sid Meier's Civilization 4\Beyond the Sword\Mods\Fall from Heaven 2\Assets\python\entrypoints\CvRandomEventInterface.py. It is under def doLetumFrigus3(argsList):, which is called by an event in C:\Program Files\Firaxis Games\Sid Meier's Civilization 4\Beyond the Sword\Mods\Fall from Heaven 2\Assets\XML\Events\CIV4EventInfos.xml after you select the write one of the options presented in C:\Program Files\Firaxis Games\Sid Meier's Civilization 4\Beyond the Sword\Mods\Fall from Heaven 2\Assets\XML\Events\CIV4EventTriggerInfos.xml, which is in this case triggered by a call in C:\Program Files\Firaxis Games\Sid Meier's Civilization 4\Beyond the Sword\Mods\Fall from Heaven 2\Assets\python\entrypoints\CvSpellInterface.py, which is triggered by the <PythonOnMove>onMoveLetumFrigus(pCaster, pPlot)</PythonOnMove> line in C:\Program Files\Firaxis Games\Sid Meier's Civilization 4\Beyond the Sword\Mods\Fall from Heaven 2\Assets\XML\Terrain\CIV4ImprovementInfos.xml

Simple really :p

It is also called more directly in CvSpellInterface.py in post combat calls for Basium and Hyborem, using False instead of True to remove the traits.

Thanks. I have it working.

I made a new trait called MINOR. I set it so only Minor leaders can gain new traits. I set Charismatic to start on move for the Seven Pines.

I also learned the Latum Illians Aggressive add is for only humans. I made mine for AI as well.

Only problem is, the AI seems to avoid stepping on it. I can trick them into it with a warrior, but they just kind of go around it. Need to fix that.

But rock! my first thing! Next, how to add traits for other weird contexts!

Cast your world spell on turn 1, get Foolish!
Get 2 Million population, Get Creative!
Found the first religion, Get Spirtual!
 
Yes there's a handy one at 10470 I am hijacking for my test, which I shall carry out as soon as I shake off this odd compulsion to read the whole of tvtropes.

That didn't work. What I did instead:
Code:
if (pLoopUnit != NULL)
{
	if ( ( pLoopUnit->isHiddenNationality() || isHiddenNationality() ) || (isEnemy(pLoopUnit->getTeam(), pNewPlot) || pLoopUnit->isEnemy(getTeam())) )
	{
		if (pLoopUnit->canCoexistWithEnemyUnit(getTeam()))
		{
			// PLACEHOLDER for coexisting units; probably never need to do anything
		}
		else
		{
			if ( GC.getUnitInfo((UnitTypes)pLoopUnit->getUnitType()).getEquipmentPromotion() == NO_PROMOTION || (NO_UNITCLASS == pLoopUnit->getUnitInfo().getUnitCaptureClassType() && pLoopUnit->canDefend(pNewPlot)))
			{
				// Not a capturable unit type, and an enemy or HN, and not invisible, so move it
				pLoopUnit->jumpToNearestValidPlot(); // can kill unit
			}
			else
			{
				// loopunit is possibly capturable
				if (isNoCapture() || GC.getUnitInfo((UnitTypes)pLoopUnit->getUnitType()).getEquipmentPromotion() == NO_PROMOTION)
				{
						// new unit cannot capture pLoopUnit, which is capturable.
						// Kick pLoopUnit out.
						pLoopUnit->jumpToNearestValidPlot(); // can kill unit
				}
				else
				{
					// CAN capture a capturable unit!
					 pLoopUnit->setCapturingPlayer(getOwnerINLINE());
				}

			}
		}
	}
}
Based on the theory that the canCoexistWithEnemyUnit check handles invisibility without erroring on me, so there's no need for an additional invsibility check. Thing is it seems to handle it only one way - an invisible unit can appear in the plot and not force anything else out, but a unit will force out invisible units. So maybe I need to alter canCoexistWithEnemyUnit.
Also I need to put in a check in the hidden nationality bit; if the units belong to the same player(or is it the same team?) then HN won't count.
 
I was just looking into allowing you to summon the other Demon Lords from the Lord of the Balors Scenario as leaders of other Infernal civs in the main game (probably making Infernal Pact no longer summon anyone, but instead allow a repeatable ritual to bring in a random demon lord). I'm pretty sure I know how to do everything I would need expect blocking the same leader from being assigned multiple times. Looking in FF I found that I could use CyGame().isCivEverActive(gc.getInfoTypeForString('CIVILIZATION_INFERNAL')) to check if the civ had ever been in the game. Is there a similar call I could use to check if individual leaders had shown up yet?

Edit: I just looked in the Python API a second time, and noticed that I had overlooked the fairly obvious bool isLeaderEverActive (LeaderHeadType eLeader) call. I guess I don't need any help after all.
 
I'm looking for a part of code to be used in my mod, i have only one question: Am i right, that no sdk-changes are needed, to get the spawning of civilizations (like Hyborem) work in normal BtS?

Would be nice, if i get the "blessing" to use the code (i've already seen the necessary parts) :).
 
I'm looking for a part of code to be used in my mod, i have only one question: Am i right, that no sdk-changes are needed, to get the spawning of civilizations (like Hyborem) work in normal BtS?

Would be nice, if i get the "blessing" to use the code (i've already seen the necessary parts) :).

No, I needed significant SDK modifications to do that.

But to your 2nd question you are welcome to use anything in the FfH code that helps you and your project. Have fun and make great stuff!
 
I have 2 trait criteria complete. making 8 cities (oncity, check, run event) and stepping on a unique terrain.

One criteria I want to do is Number of wonders, or number of razed cities. Is there any sort of counting mech on a leader? Number of wonders I might be able to do if there's an array of wonders built by a leader, or I could check the leader for wonders. Razed seems like I'd have to have a counter.

Any ideas?
 
No, I needed significant SDK modifications to do that.

Damn :(.
What about the appearance of Basium?
Haven't looked at it (because it doesn't fit that good to what i want to do), is this a "rape" of the colony-function, or also a totally new function?

But to your 2nd question you are welcome to use anything in the FfH code that helps you and your project. Have fun and make great stuff!

Thank you :).

Fun...not with python ;).

Might not want to consider it a "blessing" :lol:

:D
 
Would it be possible to remove the Defensive Pact/Common war requirement from AI's considering Permanent alliances? If so, how?

Also, would it be possible to make the AI consider the actual numerical opinion towards you instead of the "Friendly"/"pleased"/"ambivalent"/etc?

I find the waiting for this really annoying. I'd rather it require overwhelmingly positive relations with you.
 
CvTeamAI::AI_permanentAllianceTrade
Change or remove "if ((AI_getDefensivePactCounter(eTeam) + AI_getShareWarCounter(eTeam)) < 40)".

For numerical value call CvPlayerAI::AI_getAttitudeVal.
 
Is there a call to determine how many wonders a player has, or will I have to check each wonder and increment?

I see you can get all wonders available from a city. But I don't see from a player.

Thanks.
 
Regarding my earlier problem.
I *think* it was because, a unit which has just been spawned in the plot, calls setXY with plot() being NULL for it. So in the CvUnit::isInvisible and, I think especially, the CvUnit::getInvisibleType() bits (which I think was changed in the patch where I forst noticed the c++ error), all the checks based on plot() were not working right.

To be honest I've made lots of changes to try and understand and make this work, so I can't be 100% which of the changes was truly necessary. It seems to be working for me now - tried with both invisible and visible units exploring and spawning both invisible and visible foes, seems to work as I would expect without C++ errors.

My main change was in setXY, to force the unit into the plot before doing anything else.
Code:
if (pNewPlot != NULL)
	{
	    // MARNOK
	    if (plot() == NULL)
            {
               m_iX = iX;
               m_iY = iY;
            }

I will test this out and make sure it works. Feeling a bit better - I can get on with the actual modmodding I wanted to do, which was all python and xml!
 
Seems like that might work fairly well, since the function carries a pointer to the old plot directly and I don't recall it asking for plot() personally anywhere. But it could cause issues with some of the other checks which are performed before the unit is properly moved to a new plot.



I had tried moving the 2 plot visibility changes (both old & new) up to the front of the function, wound up with a lovely crash from that. So instead I just nested the invisibility check in visibility updates for the new plot (I activate the unit's visibility on the new plot, do the invis check, then deactivate the visibility once again, leaving it inactive until the normal location for updating it)
 
Back
Top Bottom