cardmaker icon indicating copy to clipboard operation
cardmaker copied to clipboard

[Feature Request] Programmatic override of Card Count

Open MarkVabulas opened this issue 4 months ago • 16 comments

Lately I've been going through different parts of the software (as a user) and I was wondering if it would ever be possible to have a setter for the count of cards to print, such as: $[count:15]. This would pay dividends during the SubLayouts as well, because we could also ignore things programmatically, but from time to time I've found myself wanting to be able to change the card count independently of the spreadsheet. Is this even remotely possible? Additionally/alternatively, we have a #nodraw for a given element, could we get #nocarddraw for the entire card to just get ignored if it ever finds that value?

MarkVabulas avatar Apr 06 '24 21:04 MarkVabulas

Card Count Override

My gut reaction is that anything messing with card counts really should be handled outside of the application.

The count of cards within an individual row is handled as part of reference reading. The rows are actually duplicated in the DeckReader for use with things like the Sub Counter logic. It's a system I wouldn't want to mess with too much.

What are the use cases where you found that overriding the card count would be helpful?

Card Count On Layouts (without references)

Not sure if you were thinking of any specific use for overriding this one.

nocarddraw

That's an interesting one. On export this just wouldn't create a file? What would this do in-app on the Canvas, possibly render of message indicating that the card won't be exported?

nhmkdev avatar Apr 06 '24 23:04 nhmkdev

So my use case for either of them is really just to reduce the count to 0, to disable the card from performing the rendering or the file output.

So in my SubLayout world, and a few other times (I can't remember off the top of my head) it has seemed useful to cancel the processing of a particular line in the excel spreadsheet, but to do it programmatically. For a SubLayout, for example, if I invoke the SubLayout through a ParentLayout, and it's signaling that it wants to use an override card instead of a default card, then each one can check for the request of the custom card and "disable"/"not disable" based on that. So If I have 10 base cards, and 50 custom ones, I don't have to make all 60 cards for my SubLayout (which I'm perfectly fine doing), I can have each one check against the contents of the PrimaryLayout fields and perform a #nocarddraw somewhere if it's not in the list of cards which are necessary.

I think having #nocarddraw would also allow a different way of generating cards and card counts based on parameters. If we wanted to fill out our single-row spreadsheet with a card count of 1000, but we dropped in a #nocarddraw inside a computation involving random numbers or specific outputs, then it could automatically handle the cases for us where we don't want 1 of those particular cards output because the values don't fit the equation, but we would still get all of the cards which do. (Give me every prime-number card, programmatically, or only Fibonacci card numbers/values) This would of course be possible through a spreadsheet, but now you're messing with rows in a spreadsheet instead of just a single count number (and/or other parameters) which would determine if a certain card gets spit out or not.

As an extension of the previous example, technically being able to increase/augment the Count based on a calculation would be more streamlined than having to pre-calculate it by hand. So for example we want to just change 1 value from "Flip over @[Cards_To_Draw] cards" to "Flip over @[Cards_To_Draw] cards" but elsewhere it uses that value to change the actual number of cards that get printed, having programmatic control over card counts would be sweet.

MarkVabulas avatar Apr 07 '24 08:04 MarkVabulas

I found another use for the #nocarddraw, debugging layouts: While going through and testing my SubLayouts, and other Layouts with many many configurable options, it would be nice to have the ability to turn on a debug flag in a _defines.csv and then all of the debug outputs run alongside any other cards. That way, I can have many test combinations for placement/organization within a layout, and not have to constantly toggle them on/off through the card count.

MarkVabulas avatar Apr 07 '24 10:04 MarkVabulas

Breaking things down to discrete pieces of functionality I'm considering:

Translation for the Card Count Column

Card counts are currently read as static numbers. They can only be manually adjusted. At the time of reference read the defines are available. A simple translation in the card count column could be easily (well hopefully) supported.

This way a define set could look like this:

define value
move_action_count 1
harvest_action_count 0

And a Reference could look like this:

count action
@[move_action_count] move 3 spaces
@[move_action_count] move 5 spaces
@[harvest_action_count] harvest 3 resources

#nocarddraw

I am definitely leaning away from this because by the time there is element translation taking place the reference and card counts have already been applied.

Alternative: Defines Passed Into SubLayouts

With the Translation for the Card Count Column item above combined with Passing defines through to the SubLayout (or Passing custom defines to a SubLayout) mentioned in https://github.com/nhmkdev/cardmaker/issues/141 The count of a given row could technically be controlled by the parent layout.

Acknowledgement

The proposals here will not be used by many users of the application. They can be extremely complex and require a lot of planning and understanding for a user. I always take some caution when implementing these special functions as the stack of things I have to support grows each time the application expands. With hundreds/thousands of existing project files out there the last thing I want to do is break everyone! 💥

nhmkdev avatar Apr 07 '24 19:04 nhmkdev

So I don't particularly see a problem with when the #nocarddraw is actually eventually executed. For example, let the full incept translator run on all columns, and if any of them ever turn up the #nocarddraw, then we can store it in a similar way to #nodraw for an individual element. The only time that #nocarddraw would ever come up is during the rendering phase, where the card would be skipped in rendering/saving, but would otherwise NOT impact card count totals etc. This means if we had #nocarddraw on every even card, we would have Example_1.png, Example_3.png, Example5.png... etc in the final output folder, and all variables inside each one would correctly call themselves card 1, 3, 5.... it's just that we wouldn't have to do the time consuming process of rendering/file saving for the interspersed files.

When some of my cards are currently taking 10-15 seconds (for the rendering/saving phases together), but the incept translation is milliseconds, then the goal is merely to fix the most processor-intensive parts. I don't think anyone would expect #nocarddraw to function differently, it would literally be a "skip me" type of command, where the card is ignored after all translations are performed, but also after all other card indices/positions/counts are finalized.


I can understand wanting to avoid programmatically changing the card count, but #nocarddraw would pay dividends in processing time, and it would just be 1 check of an if statement (then continue) at the beginning of the loop which does each card's final rendering output.

MarkVabulas avatar Apr 07 '24 23:04 MarkVabulas

The only time that #nocarddraw would ever come up is during the rendering phase, where the card would be skipped in rendering/saving, but would otherwise NOT impact card count totals etc.

Ah, okay thanks for the clarification! :+1: As long as the counts and otherwise aren't impacted then I definitely support the idea and can add it to my todo list.

As rendering on screen itself probably wouldn't be impacted much is there another name that might better describe what will happen? #noexport ? 🤔

nhmkdev avatar Apr 07 '24 23:04 nhmkdev

I give a thumbs up to #noexport. :)

MarkVabulas avatar Apr 08 '24 08:04 MarkVabulas

Initial submission of #noexport functionality: https://github.com/nhmkdev/cardmaker/commit/6be203a384728442f4efeb1be583b849b75ea881

There are likely some positioning bugs related to stitched image exports and pdf exports. Definitely more cleanup in a future commit.

nhmkdev avatar Apr 08 '24 14:04 nhmkdev

Testing the #noexport works great! (for my suggested purposes)

Additional request

  • can we ignore the flag for the purposes of canvas rendering?

Currently it seems to be running even in preview mode

MarkVabulas avatar Apr 09 '24 01:04 MarkVabulas

Additional request

* can we ignore the flag for the purposes of canvas rendering?

Certainly could let it render the whole card on the Canvas. I was planning on adding an indicator that a card is being marked as #noexport when drawn to the Canvas. What do you think of some rendered text or otherwise?

nhmkdev avatar Apr 09 '24 01:04 nhmkdev

As for signaling if it would be removed:

  • Maybe we can put it in the title of the canvas window?

Also, this is how I implemented the usage:

#(if @[UnitModelSubLayout,@[UnitType]] != Faction_Sheet_@[UnitName] then #noexport)#

And here's the defines it relies upon: UnitModelSubLayout -> #(if @[{1} Unique] == #empty then Faction_Sheet_{1} else Faction_Sheet_@[{1} Unique])#

In the SubLayout, I have a bunch of empty fields for [{1} Unique], and then in the PrimaryLayout I fill in values such as Special_Fighter, which ends up getting used. The Normal fighter gets skipped over during the SubLayout since the default name doesn't match the generated name, and the unique fighter does get generated because it matches the field name coming from PrimaryLayout. The FileExportNameOverride on the SubLayout is translated/saved as: Faction_Sheet_@[UnitName] Each SubLayout row has a UnitType and a UnitName, the UnitName is what is referenced by the PrimaryLayout and the generator, and the UnitType is to know what field to look for and to generate the name of the default card.

Because of #noexport, it only makes the files necessary for each run. Here's what the folder looks like after it's all generated: image

Before #noexport existed, it was generating all of those files for each PrimaryLayout, which meant they were all the same color Faction_Ships even if they were unique to 1 faction. Now, they end up being different card colors because they're only generated as necessary, and sometimes even the default cards are skipped when overridden.

TLDR; the final outputs look great and it's 70% faster now to generate it all.

MarkVabulas avatar Apr 09 '24 09:04 MarkVabulas

#NOEXPORT

The card will render in the UI but shouldn't export now.

I attempted to add to the Canvas title but the timing is breaking intermittently and I'll investigate later (harmless for the most part).

nhmkdev avatar Apr 09 '24 14:04 nhmkdev

This functionality is now in (very lightly tested):

Translation for the Card Count Column

Card counts are currently read as static numbers. They can only be manually adjusted. At the time of reference read the defines are available. A simple translation in the card count column could be easily (well hopefully) supported.

This way a define set could look like this:

define value
move_action_count 1
harvest_action_count 0

And a Reference could look like this:

count action
@[move_action_count] move 3 spaces
@[move_action_count] move 5 spaces
@[harvest_action_count] harvest 3 resources

Coming up next (when time permits)

When specifying a sublayout in the sublayout element provide a way to specify in-line defines (key+value). This way you can customize a card count using the above functionality.

nhmkdev avatar Apr 09 '24 15:04 nhmkdev

Submitted but still play around with overriding defines when specifying a layout in the SubLayout element: https://github.com/nhmkdev/cardmaker/commit/933d94548fb6ca3e6548a01f9209ae9d28b04979 Also attempted a fix to the display of #noexport on the canvas. Should be working as it's event driven now...

It's a slightly risky change...

SubLayout Elements (Previously)

Specify the name of the layout: SubLayout (example)

SubLayout Elements (Now)

Along with the normal functionality above it also supports specifying parameters and a set of override defines.

[layout name]::[parameters]::[define;value];[define;value][repeated as necessary]

Full example: SubLayout::::message;from primarylayout;move_action_count;2 (while the :::: looks funny it will be nice to support parameters in the future) This will create the following defines for the SubLayout to use:

define value
message from primarylayout
move_action_count 2
  • Parameters are intended for future use so it's just an empty set.
  • Override defines are top level overrides in this case. If specified they will be passed onto the SubLayout even if the parent layout provided the same value. (might be some argument for not doing so... but it seems like a Layout should be able to control what its direct SubLayout receives)

Using the above example -- Now a SubLayout can have its card count driven in-reference by @[move_action_count] that is provided as an override in the element definition.

nhmkdev avatar Apr 10 '24 00:04 nhmkdev

I'll check it out!

MarkVabulas avatar Apr 10 '24 09:04 MarkVabulas

Known issue (update coming): The translation of the SubLayout element should be performed with each row, not just once during export setup.

Updated: https://github.com/nhmkdev/cardmaker/commit/e91b2501ef3d8abd63ebf0d775c5521fe98c2eb1

Translates per-row (necessary, but slightly more processing... can always be optimized later)

nhmkdev avatar Apr 10 '24 12:04 nhmkdev