Files
wagic/projects/mtg/src/GameOptions.cpp
2011-12-15 11:26:26 +00:00

1230 lines
30 KiB
C++

#include "PrecompiledHeader.h"
#include "utils.h"
#include "MTGDeck.h"
#include "Translate.h"
#include "OptionItem.h"
#include "StyleManager.h"
#include "Credits.h"
#ifdef IOS
#include "JGE.h"
#endif
const string Options::optionNames[] = {
//Global options
"Profile",
"Lang",
//Options set on a per-profile basis
"Theme",
"Mode",
"musicVolume",
"sfxVolume",
"difficulty",
"cheatmode",
"optimizedhand",
"cheatmodedecks",
"displayOSD",
"closed_hand",
"hand_direction",
"mana_display",
"reverse_triggers",
"disable_cards",
"maxGrade",
"ASPhases",
"FirstPlayer",
"KickerPay",
"economic_difficulty",
"transitions",
"bgStyle",
"interruptSeconds",
#if defined(SDL_CONFIG)
"keybindings_sdl",
#elif defined(QT_CONFIG)
"keybindings_qt",
#elif defined(WIN32)
"keybindings_win",
#elif defined(LINUX)
"keybindings_x",
#else
"keybindings_psp",
#endif
"aidecks",
"interruptMySpells",
"interruptMyAbilities",
"saveDetailedDeckInfo",
//General interrupts
"interruptBeforeBegin",
"interruptUntap",
"interruptUpkeep",
"interruptDraw",
"interruptFirstMain",
"interruptBeginCombat",
"interruptAttackers",
"interruptBlockers",
"interruptDamage",
"interruptEndCombat",
"interruptSecondMain",
"interruptEndTurn",
"interruptCleanup",
"interruptAfterEnd",
//Unlocked modes
"prx_handler",
"prx_eviltwin",
"prx_rnddeck",
"aw_collector",
};
#pragma mark Options
int Options::getID(string name)
{
if (0 == name.size())
return INVALID_OPTION;
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
//Is it a named option?
for (int x = 0; x < LAST_NAMED; x++)
{
string lower = Options::optionNames[x];
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
if (lower == name)
return x;
}
//Is it an unlocked set?
if (name.find("unlocked_") == 0)
{
string setname = name.substr(strlen("unlocked_"));
if (setlist.size())
{
int unlocked = setlist[setname];
if (unlocked != -1)
return Options::optionSet(unlocked);
}
}
//Failure.
return INVALID_OPTION;
}
string Options::getName(int option)
{
//Invalid options
if (option < 0)
return "";
//Standard named options
if (option < LAST_NAMED)
return optionNames[option];
//Unlocked sets.
int setID = option - SET_UNLOCKS;
char buf[512];
if (setID < 0 || setID > setlist.size())
return "";
sprintf(buf, "unlocked_%s", setlist[setID].c_str());
return buf;
//Failed.
return "";
}
int Options::optionSet(int setID)
{
//Sanity check if possible
if (setID < 0 || (setID > setlist.size()))
return INVALID_OPTION;
return SET_UNLOCKS + setID;
}
int Options::optionInterrupt(int gamePhase)
{
//Huge, nearly illegible switch block spread out to improve readability.
switch (gamePhase)
{
case MTG_PHASE_BEFORE_BEGIN:
return INTERRUPT_BEFOREBEGIN;
case MTG_PHASE_UNTAP:
return INTERRUPT_UNTAP;
case MTG_PHASE_UPKEEP:
return INTERRUPT_UPKEEP;
case MTG_PHASE_DRAW:
return INTERRUPT_DRAW;
case MTG_PHASE_FIRSTMAIN:
return INTERRUPT_FIRSTMAIN;
case MTG_PHASE_COMBATBEGIN:
return INTERRUPT_BEGINCOMBAT;
case MTG_PHASE_COMBATATTACKERS:
return INTERRUPT_ATTACKERS;
case MTG_PHASE_COMBATBLOCKERS:
return INTERRUPT_BLOCKERS;
case MTG_PHASE_COMBATDAMAGE:
return INTERRUPT_DAMAGE;
case MTG_PHASE_COMBATEND:
return INTERRUPT_ENDCOMBAT;
case MTG_PHASE_SECONDMAIN:
return INTERRUPT_SECONDMAIN;
case MTG_PHASE_ENDOFTURN:
return INTERRUPT_ENDTURN;
case MTG_PHASE_CLEANUP:
return INTERRUPT_CLEANUP;
case MTG_PHASE_AFTER_EOT:
return INTERRUPT_AFTEREND;
}
return INVALID_OPTION;
}
#pragma mark -
#pragma mark GameOption
GameOption::GameOption(int value) :
number(value)
{
}
GameOption::GameOption(string value) :
number(atoi(value.c_str())), str(value)
{
}
GameOption::GameOption(int num, string str) :
number(num), str(str)
{
}
bool GameOption::isDefault()
{
string test = str;
std::transform(test.begin(), test.end(), test.begin(), ::tolower);
if (!test.size() || test == "default")
return true;
return false;
}
PIXEL_TYPE GameOption::asColor(PIXEL_TYPE fallback)
{
unsigned char color[4];
string temp;
int subpixel = 0;
//The absolute shortest a color could be is 5 characters: "0,0,0" (implicit 255 alpha)
if (str.length() < 5)
return fallback;
for (size_t i = 0; i < str.length(); i++)
{
if (isspace(str[i]))
continue;
if (str[i] == ',')
{
if (temp == "")
return fallback;
color[subpixel] = (unsigned char) atoi(temp.c_str());
temp = "";
subpixel++;
continue;
}
else if (!isdigit(str[i]))
return fallback;
if (subpixel > 3)
return fallback;
temp += str[i];
}
if (temp != "")
color[subpixel] = (unsigned char) atoi(temp.c_str());
if (subpixel == 2)
color[3] = 255;
return ARGB(color[3],color[0],color[1],color[2]);
}
bool GameOption::read(string input)
{
bool bNumeric = true;
if (!input.size())
return true; //Default reader doesn't care about invalid formatting.
//Is it a number?
for (size_t x = 0; x < input.size(); x++)
{
if (!isdigit(input[x]))
{
bNumeric = false;
break;
}
}
if (bNumeric)
number = atoi(input.c_str());
else
str = input;
return true;
}
string GameOption::menuStr()
{
if (number)
{
char buf[12];
sprintf(buf, "%d", number);
}
if (str.size())
return str;
return "0";
}
bool GameOption::write(std::ofstream * file, string name)
{
char writer[1024];
if (!file)
return false;
if (str == "")
{
if (number == 0) //This is absolutely default. No need to write it.
return true;
//It's a number!
sprintf(writer, "%s=%d\n", name.c_str(), number);
}
else
sprintf(writer, "%s=%s\n", name.c_str(), str.c_str());
(*file) << writer;
return true;
}
#pragma mark -
#pragma mark GameOptions
GameOptions::GameOptions(string filename)
{
mFilename = filename;
GameOptions::load();
}
int GameOptions::load()
{
std::string contents;
if (JFileSystem::GetInstance()->readIntoString(mFilename, contents))
{
std::stringstream stream(contents);
string s;
while (std::getline(stream, s))
{
if (!s.size())
continue;
if (s[s.size() - 1] == '\r')
s.erase(s.size() - 1); //Handle DOS files
int found = s.find("=");
string name = s.substr(0, found);
string val = s.substr(found + 1);
int id = Options::getID(name);
if (id == INVALID_OPTION)
{
if (!unknownMap[name]) unknownMap[name] = factorNewGameOption(name, val);
continue;
}
(*this)[id].read(val);
}
}
// (PSY) Make sure that cheatmode is switched off for ineligible profiles:
if (options[Options::ACTIVE_PROFILE].str != SECRET_PROFILE)
{
(*this)[Options::CHEATMODE].number = 0;
(*this)[Options::OPTIMIZE_HAND].number = 0;
(*this)[Options::CHEATMODEAIDECK].number = 0;
}
//Default values. Anywhere else to put those ?
if (!(*this)[Options::MAX_GRADE].number)
(*this)[Options::MAX_GRADE].number = Constants::GRADE_BORDERLINE;
if (!(*this)[Options::AIDECKS_UNLOCKED].number)
(*this)[Options::AIDECKS_UNLOCKED].number = 10;
return 1;
}
int GameOptions::save()
{
// (PSY) Make sure that cheatmode is switched off for ineligible profiles:
if (options[Options::ACTIVE_PROFILE].str != SECRET_PROFILE)
{
(*this)[Options::CHEATMODE].number = 0;
(*this)[Options::OPTIMIZE_HAND].number = 0;
(*this)[Options::CHEATMODEAIDECK].number = 0;
}
std::ofstream file;
if (JFileSystem::GetInstance()->openForWrite(file, mFilename))
{
for (int x = 0; x < (int) values.size(); x++)
{
//Check that this is a valid option.
string name = Options::getName(x);
GameOption * opt = get(x);
if (!name.size() || !opt)
continue;
//Save it.
opt->write(&file, name);
}
for (map<string, GameOption *>::iterator it = unknownMap.begin(); it != unknownMap.end(); it++)
{
if (it->second)
{
if (it->second->str.size())
file << it->first << "=" << it->second->str << "\n";
else if (it->second->number)
file << it->first << "=" << it->second->number << "\n";
}
}
file.close();
}
return 1;
}
GameOption& GameOptions::operator[](int optionID)
{
GameOption * go = get(optionID);
if (!go)
return GameSettings::invalid_option;
return *go;
}
GameOption& GameOptions::operator[](string optionName)
{
int id = Options::getID(optionName);
if (id != INVALID_OPTION)
return operator[](id);
GameOption * go = get(optionName);
return * go;
}
GameOption * GameOptions::factorNewGameOption(string optionName, string value)
{
GameOption * result =( Unlockable::unlockables.find(optionName) != Unlockable::unlockables.end())
? NEW GameOptionAward()
: NEW GameOption();
if (value.size())
result->read(value);
return result;
}
GameOption * GameOptions::get(string optionName)
{
if (!unknownMap[optionName])
{
unknownMap[optionName] = factorNewGameOption(optionName);
}
return unknownMap[optionName];
}
GameOption * GameOptions::get(int optionID)
{
//Invalid options!
if (optionID < 0)
return NULL;
//Option doesn't exist, so build it
int x = (int) values.size();
values.reserve(optionID);
while (x <= optionID)
{
GameOption * go = NULL;
GameOptionEnum * goEnum = NULL;
switch (x)
{
//Enum options
case Options::HANDDIRECTION:
goEnum = NEW GameOptionEnum();
goEnum->def = OptionHandDirection::getInstance();
go = goEnum;
break;
case Options::CLOSEDHAND:
goEnum = NEW GameOptionEnum();
goEnum->def = OptionClosedHand::getInstance();
go = goEnum;
break;
case Options::MANADISPLAY:
goEnum = NEW GameOptionEnum();
goEnum->def = OptionManaDisplay::getInstance();
go = goEnum;
break;
case Options::MAX_GRADE:
goEnum = NEW GameOptionEnum();
goEnum->def = OptionMaxGrade::getInstance();
go = goEnum;
break;
case Options::ASPHASES:
goEnum = NEW GameOptionEnum();
goEnum->def = OptionASkipPhase::getInstance();
go = goEnum;
break;
case Options::FIRSTPLAYER:
goEnum = NEW GameOptionEnum();
goEnum->def = OptionWhosFirst::getInstance();
go = goEnum;
break;
case Options::KICKERPAYMENT:
goEnum = NEW GameOptionEnum();
goEnum->def = OptionKicker::getInstance();
go = goEnum;
break;
case Options::KEY_BINDINGS:
go = NEW GameOptionKeyBindings();
break;
case Options::ECON_DIFFICULTY:
goEnum = NEW GameOptionEnum();
goEnum->def = OptionEconDifficulty::getInstance();
go = goEnum;
break;
default:
if (x >= Options::BEGIN_AWARDS)
go = NEW GameOptionAward();
else
go = NEW GameOption();
break;
}
values.push_back(go);
x++;
}
return values[optionID];
}
GameOptions::~GameOptions()
{
for (vector<GameOption*>::iterator it = values.begin(); it != values.end(); it++)
SAFE_DELETE(*it);
values.clear();
for (map<string, GameOption*>::iterator it = unknownMap.begin(); it != unknownMap.end(); it++)
SAFE_DELETE(it->second);
unknownMap.clear();
}
#pragma mark -
#pragma mark GameSettings
GameSettings options;
GameSettings::GameSettings()
{
styleMan = NULL;
globalOptions = NULL;
theGame = NULL;
profileOptions = NULL;
//reloadProfile should be before using options.
}
WStyle * GameSettings::getStyle()
{
if (!styleMan){
styleMan = new StyleManager();
styleMan->determineActive(NULL,NULL);
}
return styleMan->get();
}
StyleManager * GameSettings::getStyleMan()
{
if (!styleMan)
styleMan = new StyleManager();
return styleMan;
}
void GameSettings::automaticStyle(Player * p1, Player * p2)
{
if (!styleMan)
styleMan = new StyleManager();
MTGDeck * decks[2];
for (int i = 0; i < 2; i++)
{
decks[i] = new MTGDeck(MTGCollection());
Player * p;
if (i == 0)
p = p1;
else
p = p2;
map<MTGCardInstance *, int>::iterator it;
for (it = p->game->library->cardsMap.begin(); it != p->game->library->cardsMap.end(); it++)
{
decks[i]->add(it->first);
}
}
styleMan->determineActive(decks[0], decks[1]);
for (int i = 0; i < 2; i++)
{
SAFE_DELETE(decks[i]);
}
}
GameSettings::~GameSettings()
{
SAFE_DELETE(globalOptions);
SAFE_DELETE(profileOptions);
SAFE_DELETE(keypad);
SAFE_DELETE(styleMan);
}
bool GameSettings::newAward()
{
if (!profileOptions)
return false;
for (int x = Options::BEGIN_AWARDS; x < Options::SET_UNLOCKS + setlist.size(); x++)
{
GameOptionAward * goa = dynamic_cast<GameOptionAward *> (profileOptions->get(x));
if (!goa)
continue;
if (!goa->isViewed())
return true;
}
return false;
}
GameOption GameSettings::invalid_option = GameOption(0);
GameOption& GameSettings::operator[](int optionID)
{
GameOption * go = get(optionID);
if (!go)
return invalid_option;
return *go;
}
GameOption& GameSettings::operator[](string optionName)
{
int id = Options::getID(optionName);
if (id != INVALID_OPTION)
return operator[](id);
if (!profileOptions)
return invalid_option;
GameOption * go = profileOptions->get(optionName);
assert(go);
return *go;
}
GameOption* GameSettings::get(int optionID)
{
if (optionID < 0)
return &invalid_option;
else if (globalOptions && optionID <= Options::LAST_GLOBAL)
return globalOptions->get(optionID);
else if (profileOptions)
return profileOptions->get(optionID);
return &invalid_option;
}
void GameSettings::createProfileFolders()
{
if (!profileOptions)
return;
string temp = profileFile("", "", false);
JFileSystem::GetInstance()->MakeDir(temp);
temp += "/stats";
JFileSystem::GetInstance()->MakeDir(temp);
temp = profileFile(PLAYER_SETTINGS, "", false);
profileOptions->save();
}
int GameSettings::save()
{
if (globalOptions)
globalOptions->save();
createProfileFolders();
checkProfile();
return 1;
}
string GameSettings::profileFile(string filename, string fallback, bool sanity)
{
char buf[512];
string profile = (*this)[Options::ACTIVE_PROFILE].str;
if (!(*this)[Options::ACTIVE_PROFILE].isDefault())
{
//No file, return root of profile directory
if (filename == "")
{
sprintf(buf, "profiles/%s", profile.c_str());
return buf;
}
//Return file
sprintf(buf, "profiles/%s/%s", profile.c_str(), filename.c_str());
if (fileExists(buf))
{
return buf;
}
}
else
{
//Use the default directory.
sprintf(buf, "player%s%s", (filename == "" ? "" : "/"), filename.c_str());
return buf;
}
//Don't fallback if sanity checking is disabled..
if (!sanity)
{
sprintf(buf, "profiles/%s%s%s", profile.c_str(), (filename == "" ? "" : "/"), filename.c_str());
return buf;
}
//No fallback directory. This is often a crash.
if (fallback == "")
return "";
sprintf(buf, "%s%s%s", fallback.c_str(), (filename == "" ? "" : "/"), filename.c_str());
return buf;
}
void GameSettings::reloadProfile()
{
SAFE_DELETE(profileOptions);
checkProfile();
}
void GameSettings::checkProfile()
{
if (!globalOptions)
globalOptions = NEW GameOptions(GLOBAL_SETTINGS);
//If it doesn't exist, load current profile.
if (!profileOptions)
{
profileOptions = NEW GameOptions(profileFile(PLAYER_SETTINGS, "", false));
//Backwards compatibility hack for unlocked modes.
for (int x = Options::BEGIN_AWARDS; x < Options::LAST_NAMED; x++)
{
GameOptionAward * goa = dynamic_cast<GameOptionAward *> (globalOptions->get(x));
if (goa)
{
GameOptionAward * dupe = dynamic_cast<GameOptionAward *> (profileOptions->get(x));
if (dupe && goa->number && !dupe->number)
dupe->giveAward();
}
}
}
//Validation of collection, etc, only happens if the game is up.
if (theGame == NULL || MTGCollection() == NULL)
return;
string pcFile = profileFile(PLAYER_COLLECTION, "", false);
if (!pcFile.size() || !fileExists(pcFile.c_str()))
{
//If we had any default settings, we'd set them here.
//Create proper directories
createProfileFolders();
}
//Find the set for which we have the most variety
int setId = -1;
int maxcards = 0;
int ok = 0;
for (int i = 0; i < setlist.size(); i++)
{
int value = MTGCollection()->countBySet(i);
if (value > maxcards)
{
maxcards = value;
setId = i;
}
if (options[Options::optionSet(i)].number)
{
ok = 1;
break;
}
}
if (!ok && setId >= 0)
{
//Save this set as "unlocked"
(*profileOptions)[Options::optionSet(setId)] = 1;
profileOptions->save();
//Give the player their first deck
createUsersFirstDeck(setId);
}
getStyleMan()->determineActive(NULL, NULL);
}
void GameSettings::createUsersFirstDeck(int setId)
{
if (theGame == NULL || MTGCollection() == NULL)
return;
MTGDeck *mCollection = NEW MTGDeck(options.profileFile(PLAYER_COLLECTION, "", false).c_str(), MTGCollection());
if (mCollection->totalCards() > 0)
return;
//10 lands of each
int sets[] = { setId };
if (!mCollection->addRandomCards(10, sets, 1, Constants::RARITY_L, "Forest"))
mCollection->addRandomCards(10, 0, 0, Constants::RARITY_L, "Forest");
if (!mCollection->addRandomCards(10, sets, 1, Constants::RARITY_L, "Plains"))
mCollection->addRandomCards(10, 0, 0, Constants::RARITY_L, "Plains");
if (!mCollection->addRandomCards(10, sets, 1, Constants::RARITY_L, "Swamp"))
mCollection->addRandomCards(10, 0, 0, Constants::RARITY_L, "Swamp");
if (!mCollection->addRandomCards(10, sets, 1, Constants::RARITY_L, "Mountain"))
mCollection->addRandomCards(10, 0, 0, Constants::RARITY_L, "Mountain");
if (!mCollection->addRandomCards(10, sets, 1, Constants::RARITY_L, "Island"))
mCollection->addRandomCards(10, 0, 0, Constants::RARITY_L, "Island");
//Starter Deck
mCollection->addRandomCards(3, sets, 1, Constants::RARITY_R, NULL);
mCollection->addRandomCards(9, sets, 1, Constants::RARITY_U, NULL);
mCollection->addRandomCards(48, sets, 1, Constants::RARITY_C, NULL);
//Boosters
for (int i = 0; i < 2; i++)
{
mCollection->addRandomCards(1, sets, 1, Constants::RARITY_R);
mCollection->addRandomCards(3, sets, 1, Constants::RARITY_U);
mCollection->addRandomCards(11, sets, 1, Constants::RARITY_C);
}
mCollection->save();
SAFE_DELETE(mCollection);
}
void GameSettings::keypadTitle(string set)
{
if (keypad != NULL)
keypad->title = set;
}
SimplePad * GameSettings::keypadStart(string input, string * _dest, bool _cancel, bool _numpad, float _x, float _y)
{
if (keypad == NULL)
keypad = NEW SimplePad();
// show keyboard
#ifdef IOS
JGE *engine = JGE::GetInstance();
engine->SendCommand( "displayKeyboard", input);
#elif ANDROID
JGE *engine = JGE::GetInstance();
engine->SendCommand( "displayKeyboard:" << input);
#endif
keypad->bShowCancel = _cancel;
keypad->bShowNumpad = _numpad;
keypad->mX = _x;
keypad->mY = _y;
keypad->Start(input, _dest);
return keypad;
}
string GameSettings::keypadFinish()
{
if (keypad == NULL)
return "";
return keypad->Finish();
}
void GameSettings::keypadShutdown()
{
SAFE_DELETE(keypad);
}
#pragma mark -
#pragma mark EnumDefinition
//EnumDefinition
int EnumDefinition::findIndex(int value)
{
vector<assoc>::iterator it;
for (it = values.begin(); it != values.end(); it++)
{
if (it->first == value)
return it - values.begin();
}
return INVALID_ID; //Failed!
}
//GameOptionEnum
string GameOptionEnum::menuStr()
{
if (def)
{
int idx = def->findIndex(number);
if (idx != INVALID_ID)
return def->values[idx].second;
}
char buf[32];
sprintf(buf, "%d", number);
return buf;
}
bool GameOptionEnum::write(std::ofstream * file, string name)
{
if (!file || !def || number <= 0 || number >= (int) def->values.size())
return false;
(*file) << name << "=" << menuStr() << endl;
return true;
}
bool GameOptionEnum::read(string input)
{
if (!def)
return false;
number = 0;
std::transform(input.begin(), input.end(), input.begin(), ::tolower);
vector<EnumDefinition::assoc>::iterator it;
for (it = def->values.begin(); it != def->values.end(); it++)
{
string v = it->second;
std::transform(v.begin(), v.end(), v.begin(), ::tolower);
if (v == input)
{
number = it->first;
return true;
}
}
return false;
}
#pragma mark -
#pragma mark OptionMaxGrade
//Enum Definitions
OptionMaxGrade OptionMaxGrade::mDef;
OptionMaxGrade::OptionMaxGrade()
{
mDef.values.push_back(EnumDefinition::assoc(Constants::GRADE_SUPPORTED, "1: 100% Supported"));
mDef.values.push_back(EnumDefinition::assoc(Constants::GRADE_BORDERLINE, "0: Borderline (99% OK)"));
mDef.values.push_back(EnumDefinition::assoc(Constants::GRADE_UNOFFICIAL, "-1: Unofficial (unverified cards)"));
mDef.values.push_back(EnumDefinition::assoc(Constants::GRADE_CRAPPY, "-2: Crappy (bugs)"));
mDef.values.push_back(EnumDefinition::assoc(Constants::GRADE_UNSUPPORTED, "-3: Unsupported"));
mDef.values.push_back(EnumDefinition::assoc(Constants::GRADE_DANGEROUS, "-4: Dangerous (risk of crash)"));
}
;
#pragma mark -
#pragma mark OptionASkipPhase
OptionASkipPhase OptionASkipPhase::mDef;
OptionASkipPhase::OptionASkipPhase()
{
mDef.values.push_back(EnumDefinition::assoc(Constants::ASKIP_NONE, "Off"));
mDef.values.push_back(EnumDefinition::assoc(Constants::ASKIP_SAFE, "Safe"));
mDef.values.push_back(EnumDefinition::assoc(Constants::ASKIP_FULL, "Full"));
}
;
#pragma mark -
#pragma mark OptionWhosFirst
OptionWhosFirst OptionWhosFirst::mDef;
OptionWhosFirst::OptionWhosFirst()
{
mDef.values.push_back(EnumDefinition::assoc(Constants::WHO_P, "Player"));
mDef.values.push_back(EnumDefinition::assoc(Constants::WHO_O, "Opponent"));
mDef.values.push_back(EnumDefinition::assoc(Constants::WHO_R, "Random"));
}
;
OptionClosedHand OptionClosedHand::mDef;
OptionClosedHand::OptionClosedHand()
{
mDef.values.push_back(EnumDefinition::assoc(INVISIBLE, "invisible"));
mDef.values.push_back(EnumDefinition::assoc(VISIBLE, "visible"));
}
;
OptionHandDirection OptionHandDirection::mDef;
OptionHandDirection::OptionHandDirection()
{
mDef.values.push_back(EnumDefinition::assoc(VERTICAL, "vertical"));
mDef.values.push_back(EnumDefinition::assoc(HORIZONTAL, "horizontal"));
}
;
OptionManaDisplay OptionManaDisplay::mDef;
OptionManaDisplay::OptionManaDisplay()
{
mDef.values.push_back(EnumDefinition::assoc(DYNAMIC, "Eye candy"));
mDef.values.push_back(EnumDefinition::assoc(STATIC, "Simple"));
mDef.values.push_back(EnumDefinition::assoc(NOSTARSDYNAMIC, "No Glitter"));
mDef.values.push_back(EnumDefinition::assoc(BOTH, "Both"));//no luck in getting this to show up as an option.
//Both should still work as always however the enum and this dont want to pair up, no "both" in options now.
}
;
OptionVolume OptionVolume::mDef;
OptionVolume::OptionVolume()
{
mDef.values.push_back(EnumDefinition::assoc(MUTE, "Mute"));
mDef.values.push_back(EnumDefinition::assoc(MAX, "Max"));
}
;
OptionDifficulty OptionDifficulty::mDef;
OptionDifficulty::OptionDifficulty()
{
mDef.values.push_back(EnumDefinition::assoc(NORMAL, "Normal"));
mDef.values.push_back(EnumDefinition::assoc(HARD, "Hard"));
mDef.values.push_back(EnumDefinition::assoc(HARDER, "Harder"));
mDef.values.push_back(EnumDefinition::assoc(EVIL, "Evil"));
}
;
OptionEconDifficulty OptionEconDifficulty::mDef;
OptionEconDifficulty::OptionEconDifficulty()
{
mDef.values.push_back(EnumDefinition::assoc(Constants::ECON_NORMAL, "Normal"));
mDef.values.push_back(EnumDefinition::assoc(Constants::ECON_HARD, "Hard"));
mDef.values.push_back(EnumDefinition::assoc(Constants::ECON_LUCK, "Luck"));
mDef.values.push_back(EnumDefinition::assoc(Constants::ECON_EASY, "Easy"));
}
;
OptionKicker OptionKicker::mDef;
OptionKicker::OptionKicker()
{
mDef.values.push_back(EnumDefinition::assoc(Constants::KICKER_ALWAYS, "Always Pay"));
mDef.values.push_back(EnumDefinition::assoc(Constants::KICKER_CHOICE, "Offer Choice"));
}
;
#pragma mark -
#pragma mark GameOptionAward
//GameOptionAward
GameOptionAward::GameOptionAward()
{
achieved = time(NULL);
number = 0;
viewed = false;
}
bool GameOptionAward::read(string input)
{
//This is quick and dirty.
achieved = time(NULL);
tm * at = localtime(&achieved);
viewed = false;
size_t inlen = input.size();
if (!inlen)
return true; //Default reader doesn't care about invalid formatting.
else if (inlen < 8 || input != "0") //Regardless of what garbage this is fed, a non-zero value is "Awarded"
number = 1;
size_t w = input.find("V");
if (w != string::npos)
viewed = true;
//TODO: Something cleaner.
int tvals[5];
int i;
for (i = 0; i < 5; i++)
tvals[i] = 0;
string buf;
for (size_t t = 0, i = 0; t < input.size(); t++)
{
if (!isdigit(input[t]))
{
if (!isspace(input[t]) && buf.size())
{
tvals[i] = atoi(buf.c_str());
if (tvals[i] < 0)
tvals[i] = 0;
buf.clear();
i++; //Advance through input.
}
}
else
buf += input[t];
if (i >= 5)
break;
}
if (tvals[0] >= 1900)
tvals[0] -= 1900;
if (tvals[1] > 0)
tvals[1]--;
at->tm_year = tvals[0];
at->tm_mon = tvals[1];
at->tm_mday = tvals[2];
if (tvals[3])
at->tm_hour = tvals[3];
if (tvals[4])
at->tm_min = tvals[4];
at->tm_isdst = -1;
achieved = mktime(at);
if (achieved == -1)
achieved = time(NULL);
return true;
}
bool GameOptionAward::write(std::ofstream * file, string name)
{
char writer[1024];
if (!file)
return false;
if (number == 0) //Is not unlocked. Don't write.
return true;
tm * at = localtime(&achieved);
if (!at)
return false; //Hurrah for paranoia.
sprintf(writer, "%s=%d/%d/%d@%d:%d %s\n", name.c_str(), at->tm_year + 1900, at->tm_mon + 1, at->tm_mday, at->tm_hour,
at->tm_min, (viewed ? "V" : ""));
(*file) << writer;
return true;
}
bool GameOptionAward::giveAward()
{
if (number)
return false;
achieved = time(NULL);
viewed = false;
number = 1;
options.save(); //TODO - Consider efficiency of this placement.
return true;
}
bool GameOptionAward::isViewed()
{
if (!number)
return true;
return viewed;
}
;
string GameOptionAward::menuStr()
{
if (!number)
return _("Not unlocked.");
else if (achieved == 1)
return _("Unlocked.");
char buf[256];
tm * lt = localtime(&achieved);
if (!lt)
return "Error";
strftime(buf, 255, _("%B %d, %I:%M%p %Y").c_str(), lt);
return buf;
}
static JButton u32_to_button(u32 b)
{
if (b < JGE_BTN_MAX)
return static_cast<JButton> (b);
else
return JGE_BTN_NONE;
}
#pragma mark -
#pragma mark GameOptionKeyBindings
bool GameOptionKeyBindings::read(string input)
{
istringstream iss(input);
vector<pair<LocalKeySym, JButton> > assoc;
while (iss.good())
{
stringstream s;
iss.get(*(s.rdbuf()), ',');
iss.get();
LocalKeySym local;
char sep;
u32 button;
s >> local >> sep >> button;
if (':' != sep)
return false;
assoc.push_back(make_pair(local, u32_to_button(button)));
}
if (assoc.empty())
return false;
JGE* j = JGE::GetInstance();
j->ClearBindings();
for (vector<pair<LocalKeySym, JButton> >::const_iterator it = assoc.begin(); it != assoc.end(); ++it)
j->BindKey(it->first, it->second);
return true;
}
bool GameOptionKeyBindings::write(std::ofstream* file, string name)
{
JGE* j = JGE::GetInstance();
*file << name << "=";
JGE::keybindings_it start = j->KeyBindings_begin(), end = j->KeyBindings_end();
if (start != end)
{
*file << start->first << ":" << start->second;
++start;
}
for (JGE::keybindings_it it = start; it != end; ++it)
*file << "," << it->first << ":" << it->second;
*file << endl;
return true;
}
#pragma mark -