From 6ce6f9ebbaf836bef206a0dd0e7955eb98a840e7 Mon Sep 17 00:00:00 2001 From: Dael Separa Date: Wed, 8 Sep 2021 21:02:02 +0800 Subject: [PATCH] use regex to strip html tags. now works with nesting bold, and italic --- src/LegendaryKingdoms.cpp | 10 +- src/LegendaryKingdoms.hpp | 4 +- src/glyphs.hpp | 189 +++++++++++++------------------------- src/topics/book1.json | 12 +-- 4 files changed, 76 insertions(+), 139 deletions(-) diff --git a/src/LegendaryKingdoms.cpp b/src/LegendaryKingdoms.cpp index 1689323..a4b576e 100644 --- a/src/LegendaryKingdoms.cpp +++ b/src/LegendaryKingdoms.cpp @@ -26168,7 +26168,7 @@ bool processStory(SDL_Window *window, SDL_Renderer *renderer, Party::Base &party } else if (story->Text) { - text = Glyphs::createText(story->Text, FONT_GARAMOND, font_size, clrDB, listwidth); + text = Glyphs::FormattedText(story->Text, FONT_GARAMOND, font_size, clrDB, listwidth); } auto compact = (text && text->h <= text_bounds - 2 * text_space) || !text; @@ -27391,7 +27391,7 @@ bool encyclopediaScreen(SDL_Window *window, SDL_Renderer *renderer, Book::Type b } else if (Topics::ALL[topic].Text.length() > 0) { - text = Glyphs::createText(Topics::ALL[topic].Text.c_str(), FONT_GARAMOND, font_size, clrDB, listwidth); + text = Glyphs::FormattedText(Topics::ALL[topic].Text.c_str(), FONT_GARAMOND, font_size, clrDB, listwidth); } auto compact = (text && text->h <= (text_bounds - 2 * text_space - infoh)) || !text; @@ -27629,7 +27629,7 @@ bool encyclopediaScreen(SDL_Window *window, SDL_Renderer *renderer, Book::Type b } else if (Topics::ALL[topic].Text.length() > 0) { - text = Glyphs::createText(Topics::ALL[topic].Text.c_str(), FONT_GARAMOND, font_size, clrDB, listwidth); + text = Glyphs::FormattedText(Topics::ALL[topic].Text.c_str(), FONT_GARAMOND, font_size, clrDB, listwidth); } if (splash) @@ -27699,7 +27699,7 @@ bool encyclopediaScreen(SDL_Window *window, SDL_Renderer *renderer, Book::Type b } else if (Topics::ALL[topic].Text.length() > 0) { - text = Glyphs::createText(Topics::ALL[topic].Text.c_str(), FONT_GARAMOND, font_size, clrDB, listwidth); + text = Glyphs::FormattedText(Topics::ALL[topic].Text.c_str(), FONT_GARAMOND, font_size, clrDB, listwidth); } if (splash) @@ -27771,7 +27771,7 @@ bool encyclopediaScreen(SDL_Window *window, SDL_Renderer *renderer, Book::Type b } else if (Topics::ALL[topic].Text.length() > 0) { - text = Glyphs::createText(Topics::ALL[topic].Text.c_str(), FONT_GARAMOND, font_size, clrDB, listwidth); + text = Glyphs::FormattedText(Topics::ALL[topic].Text.c_str(), FONT_GARAMOND, font_size, clrDB, listwidth); } if (splash) diff --git a/src/LegendaryKingdoms.hpp b/src/LegendaryKingdoms.hpp index 97cffae..e4afbce 100644 --- a/src/LegendaryKingdoms.hpp +++ b/src/LegendaryKingdoms.hpp @@ -514,7 +514,7 @@ SDL_Surface *createTextAndImage(const char *text, const char *image, const char auto image_surface = createImage(image); - auto text_surface = Glyphs::createText(text, ttf, font_size, textColor, wrap); + auto text_surface = Glyphs::FormattedText(text, ttf, font_size, textColor, wrap); if (image_surface && text_surface) { @@ -651,7 +651,7 @@ SDL_Surface *formattedHeaderButton(SDL_Window *window, const char *font, int fon auto button = SDL_CreateRGBSurface(0, w, h, 32, bg == 0 ? 0x000000FF : 0, bg == 0 ? 0x0000FF00 : 0, bg == 0 ? 0x00FF0000 : 0, bg == 0 ? 0xFF000000 : 0); #endif - auto text_surface = Glyphs::createText(text, font, font_size, color, w); + auto text_surface = Glyphs::FormattedText(text, font, font_size, color, w); if (button && text_surface) { diff --git a/src/glyphs.hpp b/src/glyphs.hpp index 275ecc7..f324283 100644 --- a/src/glyphs.hpp +++ b/src/glyphs.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -11,23 +12,34 @@ namespace Glyphs { - // https://stackoverflow.com/questions/49333136/removing-html-tags-from-a-string-of-text - // Probably a slow implementation void Sanitize(std::string &str) { - for (auto a = 0; a < str.length(); a++) + std::regex tags("<[^<]*>"); + + str = std::regex_replace(str, tags, ""); + } + + // TODO: Use faster implementation, i.e. Render from Glyph Atlas with Kernering + void RenderText(const char *text, TTF_Font *font, SDL_Color textColor, SDL_Surface *surface, int x, int y) + { + if (font) { - if (str[a] == '<') + SDL_Rect dst; + + dst.w = surface->w; + dst.h = surface->h; + dst.x = x; + dst.y = y; + + auto text_surface = TTF_RenderText_Blended(font, text, textColor); + + if (text_surface) { - for (int b = a; b < str.length(); b++) - { - if (str[b] == '>') - { - str.erase(a, (b - a + 1)); + SDL_BlitSurface(text_surface, NULL, surface, &dst); - break; - } - } + SDL_FreeSurface(text_surface); + + text_surface = NULL; } } } @@ -76,10 +88,10 @@ namespace Glyphs if (c == '\r' || c == '\n' || c == '\t' || c == ' ') { - auto subw = 0; - if (word) { + auto subw = 0; + auto sub = copy.substr(start, i - start); Glyphs::Sanitize(sub); @@ -100,55 +112,32 @@ namespace Glyphs { x += subw; } + } - if (c == '\t' || c == ' ') - { - x += space; - - if (x > width) - { - x = 0; - - lines += 1; - } - } - else if (c == '\n' || c == '\r') - { - x = 0; - - lines += 1; - } - - if (closeBold) - { - isBold = false; - - closeBold = false; - } + if (c == '\t' || c == ' ') + { + x += space; + } - if (closeItalic) - { - isItalic = false; + if (x > width || c == '\n' || c == '\r') + { + x = 0; - closeItalic = false; - } + lines += 1; } - else if (c == ' ' || c == '\t') - { - x += space; - if (x > width) - { - x = 0; + if (closeBold) + { + isBold = false; - lines += 1; - } + closeBold = false; } - else if (c == '\n' || c == '\r') + + if (closeItalic) { - x = 0; + isItalic = false; - lines += 1; + closeItalic = false; } } else if (c == '<') @@ -223,32 +212,7 @@ namespace Glyphs } } - // TODO: Use faster implementation, i.e. Render from Glyph Atlas with Kernering - void RenderText(const char *text, TTF_Font *font, SDL_Color textColor, SDL_Surface *surface, int x, int y) - { - if (font) - { - SDL_Rect dst; - - dst.w = surface->w; - dst.h = surface->h; - dst.x = x; - dst.y = y; - - auto text_surface = TTF_RenderText_Blended(font, text, textColor); - - if (text_surface) - { - SDL_BlitSurface(text_surface, NULL, surface, &dst); - - SDL_FreeSurface(text_surface); - - text_surface = NULL; - } - } - } - - SDL_Surface *createText(const char *text, const char *ttf, int font_size, SDL_Color textColor, int wrap) + SDL_Surface *FormattedText(const char *text, const char *ttf, int font_size, SDL_Color textColor, int wrap) { TTF_Init(); @@ -346,9 +310,7 @@ namespace Glyphs lines += 1; - y = lines * skip; - - Glyphs::RenderText(sub.c_str(), font, textColor, surface, 0, y); + Glyphs::RenderText(sub.c_str(), font, textColor, surface, 0, lines * skip); } else { @@ -356,53 +318,14 @@ namespace Glyphs x += subw; } - - if (c == '\t' || c == ' ') - { - x += space; - - if (x > width) - { - x = 0; - - lines += 1; - } - } - else if (c == '\n' || c == '\r') - { - x = 0; - - lines += 1; - } - - y = lines * skip; - - if (closeBold) - { - isBold = false; - - closeBold = false; - } - - if (closeItalic) - { - isItalic = false; - - closeItalic = false; - } } - else if (c == '\t' || c == ' ') + + if (c == '\t' || c == ' ') { x += space; - - if (x > width) - { - x = 0; - - lines += 1; - } } - else if (c == '\n' || c == '\r') + + if (x > width || c == '\n' || c == '\r') { x = 0; @@ -410,6 +333,20 @@ namespace Glyphs } y = lines * skip; + + if (closeBold) + { + isBold = false; + + closeBold = false; + } + + if (closeItalic) + { + isItalic = false; + + closeItalic = false; + } } else if (c == '<') { diff --git a/src/topics/book1.json b/src/topics/book1.json index 679652f..28fc35b 100644 --- a/src/topics/book1.json +++ b/src/topics/book1.json @@ -39,7 +39,7 @@ }, { "title": "Your Party", - "text": "You must select a group of four adventurers to explore the Legendary Kingdoms. These adventurers are called party members, and each has their own backstory and set of abilities. You can select any four party members, but it is wise to have a balance of different skills in your party. If you only select the fiercest fighters, you might struggle when it comes to sneaking around or charming people. Once you have selected your party members, you should note down their skills and abilities on the adventure sheet provided at the back of this book. You can also download a copy of this sheet from www.spidermindgames.co.uk\n\nLord Ti'Quon and Amelia Pass-Dayne can cast spells, which makes up for their poor skill and health scores. You can read the rules on spells a little later on." + "text": "You must select a group of four adventurers to explore the Legendary Kingdoms. These adventurers are called party members, and each has their own backstory and set of abilities. You can select any four party members, but it is wise to have a balance of different skills in your party. If you only select the fiercest fighters, you might struggle when it comes to sneaking around or charming people. Once you have selected your party members, you should note down their skills and abilities on the adventure sheet provided at the back of this book. You can also download a copy of this sheet from www.spidermindgames.co.uk\n\nLord Ti'Quon and Amelia Pass-Dayne can cast spells, which makes up for their poor skill and health scores. You can read the rules on spells a little later on." }, { "title": "Sar Jessica Dayne", @@ -48,7 +48,7 @@ }, { "title": "Lord Ti'quon", - "text": "Fighting 1, Stealth 2, Lore 5, Survival 1, Charisma 2, Health 6\n\n-Spellcaster-\n\nLord Ti'quon is a classically trained sorcerer from Drakehallow. Thanks to his family's wealth he has been able to learn his craft in the halls of Animus Mast, the premier academy for mages in the world. His knowledge is vast, learnt from library stacks and obscure scrolls, and his ambition is as great as his knowledge. Though at the beginning of his journey in the arts of magic, Ti'Quon shows great promise. He is handicapped, somewhat, by a lack of empathy, although his rich and regal voice make up for his curtness. If he can find additional sums for more tutelage, he desires to return to Animus Mast to unlock yet greater secrets of sorcery.", + "text": "Fighting 1, Stealth 2, Lore 5, Survival 1, Charisma 2, Health 6\n\n-Spellcaster-\n\nLord Ti'quon is a classically trained sorcerer from Drakehallow. Thanks to his family's wealth he has been able to learn his craft in the halls of Animus Mast, the premier academy for mages in the world. His knowledge is vast, learnt from library stacks and obscure scrolls, and his ambition is as great as his knowledge. Though at the beginning of his journey in the arts of magic, Ti'Quon shows great promise. He is handicapped, somewhat, by a lack of empathy, although his rich and regal voice make up for his curtness. If he can find additional sums for more tutelage, he desires to return to Animus Mast to unlock yet greater secrets of sorcery.", "image": "images/characters/lord-tiquon.png" }, { @@ -58,7 +58,7 @@ }, { "title": "Amelia Pass-Dayne", - "text": "Fighting 3, Stealth 2, Lore 2, Survival 3, Charisma 1, Health 6\n\n-Spellcaster-\n\nAmelia is the half-sister of Jessica and grew up with her in Fosterly Castle. Her mother was a forester who took Amelia away from the castle when it became obvious that Baron Baldwin, her father, would take no interest in the girl. Since maturity Amelia has lived in the wild forests of the Savage Lands, learning earth magic from the druids of that isolated place. Though slender, she has become a rugged survivor, who can live off the land and fight off wild beasts. Her magic is instinctive, and much mocked by more scholarly wizards, but it is no less potent for all that. Amelia dreams of becoming a full-circle druid, but knows that she must learn much before returning home to the Savage Lands.", + "text": "Fighting 3, Stealth 2, Lore 2, Survival 3, Charisma 1, Health 6\n\n-Spellcaster-\n\nAmelia is the half-sister of Jessica and grew up with her in Fosterly Castle. Her mother was a forester who took Amelia away from the castle when it became obvious that Baron Baldwin, her father, would take no interest in the girl. Since maturity Amelia has lived in the wild forests of the Savage Lands, learning earth magic from the druids of that isolated place. Though slender, she has become a rugged survivor, who can live off the land and fight off wild beasts. Her magic is instinctive, and much mocked by more scholarly wizards, but it is no less potent for all that. Amelia dreams of becoming a full-circle druid, but knows that she must learn much before returning home to the Savage Lands.", "image": "images/characters/amelia-pass-dayne.png" }, { @@ -313,15 +313,15 @@ }, { "title": "Postscript", - "text": "I'm eight years old, sitting at the foot of the bed in my friend Simon's room. My brother, ten, is with me, and we are both quite sad because the packing has already started. We are leaving Maidenhead and heading for Crowborough in East Sussex. Dad has just been made manager of the South Terminal at Gatwick, now Terminal 4 has been finished at Heathrow, and that means we have to move house. I'm saying goodbye to my best friend Miles, my girlfriend Catherine, and everything I ever knew.\n\nDown below, my parents are sitting at the dinner table with Simon's parents, and we've been allowed to go off and play. Simon was in the middle of an amazing book called The Warlock of Firetop Mountain, and offered to read to us. He's old, a teenager of some indistinct age or other, and tall, so anything he does is by default extremely cool.\n\nWe probably played for half an hour, but in kid time that is the equivalent of half a day, and I remember distinctly battles against werewolves, ghouls and scary paintings. Then we tried to kill the evil warlock with a lump of cheese and got electrocuted. I loved it. It was the most incredible adventure in my life, and I replayed the evening over and over in my head. The day before I left, he gave me the book -- and I treasured it until it was time to hand it over to another child with dreams of swords and adventure.\n\nThe common conception of gamebooks is that they are an odd historical blip. In the wake of Dungeons & Dragons, Steve Jackson and Ian Livingstone created the vastly well-selling Fighting Fantasy gamebooks because computers were too primitive to create convincing fantasy adventures. The argument is that once computers got good enough we didn't need gamebooks anymore. They could create combat systems more engaging than rolling two dice and provide stunning visuals to bring their worlds to life. I don't really believe this, any more than I think that the novel replaced poetry books in the 19th century, or cinema replaced theatre in the 20th. Gamebooks are their own art form, and like poetry and theatre, they get more done with less.\n\nMy journey across Kakabad in Steve Jackson's Sorcery gamebooks is more imprinted upon my mind than PC games like Skyrim or the Witcher. It is more private, more personal, but perhaps most of all more wonderous. Gamebooks have no limitations upon the imagination. If I want to fill a fantasy city with three dozen different species, I don't have to worry about convincing the design team that it is worth creating this vastly different crowd for a single scene, I merely have to write it. My deserts can be vast, and take weeks to cross, but I don't need to procedurally generate four hundred miles of terrain. My voice actors are always top class, and the visual fidelity is only the limit of my reader's imagination.\n\nI refuse to believe that such a rich and limitless form of storytelling can be breezily written off as obsolete, especially when there is so much more to do, so much more to write. Legendary Kingdoms is an attempt to right that wrong, by producing the most ambitious gamebook series ever written, and trying to find an audience with it. I hope that we've succeeded, and that you are as eager for the sequel books as I am." + "text": "I'm eight years old, sitting at the foot of the bed in my friend Simon's room. My brother, ten, is with me, and we are both quite sad because the packing has already started. We are leaving Maidenhead and heading for Crowborough in East Sussex. Dad has just been made manager of the South Terminal at Gatwick, now Terminal 4 has been finished at Heathrow, and that means we have to move house. I'm saying goodbye to my best friend Miles, my girlfriend Catherine, and everything I ever knew.\n\nDown below, my parents are sitting at the dinner table with Simon's parents, and we've been allowed to go off and play. Simon was in the middle of an amazing book called The Warlock of Firetop Mountain, and offered to read to us. He's old, a teenager of some indistinct age or other, and tall, so anything he does is by default extremely cool.\n\nWe probably played for half an hour, but in kid time that is the equivalent of half a day, and I remember distinctly battles against werewolves, ghouls and scary paintings. Then we tried to kill the evil warlock with a lump of cheese and got electrocuted. I loved it. It was the most incredible adventure in my life, and I replayed the evening over and over in my head. The day before I left, he gave me the book -- and I treasured it until it was time to hand it over to another child with dreams of swords and adventure.\n\nThe common conception of gamebooks is that they are an odd historical blip. In the wake of Dungeons & Dragons, Steve Jackson and Ian Livingstone created the vastly well-selling Fighting Fantasy gamebooks because computers were too primitive to create convincing fantasy adventures. The argument is that once computers got good enough we didn't need gamebooks anymore. They could create combat systems more engaging than rolling two dice and provide stunning visuals to bring their worlds to life. I don't really believe this, any more than I think that the novel replaced poetry books in the 19th century, or cinema replaced theatre in the 20th. Gamebooks are their own art form, and like poetry and theatre, they get more done with less.\n\nMy journey across Kakabad in Steve Jackson's Sorcery gamebooks is more imprinted upon my mind than PC games like Skyrim or the Witcher. It is more private, more personal, but perhaps most of all more wonderous. Gamebooks have no limitations upon the imagination. If I want to fill a fantasy city with three dozen different species, I don't have to worry about convincing the design team that it is worth creating this vastly different crowd for a single scene, I merely have to write it. My deserts can be vast, and take weeks to cross, but I don't need to procedurally generate four hundred miles of terrain. My voice actors are always top class, and the visual fidelity is only the limit of my reader's imagination.\n\nI refuse to believe that such a rich and limitless form of storytelling can be breezily written off as obsolete, especially when there is so much more to do, so much more to write. Legendary Kingdoms is an attempt to right that wrong, by producing the most ambitious gamebook series ever written, and trying to find an audience with it. I hope that we've succeeded, and that you are as eager for the sequel books as I am." }, { "title": "Influences of Legendary Kingdoms", - "text": "I've already mentioned my early love of Fighting Fantasy, and the Sorcery epic in particular. The biggest influence for this book series, however, is the wonderful Fabled Lands series, written by Dave Morris and Jamie Thompson. Much like Legendary Kingdoms, every book in the Fabled Lands series covers a different area of land, and your character can go from book to book, growing in power and wisdom. It has become something of a holy grail amongst gamebook fans, and anyone sensible should immediately buy one (or, preferably, all seven). You can thank Fabled Lands for bolded items that you can interact with, codes that keep track of changes in the book, and the pure ambition to write an entire world in a series of books.\n\nI should also mention Duelmaster, by Jamie Thompson and Mark Smith, and Blood Sword, by David Morris and Oliver Johnson, as inspirations, creating the first multiplayer gamebooks and multi-party gamebooks respectively. So much territory has been explored by these amazing writers, and I can only hope I add to this canon of great works." + "text": "I've already mentioned my early love of Fighting Fantasy, and the Sorcery epic in particular. The biggest influence for this book series, however, is the wonderful Fabled Lands series, written by Dave Morris and Jamie Thompson. Much like Legendary Kingdoms, every book in the Fabled Lands series covers a different area of land, and your character can go from book to book, growing in power and wisdom. It has become something of a holy grail amongst gamebook fans, and anyone sensible should immediately buy one (or, preferably, all seven). You can thank Fabled Lands for bolded items that you can interact with, codes that keep track of changes in the book, and the pure ambition to write an entire world in a series of books.\n\nI should also mention Duelmaster, by Jamie Thompson and Mark Smith, and Blood Sword, by David Morris and Oliver Johnson, as inspirations, creating the first multiplayer gamebooks and multi-party gamebooks respectively. So much territory has been explored by these amazing writers, and I can only hope I add to this canon of great works." }, { "title": "The Mission of Legendary Kingdoms", - "text": "For Legendary Kingdoms, my main desire was to create, in gamebook form, a roleplaying game campaign. Those of you who play Dungeons & Dragons, or other role playing games, know that one of the greatest joys of those games is to be involved in a long story that can take months or years to come to its conclusion. In the space of such campaigns you go from novice adventurers, to some of the most important people in the world, the viceroys of kings and queens. There is a feeling that your adventure could go anywhere, restricted only by the choices you and your games master decide upon.\n\nI wanted to capture this sense in Legendary Kingdoms. The player should be able to lead armies, sail vast oceans, explore lost continents, or get involved in politics in distant courts. Alongside these grand ideas, I wanted the adventure to also be small and personal, with discussions with common folk, simple acts of courage, and discovering new places as important as empire building. Beyond that, I am also very keen on character development. I want the party members to have wild love affairs, get embroiled in vicious rivalries, or find redemption. By the end of their adventure (and despite the sandbox nature of the game, it does have an end) I want the player to feel that loose ends have been tied up, and that every member of their party has had their moment in the sun.\n\nIt's an extremely ambitious design, and though I am happy with book one, I am acutely conscious of the fact that five more vast adventures lie ahead of me -- all of them intertwining, and all of them playable in any order. But if the gamebook is to ever regain its place in the popular imagination, it needs standard bearers that are unafraid of everything that a gamebook can be. This, in a nutshell, is Legendary Kingdom's design strategy; to be the kind of adventure that you play for years, that makes you want to explore every corner and blank space on the map.\n\nMay St. Elias guide your steps..." + "text": "For Legendary Kingdoms, my main desire was to create, in gamebook form, a roleplaying game campaign. Those of you who play Dungeons & Dragons, or other role playing games, know that one of the greatest joys of those games is to be involved in a long story that can take months or years to come to its conclusion. In the space of such campaigns you go from novice adventurers, to some of the most important people in the world, the viceroys of kings and queens. There is a feeling that your adventure could go anywhere, restricted only by the choices you and your games master decide upon.\n\nI wanted to capture this sense in Legendary Kingdoms. The player should be able to lead armies, sail vast oceans, explore lost continents, or get involved in politics in distant courts. Alongside these grand ideas, I wanted the adventure to also be small and personal, with discussions with common folk, simple acts of courage, and discovering new places as important as empire building. Beyond that, I am also very keen on character development. I want the party members to have wild love affairs, get embroiled in vicious rivalries, or find redemption. By the end of their adventure (and despite the sandbox nature of the game, it does have an end) I want the player to feel that loose ends have been tied up, and that every member of their party has had their moment in the sun.\n\nIt's an extremely ambitious design, and though I am happy with book one, I am acutely conscious of the fact that five more vast adventures lie ahead of me -- all of them intertwining, and all of them playable in any order. But if the gamebook is to ever regain its place in the popular imagination, it needs standard bearers that are unafraid of everything that a gamebook can be. This, in a nutshell, is Legendary Kingdom's design strategy; to be the kind of adventure that you play for years, that makes you want to explore every corner and blank space on the map.\n\nMay St. Elias guide your steps..." }, { "title": "Sketch: Saltdad",