#include #include #include #include "storybook.h" Storybook::Storybook() { // TODO } Storybook::Storybook(FILE* fin) { pages = CyoaParse(fin); } void Storybook::UpdateStat(const char *ckey, int rel) { std::string key(ckey); auto it = stats.find(key); if (it == stats.end()) { // Key not present stats[key] = rel; } else { // Key present, add the rel stats[key] = it->second + rel; } } int Storybook::LookupStat(const char *ckey) { std::string key(ckey); auto it = stats.find(key); if (it == stats.end()){ stats[key] = 0; return 0; } else { return it->second; } return 0; } void Storybook::Find(const char *id) { for (Page* page : pages) { if (strcmp(page->id, id) == 0) { current = page; return; } } // If not found current = NULL; } void Storybook::Advance() { // TODO throw an exception if the ending type is choices switch(current->footer.type) { case FooterType::End: IsEnded = true; current = NULL; return; case FooterType::Goto: Find(current->footer.link); return; } } void Storybook::Advance(int choice_option) { if (!IsChoiceAvailable(choice_option)) { throw IllegalChoiceException(); } Choice* choice = (*current->footer.choices)[choice_option]; if (statchange_t *cg = choice->statchange) UpdateStat(cg->stat, cg->addend); Find(choice->id); } bool Storybook::IsChoiceAvailable(int choice_option) { Choice* choice = (*current->footer.choices)[choice_option]; if (!choice) return false; statcheck_t *ck = choice->statcheck; if (ck) { int val = LookupStat(ck->stat); if (ck->rel == STATCHECK_GT && val < ck->value || ck->rel == STATCHECK_LT && val > ck->value) return false; } return true; } void Storybook::print_choice(Choice* c) { if (!IsChoiceAvailable(c->option)) printf("\033[;31m"); // Red background printf("%d) %s", c->option, c->flavor); if (c->statchange) { printf("(%s %+d)", c->statchange->stat, c->statchange->addend); } if (!IsChoiceAvailable(c->option)) printf("\033[;0m"); printf("\n"); } void Storybook::Play() { printf(current->body); Choice *choice; switch (current->footer.type) { case FooterType::End: printf("The End."); Advance(); break; case FooterType::Goto: Advance(); printf("Press ENTER to continue..."); std::cin.get(); break; case FooterType::Choices: for (auto c : *current->footer.choices) { print_choice(c.second); } printf("Make a selection: "); int choice_option; std::cin >> choice_option; try { Advance(choice_option); } catch (IllegalChoiceException e) { printf("You can't do that!\n\n"); } break; default: IsEnded = true; } }