Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F134918
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
21 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/LevelPack.cpp b/src/LevelPack.cpp
index 89ecdb6..432f526 100644
--- a/src/LevelPack.cpp
+++ b/src/LevelPack.cpp
@@ -1,512 +1,528 @@
/****************************************************************************
** Copyright (C) 2011 Luka Horvat <redreaper132 at gmail.com>
** Copyright (C) 2011 Edward Lii <edward_iii at myway.com>
** Copyright (C) 2011 O. Bahri Gordebak <gordebak at gmail.com>
**
**
** This file may be used under the terms of the GNU General Public
** License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#include "LevelPack.h"
#include "Functions.h"
#include "FileManager.h"
#include "TreeStorageNode.h"
#include "POASerializer.h"
#include "MD5.h"
#include <dirent.h>
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
using namespace std;
+LevelPack::LevelPack():currentLevel(0),loaded(false),levels(){
+ //We need to set the pointer to the dictionaryManager to NULL.
+ dictionaryManager=NULL;
+}
+
+LevelPack::~LevelPack(){
+ //We call clear, since that already takes care of the deletion, including the dictionaryManager.
+ clear();
+}
+
void LevelPack::clear(){
currentLevel=0;
loaded=false;
levels.clear();
levelpackDescription.clear();
levelpackPath.clear();
levelProgressFile.clear();
congratulationText.clear();
+
+ //Also delte the dictionaryManager if it isn't null.
+ if(dictionaryManager){
+ delete dictionaryManager;
+ dictionaryManager=NULL;
+ }
}
bool LevelPack::loadLevels(const std::string& levelListFile){
//We're going to load a new levellist so first clean any existing levels.
clear();
//If the levelListFile is empty we have nothing to load so we return false.
if(levelListFile.empty()){
cerr<<"ERROR: No levellist file given."<<endl;
return false;
}
//Process the levelListFile, create a new string since lecelListFile is constant.
string levelListNew=levelListFile;
levelpackPath=pathFromFileName(levelListNew);
//Create two input streams, one for the levellist file and one for the levelprogress.
ifstream level(levelListNew.c_str());
if(!level){
cerr<<"ERROR: Can't load level list "<<levelListNew<<endl;
return false;
}
//Load the level list file.
TreeStorageNode obj;
{
POASerializer objSerializer;
if(!objSerializer.readNode(level,&obj,true)){
cerr<<"ERROR: Invalid file format of level list "<<levelListNew<<endl;
return false;
}
}
//Check if there are translations for the levels.
{
//Try to open the locale folder in the levelpack to detect if there are translations for the levelpack.
DIR *pDir;
pDir=opendir((pathFromFileName(levelListNew)+"locale/").c_str());
if(pDir!=NULL){
//Folder is present so configure the levelDictionaryManager.
dictionaryManager=new tinygettext::DictionaryManager();
dictionaryManager->add_directory(pathFromFileName(levelListNew)+"locale/");
dictionaryManager->set_charset("UTF-8");
dictionaryManager->set_language(tinygettext::Language::from_name(language));
}else{
dictionaryManager=NULL;
}
}
//Look for the name.
{
vector<string> &v=obj.attributes["name"];
if(v.size()>0){
levelpackName=v[0];
}else{
//Name is not defined so take the folder name.
levelpackName=pathFromFileName(levelListFile);
//Remove the last character '/'
levelpackName=levelpackName.substr(0,levelpackName.size()-1);
levelpackName=fileNameFromPath(levelpackName);
}
}
//Look for the description.
{
vector<string> &v=obj.attributes["description"];
if(v.size()>0)
levelpackDescription=v[0];
}
//Look for the congratulation text.
{
vector<string> &v=obj.attributes["congratulations"];
if(v.size()>0)
congratulationText=v[0];
}
//Loop through the level list entries.
for(unsigned int i=0;i<obj.subNodes.size();i++){
TreeStorageNode* obj1=obj.subNodes[i];
if(obj1==NULL)
continue;
if(obj1->value.size()>=1 && obj1->name=="levelfile"){
Level level;
level.file=obj1->value[0];
level.targetTime=0;
level.targetRecordings=0;
//Open the level file to retrieve the name and target time/recordings.
TreeStorageNode obj;
POASerializer objSerializer;
if(objSerializer.loadNodeFromFile((levelpackPath+level.file).c_str(),&obj,true)){
//Calc the MD5 FIRST because query obj.attributes will modify internal structure.
obj.name.clear();
obj.calcMD5(level.md5Digest);
//Get the name of the level.
vector<string>& v=obj.attributes["name"];
if(v.size()>0)
level.name=v[0];
//If the name is empty then we set it to the file name.
if(level.name.empty())
level.name=fileNameFromPath(level.file);
//Get the target time of the level.
v=obj.attributes["time"];
if(v.size()>0)
level.targetTime=atoi(v[0].c_str());
else
level.targetTime=-1;
//Get the target recordings of the level.
v=obj.attributes["recordings"];
if(v.size()>0)
level.targetRecordings=atoi(v[0].c_str());
else
level.targetRecordings=-1;
}
//The default for locked is true, unless it's the first one.
level.locked=!levels.empty();
level.won=false;
level.time=-1;
level.recordings=-1;
//Add the level to the levels.
levels.push_back(level);
}
}
loaded=true;
return true;
}
void LevelPack::loadProgress(const std::string& levelProgressFile){
//Open the levelProgress file.
ifstream levelProgress;
if(!levelProgressFile.empty()){
this->levelProgressFile=levelProgressFile;
levelProgress.open(processFileName(this->levelProgressFile).c_str());
}
//Check if the file exists.
if(levelProgress){
//Now load the progress/statistics.
TreeStorageNode obj;
{
POASerializer objSerializer;
if(!objSerializer.readNode(levelProgress,&obj,true)){
cerr<<"ERROR: Invalid file format of level progress file."<<endl;
}
}
//Loop through the entries.
for(unsigned int i=0;i<obj.subNodes.size();i++){
TreeStorageNode* obj1=obj.subNodes[i];
if(obj1==NULL)
continue;
if(obj1->value.size()>=1 && obj1->name=="level"){
//We've found an entry for a level, now search the correct level.
Level* level=NULL;
for(unsigned int o=0;o<levels.size();o++){
if(obj1->value[0]==levels[o].file){
level=&levels[o];
break;
}
}
//Check if we found the level.
if(!level)
continue;
//Get the progress/statistics.
for(map<string,vector<string> >::iterator i=obj1->attributes.begin();i!=obj1->attributes.end();i++){
if(i->first=="locked"){
level->locked=(i->second[0]=="1");
}
if(i->first=="won"){
level->won=(i->second[0]=="1");
}
if(i->first=="time"){
level->time=(atoi(i->second[0].c_str()));
}
if(i->first=="recordings"){
level->recordings=(atoi(i->second[0].c_str()));
}
}
}
}
}
}
void LevelPack::saveLevels(const std::string& levelListFile){
//Get the fileName.
string levelListNew=processFileName(levelListFile);
//Open an output stream.
ofstream level(levelListNew.c_str());
//Check if we can use the file.
if(!level){
cerr<<"ERROR: Can't save level list "<<levelListNew<<endl;
return;
}
//Storage node that will contain the data that should be written.
TreeStorageNode obj;
//Make sure that there's a description.
if(!levelpackDescription.empty())
obj.attributes["description"].push_back(levelpackDescription);
//Make sure that there's a congratulation text.
if(!congratulationText.empty())
obj.attributes["congratulations"].push_back(congratulationText);
//Add the levels to the file.
for(unsigned int i=0;i<levels.size();i++){
TreeStorageNode* obj1=new TreeStorageNode;
obj1->name="levelfile";
obj1->value.push_back(fileNameFromPath(levels[i].file));
obj1->value.push_back(levels[i].name);
obj.subNodes.push_back(obj1);
//We copy them to the levelpack folder
//Check if the levelpath is relative or absolute.
if(levels[i].file[0]=='%'){
copyFile(processFileName(levels[i].file).c_str(),(pathFromFileName(levelListNew)+fileNameFromPath(levels[i].file)).c_str());
}else{
//Make sure we aren't copying to the same location.
if((levelpackPath+levels[i].file)!=(pathFromFileName(levelListNew)+fileNameFromPath(levels[i].file))){
copyFile((levelpackPath+levels[i].file).c_str(),(pathFromFileName(levelListNew)+fileNameFromPath(levels[i].file)).c_str());
}
}
}
//Write the it away.
POASerializer objSerializer;
objSerializer.writeNode(&obj,level,false,true);
}
void LevelPack::addLevel(const string& levelFileName,int levelno){
//Fill in the details.
Level level;
if(!levelpackPath.empty() && levelFileName.compare(0,levelpackPath.length(),levelpackPath)==0){
level.file=fileNameFromPath(levelFileName);
}else{
level.file=levelFileName;
}
level.targetTime=0;
level.targetRecordings=0;
//Get the name of the level.
TreeStorageNode obj;
POASerializer objSerializer;
if(objSerializer.loadNodeFromFile(levelFileName.c_str(),&obj,true)){
//Calc the MD5 FIRST because query obj.attributes will modify internal structure.
obj.name.clear();
obj.calcMD5(level.md5Digest);
//Get the name of the level.
vector<string>& v=obj.attributes["name"];
if(v.size()>0)
level.name=v[0];
//If the name is empty then we set it to the file name.
if(level.name.empty())
level.name=fileNameFromPath(levelFileName);
//Get the target time of the level.
v=obj.attributes["time"];
if(v.size()>0)
level.targetTime=atoi(v[0].c_str());
else
level.targetTime=-1;
//Get the target recordings of the level.
v=obj.attributes["recordings"];
if(v.size()>0)
level.targetRecordings=atoi(v[0].c_str());
else
level.targetRecordings=-1;
}
//Set if it should be locked or not.
level.won=false;
level.time=-1;
level.recordings=-1;
level.locked=levels.size()>0?true:false;
//Check if the level should be at the end or somewhere in the middle.
if(levelno<0 || levelno>=int(levels.size())){
levels.push_back(level);
}else{
levels.insert(levels.begin()+levelno,level);
}
//NOTE: We set loaded to true.
loaded=true;
}
void LevelPack::moveLevel(unsigned int level1,unsigned int level2){
if(level1<0 || level1>=levels.size())
return;
if(level2<0 || level2>=levels.size())
return;
if(level1==level2)
return;
levels.insert(levels.begin()+level2,levels[level1]);
if(level2<=level1)
levels.erase(levels.begin()+level1+1);
else
levels.erase(levels.begin()+level1);
}
void LevelPack::saveLevelProgress(){
//Check if the levels are loaded and a progress file is given.
if(!loaded || levelProgressFile.empty())
return;
//Open the progress file.
ofstream levelProgress(processFileName(levelProgressFile).c_str());
if(!levelProgress)
return;
//Open an output stream.
TreeStorageNode node;
//Loop through the levels.
for(unsigned int o=0;o<levels.size();o++){
TreeStorageNode* obj=new TreeStorageNode;
node.subNodes.push_back(obj);
char s[64];
//Set the name of the node.
obj->name="level";
obj->value.push_back(levels[o].file);
//Set the values.
obj->attributes["locked"].push_back(levels[o].locked?"1":"0");
obj->attributes["won"].push_back(levels[o].won?"1":"0");
sprintf(s,"%d",levels[o].time);
obj->attributes["time"].push_back(s);
sprintf(s,"%d",levels[o].recordings);
obj->attributes["recordings"].push_back(s);
}
//Create a POASerializer and write away the leve node.
POASerializer objSerializer;
objSerializer.writeNode(&node,levelProgress,true,true);
}
const string& LevelPack::getLevelName(int level){
if(level<0)
level=currentLevel;
return levels[level].name;
}
const unsigned char* LevelPack::getLevelMD5(int level){
if(level<0)
level=currentLevel;
return levels[level].md5Digest;
}
void LevelPack::getLevelAutoSaveRecordPath(int level,std::string &bestTimeFilePath,std::string &bestRecordingFilePath,bool createPath){
if(level<0)
level=currentLevel;
bestTimeFilePath.clear();
bestRecordingFilePath.clear();
//get level pack path.
string levelpackPath=LevelPack::levelpackPath;
string s=levels[level].file;
//process level pack name
for(;;){
string::size_type lps=levelpackPath.find_last_of("/\\");
if(lps==string::npos){
break;
}else if(lps==levelpackPath.size()-1){
levelpackPath.resize(lps);
}else{
levelpackPath=levelpackPath.substr(lps+1);
break;
}
}
//profess file name
{
string::size_type lps=s.find_last_of("/\\");
if(lps!=string::npos) s=s.substr(lps+1);
}
//check if it's custom level
{
string path="%USER%/records/autosave/";
if(!levelpackPath.empty()){
path+=levelpackPath;
path+='/';
}
path=processFileName(path);
if(createPath) createDirectory(path.c_str());
s=path+s;
}
//calculate MD5
s+='-';
s+=Md5::toString(levels[level].md5Digest);
//over
bestTimeFilePath=s+"-best-time.mnmsrec";
bestRecordingFilePath=s+"-best-recordings.mnmsrec";
}
void LevelPack::setLevelName(unsigned int level,const std::string& name){
if(level<levels.size())
levels[level].name=name;
}
const string& LevelPack::getLevelFile(int level){
if(level<0)
level=currentLevel;
return levels[level].file;
}
const string& LevelPack::getLevelpackPath(){
return levelpackPath;
}
struct LevelPack::Level* LevelPack::getLevel(int level){
if(level<0)
return &levels[currentLevel];
return &levels[level];
}
void LevelPack::resetLevel(int level){
if(level<0)
level=currentLevel;
//Set back to default.
levels[level].locked=(level!=0);
levels[level].won=false;
levels[level].time=-1;
levels[level].recordings=-1;
}
void LevelPack::nextLevel(){
currentLevel++;
}
bool LevelPack::getLocked(unsigned int level){
return levels[level].locked;
}
void LevelPack::setCurrentLevel(unsigned int level){
currentLevel=level;
}
void LevelPack::setLocked(unsigned int level,bool locked){
levels[level].locked=locked;
}
void LevelPack::swapLevel(unsigned int level1,unsigned int level2){
if(level1<levels.size()&&level2<levels.size()){
swap(levels[level1],levels[level2]);
}
}
void LevelPack::removeLevel(unsigned int level){
if(level<levels.size()){
levels.erase(levels.begin()+level);
}
}
diff --git a/src/LevelPack.h b/src/LevelPack.h
index a666e85..492c3a8 100644
--- a/src/LevelPack.h
+++ b/src/LevelPack.h
@@ -1,182 +1,184 @@
/****************************************************************************
** Copyright (C) 2011 Luka Horvat <redreaper132 at gmail.com>
** Copyright (C) 2011 Edward Lii <edward_iii at myway.com>
** Copyright (C) 2011 O. Bahri Gordebak <gordebak at gmail.com>
**
**
** This file may be used under the terms of the GNU General Public
** License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#ifndef LEVELPACK_H
#define LEVELPACK_H
#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
#include <vector>
#include <string>
#include "GameObjects.h"
#include "Player.h"
#include "libs/tinygettext/tinygettext.hpp"
class LevelPack{
public:
//A level entry structure.
struct Level{
//The name of the level.
string name;
//The filename of the level.
string file;
//Boolean if the level is locked.
bool locked;
//Boolean if the level is won.
bool won;
//Integer containing the number of ticks (40 = 1s) it took to finish the level.
//If there's no time the value will be -1.
int time;
//Integer containing the target time to get a medal.
int targetTime;
//Integer containing the number of recordings used to finish the level.
//When not won the value is -1.
int recordings;
//Integer containing the target recordings to get a medal.
int targetRecordings;
//MD5 of level node. :/
unsigned char md5Digest[16];
};
private:
//Index of the current level.
int currentLevel;
//Boolean if the levels are loaded.
bool loaded;
//Vector containing the filenames of the levels.
std::vector<Level> levels;
//The file name of the level progress.
std::string levelProgressFile;
public:
//The name of the levelpack.
std::string levelpackName;
//The location the levelpack is stored.
std::string levelpackPath;
//A description of the levelpack.
std::string levelpackDescription;
//The text that will be displayed when the levels are finished.
std::string congratulationText;
//The dictionaryManager of the levelpack, used to translate strings.
tinygettext::DictionaryManager* dictionaryManager;
//Constructor.
- LevelPack():currentLevel(0),loaded(false),levels(){};
+ LevelPack();
+ //Destructor.
+ ~LevelPack();
//gettext function
//message: The message to translate.
inline const char* _(const std::string& message){
if(dictionaryManager){
return dictionaryManager->get_dictionary().translate(message).c_str();
}else{
return message.c_str();
}
}
//Adds a level to the levels.
//levelFileName: The filename of the level to add.
//level: The index of the level to add.
void addLevel(const std::string& levelFileName,int levelno=-1);
//Removes a level from the levels.
//level: The index of the level to remove.
void removeLevel(unsigned int level);
//Moves the level to a given index.
//level1: The level to move.
//level2: The destination.
void moveLevel(unsigned int level1,unsigned int level2);
//Swaps two level.
//level1: The first level to swap.
//level2: The second level to swap.
void swapLevel(unsigned int level1,unsigned int level2);
//Get the levelFile for a given level.
//level: The level index to get the levelFileName from.
//Returns: String containing the levelFileName.
const std::string& getLevelFile(int level=-1);
//Get the levelpackPath of the levels.
//Returns: String containing the levelpackPath.
const std::string& getLevelpackPath();
//Get the levelName for a given level.
//level: The level index to get the levelName from.
//Returns: String containing the levelName.
const std::string& getLevelName(int level=-1);
//Sets the levelName for a given level.
//level: The level index to get the levelName from.
//name: The new name of the level.
void setLevelName(unsigned int level,const std::string& name);
//Get the MD5 for a given level.
//level: The level index.
//Returns: const unsigned char[16] contains the digest.
const unsigned char* getLevelMD5(int level=-1);
//get level's auto-save record path,
//using level's MD5, file name and other information.
void getLevelAutoSaveRecordPath(int level,std::string &bestTimeFilePath,std::string &bestRecordingFilePath,bool createPath);
//Set the currentLevel.
//level: The new current level.
void setCurrentLevel(unsigned int level);
//Get the currentLevel.
//Returns: The currentLevel.
inline int getCurrentLevel(){return currentLevel;}
//Get the levelCount.
//Returns: The level count.
inline int getLevelCount(){return levels.size();}
//Method that will return the requested level.
//level: The index of the level, default is the current level.
//Returns: Pointer to the requested level structure.
struct Level* getLevel(int level=-1);
//Method that will reset any progress/statistics for a given level.
//level: The index of the level to reset, default is currentLevel.
void resetLevel(int level=-1);
//Check if a certain level is locked.
//level: The index of the level to check.
//Returns: True if the level is locked.
bool getLocked(unsigned int level);
//Set a level locked or not.
//level: The level to (un)lock.
//locked: The new status of the level, default is unlocked (false).
void setLocked(unsigned int level,bool locked=false);
//Empties the levels.
void clear();
bool loadLevels(const std::string& levelListFile);
void loadProgress(const std::string& levelProgressFile);
void saveLevels(const std::string& levelListFile);
void saveLevelProgress();
void nextLevel();
};
#endif
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Jun 19, 8:10 PM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
71423
Default Alt Text
(21 KB)
Attached To
Mode
R79 meandmyshadow
Attached
Detach File
Event Timeline