brehaut / manticore Goto Github PK
View Code? Open in Web Editor NEWA program for generating 13th Age encounters.
A program for generating 13th Age encounters.
click
event) results in a ~300ms lag on mobile as the browser waits to see if the user is double clicking.ontouchend
looks successful on first pass, but will easily capture spurious taps when the user is simply scrolling the app. Particularly problematic in manual picker mode as theres almost no screen space that is not a tap target and the list is very long.Some sort of ontap
or ontouch
synthetic event needs to be picked up by the DOM library and attached as a touch equivalent to onclick
.
Data storage, access, and processing should move to web workers.
Goal is to get all the data stuff into two workers to more cleanly separate the UI from data and processing.
Processing should specifically move to workers to prevent blocking the UI and to (in future) allow continuation of a search through potentially expensive sets
Some apex monsters may be considered territorial: they won't appear in an encounter with like monsters. Most notably dragons of any colour or size.
Some (optional?) mechanism that allows post-generation filtering of encounters to remove those that include more than one instance of a territorial monster should exist.
It may be reasonable to implement this using a tag on monsters. However, if this tag extends beyond dragons simply filtering based on the territorial tag would eliminate a potentially reasonable encounter featuring say a white dragon and a vampire master.
Filter out encounters that contain more than a provided maximum monsters, and/or fewer than a minimum specified by the user.
User specified maximums will have the side effect of more quickly exploring the search space for large plate parties.
Windows font rendering causes the UI to be a bit spidery and less legible than it could be. This is particularly problematic for non-viable selections in filters and some smaller text
Once issue #35 is complete, the dataset can be updated to include the new monsters listed in Bestiary 2. Note: Page numbers can't be populated till the final print layout is complete. Until then all the page numbers will list 0
attributes
setsAllow the user to set maximums on specific monsters, and on various taxonomy fields. Instead of acting as a filter post generation, this would filter the available list of monsters as generation occurs. This may be better suited to work after implementing web workers (#29).
The goal is to produce more useful initial sets of results so that scanning the output is easier.
This is a more general case of territorial monsters (#5)
Examples
A probably implementation would revolve around predicates limiting the scope of repeats
in bestiary.ts allocateMonsters
Limiting the lower bound is a much tricker problem
When generating encounters the UI should throw up an activity indicator as spinning up the worker process can take a few seconds (this seems to be a regression due to moving to downlevel iteration)
Bestiary 2 includes new classifications that impact the costing of monsters: Elite and Weakling monsters. These appear as variations of 'size' trait. There are a number of steps required to implement support for this:
weakling
and elite
classifiers. Also include double
and triple
.manticore.data.newMonster
to normalize the new sizes into a `ScaleFactormanticore.costs.scaleFactor
to take into account these new sizes.mook
monsters assumed they never occurred with double or triple strength monsters. This is wrong.elite
as both size and type fields depending upon the monster. The final PDF corrects this but in doing so introduces new size large elite
. There is currently no huge elite
in the bestiary.The search algorithm can trivially produce a very large number of results. For larger parties and/or higher levels these results can be small variants of the same thing (just changing quantities for instance).
Manticore should provide optional controls to specify sorting rules for prioritising certain breakdowns of encounters.
Suggested algorithm is to calculate an absolute delta percentage for each attribute specified by the use, and summing these. The smaller to total delta distance the better.
For example the user may specify 30% mooks and 25% leader. A encounter with 20% mooks and 50% leaders would have a delta of 10 + 25.
The 13th Age SRD provides fragment identifiers for every monster entry. For example: the Manticore.
Questions that need to be answered before this is implemented:
Feedback from a screen reader user regarding the checkbox elements used in the various filtering controls:
"The controls seem to be clickable elements, but they aren’t standard checkboxes and radio buttons and the like. It’s hard to tell what state they’re in when I set up a smart filter—they read as “check mark,” no matter what"
All monster contain a set of tags that describe various aspects of them. For instance a dragon has both the 'dragon' tag and a colour tag eg 'white'. With dragons this is clear. All dragons have both tags. As the colour tags always exist with the 'dragon' tag it can be considered a sub tag.
In other cases a monster may have two tags that have a tag and sub tag relationship that is not so clear cut. Eg a zombie shuffler is both a zombie and undead. However a wight is only undead — leaving aside for now that wights might suitably me tagged as ghosts, ethereal, or some other classification. Adding a single tag for 'wight' would create noise in the UI but not including a sub classification means that from a filtering perspective only 'undead' would match.
If meta tags are reasonable, should there be tags for humanoid (humans, elves, dwarves…), and goblinoids (goblins and orcs), and are goblinoids also humanoids as they are intelligent bipedal creatures.
If sub tags are accounted for, will they require improved UI in the filters interface?
It would be advantageous for a GM to be able to save an encounter for later reference.
Saving locally by localstorage or similar useful. May also be valuable to share via URL hash
When the bestiary is filtered it may produce only a small number of monsters. Currently there is no feedback about how many of those are viable for the current party configuration.
Filters should instead of listing selected monsters, should provide a count of the viable monsters, eg those that are within the level restrictions of the Building Battles table.
For very narrow monster selections its possible that the user might generate a set of encounters that are significantly below the total cost they need for the chart. The remainder and a badge marking an encounter as easy if it crosses a threshold should be listed.
Have you considered exposing the service via an API? It may help developers of other 13th Age tools if they could generate encounters via your service's logic.
An alternative thought would be to separate the core logic from the UI (core logic in one repo and UI in another with the logic as a submodule) so it would be easier to integrate the encounter generator into other applications.
Entires for the 13 True Ways are not included (I do not currently own or have access to a copy).
Data needs to be entered as a new book in static/data/bestiary.json
.
Party size and level is likely to be a relatively stable value for a given GM.
Manticore should store this in local storage (falling back to cookies if required).
Ideally this bestiary will provide monsters from all the published 13th Age material.
The program supports multiple books in the dataset (static/data/bestiary.json) but only the core book is included as currently that is the only 13th Age book I own.
In addition to the inclusion of additional books, the books need to become a filterable control. This probably needs to be in a section of the filters view that comes before the primary filters (see #2)
Some output in the generated encounters referencing books is probably helpful.
The selection mode control (filters, manual picker) wraps strangely on iPhone sized screens. This should probably become a toggle style control too.
The Typescript used in the project is a version behind the currently available version. With the new typescript React fails to compile, so react also needs to be upgraded; this should be done with a typings installation rather than vendoring the type definition files manually.
Due to some shenanigans with gulp-typescript etc, the typings are ambiently included in all build tasks regardless of whether they should be excluded or not. Possible mitigations include moving to modules rather than namespaces and references. This may entail using something like webpack to bundle the compiled code.
Monsters that are classified as wreckers and/or can use the escalation die should be annotated in results. These encounters are more dangerous than the norm.
Going forward the project will need to implement a service worker that matches the behaviour of the application cache manifest.
For more information: Service Workers
The appcache manifest cannot be removed until some time after Safari supports service workers.
Monsters should be grouped by their distinct types regardless of the counts per encounter. For example: Generating an encounter for 4 level 2 characters using normal sized troops of goblins and orcs will result in 4 permutations that include hobgobin warrior & orc berserker that just changes the ratio of constituents.
Ideally the encounters will be grouped by the distinct types. This will cause all the encounters with the same types to appear together whereas they are currently scattered about due to the way the sort algorithm works. It will also reduce the amount of space they take up on the UI
Currently every monster in the currently available data is listed in the manual picker. Users may wish to reduce this down to just the books they have on hand.
This use of the sources picker is different than on the filter selection view as it updates the list the user can pick from.
When a source is hidden any existing selections within that source should be deselected (and no longer appear in the results)
Some users want to be able to restrict the range of monster level that are used to generated encounters:
This seems like a sensible thing to add to the smart filters
Add groups with headings for A, B, C... Z for the manual monster picker to make it easier to navigate.
If non-alphabetic ordering is support (such as by level) then this should switch to be meaningful grouping for that classifier (eg, 'Level 1', 'Level 2' ...)
Entires for the 13th Age in Glorantha are not currently included.
static/data/bestiary.json
.Spoilers don't do as much damage directly as other monsters, and instead cause effects on the characters. True filtering should warn the user if only spoilers are in the selected list of monsters (regardless of how they are chosen), and the generation process should threshold the number of spoilers per encounter.
Users have requested a way to reduce range of the levels of monsters selected for generation.
This filter is probably best implemented as two range sliders: one for down and one for up. The labels on this slider need to shift based on the tier of the party configuration.
Currently the monster picker is always sorted alphabetically by name. It would be reasonable to also support sorting (and grouping) by level, size, type, or book.
To support #39 there should be a function that applies normalizations to strings for sorting and alphabetacizing.
Once Issue #35 is complete the existing datasets can be improved in two ways:
weakling
for any monster in 13 True Ways that may have been erroneously missed.large
or huge
but are more accurately described as double
or triple
strength.To improve clarity about what a filter operates on and when it operates, an additional checkbox should be added to property filter pickers: unfiltered / not this filter / no 'X' filter.
With the addition of Bestiary 2 data the list of tags and manual monster selection are unwieldy now: far too many items listed.
For a first pass improvement these lists should be grouped alphabetically.
Suggested markup would be a dl
containing dt
/dd
pairs for each letter, and existing styled checklist lists within the dd
.
The web font specified via the google web font CSS api does not cache correctly with the app cache and will flip flop between available and not available on iOS, resulting in a fallback to serif.
Following on from #42 the compilation of fallback scripts needs to change:
common.js
now contains the iterator code that was previously in processing.js
/ processing-fallback.js
common
contains code that is only used on the allocation processing worker and should be extracted / movedThe common script itself needs to work without modification in both environments as its included in the page as well as imported via importScripts
. Faffing about with adding scripts tags dynamically on the page is a layer of complication and surprise that can be avoided.
The introduction of manual selection of monsters in 0.4 highlights the need to improve the sorting of monsters by name. For instance, it would be valuable to sort monsters by their type, followed by their modifier rather than just simply lexographic name order.
For example, the user may wish to have Headless zombie, Human zombie, Ice zombie, Zombie beast, and Zombie shuffler be grouped together under as 'Zombie' type monsters.
The only mechanism for selecting monsters is via the simple filtering system. Users may wish to specify specific monsters from the bestiary that they want turned into encounters.
This should be an alternative to the current filtering system. Probably hidden behind a tab.
Note: the book selection filtering mentioned in Issue #1 should apply to this list of monsters and actually update the UI.
Entires for the 13th Bestiary are not included (I do not currently own or have access to a copy).
Data needs to be entered as a new book in static/data/bestiary.json
.
With typescript support, porting to React may be a viable, and productive, upgrade.
Core JS shims would allow the use of ES6 datastructures (specifically Map and Set) that may cleanup some logic dramatically. Additionally would remove the need to manually be shimming various ES6 APIs (such as Array.of, Array.from...)
The count of viable monsters for a given filter are currently only taking into account the party information, not other filter groups.
This means that the information can be misleading. Viability counts should take into account all other filter types available.
This one is potentially a bit messy to implement, and could potentially be a time consuming / slow op.
Hello!
I had an idea about adding some options to encounter generation to make it easier to find what i want and make the resulting list smaller. Things like "include at least 1 soldier, 1 leader and no more than 4 mooks". Instead of suggesting it, i decided to try an implement it, even tho i'm a desktop application dev and don't know nodejs or java/typescript that well.
Anyway, i made myself an ubuntu installation in a virtual box and set up node, npm, gulp etc. TL;DR First time compiling the code i got this error message:
`src/ts/app/manticore.ts(61,9): error TS2345: Argument of type '(party: IParty, monsters: Monster[]) => Promise<{}>' is not assignable to parameter of type 'Allocator'.
Type 'Promise<{}>' is not assignable to type 'Promise<Allocation[][][]>'.
Type '{}' is not assignable to type 'Allocation[][][]'.
Property 'length' is missing in type '{}'.
/home/cousken/git/manticore/src/ts/vendor/react/react.d.ts(162,11): error TS2559: Type 'Component<P, S>' has no properties in common with type 'ComponentLifecycle<P, S>'.
[21:29:37] TypeScript: 2 semantic errors
[21:29:37] TypeScript: emit succeeded (with errors)
/home/cousken/git/manticore/src/ts/workers/data-access/dataset.ts(34,27): error TS2345: Argument of type '(_: any) => Promise<string>' is not assignable to parameter of type '((reason: any) => PromiseLike<never>) | null | undefined'.
Type '(_: any) => Promise<string>' is not assignable to type '(reason: any) => PromiseLike<never>'.
Type 'Promise<string>' is not assignable to type 'PromiseLike<never>'.
Types of property 'then' are incompatible.
Type '<TResult1 = string, TResult2 = never>(onfulfilled?: ((value: string) => TResult1 | PromiseLike<TR...' is not assignable to type '<TResult1 = never, TResult2 = never>(onfulfilled?: ((value: never) => TResult1 | PromiseLike<TRes...'.
Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible.
Types of parameters 'value' and 'value' are incompatible.
Type 'string' is not assignable to type 'never'.
`
The website works fine however. So i'm just letting you know.
At some point since the last release the party numeric draggers appear to have stopped working in both chrome and safari.
Hello!
Thanks a lot for your very guiding messages on my previous issue, i've had a lot to do but i should have a little more time soon. Also i've engaged a web developer friend of mine, so he can help me out on the way.
Since i took all the recent changes today i am unable to compile with this following error:
stream.js:74
throw er; // Unhandled stream error in pipe.
^
Error: ./build/js/workers/data-access.js
Module not found: Error: Cannot resolve 'file' or 'directory' ./data-access/Party in /home/cousken/git/manticore/build/js/workers
resolve file
/home/cousken/git/manticore/build/js/workers/data-access/Party doesn't exist
/home/cousken/git/manticore/build/js/workers/data-access/Party.webpack.js doesn't exist
/home/cousken/git/manticore/build/js/workers/data-access/Party.web.js doesn't exist
/home/cousken/git/manticore/build/js/workers/data-access/Party.js doesn't exist
/home/cousken/git/manticore/build/js/workers/data-access/Party.json doesn't exist
resolve directory
/home/cousken/git/manticore/build/js/workers/data-access/Party doesn't exist (directory default file)
/home/cousken/git/manticore/build/js/workers/data-access/Party/package.json doesn't exist (directory description file)
[/home/cousken/git/manticore/build/js/workers/data-access/Party]
[/home/cousken/git/manticore/build/js/workers/data-access/Party.webpack.js]
[/home/cousken/git/manticore/build/js/workers/data-access/Party.web.js]
[/home/cousken/git/manticore/build/js/workers/data-access/Party.js]
[/home/cousken/git/manticore/build/js/workers/data-access/Party.json]
@ ./build/js/workers/data-access.js 13:16-46
To make sure i did a git clean, an the result are the same. Steps are - clean repository - yarn - gulp -> receive error.
what it says on the tin
React is generating warnings about missing 'key' attributes at runtime.
Each child in an array or iterator should have a unique "key" prop.
Components listed as being affected:
Users should be able to bookmark and refer to selections using the browsers built in behaviour. eg:
http://manticore.brehaut.net?party=4,2&smart&sources=13th-age+bestiary&role=troop+mook
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.