diff --git a/TODO.md b/TODO.md index 8a07e91..252c5bc 100644 --- a/TODO.md +++ b/TODO.md @@ -20,8 +20,9 @@ ### Dialogue -- [ ] Text formatting +- [x] Text formatting - [ ] Character profiles / speaker ID +- [ ] Scrollable dialogue pane (like Citizen Sleeper / Disco Elysium) ## Code architecture diff --git a/res/text/rooms.yarn b/res/text/rooms.yarn index 253a346..92b3003 100644 --- a/res/text/rooms.yarn +++ b/res/text/rooms.yarn @@ -5,37 +5,38 @@ title: Room:quarters <> <> <> -You: It's the crew quarters. +You: It's the [room]crew quarters[/room]. You: Well, it will be. Set-up hasn't started yet. You: That was meant to be one of my first jobs after defrost... You: ...but it doesn't exactly seem like a priority now. <> <> You: Maybe there's something useful here? --> Search the lockers (perception) <> +-> Search the lockers [ability](perception)[/ability] <> <> < 0>> - You: Aha! A small piece of paper with the **hangar access code**. + You: Aha! A small piece of paper with the [item]access code[/item] for the [room]hangar[/room]. <> <> <> You: Just some dust bunnies. Guess they stowed away from Earth. <> --> Set up a sleeping mat (ingenuity) <> +-> Set up a sleeping mat [ability](ingenuity)[/ability] <> <> < 2>> You: Nice, at least I have somewhere to crash now. <> <> - You: Hmm, I was never good at this camping stuff. Maybe I can find somewhere else to rest. + You: [failure]Hmm, I was never good at this camping stuff. Maybe I can find somewhere else to rest.[/failure] <> -> Leave === title: Room:hangar --- -You: The **hangar** seems eerily deserted. +You: The [room]hangar[/room] seems eerily deserted. === title: Room not open --- You: Hmm, that part of the ship is still inaccessible. I wonder how to get in? +<> === diff --git a/src/components/DialogueBoxComponent.hx b/src/components/DialogueBoxComponent.hx index 8cd1755..32edb1c 100644 --- a/src/components/DialogueBoxComponent.hx +++ b/src/components/DialogueBoxComponent.hx @@ -1,6 +1,10 @@ package components; +import h2d.HtmlText; +import hxyarn.dialogue.markup.MarkupParseResult; + import dialogue.event.NextLine; +import dialogue.event.LineShown; import dialogue.event.OptionSelected; import dialogue.event.OptionsShown.OptionChoice; @@ -83,9 +87,10 @@ class DialogueBoxComponent extends h2d.Flow implements h2d.domkit.Object { var chan:hxd.snd.Channel; var textPos:Int = 0; var game:Game; + public var lineMarkup:MarkupParseResult; static var SRC = - + public var displayedText(get, set):String; @@ -109,11 +114,12 @@ class DialogueBoxComponent extends h2d.Flow implements h2d.domkit.Object { return t; } - public function new(text:String, ?parent) { + public function new(lineShown:LineShown, ?parent) { this.game = Game.current; super(parent); initComponent(); - internalText = text; + this.lineMarkup = lineShown.markUpResults; + this.internalText = lineShown.line(); enableInteractive = true; interactive.onClick = function(_) onClick(); @@ -138,7 +144,59 @@ class DialogueBoxComponent extends h2d.Flow implements h2d.domkit.Object { // } // } textPos++; - displayedText = internalText.substr(0, textPos); + displayedText = applyTextAttributes(internalText.substr(0, textPos)); + } + + function applyTextAttributes(text:String):String { + var characterOffset = 0; + var characterAttribute = lineMarkup.tryGetAttributeWithName("character"); + if (characterAttribute != null) + characterOffset = -characterAttribute.length; + + var htmlTagsByIndex = new Map(); + + for (attribute in lineMarkup.attributes) { + var startTagIndex = attribute.position + characterOffset; + if (startTagIndex < text.length) { + var currrentStartTag = ""; + var currentEndTag = ""; + var endTagIndex = Std.int(Math.min(text.length, startTagIndex + attribute.length)); + if (htmlTagsByIndex.exists(startTagIndex)) + currrentStartTag = htmlTagsByIndex.get(startTagIndex); + + if (htmlTagsByIndex.exists(endTagIndex)) + currentEndTag = htmlTagsByIndex.get(endTagIndex); + + if (attribute.name == "room") { + var openTag = '$currrentStartTag'; + var closeTag = '$currentEndTag'; + htmlTagsByIndex.set(startTagIndex, openTag); + htmlTagsByIndex.set(endTagIndex, closeTag); + } else if (attribute.name == "item") { + var openTag = '$currrentStartTag'; + var closeTag = '$currentEndTag'; + htmlTagsByIndex.set(startTagIndex, openTag); + htmlTagsByIndex.set(endTagIndex, closeTag); + } + } + } + + var sb = new StringBuf(); + + for (i in 0...text.length) { + var char = text.charAt(i); + if (htmlTagsByIndex.exists(i)) { + sb.add(htmlTagsByIndex.get(i)); + } + + sb.add(char); + } + + if (htmlTagsByIndex.exists(text.length)) { + sb.add(htmlTagsByIndex.get(text.length)); + } + + return sb.toString(); } override function onRemove() { diff --git a/src/listeners/DialogueBoxController.hx b/src/listeners/DialogueBoxController.hx index 4061cad..0427279 100644 --- a/src/listeners/DialogueBoxController.hx +++ b/src/listeners/DialogueBoxController.hx @@ -42,10 +42,11 @@ class DialogueBoxController { function onLineShown(event:LineShown) { if (dialogueBox == null) { - var d = new DialogueBoxComponent(event.line(), this.parent); + var d = new DialogueBoxComponent(event, this.parent); style.addObject(d); dialogueBox = d; } else { + dialogueBox.lineMarkup = event.markUpResults; dialogueBox.internalText = event.line(); } }