storybook/src/base/storybook.cpp
2022-01-02 19:11:37 -06:00

138 lines
2.8 KiB
C++

#include <cstdlib>
#include <cstring>
#include <iostream>
#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;
}
}