Files
wagic/projects/mtg/src/GameOptions.cpp
T
techdragon.nguyen@gmail.com 8af5870d48 * Added new options parameter. "SaveDetailedDeckInfo". This will force the system to save all
deck files in long format.  This is not configurable from the game.  It must be set manually
     inside options.txt.
     ie.  saveDetailedDeckInfo=1

* added extra debug information (line number inside text file) when card parser fails to recognize a line.
    - modified return value from "processConfLine()" to return 0 only when a true error occurs and print out
         "MTGDeck: Bad Line:
         [<line no>]: <line with error>"
    - processConfLine will now return 1 for lines starting with "#".  Previously it returned 0 which is incorrect
         as comments should not be considered as errors.

* removed DeckMetaDataList class from code.  This was duplicating the DeckMetaData storage in DeckManager
* new feature for deck selection screens.
   - player decks will now have an indication of what mana color it consists of.
   - Ai decks will show symbols once the player has played against the AI deck at least once.
   -- This is made possible with a new meta data inside each deck file.
        MANA:<string representing color switches - 0/1 >
2011-01-31 10:04:18 +00:00

1123 lines
28 KiB
C++

#include "PrecompiledHeader.h"
#include "utils.h"
#include "MTGDeck.h"
#include "GameOptions.h"
#include "Translate.h"
#include "OptionItem.h"
#include "StyleManager.h"
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",
"economic_difficulty",
"transitions",
"bgStyle",
"interruptSeconds",
#if defined(QT_CONFIG)
"keybindings_qt",
#else
#if defined(WIN32)
"keybindings_win",
#else
#if defined(LINUX)
"keybindings_x",
#else
"keybindings_psp",
#endif
#endif
#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_rimom",
"prx_eviltwin",
"prx_rnddeck",
"aw_collector",
};
int Options::getID(string name)
{
if (0 == name.size())
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?
size_t un = strlen("unlocked_");
if (un < name.size())
{
string setname = name.substr(un);
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 Constants::MTG_PHASE_BEFORE_BEGIN:
return INTERRUPT_BEFOREBEGIN;
case Constants::MTG_PHASE_UNTAP:
return INTERRUPT_UNTAP;
case Constants::MTG_PHASE_UPKEEP:
return INTERRUPT_UPKEEP;
case Constants::MTG_PHASE_DRAW:
return INTERRUPT_DRAW;
case Constants::MTG_PHASE_FIRSTMAIN:
return INTERRUPT_FIRSTMAIN;
case Constants::MTG_PHASE_COMBATBEGIN:
return INTERRUPT_BEGINCOMBAT;
case Constants::MTG_PHASE_COMBATATTACKERS:
return INTERRUPT_ATTACKERS;
case Constants::MTG_PHASE_COMBATBLOCKERS:
return INTERRUPT_BLOCKERS;
case Constants::MTG_PHASE_COMBATDAMAGE:
return INTERRUPT_DAMAGE;
case Constants::MTG_PHASE_COMBATEND:
return INTERRUPT_ENDCOMBAT;
case Constants::MTG_PHASE_SECONDMAIN:
return INTERRUPT_SECONDMAIN;
case Constants::MTG_PHASE_ENDOFTURN:
return INTERRUPT_ENDTURN;
case Constants::MTG_PHASE_CLEANUP:
return INTERRUPT_CLEANUP;
case Constants::MTG_PHASE_AFTER_EOT:
return INTERRUPT_AFTEREND;
}
return INVALID_OPTION;
}
GameOption::GameOption(int value) :
number(value)
{
}
GameOption::GameOption(string value) :
number(0), 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;
}
GameOptions::GameOptions(string filename)
{
mFilename = filename;
GameOptions::load();
}
int GameOptions::load()
{
wagic::ifstream file(mFilename.c_str());
std::string s;
if (file)
{
while (std::getline(file, 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)
{
unknown.push_back(s);
continue;
}
(*this)[id].read(val);
}
file.close();
}
// (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(mFilename.c_str());
if (file)
{
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 (vector<string>::size_type t = 0; t < unknown.size(); t++)
file << unknown[t] << "\n";
file.close();
}
return 1;
}
GameOption& GameOptions::operator[](int optionID)
{
GameOption * go = get(optionID);
if (!go)
return GameSettings::invalid_option;
return *go;
}
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::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();
}
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();
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(GameApp::collection);
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::get(int optionID)
{
string option_name = Options::getName(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;
}
int GameSettings::save()
{
if (globalOptions)
globalOptions->save();
if (profileOptions)
{
//Force our directories to exist.
MAKEDIR(JGE_GET_RES("profiles").c_str());
string temp = profileFile("", "", false, false);
MAKEDIR(temp.c_str());
temp += "/stats";
MAKEDIR(temp.c_str());
temp = profileFile(PLAYER_SETTINGS, "", false);
profileOptions->save();
}
checkProfile();
return 1;
}
string GameSettings::profileFile(string filename, string fallback, bool sanity, bool relative)
{
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, "%sprofiles/%s", (relative ? "" : JGE_GET_RES("").c_str()), profile.c_str());
return buf;
}
//Return file
sprintf(buf, JGE_GET_RES("profiles/%s/%s").c_str(), profile.c_str(), filename.c_str());
if (fileExists(buf))
{
if (relative)
sprintf(buf, "profiles/%s/%s", profile.c_str(), filename.c_str());
return buf;
}
}
else
{
//Use the default directory.
sprintf(buf, "%splayer%s%s", (relative ? "" : JGE_GET_RES("").c_str()), (filename == "" ? "" : "/"), filename.c_str());
return buf;
}
//Don't fallback if sanity checking is disabled..
if (!sanity)
{
sprintf(buf, "%sprofiles/%s%s%s", (relative ? "" : JGE_GET_RES("").c_str()), 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%s", (relative ? "" : JGE_GET_RES("").c_str()), fallback.c_str(), (filename == "" ? "" : "/"),
filename.c_str());
return buf;
}
void GameSettings::reloadProfile()
{
SAFE_DELETE(profileOptions);
checkProfile();
}
void GameSettings::checkProfile()
{
if (!globalOptions)
globalOptions = NEW GameOptions(JGE_GET_RES(GLOBAL_SETTINGS));
//If it doesn't exist, load current profile.
if (!profileOptions)
{
profileOptions = NEW GameOptions(profileFile(PLAYER_SETTINGS, "", false));
//Backwards compatability 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 || theGame->collection == 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.
//Make the proper directories
if (profileOptions)
{
//Force our directories to exist.
MAKEDIR(JGE_GET_RES("profiles").c_str());
string temp = profileFile("", "", false, false);
MAKEDIR(temp.c_str());
temp += "/stats";
MAKEDIR(temp.c_str());
temp = profileFile(PLAYER_SETTINGS, "", false);
profileOptions->save();
}
}
//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 = theGame->collection->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 || theGame->collection == NULL)
return;
MTGDeck *mCollection = NEW MTGDeck(options.profileFile(PLAYER_COLLECTION, "", false).c_str(), theGame->collection);
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, int _x, int _y)
{
if (keypad == NULL)
keypad = NEW SimplePad();
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);
}
//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;
}
//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)"));
}
;
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"));
}
;
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"));
}
;
//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;
}
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;
}