Add new instances to a core lua-file

Discussion in 'Civ5 - Creation & Customization' started by martijnaikema, Jan 5, 2011.

  1. martijnaikema

    martijnaikema Warlord

    Joined:
    Oct 30, 2010
    Messages:
    111
    In the EnemyUnitPanel.xml the unit-bonusses that are displayed in the panel (like Rough Terrain Bonus) are created as instances. In the xml it is displayed as:

    Spoiler :

    <Instance Name="UsCombatInfo" >

    <Label Anchor="R,C" Offset="52.0" String=" " Font="TwCenMT14" ID="Text" WrapWidth="230" LeadingOffset="-6" >

    <Label Anchor="R,C" AnchorSide="O.I" Offset="4.0" Font="TwCenMT14" ID="Value" />
    </Label>
    </Instance>


    If I edit the core file (EnemyUnitPanel.lua) and add my bonus to it, it is displayed in the screen:

    Spoiler :

    local iType = pMyUnit:GetNameKey();
    if (pToPlot:IsRiver() and iType == "TXT_KEY_UNIT_WATERGEUS") then

    -- RiverModifier
    iModifier = 50;
    if (iModifier ~= 0) then
    controlTable = g_MyCombatDataIM:GetInstance();
    local RiverBonus = "River";

    controlTable.Text:LocalizeAndSetText( "TXT_KEY_EUPANEL_ATTACK_INTO_BONUS", RiverBonus );

    controlTable.Value:SetText( GetFormattedText(strText, iModifier, true, true) );
    end
    end
    -- pMyUnit = UI.GetHeadSelectedUnit();
    -- pToPlot = the mouseover of a certain plot



    When I add this to the core lua-file the text and bonus is displayed in the panel:


    But I do not want to edit the core file but create the new instance with my own lua. But I can not get it to work. Here is some more info from the instance.

    * The instance in the core-lua is created through the command: g_MyCombatDataIM:GetInstance = InstanceManager:new( "UsCombatInfo", "Text", Controls.MyCombatResultsStack );
    * The instance is created by including the InstanceManager.lua
    * To add a new instance I guess I have to read the instances allready created by EnemyUnitPanel.lua and add my instance to it
    * I found this thread really interesting cause it shows the power of ContextPtr-commands. I tried different options, but I can't get it to work.
    I hope someone knows how I should add a new Instance to the panel.

    Edit:When I try to create a new instance I get an error "Instance Manager built with a bad Root Control [USCombatInfo] [Text]"
     
  2. martijnaikema

    martijnaikema Warlord

    Joined:
    Oct 30, 2010
    Messages:
    111
    I checked the InstanceManager.lua file and I saw that it uses ContextPtr:BuildInstance and ContextPtr:BuildInstanceForControl.

    But I can't figure out how they work I tried the following with the correpsonding errors:

    1
    ContextPtr:BuildInstanceForControl("/InGame/WorldView/EnemyUnitPanel/UsCombatInfo"):SetText( "Attack into River", 50);

    Error:
    LuaContext::BuildInstanceForControl could not be called: 2 values on stack. Expected 1 parent table and 3 arguments

    2
    ContextPtr:BuildInstance("/InGame/WorldView/EnemyUnitPanel/UsCombatInfo"):SetText( "Attack into River", 50, false, true);

    Error:
    LuaContext::BuildInstance could not be called: 2 values on stack. Expected 1 parent table and 2 arguments

    3
    ContextPtr:BuildInstance("/InGame/WorldView/EnemyUnitPanel/UsCombatInfo").Text:SetText( "Attack into River")
    ContextPtr:BuildInstance("/InGame/WorldView/EnemyUnitPanel/UsCombatInfo").Value:SetText( "50")

    Error:
    LuaContext::BuildInstance could not be called: 2 values on stack. Expected 1 parent table and 2 arguments
     
  3. martijnaikema

    martijnaikema Warlord

    Joined:
    Oct 30, 2010
    Messages:
    111
    I still can not get it to work. Here is what I did:

    1) Created an lua-file. Named it watergeusbonus.lua.

    It contains the code to make a new instance and refers to the "MyCombatResultStack" of the core EnemyUnitPanel.lua file:

    Spoiler :

    local g_MyCombatDataRiverIM = InstanceManager:new( "UsCombatInfoRiver", "Text", Controls.MyCombatResultsStack );
    local controlTable = g_MyCombatDataRiverIM:GetInstance();

    ContextPtr:BuildInstanceForControl ( "UsCombatInfoRiver", controlTable , Controls.MyCombatResultsStack );

    controlTable.Text:SetText ( "Bonus attacking into River" );
    controlTable.Value:SetText ( "50" )



    2) Created 2 xml-files. Named it watergeusbonus.xml and watergeusbonus_small.xml.

    It contains the new instance "UsCombatInfoRiver"

    Spoiler :

    <?xml version="1.0" encoding="utf-8"?>
    <Context ColorSet="Beige_Black" Font="TwCenMT20" FontStyle="Shadow" >

    <!-- Combat Info Label Instances for River -->

    <Instance Name="UsCombatInfoRiver" >
    <Label Anchor="R,C" Offset="52.0" String=" " Font="TwCenMT14" ID="Text" WrapWidth="230" LeadingOffset="-6" >
    <Label Anchor="R,C" AnchorSide="O.I" Offset="4.0" Font="TwCenMT14" ID="Value" />
    </Label>
    </Instance>

    </Context>



    3) Test ingame. I get an error:

    Incorrect type for pointer argument. Using NULL instead.

    4) The text itself is not displayed in the panel, but on the right side of the screen




    I really hope someone can help me with this. I have uploaded the current version of the MOD so you can test it out yourself.
     

    Attached Files:

  4. Cope

    Cope Chieftain

    Joined:
    Sep 30, 2010
    Messages:
    35
    I don't think you need to call ContextPtr:BuildInstanceForControl. What's going on here is:

    local controlTable = g_MyCombatDataRiverIM:GetInstance();
    You ask for a new instance of the UsCombatInfoRiver label. This label is already tied to the Controls.MyCombatResultsStack so it will be added to this stack automatically. Then you call:

    ContextPtr:BuildInstanceForControl ( "UsCombatInfoRiver", controlTable , Controls.MyCombatResultsStack );
    What this call actually does is build a sort of "blank" instance. If you look through the various lua files you'll see that it's only ever used on an empty instance like:

    local textControls = {};
    ContextPtr:BuildInstanceForControl("LTextEntry", textControls, controlTable.PoliciesStack);

    If this call is causing your pointer error then it could well break the label's association with the MyCombatResultsStack, which would make it appear at the right center of the screen like it does now.

    Also, depending on when your .lua is executed you may have to tell the game to re-size the MyCombatResultsStack when you're finished:

    Code:
    Controls.MyCombatResultsStack:CalculateSize();
    Controls.DetailsGrid:DoAutoSize();
    Controls.DetailsGrid:SetSizeX( Controls.DetailsGrid:GetSizeX() );
    Controls.DetailsSeperator:SetSizeY( Controls.DetailsGrid:GetSizeY() );
    Controls.DetailsGrid:ReprocessAnchoring();
    
    That's my guess anyway :)
     
  5. martijnaikema

    martijnaikema Warlord

    Joined:
    Oct 30, 2010
    Messages:
    111
    Thank you for your suggestion. I tried what you said and changed the code to:

    local g_MyCombatDataRiverIM = InstanceManager:new( "UsCombatInfoRiver", "Text", Controls.MyCombatResultsStack );
    local controlTable = g_MyCombatDataRiverIM:GetInstance();

    --ContextPtr:BuildInstanceForControl ( "UsCombatInfoRiver", controlTable , Controls.MyCombatResultsStack );

    controlTable.Text:SetText ( "Bonus attacking into River" );
    controlTable.Value:SetText ( "50" )

    But the text is still displayed on the right of the screen and is not added at the existing Controls.MyCombatResultsStack.

    I also tried to change to instance name from UsCombatInfoRiver to UsCombatInfo to match the original label and change the xml-files accordingly. But still no luck :(

    Do I need to add something extra to the xml-files? I now only have the instance in the xml-files. Or re-anchor the new bonus to the panel?
     
  6. Cope

    Cope Chieftain

    Joined:
    Sep 30, 2010
    Messages:
    35
    Maybe you should try to go about this a bit differently. Instead of creating your own Instance class in your xml file try to make it a plain label, since you won't need to make more than one copy of it anyway.

    Spoiler :

    <?xml version="1.0" encoding="utf-8"?>
    <Context ColorSet="Beige_Black" Font="TwCenMT20" FontStyle="Shadow" >

    <!-- Combat Info Label Instances for River -->

    <Label Anchor="R,C" Offset="52.0" String=" " Font="TwCenMT14" ID="RiverText" WrapWidth="230" LeadingOffset="-6" >
    <Label Anchor="R,C" AnchorSide="O.I" Offset="4.0" Font="TwCenMT14" ID="Value" />
    </Label>


    </Context>


    Then in your lua file you force the game to associate it with the MyCombatResultsStack in the core files:

    Spoiler :

    Controls.RiverText:SetText("Bonus attacking into River" );
    Controls.Value:SetText( "50" );

    Controls.RiverText:ChangeParent(ContextPtr:LookUpControl("/InGame/WorldView/EnemyUnitPanel/MyCombatResultsStack"));
    ContextPtr:LookUpControl("/InGame/WorldView/EnemyUnitPanel/MyCombatResultsStack"):ReprocessAnchoring();
     
  7. martijnaikema

    martijnaikema Warlord

    Joined:
    Oct 30, 2010
    Messages:
    111
    You were right. That indeed did the trick. Thank you.

    To get the anchoring right I added this code:

    Spoiler :

    local iModifier = 50;
    local iValue = " : [COLOR_POSITIVE_TEXT]+" .. Locale.ToNumber(iModifier, "#.##") .. "%[ENDCOLOR][]";
    Controls.RiverText:SetText( "Bonus fighting near River");
    Controls.Value:SetText( iValue );
    Controls.RiverText:SetHide(false);

    Controls.RiverText:ChangeParent(ContextPtr:LookUpControl("/InGame/WorldView/EnemyUnitPanel/MyCombatResultsStack"));
    ContextPtr:LookUpControl("/InGame/WorldView/EnemyUnitPanel/MyCombatResultsStack"):CalculateSize();
    ContextPtr:LookUpControl("/InGame/WorldView/EnemyUnitPanel/TheirCombatResultsStack"):CalculateSize();

    local sizeX = ContextPtr:LookUpControl("/InGame/WorldView/EnemyUnitPanel/DetailsGrid"):GetSizeX();
    local sizeY = ContextPtr:LookUpControl("/InGame/WorldView/EnemyUnitPanel/DetailsGrid"):GetSizeY()
    ContextPtr:LookUpControl("/InGame/WorldView/EnemyUnitPanel/DetailsGrid"):DoAutoSize();
    ContextPtr:LookUpControl("/InGame/WorldView/EnemyUnitPanel/DetailsGrid"):SetSizeX( sizeX );
    ContextPtr:LookUpControl("/InGame/WorldView/EnemyUnitPanel/DetailsSeperator"):SetSizeY( sizeY );
    ContextPtr:LookUpControl("/InGame/WorldView/EnemyUnitPanel/DetailsGrid"):ReprocessAnchoring();
     
  8. Cope

    Cope Chieftain

    Joined:
    Sep 30, 2010
    Messages:
    35
    Glad to help :)

    If you want to streamline it a bit you could store the EnemyUnitPanel in a local variable, then you only have to do the LookUpControl once:

    Code:
    local eupanel = ContextPtr:LookUpControl("/InGame/WorldView/EnemyUnitPanel");
    
    Controls.RiverText:ChangeParent(eupanel.MyCombatResultsStack);
    ...
    eupanel.DetailsGrid:DoAutoSize();
    ...
    
    At least I assume this would work.
     

Share This Page