Added Enigma game
This commit is contained in:
720
project/jni/application/enigma/src/lev/Index.cpp
Normal file
720
project/jni/application/enigma/src/lev/Index.cpp
Normal file
@@ -0,0 +1,720 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/VolatileIndex.hh"
|
||||
#include "errors.hh"
|
||||
#include "main.hh"
|
||||
#include "options.hh"
|
||||
#include "sound.hh"
|
||||
#include "PreferenceManager.hh"
|
||||
#include "StateManager.hh"
|
||||
#include "lev/ScoreManager.hh"
|
||||
#include "lev/RatingManager.hh"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace enigma { namespace lev {
|
||||
|
||||
std::map<std::string, Index *> Index::indices;
|
||||
std::map<std::string, std::vector<Index *> *> Index::indexGroups;
|
||||
|
||||
Index * Index::currentIndex = NULL;
|
||||
std::string Index::currentGroup;
|
||||
std::map<std::string, std::string> Index::nullExtensions;
|
||||
|
||||
void Index::initGroups() {
|
||||
ASSERT(indexGroups.empty(), XFrontend, "Reinitialization of groups");
|
||||
std::vector<std::string> groupNames = getGroupNames();
|
||||
for (int i = 0; i < groupNames.size(); i++) {
|
||||
std::vector<Index *> *group = new std::vector<Index *>;
|
||||
indexGroups.insert(std::make_pair(groupNames[i], group));
|
||||
}
|
||||
currentGroup = app.state->getString("CurrentGroup");
|
||||
}
|
||||
|
||||
void Index::registerIndex(Index *anIndex) {
|
||||
if (anIndex == NULL)
|
||||
return;
|
||||
|
||||
// check for uniqueness of index name
|
||||
if (findIndex(anIndex->getName()) != NULL)
|
||||
return;
|
||||
|
||||
indices.insert(std::make_pair(anIndex->getName(), anIndex));
|
||||
|
||||
|
||||
// register index in state.xml and update current position, first with last values
|
||||
std::string groupName = "";
|
||||
double stateLocation = 0;
|
||||
app.state->addIndex(anIndex->getName(), groupName, stateLocation,
|
||||
anIndex->currentPosition, anIndex->screenFirstPosition);
|
||||
|
||||
// user location for index?
|
||||
if (stateLocation > 0)
|
||||
anIndex->indexLocation = stateLocation;
|
||||
|
||||
// reset positions that are out of range - this may happen due to
|
||||
// modified levelpacks (updates, deleted levels in auto, new commandline)
|
||||
if (anIndex->currentPosition < 0 || anIndex->currentPosition >= anIndex->size())
|
||||
anIndex->currentPosition = 0;
|
||||
|
||||
// check user preferences for assigned group
|
||||
if (!groupName.empty())
|
||||
anIndex->indexGroup = groupName; // use users preference
|
||||
else
|
||||
groupName = anIndex->indexGroup; // use index default group
|
||||
|
||||
std::vector<Index *> * group;
|
||||
|
||||
// if no prefs ask for index default group
|
||||
|
||||
// make new group if not existing
|
||||
if (groupName != INDEX_EVERY_GROUP) {
|
||||
std::map<std::string, std::vector<Index *> *>::iterator i = indexGroups.find(groupName);
|
||||
if (i != indexGroups.end()) {
|
||||
group = i->second;
|
||||
} else {
|
||||
// make the group
|
||||
group = new std::vector<Index *>;
|
||||
indexGroups.insert(std::make_pair(groupName, group));
|
||||
app.state->addGroup(groupName, anIndex->getName(), 0);
|
||||
|
||||
// fill group with indices that appear in every group
|
||||
std::map<std::string, Index *>::iterator iti;
|
||||
for (iti = indices.begin(); iti != indices.end(); iti++)
|
||||
if ((*iti).second->getGroupName() == INDEX_EVERY_GROUP)
|
||||
addIndexToGroup((*iti).second, group);
|
||||
}
|
||||
}
|
||||
|
||||
if (groupName != INDEX_EVERY_GROUP) {
|
||||
// insert according to user prefs or index defaults
|
||||
addIndexToGroup(anIndex, group);
|
||||
addIndexToGroup(anIndex, getGroup(INDEX_ALL_PACKS));
|
||||
} else {
|
||||
// add index to all groups inclusive INDEX_ALL_PACKS
|
||||
std::map<std::string, std::vector<Index *> *>::iterator itg;
|
||||
for (itg = indexGroups.begin(); itg != indexGroups.end(); itg++)
|
||||
addIndexToGroup(anIndex, (*itg).second);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void Index::addIndexToGroup(Index *anIndex, std::vector<Index *> * aGroup) {
|
||||
std::vector<Index *>::iterator itg;
|
||||
for (itg = aGroup->begin(); itg != aGroup->end() &&
|
||||
(*itg)->indexLocation <= anIndex->indexLocation;
|
||||
itg++) {
|
||||
}
|
||||
aGroup->insert(itg, anIndex);
|
||||
}
|
||||
|
||||
void Index::removeIndexFromGroup(Index *anIndex, std::string groupName) {
|
||||
std::vector<Index *> *theGroup = indexGroups[groupName];
|
||||
std::vector<Index *>::iterator itg;
|
||||
for (itg = theGroup->begin(); itg != theGroup->end(); itg++) {
|
||||
if ((*itg) == anIndex) {
|
||||
theGroup->erase(itg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Index * Index::findIndex(std::string anIndexName) {
|
||||
std::string::size_type lastChar = anIndexName.find_last_not_of(" ");
|
||||
if (lastChar == std::string::npos)
|
||||
// the name is effectively an empty string
|
||||
return NULL;
|
||||
|
||||
// stip of trailing and leading spaces
|
||||
std::string name = anIndexName.substr(0 , lastChar + 1);
|
||||
name = name.substr(anIndexName.find_first_not_of(" "));
|
||||
|
||||
std::map<std::string, Index *>::iterator i = indices.find(name);
|
||||
if (i != indices.end())
|
||||
return i->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string Index::getCurrentGroup() {
|
||||
if (currentIndex == NULL)
|
||||
// initialize current group
|
||||
getCurrentIndex();
|
||||
return currentGroup;
|
||||
}
|
||||
|
||||
void Index::setCurrentGroup(std::string groupName) {
|
||||
// set group - even "All Packs"
|
||||
app.state->setProperty("CurrentGroup", groupName);
|
||||
currentGroup = groupName;
|
||||
|
||||
// set current index for desired group
|
||||
std::string indexName = getGroupSelectedIndex(groupName);
|
||||
Index * newIndex = findIndex(indexName);
|
||||
std::string indexGroupName;
|
||||
|
||||
if (newIndex != NULL)
|
||||
indexGroupName = newIndex->getGroupName();
|
||||
|
||||
if (newIndex != NULL && (indexGroupName == groupName ||
|
||||
indexGroupName == INDEX_EVERY_GROUP ||
|
||||
groupName == INDEX_ALL_PACKS)) {
|
||||
// set the groups current index as main current index
|
||||
setCurrentIndex(indexName);
|
||||
} else {
|
||||
// the groups current index is no longer available or did change the
|
||||
// group -- reset the groups current index
|
||||
std::vector<Index *> * group = getGroup(groupName);
|
||||
if (group->size() > 0) {
|
||||
setCurrentIndex((*group)[0]->getName());
|
||||
} else {
|
||||
// the group is empty -- delete group current index entry and
|
||||
// leave the apps current index unchanged
|
||||
setGroupSelectedIndex(groupName,"");
|
||||
}
|
||||
}
|
||||
// Log << "Index setCurrentGroup: wanted " << groupName << " - got " << currentGroup << " - idxGroup " << indexGroupName <<"\n";
|
||||
}
|
||||
|
||||
std::vector<std::string> Index::getGroupNames() {
|
||||
std::vector<std::string> names;
|
||||
app.state->getGroupNames(&names);
|
||||
return names;
|
||||
}
|
||||
|
||||
void Index::deleteGroup(std::string groupName) {
|
||||
std::vector<Index *> * theGroup = getGroup(groupName);
|
||||
if (theGroup != NULL) {
|
||||
indexGroups.erase(groupName);
|
||||
delete theGroup;
|
||||
}
|
||||
|
||||
if (currentGroup == groupName) {
|
||||
std::vector<std::string> groups = getGroupNames();
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
if (groups[i] == groupName) {
|
||||
if (i > 0) {
|
||||
setCurrentGroup(groups[i-1]);
|
||||
} else {
|
||||
ASSERT (groups.size() > 1, XFrontend, "Delete of last existing group.");
|
||||
setCurrentGroup(groups[1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
app.state->deleteGroup(groupName);
|
||||
}
|
||||
|
||||
void Index::moveGroup(std::string groupName, int newPos) {
|
||||
std::string indexName = app.state->getGroupSelectedIndex(groupName);
|
||||
std::string column = app.state->getGroupSelectedColumn(groupName);
|
||||
app.state->deleteGroup(groupName);
|
||||
app.state->insertGroup(newPos, groupName, indexName, column);
|
||||
}
|
||||
|
||||
void Index::renameGroup(std::string oldName, std::string newName) {
|
||||
// rename state group element
|
||||
app.state->renameGroup(oldName, newName);
|
||||
|
||||
// rename map of groups
|
||||
std::vector<Index *> * group = getGroup(oldName);
|
||||
indexGroups.erase(oldName);
|
||||
indexGroups.insert(std::make_pair(newName, group));
|
||||
|
||||
// rename group name in indices
|
||||
for (int i = 0; i < group->size(); i++) {
|
||||
if ((*group)[i]->getGroupName() == oldName) {
|
||||
(*group)[i]->indexGroup = newName;
|
||||
// set group as users choice for index in state
|
||||
app.state->setIndexGroup((*group)[i]->getName(), newName);
|
||||
}
|
||||
}
|
||||
|
||||
// handle currentGroup
|
||||
if (currentGroup == oldName) {
|
||||
currentGroup = newName;
|
||||
app.state->setProperty("CurrentGroup", newName);
|
||||
}
|
||||
}
|
||||
|
||||
void Index::insertGroup(std::string groupName, int newPos) {
|
||||
// make the group
|
||||
std::vector<Index *> *group = new std::vector<Index *>;
|
||||
indexGroups.insert(std::make_pair(groupName, group));
|
||||
app.state->insertGroup(newPos, groupName, "", "");
|
||||
|
||||
// fill group with indices that appear in every group
|
||||
std::map<std::string, Index *>::iterator iti;
|
||||
for (iti = indices.begin(); iti != indices.end(); iti++)
|
||||
if ((*iti).second->getGroupName() == INDEX_EVERY_GROUP)
|
||||
addIndexToGroup((*iti).second, group);
|
||||
|
||||
setCurrentGroup(groupName);
|
||||
}
|
||||
|
||||
std::string Index::getGroupSelectedIndex(std::string groupName) {
|
||||
return app.state->getGroupSelectedIndex(groupName);
|
||||
}
|
||||
|
||||
int Index::getGroupSelectedColumn(std::string groupName) {
|
||||
std::string columnString = app.state->getGroupSelectedColumn(groupName);
|
||||
if (columnString.empty())
|
||||
return INDEX_GROUP_COLUMN_UNKNOWN;
|
||||
else {
|
||||
int col = INDEX_GROUP_COLUMN_UNKNOWN;
|
||||
std::sscanf(columnString.c_str(), "%i", &col);
|
||||
return col;
|
||||
}
|
||||
}
|
||||
|
||||
void Index::setGroupSelectedIndex(std::string groupName, std::string indexName) {
|
||||
app.state->setGroupSelectedIndex(groupName, indexName);
|
||||
}
|
||||
|
||||
void Index::setGroupSelectedColumn(std::string groupName, int column) {
|
||||
if (column == INDEX_GROUP_COLUMN_UNKNOWN)
|
||||
app.state->setGroupSelectedColumn(groupName, "");
|
||||
else
|
||||
app.state->setGroupSelectedColumn(groupName, ecl::strf("%d",column));
|
||||
}
|
||||
|
||||
Index * Index::getCurrentIndex() {
|
||||
if (currentIndex == NULL) {
|
||||
// first look for user preference
|
||||
if (setCurrentIndex(app.state->getGroupSelectedIndex(
|
||||
app.state->getString("CurrentGroup"))))
|
||||
;
|
||||
|
||||
// fallback to "Tutorial" pack
|
||||
else if (setCurrentIndex("Tutorial"))
|
||||
;
|
||||
|
||||
// fallback to any pack
|
||||
else if (!indices.empty()) {
|
||||
setCurrentIndex(indices.begin()->second->getName());
|
||||
}
|
||||
// add empty pack
|
||||
else {
|
||||
std::vector<std::string> emptyList;
|
||||
registerIndex(new lev::VolatileIndex("Empty Index",
|
||||
INDEX_DEFAULT_GROUP, emptyList));
|
||||
setCurrentIndex("Empty Index");
|
||||
}
|
||||
}
|
||||
return currentIndex;
|
||||
}
|
||||
|
||||
bool Index::setCurrentIndex(std::string anIndexName) {
|
||||
Index * newIndex = findIndex(anIndexName);
|
||||
if (newIndex != NULL) {
|
||||
if (newIndex != currentIndex) {
|
||||
sound::SetDefaultSoundSet(newIndex->get_default_SoundSet());
|
||||
currentIndex = newIndex;
|
||||
std::string group = currentIndex->getGroupName();
|
||||
if (group != INDEX_EVERY_GROUP &&
|
||||
app.state->getString("CurrentGroup") != INDEX_ALL_PACKS) {
|
||||
app.state->setProperty("CurrentGroup", group);
|
||||
currentGroup = group;
|
||||
}
|
||||
if (getGroupSelectedIndex(currentGroup) != currentIndex->getName()) {
|
||||
setGroupSelectedIndex(currentGroup, currentIndex->getName());
|
||||
setGroupSelectedColumn(currentGroup, INDEX_GROUP_COLUMN_UNKNOWN);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Index * Index::nextGroupIndex() {
|
||||
std::vector<Index *> * curGroup = getGroup(currentGroup);
|
||||
ASSERT(curGroup != NULL, XFrontend, "");
|
||||
|
||||
for (int i = 0; i < curGroup->size() - 1; i++) {
|
||||
if ((*curGroup)[i] == currentIndex)
|
||||
return (*curGroup)[i+1];
|
||||
}
|
||||
return currentIndex;
|
||||
}
|
||||
|
||||
Index * Index::previousGroupIndex() {
|
||||
std::vector<Index *> * curGroup = getGroup(currentGroup);
|
||||
ASSERT(curGroup != NULL, XFrontend, "");
|
||||
|
||||
for (int i = 1; i < curGroup->size(); i++) {
|
||||
if ((*curGroup)[i] == currentIndex)
|
||||
return (*curGroup)[i-1];
|
||||
}
|
||||
return currentIndex;
|
||||
}
|
||||
|
||||
Proxy * Index::getCurrentProxy() {
|
||||
return getCurrentIndex()->getCurrent();
|
||||
}
|
||||
|
||||
std::vector<Index *> * Index::getGroup(std::string groupName) {
|
||||
std::map<std::string, std::vector<Index *> *>::iterator i = indexGroups.find(groupName);
|
||||
if (i != indexGroups.end())
|
||||
return i->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double Index::getNextUserLocation() {
|
||||
double lastUsed = INDEX_USER_PACK_LOCATION;
|
||||
std::map<std::string, Index *>::iterator iti;
|
||||
for (iti = indices.begin(); iti != indices.end(); iti++) {
|
||||
double idxLocation = (*iti).second->indexLocation;
|
||||
if (idxLocation > lastUsed && idxLocation < INDEX_DEFAULT_PACK_LOCATION) {
|
||||
lastUsed = idxLocation;
|
||||
}
|
||||
}
|
||||
if (lastUsed + 999 < INDEX_DEFAULT_PACK_LOCATION)
|
||||
return lastUsed + 100;
|
||||
else
|
||||
return 0.9 * lastUsed + INDEX_DEFAULT_PACK_LOCATION / 10;
|
||||
}
|
||||
|
||||
|
||||
Index::Index(std::string anIndexName, std::string aGroupName, double defaultLocation) :
|
||||
indexName (anIndexName), indexGroup (aGroupName), defaultGroup (aGroupName),
|
||||
indexLocation (defaultLocation), indexDefaultLocation (defaultLocation),
|
||||
currentPosition (0), screenFirstPosition (0) {
|
||||
}
|
||||
|
||||
Index::~Index() {}
|
||||
|
||||
std::string Index::getName() {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
std::string Index::getGroupName() {
|
||||
return indexGroup;
|
||||
}
|
||||
|
||||
std::string Index::getDefaultGroupName() {
|
||||
return defaultGroup;
|
||||
}
|
||||
|
||||
double Index::getLocation() {
|
||||
return indexLocation;
|
||||
}
|
||||
|
||||
double Index::getDefaultLocation() {
|
||||
return indexDefaultLocation;
|
||||
}
|
||||
|
||||
void Index::setDefaultLocation(double defLocation) {
|
||||
indexDefaultLocation = defLocation;
|
||||
}
|
||||
|
||||
void Index::moveToGroup(std::string newGroupName) {
|
||||
// remove from old group
|
||||
if (indexGroup != INDEX_EVERY_GROUP) {
|
||||
// remove index from the unique group
|
||||
removeIndexFromGroup(this, indexGroup);
|
||||
removeIndexFromGroup(this, INDEX_ALL_PACKS);
|
||||
} else {
|
||||
// remove index from all groups inclusive INDEX_ALL_PACKS
|
||||
std::vector<std::string> groupNames = getGroupNames();
|
||||
for (int i = 0; i < groupNames.size(); i++)
|
||||
removeIndexFromGroup(this, groupNames[i]);
|
||||
// declare this index as not belonging to any group
|
||||
indexGroup = "";
|
||||
}
|
||||
|
||||
// create group if not existing
|
||||
if (newGroupName != INDEX_EVERY_GROUP) {
|
||||
std::map<std::string, std::vector<Index *> *>::iterator i = indexGroups.find(newGroupName);
|
||||
if (i == indexGroups.end()) {
|
||||
// make the group
|
||||
std::vector<Index *> *group = new std::vector<Index *>;
|
||||
indexGroups.insert(std::make_pair(newGroupName, group));
|
||||
app.state->addGroup(newGroupName, indexName, 0);
|
||||
|
||||
// fill group with indices that appear in every group
|
||||
std::map<std::string, Index *>::iterator iti;
|
||||
for (iti = indices.begin(); iti != indices.end(); iti++)
|
||||
if ((*iti).second->getGroupName() == INDEX_EVERY_GROUP)
|
||||
addIndexToGroup((*iti).second, group);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
indexGroup = newGroupName;
|
||||
|
||||
// add to new group
|
||||
if (newGroupName != INDEX_EVERY_GROUP) {
|
||||
// insert according to user prefs or index defaults
|
||||
addIndexToGroup(this, getGroup(newGroupName));
|
||||
addIndexToGroup(this, getGroup(INDEX_ALL_PACKS));
|
||||
} else {
|
||||
// add index to all groups inclusive INDEX_ALL_PACKS
|
||||
std::map<std::string, std::vector<Index *> *>::iterator itg;
|
||||
for (itg = indexGroups.begin(); itg != indexGroups.end(); itg++)
|
||||
addIndexToGroup(this, (*itg).second);
|
||||
}
|
||||
|
||||
// store new group as users state
|
||||
app.state->setIndexGroup(indexName,
|
||||
newGroupName == defaultGroup ? "" : newGroupName);
|
||||
|
||||
// select this index with its new group if it is the current Index
|
||||
if (this == currentIndex) {
|
||||
if (indexGroup != INDEX_EVERY_GROUP &&
|
||||
app.state->getString("CurrentGroup") != INDEX_ALL_PACKS) {
|
||||
app.state->setProperty("CurrentGroup", indexGroup);
|
||||
currentGroup = indexGroup;
|
||||
}
|
||||
if (getGroupSelectedIndex(currentGroup) != currentIndex->getName()) {
|
||||
setGroupSelectedIndex(currentGroup, currentIndex->getName());
|
||||
setGroupSelectedColumn(currentGroup, INDEX_GROUP_COLUMN_UNKNOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int indexLocationCompare(Index * first, Index * second) {
|
||||
return first->getLocation() < second->getLocation();
|
||||
}
|
||||
|
||||
void Index::locateBehind(std::string predName) {
|
||||
double predLocation = 0;
|
||||
double succLocation = 0;
|
||||
double newLocation;
|
||||
std::string predGroup;
|
||||
std::string succGroup;
|
||||
std::vector<Index *> * allGroup = getGroup(INDEX_ALL_PACKS);
|
||||
if (predName.empty()) {
|
||||
succLocation = (*allGroup)[0]->indexLocation;
|
||||
succGroup = (*allGroup)[0]->indexGroup;
|
||||
} else {
|
||||
for (int i = 0; i < allGroup->size(); i++) {
|
||||
if ((*allGroup)[i]->getName() == predName) {
|
||||
predLocation = (*allGroup)[i]->indexLocation;
|
||||
predGroup = (*allGroup)[i]->indexGroup;
|
||||
int succ = 0;
|
||||
if ((i+1 < allGroup->size()) && ((*allGroup)[i+1] != this)) {
|
||||
succ = i + 1;
|
||||
} else if (i+2 < allGroup->size()) {
|
||||
succ = i + 2;
|
||||
}
|
||||
if (succ > 0) {
|
||||
succLocation = (*allGroup)[succ]->indexLocation;
|
||||
succGroup = (*allGroup)[succ]->indexGroup;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT (!(predLocation == 0 && succLocation == 0), XFrontend, "");
|
||||
if (predLocation == 0) {
|
||||
if (succGroup == indexGroup) {
|
||||
newLocation = succLocation * 0.98;
|
||||
} else {
|
||||
newLocation = succLocation * 0.75;
|
||||
}
|
||||
} else if (succLocation == 0) {
|
||||
if (predGroup == indexGroup) {
|
||||
newLocation = predLocation + 100;
|
||||
} else {
|
||||
newLocation = predLocation + 10000;
|
||||
}
|
||||
} else if ((predGroup == indexGroup && succGroup == indexGroup) ||
|
||||
(predGroup != indexGroup && succGroup != indexGroup)){
|
||||
newLocation = (predLocation + succLocation) / 2;
|
||||
} else if (predGroup == indexGroup) {
|
||||
newLocation = 0.95 * predLocation + 0.05 * succLocation;
|
||||
} else {
|
||||
newLocation = 0.05 * predLocation + 0.95 * succLocation;
|
||||
}
|
||||
// Log << "newLocation " << newLocation << "\n";
|
||||
indexLocation = newLocation;
|
||||
app.state->setIndexLocation(indexName, indexLocation);
|
||||
|
||||
// reorder all groups according to new location
|
||||
std::map<std::string, std::vector<Index *> *>::iterator itg;
|
||||
for (itg = indexGroups.begin(); itg != indexGroups.end(); itg++)
|
||||
std::sort((*itg).second->begin(), (*itg).second->end(), indexLocationCompare);
|
||||
}
|
||||
|
||||
void Index::renameIndex(std::string newName) {
|
||||
indices.erase(indexName);
|
||||
indices[newName] = this;
|
||||
app.state->setIndexName(indexName, newName);
|
||||
indexName = newName;
|
||||
}
|
||||
|
||||
bool Index::isSource(Proxy *) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int Index::getCurrentPosition() {
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
int Index::getCurrentLevel() {
|
||||
return currentPosition + 1;
|
||||
}
|
||||
|
||||
Proxy * Index::getCurrent() {
|
||||
return getProxy(currentPosition);
|
||||
}
|
||||
|
||||
void Index::setCurrentPosition(int newPos) {
|
||||
// reset positions that are out of range - this may happen due to
|
||||
// editable Indices
|
||||
if (newPos < 0 || newPos > size())
|
||||
newPos = 0;
|
||||
|
||||
//
|
||||
currentPosition = newPos;
|
||||
app.state->setIndexCurpos(getName(), currentPosition);
|
||||
}
|
||||
|
||||
int Index::getScreenFirstPosition() {
|
||||
return screenFirstPosition;
|
||||
}
|
||||
|
||||
void Index::setScreenFirstPosition(int iFirstPos) {
|
||||
screenFirstPosition = iFirstPos;
|
||||
app.state->setIndexCurfirst(getName(), screenFirstPosition);
|
||||
}
|
||||
|
||||
bool Index::mayPlayLevel(int levelNumber) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Proxy * Index::getProxy(int pos) {
|
||||
if (pos >= 0 && pos < proxies.size())
|
||||
return proxies[pos];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Index::containsProxy(Proxy * aProxy) {
|
||||
for (int i = 0; i < proxies.size(); i++) {
|
||||
if (proxies[i] == aProxy)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Index::hasNormLevelPath(std::string path) {
|
||||
for (int i = 0; i < proxies.size(); i++) {
|
||||
if (proxies[i]->getNormLevelPath() == path)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Index::advanceLevel(LevelAdvanceMode advMode) {
|
||||
NextLevelMode nextMode = static_cast<NextLevelMode>(app.state->getInt("NextLevelMode"));
|
||||
|
||||
switch (advMode) {
|
||||
case ADVANCE_STRICTLY:
|
||||
nextMode = NEXT_LEVEL_STRICTLY;
|
||||
break;
|
||||
case ADVANCE_UNSOLVED:
|
||||
nextMode = NEXT_LEVEL_UNSOLVED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
bool found = false;
|
||||
const int max = size();
|
||||
int newPos = currentPosition;
|
||||
lev::ScoreManager *scm = lev::ScoreManager::instance();
|
||||
lev::RatingManager *ratingMgr = lev::RatingManager::instance();
|
||||
int difficulty = app.state->getInt("Difficulty");
|
||||
|
||||
while (newPos < max - 1 && !found) {
|
||||
++newPos;
|
||||
|
||||
if (nextMode == NEXT_LEVEL_UNSOLVED || nextMode == NEXT_LEVEL_NOT_BEST ||
|
||||
nextMode == NEXT_LEVEL_OVER_PAR) {
|
||||
bool solved = scm->isSolved(proxies[newPos], difficulty);
|
||||
if (!solved) // always play unsolved levels
|
||||
found = true;
|
||||
else { // solved levels
|
||||
if (nextMode == NEXT_LEVEL_NOT_BEST) {
|
||||
int par_time = ratingMgr->getBestScore(proxies[newPos], difficulty);
|
||||
int best_user_time = scm->getBestUserScore(proxies[newPos], difficulty);
|
||||
if (best_user_time<0 || (par_time>0 && best_user_time>par_time))
|
||||
found = true;
|
||||
} else if (nextMode == NEXT_LEVEL_OVER_PAR) {
|
||||
int par_time = ratingMgr->getParScore(proxies[newPos], difficulty);
|
||||
int best_user_time = scm->getBestUserScore(proxies[newPos], difficulty);
|
||||
if (best_user_time<0 || (par_time>0 && best_user_time>par_time))
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
found = true;
|
||||
}
|
||||
if (!found)
|
||||
newPos = 0; // ?
|
||||
|
||||
currentPosition = newPos;
|
||||
return found;
|
||||
}
|
||||
|
||||
int Index::size() const {
|
||||
return proxies.size();
|
||||
}
|
||||
|
||||
void Index::appendProxy(Proxy * newLevel, controlType varCtrl,
|
||||
scoreUnitType varUnit, std::string varTarget,
|
||||
std::map<std::string, std::string> varExtensions) {
|
||||
proxies.push_back(newLevel);
|
||||
}
|
||||
|
||||
void Index::clear() {
|
||||
// proxies.clear();
|
||||
}
|
||||
|
||||
void Index::updateFromProxies() {
|
||||
for (int i = 0, l = proxies.size(); i < l; i++) {
|
||||
try {
|
||||
proxies[i]->loadMetadata(true);
|
||||
} catch (XLevelLoading &err) {
|
||||
// silently ignore errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- LevelPack interface ---------- */
|
||||
|
||||
|
||||
/*! Return the default SoundSet (see options::SoundSet for meaning) */
|
||||
const char* Index::get_default_SoundSet() const {
|
||||
return "Enigma";
|
||||
}
|
||||
|
||||
/*! Returns true if it's a twoplayer levelpack, but has no
|
||||
it-yinyang (needed to add it-yinyang to inventory if
|
||||
oxyd-linkgame is played as single-player) */
|
||||
bool Index::needs_twoplayers() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
}} // namespace enigma::lev
|
||||
179
project/jni/application/enigma/src/lev/Index.hh
Normal file
179
project/jni/application/enigma/src/lev/Index.hh
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef LEV_INDEX_HH_INCLUDED
|
||||
#define LEV_INDEX_HH_INCLUDED
|
||||
|
||||
#include "lev/Proxy.hh"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define INDEX_DEFAULT_GROUP "User"
|
||||
#define INDEX_EVERY_GROUP "Every Group"
|
||||
#define INDEX_ALL_PACKS "All Packs"
|
||||
|
||||
#define INDEX_STARTUP_PACK_NAME "Startup Levels"
|
||||
#define INDEX_AUTO_PACK_NAME "Auto Folder"
|
||||
#define INDEX_HISTORY_PACK_NAME "History"
|
||||
#define INDEX_SEARCH_PACK_NAME "Search Result"
|
||||
#define INDEX_CLIPBOARD_PACK_NAME "Clipboard"
|
||||
|
||||
#define INDEX_STARTUP_PACK_LOCATION 5100
|
||||
#define INDEX_AUTO_PACK_LOCATION 5200
|
||||
#define INDEX_HISTORY_PACK_LOCATION 5300
|
||||
#define INDEX_SEARCH_PACK_LOCATION 5400
|
||||
#define INDEX_CLIPBOARD_PACK_LOCATION 5500
|
||||
|
||||
#define INDEX_USER_PACK_LOCATION 50000
|
||||
#define INDEX_DEFAULT_PACK_LOCATION 69000
|
||||
|
||||
#define INDEX_GROUP_COLUMN_UNKNOWN -1000
|
||||
|
||||
|
||||
|
||||
namespace enigma { namespace lev {
|
||||
enum LevelAdvanceMode {
|
||||
ADVANCE_NEXT_MODE, // honor NextLevelMode
|
||||
ADVANCE_STRICTLY, // move to the next level in index
|
||||
ADVANCE_UNSOLVED // move to next not yet solved level
|
||||
};
|
||||
|
||||
enum NextLevelMode {
|
||||
NEXT_LEVEL_STRICTLY, // move to the next level in index
|
||||
NEXT_LEVEL_UNSOLVED, // move to next not yet solved level
|
||||
NEXT_LEVEL_NOT_BEST, // move to next level where player is not best score holder
|
||||
NEXT_LEVEL_OVER_PAR // move to next level with a score over PAR
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Index {
|
||||
public:
|
||||
static void initGroups();
|
||||
static void registerIndex(Index *anIndex);
|
||||
static Index * findIndex(std::string anIndexName);
|
||||
static Index * getCurrentIndex();
|
||||
static bool setCurrentIndex(std::string anIndexName);
|
||||
static Index * nextGroupIndex();
|
||||
static Index * previousGroupIndex();
|
||||
static Proxy * getCurrentProxy();
|
||||
static std::string getCurrentGroup();
|
||||
static void setCurrentGroup(std::string groupName);
|
||||
static std::vector<std::string> getGroupNames();
|
||||
static std::vector<Index *> * getGroup(std::string groupName);
|
||||
static std::string getGroupSelectedIndex(std::string groupName);
|
||||
static int getGroupSelectedColumn(std::string groupName);
|
||||
static void setGroupSelectedIndex(std::string groupName, std::string indexName);
|
||||
static void setGroupSelectedColumn(std::string groupName, int column);
|
||||
static void deleteGroup(std::string groupName);
|
||||
static void moveGroup(std::string groupName, int newPos);
|
||||
static void renameGroup(std::string oldName, std::string newName);
|
||||
static void insertGroup(std::string groupName, int newPos);
|
||||
static double getNextUserLocation();
|
||||
|
||||
/**
|
||||
* Convention: method names *Level() can take int pos or Proxy as arg.
|
||||
*/
|
||||
Index(std::string anIndexName = "Unnamed Pack",
|
||||
std::string aGroupName = INDEX_DEFAULT_GROUP,
|
||||
double defaultLocation = INDEX_DEFAULT_PACK_LOCATION);
|
||||
~Index();
|
||||
|
||||
std::string getName();
|
||||
std::string getGroupName();
|
||||
std::string getDefaultGroupName();
|
||||
double getLocation();
|
||||
double getDefaultLocation();
|
||||
void setDefaultLocation(double defLocation);
|
||||
void moveToGroup(std::string groupName);
|
||||
void locateBehind(std::string indexName);
|
||||
void renameIndex(std::string newName);
|
||||
virtual bool isSource(Proxy * aProxy);
|
||||
|
||||
int getCurrentPosition(); // 0 .. size-1
|
||||
int getCurrentLevel(); // 1 .. size
|
||||
Proxy * getCurrent();
|
||||
void setCurrentPosition(int newPos);
|
||||
int getScreenFirstPosition();
|
||||
void setScreenFirstPosition(int iFirstPos);
|
||||
virtual bool mayPlayLevel(int levelNumber);
|
||||
Proxy * getProxy(int pos);
|
||||
bool containsProxy(Proxy * aProxy);
|
||||
bool hasNormLevelPath(std::string path);
|
||||
virtual bool advanceLevel(LevelAdvanceMode advMode);
|
||||
|
||||
/*! Return number of levels */
|
||||
virtual int size() const;
|
||||
virtual void appendProxy(Proxy * newLevel, controlType varCtrl = force,
|
||||
scoreUnitType varUnit = duration, std::string varTarget = "time",
|
||||
std::map<std::string, std::string> varExtensions = nullExtensions);
|
||||
virtual void clear();
|
||||
void updateFromProxies();
|
||||
|
||||
// ---------- LevelPack legacy methods ---to be renamed ------- */
|
||||
/*! Return the default SoundSet (see options::SoundSet for meaning) */
|
||||
virtual const char* get_default_SoundSet() const;
|
||||
|
||||
/*! Returns true if it's a twoplayer levelpack, but has no
|
||||
it-yinyang (needed to add it-yinyang to inventory if
|
||||
oxyd-linkgame is played as single-player) */
|
||||
virtual bool needs_twoplayers() const;
|
||||
|
||||
|
||||
protected:
|
||||
std::string indexName;
|
||||
std::string indexGroup;
|
||||
double indexLocation;
|
||||
std::string defaultGroup;
|
||||
double indexDefaultLocation;
|
||||
int currentPosition; // 0,...
|
||||
int screenFirstPosition; // LevelWidget ifirst
|
||||
std::vector<Proxy *> proxies;
|
||||
static std::map<std::string, std::string> nullExtensions;
|
||||
|
||||
private:
|
||||
/**
|
||||
* A map of index names to the indices themselves.
|
||||
*/
|
||||
static std::map<std::string, Index *> indices;
|
||||
|
||||
/**
|
||||
* A map of index group names to vectors of indices. The vectors
|
||||
* are sorted by the user sequence preference in the index group menu.
|
||||
* Every index is listed in the group the user asigned it to.
|
||||
*/
|
||||
static std::map<std::string, std::vector<Index *> *> indexGroups;
|
||||
|
||||
/**
|
||||
* Current active index. This index is selected in the Levelpack menu,
|
||||
* shown and used in the submenus and stored in the user preferences.
|
||||
* It's default is the "Tutorial" index.
|
||||
*/
|
||||
static Index * currentIndex;
|
||||
static std::string currentGroup;
|
||||
|
||||
static void addIndexToGroup(Index *anIndex, std::vector<Index *> * aGroup);
|
||||
static void removeIndexFromGroup(Index *anIndex, std::string groupName);
|
||||
|
||||
};
|
||||
|
||||
}} // namespace enigma::lev
|
||||
#endif
|
||||
1102
project/jni/application/enigma/src/lev/PersistentIndex.cpp
Normal file
1102
project/jni/application/enigma/src/lev/PersistentIndex.cpp
Normal file
File diff suppressed because it is too large
Load Diff
134
project/jni/application/enigma/src/lev/PersistentIndex.hh
Normal file
134
project/jni/application/enigma/src/lev/PersistentIndex.hh
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef LEV_PERSISTENTINDEX_HH_INCLUDED
|
||||
#define LEV_PERSISTENTINDEX_HH_INCLUDED
|
||||
|
||||
#include "lev/Index.hh"
|
||||
|
||||
#include <string>
|
||||
#include <istream>
|
||||
#include <xercesc/dom/DOMDocument.hpp>
|
||||
|
||||
|
||||
#define INDEX_STD_FILENAME "index.xml"
|
||||
|
||||
namespace enigma { namespace lev {
|
||||
|
||||
struct Variation {
|
||||
// Constructor
|
||||
Variation(controlType ctrlValue = force, scoreUnitType unitValue = duration,
|
||||
std::string targetValue = "time");
|
||||
|
||||
controlType ctrl;
|
||||
scoreUnitType unit;
|
||||
std::string target;
|
||||
std::map<std::string, std::string> extensions;
|
||||
|
||||
bool operator == (const Variation& otherVar);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class PersistentIndex : public Index {
|
||||
public:
|
||||
static void registerPersistentIndices(bool onlySystemIndices);
|
||||
static PersistentIndex * historyIndex;
|
||||
static void addCurrentToHistory();
|
||||
|
||||
/**
|
||||
* Convention: method names *Level() can take int pos or Proxy as arg.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* thePackPath " " for a new not yet defined path
|
||||
*/
|
||||
PersistentIndex(std::string thePackPath, bool systemOnly,
|
||||
double defaultLocation = INDEX_DEFAULT_PACK_LOCATION,
|
||||
std::string anIndexName = "",
|
||||
std::string theIndexFilename = INDEX_STD_FILENAME,
|
||||
std::string aGroupName = INDEX_DEFAULT_GROUP);
|
||||
/**
|
||||
* Legacy 0.92 constructor - called once to convert the index to XML.
|
||||
* When the index has been stored as XML this constructor will not be
|
||||
* called again.
|
||||
*/
|
||||
PersistentIndex(std::istream *legacyIndex, std::string thePackPath, bool isZip = false,
|
||||
std::string anIndexName = "", std::string theIndexFilename = INDEX_STD_FILENAME);
|
||||
~PersistentIndex();
|
||||
void load(bool systemOnly, bool update = false);
|
||||
void loadDoc();
|
||||
std::string getPackPath();
|
||||
bool setName(std::string newName);
|
||||
std::string getOwner();
|
||||
void setOwner(std::string newOwner);
|
||||
int getRelease();
|
||||
void setRelease(int newRelease);
|
||||
int getRevision();
|
||||
void setRevision(int newRevision);
|
||||
double getCompatibility();
|
||||
void setCompatibility(double newCompatibility);
|
||||
bool isUserEditable();
|
||||
bool isUpdatable();
|
||||
bool isCross();
|
||||
void markNewAsCross();
|
||||
virtual void clear();
|
||||
virtual void appendProxy(Proxy * newLevel, controlType varCtrl = force,
|
||||
scoreUnitType varUnit = duration, std::string varTarget = "time",
|
||||
std::map<std::string, std::string> varExtensions = nullExtensions);
|
||||
void insertProxy(int pos, Proxy * newLevel, bool allowDuplicates = true,
|
||||
controlType varCtrl = force, scoreUnitType varUnit = duration,
|
||||
std::string varTarget = "time",
|
||||
std::map<std::string, std::string> varExtensions = nullExtensions);
|
||||
Variation getVariation(int pos);
|
||||
void erase(int pos);
|
||||
void exchange(int pos1, int pos2);
|
||||
virtual bool isSource(Proxy * aProxy);
|
||||
bool save(bool allowOverwrite = true);
|
||||
protected:
|
||||
std::string packPath; // "auto", "",...
|
||||
std::string indexFilename;
|
||||
std::string owner;
|
||||
int release;
|
||||
int revision;
|
||||
double compatibility;
|
||||
std::vector<Variation> variations;
|
||||
bool isModified;
|
||||
bool isUserOwned;
|
||||
bool isEditable;
|
||||
std::string indexUrl;
|
||||
private:
|
||||
static std::vector<PersistentIndex *> indexCandidates;
|
||||
std::string absIndexPath;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *infoElem;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *updateElem;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *levelsElem;
|
||||
|
||||
static void checkCandidate(PersistentIndex * candidate);
|
||||
// legacy 0.92
|
||||
void parsePar(const string& par, int& par_value, std::string& par_text);
|
||||
};
|
||||
|
||||
void AddLevelPack (const char *init_file, const char *name);
|
||||
void AddZippedLevelPack (const char *zipfile);
|
||||
|
||||
}} // namespace enigma::lev
|
||||
#endif
|
||||
1172
project/jni/application/enigma/src/lev/Proxy.cpp
Normal file
1172
project/jni/application/enigma/src/lev/Proxy.cpp
Normal file
File diff suppressed because it is too large
Load Diff
195
project/jni/application/enigma/src/lev/Proxy.hh
Normal file
195
project/jni/application/enigma/src/lev/Proxy.hh
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef LEV_PROXY_HH_INCLUDED
|
||||
#define LEV_PROXY_HH_INCLUDED
|
||||
|
||||
#include "enigma.hh"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <xercesc/dom/DOMDocument.hpp>
|
||||
|
||||
namespace enigma { namespace lev {
|
||||
enum controlType {force, balance, key, other};
|
||||
enum scoreUnitType {duration, number};
|
||||
enum scoreTargetType {time, pushes, moves, callback};
|
||||
enum levelStatusType {
|
||||
STATUS_RELEASED,
|
||||
STATUS_STABLE,
|
||||
STATUS_TEST,
|
||||
STATUS_EXPERIMENTAL,
|
||||
STATUS_UNKNOWN
|
||||
};
|
||||
|
||||
/**
|
||||
* A standin for an addressable level file and its level metadata.
|
||||
* Every level index and the commandline register their levels with the
|
||||
* known level metadata. The unique proxy is henceforth used to access
|
||||
* level data and to load the level. The level metadata are updated on
|
||||
* level load and can be updated without a complete load of the level.
|
||||
*
|
||||
* The supplied level address is analysed and normalized to a unique
|
||||
* schema. Urls, Enigma resource path addresses, absolute paths and
|
||||
* Oxyd level addresses are supported.
|
||||
*
|
||||
* Mismatches of levels to requested levels are detected on level load.
|
||||
* Old level revisions on the users Enigma home directory shadowing new
|
||||
* revisions of a new Enigma installation will be handled, too.
|
||||
*/
|
||||
class Proxy {
|
||||
public:
|
||||
enum pathType { pt_url, pt_resource, pt_absolute, pt_oxyd};
|
||||
static const XMLCh levelNS[]; // the XML namespace
|
||||
static Proxy *loadedLevel(); // tmp ?
|
||||
|
||||
/**
|
||||
* The registration of a level.
|
||||
* @arg levelPath as stored in indices or entered on the commandline.
|
||||
* valid formats are:
|
||||
* welcome, ./firefox, stable/welcome:, ftp://..., #oxyd#17
|
||||
* @arg indexPath a path identifier of the index in strict standard form:
|
||||
* stable, "", #commandline, #history, #oxyd, http://...
|
||||
* resource path level packs use the subdirectory name below
|
||||
* levels or "", zipped packs the filename without suffix
|
||||
* @arg levelId the version independent level id as used for scoring
|
||||
* @arg levelTitle the english title of the level
|
||||
* @arg levelAuthor the name of the author
|
||||
* @arg levelScoreVersion the score version
|
||||
* @arg levelRelease the level compatibility release version
|
||||
* @arg levelHasEasymode support of an easy mode
|
||||
*/
|
||||
static Proxy *registerLevel(std::string levelPath, std::string indexPath,
|
||||
std::string levelId, std::string levelTitle, std::string levelAuthor,
|
||||
int levelScoreVersion, int levelRelease, bool levelHasEasymode,
|
||||
GameType levelCompatibilty, levelStatusType status =STATUS_RELEASED,
|
||||
int levelRevision = 0);
|
||||
|
||||
static Proxy *autoRegisterLevel(std::string indexPath, std::string filename);
|
||||
|
||||
static std::string search(std::string text);
|
||||
static void countLevels();
|
||||
static std::set<std::string> getLevelIds(bool withEasy);
|
||||
static std::set<Proxy *> getProxies();
|
||||
|
||||
void loadLevel();
|
||||
void loadMetadata(bool expectLevel);
|
||||
Proxy * copy(std::string newBasePath, std::string newPackPath, bool backup = true);
|
||||
|
||||
/**
|
||||
* Retrieve and translate a level string. The key may be "title",
|
||||
* "subtitle" or any level specific string key. The priorities for
|
||||
* translation are as follows: protected translation - gettext
|
||||
* translation - public translation - protected english - key
|
||||
* @arg key the key for the search string
|
||||
* @return the translation of the string
|
||||
*/
|
||||
std::string getLocalizedString(const std::string &key);
|
||||
|
||||
std::string getId();
|
||||
int getScoreVersion();
|
||||
int getReleaseVersion();
|
||||
int getRevisionNumber();
|
||||
levelStatusType getLevelStatus();
|
||||
std::string getAuthor();
|
||||
std::string getTitle(); // english title
|
||||
bool hasEasymode();
|
||||
std::string getContact();
|
||||
std::string getHomepage();
|
||||
controlType getControl();
|
||||
scoreUnitType getScoreUnit();
|
||||
std::string getScoreTarget();
|
||||
std::string getCredits(bool infoUsage);
|
||||
std::string getDedication(bool infoUsage);
|
||||
int getEasyScore();
|
||||
int getDifficultScore();
|
||||
GameType getEngineCompatibility();
|
||||
double getEnigmaCompatibility();
|
||||
|
||||
/**
|
||||
* the level address that can be used independent of a level pack
|
||||
* as a crossreference. (stable/welcome, #oxyd#17, http://..., ~/test)
|
||||
*/
|
||||
std::string getNormLevelPath();
|
||||
|
||||
/**
|
||||
* The normalized level path with all critical characters substituted
|
||||
* by '~' to allow url's to be used and to make generated paths portable.
|
||||
* Url protocols like "http://" are substituted by "http/". The returned
|
||||
* path can be used as a local path element.
|
||||
*/
|
||||
std::string getLocalSubstitutionLevelPath();
|
||||
|
||||
/**
|
||||
* the type of the level address
|
||||
*/
|
||||
Proxy::pathType getNormPathType();
|
||||
std::string getAbsLevelPath();
|
||||
void loadDependency(std::string depId);
|
||||
void release();
|
||||
private:
|
||||
static Proxy *currentLevel;
|
||||
static std::map<std::string, Proxy *> cache;
|
||||
static std::vector<Proxy *> loadedLibs;
|
||||
static std::vector<Proxy *> registeredLibs;
|
||||
static void releaseLibs();
|
||||
|
||||
bool isLibraryFlag;
|
||||
pathType normPathType;
|
||||
std::string normLevelPath; // stable/welcome, #oxyd#17, http://..., ~/test
|
||||
std::string absLevelPath;
|
||||
std::string id; // level id - old filename or indexname
|
||||
std::string title; // old name
|
||||
std::string author;
|
||||
int scoreVersion;
|
||||
int releaseVersion;
|
||||
int revisionNumber;
|
||||
levelStatusType levelStatus;
|
||||
bool hasEasymodeFlag;
|
||||
scoreUnitType scoreUnit;
|
||||
/**
|
||||
* The compatibility that needs to be preset on level load.
|
||||
* Usually level set the compatibility themselves on load. But heritage
|
||||
* levels loaded from DAT-files do not. Thus we need to keep the type
|
||||
* info in the Proxy as an exception.
|
||||
*/
|
||||
GameType engineCompatibility;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *infoElem;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMNodeList *stringList;
|
||||
|
||||
Proxy(bool proxyIsLibrary, pathType thePathType, std::string theNormLevelPath,
|
||||
std::string levelId, std::string levelTitle, std::string levelAuthor,
|
||||
int levelScoreVersion, int levelRelease, bool levelHasEasymode,
|
||||
GameType levelCompatibilty, levelStatusType status, int levelRevision = 0);
|
||||
~Proxy();
|
||||
void load(bool onlyMetadata, bool expectLevel);
|
||||
void loadDoc();
|
||||
void loadLuaCode();
|
||||
void processDependencies();
|
||||
void registerPreloadDependency(std::string depPath, std::string depId,
|
||||
int depRelease, bool depPreload, std::string depUrl);
|
||||
std::string getType();
|
||||
bool updateId();
|
||||
bool updateReleaseVersion();
|
||||
int scoreText2Int(std::string text);
|
||||
};
|
||||
}} // namespace enigma::lev
|
||||
#endif
|
||||
|
||||
698
project/jni/application/enigma/src/lev/RatingManager.cpp
Normal file
698
project/jni/application/enigma/src/lev/RatingManager.cpp
Normal file
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
* Copyright (C) 2006, 2007 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lev/RatingManager.hh"
|
||||
|
||||
#include "main.hh"
|
||||
#include "ecl_util.hh"
|
||||
#include "errors.hh"
|
||||
#include "LocalToXML.hh"
|
||||
#include "Utf8ToXML.hh"
|
||||
#include "XMLtoUtf8.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/util/XercesVersion.hpp>
|
||||
#if _XERCES_VERSION < 30000
|
||||
#include <xercesc/framework/LocalFileFormatTarget.hpp>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace enigma;
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
|
||||
namespace enigma { namespace lev {
|
||||
std::time_t timeValue(const std::string &timeString) {
|
||||
std::tm time;
|
||||
time.tm_year = atoi(timeString.substr(0,4).c_str()) - 1900;
|
||||
time.tm_mon = atoi(timeString.substr(5,2).c_str()) - 1;
|
||||
time.tm_mday = atoi(timeString.substr(8,2).c_str());
|
||||
time.tm_hour = atoi(timeString.substr(11,2).c_str());
|
||||
time.tm_min = atoi(timeString.substr(14,2).c_str());
|
||||
time.tm_sec = atoi(timeString.substr(17,2).c_str());
|
||||
time.tm_isdst = false;
|
||||
return std::mktime(&time);
|
||||
}
|
||||
|
||||
std::time_t timeValue(const XMLCh * const string) {
|
||||
std::string timeString = XMLtoUtf8(string).c_str();
|
||||
return timeValue(timeString);
|
||||
}
|
||||
|
||||
Rating::Rating()
|
||||
{
|
||||
intelligence = 0;
|
||||
dexterity = 0;
|
||||
patience = 0;
|
||||
knowledge = 0;
|
||||
speed = 0;
|
||||
bestScoreEasy = -1; //DEFAULT_TIME;
|
||||
bestScoreDifficult = -1; //DEFAULT_TIME;
|
||||
parScoreEasy = -1;
|
||||
parScoreDifficult = -1;
|
||||
numSolvedEasy = 0;
|
||||
numSolvedDifficult = 0;
|
||||
pdmSolvedEasy = 0;
|
||||
pdmSolvedDifficult = 0;
|
||||
averageRating = -1;
|
||||
}
|
||||
|
||||
|
||||
RatingManager *RatingManager::theSingleton = 0;
|
||||
|
||||
RatingManager* RatingManager::instance() {
|
||||
if (theSingleton == 0) {
|
||||
theSingleton = new RatingManager();
|
||||
}
|
||||
return theSingleton;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RatingManager::RatingManager() : didAddRatings (false), didEditRatings (false) {
|
||||
std::tm time;
|
||||
time.tm_year = 2006 - 1900; // the past - all ratings are newer as this
|
||||
time.tm_mon = 02; // is the date it was coded
|
||||
time.tm_mday = 30;
|
||||
time.tm_hour = 20;
|
||||
time.tm_min = 10;
|
||||
time.tm_sec = 00;
|
||||
time.tm_isdst = false;
|
||||
ratingVersion = std::mktime(&time);
|
||||
if(app.state->getString("RatingsUpdateTime").empty()) {
|
||||
// guarantee usable "RatingsUpdateTime"
|
||||
char str[22];
|
||||
std::strftime(str, 22, "%Y-%m-%dT%H:%M:%SZ", std::gmtime(&ratingVersion));
|
||||
std::string currentTimeString = str;
|
||||
app.state->setProperty("RatingsUpdateTime", currentTimeString);
|
||||
}
|
||||
std::string sysRatingPath;
|
||||
std::string userRatingPath;
|
||||
if (app.systemFS->findFile(RATINGSFILENAME, sysRatingPath)) {
|
||||
// preload cache with application distributed ratings
|
||||
loadURI(sysRatingPath);
|
||||
}
|
||||
if (app.resourceFS->findFile(RATINGSFILENAME, userRatingPath) &&
|
||||
userRatingPath != sysRatingPath) {
|
||||
// update with user saved ratings - ignore cache changes as there
|
||||
// is no reason to store the cache.
|
||||
loadURI(userRatingPath);
|
||||
}
|
||||
if (app.prefs->getBool("RatingsAutoUpdate") == true)
|
||||
update();
|
||||
}
|
||||
|
||||
RatingManager::~RatingManager() {
|
||||
}
|
||||
|
||||
RatingManager::loadResult RatingManager::loadURI(std::string path) {
|
||||
RatingManager::loadResult status = checked;
|
||||
try {
|
||||
app.domParserErrorHandler->resetErrors();
|
||||
app.domParserErrorHandler->reportToErr();
|
||||
app.domParserSchemaResolver->resetResolver();
|
||||
app.domParserSchemaResolver->addSchemaId("ratings.xsd","ratings.xsd");
|
||||
DOMDocument *doc = app.domParser->parseURI(path.c_str());
|
||||
if (doc != NULL && !app.domParserErrorHandler->getSawErrors()) {
|
||||
DOMElement *updateElem =
|
||||
dynamic_cast<DOMElement *>(doc->getElementsByTagName(
|
||||
Utf8ToXML("update").x_str())->item(0));
|
||||
std::time_t newVersion = timeValue(updateElem->getAttribute(Utf8ToXML("date").x_str()));
|
||||
bool isUpdate = (std::difftime(newVersion, ratingVersion) > 0) ? true : false;
|
||||
if (isUpdate) {
|
||||
ratingVersion = newVersion;
|
||||
ratingVersionString = XMLtoUtf8(updateElem->getAttribute(Utf8ToXML("date").x_str())).c_str();
|
||||
urlFullUpdate = XMLtoUtf8(updateElem->getAttribute(Utf8ToXML("urlFull").x_str())).c_str();
|
||||
urlIncrementalUpdate = XMLtoUtf8(updateElem->getAttribute(Utf8ToXML("urlIncremental").x_str())).c_str();
|
||||
updateMinDelay = XMLString::parseInt(updateElem->getAttribute(Utf8ToXML("delay").x_str()));
|
||||
}
|
||||
DOMNodeList *levelList = doc->getElementsByTagName(
|
||||
Utf8ToXML("level").x_str());
|
||||
for (int i = 0, l = levelList-> getLength(); i < l; i++) {
|
||||
DOMElement *levelElem = dynamic_cast<DOMElement *>(levelList->item(i));
|
||||
const XMLCh * attr = levelElem->getAttribute(Utf8ToXML("id").x_str());
|
||||
std::string id = XMLtoUtf8(attr).c_str();
|
||||
attr = levelElem->getAttribute(Utf8ToXML("sv").x_str());
|
||||
short sv = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : 0;
|
||||
std::string cacheKey = id + "#" + ecl::strf("%d", sv);
|
||||
std::map<std::string, Rating *>::iterator it = cache.find(cacheKey);
|
||||
Rating * theRating;
|
||||
bool isNewRating = false;
|
||||
if (it != cache.end()) {
|
||||
if (isUpdate)
|
||||
// update the outdated entry
|
||||
theRating = it->second;
|
||||
else
|
||||
// keep the newer entry
|
||||
continue;
|
||||
} else {
|
||||
// add not existing entries in all cases
|
||||
theRating = new Rating();
|
||||
isNewRating = true;
|
||||
}
|
||||
status = updated;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("int").x_str());
|
||||
theRating->intelligence = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : 0;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("dex").x_str());
|
||||
theRating->dexterity = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : 0;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("pat").x_str());
|
||||
theRating->patience = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : 0;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("kno").x_str());
|
||||
theRating->knowledge = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : 0;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("spe").x_str());
|
||||
theRating->speed = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : 0;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("bse").x_str());
|
||||
theRating->bestScoreEasy = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : -1;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("bseh").x_str());
|
||||
theRating->bestScoreEasyHolder = XMLtoUtf8(attr).c_str();
|
||||
attr = levelElem->getAttribute(Utf8ToXML("bsd").x_str());
|
||||
theRating->bestScoreDifficult = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : -1;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("bsdh").x_str());
|
||||
theRating->bestScoreDifficultHolder = XMLtoUtf8(attr).c_str();
|
||||
attr = levelElem->getAttribute(Utf8ToXML("pare").x_str());
|
||||
theRating->parScoreEasy = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : -1;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("pard").x_str());
|
||||
theRating->parScoreDifficult = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : -1;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("solvne").x_str());
|
||||
theRating->numSolvedEasy = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : 0;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("solvpe").x_str());
|
||||
theRating->pdmSolvedEasy = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : 0;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("solvnd").x_str());
|
||||
theRating->numSolvedDifficult = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : 0;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("solvpd").x_str());
|
||||
theRating->pdmSolvedDifficult = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : 0;
|
||||
attr = levelElem->getAttribute(Utf8ToXML("avgur").x_str());
|
||||
theRating->averageRating = XMLString::stringLen(attr) > 0 ? XMLString::parseInt(attr) : -1;
|
||||
if (isNewRating)
|
||||
cache.insert(std::make_pair(cacheKey, theRating));
|
||||
}
|
||||
doc->release();
|
||||
} else {
|
||||
status = error;
|
||||
}
|
||||
|
||||
}
|
||||
catch (const XMLException& toCatch) {
|
||||
char* message = XMLString::transcode(toCatch.getMessage());
|
||||
cerr << "Exception on load of preferences: "
|
||||
<< message << "\n";
|
||||
XMLString::release(&message);
|
||||
return error;
|
||||
}
|
||||
catch (const DOMException& toCatch) {
|
||||
char* message = XMLString::transcode(toCatch.msg);
|
||||
cerr << "Exception on load of preferences: "
|
||||
<< message << "\n";
|
||||
XMLString::release(&message);
|
||||
return error;
|
||||
}
|
||||
catch (...) {
|
||||
cerr << "Unexpected Exception on load of preferences\n" ;
|
||||
return error;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void RatingManager::update() {
|
||||
std::time_t currentTime = std::time(NULL);
|
||||
|
||||
// check if an update is allowed
|
||||
std::time_t currentWeirdTime = std::mktime(gmtime(¤tTime));
|
||||
double updateDelay = std::difftime(currentWeirdTime,
|
||||
timeValue(app.state->getString("RatingsUpdateTime")));
|
||||
if (updateDelay/86400 < updateMinDelay) {
|
||||
Log << "Rating update not yet allowed: " <<updateDelay<< " s\n";
|
||||
return;
|
||||
}
|
||||
Log << "Rating update allowed\n";
|
||||
|
||||
// do update
|
||||
bool didUpdate = false;
|
||||
loadResult result;
|
||||
std::string oldUrlIncrementalUpdate;
|
||||
std::string oldUrlFullUpdate;
|
||||
do {
|
||||
Log << "Ratings update from '" << urlIncrementalUpdate << "'\n";
|
||||
oldUrlIncrementalUpdate = urlIncrementalUpdate;
|
||||
oldUrlFullUpdate = urlFullUpdate;
|
||||
result = loadURI(urlIncrementalUpdate);
|
||||
if (result == updated)
|
||||
didUpdate = true;
|
||||
} while (result != error &&
|
||||
oldUrlIncrementalUpdate != urlIncrementalUpdate &&
|
||||
oldUrlIncrementalUpdate != oldUrlFullUpdate);
|
||||
|
||||
|
||||
if (result == error) {
|
||||
// check if we are allowed for an full update
|
||||
if (updateDelay/86400 > 3 * updateMinDelay) {
|
||||
result = loadURI(urlFullUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
if (result != error) {
|
||||
// save current time as rating update time
|
||||
char str[22];
|
||||
std::strftime(str, 22, "%Y-%m-%dT%H:%M:%SZ", std::gmtime(¤tTime));
|
||||
std::string currentTimeString = str;
|
||||
app.state->setProperty("RatingsUpdateTime", currentTimeString);
|
||||
}
|
||||
|
||||
if (didUpdate)
|
||||
didAddRatings = true; // we need to save the cache
|
||||
else if (result == checked)
|
||||
; // the update had no new ratings
|
||||
|
||||
}
|
||||
|
||||
// the following local vars should be ivars or arguments to doit - but
|
||||
// as <algorithm> is anti OO it does not allow to transfer a context.
|
||||
DOMDocument *saveDoc;
|
||||
DOMElement *levelsElem;
|
||||
void saveLevelRating(const std::map<std::string, Rating *>::value_type info) {
|
||||
DOMElement *level = saveDoc->createElement(Utf8ToXML("level").x_str());
|
||||
std::string id = info.first.substr(0, info.first.rfind('#'));
|
||||
std::string sv = info.first.substr(info.first.rfind('#')+1);
|
||||
level->setAttribute(Utf8ToXML("id").x_str(), Utf8ToXML(id.c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("sv").x_str(), Utf8ToXML(sv.c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("int").x_str(), Utf8ToXML(ecl::strf("%d",info.second->intelligence).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("dex").x_str(), Utf8ToXML(ecl::strf("%d",info.second->dexterity).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("pat").x_str(), Utf8ToXML(ecl::strf("%d",info.second->patience).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("kno").x_str(), Utf8ToXML(ecl::strf("%d",info.second->knowledge).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("spe").x_str(), Utf8ToXML(ecl::strf("%d",info.second->speed).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("bse").x_str(), Utf8ToXML(ecl::strf("%d",info.second->bestScoreEasy).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("bsd").x_str(), Utf8ToXML(ecl::strf("%d",info.second->bestScoreDifficult).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("bseh").x_str(), Utf8ToXML(info.second->bestScoreEasyHolder.c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("bsdh").x_str(), Utf8ToXML(info.second->bestScoreDifficultHolder.c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("pare").x_str(), Utf8ToXML(ecl::strf("%d",info.second->parScoreEasy).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("pard").x_str(), Utf8ToXML(ecl::strf("%d",info.second->parScoreDifficult).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("solvne").x_str(), Utf8ToXML(ecl::strf("%d",info.second->numSolvedEasy).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("solvpe").x_str(), Utf8ToXML(ecl::strf("%d",info.second->pdmSolvedEasy).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("solvnd").x_str(), Utf8ToXML(ecl::strf("%d",info.second->numSolvedDifficult).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("solvpd").x_str(), Utf8ToXML(ecl::strf("%d",info.second->pdmSolvedDifficult).c_str()).x_str());
|
||||
level->setAttribute(Utf8ToXML("avgur").x_str(), Utf8ToXML(ecl::strf("%d",info.second->averageRating).c_str()).x_str());
|
||||
levelsElem->appendChild(level);
|
||||
}
|
||||
|
||||
void RatingManager::save() {
|
||||
if (!(didAddRatings || didEditRatings))
|
||||
return;
|
||||
if (didEditRatings) {
|
||||
// set the rating version to the current time
|
||||
char date[25];
|
||||
std::time_t current = std::time(NULL);
|
||||
strftime(date, 25, "%Y-%m-%dT%H:%M:%SZ",gmtime(¤t));
|
||||
ratingVersionString = date;
|
||||
}
|
||||
std::string ratTemplatePath;
|
||||
if (!app.systemFS->findFile("schemas/ratings.xml" , ratTemplatePath)) {
|
||||
cerr << "Ratings: no template found\n";
|
||||
return;
|
||||
}
|
||||
try {
|
||||
app.domParserErrorHandler->resetErrors();
|
||||
app.domParserErrorHandler->reportToErr();
|
||||
app.domParserSchemaResolver->resetResolver();
|
||||
app.domParserSchemaResolver->addSchemaId("ratings.xsd","ratings.xsd");
|
||||
saveDoc = app.domParser->parseURI(ratTemplatePath.c_str());
|
||||
if (saveDoc != NULL && !app.domParserErrorHandler->getSawErrors()) {
|
||||
DOMElement * updateElem = dynamic_cast<DOMElement *>(saveDoc->getElementsByTagName(
|
||||
Utf8ToXML("update").x_str())->item(0));
|
||||
updateElem->setAttribute(Utf8ToXML("date").x_str(), Utf8ToXML(ratingVersionString.c_str()).x_str());
|
||||
updateElem->setAttribute(Utf8ToXML("urlFull").x_str(), Utf8ToXML(urlFullUpdate.c_str()).x_str());
|
||||
updateElem->setAttribute(Utf8ToXML("urlIncremental").x_str(), Utf8ToXML(urlIncrementalUpdate.c_str()).x_str());
|
||||
updateElem->setAttribute(Utf8ToXML("delay").x_str(), Utf8ToXML(ecl::strf("%d",updateMinDelay).c_str()).x_str());
|
||||
levelsElem = dynamic_cast<DOMElement *>(saveDoc->getElementsByTagName(
|
||||
Utf8ToXML("levels").x_str())->item(0));
|
||||
std::for_each(cache.begin(), cache.end(), saveLevelRating);
|
||||
std::string writePath = app.userPath + "/" + RATINGSFILENAME;
|
||||
#if _XERCES_VERSION >= 30000
|
||||
app.domSer->writeToURI(saveDoc, LocalToXML(writePath.c_str()).x_str());
|
||||
#else
|
||||
XMLFormatTarget *myFormTarget = new LocalFileFormatTarget(writePath.c_str());
|
||||
app.domSer->writeNode(myFormTarget, *saveDoc);
|
||||
#endif
|
||||
saveDoc->release();
|
||||
}
|
||||
}
|
||||
catch (const XMLException& toCatch) {
|
||||
char* message = XMLString::transcode(toCatch.getMessage());
|
||||
cerr << "Exception on load of preferences: "
|
||||
<< message << "\n";
|
||||
XMLString::release(&message);
|
||||
return;
|
||||
}
|
||||
catch (const DOMException& toCatch) {
|
||||
char* message = XMLString::transcode(toCatch.msg);
|
||||
cerr << "Exception on load of preferences: "
|
||||
<< message << "\n";
|
||||
XMLString::release(&message);
|
||||
return;
|
||||
}
|
||||
catch (...) {
|
||||
cerr << "Unexpected Exception on load of preferences\n" ;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RatingManager::registerRating(std::string levelId, short levelScoreVersion,
|
||||
short intelligence, short dexterity, short patience,
|
||||
short knowledge, short speed, short bestScoreEasy,
|
||||
std::string bestScoreEasyHolder, short bestScoreDifficult,
|
||||
std::string bestScoreDifficultHolder) {
|
||||
std::string cacheKey = levelId + "#" + ecl::strf("%d", levelScoreVersion);
|
||||
std::map<std::string, Rating *>::iterator i = cache.find(cacheKey);
|
||||
if (i != cache.end()) {
|
||||
// Log << "Rating cache hit for " << levelId <<"\n";
|
||||
return;
|
||||
}
|
||||
Rating *theRating = new Rating();
|
||||
theRating->intelligence = intelligence;
|
||||
theRating->dexterity = dexterity;
|
||||
theRating->patience = patience;
|
||||
theRating->knowledge = knowledge;
|
||||
theRating->speed = speed;
|
||||
theRating->bestScoreEasy = bestScoreEasy;
|
||||
theRating->bestScoreEasyHolder = bestScoreEasyHolder;
|
||||
theRating->bestScoreDifficult = bestScoreDifficult;
|
||||
theRating->bestScoreDifficultHolder = bestScoreDifficultHolder;
|
||||
cache.insert(std::make_pair(cacheKey, theRating));
|
||||
didAddRatings = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Rating * RatingManager::registerNewRating(Proxy * levelProxy) {
|
||||
std::string cacheKey = levelProxy->getId() + "#" +
|
||||
ecl::strf("%d", levelProxy->getScoreVersion());
|
||||
std::map<std::string, Rating *>::iterator it = cache.find(cacheKey);
|
||||
if (it != cache.end()) {
|
||||
return it->second;
|
||||
}
|
||||
Rating *theRating = new Rating();
|
||||
cache.insert(std::make_pair(cacheKey, theRating));
|
||||
didAddRatings = true;
|
||||
return theRating;
|
||||
}
|
||||
|
||||
Rating * RatingManager::findRating(Proxy * levelProxy) {
|
||||
std::string cacheKey = levelProxy->getId() + "#" +
|
||||
ecl::strf("%d", levelProxy->getScoreVersion());
|
||||
std::map<std::string, Rating *>::iterator it = cache.find(cacheKey);
|
||||
if (it != cache.end()) {
|
||||
Rating * theRating = it->second;
|
||||
return theRating;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
short RatingManager::getIntelligence(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->intelligence;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RatingManager::setIntelligence(Proxy *levelProxy, short intelligence) {
|
||||
Rating * theRating = registerNewRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
theRating->intelligence = intelligence;
|
||||
didEditRatings = true;
|
||||
}
|
||||
}
|
||||
|
||||
short RatingManager::getDexterity(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->dexterity;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RatingManager::setDexterity(Proxy *levelProxy, short dexterity) {
|
||||
Rating * theRating = registerNewRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
theRating->dexterity = dexterity;
|
||||
didEditRatings = true;
|
||||
}
|
||||
}
|
||||
|
||||
short RatingManager::getPatience(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->patience;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RatingManager::setPatience(Proxy *levelProxy, short patience) {
|
||||
Rating * theRating = registerNewRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
theRating->patience = patience;
|
||||
didEditRatings = true;
|
||||
}
|
||||
}
|
||||
|
||||
short RatingManager::getKnowledge(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->knowledge;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RatingManager::setKnowledge(Proxy *levelProxy, short knowledge) {
|
||||
Rating * theRating = registerNewRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
theRating->knowledge = knowledge;
|
||||
didEditRatings = true;
|
||||
}
|
||||
}
|
||||
|
||||
short RatingManager::getSpeed(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->speed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RatingManager::setSpeed(Proxy *levelProxy, short speed) {
|
||||
Rating * theRating = registerNewRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
theRating->speed = speed;
|
||||
didEditRatings = true;
|
||||
}
|
||||
}
|
||||
|
||||
short RatingManager::getDifficulty(Proxy *levelProxy) {
|
||||
int difficulty = 7*getIntelligence(levelProxy) +
|
||||
6*getDexterity(levelProxy) +
|
||||
4*getPatience(levelProxy) +
|
||||
3*getKnowledge(levelProxy) +
|
||||
4*getSpeed(levelProxy) - 23;
|
||||
return difficulty > 0 ? difficulty : 0;
|
||||
}
|
||||
|
||||
short RatingManager::getBestScore(Proxy *levelProxy, int difficulty) {
|
||||
if (difficulty == DIFFICULTY_EASY && !levelProxy->hasEasymode())
|
||||
difficulty = DIFFICULTY_HARD;
|
||||
switch (difficulty) {
|
||||
case DIFFICULTY_EASY:
|
||||
return getBestScoreEasy(levelProxy);
|
||||
case DIFFICULTY_HARD:
|
||||
return getBestScoreDifficult(levelProxy);
|
||||
default:
|
||||
ecl::Assert <XFrontend> (false, "RatingManager::getBestScore illegal difficulty");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string RatingManager::cutHolders(std::string org, int factor) {
|
||||
if (factor <= 0)
|
||||
return org;
|
||||
|
||||
int others = 0;
|
||||
if (org.rfind(" others") == org.length() - 7) {
|
||||
// ratings string is already cut
|
||||
std::string::size_type lastPlus = org.rfind('+');
|
||||
std::istringstream othersString(org.substr(lastPlus + 1));
|
||||
othersString >> std::dec >> others;
|
||||
org = org.substr(0, lastPlus);
|
||||
}
|
||||
std::string::size_type cutPlus;
|
||||
for (int i=0; i< factor; i++) {
|
||||
cutPlus = org.rfind('+');
|
||||
if (cutPlus == std::string::npos)
|
||||
return "";
|
||||
org = org.substr(0, cutPlus);
|
||||
others++;
|
||||
}
|
||||
return ecl::strf("%s+%d others", org.c_str(), others);
|
||||
}
|
||||
|
||||
std::string RatingManager::getBestScoreHolder(Proxy *levelProxy, int difficulty, int cut) {
|
||||
if (difficulty == DIFFICULTY_EASY && !levelProxy->hasEasymode())
|
||||
difficulty = DIFFICULTY_HARD;
|
||||
switch (difficulty) {
|
||||
case DIFFICULTY_EASY:
|
||||
return getBestScoreEasyHolder(levelProxy, cut);
|
||||
case DIFFICULTY_HARD:
|
||||
return getBestScoreDifficultHolder(levelProxy, cut);
|
||||
default:
|
||||
ecl::Assert <XFrontend> (false, "RatingManager::getBestScoreHolder illegal difficulty");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
short RatingManager::getBestScoreEasy(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->bestScoreEasy;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string RatingManager::getBestScoreEasyHolder(Proxy *levelProxy, int cut) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return cutHolders(theRating->bestScoreEasyHolder, cut);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
short RatingManager::getBestScoreDifficult(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->bestScoreDifficult;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string RatingManager::getBestScoreDifficultHolder(Proxy *levelProxy, int cut) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return cutHolders(theRating->bestScoreDifficultHolder, cut);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
short RatingManager::getParScore(Proxy *levelProxy, int difficulty) {
|
||||
if (difficulty == DIFFICULTY_EASY && !levelProxy->hasEasymode())
|
||||
difficulty = DIFFICULTY_HARD;
|
||||
switch (difficulty) {
|
||||
case DIFFICULTY_EASY:
|
||||
return getParScoreEasy(levelProxy);
|
||||
case DIFFICULTY_HARD:
|
||||
return getParScoreDifficult(levelProxy);
|
||||
default:
|
||||
ecl::Assert <XFrontend> (false, "RatingManager::getParScore illegal difficulty");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
short RatingManager::getParScoreEasy(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->parScoreEasy;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
short RatingManager::getParScoreDifficult(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->parScoreDifficult;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
short RatingManager::getNumSolvedEasy(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->numSolvedEasy;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
short RatingManager::getNumSolvedDifficult(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->numSolvedDifficult;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
short RatingManager::getPdmSolvedEasy(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->pdmSolvedEasy;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string RatingManager::getPcSolvedEasy(Proxy *levelProxy) {
|
||||
std::string s = ecl::strf("%5.3d", getPdmSolvedEasy(levelProxy));
|
||||
s.insert(3,1,'.');
|
||||
return s;
|
||||
}
|
||||
|
||||
short RatingManager::getPdmSolvedDifficult(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->pdmSolvedDifficult;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string RatingManager::getPcSolvedDifficult(Proxy *levelProxy) {
|
||||
std::string s = ecl::strf("%5.3d", getPdmSolvedDifficult(levelProxy));
|
||||
s.insert(3,1,'.');
|
||||
return s;
|
||||
}
|
||||
|
||||
short RatingManager::getDAverageRating(Proxy *levelProxy) {
|
||||
Rating * theRating = findRating(levelProxy);
|
||||
if (theRating != NULL) {
|
||||
return theRating->averageRating;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string RatingManager::getAverageRating(Proxy *levelProxy) {
|
||||
short rat = getDAverageRating(levelProxy);
|
||||
std::string s;
|
||||
if ( rat >= 0 ) {
|
||||
s = ecl::strf("%3.2d", rat);
|
||||
s.insert(2,1,'.');
|
||||
} else {
|
||||
s = "-";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}} // namespace enigma::lev
|
||||
175
project/jni/application/enigma/src/lev/RatingManager.hh
Normal file
175
project/jni/application/enigma/src/lev/RatingManager.hh
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2006, 2007 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef RATINGMGR_HH_INCLUDED
|
||||
#define RATINGMGR_HH_INCLUDED
|
||||
|
||||
#include "lev/Proxy.hh"
|
||||
#include "enigma.hh"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
|
||||
namespace enigma { namespace lev {
|
||||
/**
|
||||
* The public rating info is currently just a data structure as the data
|
||||
* have no behaviour. No public direct access to the data should occur.
|
||||
*/
|
||||
struct Rating
|
||||
{
|
||||
// Constructor
|
||||
Rating();
|
||||
|
||||
// Constants
|
||||
enum { DEFAULT_TIME = 99*60+59 };
|
||||
|
||||
// Variables.
|
||||
short intelligence;
|
||||
short dexterity;
|
||||
short patience;
|
||||
short knowledge;
|
||||
short speed;
|
||||
short bestScoreEasy; // Best time in seconds or Minimum moves to solve level(for easy mode)
|
||||
short bestScoreDifficult; // Best time in seconds or Minimum moves to solve level(for normal mode)
|
||||
std::string bestScoreEasyHolder; // player name(s) for 'best_time_easy'
|
||||
std::string bestScoreDifficultHolder; // same for 'best_time_normal'
|
||||
short parScoreEasy;
|
||||
short parScoreDifficult;
|
||||
int numSolvedEasy;
|
||||
int numSolvedDifficult;
|
||||
short pdmSolvedEasy; // per deca mille - 1/10000
|
||||
short pdmSolvedDifficult;
|
||||
short averageRating; // rating * 10
|
||||
};
|
||||
|
||||
/**
|
||||
* A singelton manager for public ratings and score statistics
|
||||
* The singelton loads the ratings on initialization and caches them. An
|
||||
* update methods allows to online update the ratings and a save method that
|
||||
* should be called on game exit saves the cached ratings if they have been
|
||||
* modified.
|
||||
*
|
||||
* The key to rating access is the Proxy. A rating is bound to a level id
|
||||
* together with its scoring version.
|
||||
* An up to date rating file is distributed with the application. These
|
||||
* ratings are filled up by existing ratings and stored on the users enigma
|
||||
* path. On an update which can be incremental or full the downloaded ratings
|
||||
* replace their predecessors. All other ratings are kept.
|
||||
*
|
||||
* Only the rating administrator can and should edit ratings by copying
|
||||
* the current offical rating file to his user enigma path, editing
|
||||
* the ratings and leaving Enigma what saves the ratings with the current
|
||||
* time stamp. The rating administrator has to ensure that he plays
|
||||
* a clean Enigma version without any additional level packs on his
|
||||
* resource path!
|
||||
*
|
||||
* Note: the time handling is a little bit weird due to limitations in the
|
||||
* C++ standard libs. As no convertion for GMT to time_t exists and we
|
||||
* would have to know the daylight saving offsets for a correct localtime
|
||||
* handling we cheat with our time handling: We save correct GMT time values.
|
||||
* But we read these values and convert them to local times without daylight
|
||||
* saving correctures. This does not harm as we use these values only for
|
||||
* comparisons and nothing more!
|
||||
*/
|
||||
class RatingManager {
|
||||
public:
|
||||
static RatingManager *instance();
|
||||
~RatingManager();
|
||||
|
||||
/**
|
||||
* Online updates the ratings from the update URLs. Online updates
|
||||
* are only processed if the delay period after the last successful
|
||||
* update is over. This feature reduced network access and server
|
||||
* load.
|
||||
* Unsuccessful online updates do not harm.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Save the ratings if changes are pending.
|
||||
*/
|
||||
void save();
|
||||
|
||||
/**
|
||||
* Registers an 0.92 index.txt rating in the cache. This rating will be
|
||||
* used and stored in the new users ratings.xml only if no newer rating
|
||||
* exists.
|
||||
*/
|
||||
void registerRating(std::string levelId, short levelScoreVersion,
|
||||
short intelligence, short dexterity, short patience,
|
||||
short knowledge, short speed, short bestScoreEasy,
|
||||
std::string bestScoreEasyHolder, short bestScoreDifficult,
|
||||
std::string bestScoreDifficultHolder);
|
||||
short getIntelligence(Proxy *levelProxy);
|
||||
void setIntelligence(Proxy *levelProxy, short intelligence);
|
||||
short getDexterity(Proxy *levelProxy);
|
||||
void setDexterity(Proxy *levelProxy, short dexterity);
|
||||
short getPatience(Proxy *levelProxy);
|
||||
void setPatience(Proxy *levelProxy, short patience);
|
||||
short getKnowledge(Proxy *levelProxy);
|
||||
void setKnowledge(Proxy *levelProxy, short knowledge);
|
||||
short getSpeed(Proxy *levelProxy);
|
||||
void setSpeed(Proxy *levelProxy, short speed);
|
||||
short getDifficulty(Proxy *levelProxy);
|
||||
short getBestScore(Proxy *levelProxy, int difficulty);
|
||||
std::string getBestScoreHolder(Proxy *levelProxy, int difficulty, int cut = 0);
|
||||
short getBestScoreEasy(Proxy *levelProxy);
|
||||
std::string getBestScoreEasyHolder(Proxy *levelProxy, int cut = 0);
|
||||
short getBestScoreDifficult(Proxy *levelProxy);
|
||||
std::string getBestScoreDifficultHolder(Proxy *levelProxy, int cut = 0);
|
||||
short getParScore(Proxy *levelProxy, int difficulty);
|
||||
short getParScoreEasy(Proxy *levelProxy);
|
||||
short getParScoreDifficult(Proxy *levelProxy);
|
||||
short getNumSolvedEasy(Proxy *levelProxy);
|
||||
short getNumSolvedDifficult(Proxy *levelProxy);
|
||||
short getPdmSolvedEasy(Proxy *levelProxy);
|
||||
std::string getPcSolvedEasy(Proxy *levelProxy);
|
||||
short getPdmSolvedDifficult(Proxy *levelProxy);
|
||||
std::string getPcSolvedDifficult(Proxy *levelProxy);
|
||||
short getDAverageRating(Proxy *levelProxy);
|
||||
std::string getAverageRating(Proxy *levelProxy);
|
||||
protected:
|
||||
RatingManager();
|
||||
private:
|
||||
enum loadResult { updated, checked, error};
|
||||
static RatingManager *theSingleton;
|
||||
std::map<std::string, Rating *> cache;
|
||||
std::time_t ratingVersion;
|
||||
std::string ratingVersionString;
|
||||
std::string urlFullUpdate;
|
||||
std::string urlIncrementalUpdate;
|
||||
short updateMinDelay;
|
||||
Rating * findRating(Proxy * levelProxy);
|
||||
Rating * registerNewRating(Proxy * levelProxy);
|
||||
std::string cutHolders(std::string org, int factor);
|
||||
|
||||
/**
|
||||
* Loads the ratings from a given URI and updates the cached ratings.
|
||||
* Not existing ratings are always added, existing ratings are updated
|
||||
* only if the rating version is newer than the cached version.
|
||||
* @arg path a local filepath or a URL
|
||||
* @return ratings cache updated, no updates but file checked, or error
|
||||
*/
|
||||
loadResult loadURI(std::string path);
|
||||
bool didAddRatings;
|
||||
bool didEditRatings;
|
||||
};
|
||||
}} // namespace enigma::lev
|
||||
|
||||
#endif
|
||||
1152
project/jni/application/enigma/src/lev/ScoreManager.cpp
Normal file
1152
project/jni/application/enigma/src/lev/ScoreManager.cpp
Normal file
File diff suppressed because it is too large
Load Diff
136
project/jni/application/enigma/src/lev/ScoreManager.hh
Normal file
136
project/jni/application/enigma/src/lev/ScoreManager.hh
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SCOREMGR_HH_INCLUDED
|
||||
#define SCOREMGR_HH_INCLUDED
|
||||
|
||||
#include "PropertyManager.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
#include "lev/RatingManager.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "main.hh"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <xercesc/dom/DOMElement.hpp>
|
||||
|
||||
namespace enigma { namespace lev {
|
||||
// Constants
|
||||
enum {
|
||||
SCORE_MAX = 99*60+59,
|
||||
SCORE_UNSOLVED = -1,
|
||||
SCORE_SOLVED = -2
|
||||
};
|
||||
|
||||
/**
|
||||
* A singelton manager for user scores.
|
||||
*
|
||||
* There are 2 small paradigm shifts in 0.92 scores and 1.00 scores:<p>
|
||||
* There is no longer a separate "finished" flag but levels that have
|
||||
* been solved without a score value are marked as "SCORE_SOLVED".<p>
|
||||
* Easy mode scores for levels that have no separate easy mode are stored
|
||||
* as difficult mode scores. All requests for easy mode scores return the
|
||||
* difficult mode scores in this case.
|
||||
*/
|
||||
class ScoreManager : public PropertyManager{
|
||||
public:
|
||||
static ScoreManager *instance();
|
||||
~ScoreManager();
|
||||
void markModified();
|
||||
virtual bool save();
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* Returns true if the level has been solved for the given difficulty
|
||||
* in any score version.
|
||||
* @arg difficulty DIFFICULTY_EASY, DIFFICULTY_HARD, DIFFICULTY_ANY
|
||||
*/
|
||||
bool isSolved(lev::Proxy *levelProxy, int difficulty);
|
||||
/**
|
||||
* Returns true if the level has only been solved for the given difficulty
|
||||
* in an outdated score version.
|
||||
* @arg difficulty DIFFICULTY_EASY, DIFFICULTY_HARD
|
||||
*/
|
||||
bool isOutdated(lev::Proxy *levelProxy, int difficulty);
|
||||
/**
|
||||
* Returns the best score that the user has reached for the given
|
||||
* difficulty so far or -1 for not yet solved in the current score
|
||||
* version.
|
||||
* @arg difficulty DIFFICULTY_EASY, DIFFICULTY_HARD
|
||||
*/
|
||||
int getBestUserScore(lev::Proxy *levelProxy, int difficulty);
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void updateUserScore(lev::Proxy *levelProxy, int difficulty, int score,
|
||||
double enigmaRelease = ENIGMACOMPATIBITLITY);
|
||||
/**
|
||||
* Returns true if the users best score is equal or better than the
|
||||
* official best score for the given difficulty
|
||||
* @arg difficulty DIFFICULTY_EASY, DIFFICULTY_HARD
|
||||
*/
|
||||
bool bestScoreReached(lev::Proxy *levelProxy, int difficulty);
|
||||
bool parScoreReached(lev::Proxy *levelProxy, int difficulty);
|
||||
/**
|
||||
* Resets the user score status to unsolved for the given diffculty.
|
||||
* If the level has no easy mode the score for the difficult mode
|
||||
* will be reset to unsolved.
|
||||
*/
|
||||
void markUnsolved(lev::Proxy *levelProxy, int difficulty);
|
||||
/**
|
||||
* Resets the score value and marks the level as solved for the given
|
||||
* difficulty. If the level has no easy mode a request will mark the
|
||||
* difficult mode score as solved. This action is restriced to
|
||||
* wizards.
|
||||
*/
|
||||
void markSolved(lev::Proxy *levelProxy, int difficulty);
|
||||
int countSolved(lev::Index *ind, int difficulty);
|
||||
int countBestScore(lev::Index *ind, int difficulty);
|
||||
int countParScore(lev::Index *ind, int difficulty);
|
||||
double calcHCP(lev::Index *ind, int difficulty);
|
||||
void setRating(lev::Proxy *levelProxy, int rating);
|
||||
int getRating(lev::Proxy *levelProxy);
|
||||
bool isRatingInherited(lev::Proxy *levelProxy);
|
||||
protected:
|
||||
ScoreManager();
|
||||
private:
|
||||
static ScoreManager *theSingleton;
|
||||
static unsigned ctab[256];
|
||||
static unsigned pol;
|
||||
RatingManager *ratingMgr;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *levelsElem;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMNodeList * levelList;
|
||||
std::map<std::string, XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *> allLevelScores; // all scoreversions for each level
|
||||
std::map<std::string, XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *> curLevelScores; // most current scoreversion for each level
|
||||
std::string userId;
|
||||
bool hasValidUserId;
|
||||
bool didUpgrade;
|
||||
bool isModified;
|
||||
|
||||
void finishUserId(unsigned id3);
|
||||
std::string sec(std::string target);
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement * getLevel(lev::Proxy *levelProxy);
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement * getCreateLevel(lev::Proxy *levelProxy);
|
||||
|
||||
unsigned idFromLegacyScore();
|
||||
std::string upgradeSum();
|
||||
bool upgradeLegacy();
|
||||
};
|
||||
}} // namespace enigma::lev
|
||||
|
||||
#endif
|
||||
53
project/jni/application/enigma/src/lev/VolatileIndex.cpp
Normal file
53
project/jni/application/enigma/src/lev/VolatileIndex.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "lev/VolatileIndex.hh"
|
||||
#include "errors.hh"
|
||||
#include "main.hh"
|
||||
|
||||
|
||||
|
||||
namespace enigma { namespace lev {
|
||||
|
||||
int VolatileIndex::levelCount = 0;
|
||||
|
||||
VolatileIndex::VolatileIndex(std::string anIndexName, std::string aGroupName,
|
||||
const std::vector<string> levelpaths, double defaultLocation) :
|
||||
Index(anIndexName, aGroupName, defaultLocation) {
|
||||
for (unsigned i=0; i<levelpaths.size(); i++) {
|
||||
levelCount++;
|
||||
Proxy * aProxy = Proxy::registerLevel(levelpaths[i], "#commandline",
|
||||
ecl::strf("_%d",levelCount), ecl::strf("Level %d", i), "unknown",
|
||||
1, 0, false, GAMET_UNKNOWN, STATUS_UNKNOWN);
|
||||
proxies.push_back(aProxy);
|
||||
try {
|
||||
aProxy->loadMetadata(true);
|
||||
}
|
||||
catch (XLevelLoading &err) {
|
||||
Log << "Level load error on '" << levelpaths[i] << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VolatileIndex::~VolatileIndex() {}
|
||||
|
||||
void VolatileIndex::clear() {
|
||||
proxies.clear();
|
||||
currentPosition = 0;
|
||||
}
|
||||
}} // namespace enigma::lev
|
||||
46
project/jni/application/enigma/src/lev/VolatileIndex.hh
Normal file
46
project/jni/application/enigma/src/lev/VolatileIndex.hh
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef LEV_VOLATILEINDEX_HH_INCLUDED
|
||||
#define LEV_VOLATILEINDEX_HH_INCLUDED
|
||||
|
||||
#include "lev/Index.hh"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace enigma { namespace lev {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class VolatileIndex : public Index {
|
||||
public:
|
||||
/**
|
||||
* Convention: method names *Level() can take int pos or Proxy as arg.
|
||||
*/
|
||||
VolatileIndex(std::string anIndexName, std::string aGroupName,
|
||||
const std::vector<string> levelpaths,
|
||||
double defaultLocation = INDEX_DEFAULT_PACK_LOCATION);
|
||||
~VolatileIndex();
|
||||
virtual void clear();
|
||||
private:
|
||||
static int levelCount; // used for volatile level ids - necessary for lua levels
|
||||
};
|
||||
|
||||
}} // namespace enigma::lev
|
||||
#endif
|
||||
Reference in New Issue
Block a user