Mod-Modders Guide to Fall Further

Aye, a loop over BuildingInfo to find an AlignmentShift, then a check for that building against the player. Assuming that the player can also respond to a query of buildingtype, and not just buildingclass. If it can only do class, just add a tracker in CvPlayer for CvPlayer::getNetBuildingAlignmentShift() or something.
 
player can only respond to buildingclass, but you can easily get the buildingclass by using GC.getBuildingInfo(whateverbuilding).getBuildingClassType()
 
the difference for Assimiliation will probably average to zero. But I just saw that FFH added a CvPlayer::getNumBuilding for cases like this.
 
Alright. I wrote a block of code that SHOULD accomplish what I want in CvPlayer::doTurn....

First I loop over all buildings, check to see if the building has an AlignmentShift (this is the max a building can shift your alignment). I then check it's AlignmentShiftModifier(per turn shift amount) and see if it's negative or positive... This is needed so I can see which direction it moves you (evil or good). I then check to make sure your alignment isn't over/under the cap(depends on direction), see if you actually possess the building, and count how many. After that I change alignment for every iteration of the building you possess.


It's not working, however... Not sure why. Here's the code.... I'm sure it's a stupid mistake on my part, but I can't find it. :wallbash:

Spoiler :

Code:
/*************************************************************************************************/
/**	Broader Alignments						04/08/08	Written: Grey Fox	Imported: Xienwolf	**/
/**																								**/
/**		Ensures that all actions during other Player's Turns are reflected in Current Alignment **/
/*************************************************************************************************/
/**								---- Start Original Code ----									**
    if (GC.getGameINLINE().isOption(GAMEOPTION_BROADER_ALIGNMENTS))
    {
        updateAlignment();
    }
	FAssert(m_iPower >= 0);
/**								----  End Original Code  ----									**/
/*************************************************************************************************/
/**	Expanded Broader Alignments 			11/03/09								Valkrionn	**/
/**																								**/
/**								Used to determine per turn shifts								**/
/*************************************************************************************************/
    if (GC.getGameINLINE().isOption(GAMEOPTION_BROADER_ALIGNMENTS))
    {
        for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
        {
            if (paiNumRealBuilding[iI] > 0)
            {
                BuildingClassTypes eBuildingClass = (BuildingClassTypes)GC.getBuildingInfo((BuildingTypes)iI).getBuildingClassType();
                if (::isWorldWonderClass(eBuildingClass))
                {
                    eBuilding = (BuildingTypes)iI;
                }
                else
                {
                    eBuilding = (BuildingTypes)GC.getCivilizationInfo(getCivilizationType()).getCivilizationBuildings(eBuildingClass);
                }
                if (eBuilding != NO_BUILDING)
                {
                    if (GC.getBuildingInfo(eBuilding).getAlignmentShift() != 0)
                    {
                        if (GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier() != 0)
                        {
                            if (GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier() > 0)
                            {
                                if (getBroadAlignment() < GC.getBuildingInfo(eBuilding).getAlignmentShift())
                                {
                                    if (getNumBuilding(eBuilding) > 0)
                                    {
                                        iNumBuildingType = countNumBuildings(eBuilding);
                                        for (int iBuildingShiftLoop = 0; iBuildingShiftLoop < iNumBuildingType; iBuildingShiftLoop++)
                                        {
                                            changeBroadAlignment(GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier());
                                            updateAlignment();
                                        }
                                    }
                                }
                            }

                            if (GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier() < 0)
                            {
                                if (getBroadAlignment() > GC.getBuildingInfo(eBuilding).getAlignmentShift())
                                {
                                    if (getNumBuilding(eBuilding) > 0)
                                    {
                                        iNumBuildingType = countNumBuildings(eBuilding);
                                        for (int iBuildingShiftLoop = 0; iBuildingShiftLoop < iNumBuildingType; iBuildingShiftLoop++)
                                        {
                                            changeBroadAlignment(GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier());
                                            updateAlignment();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        updateAlignment();

    }
	FAssert(m_iPower >= 0);
/*************************************************************************************************/
/**	Broader Alignments Expansion				END												**/
/*************************************************************************************************/
/*************************************************************************************************/
/**	Broader Alignments							END												**/
/*************************************************************************************************/
 
Just because you are likely to return to this, I would advise you get it OUT of ::doTurn, and instead make a new function called ::processAlignment() or something. Then call that instead of updateAlignment in this first posted IF statement. Just move all the following code out into the new function.

"paiNumRealBuilding[iI]"

If this is the global variable, bad form, you should use the ::get___() accessor instead of going straight to the variable. Also you are missing the m_ which is common for a global, so I'll assume it is a local variable which was loaded earlier in the function. Also, you don't want to use RealBuilding IIRC, because then you skip free things like the Mage Guild from Catacomb Libralus.

Why are you doing the checking of CivilizationBuildings for the Buildingclass? That will lead to you doing multiple checks for each building. So when I loop through everything and I check the Mage Guild, I will see that the Bannor don't have a unique version, so I check the Mage Guild. Later I get to the Sheaim UB for Mage Guilds, I see that I use a normal Mage Guild, so I check those again. Thus I have looked at my Mage Guilds twice. You are in a loop over all BuildingTypes, just use what the loop currently is.

Buildings must have both <iAlignmentShift> and <iAlignmentShiftModifier> to do anything in this function as you have it written.

You shouldn't be calling for getNumBuilding(eBuilding) if you already checked that they have this building at the start of your function. Though since you changed what building you are looking at, you DO need it as you have things written. But as I said, you really shouldn't change which building you are looking at.

Instead of looping over the number of buildings that they have, you really ought to just multiply the shift by the number of buildings which they have and finish in a single line. You should also use a std::min() -- or std::max() for the negatives -- function to ensure that they cannot exceed their shift limit.
 
Just because you are likely to return to this, I would advise you get it OUT of ::doTurn, and instead make a new function called ::processAlignment() or something. Then call that instead of updateAlignment in this first posted IF statement. Just move all the following code out into the new function.

"paiNumRealBuilding[iI]"

If this is the global variable, bad form, you should use the ::get___() accessor instead of going straight to the variable. Also you are missing the m_ which is common for a global, so I'll assume it is a local variable which was loaded earlier in the function. Also, you don't want to use RealBuilding IIRC, because then you skip free things like the Mage Guild from Catacomb Libralus.

Why are you doing the checking of CivilizationBuildings for the Buildingclass? That will lead to you doing multiple checks for each building. So when I loop through everything and I check the Mage Guild, I will see that the Bannor don't have a unique version, so I check the Mage Guild. Later I get to the Sheaim UB for Mage Guilds, I see that I use a normal Mage Guild, so I check those again. Thus I have looked at my Mage Guilds twice. You are in a loop over all BuildingTypes, just use what the loop currently is.

Buildings must have both <iAlignmentShift> and <iAlignmentShiftModifier> to do anything in this function as you have it written.

You shouldn't be calling for getNumBuilding(eBuilding) if you already checked that they have this building at the start of your function. Though since you changed what building you are looking at, you DO need it as you have things written. But as I said, you really shouldn't change which building you are looking at.

Instead of looping over the number of buildings that they have, you really ought to just multiply the shift by the number of buildings which they have and finish in a single line. You should also use a std::min() -- or std::max() for the negatives -- function to ensure that they cannot exceed their shift limit.

Honestly, the first part is cloned from another function. :blush: Was looking at it, figured it would be the reason I was crashing honestly. By first part, I mean the from the building loop to assigning eBuilding.... Which includes the civ buildings.

Yes, both AlignmentShift and Modifier are needed. The Shift is the max... Can set it to +/-511 if I don't want it used. The Modifier is the actual amount changed each turn, and that one is vital.

True, at the time I honestly hadn't read over the first bit well. Just saw that it would assign eBuilding, which is what I had been using in the first place I had the code... Was surrounded by a loud group of friends, so I was rather distracted at the time. :lol:

That would work, yeah... At the time I just wanted it working, then I planned to clean it up. How do I use std::min() or max()? Haven't seen them yet.

Edit: And yes, moving it to a new function would make life easier when I expand it.
 
Here's the revised code... No more crashes, but it still doesn't work. Doesn't change the alignment. Either the 'changeBroadAlignment' call is messed up, or something else (likely the checks for direction of shift) is messed up.

Edit: Alright, I removed everything in bold and it still didn't work. Basically trimmed it to "Does this building exist for the player? If so, change alignment.". The tags themselves work correctly (Show up on the building [Testing using a modified Asylum]), so I'm not sure what's wrong with it.

Edit2: Looked at the 'UpdateAlignment' function, and it appears that is the issue... The shifts each turn aren't being saved when alignment updates. Events use a different variable, so I'll use that... After I check to make sure the shift is valid, it can be added to all the others without causing issues afterall.

Code:
/*************************************************************************************************/
/**	Expanded Broader Alignments 			11/03/09								Valkrionn	**/
/**																								**/
/**								Used to determine per turn shifts								**/
/*************************************************************************************************/
    if (GC.getGameINLINE().isOption(GAMEOPTION_BROADER_ALIGNMENTS))
    {
        for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
        {
            if (getNumBuilding(iI) > 0)
            {
                BuildingClassTypes eBuildingClass = (BuildingClassTypes)GC.getBuildingInfo((BuildingTypes)iI).getBuildingClassType();
                eBuilding = (BuildingTypes)iI;
                if (GC.getBuildingInfo(eBuilding).getAlignmentShift() != 0)
                {
                    if (GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier() != 0)
                    {
[B]                        if (GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier() > 0)
                        {
                            if (getBroadAlignment() < GC.getBuildingInfo(eBuilding).getAlignmentShift())
                            {
                                iNumBuildingType = countNumBuildings(eBuilding);
                                changeBroadAlignment((GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier())*iNumBuildingType);
                                updateAlignment();
                            }
                        }

                        if (GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier() < 0)
                        {
                            if (getBroadAlignment() > GC.getBuildingInfo(eBuilding).getAlignmentShift())
                            {[/B]
                                iNumBuildingType = countNumBuildings(eBuilding);
                                changeBroadAlignment((GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier())*iNumBuildingType);
                                updateAlignment();
                            }
                        }
                    }
                }
            }
        }

        updateAlignment();

    }
	FAssert(m_iPower >= 0);
/*************************************************************************************************/
/**	Broader Alignments Expansion				END												**/
/*************************************************************************************************/
 
My last edit was exactly right. ;)

The updateAlignment function was the culprit... My changes weren't being saved when it updated. I added a new variable to store it in, called it in updateAlignment, and it all works PERFECTLY. ;)

Tested by allowing the Asylum to drop you to -200 at a rate of -5 (no building will be that high normally). Started as the Emperor, with an alignment of -100... 20 turns later, I was at -200 and the change shut off. After adding a few buildings to raise my alignment back up, it kicked right back in. :goodjob: Now I expand it to Units/Religions/Civics.

Here's the final code (barring a move to it's own function):

EDIT: Changed the code a bit. Moved the actual alignment shift to after the loop, so that I can compare Actual Alignment to the Target, and if Target is less than the possible Shift use the Target instead. Which actually leads me to my next question... How do I get the absolute value of a variable? If I had that, I could drop the check for shift direction at the end, I think.

Code:
/*************************************************************************************************/
/**	Expanded Broader Alignments 			11/03/09								Valkrionn	**/
/**																								**/
/**								Used to determine per turn shifts								**/
/*************************************************************************************************/
    if (GC.getGameINLINE().isOption(GAMEOPTION_BROADER_ALIGNMENTS))
    {
        for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
        {
            if (getNumBuilding(iI) > 0)
            {
                BuildingClassTypes eBuildingClass = (BuildingClassTypes)GC.getBuildingInfo((BuildingTypes)iI).getBuildingClassType();
                eBuilding = (BuildingTypes)iI;
                if (GC.getBuildingInfo(eBuilding).getAlignmentShift() != 0)
                {
                    if (GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier() != 0)
                    {
                        if (GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier() > 0)
                        {
                            if (getBroadAlignment() < GC.getBuildingInfo(eBuilding).getAlignmentShift())
                            {
                                iNumBuildingType = countNumBuildings(eBuilding);
                                iAlignmentShift += ((GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier())*iNumBuildingType);
                            }
                        }

                        if (GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier() < 0)
                        {
                            if (getBroadAlignment() > GC.getBuildingInfo(eBuilding).getAlignmentShift())
                            {
                                iNumBuildingType = countNumBuildings(eBuilding);
                                iAlignmentShift += ((GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier())*iNumBuildingType);
                            }
                        }
                    }
                }
            }
        }
        if (iAlignmentShift != 0)
        {
            iAlignmentDifference = ((GC.getBuildingInfo(eBuilding).getAlignmentShift()) - getBroadAlignment());
            if (iAlignmentDifference > 0)
            {
                if (iAlignmentDifference < iAlignmentShift)
                {
                    changeBroadShiftModifier(iAlignmentDifference);
                }
                else
                {
                    changeBroadShiftModifier(iAlignmentShift);
                }
            }
            if (iAlignmentDifference < 0)
            {
                if (iAlignmentDifference > iAlignmentShift)
                {
                    changeBroadShiftModifier(iAlignmentDifference);
                }
                else
                {
                    changeBroadShiftModifier(iAlignmentShift);
                }
            }
        }
        updateAlignment();
    }
	FAssert(m_iPower >= 0);
/*************************************************************************************************/
/**	Broader Alignments Expansion				END												**/
/*************************************************************************************************/
 
abs(x)

And the max/min are used like:

std::min(a,b) will be equal to the lower value between a and b

std::max(a,b) will be equal to the larger value.

There is also a range function, but I can never remember the format.
 
Yeah, abs() I already found. Was actually what I assumed it to be, for once. :lol:

std::min() is going to be useful. Can remove a few if checks... Probably quite a bit more of the code could be cleaned up, but it works. :lol: I DO need to add the possibility for a building with just a shiftmod, no cap... At the moment it won't do anything.

Here's my (new) code:

Code:
/*************************************************************************************************/
/**	Expanded Broader Alignments 			11/03/09								Valkrionn	**/
/**																								**/
/**								Used to determine per turn shifts								**/
/*************************************************************************************************/
    if (GC.getGameINLINE().isOption(GAMEOPTION_BROADER_ALIGNMENTS))
    {
        for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
        {
            if (getNumBuilding(iI) > 0)
            {
                BuildingClassTypes eBuildingClass = (BuildingClassTypes)GC.getBuildingInfo((BuildingTypes)iI).getBuildingClassType();
                eBuilding = (BuildingTypes)iI;
                if (GC.getBuildingInfo(eBuilding).getAlignmentShift() != 0)
                {
                    if (GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier() != 0)
                    {
                        if (GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier() > 0)
                        {
                            if (getBroadAlignment() < GC.getBuildingInfo(eBuilding).getAlignmentShift())
                            {
                                iNumBuildingType = countNumBuildings(eBuilding);
                                iAlignmentDifference = ((GC.getBuildingInfo(eBuilding).getAlignmentShift()) - getBroadAlignment());
                                iPossibleShift = ((GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier())*iNumBuildingType);

                                iAlignmentShift += std::min(abs(iAlignmentDifference), abs(iPossibleShift));
                            }
                        }

                        if (GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier() < 0)
                        {
                            if (getBroadAlignment() > GC.getBuildingInfo(eBuilding).getAlignmentShift())
                            {
                                iNumBuildingType = countNumBuildings(eBuilding);
                                iAlignmentDifference = ((GC.getBuildingInfo(eBuilding).getAlignmentShift()) - getBroadAlignment());
                                iPossibleShift = ((GC.getBuildingInfo(eBuilding).getAlignmentShiftModifier())*iNumBuildingType);

                                iAlignmentShift += std::min(abs(iAlignmentDifference), abs(iPossibleShift));
                            }
                        }
                    }
                }
            }
        }
        if (iAlignmentShift != 0)
        {
            changeBroadShiftModifier(iAlignmentShift);
        }
        updateAlignment();
    }
	FAssert(m_iPower >= 0);
/*************************************************************************************************/
/**	Broader Alignments Expansion				END												**/
/*************************************************************************************************/
 
So, here's a question for all of you:


What is the difference between:

A)
Spoiler :
Code:
        <UnitInfo>
            <Class>UNITCLASS_WARRIOR</Class>
            <Type>UNIT_BEASTMAN</Type>
            <UniqueNames>
            </UniqueNames>
            <Special>NONE</Special>
            <Capture>NONE</Capture>
            <Combat>UNITCOMBAT_MELEE</Combat>
            <Domain>DOMAIN_LAND</Domain>
            <DefaultUnitAI>UNITAI_ATTACK</DefaultUnitAI>
            <Invisible>NONE</Invisible>
            <SeeInvisible>NONE</SeeInvisible>
            <Description>TXT_KEY_UNIT_BEASTMAN</Description>
            <Civilopedia>TXT_KEY_UNIT_WARRIOR_PEDIA</Civilopedia>
            <Strategy>TXT_KEY_UNIT_BEASTMAN_STRATEGY</Strategy>
            <Advisor>ADVISOR_MILITARY</Advisor>
            <bAnimal>0</bAnimal>
            <bFood>0</bFood>
            <bNoBadGoodies>0</bNoBadGoodies>
            <bOnlyDefensive>0</bOnlyDefensive>
            <bNoCapture>0</bNoCapture>
            <bQuickCombat>0</bQuickCombat>
            <bRivalTerritory>0</bRivalTerritory>
            <bMilitaryHappiness>1</bMilitaryHappiness>
            <bMilitarySupport>1</bMilitarySupport>
            <bMilitaryProduction>1</bMilitaryProduction>
            <bPillage>1</bPillage>
            <bSpy>0</bSpy>
            <bSabotage>0</bSabotage>
            <bDestroy>0</bDestroy>
            <bStealPlans>0</bStealPlans>
            <bInvestigate>0</bInvestigate>
            <bCounterSpy>0</bCounterSpy>
            <bFound>0</bFound>
            <bGoldenAge>0</bGoldenAge>
            <bInvisible>0</bInvisible>
            <bFirstStrikeImmune>0</bFirstStrikeImmune>
            <bNoDefensiveBonus>0</bNoDefensiveBonus>
            <bIgnoreBuildingDefense>0</bIgnoreBuildingDefense>
            <bCanMoveImpassable>0</bCanMoveImpassable>
            <bCanMoveAllTerrain>0</bCanMoveAllTerrain>
            <bFlatMovementCost>0</bFlatMovementCost>
            <bIgnoreTerrainCost>0</bIgnoreTerrainCost>
            <bNukeImmune>0</bNukeImmune>
            <bPrereqBonuses>0</bPrereqBonuses>
            <bPrereqReligion>0</bPrereqReligion>
            <bMechanized>0</bMechanized>
            <bSuicide>0</bSuicide>
            <bHiddenNationality>0</bHiddenNationality>
            <bAlwaysHostile>0</bAlwaysHostile>
            <UnitClassUpgrades>
                <UnitClassUpgrade>
                    <UnitClassUpgradeType>UNITCLASS_AXEMAN</UnitClassUpgradeType>
                    <bUnitClassUpgrade>1</bUnitClassUpgrade>
                </UnitClassUpgrade>
            </UnitClassUpgrades>
            <UnitClassTargets>
            </UnitClassTargets>
            <UnitCombatTargets>
            </UnitCombatTargets>
            <UnitClassDefenders>
            </UnitClassDefenders>
            <UnitCombatDefenders>
            </UnitCombatDefenders>
            <FlankingStrikes>
            </FlankingStrikes>
            <UnitAIs>
                <UnitAI>
                    <UnitAIType>UNITAI_ATTACK</UnitAIType>
                    <bUnitAI>1</bUnitAI>
                </UnitAI>
                <UnitAI>
                    <UnitAIType>UNITAI_PILLAGE</UnitAIType>
                    <bUnitAI>1</bUnitAI>
                </UnitAI>
            </UnitAIs>
            <NotUnitAIs>
            </NotUnitAIs>
            <Builds>
            </Builds>
            <ReligionSpreads>
            </ReligionSpreads>
            <CorporationSpreads>
            </CorporationSpreads>
            <GreatPeoples>
            </GreatPeoples>
            <Buildings>
            </Buildings>
            <ForceBuildings>
            </ForceBuildings>
            <HolyCity>NONE</HolyCity>
            <ReligionType>NONE</ReligionType>
            <StateReligion>NONE</StateReligion>
            <PrereqReligion>NONE</PrereqReligion>
            <PrereqCorporation>NONE</PrereqCorporation>
            <PrereqBuilding>NONE</PrereqBuilding>
            <PrereqTech>NONE</PrereqTech>
            <TechTypes>
            </TechTypes>
            <BonusType>NONE</BonusType>
            <PrereqBonuses>
            </PrereqBonuses>
            <ProductionTraits>
            </ProductionTraits>
            <Flavors>
            </Flavors>
            <iAIWeight>0</iAIWeight>
            <iCost>25</iCost>
            <iHurryCostModifier>0</iHurryCostModifier>
            <iAdvancedStartCost>100</iAdvancedStartCost>
            <iAdvancedStartCostIncrease>0</iAdvancedStartCostIncrease>
            <iMinAreaSize>-1</iMinAreaSize>
            <iMoves>1</iMoves>
            <bNoRevealMap>0</bNoRevealMap>
            <iAirRange>0</iAirRange>
            <iAirUnitCap>0</iAirUnitCap>
            <iDropRange>0</iDropRange>
            <iNukeRange>-1</iNukeRange>
            <iWorkRate>0</iWorkRate>
            <iBaseDiscover>0</iBaseDiscover>
            <iDiscoverMultiplier>0</iDiscoverMultiplier>
            <iBaseHurry>0</iBaseHurry>
            <iHurryMultiplier>0</iHurryMultiplier>
            <iBaseTrade>0</iBaseTrade>
            <iTradeMultiplier>0</iTradeMultiplier>
            <iGreatWorkCulture>0</iGreatWorkCulture>
            <iEspionagePoints>0</iEspionagePoints>
            <TerrainImpassables>
            </TerrainImpassables>
            <FeatureImpassables>
            </FeatureImpassables>
            <TerrainPassableTechs>
            </TerrainPassableTechs>
            <FeaturePassableTechs>
            </FeaturePassableTechs>
            <iCombat>3</iCombat>
            <iCombatLimit>100</iCombatLimit>
            <iAirCombat>0</iAirCombat>
            <iAirCombatLimit>0</iAirCombatLimit>
            <iXPValueAttack>8</iXPValueAttack>
            <iXPValueDefense>4</iXPValueDefense>
            <iFirstStrikes>0</iFirstStrikes>
            <iChanceFirstStrikes>0</iChanceFirstStrikes>
            <iInterceptionProbability>0</iInterceptionProbability>
            <iEvasionProbability>0</iEvasionProbability>
            <iWithdrawalProb>0</iWithdrawalProb>
            <iCollateralDamage>0</iCollateralDamage>
            <iCollateralDamageLimit>0</iCollateralDamageLimit>
            <iCollateralDamageMaxUnits>0</iCollateralDamageMaxUnits>
            <iCityAttack>20</iCityAttack>
            <iCityDefense>25</iCityDefense>
            <iAnimalCombat>0</iAnimalCombat>
            <iHillsAttack>0</iHillsAttack>
            <iHillsDefense>0</iHillsDefense>
            <TerrainNatives>
            </TerrainNatives>
            <FeatureNatives>
            </FeatureNatives>
            <TerrainAttacks>
            </TerrainAttacks>
            <TerrainDefenses>
            </TerrainDefenses>
            <FeatureAttacks>
            </FeatureAttacks>
            <FeatureDefenses>
            </FeatureDefenses>
            <UnitClassAttackMods>
            </UnitClassAttackMods>
            <UnitClassDefenseMods>
            </UnitClassDefenseMods>
            <UnitCombatMods>
            </UnitCombatMods>
            <UnitCombatCollateralImmunes>
            </UnitCombatCollateralImmunes>
            <DomainMods>
            </DomainMods>
            <BonusProductionModifiers>
            </BonusProductionModifiers>
            <iBombRate>0</iBombRate>
            <iBombardRate>0</iBombardRate>
            <SpecialCargo>NONE</SpecialCargo>
            <DomainCargo>NONE</DomainCargo>
            <iCargo>0</iCargo>
            <iConscription>1</iConscription>
            <iCultureGarrison>3</iCultureGarrison>
            <iExtraCost>0</iExtraCost>
            <iAsset>1</iAsset>
            <iPower>3</iPower>
            <UnitMeshGroups>
            <iGroupSize>3</iGroupSize>
            <fMaxSpeed>1.75</fMaxSpeed>
            <fPadTime>1</fPadTime>
            <iMeleeWaveSize>3</iMeleeWaveSize>
            <iRangedWaveSize>0</iRangedWaveSize>
                <UnitMeshGroup>
                    <iRequired>3</iRequired>
                    <EarlyArtDefineTag>ART_DEF_UNIT_BEASTMAN</EarlyArtDefineTag>
                </UnitMeshGroup>
            </UnitMeshGroups>
            <FormationType>FORMATION_TYPE_DEFAULT</FormationType>
            <HotKey></HotKey>
            <bAltDown>0</bAltDown>
            <bShiftDown>0</bShiftDown>
            <bCtrlDown>0</bCtrlDown>
            <bGraphicalOnly>0</bGraphicalOnly>
            <iHotKeyPriority>0</iHotKeyPriority>
            <FreePromotions>
            </FreePromotions>
            <LeaderPromotion>NONE</LeaderPromotion>
            <iLeaderExperience>0</iLeaderExperience>
            <iCombatDefense>3</iCombatDefense>
            <iTier>1</iTier>
            <iWeaponTier>1</iWeaponTier>
        </UnitInfo>

B)
Spoiler :
Code:
		<UnitInfo>		<!-- Beastman -->
			<Class>UNITCLASS_WARRIOR</Class>
			<Type>UNIT_BEASTMAN</Type>
			<Combat>UNITCOMBAT_MELEE</Combat>
			<DefaultUnitAI>UNITAI_CITY_DEFENSE</DefaultUnitAI>
			<Description>TXT_KEY_UNIT_BEASTMAN</Description>
			<Civilopedia>TXT_KEY_UNIT_WARRIOR_PEDIA</Civilopedia>
			<Advisor>ADVISOR_MILITARY</Advisor>
			<bMilitaryHappiness>1</bMilitaryHappiness>
			<bMilitarySupport>1</bMilitarySupport>
			<bMilitaryProduction>1</bMilitaryProduction>
			<bPillage>1</bPillage>
			<UnitClassUpgrades>
				<UnitClassUpgrade>
					<UnitClassUpgradeType>UNITCLASS_AXEMAN</UnitClassUpgradeType>
					<bUnitClassUpgrade>1</bUnitClassUpgrade>
				</UnitClassUpgrade>
			</UnitClassUpgrades>
			<UnitAIs>
				<UnitAI>
					<UnitAIType>UNITAI_ATTACK</UnitAIType>
					<bUnitAI>1</bUnitAI>
				</UnitAI>
				<UnitAI>
					<UnitAIType>UNITAI_PILLAGE</UnitAIType>
					<bUnitAI>1</bUnitAI>
				</UnitAI>
			</UnitAIs>
			<iCost>25</iCost>
			<iMoves>1</iMoves>
			<iCombat>3</iCombat>
			<iCityAttack>20</iCityAttack>
			<iCityDefense>25</iCityDefense>
			<iConscription>1</iConscription>
			<iCultureGarrison>3</iCultureGarrison>
			<iAsset>1</iAsset>
			<iPower>3</iPower>
			<UnitMeshGroups>
				<iGroupSize>3</iGroupSize>
				<iMeleeWaveSize>3</iMeleeWaveSize>
				<iRangedWaveSize>0</iRangedWaveSize>
				<UnitMeshGroup>
					<iRequired>3</iRequired>
					<EarlyArtDefineTag>ART_DEF_UNIT_BEASTMAN</EarlyArtDefineTag>
				</UnitMeshGroup>
			</UnitMeshGroups>
			<iTier>1</iTier>
			<iWeaponTierMax>1</iWeaponTierMax>
		</UnitInfo>

and C)
Spoiler :
Code:
		<UnitInfo>		<!-- Beastman -->
			<Class>UNITCLASS_WARRIOR</Class>
			<Type>UNIT_BEASTMAN</Type>
			<Combat>UNITCOMBAT_MELEE</Combat>
			<DefaultUnitAI>UNITAI_CITY_DEFENSE</DefaultUnitAI>
			<Description>TXT_KEY_UNIT_BEASTMAN</Description>
			<Civilopedia>TXT_KEY_UNIT_WARRIOR_PEDIA</Civilopedia>
			<Advisor>ADVISOR_MILITARY</Advisor>
			<iCost>25</iCost>
			<iTier>1</iTier>
			<iWeaponTierMax>1</iWeaponTierMax>
			<iCombat>3</iCombat>
			<iCombatDefense>3</iCombatDefense>
			<iMoves>1</iMoves>
			<iCityAttack>20</iCityAttack>
			<iCityDefense>25</iCityDefense>
			<UnitClassUpgrades>
				<UnitClassUpgrade>
					<UnitClassUpgradeType>UNITCLASS_AXEMAN</UnitClassUpgradeType>
					<bUnitClassUpgrade>1</bUnitClassUpgrade>
				</UnitClassUpgrade>
			</UnitClassUpgrades>
			<bMilitaryHappiness>1</bMilitaryHappiness>
			<bMilitarySupport>1</bMilitarySupport>
			<bMilitaryProduction>1</bMilitaryProduction>
			<bPillage>1</bPillage>
			<iConscription>1</iConscription>
			<iCultureGarrison>3</iCultureGarrison>
			<iAsset>1</iAsset>
			<iPower>3</iPower>
			<UnitAIs>
				<UnitAI>
					<UnitAIType>UNITAI_ATTACK</UnitAIType>
					<bUnitAI>1</bUnitAI>
				</UnitAI>
				<UnitAI>
					<UnitAIType>UNITAI_PILLAGE</UnitAIType>
					<bUnitAI>1</bUnitAI>
				</UnitAI>
			</UnitAIs>
			<UnitMeshGroups>
				<iGroupSize>3</iGroupSize>
				<iMeleeWaveSize>3</iMeleeWaveSize>
				<iRangedWaveSize>0</iRangedWaveSize>
				<UnitMeshGroup>
					<iRequired>3</iRequired>
					<EarlyArtDefineTag>ART_DEF_UNIT_BEASTMAN</EarlyArtDefineTag>
				</UnitMeshGroup>
			</UnitMeshGroups>
		</UnitInfo>


And is it possible for all of them to be valid for the same Schema?
 
And the answer is: The Schema is different!

A) All tags are required in the exact order specified in the Schema. Easy to add new abilities to a unit since you don't have to know where to insert a tag. PAINFUL to read the data and decide precisely what the unit is capable of.

Spoiler :
Code:
	<ElementType name="UnitInfo" content="eltOnly">
		<element type="Class"/>
		<element type="Type"/>
		<element type="bTypeDependency"/>
		<element type="AndDependencyTypes"/>
		<element type="OrDependencyTypes"/>
		<element type="UniqueNames"/>
		<element type="Quotes"/>
		<element type="Images"/>
		<element type="Special"/>
		<element type="Capture"/>
		<element type="Combat"/>
		<element type="Domain"/>
		<element type="DefaultUnitAI"/>
		<element type="Invisible"/>
		<element type="SeeInvisible"/>
		<element type="Description"/>
		<element type="Civilopedia"/>
		<element type="Strategy"/>
		<element type="Help"/>
		<element type="Advisor"/>
		<element type="bAnimal"/>
		<element type="bFood"/>
		<element type="bNoBadGoodies"/>
		<element type="bOnlyDefensive"/>
		<element type="bNoCapture"/>
		<element type="bQuickCombat"/>
.
.
.

B) All tags must be in the right order, but if a defaul value is used, you don't need to include the tag. Easy to see what a unit is capable of, easy to modify abilities the unit already has. A bit of a pain to add new abilities because you have to remember what tags come before which other ones, or have a "Sample" to work from, or understand how to find/read the schema

Spoiler :
Code:
	<ElementType name="UnitInfo" content="eltOnly">
		<element type="Class"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Type"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="bTypeDependency"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="AndDependencyTypes"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="OrDependencyTypes"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="UniqueNames"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Quotes"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Images"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Special"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Capture"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Combat"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Domain"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="DefaultUnitAI"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Invisible"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="SeeInvisible"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Description"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Civilopedia"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Strategy"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Help"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="Advisor"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="bAnimal"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="bFood"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="bNoBadGoodies"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="bOnlyDefensive"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="bNoCapture"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
		<element type="bQuickCombat"[COLOR="Lime"] minOccurs="0"[/COLOR]/>
.
.
.

C) You only include the tags which you have non-default values for, and you can put them in absolutely any order you want to. As long as you don't get a typo for a tag name, you don't have to reference anything else at all.

Spoiler :
Code:
	<ElementType name="UnitInfo" content="eltOnly"[COLOR="Lime"] order="many"[/COLOR]>
		<element type="Class"/>
		<element type="Type"/>
		<element type="bTypeDependency"/>
		<element type="AndDependencyTypes"/>
		<element type="OrDependencyTypes"/>
		<element type="UniqueNames"/>
		<element type="Quotes"/>
		<element type="Images"/>
		<element type="Special"/>
		<element type="Capture"/>
		<element type="Combat"/>
		<element type="Domain"/>
		<element type="DefaultUnitAI"/>
		<element type="Invisible"/>
		<element type="SeeInvisible"/>
		<element type="Description"/>
		<element type="Civilopedia"/>
		<element type="Strategy"/>
		<element type="Help"/>
		<element type="Advisor"/>
		<element type="bAnimal"/>
		<element type="bFood"/>
		<element type="bNoBadGoodies"/>
		<element type="bOnlyDefensive"/>
		<element type="bNoCapture"/>
		<element type="bQuickCombat"/>
.
.
.


Only partial schemas posted, the bit you add from the basic schema in "A" is highlighted in Lime, which reveals the final awesome thing about the "C" method, the schema adjustment is PATHETICALLY easy :)
 
Already exists in XML language library. Just nobody around here really knows much about XML (I fortunately happened to mod GUI's for Everquest a few years ago, so understood a FEW of the more intricate things you can do, and more importantly, had access to a good tutorial. Just finally decided that this order stuff bugs me enough to try and solve it)
 
One potential (but rare and minor) downside is that you also get the effect of maxOccurs="*" from this, so some day you might add a duplicate of a tag. But the DLL will just wind up taking one and ignoring the other (pretty sure it'll grab the first one it finds only), so it'll be slightly annoying to track down why your changes aren't taking effect if you tweak the wrong one of the duplicated values, but as I said.. it'll be rare that someone accidentally adds a value which is already in the XML for that item.
 
Top Bottom