history
This app started as a hack of path-o-logic's RandListGen, with ideas from Jeremy Hamilton's GMEmulator.swf open source flash app. What does that mean? It means you can ask it a question, and it will provide an answer as best it can, it's a tool used for GM-less play. It also means you can put in some lists of items, and have it spit an answer back by picking an item randomly. I ended up re-writing all of the RandListGen code from scratch, but credit is due where credit is due. But, as luck would have it, the help section for table parsing on that site works for both. I'd say the tables are vaguely compatible with Bruce Gulke's TableSmith or Inspiration Pad Pro, or the tables at Abulafia. Again, credit is due where credit is due, those are all excellent programs.
Support: ranDM Solo will always work best on the latest browser. Safari is my development platform; I test major releases on the latest versions of Google Chrome, Mozilla Firefox, iOS Safari on iPhone and iPad, and a Motorola Droid X2 Android Device. If you find a bug, let me know, I can be found on Google Plus.
- v0.2: unreleased, core functions work, fudge parsing broken, ui bad, screenshots prove it existed.
- v0.3: question parser updated, bugs squashed, fudge fixed, ui not as bad but still bad
- v0.4: kraken released, shared with to g+ lone wolf community, ask parser fixed, ui fixed, appcache, dropboxenated, webapp mode validated on iOS
- v0.5: save and load to html5 localstorage, help button actually toggles div, nasty modal alertses, we hates them, 1024x1024 icon, updated help
- v0.6: replaced dice parser when called from ask menu, it now supports standard math and fudge within parser. toggle for showing individual rolls, settings div.
- v0.7: replaced css multicolumn layout hell with flex layout bliss, standardized buttons, selects
- v0.8: replaced data backend: reductive table queries that attempt to guarantee unique results, multi-format import, removed path-o-logic functions, results bug squashing, fairly full unicode / emoji support.
- number of table formats supported on import:
- original flavor: tables defined with |table
- original flavor: tables called with [table]
- original flavor: table item qty defined by n@ at line start
- new recipe: table definition |table or ;table or :table
- new recipe: table call [table] or {table}
- new recipe: table item qty defined by n@ or n, at line start -- this should make importing tables designed for your use from other table generator products easier to import.
- new recipe: table item indices (e.g. 1), 2) or 1. 2. etc.) automatically removed, option coming to toggle...?
- v0.8.1, bugfixes only, replaced question text, firefox enter bug squashed, offline functionality restored
- v0.8.2, help text update
- v0.9, more parser udpates: variables, evals, runs, programming; undefined result bug for empty row squashed, NoTableNamed bug squashed for mixed case table names, even newer help text, dice rolls can be used for distribution in tables: |tablename^2d6, or at call: [tablename^2d6] for better probability distribution, migration to promise-backed asynchronous IndexedDB for list backend. It's log, it's log, it can append or prepend to the oracle log area depending on your preference, it's better than bad it's good. auto save on window close, auto load on window open.
- v0.9.1, bug fixes
- v0.9.2, more bug fixes and the addition of the Scarlet Heroes engine, updated help text
- v0.9.3, new engines added: so1um and Tiny Universal!
no bugs were fixed this time, only introduced. Scratch that, Steven Lincoln found a bug where year-old versions of this tool wouldn't update!
- v0.9.3 part deux: updated localforage in manifest from 1.2.6 to v1.5, giving us a default storage of indexedDB, which hopefully solves weird storage bugs. as always the latest macos and ios recommended (ditto android though google's standards support tends to be better than apple's).
- v0.9.4, new engines added: Tiny Solitary Solders Solo and what I'm calling "randm questions". clarified help text on 'add to home screen'
Features, ideas, plots, plans
- engines I could add
Tiny Solitary Soldiers Solo RPG, needs scene alterations in scene code but not a big deal. done! except for scene alterations.
- Freeform Universal, unknown licensure. CC? purchase
here for about $3.
- John Fiore's 9qs. Not trivial but not impossible either. it's definitely a new set of structures to
implement. I would need generic and free licensed vector art to simulate the results, and the scene button would need to be altered to indicate different scene structures. that's not
impossible, but a lot of stuff needs to be modified to implement. someone already did this? (edit: yup, game icons
are available under CC AT license at game-icons.net
- GM's Apprentice by Larcenous Designs. Another one that's tough to implement as it
is, since it would require folks to own the cards, and to have named them just so, and for them to own the cards, and named them locally just so... but I could see this going into a
different webapp, reductive tables are already there, and the results are just img src = blah in a reductive table, most of the functions are already done. this could be interesting.
120 cards in fantasy, 120 cards in scifi. someone already did something like this... Todd Zircher? (edit: Yup, as usual
Todd is ahead of the game)
- Fate Solo by Cabbage Games from Kenny Norris at soloroleplayer.com (closed down?).
- UI Cleanup
- a settings div that shows and hides to clean up and minimalize the UI
- dynamic textarea sizing for NPC, PC, Thread lists
- pastebin editing mode
- import/export pastebin from JSON / save to text
- maybe do something clever with SVG. Story cubes, except I don't want to make that art.
- multi-saves: save npc, pc, threadlist, and log to separate hashes which can be loaded and stored on demand. localstorage might be a good candidate for this, or a separate localforage db.
JIT/local storage retrieval/partial hash evaluation to keep memory footprint light and fast? moved to localforage, likely to continue.
- implement the caret (^) as a parameter to table calls to return an array item index. solves table bloat for tables best called with 2d6, etc. -- [encounterlist^1d8+1d12] or {encounterlist^1d8+1d12}. done in getrandomarrayitem function, but not explained in help. works for ^2d10, not for ^1d8+1d12. might be nice to include this in the table storage function, e.g. |encounterlist^1d8+1d12 and store it as 'roll' under the array hash.
- solve duplicate table name problem, probably with '.' as the divider, but consider other options (: or ^). e.g. [utility.color], [modern.newnpc], [modern.newnpc^2d6].
var tablerolldef = {}; tablerolldef[tablename] = roll; if (tablerolldef[tablename]){ roll = tablerolldef[tablename].roll}
it would be nice to be able to save certain table results as variables. could implement call or lookup with [[tablename]] or {{tablename}}, or [tablename[varname]], or [tablename$varname], or [tablename%varname%], or tablename^roll^varname, or denote a table lookup to be stored with ||tablename. easier if this is done on a per-call basis. tablesmith uses %varname%, IPP uses [@tablename] done!
additional tablesmith-compatible dice rolls, e.g. {Dice~1d10} skipping this.
- indefinite articles parsing at return., replace "a elf" with "an elf". probably use special menu tags? e.g. [a][tablename], [a^tablename], ipp: \a [tablename]
- shortcut multi-calls to tables: ora 6*[modern.newnpc] or ora 6@[modern.newnpc] or something I haven't thought of yet.
- method to detect html results and either strip tags and append to log text, or redirect output to results area... or convert the log area to text.
- mythic events (and cards) are currently separate call and data structures, integrate them and the new scene / end scene bits into the results of the ask engine. remove their buttons? buttons optional in settings?
- current method of weighting priority duplicates array entries, which is needless bloat. I could stuff a hash table in front, but I always say that.
- make future choices based on performance, jsperf or some such
- cloud saves or some such to support multiple devices. Probably CORS instead of JSONP. Cloudkit JS, REST Core API v2 to Dropbox, Google Drive,
this looks promising, as does this,
or this, and
this.
- dropbox core api v2
- cloudbase
- Facebook parse, shutting down but many open source implementations exist
- appcelerator
- nimbusbase
- the unhosted / nosql movement
- Azure/AWS
- Google Cloud, claims to be half price of similar AWS/Azure
- Google Firebase, which claims to be free and the main benefactor to parse
- IBM Cloudant, appears to be free under $50/mo
bug list and bug squashing
an array of hash tables would be nice, perfect even, but I read that JS hash tables are slow, or double-down on a hash table of hash tables. hashes, and it's quick!
localstorage backend for list storage; current array of arrays bogs down somewhere between 1mb and 2mb of text. done!
table parser update. also known as a data backend update. done!
means the table list storage mechanism needs to be rejiggered. hashes!
JSON might have an answer, and there's always xml. JSON it is!
and if I'm going that far deep into the data structure, it's more sense to re-write the parser around the data structure. done!
night moves, checkbox or toggle button that inverts screen color done!
replace [tablecall] with {tablecall} to clone table and make reductive table calls like we do for cards: These tables aren't reductive or unique. In other words, if you query a table multiple times, you can end up with the same result. This happens often with short tables. Reductive tables are something that I want to implement in the parser, since unique results are always nice. Odds are good that reductive tables will be called by {tablename} instead of [tablename] done!
finding what you want in a two-dimensional array is a pain. probably faster to keep arrays of arrays, but instead of the special array list of table names, put them in a hash table, key being table name and value being 1st dim. array index. done!
figure out why this app hates unicode so much done!
find the common unicode characters and string replace them with the old dumb quotes, ellipses, and apostrophes that no one likes anymore. not needed with unicode support!
- the first time you launch the program, it shows you everything that it should.
if you don't save your tables, then close the window and don't clear your browser cache, the next time you open the app, a few of the windows will read "undefined" instead of that help text.
This bug has been around for quite a while; I'm pretty sure I just missed its birthday. One of these days I will get annoyed with it and fix it, I promise.
- the check boxes for 'night mode', 'reverse log', and 'show dice rolls' can be meaningless on app reload until you check them once. I expect this bug to be squashed when I fix the above bug; if I'm diving into the app state on startup, I may as well fix them both.
the hard way -- black magic variables
long story short, an eval code block. for the parser to interpret it, it must be the only thing on the line. the global variable hash table / object 'variable' is yours to use for convenience. Global vars can't be deleted, but hash table / object entries can. If you understand javascript, this code block explains what's going on:
var yourjavascriptcode = somestring;
evalstring = "{eval {" + somestring + "}}";
var strip = evalstring.match(/^\{eval\s(\{.*\})\}$/,1)
eval(strip[1])
If you don't understand javascript, on the other hand, it was probably gibberish.
and this code block is just here to give you ideas...
definition
|variable varname
[tablename] or {tablename} or #diceexpr#
or... if you're going to set it later with an expr
null or "" or 1@
or... an indexed array of strings
{eval {variable["varname"]=["arrayitem0","arrayitem1","arrayitem2"];}}
or... a hash table / object
{eval {variable["varname"]={ key: "value";};}}
or... a number
{eval {variable["varname"]= 0;}}
or... a string
{eval {variable["varname"]= "value";}}
or... a table call
{eval {variable["varname"]=getrandomarrayitem('tablename');}}
or... a reductive table call
{eval {variable["varname"]=getrandomarrayitem('tablename,true');}}
or... empty a reductive table so the next call to it is full
{eval {reductive["tablename"]=[];}}
or... a dice parser function call
{eval {variable["varname"]=diceparser("1d6*1000/10f+15+30d4");}}
or... a string to send to the parser
{eval {variable["varname"]=parseresult("#3d6# [nested] tables that are [nested] are neat");}}
or... stringified JSON...
{eval {variable["varname"]=json.parse('{"result":true,"count":1}');}}
or... a modal prompt for it
{eval {variable["varname"]=prompt("type a value for variable varname:");}}
or... cut and paste your stringified JSON into a prompt...
{eval {variable["varname"]=prompt("paste your JSON here:"); variable['varname']=json.parse(variable['varname']);}}
or a run block
the result of an eval code block is stored for later reference. If you want an eval block to run every time and display new results, don't use {eval {expr}}, use {run {expr}}. Run results are evaluated every time they come up.
if you're still reading... why not?
or... a function definition (functions can't be deleted)
{eval {function MakeThisStuffUppercase(str){ return str.toUpperCase()}}
or... after we define -- and init, otherwise it didn't happen -- the function, save the results of a function call
{eval {variable["varname"]=MakeThisStuffUppercase(variable["varname"]);}}