A couple more "quick" inquiries

That page is doing something weird with the seed for it's random. If you input your own, it behaves as expected:
Code:
--math.randomseed(os.time())
return math.random(), math.random(), math.random()

Either of the methods I posted already accomplish "percentage" functionality. You don't need a random integer and a random float generated separately. It won't make it any "more random". Granted the percentage functionality offered assumes you input a percentage that's already been converted to decimal but that's kinda insignificant. I suppose you could always do 100 * random > value but how is that functionally any different than random > value / 100? :crazyeye:
 
I don't think the lua demo page is returning a true random number...I think it is simulating the effect of getting a random number but is actually pulling a number off an algorithm, which probably requires far less website 'bloat' than an actual random number generator.

I have noticed in something I've been testing in-game, though, that when I use
Code:
local iRandomChance = math.random(1000)
iRandomChance seems to always return "784" the first time after starting a new game...but thereafter it seems to vary as one would expect.
 
I have noticed in something I've been testing in-game, though, that when I use
Code:
local iRandomChance = math.random(1000)
iRandomChance seems to always return "784" the first time after starting a new game...but thereafter it seems to vary as one would expect.

That's a widely reported issue with the random Lua implements. Wide enough that I actually call a random to trash it during seeding in code I wrote years ago simply because I read it wasn't a bad idea to do so.
 
Let the necro begin!

So I'm beginning the process of updating my old World of Asmos civpack - I figure it'll take me 6 months :p (and if you don't know what I'm talking about, I don't think that should affect the outcome of this question) - and I'm adding a civ whose UA allows it to gain 2 faith from every science-producing building and 3 science from every faith-producing building. This is accomplished via a dummy policy.

Now, I could manually type in every entry in Policy_BuildingClassYieldChanges for every buildingclass whose building yields faith. But I'm lazy. :p So I'd rather just use SQL SELECT statements and iterators to do the job for me. But SQL doesn't have iterators, so I have to do this in lua - with DB.Query(string sqlArguments), apparently.

I came up with these two iterators:
Code:
for row in DB.Query("SELECT Class FROM Buildings WHERE Type IN (SELECT BuildingType FROM Building_YieldChanges WHERE YieldType = 'YIELD_FAITH' AND Yield > 0)") do
	DB.Query("INSERT INTO Policy_BuildingClassYieldChanges (PolicyType, BuildingClassType, YieldType, Yield) VALUES ('POLICY_WOA_CST', "..row.Class..", 'YIELD_SCIENCE', 3);)")
end

for row in DB.Query("SELECT Class FROM Buildings WHERE Type IN (SELECT BuildingType FROM Building_YieldChangesPerPop WHERE YieldType = 'YIELD_SCIENCE' AND Yield > 0) AND (SELECT BuildingType FROM Building_YieldChanges WHERE YieldType = 'YIELD_SCIENCE' AND Yield > 0") do
	DB.Query("INSERT INTO Policy_BuildingClassYieldChanges (PolicyType, BuildingClassType, YieldType, Yield) VALUES ('POLICY_WOA_CST', "..row.Class..", 'YIELD_FAITH', 2);)")
end
Love that wall of code, eh? :p

So, a couple questions:
1) Is my method even viable or should I stop being lazy?
2) Will it work or are there obvious mistakes?
3) Does it need an event hook, and if so, which one? Because optimally we only want this to fire as many times as the code from SQL files does...
 
You should be able to do everything short of actually giving the policy via SQL. That's what triggers and variable table-building INSERT etc statements in SQL are for. But you'd need to get help from someone far more knowledgeable in SQL than I.

  1. Pray to Whoward for guidance.
  2. If #1 fails of a result, pray harder

I think this is a time where you really do need to pray* for guidance. Nutty, JFD, Leugi, Whoward would all do I would think.

* where "pray" is a tongue-in-cheek cognate for "ask for help".
 
As a member of Sacred College of Codinals, and on behalf of His Codeliness, Pope Gazebo, I bring to you guidance.

AFAIK, you cannot add to/change the Database after your mods have been configured (except where text is concerned). So you'll have to settle with using a trigger, as LeeS says:

Code:
INSERT INTO Policy_BuildingClassYieldChanges
		(PolicyType,		BuildingClassType, YieldType,			YieldChange)
SELECT	('POLICY_WOA_CST'),	BuildingClass,		('YIELD_FAITH'),	2
FROM Buildings WHERE Type IN (SELECT BuildingType FROM Building_YieldChanges WHERE YieldType = 'YIELD_SCIENCE' AND Yield > 0)
AND Cost > 0 AND GreatWorkCount > -1;

INSERT INTO Policy_BuildingClassYieldChanges
		(PolicyType,		BuildingClassType, YieldType,			YieldChange)
SELECT	('POLICY_WOA_CST'),	BuildingClass,		('YIELD_SCIENCE'),	3
FROM Buildings WHERE Type IN (SELECT BuildingType FROM Building_YieldChanges WHERE YieldType = 'YIELD_FAITH' AND Yield > 0)
AND Cost > 0 AND GreatWorkCount > -1;

CREATE TRIGGER AW_Policy_BuildingClassYieldChanges
AFTER INSERT ON Buildings
BEGIN
	INSERT INTO Policy_BuildingClassYieldChanges
			(PolicyType,		BuildingClassType, YieldType,			YieldChange)
	SELECT	('POLICY_WOA_CST'),	NEW.BuildingClass,		('YIELD_FAITH'),	2
	FROM Buildings WHERE Type IN (SELECT BuildingType FROM Building_YieldChanges WHERE YieldType = 'YIELD_SCIENCE' AND Yield > 0)
	AND Cost > 0 AND GreatWorkCount > -1;
	
	INSERT INTO Policy_BuildingClassYieldChanges
			(PolicyType,		BuildingClassType, YieldType,			YieldChange)
	SELECT	('POLICY_WOA_CST'),	NEW.BuildingClass,		('YIELD_SCIENCE'),	3
	FROM Buildings WHERE Type IN (SELECT BuildingType FROM Building_YieldChanges WHERE YieldType = 'YIELD_FAITH' AND Yield > 0)
	AND Cost > 0 AND GreatWorkCount > -1;
END;

May the Good Lord Whoward bless unto you good codings, AW.
 
But SQL doesn't have iterators, so I have to do this in lua

SQL uses compound inserts (selects within inserts) to achieve the same outcome as loops/iterators in programming languages. See the solution given by JFD below and also this thread, which has a step-by-step more complex example
 
Code:
INSERT INTO Policy_BuildingClassYieldChanges
		(PolicyType,		BuildingClassType, YieldType,			YieldChange)
SELECT	('POLICY_WOA_CST'),	BuildingClass,		('YIELD_FAITH'),	2
FROM Buildings WHERE Type IN (SELECT BuildingType FROM Building_YieldChanges WHERE YieldType = 'YIELD_SCIENCE' AND Yield > 0)
AND Cost > 0 AND GreatWorkCount > -1;
There is an issue with the insert's sub-select statement. Because the Policy_BuildingClassYieldChanges table uses building class, while the Building_YieldChanges uses building type, if we have two buildings of the same class with a science yield, we'll get duplicate entries in the Policy_BuildingClassYieldChanges table. Not a problem for the game (as it'll either use the first entry or the last), but not good practice. The solution is to SELECT DISTINCT ...

Edit:
Spoiler :
And that of course assumes that both buildings have the same value for Yield ... if they add different amounts of yield you're back to the duplicate entries problem, and will need to modify the select to use grouping and the max() function ...


Code:
CREATE TRIGGER AW_Policy_BuildingClassYieldChanges
AFTER INSERT ON Buildings
BEGIN
	INSERT INTO Policy_BuildingClassYieldChanges
			(PolicyType,		BuildingClassType, YieldType,			YieldChange)
	SELECT	('POLICY_WOA_CST'),	NEW.BuildingClass,		('YIELD_FAITH'),	2
	FROM Buildings WHERE Type IN (SELECT BuildingType FROM Building_YieldChanges WHERE YieldType = 'YIELD_SCIENCE' AND Yield > 0)
	AND Cost > 0 AND GreatWorkCount > -1;
END;
There are two issues with the trigger. Firstly, whenever a new building is added it selects all the buildings that have a science yield and inserts one row for each for the new building into the policy yield table, regardless of whether or not the new building has a science yield!

The select within the trigger needs to test the yield of the new building only, so needs to be
Code:
    SELECT 'POLICY_WOA_CST', b.BuildingClass, 'YIELD_FAITH', 2 FROM Buildings b, Building_YieldChanges y
      WHERE b.Type = NEW.Type AND b.Type = y.BuildingType AND y.YieldType = 'YIELD_SCIENCE' AND y.Yield > 0
      AND b.Cost > 0 AND b.GreatWorkCount > -1;

Which highlights the second issue, the trigger assumes the Building_YieldChanges table has been updated BEFORE the Buildings table - given that most modders arrange their XML/SQL with the main table (Buildings) before the secondary tables (Building_Xyz), this is highly unlikely to be true.

So we need a second trigger, on the Building_YieldChanges table

Code:
CREATE TRIGGER AW_Building_YieldChanges
AFTER INSERT ON Building_YieldChanges
BEGIN
  INSERT INTO Policy_BuildingClassYieldChanges(PolicyType, BuildingClassType, YieldType, YieldChange)
    SELECT 'POLICY_WOA_CST', b.BuildingClass, 'YIELD_FAITH', 2 FROM Buildings b, Building_YieldChanges y
      WHERE y.BuildingType = NEW.BuildingType AND b.Type = y.BuildingType AND NEW.YieldType = 'YIELD_SCIENCE' AND NEW.Yield > 0
      AND b.Cost > 0 AND b.GreatWorkCount > -1;
END;

We could make this trigger slightly more efficient (but by so little as to not be worth it for the added complexity) by using a WHEN clause

...


Oh yes, and stop putting brackets around quoted strings!
('POLICY_WOA_CST') is redundant (and in some flavours of SQL will cause an error), it should just be 'POLICY_WOA_CST'
 
Boy, this generated a lot more interest than usual! Thanks much to all y'all for the guidance; much appreciated.

So what I've pieced together from the God of Modding's discourse with the Modjesty is that his Modjesty's code should work except for the fact that he's trying to insert a building type into a buildingclass type column, and so the relevant parts should be replaced with a SELECT statement that extracts the buildingclass type from the building - as provided by Deus Moddi - like so:
Code:
INSERT INTO Policy_BuildingClassYieldChanges
		(PolicyType,		BuildingClassType, YieldType,			YieldChange)
SELECT 'POLICY_WOA_CST', b.BuildingClass, 'YIELD_FAITH', 2 FROM Buildings b, Building_YieldChanges y
      WHERE b.Type = NEW.Type AND b.Type = y.BuildingType AND y.YieldType = 'YIELD_SCIENCE' AND y.Yield > 0
      AND b.Cost > 0 AND b.GreatWorkCount > -1;

INSERT INTO Policy_BuildingClassYieldChanges
		(PolicyType,		BuildingClassType, YieldType,			YieldChange)
SELECT 'POLICY_WOA_CST', b.BuildingClass, 'YIELD_FAITH', 2 FROM Buildings b, Building_YieldChanges y
      WHERE b.Type = NEW.Type AND b.Type = y.BuildingType AND y.YieldType = 'YIELD_SCIENCE' AND y.Yield > 0
      AND b.Cost > 0 AND b.GreatWorkCount > -1;

CREATE TRIGGER AW_Policy_BuildingClassYieldChanges
AFTER INSERT ON Buildings
BEGIN
	INSERT INTO Policy_BuildingClassYieldChanges
			(PolicyType,		BuildingClassType, YieldType,			YieldChange)
	SELECT 'POLICY_WOA_CST', b.BuildingClass, 'YIELD_FAITH', 2 FROM Buildings b, Building_YieldChanges y
     	 WHERE b.Type = NEW.Type AND b.Type = y.BuildingType AND y.YieldType = 'YIELD_SCIENCE' AND y.Yield > 0
     	 AND b.Cost > 0 AND b.GreatWorkCount > -1;
	
	INSERT INTO Policy_BuildingClassYieldChanges
			(PolicyType,		BuildingClassType, YieldType,			YieldChange)
	SELECT 'POLICY_WOA_CST', b.BuildingClass, 'YIELD_FAITH', 2 FROM Buildings b, Building_YieldChanges y
      	WHERE b.Type = NEW.Type AND b.Type = y.BuildingType AND y.YieldType = 'YIELD_SCIENCE' AND y.Yield > 0
      	AND b.Cost > 0 AND b.GreatWorkCount > -1;
END;
'course, I guess I could always just plug this into SQLiteBrowser's Execute SQL tab and see if it returns any errors...
EDIT: And upon doing so I get the following error:
Code:
no such column: NEW.Type: INSERT INTO Policy_BuildingClassYieldChanges
		(PolicyType,		BuildingClassType, YieldType,			YieldChange)
SELECT 'POLICY_WOA_CST', b.BuildingClass, 'YIELD_FAITH', 2 FROM Buildings b, Building_YieldChanges y
      WHERE b.Type = NEW.Type AND b.Type = y.BuildingType AND y.YieldType = 'YIELD_SCIENCE' AND y.Yield > 0
      AND b.Cost > 0 AND b.GreatWorkCount > -1;
 
NEW is the contents (ie the table row) that was being inserted when the TRIGGER fired. So any NEW.{column_name} in the SQL that you feed into SQLite to test the code will have to be replaced with what you would have been inserting, eg NEW.Type will have to be replaced (only for testing) with 'BUILDING_MY_NEW_PILE_OF_BRICKS_AND_MORTAR' and (if it was used) NEW.Cost would be replaced with 175
 
The JFD code is three statements - two inserts and a create trigger - all valid SQL (just with a couple of logic issues)

The AW code has incorrectly replaced the first two inserts with my code that should have been inside the trigger, that is the text "The select within the trigger ..." of my post has been ignored.
 
who's up for another necro? :D

So I'm really bad at UI modding. The "choose a resource" popup from my Urartu mod is about the extent of my skill, and that was mostly copied from MC's Phoenicia. But I've begun work on a mod that, foolishly, would include a lot of new UI. :p
Basically I'm looking at something kind of like the E&D events popup, or the Mayan UA "choose a free GP" popup. I'm trying to create one "template" UI element that can then be copied over many times in a downwards-descending stack, with different icons and text in each one.
But I don't understand how.

Is each of those child elements considered what's called an "instance"? Or a stack? Or are they part of a stack that's part of a grid that's part of a box that's part of a context? :crazyeye:
The mayan popup iterates over all great people like so:
Code:
for info in GameInfo.Units{Special = "SPECIALUNIT_PEOPLE"} do
	
		if(player:CanTrain(info.ID, true, true, true, false)) then
			local controlTable = {};
			ContextPtr:BuildInstanceForControl( "ItemInstance", controlTable, stackControl );
			local unitType = info.Type;
What the heck is BuildInstanceForControl? Where did ContextPtr come from?
 
Who's up for another necro? :D
Lurches up to keyboard with arms held straight out, moaning "Brains ... brains!!!"
(The "arms held straight out" bit makes it very hard to type!)

Is each of those child elements considered what's called an "instance"?
Yes

Or a stack?
The stack is the container, think of it as a blank sheet of paper that you can write on, either adding "things" at the bottom or to the right.

The "instances" are the things that we put into the list (stack).

When you create the XML of the UI context, you can (simplified a little) either put things into the stack (creating a static stack), or you can leave the stack empty in the XML and add the instances via Lua (a dynamic stack)

Think of a list of 2015 racing drivers. At the start of the season, the list(stack) of drivers is (pretty much) known, so the list(stack) of drivers can be created as a static stack. However, the grid line up for any particular race is dynamic, so we'd need to create an empty stack and dynamically add the drivers to it in their qualifying order (with Lua once the placings were known)

Or are they part of a stack that's part of a grid that's part of a box that's part of a context? :crazyeye:
A stack is usually placed within a grid or box (they're pretty much interchangeable) as grids/boxes give us the ability to place things at an absolute point on the screen (say in the middle, or top left) or relative to another box (eg a title centred at the top of a dialog box). The context is the outer-most container, there is only one per UI sub-screen.

So you will typically have a context that contains a grid (that forms the outer border of a dialog) that contains several boxes (to split the dialog into sub-areas, eg a long thin one at the top for the title text, another long thin one just below that for any needed tabs, and one taking up the rest of the internal space to put other stuff in) those boxes may contain other boxes (eg we may split the big box into two smaller boxes if we want left and right columns of stuff), and eventually one of those boxes will contain the stack.

What the heck is BuildInstanceForControl?
BuildInstanceForControl() is the Lua method used to add things to an empty stack, in the example above, what would add each driver in turn onto the "starting grid" stack

Where did ContextPtr come from?
ContextPtr is a (semi-)global that exists for every UI sub-screen, think of it as the Lua equivalent of the <Context></Context> tags in the UI XML file

See also "UI Tutorial 1 - Basics"

HTH

W
 
Sorry for the late reply and yes, I think that should help, thanks!
So for BuildInstanceForControl - is controlTable then, essentially, the pointer variable representing the instance? Based on the code directly following the block including ContextPtr, posted above:
Code:
local portraitOffset, portraitAtlas = UI.GetUnitPortraitIcon(info.ID, playerID);
			IconHookup( portraitOffset, 64, portraitAtlas, controlTable.Icon64 );
			controlTable.Help:LocalizeAndSetText(info.Strategy);
			controlTable.Name:LocalizeAndSetText(info.Description);
Since there's not a single icon hooked up to the entire stack - and a stack is the container of instances, right? - then controlTable probably doesn't represent the stack...

But there's this in the mayan UI:
Code:
<Stack Anchor="L,T" Offset="0,50" Size="560,650" Padding="10" StackGrowth="Bottom">
			<!-- Body Text -->
			<Label Anchor="L,T" Offset="30,0" WrapWidth="500" LeadingOffset="-4" Font="TwCenMT20" FontStyle="Shadow" ColorSet="Beige_Black_Alpha" ID="DescriptionLabel"/>
			<ScrollPanel Anchor="L,T" Offset="15,0" Size="500,430" Vertical="1" ID="ItemScrollPanel">
				<!-- Scroll Controls -->
				<ScrollBar Style="VertSlider" Length="400" Offset="0.18" Anchor="R,T" AnchorSide="O,I"/>
				<UpButton Offset="0.0" Style="ScrollBarUp" Anchor="R,T" AnchorSide="O,I"/>
				<DownButton Offset="0.0" Style="ScrollBarDown" Anchor="R,B" AnchorSide="O,I"/>
				[COLOR="Blue"]<Stack Anchor="L,T" Offset="0,0" StackGrowth="Bottom" Padding="0" ID="ItemStack"/>[/COLOR]			</ScrollPanel>
			<!--=======================================================================================================================-->
		</Stack>
I assume this is the generic button that's copied over as many times as there are GPs, since it's contained within the stack.
EDIT: Dang, I apparently missed this whole section:
Spoiler :
Code:
<Instance Name="ItemInstance">
		<Box Anchor="L,C" Offset="0,0" Size="560,53" Color="255,255,255,0">
			<Button Anchor="L,C" Size="560,53" Color="255,255,255,255" Offset="0,0" StateOffsetIncrement="0,0" ID="Button">
				<ShowOnMouseOver>
					<AlphaAnim Anchor="L,C" Size="560,56" Pause="0" Cycle="Bounce" Speed="1" AlphaStart="2" AlphaEnd="1">
						<Grid Size="560,56" Offset="0,0" Padding="0,0" Style="Grid9FrameTurnsHL"/>
					</AlphaAnim>
				</ShowOnMouseOver>
				<AlphaAnim Anchor="L,C" Size="560,56" Pause="0" Cycle="Bounce" Speed="1" AlphaStart="2" AlphaEnd="1" ID="SelectionAnim" Hidden="1">
					<Grid Size="560,56" Offset="0,0" Padding="0,0" Style="Grid9FrameTurnsHL"/>
				</AlphaAnim>
				<Image Anchor="L,C" Size="64,64" Texture="Assets/UI/Art/Icons/DifficultyLevelIcons256.dds" ID="Icon64"/>
				<Label Anchor="L,C" Offset="64,0" Font="TwCenMT22" ColorSet="Beige_Black_Alpha" FontStyle="Shadow" ID="Name"/>
				<Image Anchor="C,B" Offset="0,0" Texture="bar340x2.dds" Size="340.1"/>
			</Button>
			<Box Anchor="L,T" Offset="8,8" Size="560,36" Color="255,255,255,0" Hidden="1">
				<Label Anchor="L,T" Offset="0,0" WrapWidth="300" LeadingOffset="-8" Font="TwCenMT18" ColorSet="Beige_Black_Alpha" FontStyle="Shadow" ID="Help"/>
			</Box>
		</Box>
	</Instance>
But what's the point of the stack within the stack?
It's used later on, apparently:
Code:
Controls.ItemStack:CalculateSize();
	Controls.ItemStack:ReprocessAnchoring();
Is that just necessary so that the instances don't end up being placed on top of each other or whatnot?

Boxes and grids are interchangeable? :dubious:

And I assume it's possible to make a scroll bar to, well, scroll, through the stack of instances - but I'm not quite that far along yet; I think that's part 3 or so. Needless to say, it might behoove me to make that stack to begin with first.

(The "arms held straight out" bit makes it very hard to type!)
Probably not so much if you sat an arm's length away from your keyboard, which I don't, which I guess makes me a hypocrite. Oh well. :p

#AWCanIntoWorldNecromancer

EDIT: Basically, this is a rough sketch of what I'm hoping to make the end result:
 

Attachments

  • UIPopupVisual.png
    UIPopupVisual.png
    29.9 KB · Views: 121
So for BuildInstanceForControl - is controlTable then, essentially, the pointer variable representing the instance?
Short answer - yes controlTable represents the instance of the thing just created in the stack

Longer answer - controlTable is a Lua table (as indicated by the {} when it is created). Lua doesn't have the concept of a pointer, it uses "pass by value" and "pass by reference" to achieve similar results. When BuildInstanceForControl() is called, the controlTable variable, being a table, is passed by reference, which means that the code within BuildInstanceForControl() can change its contents. All the data representing the thing that BuildInstanceForControl() creates on the stack is placed within the controlTable table.

then controlTable probably doesn't represent the stack...
Correct. controlTable is the latest instance of the thing created on the stack (as the code is within a loop, the first time around controlTable will be the top and only item in the stack, the second time around it will be the item below it)
if you want the actual stack, you can use Controls.ItemStack (Controls is a semi-global variable, like ContextPtr, that contains an entry for every UI component that has an ID)

But there's this in the mayan UI: ... Dang ...
Yes, you need to understand the role of <Instance> within the context of dynamic stacks - I really recommend reading the associated UI Tutorial!

But what's the point of the stack within the stack?
In a word - layout

Code:
<[COLOR="magenta"]Stack[/COLOR] ... StackGrowth="Bottom">
    <[COLOR="seagreen"]Label[/COLOR] .../>
    <[COLOR="blue"]ScrollPane[/COLOR]l ...>
        <[COLOR="darkorange"]ScrollBar[/COLOR] .../>
        <[COLOR="darkorange"]UpButton[/COLOR] .../>
        <[COLOR="darkorange"]DownButton[/COLOR] .../>

        <[COLOR="red"]Stack[/COLOR] .../>
    </[COLOR="blue"]ScrollPanel[/COLOR]>
</[COLOR="magenta"]Stack[/COLOR]>

The outer most stack is used for layout, it has two inner items
At the top, a label, below that a panel. It doesn't matter how tall the label is, the panel will always nestle below it - that's what stacks do, arrange their inner components shuffled up to each other.
The panel, is a scroll panel, it contains four inner items
Three of them make up the slider (the scroll bar, an "Up" button at the top and a "Down" button at the bottom) that appears on the right hand side.
The other is our dynamic stack (we can tell that as it contains nothing), that the button instances will be placed in with Lua.

Now, when the game core UI code reads the xml file there is nothing in the dynamic stack, so it takes up no space on the screen. After we have used Lua to add the items, we have to tell the UI to work out how big the dynamic stack now is and redraw it. But the dynamic stack is (usually) inside a scroll panel, so we also have to tell the scroll panel to recalculate what it contains and set up the slider as appropriate, and part of that is ...

Code:
  Controls.ItemStack:CalculateSize();
  Controls.ItemStack:ReprocessAnchoring();


Boxes and grids are interchangeable? :dubious:
A <Grid> is just short-hand for a <Box> with lots of graphical elements to make it look pretty - see (IIRC) the game core Styles.xml file.

And I assume it's possible to make a scroll bar to
See the three items in Dark Orange above

I think that's (UI Tutorial) part 3 or so.
Which you really need to read if you're going to use dynamic stacks

W
 
this is a rough sketch of what I'm hoping to make the end result:

I'd approach this as
Code:
an outer grid (to get all the sexy graphics) containing
    (optional) decorative elements (side handles, top scroll work)
    a label for the heading
    a dividing line
    a label for the information
    a dividing line
    an inner box containing
        an "awesome background art" image
	    a scroll panel containing
	        the three components of the slider
	        a dynamic stack
    a dividing line
    the close button

You will also need the standard context stuff, and also the <Instance> for the items being placed into the dynamic stack

The item instance could be
Code:
a box containing
    an image for the icon
    4 labels for the lines of text
    a button
 
"awesome background art" is more what I was trying to make as, well, background art that all the instances are placed on top of - like that picture of the great prophet for the Choose Religion popup.

More recently, for each instance, I've considered removing two of those three lines of text and replacing them with an additional two buttons. So I guess the end result looks like this:
Code:
an outer grid (to get all the sexy graphics) containing
	(optional) decorative elements (side handles, top scroll work)
	an "awesome background art" image
	a label for the heading
	a dividing line
	a label for the information
	a dividing line
	an inner box containing
		a scroll panel containing
			the three components of the slider
			a dynamic stack containing instances of
				a box containing
					an image for the icon
					2 labels for lines of text
					A non-dynamic right-growing stack containing
						A button
						another button
						still another button
	a dividing line
	the close button
Unless I don't need that last stack.

I don't think I've ever gotten this many answers right during an inquiry in this thread :lol:... and simultaneously still been largely confused.
I guess the next question would be... if the instance has to be added to the dynamic stack, where do I place it in the XML? Near the top, like the mayan popup does?

Meanwhile, to make one of three buttons work, I need to be studying up on another facet of the inner workings of Sukritact's events popup: namely, how the DoFunc part works. The DoFunc is a function, no? But decisions are fed into a table... meaning it's somehow possible to call a table value like a function, apparently. And that's what I'm (hopefully) about to find out.
EDIT: Ah, well, that was a little less intricate than I expected:
Code:
tDecision.DoFunc(pPlayer, tDecision.Data1, tDecision.Data2)
 
Top Bottom