Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide endpoint to launch an encounter based on POSTed payload #46

Closed
cynicaloptimist opened this issue Nov 24, 2016 · 30 comments
Closed

Comments

@cynicaloptimist
Copy link
Owner

This endpoint will provide a means for tools like Kobold Fight Club to provide users with a one-click option to start encounters built in another tool. Where possible, it should attach stat blocks for OGL creatures, and make placeholders for player characters and non OGL creatures.

@cynicaloptimist
Copy link
Owner Author

The JSON payload could use a simplified version of the schema in ogl_creatures.json. The only required field would be Name, but other data could be provided when available.

@cynicaloptimist
Copy link
Owner Author

cynicaloptimist commented Nov 24, 2016

Example payload:

{
  "Combatants": [
    {
      "Name": "Bob",
      "Type": "Human Rogue",
      "HP": {
        "Value": 10
      },
      "InitiativeModifier": 2,
      "AC": {
        "Value": 10
      },
      "Player": "player"
    },
    {
      "Name": "Goblin",
      "Type": "Small humanoid (goblin)",
      "HP": {
        "Value": 6
      },
      "InitiativeModifier": 2,
      "AC": {
        "Value": 12
      },
      "Player": "npc"
    }
  ]
}

@Asmor
Copy link

Asmor commented Nov 24, 2016

Presumably "player" and "npc" are the sides in the encounter?

@cynicaloptimist
Copy link
Owner Author

Yes, currently Improved Initiative will initialize a player (instead of an NPC) if this field is set to "player". "npc" isn't actually meaningful here, but might be in the future- it has the same effect as omitting the field altogether.

@cynicaloptimist
Copy link
Owner Author

I've been thinking about this feature, and I have a few concerns around the concept of a 'statblock identity' that I'd like feedback on.

Part of the magic of this feature is the idea that, although the calling service may not have complete statblocks for the creatures in the encounter, Improved Initiative needs to be able to match up the entry with the appropriate statblock when available.

  • Some names might be formatted differently between service. Consider II's "Dragon, Black (Adult)" versus "Adult Black Dragon".
  • There may be multiple versions of a statblock, either through errata, multiple printings, or appearance in separate books.

The responsibility of finding a matching statblock could be delegated to the calling service; Improved Initiative provides a public (but undocumented) statblock API that can be used for lookups.

A separate 'creature service' that masters all of the statblocks and assigns each one a unique, deterministic ID could be spun up to serve apps like these.

The quick and dirty way is probably the best here- Try to do a name match (with some massaging for possible differences in formatting) and apply the found statblock if appropriate.

@Asmor
Copy link

Asmor commented Dec 13, 2016

Making a deterministic ID would be difficult, I think. Especially if 3rd-party products enter the picture. Also, there are some creatures which appear in multiple sources with different stat blocks. Blood Hawk is in the Monster Manual and, curiously, 5th Edition Foes, for example. Catoblepas is in 5eF and Volo's guide. There are a few others (almost all of which are 5th edition foes and an official source) as well, and in all cases the monsters have different stat blocks.

Currently KFC uses randomly-generated, meaningless GUIDs for identifying monsters. I've been intending to transition it to using human-readable ids which are the monster's name with the following transformations:

  1. Lower case
  2. All punctuation removed
  3. All space replaced with hyphens
  4. If the monster is from a 3rd party source, given a source-specific prefix.

So the official Blood Hawk would be blood-hawk, and the 5th Edition Foes one would be 5ef-blood-hawk.

My best idea for making a truly deterministic ID that anyone could implement would be to base it on the product the monster appears in (for those appearing in multiple sources, like basic rules and monster manual, make a common-sense choice of canonical source; monster manul in that case).

Uniquely identifying a product is itself non-trivial. The ISBN could work. ISBNs are recycled and re-issued over time, but it seems very unlikely two 5th edition monster books would ever get the same one. From there, you can identify the monster based on where it appears in the book. So something like...

ISBN:PAGE:ORDER

Where ISBN is the ISBN; PAGE is the first page the monster's stat block appears on (in case the block spans multiple pages), and ORDER is which number stat block it is on the page (1 if it's the only stat block on the page or the first).

So the MM blood hawk would be 978-0786965618:319:1 and the MM Boar would be 978-0786965618:319:2

But then this could potentially change in subsequent printings... Not to mention it would be a huge pain in the ass.

It's a very tough problem to crack.

@cynicaloptimist
Copy link
Owner Author

Using the ISBN also breaks down in some cases- I think that WotC publishes some statblocks online that never necessarily make it into something with an ISBN.

I do really like the human readable ids. You'd also need to provide rules for placement of descriptors such as in the Dragon, Green (adult) vs Adult Green Dragon example. There are a few other non-obvious decisions such as how to shorten the names of source materials. I think it would make sense to always include the source identifier, so the official blood hawk would be srd-blood-hawk (aside: would it make sense to use a username in that spot in the case of a user-provided statblock?) If we set a precedent by providing clear, unambiguous rules for the human readable IDs, it makes it easy for other apps to integrate. I think that's the right next step.

@cynicaloptimist
Copy link
Owner Author

cynicaloptimist commented Dec 13, 2016

suggestion: use a tilde with source-specific prefix instead of a dash. srd~blood-hawk.

@cynicaloptimist
Copy link
Owner Author

I added a branch with a first draft at assigning deterministic, human readable IDs to each statblock.
https://github.com/cynicaloptimist/improved-initiative/tree/launch-encounter-endpoint

@Asmor
Copy link

Asmor commented Dec 13, 2016

I would say the name should appear exactly as it does in the stat block. "Adult Blue Dragon."

I don't think it makes sense to use the SRD as the canonical source for monsters therein... They're all found in the Monster Manual, which is what I'd imagine most people use, and there are monsters in the MM that aren't in the SRD.

Also, as a practical aside, I've had people ask about and contribute lots of 3rd party sources, but I've never had anyone ask about the SRD. I didn't even know the SRD existed until just this moment. Not sure how different our audiences are, but anecdotally from my end it seems like nobody cares about the SRD.

A different separator for source makes sense, but I think tilde is a little too visually similar to hyphen. How about colon : or pipe |?

Also we'd need to come up with a list of ids for sources now. Here are my suggestions:

  • hoard: Hoard of the Dragon Queen
  • tiamat: Rise of Tiamat
  • strahd: Curse of Strahd
  • sking: Storm King's Thunder
  • mm: Monster Manual
  • apoc: Princes of the Apocalypse
  • abyss: Out of the Abyss
  • mad: Monster-A-Day
  • 5ef: Fifth Edition Foes
  • thulse-cs: Primeval Thule Campaign Setting
  • thule-gm: Primeval Thule Gamemaster's Companion
  • tob: Tome of Beasts
  • volo: Volo's Guide to Monsters

I've left out all of the online supplements (basic rules, adventure supplements, srd) and the PHB as most (all?) of the stuff from them is found primarily in other products

@cynicaloptimist
Copy link
Owner Author

cynicaloptimist commented Dec 13, 2016

I agree, 'exactly as it appears in the statblock' makes the most sense. Note that this might differ between MM and SRD- I'll have to check. More on that below.

I went with tilde because it's valid in url strings (colon and pipe are not). This is nice, because I like being able to encode the ID in a url to retrieve the full statblock. There's some precedent in using a tilde to denote source, in the typings project.

As a concept, the SRD is actually very important to Improved Initiative. This is because the WotC licenses only allow us to provide full statblocks for monsters that are in the SRD. That's my understanding, at least-- IANAL.

Since Improved Initiative only provides monsters from the SRD, this provides a challenge if you want to launch an encounter with mm~orc and II only has srd~orc. It might be reasonable to use mm~ and dmg~ as special cases that also map to srd~ where applicable.

It's true that there are monsters that appear in the MM and not in the SRD. This effectively means that, for example, I can't include the Beholder statblock in Improved Initiative. This is an intentional move by WotC.

@Asmor
Copy link

Asmor commented Dec 13, 2016

Good point about URLs. What about dot? srd.orc, srd.blood-hawk, etc?

I understand why the SRD makes sense from your perspective, but if the goal is to make IDs that anyone could calculate, I think the MM makes more sense to be considered the canonical source. That doesn't mean that you need to use the monster manual as your source, just that the critters from the SRD would have their IDs generated based on their appearance in the MM.

@cynicaloptimist
Copy link
Owner Author

Dot works fine, sure.

I suppose you're right about the canonical source. WotC's current page about the SRD implies that they intend the statblocks in the SRD to be the same as the ones in their canonical source, so the SRD is really more of a licensing concern. I'll update my statblock library to point everything to the canonical source for this purpose, and use the names exactly as they appear in the statblock.

@cynicaloptimist
Copy link
Owner Author

cynicaloptimist commented Dec 21, 2016

The aforementioned branch launch-encounter-endpoint now supports receiving a payload posted to the /launchencounter/ endpoint. It works with minimal statblocks, and you can provide differences where applicable. I tested it with the following payload:
{ "Combatants": [{ "Name": "Nemo", "HP": { "Value": 10 } }, { "Name": "Fat Goblin", "HP": { "Value": 20 }, "Id": "mm.goblin"}, { "Id": "mm.goblin"}]}

The endpoint will accept urlencoded and json payloads, but I think the only good way to cause the browser to navigate to the result is by using a urlencoded form payload. Please experiment with this branch and feel free to submit feedback or PRs to get it working from your end.

Edit: complete payload

@Asmor
Copy link

Asmor commented Dec 21, 2016

I'll probably have some time to play around with this this weekend or next weekend.

@Asmor
Copy link

Asmor commented Dec 22, 2016

I lied, gave it a crack today. :)

Ok, I've KFC successfully exporting to Improved Initative. The basic functionality seems solid.

When Improved Initiative recognizes a monster's FID, it grabs its source, alignment, and type, but everything else is blank. E.g. here's what a goblin looks like when I export:

image

Here's the POST payload that I'm testing with (this is actually being generated dynamically, it's not a static test). There's only one player, Bob.

Combatants=[{"Name":"Lich+(in+lair)","HP":{"Value":135},"InitiativeModifier":3,"AC":17,"Player":"npc","Id":"mm.lich-in-lair"},{"Name":"Marid+#1","HP":{"Value":229},"InitiativeModifier":1,"AC":17,"Player":"npc","Id":"mm.marid"},{"Name":"Marid+#2","HP":{"Value":229},"InitiativeModifier":1,"AC":17,"Player":"npc","Id":"mm.marid"},{"Name":"Marid+#3","HP":{"Value":229},"InitiativeModifier":1,"AC":17,"Player":"npc","Id":"mm.marid"},{"Name":"Marid+#4","HP":{"Value":229},"InitiativeModifier":1,"AC":17,"Player":"npc","Id":"mm.marid"},{"Name":"Marid+#5","HP":{"Value":229},"InitiativeModifier":1,"AC":17,"Player":"npc","Id":"mm.marid"},{"Name":"Adult+Black+Dragon","HP":{"Value":195},"InitiativeModifier":2,"AC":19,"Player":"npc","Id":"mm.adult-black-dragon"},{"Name":"Will-o'-Wisp","HP":{"Value":22},"InitiativeModifier":9,"AC":19,"Player":"npc","Id":"mm.will-o-wisp"},{"Name":"Goblin+#1","HP":{"Value":7},"InitiativeModifier":2,"AC":15,"Player":"npc","Id":"mm.goblin"},{"Name":"Goblin+#2","HP":{"Value":7},"InitiativeModifier":2,"AC":15,"Player":"npc","Id":"mm.goblin"},{"Name":"Goblin+#3","HP":{"Value":7},"InitiativeModifier":2,"AC":15,"Player":"npc","Id":"mm.goblin"},{"Name":"Goblin+#4","HP":{"Value":7},"InitiativeModifier":2,"AC":15,"Player":"npc","Id":"mm.goblin"},{"Name":"Goblin+#5","HP":{"Value":7},"InitiativeModifier":2,"AC":15,"Player":"npc","Id":"mm.goblin"},{"Name":"Goblin+#6","HP":{"Value":7},"InitiativeModifier":2,"AC":15,"Player":"npc","Id":"mm.goblin"},{"Name":"Bugbear","HP":{"Value":27},"InitiativeModifier":2,"AC":16,"Player":"npc","Id":"mm.bugbear"},{"Name":"bob","InitiativeModifier":1,"HP":{"Value":1},"Player":"player"}]

In the interests of trying to make matches as likely as possible, here's the algorithm I'm using to scrub the monster's name and generate the FID:

var scrubbedName = monster.name
	.toLowerCase()
	.replace(/ /g, "-")
	.replace(/--+/g, "-")
	.replace(/[^-a-z0-9]/g, "");

If you want to try playing with it yourself, you can check out and run this branch: https://github.com/Asmor/5e-monsters/tree/improved-initiative-integration

It's hard coded to expect improved initiative to be running at http://localhost/

The button to launch Improved Initiative is in the "run encounter" screen. You'll need to select an encounter and a party (to create a quick party you can just type bob 1 1 and click manage), then there's an ugly unstyled button next to the big red "Fight" button

@Asmor
Copy link

Asmor commented Dec 22, 2016

Oh, and the prefixes I'm using are the same as I suggested above, modulo fixing a type on the thule-cs

	var sourcePrefixes = [
		// Core books
		{ name: "Monster Manual", prefix: "mm" },
		{ name: "Volo's Guide to Monsters", prefix: "volo" },

		// Official adventures
		{ name: "Curse of Strahd", prefix: "strahd" },
		{ name: "Hoard of the Dragon Queen", prefix: "hoard" },
		{ name: "Out of the Abyss", prefix: "abyss" },
		{ name: "Princes of the Apocalypse", prefix: "apoc" },
		{ name: "Rise of Tiamat", prefix: "tiamat" },
		{ name: "Storm King's Thunder", prefix: "sking" },

		// Third-party
		{ name: "Fifth Edition Foes", prefix: "5ef" },
		{ name: "Monster-A-Day", prefix: "mad" },
		{ name: "Primeval Thule Campaign Setting", prefix: "thule-cs" },
		{ name: "Primeval Thule Gamemaster's Companion", prefix: "thule-gm" },
		{ name: "Tome of Beasts", prefix: "tob" },
	];

@cynicaloptimist
Copy link
Owner Author

Made a PR for this- you needed to encapsulate the AC value. Asmor/5e-monsters#36

@cynicaloptimist
Copy link
Owner Author

I've merged these changes into my dev branch, so you can test your changes against the dev server at http://improved-initiative-dev.azurewebsites.net/

@Asmor
Copy link

Asmor commented Dec 28, 2016

I've got a copy of KFC up that's pointing at that location, and it's working

http://kobold.club/testing/build/

@cynicaloptimist
Copy link
Owner Author

Excellent, it looks great! I've deployed this build to the official Improved Initiative site, so you can launch this feature at your leisure.

Feel free to use any of the Improved Initiative boot logos when styling your Launch Improved Initiative button.

Can you send me a PM with some details on the amount of traffic you get on KFC, so I have an idea of what load to expect? Thanks!

@Asmor
Copy link

Asmor commented Dec 28, 2016

Emailed details to you at the email address in your GitHub profile

@cynicaloptimist
Copy link
Owner Author

Quick FYI- had to roll back the deployment, I broke legacy saved encounters. I'll update you again when the new build is live and working.

@Asmor
Copy link

Asmor commented Dec 28, 2016

np. It'll probably be at least a few days before I have this styled appropriately for live

@cynicaloptimist
Copy link
Owner Author

New build has been live for a day or so, and nobody's screamed yet :-)

@Asmor
Copy link

Asmor commented Dec 29, 2016

Schway. I should have some time this weekend to clean up my end and push it out

@Asmor
Copy link

Asmor commented Jan 1, 2017

http://kobold.club/testing/build/#/battle-setup

Just wanted to run this by you and make sure you're cool with what I did with the button and your logo

@cynicaloptimist
Copy link
Owner Author

This looks great! Thanks for the update.

@Asmor
Copy link

Asmor commented Jan 1, 2017

Just made the changes live on my end. We're officially integrated!

@cynicaloptimist
Copy link
Owner Author

Woohoo!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants