Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
543 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/README b/README
index 1e8bd49..1daf991 100644
--- a/README
+++ b/README
@@ -1,64 +1,76 @@
Me and My Shadow
====================
Me and My Shadow is a free libre puzzle/platform game in which you try to reach
the exit by solving puzzles. Spikes, moving blocks, fragile blocks and much
more stand between you and the exit. Record your moves and let your shadow
mimic them to reach blocks you couldn't reach alone.
- Tutorial for beginners
- 2 level packs containing over 40 levels
- 18 different block types
- Built-in level editor
- Easily installable addons
- Original music by Juho-Petteri Yliuntinen
- Cross platform
Compiling on Linux
====================
You will need the following packages (and their -dev(el) files) to be installed:
* libSDL
* libSDL_image
* libSDL_ttf
* libSDL_mixer
* libSDL_gfx
* libcurl
* libarchive
* cmake
* C++ compiler (found in packages like g++, gcc-c++, gcc)
The process is simple. Enter a terminal and move to directory containing
MeAndMyShadow. Then just type
cmake .
to generate the Makefile. If everything configured properly you don't see any
errors and then you can start compiling by typing
make
Finally you can run MeAndMyShadow with
./meandmyshadow
To install MeAndMyShadow on your system, run following as root
make install
Compiling without GL
====================
In some cases you might want to compile Me and My Shadow without openGL
hardware accelaration. In order to do this follow the steps above but replace the
cmake call with:
cmake -DHARDWARE_ACCELERATION=OFF .
Note that you can always run Me and My Shadow in SDL mode by setting gl to 0 in
the config file or by running it as following:
- meandmyshadow -set gl 0
\ No newline at end of file
+ meandmyshadow -set gl 0
+
+Compiling on Mac
+====================
+You need to have Xcode 4+ and following frameworks:
+
+ * SDL.framework
+ * SDL_image.framework
+ * SDL_ttf.framewrok
+ * SDL_mixer.framework
+ * SDL_gfx.framework
+
+Offical SDL binaries builded not builded for embeding with app. So you need to build them from sources or use unofficial binaries, please refer to this article: http://thirdcog.eu/apps/frameworks
diff --git a/src/Addons.cpp b/src/Addons.cpp
index 5610edd..3332967 100644
--- a/src/Addons.cpp
+++ b/src/Addons.cpp
@@ -1,603 +1,609 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Addons.h"
#include "GameState.h"
#include "Functions.h"
#include "FileManager.h"
#include "Globals.h"
#include "Objects.h"
#include "GUIObject.h"
#include "GUIScrollBar.h"
#include "GUIListBox.h"
#include "POASerializer.h"
#include "InputManager.h"
#include <string>
#include <sstream>
#include <iostream>
-#include <SDL/SDL_ttf.h>
#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_ttf/SDL_ttf.h>
+#else
+#include <SDL/SDL_ttf.h>
+#endif
+
+
using namespace std;
Addons::Addons(){
//Render the title.
title=TTF_RenderUTF8_Blended(fontTitle,_("Addons"),themeTextColor);
FILE* addon=fopen((getUserPath(USER_CACHE)+"addons").c_str(),"wb");
action=NONE;
addons=NULL;
//Clear the GUI if any.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
//Try to get(download) the addonsList.
if(getAddonsList(addon)==false) {
//It failed so we show the error message.
GUIObjectRoot=new GUIObject(0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
GUIObject* obj=new GUIObject(90,96,200,32,GUIObjectLabel,_("Unable to initialize addon menu:"));
obj->name="lbl";
GUIObjectRoot->addChild(obj);
obj=new GUIObject(120,130,200,32,GUIObjectLabel,error.c_str());
obj->name="lbl";
GUIObjectRoot->addChild(obj);
obj=new GUIObject(90,550,200,32,GUIObjectButton,_("Back"));
obj->name="cmdBack";
obj->eventCallback=this;
GUIObjectRoot->addChild(obj);
return;
}
//Now create the GUI.
createGUI();
}
Addons::~Addons(){
delete addons;
//Free the title surface.
SDL_FreeSurface(title);
//If the GUIObjectRoot exist delete it.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}
void Addons::createGUI(){
//Downloaded the addons file now we can create the GUI.
GUIObjectRoot=new GUIObject(0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
//Create list of categories
GUISingleLineListBox *listTabs=new GUISingleLineListBox((SCREEN_WIDTH-360)/2,100,360,36);
listTabs->name="lstTabs";
listTabs->item.push_back(_("Levels"));
listTabs->item.push_back(_("Level Packs"));
listTabs->item.push_back(_("Themes"));
listTabs->value=0;
listTabs->eventCallback=this;
GUIObjectRoot->addChild(listTabs);
//Create the list for the addons.
//By default levels will be selected.
list=new GUIListBox(SCREEN_WIDTH*0.1,160,SCREEN_WIDTH*0.8,SCREEN_HEIGHT-220);
list->item=addonsToList("levels");
list->name="lstAddons";
list->eventCallback=this;
list->value=-1;
GUIObjectRoot->addChild(list);
type="levels";
//And the buttons at the bottom of the screen.
GUIObject* obj=new GUIObject(SCREEN_WIDTH*0.3,SCREEN_HEIGHT-50,-1,32,GUIObjectButton,_("Back"),0,true,true,GUIGravityCenter);
obj->name="cmdBack";
obj->eventCallback=this;
GUIObjectRoot->addChild(obj);
actionButton=new GUIObject(SCREEN_WIDTH*0.7,SCREEN_HEIGHT-50,-1,32,GUIObjectButton,_("Install"),0,false,true,GUIGravityCenter);
actionButton->name="cmdInstall";
actionButton->eventCallback=this;
GUIObjectRoot->addChild(actionButton);
updateButton=new GUIObject(SCREEN_WIDTH*0.5,SCREEN_HEIGHT-50,-1,32,GUIObjectButton,_("Update"),0,false,false,GUIGravityCenter);
updateButton->name="cmdUpdate";
updateButton->eventCallback=this;
GUIObjectRoot->addChild(updateButton);
}
bool Addons::getAddonsList(FILE* file){
//First we download the file.
if(downloadFile("http://sourceforge.net/p/meandmyshadow/addons/ci/HEAD/tree/addons04?format=raw",file)==false){
//NOTE: We keep the console output English so we put the string literal here twice.
cerr<<"ERROR: unable to download addons file!"<<endl;
error=_("ERROR: unable to download addons file!");
return false;
}
fclose(file);
//Load the downloaded file.
ifstream addonFile;
addonFile.open((getUserPath(USER_CACHE)+"addons").c_str());
if(!addonFile.good()) {
//NOTE: We keep the console output English so we put the string literal here twice.
cerr<<"ERROR: unable to load addon_list file!"<<endl;
error=_("ERROR: unable to load addon_list file!");
return false;
}
//Parse the addonsfile.
TreeStorageNode obj;
{
POASerializer objSerializer;
if(!objSerializer.readNode(addonFile,&obj,true)){
//NOTE: We keep the console output English so we put the string literal here twice.
cerr<<"ERROR: Invalid file format of addons file!"<<endl;
error=_("ERROR: Invalid file format of addons file!");
return false;
}
}
//Also load the installed_addons file.
ifstream iaddonFile;
iaddonFile.open((getUserPath(USER_CONFIG)+"installed_addons").c_str());
if(!iaddonFile) {
//The installed_addons file doesn't exist, so we create it.
ofstream iaddons;
iaddons.open((getUserPath(USER_CONFIG)+"installed_addons").c_str());
iaddons<<" "<<endl;
iaddons.close();
//Also load the installed_addons file.
iaddonFile.open((getUserPath(USER_CONFIG)+"installed_addons").c_str());
if(!iaddonFile) {
//NOTE: We keep the console output English so we put the string literal here twice.
cerr<<"ERROR: Unable to create the installed_addons file."<<endl;
error=_("ERROR: Unable to create the installed_addons file.");
return false;
}
}
//And parse the installed_addons file.
TreeStorageNode obj1;
{
POASerializer objSerializer;
if(!objSerializer.readNode(iaddonFile,&obj1,true)){
//NOTE: We keep the console output English so we put the string literal here twice.
cerr<<"ERROR: Invalid file format of the installed_addons!"<<endl;
error=_("ERROR: Invalid file format of the installed_addons!");
return false;
}
}
//Fill the vector.
addons = new std::vector<Addon>;
fillAddonList(*addons,obj,obj1);
//Close the files.
iaddonFile.close();
addonFile.close();
return true;
}
void Addons::fillAddonList(std::vector<Addons::Addon> &list, TreeStorageNode &addons, TreeStorageNode &installed_addons){
//Loop through the blocks of the addons file.
//These should contain the types levels, levelpacks, themes.
for(unsigned int i=0;i<addons.subNodes.size();i++){
TreeStorageNode* block=addons.subNodes[i];
if(block==NULL) continue;
string type;
type=block->name;
//Now loop the entries(subNodes) of the block.
for(unsigned int i=0;i<block->subNodes.size();i++){
TreeStorageNode* entry=block->subNodes[i];
if(entry==NULL) continue;
if(entry->name=="entry" && entry->value.size()==1){
//The entry is valid so create a new Addon.
Addon addon = *(new Addon);
addon.type=type;
addon.name=entry->value[0];
addon.file=entry->attributes["file"][0];
if(!entry->attributes["folder"].empty()){
addon.folder=entry->attributes["folder"][0];
}
addon.author=entry->attributes["author"][0];
addon.version=atoi(entry->attributes["version"][0].c_str());
addon.upToDate=false;
addon.installed=false;
//Check if the addon is already installed.
for(unsigned int i=0;i<installed_addons.subNodes.size();i++){
TreeStorageNode* installed=installed_addons.subNodes[i];
if(installed==NULL) continue;
if(installed->name=="entry" && installed->value.size()==3){
if(addon.type.compare(installed->value[0])==0 && addon.name.compare(installed->value[1])==0) {
addon.installed=true;
addon.installedVersion=atoi(installed->value[2].c_str());
if(addon.installedVersion>=addon.version) {
addon.upToDate=true;
}
}
}
}
//Finally put him in the list.
list.push_back(addon);
}
}
}
}
std::vector<std::string> Addons::addonsToList(const std::string &type){
std::vector<std::string> result;
for(unsigned int i=0;i<addons->size();i++) {
//Check if the addon is from the right type.
if((*addons)[i].type==type) {
string entry = (*addons)[i].name + " by " + (*addons)[i].author;
if((*addons)[i].installed) {
if((*addons)[i].upToDate) {
entry += " *";
} else {
entry += " +";
}
}
result.push_back(entry);
}
}
return result;
}
bool Addons::saveInstalledAddons(){
if(!addons) return false;
//Open the file.
ofstream iaddons;
iaddons.open((getUserPath(USER_CONFIG)+"installed_addons").c_str());
if(!iaddons) return false;
//Loop all the levels.
TreeStorageNode installed;
for(unsigned int i=0;i<addons->size();i++) {
//Check if the level is installed or not.
if((*addons)[i].installed) {
TreeStorageNode *entry=new TreeStorageNode;
entry->name="entry";
entry->value.push_back((*addons)[i].type);
entry->value.push_back((*addons)[i].name);
char version[64];
sprintf(version,"%d",(*addons)[i].installedVersion);
entry->value.push_back(version);
installed.subNodes.push_back(entry);
}
}
//And write away the file.
POASerializer objSerializer;
objSerializer.writeNode(&installed,iaddons,true,true);
return true;
}
void Addons::handleEvents(){
//Check if we should quit.
if(event.type==SDL_QUIT){
//Save the installed addons before exiting.
saveInstalledAddons();
setNextState(STATE_EXIT);
}
//Check if escape is pressed, if so return to the main menu.
if(inputMgr.isKeyUpEvent(INPUTMGR_ESCAPE)){
setNextState(STATE_MENU);
}
}
void Addons::logic(){}
void Addons::render(){
//Draw background.
objThemes.getBackground(true)->draw(screen);
//Draw the title.
applySurface((SCREEN_WIDTH-title->w)/2,40-TITLE_FONT_RAISE,title,screen,NULL);
}
void Addons::resize(){
//Delete the gui (if any).
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
//Now create a new one.
createGUI();
}
void Addons::GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType){
if(name=="lstTabs"){
if(obj->value==0){
list->item=addonsToList("levels");
type="levels";
}else if(obj->value==1){
list->item=addonsToList("levelpacks");
type="levelpacks";
}else{
list->item=addonsToList("themes");
type="themes";
}
list->value=0;
GUIEventCallback_OnEvent("lstAddons",list,GUIEventChange);
}else if(name=="lstAddons"){
//Get the addon struct that belongs to it.
Addon *addon=NULL;
if(!list->item.empty()) {
string entry = list->item[list->value];
if(type.compare("levels")==0) {
for(unsigned int i=0;i<addons->size();i++) {
std::string prefix=(*addons)[i].name;
if(!entry.compare(0, prefix.size(), prefix)) {
addon=&(*addons)[i];
}
}
} else if(type.compare("levelpacks")==0) {
for(unsigned int i=0;i<addons->size();i++) {
std::string prefix=(*addons)[i].name;
if(!entry.compare(0, prefix.size(), prefix)) {
addon=&(*addons)[i];
}
}
} else if(type.compare("themes")==0) {
for(unsigned int i=0;i<addons->size();i++) {
std::string prefix=(*addons)[i].name;
if(!entry.compare(0, prefix.size(), prefix)) {
addon=&(*addons)[i];
}
}
}
}
selected=addon;
updateActionButton();
updateUpdateButton();
}else if(name=="cmdBack"){
saveInstalledAddons();
setNextState(STATE_MENU);
}else if(name=="cmdUpdate"){
//First remove the addon and then install it again.
if(type.compare("levels")==0) {
if(downloadFile(selected->file,(getUserPath(USER_DATA)+"/levels/"))!=false){
selected->upToDate=true;
selected->installedVersion=selected->version;
list->item=addonsToList("levels");
updateActionButton();
updateUpdateButton();
}else{
cerr<<"ERROR: Unable to download addon!"<<endl;
msgBox(_("ERROR: Unable to download addon!"),MsgBoxOKOnly,_("ERROR:"));
return;
}
}else if(type.compare("levelpacks")==0) {
if(!removeDirectory((getUserPath(USER_DATA)+"levelpacks/"+selected->folder+"/").c_str())){
cerr<<"ERROR: Unable to remove the directory "<<(getUserPath(USER_DATA)+"levelpacks/"+selected->folder+"/")<<"."<<endl;
return;
}
if(downloadFile(selected->file,(getUserPath(USER_CACHE)+"/tmp/"))!=false){
extractFile(getUserPath(USER_CACHE)+"/tmp/"+fileNameFromPath(selected->file,true),getUserPath(USER_DATA)+"/levelpacks/"+selected->folder+"/");
selected->upToDate=true;
selected->installedVersion=selected->version;
list->item=addonsToList("levelpacks");
updateActionButton();
updateUpdateButton();
}else{
cerr<<"ERROR: Unable to download addon!"<<endl;
msgBox(_("ERROR: Unable to download addon!"),MsgBoxOKOnly,_("ERROR:"));
return;
}
}else if(type.compare("themes")==0) {
if(!removeDirectory((getUserPath(USER_DATA)+"themes/"+selected->folder+"/").c_str())){
cerr<<"ERROR: Unable to remove the directory "<<(getUserPath(USER_DATA)+"themes/"+selected->folder+"/")<<"."<<endl;
return;
}
if(downloadFile(selected->file,(getUserPath(USER_CACHE)+"/tmp/"))!=false){
extractFile((getUserPath(USER_CACHE)+"/tmp/"+fileNameFromPath(selected->file,true)),(getUserPath(USER_DATA)+"/themes/"+selected->folder+"/"));
selected->upToDate=true;
selected->installedVersion=selected->version;
list->item=addonsToList("themes");
updateActionButton();
updateUpdateButton();
}else{
cerr<<"ERROR: Unable to download addon!"<<endl;
msgBox(_("ERROR: Unable to download addon!"),MsgBoxOKOnly,_("ERROR:"));
return;
}
}
}else if(name=="cmdInstall"){
switch(action) {
case NONE:
break;
case INSTALL:
//Download the addon.
if(type.compare("levels")==0) {
if(downloadFile(selected->file,getUserPath(USER_DATA)+"/levels/")!=false){
selected->upToDate=true;
selected->installed=true;
selected->installedVersion=selected->version;
list->item=addonsToList("levels");
updateActionButton();
;
//And add the level to the levels levelpack.
LevelPack* levelsPack=getLevelPackManager()->getLevelPack("Levels");
levelsPack->addLevel(getUserPath(USER_DATA)+"/levels/"+fileNameFromPath(selected->file));
levelsPack->setLocked(levelsPack->getLevelCount()-1);
}else{
cerr<<"ERROR: Unable to download addon!"<<endl;
msgBox(_("ERROR: Unable to download addon!"),MsgBoxOKOnly,_("ERROR:"));
return;
}
}else if(type.compare("levelpacks")==0) {
if(downloadFile(selected->file,getUserPath(USER_CACHE)+"/tmp/")!=false){
extractFile(getUserPath(USER_CACHE)+"/tmp/"+fileNameFromPath(selected->file,true),getUserPath(USER_DATA)+"/levelpacks/"+selected->folder+"/");
selected->upToDate=true;
selected->installed=true;
selected->installedVersion=selected->version;
list->item=addonsToList("levelpacks");
updateActionButton();
updateUpdateButton();
//And add the levelpack to the levelpackManager.
getLevelPackManager()->loadLevelPack(getUserPath(USER_DATA)+"/levelpacks/"+selected->folder);
}else{
cerr<<"ERROR: Unable to download addon!"<<endl;
msgBox(_("ERROR: Unable to download addon!"),MsgBoxOKOnly,_("ERROR:"));
return;
}
}else if(type.compare("themes")==0) {
if(downloadFile(selected->file,getUserPath(USER_CACHE)+"/tmp/")!=false){
extractFile(getUserPath(USER_CACHE)+"/tmp/"+fileNameFromPath(selected->file,true),getUserPath(USER_DATA)+"/themes/"+selected->folder+"/");
selected->upToDate=true;
selected->installed=true;
selected->installedVersion=selected->version;
list->item=addonsToList("themes");
updateActionButton();
updateUpdateButton();
}else{
cerr<<"ERROR: Unable to download addon!"<<endl;
msgBox(_("ERROR: Unable to download addon!"),MsgBoxOKOnly,_("ERROR:"));
return;
}
}
break;
case UNINSTALL:
//Uninstall the addon.
if(type.compare("levels")==0) {
if(remove((getUserPath(USER_DATA)+"levels/"+fileNameFromPath(selected->file)).c_str())){
cerr<<"ERROR: Unable to remove the file "<<(getUserPath(USER_DATA) + "levels/" + fileNameFromPath(selected->file))<<"."<<endl;
return;
}
selected->upToDate=false;
selected->installed=false;
list->item=addonsToList("levels");
updateActionButton();
updateUpdateButton();
//And remove the level from the levels levelpack.
LevelPack* levelsPack=getLevelPackManager()->getLevelPack("Levels");
for(int i=0;i<levelsPack->getLevelCount();i++){
if(levelsPack->getLevelFile(i)==(getUserPath(USER_DATA)+"levels/"+fileNameFromPath(selected->file))){
//Remove the level and break out of the loop.
levelsPack->removeLevel(i);
break;
}
}
}else if(type.compare("levelpacks")==0) {
if(!removeDirectory((getUserPath(USER_DATA)+"levelpacks/"+selected->folder+"/").c_str())){
cerr<<"ERROR: Unable to remove the directory "<<(getUserPath(USER_DATA)+"levelpacks/"+selected->folder+"/")<<"."<<endl;
return;
}
selected->upToDate=false;
selected->installed=false;
list->item=addonsToList("levelpacks");
updateActionButton();
updateUpdateButton();
//And remove the levelpack from the levelpack manager.
getLevelPackManager()->removeLevelPack(selected->folder);
}else if(type.compare("themes")==0) {
if(!removeDirectory((getUserPath(USER_DATA)+"themes/"+selected->folder+"/").c_str())){
cerr<<"ERROR: Unable to remove the directory "<<(getUserPath(USER_DATA)+"themes/"+selected->folder+"/")<<"."<<endl;
return;
}
selected->upToDate=false;
selected->installed=false;
list->item=addonsToList("themes");
updateActionButton();
updateUpdateButton();
}
break;
}
}
}
void Addons::updateUpdateButton(){
//some sanity check
if(selected==NULL){
updateButton->enabled=false;
return;
}
//Check if the selected addon is installed.
if(selected->installed){
//It is installed, but is it uptodate?
if(selected->upToDate){
//The addon is installed and there is no need to show the button.
updateButton->enabled=false;
updateButton->visible=false;
}else{
//Otherwise show the button
updateButton->enabled=true;
updateButton->visible=true;
}
}else{
//The addon isn't installed so we can only install it.
updateButton->enabled=false;
}
}
void Addons::updateActionButton(){
//some sanity check
if(selected==NULL){
actionButton->enabled=false;
action = NONE;
return;
}
//Check if the selected addon is installed.
if(selected->installed){
//It is installed, but is it uptodate?
actionButton->enabled=true;
actionButton->caption=_("Uninstall");
action = UNINSTALL;
}else{
//The addon isn't installed so we can only install it.
actionButton->enabled=true;
actionButton->caption=_("Install");
action = INSTALL;
}
}
diff --git a/src/Addons.h b/src/Addons.h
index ac49692..c02a387 100644
--- a/src/Addons.h
+++ b/src/Addons.h
@@ -1,132 +1,136 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ADDONS_H
#define ADDONS_H
#include "GameState.h"
#include "GameObjects.h"
#include "GUIObject.h"
#include "GUIListBox.h"
#include <vector>
#include <string>
-#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#include <SDL_ttf/SDL_ttf.h>
+#else
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
+#endif
//The addons menu.
class Addons: public GameState,public GUIEventCallback{
private:
//An addon entry.
struct Addon{
//The name of the addon.
string name;
//The type of addon. (Level, Levelpack, Theme)
string type;
//The link to the addon file.
string file;
//The folder to place the addon in, only for themes and levelpacks.
string folder;
//The name of the author.
string author;
//The latest version of the addon.
int version;
//The version that the user has installed, if installed.
int installedVersion;
//Boolean if the addon is installed.
bool installed;
//Boolean if the addon is upToDate. (installedVersion==version)
bool upToDate;
};
//The title.
SDL_Surface* title;
//Vector containing all the addons.
std::vector<Addon>* addons;
//File pointing to the addon file in the userpath.
FILE* addon;
//String that should contain the error when something fails.
string error;
//The type of addon that is currently selected.
string type;
//Pointer to the addon that is selected.
Addon* selected;
//The list used for listing the addons.
GUIListBox* list;
//The button that does install/uninstall.
GUIObject* actionButton;
//The button used for the updates
GUIObject* updateButton;
//The possible actions for the action button.
//Note: Update was moved to an extra button.
enum Action{
NONE, INSTALL, UNINSTALL
};
//The current action.
Action action;
public:
//Constructor.
Addons();
//Destructor.
~Addons();
//Method that will create the GUI.
void createGUI();
//Method that loads that downloads the addons list.
//file: Pointer to the file to download the list to.
//Returns: True if the file is downloaded successfuly.
bool getAddonsList(FILE* file);
//
void fillAddonList(std::vector<Addons::Addon> &list,TreeStorageNode &addons,TreeStorageNode &installed);
//Put all the addons of a given type in a vector.
//type: The type the addons must be.
//Returns: Vector containing the addons.
std::vector<std::string> addonsToList(const string &type);
//Method that will save the installed addons to the installed_addons file.
//Returns: True if the file is saved successfuly.
bool saveInstalledAddons();
//Inherited from GameState.
void handleEvents();
void logic();
void render();
void resize();
//Method used for GUI event handling.
//name: The name of the callback.
//obj: Pointer to the GUIObject that caused the event.
//eventType: The type of event: click, change, etc..
void GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType);
//Updates the text on the action button to the current action.
void updateActionButton();
//Switches enabled/disables of the update button
void updateUpdateButton();
};
#endif
diff --git a/src/FileManager.cpp b/src/FileManager.cpp
index 1682deb..4e803b3 100644
--- a/src/FileManager.cpp
+++ b/src/FileManager.cpp
@@ -1,736 +1,752 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include "Globals.h"
#include "FileManager.h"
#include "Functions.h"
+#ifdef __APPLE__
+#include "archive.h"
+#include "archive_entry.h"
+#else
#include <archive.h>
#include <archive_entry.h>
+#endif
using namespace std;
#ifdef WIN32
#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <direct.h>
#pragma comment(lib,"shlwapi.lib")
#else
#include <strings.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
#endif
//Under Windows there's just one userpath.
#ifdef WIN32
string userPath,dataPath,appPath,exeName;
#else
//But on other platforms we make a difference between the userPath (config files) and the userDataPath (data files).
//Finally there's the path for cache data userCachePath.
string userPath,userDataPath,userCachePath,dataPath,appPath,exeName;
#endif
bool configurePaths() {
//Get the appPath and the exeName.
{
char s[4096];
int i,m;
#ifdef WIN32
m=GetModuleFileNameA(NULL,s,sizeof(s));
#else
m=readlink("/proc/self/exe",s,sizeof(s));
#endif
s[m]=0;
for(i=m-1;i>=0;i--){
if(s[i]=='/'||s[i]=='\\'){
s[i]=0;
break;
}
}
appPath=s;
exeName=s+i+1;
}
//TODO: Check if the userpath is empty before setting userPath???
//Check if the userPath is empty.
if(getUserPath().empty()){
#ifdef WIN32
//Get the userPath.
char s[1024];
SHGetSpecialFolderPathA(NULL,s,CSIDL_PERSONAL,1);
userPath=s;
userPath+="\\My Games\\meandmyshadow\\";
#else
//Temp variable that is used to prevent NULL assignement.
char* env;
//First get the $XDG_CONFIG_HOME env var.
env=getenv("XDG_CONFIG_HOME");
//If it's null set userPath to $HOME/.config/.
if(env!=NULL){
userPath=env;
}else{
userPath=getenv("HOME");
userPath+="/.config";
}
//And add meandmyshadow to it.
userPath+="/meandmyshadow/";
//Now get the $XDG_DATA_HOME env var.
env=getenv("XDG_DATA_HOME");
//If it's null set userDataPath to $HOME/.local/share.
+
if(env!=NULL){
userDataPath=env;
}else{
userDataPath=getenv("HOME");
userDataPath+="/.local/share";
}
//And add meandmyshadow to it.
userDataPath+="/meandmyshadow/";
-
+
//Now get the $XDG_CACHE_HOME env var.
env=getenv("XDG_CACHE_HOME");
//If it's null set userCachePath to $HOME/.cache.
if(env!=NULL){
userCachePath=env;
}else{
userCachePath=getenv("HOME");
userCachePath+="/.cache";
}
//And add meandmyshadow to it.
userCachePath+="/meandmyshadow/";
//Set env null.
env=NULL;
#endif
//Print the userPath.
cout<<"User preferences will be fetched from: "<<userPath<<endl;
#ifndef WIN32
//In case of a non-Windows computer show the user data path.
cout<<"User data will be fetched from: "<<userDataPath<<endl;
#endif
}
#ifdef WIN32
//Create the userPath folder and other subfolders.
createDirectory(userPath.c_str());
createDirectory((userPath+"levels").c_str());
createDirectory((userPath+"levelpacks").c_str());
createDirectory((userPath+"themes").c_str());
createDirectory((userPath+"progress").c_str());
createDirectory((userPath+"tmp").c_str());
//The records folder for recordings.
createDirectory((userPath+"records").c_str());
createDirectory((userPath+"records\\autosave").c_str());
//And the custom folder inside the userpath.
createDirectory((userPath+"custom").c_str());
createDirectory((userPath+"custom\\levels").c_str());
createDirectory((userPath+"custom\\levelpacks").c_str());
#else
//Create the userPath.
createDirectory(userPath.c_str());
createDirectory(userDataPath.c_str());
createDirectory(userCachePath.c_str());
//Also create other folders in the userpath.
createDirectory((userDataPath+"/levels").c_str());
createDirectory((userDataPath+"/levelpacks").c_str());
createDirectory((userDataPath+"/themes").c_str());
createDirectory((userDataPath+"/progress").c_str());
createDirectory((userCachePath+"/tmp").c_str());
//The records folder for recordings.
createDirectory((userDataPath+"/records").c_str());
createDirectory((userDataPath+"/records/autosave").c_str());
//And the custom folder inside the userpath.
createDirectory((userDataPath+"/custom").c_str());
createDirectory((userDataPath+"/custom/levels").c_str());
createDirectory((userDataPath+"/custom/levelpacks").c_str());
#endif
//Get the dataPath by trying multiple relative locations.
{
FILE *f;
string s;
while(true){
//try existing one
if(!dataPath.empty()){
s=dataPath+"font/knewave.ttf";
if((f=fopen(s.c_str(),"rb"))!=NULL){
fclose(f);
break;
}
}
//try "./"
dataPath="./data/";
s=dataPath+"font/knewave.ttf";
if((f=fopen(s.c_str(),"rb"))!=NULL){
fclose(f);
break;
}
//try "../"
dataPath="../data/";
s=dataPath+"font/knewave.ttf";
if((f=fopen(s.c_str(),"rb"))!=NULL){
fclose(f);
break;
}
//try App.Path
dataPath=getAppPath()+"/data/";
s=dataPath+"font/knewave.ttf";
if((f=fopen(s.c_str(),"rb"))!=NULL){
fclose(f);
break;
}
//try App.Path+"/../"
dataPath=getAppPath()+"/../data/";
s=dataPath+"font/knewave.ttf";
if((f=fopen(s.c_str(),"rb"))!=NULL){
fclose(f);
break;
}
//try DATA_PATH
#ifdef DATA_PATH
dataPath=DATA_PATH;
s=dataPath+"font/knewave.ttf";
if((f=fopen(s.c_str(),"rb"))!=NULL){
fclose(f);
break;
}
+#endif
+#ifdef __APPLE__
+ extern std::string get_data_path();
+ dataPath = get_data_path();
+ dataPath=get_data_path();
+ s=dataPath+"font/knewave.ttf";
+ if((f=fopen(s.c_str(),"rb"))!=NULL){
+ fclose(f);
+ break;
+ }
+
#endif
//error: can't find file
return false;
}
-
//Print the dataPath.
cout<<"Data files will be fetched from: "<<dataPath<<endl;
}
return true;
}
std::vector<std::string> enumAllFiles(std::string path,const char* extension,bool containsPath){
vector<string> v;
#ifdef WIN32
string s1;
WIN32_FIND_DATAA f;
if(!path.empty()){
char c=path[path.size()-1];
if(c!='/'&&c!='\\') path+="\\";
}
s1=path;
if(extension!=NULL && *extension){
s1+="*.";
s1+=extension;
}else{
s1+="*";
}
HANDLE h=FindFirstFileA(s1.c_str(),&f);
if(h==NULL||h==INVALID_HANDLE_VALUE) return v;
do{
if(!(f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
if(containsPath){
v.push_back(path+f.cFileName);
}else{
v.push_back(f.cFileName);
}
}
}while(FindNextFileA(h,&f));
FindClose(h);
return v;
#else
int len=0;
if(extension!=NULL && *extension) len=strlen(extension);
if(!path.empty()){
char c=path[path.size()-1];
if(c!='/'&&c!='\\') path+="/";
}
DIR *pDir;
struct dirent *pDirent;
pDir=opendir(path.c_str());
if(pDir==NULL) return v;
while((pDirent=readdir(pDir))!=NULL){
if(pDirent->d_name[0]=='.'){
if(pDirent->d_name[1]==0||
(pDirent->d_name[1]=='.'&&pDirent->d_name[2]==0)) continue;
}
string s1=path+pDirent->d_name;
struct stat S_stat;
lstat(s1.c_str(),&S_stat);
if(!S_ISDIR(S_stat.st_mode)){
if(len>0){
if((int)s1.size()<len+1) continue;
if(s1[s1.size()-len-1]!='.') continue;
if(strcasecmp(&s1[s1.size()-len],extension)) continue;
}
if(containsPath){
v.push_back(s1);
}else{
v.push_back(string(pDirent->d_name));
}
}
}
closedir(pDir);
return v;
#endif
}
std::vector<std::string> enumAllDirs(std::string path,bool containsPath){
vector<string> v;
#ifdef WIN32
string s1;
WIN32_FIND_DATAA f;
if(!path.empty()){
char c=path[path.size()-1];
if(c!='/'&&c!='\\') path+="\\";
}
s1=path+"*";
HANDLE h=FindFirstFileA(s1.c_str(),&f);
if(h==NULL||h==INVALID_HANDLE_VALUE) return v;
do{
// skip '.' and '..' and hidden folders
if(f.cFileName[0]=='.'){
/*if(f.cFileName[1]==0||
(f.cFileName[1]=='.'&&f.cFileName[2]==0))*/ continue;
}
if(f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
if(containsPath){
v.push_back(path+f.cFileName);
}else{
v.push_back(f.cFileName);
}
}
}while(FindNextFileA(h,&f));
FindClose(h);
return v;
#else
if(!path.empty()){
char c=path[path.size()-1];
if(c!='/'&&c!='\\') path+="/";
}
DIR *pDir;
struct dirent *pDirent;
pDir=opendir(path.c_str());
if(pDir==NULL) return v;
while((pDirent=readdir(pDir))!=NULL){
if(pDirent->d_name[0]=='.'){
if(pDirent->d_name[1]==0||
(pDirent->d_name[1]=='.'&&pDirent->d_name[2]==0)) continue;
}
string s1=path+pDirent->d_name;
struct stat S_stat;
lstat(s1.c_str(),&S_stat);
if(S_ISDIR(S_stat.st_mode)){
//Skip hidden folders.
s1=string(pDirent->d_name);
if(s1.find('.')==0) continue;
//Add result to vector.
if(containsPath){
v.push_back(path+pDirent->d_name);
}else{
v.push_back(s1);
}
}
}
closedir(pDir);
return v;
#endif
}
std::string processFileName(const std::string& s){
string prefix=dataPath;
//FIXME: Do we still need those last three?
//REMARK: maybe 'return prefix+s;' is not needed (?)
// it causes some bugs such as can't save level progress
if(s.compare(0,6,"%DATA%")==0){
if(s.size()>6 && (s[6]=='/' || s[6]=='\\')){
return dataPath+s.substr(7);
}else{
return dataPath+s.substr(6);
}
}else if(s.compare(0,6,"%USER%")==0){
if(s.size()>6 && (s[6]=='/' || s[6]=='\\')){
return getUserPath(USER_DATA)+s.substr(7);
}else{
return getUserPath(USER_DATA)+s.substr(6);
}
}else if(s.compare(0,9,"%LVLPACK%")==0){
if(s.size()>9 && (s[9]=='/' || s[9]=='\\')){
return prefix+"levelpacks/"+s.substr(10);
}else{
return prefix+"levelpacks/"+s.substr(9);
}
}else if(s.compare(0,5,"%LVL%")==0){
if(s.size()>5 && (s[5]=='/' || s[5]=='\\')){
return prefix+"levels/"+s.substr(6);
}else{
return prefix+"levels/"+s.substr(5);
}
}else if(s.compare(0,8,"%THEMES%")==0){
if(s.size()>8 && (s[8]=='/' || s[8]=='\\')){
return prefix+"themes/"+s.substr(9);
}else{
return prefix+"themes/"+s.substr(8);
}
}else if(s.size()>0 && (s[0]=='/' || s[0]=='\\')){
return s;
#ifdef WIN32
// Another fix for Windows :(
}else if(s.size()>1 && (s[1]==':')){
return s;
#endif
}else{
return prefix+s;
}
}
std::string fileNameFromPath(const std::string &path, const bool webURL){
std::string filename;
size_t pos;
#ifdef WIN32
// FIXME: '/' in string should be '/' not '\/',
// we don't need to escape it
if(webURL){
pos = path.find_last_of("/");
}else{
// NOTE: sometimes path separator in Windows can be '/',
// so we must check botn '\' and '/'
pos = path.find_last_of("\\/");
}
#else
// FIXME: '/' in string should be '/' not '\/',
// we don't need to escape it
pos = path.find_last_of("/");
#endif
if(pos != std::string::npos)
filename.assign(path.begin() + pos + 1, path.end());
else
filename=path;
return filename;
}
std::string pathFromFileName(const std::string &filename){
std::string path;
// FIXME: '/' in string should be '/' not '\/',
// we don't need to escape it
#ifdef WIN32
// NOTE: sometimes path separator in Windows can be '/',
// so we must check botn '\' and '/'
size_t pos = filename.find_last_of("\\/");
#else
size_t pos = filename.find_last_of("/");
#endif
if(pos != std::string::npos)
path.assign(filename.begin(), filename.begin() + pos +1);
else
path=filename;
return path;
}
bool downloadFile(const string &path, const string &destination) {
string filename=fileNameFromPath(path,true);
FILE* file = fopen((destination+filename).c_str(), "wb");
bool status=downloadFile(path,file);
fclose(file);
//And return the status.
return status;
}
bool downloadFile(const string &path, FILE* destination) {
CURL* curl=curl_easy_init();
// proxy test (test only)
string internetProxy = getSettings()->getValue("internet-proxy");
size_t pos = internetProxy.find_first_of(":");
if(pos!=string::npos){
curl_easy_setopt(curl,CURLOPT_PROXYPORT,atoi(internetProxy.substr(pos+1).c_str()));
internetProxy = internetProxy.substr(0,pos);
curl_easy_setopt(curl,CURLOPT_PROXY,internetProxy.c_str());
}
curl_easy_setopt(curl,CURLOPT_URL,path.c_str());
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,writeData);
curl_easy_setopt(curl,CURLOPT_WRITEDATA,destination);
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return (res==0);
}
size_t writeData(void *ptr, size_t size, size_t nmemb, void *stream){
return fwrite(ptr, size, nmemb, (FILE *)stream);
}
bool extractFile(const string &fileName, const string &destination) {
//Create the archive we're going to extract.
archive* file=NULL;
//Create the destination we're going to extract to.
archive* dest=NULL;
file=archive_read_new();
dest=archive_write_disk_new();
archive_write_disk_set_options(dest, ARCHIVE_EXTRACT_TIME);
archive_read_support_format_zip(file);
//Now read the archive.
if(archive_read_open_file(file,fileName.c_str(),10240)) {
cerr<<"Error while reading archive "+fileName<<endl;
return false;
}
//Now write every entry to disk.
int status;
archive_entry* entry=NULL;
while(true) {
status=archive_read_next_header(file,&entry);
if(status==ARCHIVE_EOF){
break;
}
if(status!=ARCHIVE_OK){
cerr<<"Error while reading archive "+fileName<<endl;
return false;
}
archive_entry_copy_pathname(entry,(destination+archive_entry_pathname(entry)).c_str());
status=archive_write_header(dest,entry);
if(status!=ARCHIVE_OK){
cerr<<"Error while extracting archive "+fileName<<endl;
return false;
}else{
copyData(file, dest);
status=archive_write_finish_entry(dest);
if(status!=ARCHIVE_OK){
cerr<<"Error while extracting archive "+fileName<<endl;
return false;
}
}
}
//Finally close the archive.
archive_read_close(file);
archive_read_finish(file);
return true;
}
bool createDirectory(const char* path){
#ifdef WIN32
char s0[1024],s[1024];
GetCurrentDirectoryA(sizeof(s0),s0);
PathCombineA(s,s0,path);
for(unsigned int i=0;i<sizeof(s);i++){
if(s[i]=='\0') break;
else if(s[i]=='/') s[i]='\\';
}
//printf("createDirectory:%s\n",s);
return SHCreateDirectoryExA(NULL,s,NULL)!=0;
#else
return mkdir(path,0777)==0;
#endif
}
bool removeDirectory(const char *path){
#ifdef WIN32
WIN32_FIND_DATAA f;
HANDLE h = FindFirstFileA((string(path)+"\\*").c_str(),&f);
#else
//Open the directory that needs to be removed.
DIR* d=opendir(path);
#endif
//Get the path length
size_t path_len = strlen(path);
//Boolean if the directory is emptied.
//True: succes False: failure
//Default is true because if the directory is empty it will never enter the while loop, but we still have success.
bool r = true;
#ifdef WIN32
if(h!=NULL && h!=INVALID_HANDLE_VALUE) {
#else
//Check if the directory exists.
if(d) {
//Pointer to an entry of the directory.
struct dirent* p;
#endif
#ifdef WIN32
do{
#else
//Loop the entries of the directory that needs to be removed as long as there's no error.
while(r && (p=readdir(d))) {
#endif
/* Skip the names "." and ".." as we don't want to recurse on them. */
#ifdef WIN32
if (!strcmp(f.cFileName, ".") || !strcmp(f.cFileName, "..")) {
#else
if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) {
#endif
//The filename is . or .. so we continue to the next entry.
continue;
} else {
//r2 tells if the entry is deleted.
//True: succes False: failure
//Default is false.
bool r2 = false;
char* buf;
size_t len;
#ifdef WIN32
//Get the length of the path + the directory entry name.
len = path_len + strlen(f.cFileName) + 2;
#else
//Get the length of the path + the directory entry name.
len = path_len + strlen(p->d_name) + 2;
#endif
buf = (char*) malloc(len);
if(buf) {
#ifdef WIN32
_snprintf(buf, len, "%s\\%s", path, f.cFileName);
if(f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
r2 = removeDirectory(buf);
}else{
r2 = unlink(buf)==0;
}
#else
struct stat statbuf;
snprintf(buf, len, "%s/%s", path, p->d_name);
if(!stat(buf, &statbuf)){
//Check if the entry is a directory or a file.
if (S_ISDIR(statbuf.st_mode)){
//We call ourself(removeDirectory) recursively.
//We return true on success.
r2 = removeDirectory(buf);
}else{
//unlink() returns zero on succes so we set r2 to the unlink(buf)==0.
r2 = unlink(buf)==0;
}
}
#endif
//Free the buf.
free(buf);
}
//We set r to r2 since r2 contains the status of the latest deletion.
r = r2;
}
#ifdef WIN32
}while(r && FindNextFileA(h,&f));
FindClose(h);
#else
}
//Close the directory.
closedir(d);
#endif
}
//The while loop has ended, meaning we (tried) cleared the directory.
//If r is true, meaning no errors we can delete the directory.
if(r){
//The return value of rmdir is 0 when it succeeded.
r = rmdir(path)==0;
}
//Return the status.
return r;
}
bool renameDirectory(const char* oldPath,const char* newPath){
return rename(oldPath,newPath)==0;
}
void copyData(archive* file, archive* dest) {
int status;
const void* buff;
size_t size;
#if ARCHIVE_VERSION_NUMBER < 3000000
off_t offset;
#else
int64_t offset;
#endif
while(true) {
status=archive_read_data_block(file, &buff, &size, &offset);
if(status==ARCHIVE_EOF){
return;
}
if(status!=ARCHIVE_OK){
cerr<<"Error while writing data to disk."<<endl;
return;
}
status=archive_write_data_block(dest, buff, size, offset);
if(status!=ARCHIVE_OK) {
cerr<<"Error while writing data to disk."<<endl;
return;
}
}
}
bool copyFile(const char* source,const char* dest){
//Open the source file.
ifstream fin(source,fstream::binary);
if(!fin)
return false;
//Open the dest file.
ofstream fout(dest,fstream::trunc|fstream::binary);
if(!fout)
return false;
//Copy.
fout<<fin.rdbuf();
return true;
}
bool removeFile(const char* file){
return remove(file)==0;
}
bool createFile(const char* file){
//Open the file with write permission.
FILE* f=fopen(file,"wb");
//Check if there are no problems.
if(f){
//Close the file.
fclose(f);
return true;
}else{
return false;
}
}
diff --git a/src/FileManager.h b/src/FileManager.h
index c8cb08f..faa1215 100644
--- a/src/FileManager.h
+++ b/src/FileManager.h
@@ -1,187 +1,191 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FILE_MANAGER_H
#define FILE_MANAGER_H
#include <string>
#include <vector>
#include <iostream>
//Included for the extractFile method.
+#ifdef __APPLE__
+#include "archive.h"
+#else
#include <archive.h>
+#endif
//Included for the downloadFile method.
#include <curl/curl.h>
//NOTE: All the methods work with processed pathnames.
//So %DATA%, %USER%, etc. can't be used.
//With exception of processFileName().
//A few strings that all have to do with file locations.
//userPath = The path the user files will be stored (addons, settings).
//exeName = The name of the executable.
//dataPath = The path the data files are located.
//appPath = The path where the executable is located.
extern std::string userPath,exeName,dataPath,appPath;
//The following two paths are for non-Windows systems only.
//userDataPath = The path for user created content and user downloaded content (addons).
//userCachePath = The path where temporary stuff will be stored.
#ifndef WIN32
extern std::string userDataPath,userCachePath;
#endif
//Enum containing the different userPath types.
//NOTE: They are only needed for the non-Windows platform..
enum UserPaths{
//The userpath containing the config files.
//Default $HOME/.config/meandmyshadow/
USER_CONFIG,
//The userpath containing the user data.
//Default $HOME/.local/share/meandmyshadow/
USER_DATA,
//The userpath containing the temporary files.
//Default $HOME/.cache/meandmyshadow/
USER_CACHE
};
//Method for retrieving the userPath.
//type: The type of userpath to return, only used on non-Windows platforms.
//Returns: The userPath.
inline const std::string& getUserPath(int type=0){
#ifdef WIN32
return userPath;
#else
switch(type){
case USER_CONFIG:
return userPath;
break;
case USER_DATA:
return userDataPath;
break;
case USER_CACHE:
return userCachePath;
break;
default:
std::cerr<<"WARNING: Illegal userpath type, returning user config path."<<std::endl;
return userPath;
break;
}
#endif
}
//Method for retrieving the exeName.
//Returns: The exeName.
inline const std::string& getEXEName(){
return exeName;
}
//Method for retrieving the dataPath.
//Returns: The dataPath.
inline const std::string& getDataPath(){
return dataPath;
}
//Method for retrieving the appPath.
//Returns: The appPath.
inline const std::string& getAppPath(){
return appPath;
}
//This method will try to find paths for the userPath, dataPath, appPath and exeName.
//Returns: True if nothing went wrong.
bool configurePaths();
//Method that returns a list of all the files in a given directory.
//path: The path to list the files of.
//extension: The extension the files must have.
//containsPath: Specifies if the return file name should contains path.
//Returns: A vector containing the names of the files.
std::vector<std::string> enumAllFiles(std::string path,const char* extension=NULL,bool containsPath=false);
//Method that returns a list of all the directories in a given directory.
//path: The path to list the directory of.
//containsPath: Specifies if the return file name should contains path.
//Returns: A vector containing the names of the directories.
std::vector<std::string> enumAllDirs(std::string path,bool containsPath=false);
//Method that will parse the string.
//It will convert %USER%, %DATA%, etc. to their according path.
//s: The string that needs to be processed.
//Returns: The processed string.
std::string processFileName(const std::string& s);
//Method used to retrieve the fileName from a full path.
//path: The path with the filename.
//webURL: Boolean if the path is a weburl.
//Returns: String containing the fileName.
std::string fileNameFromPath(const std::string &path, const bool webURL=false);
//Method used to retrieve the path without the fileName from a full path.
//filename: The path with the filename.
//Returns: String containing the path.
std::string pathFromFileName(const std::string &filename);
//Method that will download a file.
//path: The file to download.
//destination: The destination path where the file will be downloaded to.
//Returns: True if it succeeds without errors.
bool downloadFile(const std::string &path, const std::string &destination);
//Method that will download a file.
//path: The file to download.
//destination: A destination file where the downloaded file will be written to.
//Returns: True if it succeeds without errors.
bool downloadFile(const std::string &path, FILE* destination);
//Method used by curl to copy blocks of data.
size_t writeData(void* ptr,size_t size,size_t nmemb,void* stream);
//Method that will extract an archive and places it in the destination folder.
//fileName: The name of the archive.
//destination: The destination location where the extracted files will come.
//Returns: True if it succeeds without errors.
bool extractFile(const std::string &fileName, const std::string &destination);
//Method used to read a data blcok from an archive and write it to an archive.
//file: The archive to read from.
//dest: The archive to write to.
void copyData(archive* file, archive* dest);
//Method that will create a directory.
//path: The directory to create.
//Returns: True if it succeeds.
bool createDirectory(const char* path);
//Method that will remove a directory.
//path: The directory to remove.
//Returns: True if it succeeds.
bool removeDirectory(const char* path);
//Method that will rename a directory.
//oldPath: The folder path.
//newPath: The destination folder name.
//Returns: True if it succeeds.
bool renameDirectory(const char* oldPath,const char* newPath);
//Method that will create a file.
//file: The filename of the file to create.
//Returns: True if it succeeds.
bool createFile(const char* file);
//Method that will copy a file.
//source: The input file.
//dest: The output file.
//Returns: True if it succeeds.
bool copyFile(const char* source,const char* dest);
//Method that will remove a file.
//file: The file to remove.
//Returns: True if it succeeds.
bool removeFile(const char* file);
#endif
diff --git a/src/Functions.cpp b/src/Functions.cpp
index 5e4cde0..b34aa51 100644
--- a/src/Functions.cpp
+++ b/src/Functions.cpp
@@ -1,1592 +1,1599 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#include <SDL_gfx/SDL_gfxPrimitives.h>
+#include <SDL_gfx/SDL_rotozoom.h>
+#else
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_gfxPrimitives.h>
#include <SDL/SDL_rotozoom.h>
+#endif
#include <SDL/SDL_syswm.h>
#include <string>
#include "Globals.h"
#include "Functions.h"
#include "FileManager.h"
#include "Objects.h"
#include "Player.h"
#include "GameObjects.h"
#include "LevelPack.h"
#include "TitleMenu.h"
#include "LevelEditSelect.h"
#include "LevelEditor.h"
#include "Game.h"
#include "LevelPlaySelect.h"
#include "Addons.h"
#include "InputManager.h"
#include "ImageManager.h"
#include "MusicManager.h"
#include "LevelPackManager.h"
#include "ThemeManager.h"
#include "GUIListBox.h"
#include "GUIOverlay.h"
#include "StatisticsManager.h"
#include "StatisticsScreen.h"
#include "libs/tinyformat/tinyformat.h"
#include "libs/tinygettext/tinygettext.hpp"
#include "libs/tinygettext/log.hpp"
extern "C" {
#include "libs/findlocale/findlocale.h"
}
#ifdef HARDWARE_ACCELERATION
#include <GL/gl.h>
#include <GL/glu.h>
//fix some Windows header bug
#ifndef GL_BGR
#define GL_BGR GL_BGR_EXT
#endif
#ifndef GL_BGRA
#define GL_BGRA GL_BGRA_EXT
#endif
#endif
using namespace std;
#ifdef WIN32
#include <windows.h>
#include <shlobj.h>
#else
#include <strings.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
#endif
//Workaround for the resizing below 800x600 for X systems.
#ifdef __linux__
#include<X11/Xlib.h>
#include<X11/Xutil.h>
#endif
//Initialise the imagemanager.
//The ImageManager is used to prevent loading images multiple times.
ImageManager imageManager;
//Initialise the musicManager.
//The MusicManager is used to prevent loading music files multiple times and for playing/fading music.
MusicManager musicManager;
//Initialise the levelPackManager.
//The LevelPackManager is used to prevent loading levelpacks multiple times and for the game to know which levelpacks there are.
LevelPackManager levelPackManager;
//Map containing changed settings using command line arguments.
map<string,string> tmpSettings;
//Pointer to the settings object.
//It is used to load and save the settings file and change the settings.
Settings* settings=0;
#ifdef HARDWARE_ACCELERATION
GLuint screenTexture;
#endif
SDL_Surface* loadImage(string file){
//We use the imageManager to load the file.
return imageManager.loadImage(file);
}
void applySurface(int x,int y,SDL_Surface* source,SDL_Surface* dest,SDL_Rect* clip){
//The offset is needed to draw at the right location.
SDL_Rect offset;
offset.x=x;
offset.y=y;
//Let SDL do the drawing of the surface.
SDL_BlitSurface(source,clip,dest,&offset);
}
void drawRect(int x,int y,int w,int h,SDL_Surface* dest,Uint32 color){
//NOTE: We let SDL_gfx render it.
rectangleRGBA(dest,x,y,x+w,y+h,color >> 24,color >> 16,color >> 8,255);
}
//Draw a box with anti-aliased borders using SDL_gfx.
void drawGUIBox(int x,int y,int w,int h,SDL_Surface* dest,Uint32 color){
//Fill content's background color from function parameter
boxRGBA(dest,x+1,y+1,x+w-2,y+h-2,color >> 24,color >> 16,color >> 8,color >> 0);
//Draw first black borders around content and leave 1 pixel in every corner
lineRGBA(dest,x+1,y,x+w-2,y,0,0,0,255);
lineRGBA(dest,x+1,y+h-1,x+w-2,y+h-1,0,0,0,255);
lineRGBA(dest,x,y+1,x,y+h-2,0,0,0,255);
lineRGBA(dest,x+w-1,y+1,x+w-1,y+h-2,0,0,0,255);
//Fill the corners with transperent color to create anti-aliased borders
pixelRGBA(dest,x,y,0,0,0,160);
pixelRGBA(dest,x,y+h-1,0,0,0,160);
pixelRGBA(dest,x+w-1,y,0,0,0,160);
pixelRGBA(dest,x+w-1,y+h-1,0,0,0,160);
//Draw second lighter border around content
rectangleRGBA(dest,x+1,y+1,x+w-2,y+h-2,0,0,0,64);
//Create anti-aliasing in corners of second border
pixelRGBA(dest,x+1,y+1,0,0,0,50);
pixelRGBA(dest,x+1,y+h-2,0,0,0,50);
pixelRGBA(dest,x+w-2,y+1,0,0,0,50);
pixelRGBA(dest,x+w-2,y+h-2,0,0,0,50);
}
void drawLine(int x1,int y1,int x2,int y2,SDL_Surface* dest,Uint32 color){
//NOTE: We let SDL_gfx render it.
lineRGBA(dest,x1,y1,x2,y2,color >> 24,color >> 16,color >> 8,255);
}
void drawLineWithArrow(int x1,int y1,int x2,int y2,SDL_Surface* dest,Uint32 color,int spacing,int offset,int xsize,int ysize){
//Draw line first
drawLine(x1,y1,x2,y2,dest,color);
//calc delta and length
double dx=x2-x1;
double dy=y2-y1;
double length=sqrt(dx*dx+dy*dy);
if(length<0.001) return;
//calc the unit vector
dx/=length; dy/=length;
//Now draw arrows on it
for(double p=offset;p<length;p+=spacing){
drawLine(int(x1+p*dx+0.5),int(y1+p*dy+0.5),
int(x1+(p-xsize)*dx-ysize*dy+0.5),int(y1+(p-xsize)*dy+ysize*dx+0.5),dest,color);
drawLine(int(x1+p*dx+0.5),int(y1+p*dy+0.5),
int(x1+(p-xsize)*dx+ysize*dy+0.5),int(y1+(p-xsize)*dy-ysize*dx+0.5),dest,color);
}
}
bool createScreen(){
//Check if we are going fullscreen.
if(settings->getBoolValue("fullscreen"))
pickFullscreenResolution();
//Set the screen_width and height.
SCREEN_WIDTH=atoi(settings->getValue("width").c_str());
SCREEN_HEIGHT=atoi(settings->getValue("height").c_str());
//Update the camera.
camera.w=SCREEN_WIDTH;
camera.h=SCREEN_HEIGHT;
//Boolean if this is the first screen creation.
bool initial=true;
//Check if we should use gl or software rendering.
if(settings->getBoolValue("gl")){
#ifdef HARDWARE_ACCELERATION
SDL_GL_SetAttribute(SDL_GL_RED_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,16);
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE,32);
SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS,0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES,0);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
//Set the video mode.
Uint32 flags=SDL_HWSURFACE | SDL_OPENGL;
if(settings->getBoolValue("fullscreen"))
flags|=SDL_FULLSCREEN;
else if(settings->getBoolValue("resizable"))
flags|=SDL_RESIZABLE;
if(SDL_SetVideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,flags)==NULL){
fprintf(stderr,"FATAL ERROR: SDL_SetVideoMode failed\n");
return false;
}
//Delete the old screen.
//Warning: only if previous mode is OpenGL mode.
//NOTE: The previous mode can't switch during runtime.
if(screen){
SDL_FreeSurface(screen);
screen=NULL;
//There was a screen so this isn't the initial screen creation.
initial=false;
}
//Create a screen
screen=SDL_CreateRGBSurface(SDL_HWSURFACE,SCREEN_WIDTH,SCREEN_HEIGHT,32,0x00FF0000,0x0000FF00,0x000000FF,0);
//Create a texture.
glDeleteTextures(1,&screenTexture);
glGenTextures(1,&screenTexture);
//And set up gl correctly.
glClearColor(0, 0, 0, 0);
glClearDepth(1.0f);
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glLoadIdentity();
#else
//NOTE: Hardware accelerated rendering requested but compiled without.
cerr<<"FATAL ERROR: Unable to use hardware acceleration (compiled without)."<<endl;
return false;
#endif
}else{
//Set the flags.
Uint32 flags=SDL_HWSURFACE | SDL_DOUBLEBUF;
if(settings->getBoolValue("fullscreen"))
flags|=SDL_FULLSCREEN;
else if(settings->getBoolValue("resizable"))
flags|=SDL_RESIZABLE;
//Check if there already was a screen.
if(screen)
initial=false;
//Create the screen and check if there weren't any errors.
screen=SDL_SetVideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,flags);
if(screen==NULL){
fprintf(stderr,"FATAL ERROR: SDL_SetVideoMode failed\n");
return false;
}
}
//Now configure the newly created window (if windowed).
if(settings->getBoolValue("fullscreen")==false)
configureWindow(initial);
//Create the temp surface, just a replica of the screen surface, free the previous one if any.
if(tempSurface)
SDL_FreeSurface(tempSurface);
tempSurface=SDL_CreateRGBSurface(SDL_HWSURFACE|SDL_SRCALPHA,
screen->w,screen->h,screen->format->BitsPerPixel,
screen->format->Rmask,screen->format->Gmask,screen->format->Bmask,0);
//Set the the window caption.
SDL_WM_SetCaption(("Me and My Shadow "+version).c_str(),NULL);
SDL_EnableUNICODE(1);
//Nothing went wrong so return true.
return true;
}
#ifdef WIN32
static WNDPROC m_OldWindowProc=NULL;
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
if(msg==WM_GETMINMAXINFO){
if(m_OldWindowProc){
CallWindowProc(m_OldWindowProc,hwnd,msg,wParam,lParam);
}else{
DefWindowProc(hwnd,msg,wParam,lParam);
}
RECT r={0,0,800,600};
AdjustWindowRect(&r,GetWindowLong(hwnd,GWL_STYLE),FALSE);
MINMAXINFO *info=(MINMAXINFO*)lParam;
info->ptMinTrackSize.x=r.right-r.left;
info->ptMinTrackSize.y=r.bottom-r.top;
return 0;
}else{
if(m_OldWindowProc){
return CallWindowProc(m_OldWindowProc,hwnd,msg,wParam,lParam);
}else{
return DefWindowProc(hwnd,msg,wParam,lParam);
}
}
}
#endif
void pickFullscreenResolution(){
//Vector that will hold the resolutions to choose from.
vector<_res> resolutionList;
//Enumerate avaliable resolutions using SDL_ListModes()
//Note: we enumerate fullscreen resolutions because
// windowed resolutions always can be arbitrary
if(resolutionList.empty()){
SDL_Rect **modes=SDL_ListModes(NULL,SDL_FULLSCREEN|SDL_HWSURFACE);
if(modes==NULL || ((intptr_t)modes) == -1){
cout<<"Error: Can't enumerate avaliable screen resolutions."
" Use predefined screen resolutions list instead."<<endl;
static const _res predefinedResolutionList[] = {
{800,600},
{1024,600},
{1024,768},
{1152,864},
{1280,720},
{1280,768},
{1280,800},
{1280,960},
{1280,1024},
{1360,768},
{1366,768},
{1440,900},
{1600,900},
{1600,1200},
{1680,1080},
{1920,1080},
{1920,1200},
{2560,1440},
{3840,2160}
};
//Fill the resolutionList.
for(unsigned int i=0;i<sizeof(predefinedResolutionList)/sizeof(_res);i++){
resolutionList.push_back(predefinedResolutionList[i]);
}
}else{
//Fill the resolutionList.
for(unsigned int i=0;modes[i]!=NULL;i++){
//Check if the resolution is higher than the minimum (800x600).
if(modes[i]->w>=800 && modes[i]->h>=600){
_res res={modes[i]->w, modes[i]->h};
resolutionList.push_back(res);
}
}
//Reverse it so that we begin with the lowest resolution.
reverse(resolutionList.begin(),resolutionList.end());
}
}
//The resolution that will hold the final result, we start with the minimum (800x600).
_res closestMatch={800,600};
int width=atoi(getSettings()->getValue("width").c_str());
//int height=atoi(getSettings()->getValue("height").c_str());
//Now loop through the resolutionList.
for(int i=0;i<(int)resolutionList.size();i++){
//The delta between the closestMatch and the resolution from the list.
int dM=(closestMatch.w-resolutionList[i].w);
//The delta between the target width and the resolution from the list.
int dT=(width-resolutionList[i].w);
//Since the resolutions are getting higher the lower (more negative) the further away it is.
//That's why we check if the deltaMatch is lower than the the deltaTarget.
if((dM)<(dT)){
closestMatch.w=resolutionList[i].w;
closestMatch.h=resolutionList[i].h;
}
}
//Now set the resolution to the closest match.
char s[64];
sprintf(s,"%d",closestMatch.w);
getSettings()->setValue("width",s);
sprintf(s,"%d",closestMatch.h);
getSettings()->setValue("height",s);
}
void configureWindow(bool initial){
//We only need to configure the window if it's resizable.
if(!getSettings()->getBoolValue("resizable"))
return;
//Retrieve the WM info from SDL containing the window handle.
struct SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWMInfo(&wmInfo);
#ifdef __linux__
//We assume that a linux system running meandmyshadow is also running an Xorg server.
if(wmInfo.subsystem==SDL_SYSWM_X11){
//Create the size hints to give to the window.
XSizeHints* sizeHints;
if(!(sizeHints=XAllocSizeHints())){
cerr<<"ERROR: Unable to allocate memory for XSizeHings."<<endl;
return;
}
//Configure the size hint.
sizeHints->flags=PMinSize;
sizeHints->min_width=800;
sizeHints->min_height=600;
//Set the normal hints of the window.
(void)wmInfo.info.x11.lock_func;
XSetNormalHints(wmInfo.info.x11.display,wmInfo.info.x11.wmwindow,sizeHints);
(void)wmInfo.info.x11.unlock_func;
//Free size hint structure
XFree(sizeHints);
}else{
//No X11 so an unsupported window manager.
cerr<<"WARNING: Unsupported window manager."<<endl;
}
#elif defined(WIN32)
//We overwrite the window proc of SDL
WNDPROC wndproc=(WNDPROC)GetWindowLong(wmInfo.window,GWL_WNDPROC);
if(wndproc!=NULL && wndproc!=(WNDPROC)WindowProc){
m_OldWindowProc=wndproc;
SetWindowLong(wmInfo.window,GWL_WNDPROC,(LONG)(WNDPROC)WindowProc);
}
#endif
}
void onVideoResize(){
//Check if the resize event isn't malformed.
if(event.resize.w<=0 || event.resize.h<=0)
return;
//Check the size limit.
if(event.resize.w<800)
event.resize.w=800;
if(event.resize.h<600)
event.resize.h=600;
//Check if it really resizes.
if(SCREEN_WIDTH==event.resize.w && SCREEN_HEIGHT==event.resize.h)
return;
char s[32];
//Set the new width and height.
sprintf(s,"%d",event.resize.w);
getSettings()->setValue("width",s);
sprintf(s,"%d",event.resize.h);
getSettings()->setValue("height",s);
//Do resizing.
if(!createScreen())
return;
//Tell the theme to resize.
if(!loadTheme(""))
return;
//The new resolution is valid.
//Now we can save the settings. (TODO: should we save?)
//saveSettings();
//And let the currentState update it's GUI to the new resolution.
currentState->resize();
}
bool init(){
//Initialze SDL.
if(SDL_Init(SDL_INIT_EVERYTHING)==-1) {
fprintf(stderr,"FATAL ERROR: SDL_Init failed\n");
return false;
}
//Initialze SDL_mixer (audio).
if(Mix_OpenAudio(22050,MIX_DEFAULT_FORMAT,2,512)==-1){
fprintf(stderr,"FATAL ERROR: Mix_OpenAudio failed\n");
return false;
}
//Set the volume.
Mix_Volume(-1,atoi(settings->getValue("sound").c_str()));
//Initialze SDL_ttf (fonts).
if(TTF_Init()==-1){
fprintf(stderr,"FATAL ERROR: TTF_Init failed\n");
return false;
}
//Create the screen.
if(!createScreen())
return false;
//Load key config. Then initalize joystick support.
inputMgr.loadConfig();
inputMgr.openAllJoysitcks();
//Init tinygettext for translations for the right language
dictionaryManager = new tinygettext::DictionaryManager();
dictionaryManager->add_directory(getDataPath()+"locale");
dictionaryManager->set_charset("UTF-8");
//Check if user have defined own language. If not, find it out for the player using findlocale
string lang=getSettings()->getValue("lang");
if(lang.length()>0){
printf("Locale set by user to %s\n",lang.c_str());
language=lang;
}else{
FL_Locale *locale;
FL_FindLocale(&locale,FL_MESSAGES);
printf("Locale isn't set by user: %s\n",locale->lang);
language=locale->lang;
if(locale->country!=NULL){
language+=string("_")+string(locale->country);
}
if(locale->variant!=NULL){
language+=string("@")+string(locale->variant);
}
FL_FreeLocale(&locale);
}
//Now set the language in the dictionaryManager.
dictionaryManager->set_language(tinygettext::Language::from_name(language));
//Disable annoying 'Couldn't translate: blah blah blah'
tinygettext::Log::set_log_info_callback(NULL);
//Create the types of blocks.
for(int i=0;i<TYPE_MAX;i++){
Game::blockNameMap[Game::blockName[i]]=i;
}
//Nothing went wrong so we return true.
return true;
}
static TTF_Font* loadFont(const char* name,int size){
TTF_Font* tmpFont=TTF_OpenFont((getDataPath()+"font/"+name+".ttf").c_str(),size);
if(tmpFont){
return tmpFont;
}else{
return TTF_OpenFont((getDataPath()+"font/DroidSansFallback.ttf").c_str(),size);
}
}
bool loadFonts(){
//Load the fonts.
//NOTE: This is a separate method because it will be called separately when re-initing in case of language change.
//First close the fonts if needed.
if(fontTitle)
TTF_CloseFont(fontTitle);
if(fontGUI)
TTF_CloseFont(fontGUI);
if(fontGUISmall)
TTF_CloseFont(fontGUISmall);
if(fontText)
TTF_CloseFont(fontText);
/// TRANSLATORS: Font used in GUI:
/// - Use "knewave" for languages using Latin and Latin-derived alphabets
/// - "DroidSansFallback" can be used for non-Latin writing systems
fontTitle=loadFont(_("knewave"),55);
fontGUI=loadFont(_("knewave"),32);
fontGUISmall=loadFont(_("knewave"),24);
/// TRANSLATORS: Font used for normal text:
/// - Use "Blokletters-Viltstift" for languages using Latin and Latin-derived alphabets
/// - "DroidSansFallback" can be used for non-Latin writing systems
fontText=loadFont(_("Blokletters-Viltstift"),16);
if(fontTitle==NULL || fontGUI==NULL || fontGUISmall==NULL || fontText==NULL){
printf("ERROR: Unable to load fonts! \n");
return false;
}
//Nothing went wrong so return true.
return true;
}
//Generate small arrows used for some GUI widgets.
static void generateArrows(){
TTF_Font* fontArrow=loadFont(_("knewave"),18);
if(arrowLeft1){
SDL_FreeSurface(arrowLeft1);
SDL_FreeSurface(arrowRight1);
SDL_FreeSurface(arrowLeft2);
SDL_FreeSurface(arrowRight2);
}
arrowLeft1=TTF_RenderUTF8_Blended(fontArrow,"<",themeTextColor);
arrowRight1=TTF_RenderUTF8_Blended(fontArrow,">",themeTextColor);
arrowLeft2=TTF_RenderUTF8_Blended(fontArrow,"<",themeTextColorDialog);
arrowRight2=TTF_RenderUTF8_Blended(fontArrow,">",themeTextColorDialog);
TTF_CloseFont(fontArrow);
}
bool loadTheme(string name){
//Load default fallback theme if it isn't loaded yet
if(objThemes.themeCount()==0){
if(objThemes.appendThemeFromFile(getDataPath()+"themes/Cloudscape/theme.mnmstheme")==NULL){
printf("ERROR: Can't load default theme file\n");
return false;
}
}
//Resize background or load specific theme
if(name==""||name.empty()){
objThemes.scaleToScreen();
}else{
string theme=processFileName(name);
if(objThemes.appendThemeFromFile(theme+"/theme.mnmstheme")==NULL){
printf("ERROR: Can't load theme %s\n",theme.c_str());
return false;
}
}
generateArrows();
//Everything went fine so return true.
return true;
}
static Mix_Chunk* loadWAV(const char* s){
Mix_Chunk* c=Mix_LoadWAV(s);
if(c!=NULL) return c;
printf("ERROR: Can't load sound file %s: %s\n",s,SDL_GetError());
return NULL;
}
bool loadFiles(){
//Load the fonts.
if(!loadFonts())
return false;
//Show a loading screen
{
SDL_Rect r={0,0,screen->w,screen->h};
SDL_FillRect(screen,&r,0);
SDL_Color fg={255,255,255};
SDL_Surface *surface=TTF_RenderUTF8_Blended(fontTitle,_("Loading..."),fg);
if(surface!=NULL){
r.x=(screen->w-surface->w)/2;
r.y=(screen->h-surface->h)/2;
SDL_BlitSurface(surface,NULL,screen,&r);
SDL_FreeSurface(surface);
}
SDL_Flip(screen);
}
musicManager.destroy();
//Load the music and play it.
if(musicManager.loadMusic((getDataPath()+"music/menu.music")).empty()){
printf("WARNING: Unable to load background music! \n");
}
musicManager.playMusic("menu",false);
//Always load the default music list for fallback.
musicManager.loadMusicList((getDataPath()+"music/default.list"));
//Load the configured music list.
getMusicManager()->loadMusicList((getDataPath()+"music/"+getSettings()->getValue("musiclist")+".list"));
getMusicManager()->setMusicList(getSettings()->getValue("musiclist"));
//Check if music is enabled.
if(getSettings()->getBoolValue("music"))
getMusicManager()->setEnabled();
//Load the sound effects
jumpSound=loadWAV((getDataPath()+"sfx/jump.wav").c_str());
hitSound=loadWAV((getDataPath()+"sfx/hit.wav").c_str());
saveSound=loadWAV((getDataPath()+"sfx/checkpoint.wav").c_str());
swapSound=loadWAV((getDataPath()+"sfx/swap.wav").c_str());
toggleSound=loadWAV((getDataPath()+"sfx/toggle.wav").c_str());
errorSound=loadWAV((getDataPath()+"sfx/error.wav").c_str());
collectSound=loadWAV((getDataPath()+"sfx/collect.wav").c_str());
achievementSound=loadWAV((getDataPath()+"sfx/achievement.ogg").c_str());
levelPackManager.destroy();
//Now sum up all the levelpacks.
vector<string> v=enumAllDirs(getDataPath()+"levelpacks/");
for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
levelPackManager.loadLevelPack(getDataPath()+"levelpacks/"+*i);
}
v=enumAllDirs(getUserPath(USER_DATA)+"levelpacks/");
for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
levelPackManager.loadLevelPack(getUserPath(USER_DATA)+"levelpacks/"+*i);
}
v=enumAllDirs(getUserPath(USER_DATA)+"custom/levelpacks/");
for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
levelPackManager.loadLevelPack(getUserPath(USER_DATA)+"custom/levelpacks/"+*i);
}
//Now we add a special levelpack that will contain the levels not in a levelpack.
LevelPack* levelsPack=new LevelPack;
levelsPack->levelpackName="Levels";
LevelPack* customLevelsPack=new LevelPack;
customLevelsPack->levelpackName="Custom Levels";
//List the addon levels and add them one for one.
v=enumAllFiles(getUserPath(USER_DATA)+"levels/");
for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
levelsPack->addLevel(getUserPath(USER_DATA)+"levels/"+*i);
levelsPack->setLocked(levelsPack->getLevelCount()-1);
}
//List the custom levels and add them one for one.
v=enumAllFiles(getUserPath(USER_DATA)+"custom/levels/");
for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
levelsPack->addLevel(getUserPath(USER_DATA)+"custom/levels/"+*i);
levelsPack->setLocked(levelsPack->getLevelCount()-1);
customLevelsPack->addLevel(getUserPath(USER_DATA)+"custom/levels/"+*i);
customLevelsPack->setLocked(customLevelsPack->getLevelCount()-1);
}
//Add them to the manager.
levelPackManager.addLevelPack(levelsPack);
levelPackManager.addLevelPack(customLevelsPack);
//Load statistics
statsMgr.loadPicture();
statsMgr.registerAchievements();
statsMgr.loadFile(getUserPath(USER_CONFIG)+"statistics");
//Do something ugly and slow
statsMgr.reloadCompletedLevelsAndAchievements();
statsMgr.reloadOtherAchievements();
//Load the theme, both menu and default.
if(!loadTheme(getSettings()->getValue("theme")))
return false;
//Nothing failed so return true.
return true;
}
bool loadSettings(){
settings=new Settings(getUserPath(USER_CONFIG)+"meandmyshadow.cfg");
settings->parseFile();
//Now apply settings changed through command line arguments, if any.
map<string,string>::iterator it;
for(it=tmpSettings.begin();it!=tmpSettings.end();++it){
settings->setValue(it->first,it->second);
}
tmpSettings.clear();
//Always return true?
return true;
}
bool saveSettings(){
settings->save();
//Always return true?
return true;
}
Settings* getSettings(){
return settings;
}
MusicManager* getMusicManager(){
return &musicManager;
}
LevelPackManager* getLevelPackManager(){
return &levelPackManager;
}
void flipScreen(){
if(settings->getBoolValue("gl")){
#ifdef HARDWARE_ACCELERATION
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//Create a texture from the screen surface.
glBindTexture(GL_TEXTURE_2D,screenTexture);
//Set the texture's stretching properties
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D,0,screen->format->BytesPerPixel,screen->w,screen->h,0,GL_BGRA,GL_UNSIGNED_BYTE,screen->pixels);
glBegin(GL_QUADS);
glTexCoord2i(0,0); glVertex3f(0,0,0);
glTexCoord2i(1,0); glVertex3f(SCREEN_WIDTH,0,0);
glTexCoord2i(1,1); glVertex3f(SCREEN_WIDTH,SCREEN_HEIGHT,0);
glTexCoord2i(0,1); glVertex3f(0,SCREEN_HEIGHT,0);
glEnd();
SDL_GL_SwapBuffers();
#else
//NOTE: Trying to flip the screen using gl while compiled without.
cerr<<"FATAL ERROR: Unable to draw to screen using OpenGL (compiled without)."<<endl;
#endif
}else{
SDL_Flip(screen);
}
}
void clean(){
//Save statistics
statsMgr.saveFile(getUserPath(USER_CONFIG)+"statistics");
//We delete the settings.
if(settings){
delete settings;
settings=NULL;
}
//Get rid of the currentstate.
//NOTE: The state is probably already deleted by the changeState function.
if(currentState)
delete currentState;
//Destroy the GUI if present.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
//Destroy the imageManager.
imageManager.destroy();
//Destroy the musicManager.
musicManager.destroy();
//Destroy all sounds
Mix_FreeChunk(jumpSound);
Mix_FreeChunk(hitSound);
Mix_FreeChunk(saveSound);
Mix_FreeChunk(swapSound);
Mix_FreeChunk(toggleSound);
Mix_FreeChunk(errorSound);
Mix_FreeChunk(collectSound);
Mix_FreeChunk(achievementSound);
//Destroy the levelPackManager.
levelPackManager.destroy();
levels=NULL;
//Close all joysticks.
inputMgr.closeAllJoysticks();
//Close the fonts and quit SDL_ttf.
TTF_CloseFont(fontTitle);
TTF_CloseFont(fontGUI);
TTF_CloseFont(fontGUISmall);
TTF_CloseFont(fontText);
TTF_Quit();
//Remove the temp surface.
SDL_FreeSurface(tempSurface);
//Stop audio.and quit
Mix_CloseAudio();
+#ifndef __APPLE__
Mix_Quit();
-
+#endif
//And finally quit SDL.
SDL_Quit();
}
void setNextState(int newstate){
//Only change the state when we aren't already exiting.
if(nextState!=STATE_EXIT){
nextState=newstate;
}
}
void changeState(){
//Check if there's a nextState.
if(nextState!=STATE_NULL){
//Delete the currentState.
delete currentState;
currentState=NULL;
//Set the currentState to the nextState.
stateID=nextState;
nextState=STATE_NULL;
//Init the state.
switch(stateID){
case STATE_GAME:
currentState=new Game();
break;
case STATE_MENU:
currentState=new Menu();
break;
case STATE_LEVEL_SELECT:
currentState=new LevelPlaySelect();
break;
case STATE_LEVEL_EDIT_SELECT:
currentState=new LevelEditSelect();
break;
case STATE_LEVEL_EDITOR:
currentState=new LevelEditor();
break;
case STATE_OPTIONS:
currentState=new Options();
break;
case STATE_ADDONS:
currentState=new Addons();
break;
case STATE_CREDITS:
currentState=new Credits();
break;
case STATE_STATISTICS:
currentState=new StatisticsScreen();
break;
}
//NOTE: STATE_EXIT isn't mentioned, meaning that currentState is null.
//This way the game loop will break and the program will exit.
//Fade out.
int fade=255;
SDL_BlitSurface(screen,NULL,tempSurface,NULL);
while(fade>0){
fade-=17;
if(fade<0)
fade=0;
SDL_FillRect(screen,NULL,0);
SDL_SetAlpha(tempSurface, SDL_SRCALPHA, fade);
SDL_BlitSurface(tempSurface,NULL,screen,NULL);
flipScreen();
SDL_Delay(25);
}
}
}
void musicStoppedHook(){
//We just call the musicStopped method of the MusicManager.
musicManager.musicStopped();
}
bool checkCollision(const SDL_Rect& a,const SDL_Rect& b){
//Check if the left side of box a isn't past the right side of b.
if(a.x>=b.x+b.w){
return false;
}
//Check if the right side of box a isn't left of the left side of b.
if(a.x+a.w<=b.x){
return false;
}
//Check if the top side of box a isn't under the bottom side of b.
if(a.y>=b.y+b.h){
return false;
}
//Check if the bottom side of box a isn't above the top side of b.
if(a.y+a.h<=b.y){
return false;
}
//We have collision.
return true;
}
void setCamera(const SDL_Rect* r,int count){
//SetCamera only works in the Level editor and mouse is inside window.
if(stateID==STATE_LEVEL_EDITOR&&(SDL_GetAppState()&SDL_APPMOUSEFOCUS)){
//Get the mouse coordinates.
int x,y;
SDL_GetMouseState(&x,&y);
//Make sure we avoid the toolbar.
SDL_Rect mouse={x,y,0,0};
//SDL_Rect toolbar={(SCREEN_WIDTH-460)/2,SCREEN_HEIGHT-50,460,50};
for(int i=0;i<count;i++){
if(checkCollision(mouse,r[i]))
return;
}
//Check if the mouse is near the left edge of the screen.
//Else check if the mouse is near the right edge.
if(x<50){
//We're near the left edge so move the camera.
camera.x-=5;
}else if(x>SCREEN_WIDTH-50){
//We're near the right edge so move the camera.
camera.x+=5;
}
//Check if the mouse is near the top edge of the screen.
//Else check if the mouse is near the bottom edge.
if(y<50){
//We're near the top edge so move the camera.
camera.y-=5;
}else if(y>SCREEN_HEIGHT-50){
//We're near the bottom edge so move the camera.
camera.y+=5;
}
}
}
int parseArguments(int argc, char** argv){
//Loop through all arguments.
//We start at one since 0 is the command itself.
for(int i=1;i<argc;i++){
string argument=argv[i];
//Check if the argument is the data-dir.
if(argument=="--data-dir"){
//We need a second argument so we increase i.
i++;
if(i>=argc){
printf("ERROR: Missing argument for command '%s'\n\n",argument.c_str());
return -1;
}
//Configure the dataPath with the given path.
dataPath=argv[i];
if(!getDataPath().empty()){
char c=dataPath[dataPath.size()-1];
if(c!='/'&&c!='\\') dataPath+="/";
}
}else if(argument=="--user-dir"){
//We need a second argument so we increase i.
i++;
if(i>=argc){
printf("ERROR: Missing argument for command '%s'\n\n",argument.c_str());
return -1;
}
//Configure the userPath with the given path.
userPath=argv[i];
if(!userPath.empty()){
char c=userPath[userPath.size()-1];
if(c!='/'&&c!='\\') userPath+="/";
}
}else if(argument=="-f" || argument=="-fullscreen" || argument=="--fullscreen"){
tmpSettings["fullscreen"]="1";
}else if(argument=="-w" || argument=="-windowed" || argument=="--windowed"){
tmpSettings["fullscreen"]="0";
}else if(argument=="-mv" || argument=="-music" || argument=="--music"){
//We need a second argument so we increase i.
i++;
if(i>=argc){
printf("ERROR: Missing argument for command '%s'\n\n",argument.c_str());
return -1;
}
//Now set the music volume.
tmpSettings["music"]=argv[i];
}else if(argument=="-sv" || argument=="-sound" || argument=="--sound"){
//We need a second argument so we increase i.
i++;
if(i>=argc){
printf("ERROR: Missing argument for command '%s'\n\n",argument.c_str());
return -1;
}
//Now set sound volume.
tmpSettings["sound"]=argv[i];
}else if(argument=="-set" || argument=="--set"){
//We need a second and a third argument so we increase i.
i+=2;
if(i>=argc){
printf("ERROR: Missing argument for command '%s'\n\n",argument.c_str());
return -1;
}
//And set the setting.
tmpSettings[argv[i-1]]=argv[i];
}else if(argument=="-v" || argument=="-version" || argument=="--version"){
//Print the version.
printf("%s\n",version.c_str());
return 0;
}else if(argument=="-h" || argument=="-help" || argument=="--help"){
//If the help is requested we'll return false without printing an error.
//This way the usage/help text will be printed.
return -1;
}else{
//Any other argument is unknow so we return false.
printf("ERROR: Unknown argument %s\n\n",argument.c_str());
return -1;
}
}
//If everything went well we can return true.
return 1;
}
//Special structure that will recieve the GUIEventCallbacks of the messagebox.
struct msgBoxHandler:public GUIEventCallback{
public:
//Integer containing the ret(urn) value of the messageBox.
int ret;
public:
//Constructor.
msgBoxHandler():ret(0){}
void GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType){
//Make sure it's a click event.
if(eventType==GUIEventClick){
//Set the return value.
ret=obj->value;
//After a click event we can delete the GUI.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}
}
};
msgBoxResult msgBox(string prompt,msgBoxButtons buttons,const string& title){
//Create the event handler.
msgBoxHandler objHandler;
//The GUI objects.
GUIObject* obj;
//Create the GUIObjectRoot, the height and y location is temp.
//It depends on the content what it will be.
GUIObject* root=new GUIObject((SCREEN_WIDTH-600)/2,200,600,200,GUIObjectFrame,title.c_str());
//Integer containing the current y location used to grow dynamic depending on the content.
int y=50;
//Now process the prompt.
{
//Pointer to the string.
char* lps=(char*)prompt.c_str();
//Pointer to a character.
char* lp=NULL;
//We keep looping forever.
//The only way out is with the break statement.
for(;;){
//As long as it's still the same sentence we continue.
//It will stop when there's a newline or end of line.
for(lp=lps;*lp!='\n'&&*lp!='\r'&&*lp!=0;lp++);
//Store the character we stopped on. (End or newline)
char c=*lp;
//Set the character in the string to 0, making lps a string containing one sentence.
*lp=0;
//Add a GUIObjectLabel with the sentence.
root->addChild(new GUIObject(0,y,root->width,25,GUIObjectLabel,lps,0,true,true,GUIGravityCenter));
//Increase y with 25, about the height of the text.
y+=25;
//Check the stored character if it was a stop.
if(c==0){
//It was so break out of the for loop.
lps=lp;
break;
}
//It wasn't meaning more will follow.
//We set lps to point after the "newline" forming a new string.
lps=lp+1;
}
}
//Add 70 to y to leave some space between the content and the buttons.
y+=70;
//Recalc the size of the message box.
root->top=(SCREEN_HEIGHT-y)/2;
root->height=y;
//Now we need to add the buttons.
//Integer containing the number of buttons to add.
int count=0;
//Array with the return codes for the buttons.
int value[3]={0};
//Array containing the captation for the buttons.
string button[3]={"","",""};
switch(buttons){
case MsgBoxOKCancel:
count=2;
button[0]=_("OK");value[0]=MsgBoxOK;
button[1]=_("Cancel");value[1]=MsgBoxCancel;
break;
case MsgBoxAbortRetryIgnore:
count=3;
button[0]=_("Abort");value[0]=MsgBoxAbort;
button[1]=_("Retry");value[1]=MsgBoxRetry;
button[2]=_("Ignore");value[2]=MsgBoxIgnore;
break;
case MsgBoxYesNoCancel:
count=3;
button[0]=_("Yes");value[0]=MsgBoxYes;
button[1]=_("No");value[1]=MsgBoxNo;
button[2]=_("Cancel");value[2]=MsgBoxCancel;
break;
case MsgBoxYesNo:
count=2;
button[0]=_("Yes");value[0]=MsgBoxYes;
button[1]=_("No");value[1]=MsgBoxNo;
break;
case MsgBoxRetryCancel:
count=2;
button[0]=_("Retry");value[0]=MsgBoxRetry;
button[1]=_("Cancel");value[1]=MsgBoxCancel;
break;
default:
count=1;
button[0]=_("OK");value[0]=MsgBoxOK;
break;
}
//Now we start making the buttons.
{
//Reduce y so that the buttons fit inside the frame.
y-=40;
double places[3]={0.0};
if(count==1){
places[0]=0.5;
}else if(count==2){
places[0]=0.4;
places[1]=0.6;
}else if(count==3){
places[0]=0.3;
places[1]=0.5;
places[2]=0.7;
}
//Loop to add the buttons.
for(int i=0;i<count;i++){
obj=new GUIObject(root->width*places[i],y,-1,36,GUIObjectButton,button[i].c_str(),value[i],true,true,GUIGravityCenter);
obj->eventCallback=&objHandler;
root->addChild(obj);
}
}
//Now we dim the screen and keep the GUI rendering/updating.
GUIOverlay* overlay=new GUIOverlay(root);
overlay->enterLoop(true);
//And return the result.
return (msgBoxResult)objHandler.ret;
}
struct fileDialogHandler:public GUIEventCallback{
public:
//The ret(urn) value, true=ok and false=cancel
bool ret;
//Boolean if it's a save dialog.
bool isSave;
//Boolean if the file should be verified.
bool verifyFile;
//Boolean if files should be listed instead of directories.
bool files;
//Pointer to the textfield containing the filename.
GUIObject* txtName;
//Pointer to the listbox containing the different files.
GUIListBox* lstFile;
//The extension the files listed should have.
const char* extension;
//The current filename.
string fileName;
//The current search path.
string path;
//Vector containing the search paths.
vector<string> searchPath;
public:
//Constructor.
fileDialogHandler(bool isSave=false,bool verifyFile=false, bool files=true):ret(false),
isSave(isSave),verifyFile(verifyFile),
files(files),txtName(NULL),lstFile(NULL),extension(NULL){}
void GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType){
//Check for the ok event.
if(name=="cmdOK"){
//Get the entered fileName from the text field.
std::string s=txtName->caption;
//If it doesn't contain a slash we need to add the path to the fileName.
if(s.find_first_of("/")==string::npos)
s=path+s;
//If the string empty we return.
if(s.empty() || s.find_first_of("*?")!=string::npos)
return;
//We only need to check for extensions if it isn't a folder dialog.
if(files){
//If there isn't right extension add it.
size_t found=s.find_first_of(".");
if(found!=string::npos)
s.replace(s.begin()+found+1,s.end(),extension);
else if (s.substr(found+1)!=extension)
s.append(string(".")+extension);
}
//Check if we should save or load the file.
//
if(isSave){
//Open the file with read permission to check if it already exists.
FILE* f;
f=fopen(processFileName(s).c_str(),"rb");
//Check if it exists.
if(f){
//Close the file.
fclose(f);
//Let the currentState render once to prevent multiple GUI overlapping and prevent the screen from going black.
currentState->render();
//Prompt the user with a Yes or No question.
/// TRANSLATORS: Filename is coming before this text
if(msgBox(tfm::format(_("%s already exists.\nDo you want to overwrite it?"),s),MsgBoxYesNo,_("Overwrite Prompt"))!=MsgBoxYes){
//He answered no, so we return.
return;
}
}
//Check if we should verify the file.
//Verifying only applies to files not to directories.
if(verifyFile && files){
//Open the file with write permission.
f=fopen(processFileName(s).c_str(),"wb");
//Check if their aren't problems.
if(f){
//Close the file.
fclose(f);
}else{
//Let the currentState render once to prevent multiple GUI overlapping and prevent the screen from going black.
currentState->render();
//The file can't be opened so tell the user.
msgBox(tfm::format(_("Can't open file %s."),s),MsgBoxOKOnly,_("Error"));
return;
}
}
}else if(verifyFile && files){
//We need to verify a file for opening.
FILE *f;
f=fopen(processFileName(s).c_str(),"rb");
//Check if it didn't fail.
if(f){
//Succes, so close the file.
fclose(f);
}else{
//Let the currentState render once to prevent multiple GUI overlapping and prevent the screen from going black.
currentState->render();
//Unable to open file so tell the user.
msgBox(tfm::format(_("Can't open file %s."),s),MsgBoxOKOnly,_("Error"));
return;
}
}
//If we haven't returned then it's fine.
//Set the fileName to the chosen file.
fileName=s;
//Delete the GUI.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
//Set return to true.
ret=true;
}else if(name=="cmdCancel"){
//Cancel means we can kill the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}else if(name=="lstFile"){
//Get a pointer to the listbox.
GUIListBox* obj1=lstFile;
//Make sure the option exist and change textfield to it.
if(obj1!=NULL && txtName!=NULL && obj1->value>=0 && obj1->value<(int)obj1->item.size()){
txtName->caption=obj1->item[obj1->value];
}
}else if(name=="lstSearchIn"){
//Get the searchpath listbox.
GUISingleLineListBox *obj1=dynamic_cast<GUISingleLineListBox*>(obj);
//Check if the entry exists.
if(obj1!=NULL && lstFile!=NULL && obj1->value>=0 && obj1->value<(int)searchPath.size()){
//Temp string.
string s;
//Get the new search path.
path=searchPath[obj1->value];
//Make sure it isn't empty.
if(!path.empty()){
//Process the filename.
s=processFileName(path);
}else{
//It's empty so we give the userpath.
s=getUserPath();
}
//Fill the list with files or directories.
if(files) {
lstFile->item=enumAllFiles(s,extension);
}else
lstFile->item=enumAllDirs(s);
//Remove any selection from the list.
lstFile->value=-1;
}
}
}
};
bool fileDialog(string& fileName,const char* title,const char* extension,const char* path,bool isSave,bool verifyFile,bool files){
//Pointer to GUIObject to make the GUI with.
GUIObject* obj;
//Create the fileDialogHandler, used for event handling.
fileDialogHandler objHandler(isSave,verifyFile,files);
//Vector containing the pathNames.
vector<string> pathNames;
//Set the extension of the objHandler.
objHandler.extension=extension;
//We now need to splits the given path into multiple path names.
if(path && path[0]){
//The string isn't empty.
//Pointer to the paths string.
char* lp=(char*)path;
//Pointer to the first newline.
char* lps=strchr(lp,'\n');
//Pointer used for checking if their's another newline.
//It will indicate if it's the last set or not.
char* lpe;
//Check for a newline.
if(lps){
//We have newline(s) so loop forever.
//We can only break out of the loop when the string ends.
for(;;){
//Add the first searchpath.
//This is the beginning of the string (lp) to the first newline. (lps)
objHandler.searchPath.push_back(string(lp,lps-lp));
//We should have another newline so search for it.
lpe=strchr(lps+1,'\n');
if(lpe){
//We found it so we add that to the pathname.
pathNames.push_back(string(lps+1,lpe-lps-1));
//And start over again by setting lp to the start of a new set of searchPath/pathName.
lp=lpe+1;
}else{
//There is no newline anymore, meaning the last entry, the rest of the string must be the pathName.
pathNames.push_back(string(lps+1));
//And break out of the loop.
break;
}
//We haven't broken out so search for a newline.
lps=strchr(lp,'\n');
//If there isn't a newline break.
if(!lps)
break;
}
}else{
//There is no newline thus the whole string is the searchPath.
objHandler.searchPath.push_back(path);
}
}else{
//Empty so put an empty string as searchPath.
objHandler.searchPath.push_back(string());
}
//It's time to create the GUI.
//If there are more than one pathNames we need to add a GUISingleLineListBox.
int base_y=pathNames.empty()?20:60;
//Create the frame.
GUIObject* root=new GUIObject(100,100-base_y/2,600,400+base_y,GUIObjectFrame,title?title:(isSave?_("Save File"):_("Load File")));
//Create the search path list box if needed.
if(!pathNames.empty()){
root->addChild(new GUIObject(8,40,184,36,GUIObjectLabel,_("Search In")));
GUISingleLineListBox* obj1=new GUISingleLineListBox(160,40,432,36);
obj1->item=pathNames;
obj1->value=0;
obj1->name="lstSearchIn";
obj1->eventCallback=&objHandler;
root->addChild(obj1);
}
//Add the FileName label and textfield.
root->addChild(new GUIObject(8,20+base_y,184,36,GUIObjectLabel,_("File Name")));
{
//Fill the textbox with the given fileName.
string s=fileName;
if(!isSave){
//But only if it isn't empty.
if(s.empty() && extension && extension[0])
s=string("*.")+string(extension);
}
//Create the textbox and add it to the GUI.
objHandler.txtName=new GUIObject(160,20+base_y,432,36,GUIObjectTextBox,s.c_str());
root->addChild(objHandler.txtName);
}
//Now we add the ListBox containing the files or directories.
{
GUIListBox* obj1=new GUIListBox(8,60+base_y,584,292);
//Get the searchPath.
string s=objHandler.searchPath[0];
//Make sure it isn't empty.
if(!s.empty()){
objHandler.path=s;
s=processFileName(s);
}else{
s=getUserPath();
}
//Check if we should list files or directories.
if(files){
//Fill the list with files.
obj1->item=enumAllFiles(s,extension);
}else{
//Fill the list with directories.
obj1->item=enumAllDirs(s);
}
obj1->name="lstFile";
obj1->eventCallback=&objHandler;
root->addChild(obj1);
objHandler.lstFile=obj1;
}
//Now create the OK and Cancel buttons.
obj=new GUIObject(200,360+base_y,192,36,GUIObjectButton,_("OK"));
obj->name="cmdOK";
obj->eventCallback=&objHandler;
root->addChild(obj);
obj=new GUIObject(400,360+base_y,192,36,GUIObjectButton,_("Cancel"));
obj->name="cmdCancel";
obj->eventCallback=&objHandler;
root->addChild(obj);
//Create the gui overlay.
GUIOverlay* overlay=new GUIOverlay(root);
overlay->enterLoop();
//Now determine what the return value is (and if there is one).
if(objHandler.ret)
fileName=objHandler.fileName;
return objHandler.ret;
}
diff --git a/src/Game.h b/src/Game.h
index bdd62a6..b8c4a6e 100644
--- a/src/Game.h
+++ b/src/Game.h
@@ -1,216 +1,221 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GAME_H
#define GAME_H
#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#include <SDL_ttf/SDL_ttf.h>
+#else
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
+#endif
#include <vector>
#include <map>
#include <string>
#include "GameState.h"
#include "GUIObject.h"
#include "GameObjects.h"
#include "Player.h"
#include "Shadow.h"
//This structure contains variables that make a GameObjectEvent.
struct typeGameObjectEvent{
//The type of event.
int eventType;
//The type of object that should react to the event.
int objectType;
//Flags, 0x1 means use the id.
int flags;
//Blocks with this id should react to the event.
std::string id;
};
class ThemeManager;
class ThemeBackground;
class TreeStorageNode;
class Game : public GameState,public GUIEventCallback{
private:
//Boolean if the game should reset.
bool isReset;
//contains currently played level.
TreeStorageNode* currentLevelNode;
protected:
//Array containing "tooltips" for certain block types.
//It will be shown in the topleft corner of the screen.
SDL_Surface* bmTips[TYPE_MAX];
//SDL_Surface containing the action images (record, play, etc..)
SDL_Surface* action;
//SDL_Surface containing the medal image.
SDL_Surface* medals;
//SDL_Surface containing the collectable image.
SDL_Surface* collectable;
//Vector containing all the levelObjects in the current game.
std::vector<GameObject*> levelObjects;
//The name of the current level.
std::string levelName;
//The path + file of the current level.
std::string levelFile;
//Editor data containing information like name, size, etc...
std::map<std::string,std::string> editorData;
//Vector used to queue the gameObjectEvents.
std::vector<typeGameObjectEvent> eventQueue;
//The themeManager.
ThemeManager* customTheme;
//The themeBackground.
ThemeBackground* background;
//Load a level from node.
//After calling this function the ownership of
//node will transfer to Game class. So don't delete
//the node after calling this function!
virtual void loadLevelFromNode(TreeStorageNode* obj, const std::string& fileName);
public:
//Array used to convert GameObject type->string.
static const char* blockName[TYPE_MAX];
//Map used to convert GameObject string->type.
static std::map<std::string,int> blockNameMap;
//Boolean that is set to true when a game is won.
bool won;
//Boolean that is set to true when we should save game on next logic update.
bool saveStateNextTime;
//Boolean that is set to true when we should load game on next logic update.
bool loadStateNextTime;
//Boolean if the replaying currently done is for the interlevel screen.
bool interlevel;
//X position of second medal in interlevel popup
int medalX;
//Integer containing the current tip index.
int gameTipIndex;
//Integer containing the number of ticks passed since the start of the level.
int time;
//Integer containing the stored value of time.
int timeSaved;
//Integer containing the number of recordings it took to finish.
int recordings;
//Integer containing the stored value of recordings.
int recordingsSaved;
//Integer keeping track of currently obtained collectables
int currentCollectables;
//Integer keeping track of total colletables in the level
int totalCollectables;
//Integer containing the stored value of current collectables
int currentCollectablesSaved;
//Boolean if the camera should follow the shadow or not.
bool shadowCam;
//The player...
Player player;
//... and his shadow.
Shadow shadow;
//warning: weak reference only, may point to invalid location
GameObject* objLastCheckPoint;
//Constructor.
//loadLevel: Boolean if the GameState should load the level.
Game(bool loadLevel=true);
//If this is not empty then when next Game class is created
//it will play this record file.
static std::string recordFile;
//Destructor.
//It will call destroy();
~Game();
//Method used to clean up the GameState.
void destroy();
//Inherited from GameState.
void handleEvents();
void logic();
void render();
void resize();
//This method will load a level.
//fileName: The fileName of the level.
virtual void loadLevel(std::string fileName);
//Method used to broadcast a GameObjectEvent.
//eventType: The type of event.
//objectType: The type of object that should react to the event.
//id: The id of the blocks that should react.
void broadcastObjectEvent(int eventType,int objectType=-1,const char* id=NULL);
//Returns if the player and shadow can save the current state.
bool canSaveState();
//Method used to store the current state.
//This is used for checkpoints.
//Returns: True if it succeeds without problems.
bool saveState();
//Method used to load the stored state.
//This is used for checkpoints.
//Returns: True if it succeeds without problems.
bool loadState();
//Method that will reset the GameState to it's initial state.
//save: Boolean if the saved state should also be delted.
void reset(bool save);
//Save current game record to the file.
//fileName: The filename of the destination file.
void saveRecord(const char* fileName);
//Load game record (and its level) from file and play it.
//fileName: The filename of the recording file.
void loadRecord(const char* fileName);
//Method called by the player (or shadow) when he finished.
void replayPlay();
//Method that gets called when the recording has ended.
void recordingEnded();
//get current level's auto-save record path,
//using current level's MD5, file name and other information.
void getCurrentLevelAutoSaveRecordPath(std::string &bestTimeFilePath,std::string &bestRecordingFilePath,bool createPath);
//Method that will prepare the gamestate for the next level and start it.
//If it's the last level it will show the congratulations text and return to the level select screen.
void gotoNextLevel();
//GUI event handling is done here.
void GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType);
};
#endif
diff --git a/src/Globals.cpp b/src/Globals.cpp
index 50b53b0..2d2dedd 100644
--- a/src/Globals.cpp
+++ b/src/Globals.cpp
@@ -1,97 +1,101 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Globals.h"
-#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#include <SDL_ttf/SDL_ttf.h>
+#else
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
+#endif
#include "libs/tinygettext/tinygettext.hpp"
//Set the defautl value for the screen width and height.
int SCREEN_WIDTH=800;
int SCREEN_HEIGHT=600;
//Set the default value for the level width and height.
int LEVEL_HEIGHT=0;
int LEVEL_WIDTH=0;
//The language that in which the game should be translated.
std::string language;
//The DictionaryManager that is used to translate the game itself.
tinygettext::DictionaryManager* dictionaryManager=NULL;
//Set both the screen and the tempSurface to NULL.
SDL_Surface* screen=NULL;
SDL_Surface* tempSurface=NULL;
//Font that is used for titles.
//Knewave large.
TTF_Font* fontTitle=NULL;
//Font that is used for captions of buttons and other GUI elements.
//Knewave small.
TTF_Font* fontGUI=NULL;
//Font that is used for long captions of buttons and other GUI elements.
//Knewave small.
TTF_Font* fontGUISmall=NULL;
//Font that is used for (long) text.
//Blokletter-Viltstift small.
TTF_Font* fontText=NULL;
//Small arrows used for GUI widgets.
//2 directions and 2 different/same colors depending on theme.
SDL_Surface* arrowLeft1=NULL;
SDL_Surface* arrowRight1=NULL;
SDL_Surface* arrowLeft2=NULL;
SDL_Surface* arrowRight2=NULL;
//Sound played when the player jumps.
Mix_Chunk* jumpSound=NULL;
//Sound played when the player dies.
Mix_Chunk* hitSound=NULL;
//Sound played when the saves a state.
Mix_Chunk* saveSound=NULL;
//Sound played when the player swaps.
Mix_Chunk* swapSound=NULL;
//Sound played when the player toggles a switch.
Mix_Chunk* toggleSound=NULL;
//The sound played when the player tries something that doesn't work.
//For example a broken portal or swapping the shadow into a shadow block.
Mix_Chunk* errorSound=NULL;
//Sound played when the player picks up a collectable.
Mix_Chunk* collectSound=NULL;
//Sound played when an achievement is achieved..
Mix_Chunk* achievementSound=NULL;
//Set the current stateID and the nextState.
int stateID=STATE_NULL;
int nextState=STATE_NULL;
//The name of the current level.
std::string levelName;
//Initialise the camera.
//Start location is 0, size is the same as the screen size.
SDL_Rect camera={0,0,SCREEN_WIDTH,SCREEN_HEIGHT};
//The SDL_Event object.
SDL_Event event;
//Themable colors
SDL_Color themeTextColor={0,0,0};
SDL_Color themeTextColorDialog={0,0,0};
diff --git a/src/Globals.h b/src/Globals.h
index a1a203b..30075f5 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -1,212 +1,216 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLOBALS_H
#define GLOBALS_H
-#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#include <SDL_ttf/SDL_ttf.h>
+#else
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
+#endif
#include <string>
#include "libs/tinygettext/tinygettext.hpp"
-#ifdef WIN32
+#if defined (WIN32) || defined (__APPLE__)
//#define DATA_PATH
#else
#include "config.h"
#endif
#define TITLE_FONT_RAISE 19
#define GUI_FONT_RAISE 5
//Global constants
//The width of the screen.
extern int SCREEN_WIDTH;
//The height of the screen.
extern int SCREEN_HEIGHT;
//The depth of the screen.
const int SCREEN_BPP=32;
//Strin containing the
const std::string version="V0.5 Development version";
//The height of the current level.
extern int LEVEL_HEIGHT;
//The width of the current level.
extern int LEVEL_WIDTH;
//The target frames per seconds.
const int g_FPS=40;
//The language that in which the game should be translated.
extern std::string language;
//The DictionaryManager that is used to translate the game itself.
extern tinygettext::DictionaryManager* dictionaryManager;
//The screen surface, it's used to draw on before it's drawn to the real screen.
extern SDL_Surface* screen;
//SDL_Surface with the same dimensions as screen which can be used for all kinds of (temp) drawing.
extern SDL_Surface* tempSurface;
//Font that is used for titles.
//Knewave large.
extern TTF_Font* fontTitle;
//Font that is used for captions of buttons and other GUI elements.
//Knewave small.
extern TTF_Font* fontGUI;
//Font that is used for long captions of buttons and other GUI elements.
//Knewave smaller.
extern TTF_Font* fontGUISmall;
//Font that is used for (long) text.
//Blokletter-Viltstift small.
extern TTF_Font* fontText;
//Small arrows used for GUI widgets.
//2 directions and 2 different/same colors depending on theme.
extern SDL_Surface* arrowLeft1;
extern SDL_Surface* arrowRight1;
extern SDL_Surface* arrowLeft2;
extern SDL_Surface* arrowRight2;
//Sound played when the player jumps.
extern Mix_Chunk* jumpSound;
//Sound played when the player dies.
extern Mix_Chunk* hitSound;
//Sound played when the saves a state.
extern Mix_Chunk* saveSound;
//Sound played when the player swaps.
extern Mix_Chunk* swapSound;
//Sound played when the player toggles a switch.
extern Mix_Chunk* toggleSound;
//The sound played when the player tries something that doesn't work.
//For example a broken portal or swapping the shadow into a shadow block.
extern Mix_Chunk* errorSound;
//Sound played when the player picks up a collectable.
extern Mix_Chunk* collectSound;
//Sound played when an achievement is achieved..
extern Mix_Chunk* achievementSound;
//Event, used for event handling.
extern SDL_Event event;
//GUI
class GUIObject;
extern GUIObject *GUIObjectRoot;
//The state id of the current state.
extern int stateID;
//Integer containing what the next state will be.
extern int nextState;
//String containing the name of the current level.
extern std::string levelName;
//SDL rectangle used to store the camera.
//x is the x location of the camera.
//y is the y location of the camera.
//w is the width of the camera. (equal to SCREEN_WIDTH)
//h is the height of the camera. (equal to SCREEN_HEIGHT)
extern SDL_Rect camera;
//Themable colors
extern SDL_Color themeTextColor;
extern SDL_Color themeTextColorDialog;
//Enumeration containing the ids of the game states.
enum GameStates
{
//State null is a special state used to indicate no state.
//This is used when no next state is defined.
STATE_NULL,
//This state is before the actual leveleditor used to make levelpacks.
STATE_LEVEL_EDIT_SELECT,
//This state is for the level editor.
STATE_LEVEL_EDITOR,
//This state is for the main menu.
STATE_MENU,
//This state is for the actual game.
STATE_GAME,
//Special state used when exiting meandmyshadow.
STATE_EXIT,
//This state is for the help screen.
STATE_LEVEL_SELECT,
//This state is for the options screen.
STATE_OPTIONS,
//This state is for the addon screen.
STATE_ADDONS,
//This state is for credits screen
STATE_CREDITS,
//This state is for statistics screen
STATE_STATISTICS,
};
//Enumeration containing the ids of the different block types.
enum GameTileType{
//The normal solid block.
TYPE_BLOCK=0,
//Block representing the start location of the player.
TYPE_START_PLAYER,
//Block representing the start location of the shadow.
TYPE_START_SHADOW,
//The exit of the level.
TYPE_EXIT,
//The shadow block which is only solid for the shadow.
TYPE_SHADOW_BLOCK,
//Block that can kill both the player and the shadow.
TYPE_SPIKES,
//Special point where the player can save.
TYPE_CHECKPOINT,
//Block that will switch the location of the player and the shadow when invoked.
TYPE_SWAP,
//Block that will crumble to dust when stepped on it for the third time.
TYPE_FRAGILE,
//Normal block that moves along a path.
TYPE_MOVING_BLOCK,
//Shadow block that moves along a path.
TYPE_MOVING_SHADOW_BLOCK,
//A spike block that moves along a path.
TYPE_MOVING_SPIKES,
//Special block which, once entered, moves the player/shadow to a different portal.
TYPE_PORTAL,
//A block with a button which can activate or stop moving blocks, converyor belts
TYPE_BUTTON,
//A switch which can activate or stop moving blocks, converyor belts
TYPE_SWITCH,
//Solid block which works like
TYPE_CONVEYOR_BELT,
TYPE_SHADOW_CONVEYOR_BELT,
//Block that contains a message that can be read.
TYPE_NOTIFICATION_BLOCK,
//A collectable that is able to open locked doors
TYPE_COLLECTABLE,
//The (max) number of tiles.
TYPE_MAX
};
#endif
diff --git a/src/ImageManager.h b/src/ImageManager.h
index a45e065..cb36c49 100644
--- a/src/ImageManager.h
+++ b/src/ImageManager.h
@@ -1,49 +1,53 @@
/*
* Copyright (C) 2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IMAGEMANAGER_H
#define IMAGEMANAGER_H
#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_image/SDL_image.h>
+#else
#include <SDL/SDL_image.h>
+#endif
#include <string>
#include <map>
//Class for loading images.
class ImageManager{
public:
//Constructor.
ImageManager(){}
//Destructor.
~ImageManager();
//Loads an image.
//file: The image file to load.
//Returns: The SDL_Surface containing the image.
SDL_Surface* loadImage(std::string file);
//Destroys the images
void destroy();
private:
//Map containing the images.
//The key is the name of the image and the value is a pointer to the SDL_Surface.
std::map<std::string,SDL_Surface*> imageCollection;
};
#endif
diff --git a/src/LevelEditSelect.cpp b/src/LevelEditSelect.cpp
index 88d2a4f..72ba675 100644
--- a/src/LevelEditSelect.cpp
+++ b/src/LevelEditSelect.cpp
@@ -1,734 +1,736 @@
/*
* Copyright (C) 2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "LevelEditSelect.h"
#include "GameState.h"
#include "Functions.h"
#include "FileManager.h"
#include "Globals.h"
#include "Objects.h"
#include "GUIObject.h"
#include "GUIListBox.h"
#include "GUIScrollBar.h"
#include "InputManager.h"
#include "StatisticsManager.h"
#include "Game.h"
#include "GUIOverlay.h"
+#ifdef __APPLE__
+#include <SDL_ttf/SDL_ttf.h>
+#else
#include <SDL/SDL_ttf.h>
-#include <SDL/SDL.h>
-#include <stdio.h>
+#endif
#include <algorithm>
#include <string>
#include <iostream>
#include "libs/tinyformat/tinyformat.h"
using namespace std;
LevelEditSelect::LevelEditSelect():LevelSelect(_("Map Editor"),LevelPackManager::CUSTOM_PACKS){
//Create the gui.
createGUI(true);
//Set the levelEditGUIObjectRoot.
levelEditGUIObjectRoot=GUIObjectRoot;
//show level list
changePack();
refresh();
}
LevelEditSelect::~LevelEditSelect(){
selectedNumber=NULL;
}
void LevelEditSelect::createGUI(bool initial){
if(initial){
//The levelpack name text field.
levelpackName=new GUIObject(280,104,240,32,GUIObjectTextBox);
levelpackName->eventCallback=this;
levelpackName->visible=false;
GUIObjectRoot->addChild(levelpackName);
}
if(!initial){
//Remove the previous buttons.
for(int i=0;i<(int)GUIObjectRoot->childControls.size();i++){
if(GUIObjectRoot->childControls[i]->type==GUIObjectButton && GUIObjectRoot->childControls[i]->caption!=_("Back")){
delete GUIObjectRoot->childControls[i];
GUIObjectRoot->childControls.erase(GUIObjectRoot->childControls.begin()+i);
i--;
}
}
}
//Create the six buttons at the bottom of the screen.
GUIObject* obj=new GUIObject(SCREEN_WIDTH*0.02,SCREEN_HEIGHT-120,-1,32,GUIObjectButton,_("New Levelpack"));
obj->name="cmdNewLvlpack";
obj->eventCallback=this;
GUIObjectRoot->addChild(obj);
propertiesPack=new GUIObject(SCREEN_WIDTH*0.5,SCREEN_HEIGHT-120,-1,32,GUIObjectButton,_("Pack Properties"),0,true,true,GUIGravityCenter);
propertiesPack->name="cmdLvlpackProp";
propertiesPack->eventCallback=this;
GUIObjectRoot->addChild(propertiesPack);
removePack=new GUIObject(SCREEN_WIDTH*0.98,SCREEN_HEIGHT-120,-1,32,GUIObjectButton,_("Remove Pack"),0,true,true,GUIGravityRight);
removePack->name="cmdRmLvlpack";
removePack->eventCallback=this;
GUIObjectRoot->addChild(removePack);
move=new GUIObject(SCREEN_WIDTH*0.02,SCREEN_HEIGHT-60,-1,32,GUIObjectButton,_("Move Map"));
move->name="cmdMoveMap";
move->eventCallback=this;
//NOTE: Set enabled equal to the inverse of initial.
//When resizing the window initial will be false and therefor the move button can stay enabled.
move->enabled=false;
GUIObjectRoot->addChild(move);
remove=new GUIObject(SCREEN_WIDTH*0.5,SCREEN_HEIGHT-60,-1,32,GUIObjectButton,_("Remove Map"),0,false,true,GUIGravityCenter);
remove->name="cmdRmMap";
remove->eventCallback=this;
GUIObjectRoot->addChild(remove);
edit=new GUIObject(SCREEN_WIDTH*0.98,SCREEN_HEIGHT-60,-1,32,GUIObjectButton,_("Edit Map"),0,false,true,GUIGravityRight);
edit->name="cmdEdit";
edit->eventCallback=this;
GUIObjectRoot->addChild(edit);
//Now update widgets and then check if they overlap
GUIObjectRoot->render(0,0,false);
if(propertiesPack->left-propertiesPack->gravityX < obj->left+obj->width ||
propertiesPack->left-propertiesPack->gravityX+propertiesPack->width > removePack->left-removePack->gravityX){
obj->smallFont=true;
obj->width=-1;
propertiesPack->smallFont=true;
propertiesPack->width=-1;
removePack->smallFont=true;
removePack->width=-1;
move->smallFont=true;
move->width=-1;
remove->smallFont=true;
remove->width=-1;
edit->smallFont=true;
edit->width=-1;
}
//Check again
GUIObjectRoot->render(0,0,false);
if(propertiesPack->left-propertiesPack->gravityX < obj->left+obj->width ||
propertiesPack->left-propertiesPack->gravityX+propertiesPack->width > removePack->left-removePack->gravityX){
obj->left = SCREEN_WIDTH*0.02;
obj->top = SCREEN_HEIGHT-140;
obj->smallFont=false;
obj->width=-1;
obj->gravity = GUIGravityLeft;
propertiesPack->left = SCREEN_WIDTH*0.02;
propertiesPack->top = SCREEN_HEIGHT-100;
propertiesPack->smallFont=false;
propertiesPack->width=-1;
propertiesPack->gravity = GUIGravityLeft;
removePack->left = SCREEN_WIDTH*0.02;
removePack->top = SCREEN_HEIGHT-60;
removePack->smallFont=false;
removePack->width=-1;
removePack->gravity = GUIGravityLeft;
move->left = SCREEN_WIDTH*0.98;
move->top = SCREEN_HEIGHT-140;
move->smallFont=false;
move->width=-1;
move->gravity = GUIGravityRight;
remove->left = SCREEN_WIDTH*0.98;
remove->top = SCREEN_HEIGHT-100;
remove->smallFont=false;
remove->width=-1;
remove->gravity = GUIGravityRight;
edit->left = SCREEN_WIDTH*0.98;
edit->top = SCREEN_HEIGHT-60;
edit->smallFont=false;
edit->width=-1;
edit->gravity = GUIGravityRight;
}
}
void LevelEditSelect::changePack(){
packName=levelpacks->item[levelpacks->value];
if(packName=="Custom Levels"){
//Disable some levelpack buttons.
propertiesPack->enabled=false;
removePack->enabled=false;
}else{
//Enable some levelpack buttons.
propertiesPack->enabled=true;
removePack->enabled=true;
}
//Set last levelpack.
getSettings()->setValue("lastlevelpack",packName);
//Now let levels point to the right pack.
levels=getLevelPackManager()->getLevelPack(packName);
}
void LevelEditSelect::packProperties(bool newPack){
//Open a message popup.
GUIObject* root=new GUIObject((SCREEN_WIDTH-600)/2,(SCREEN_HEIGHT-320)/2,600,320,GUIObjectFrame,_("Properties"));
GUIObject* obj;
obj=new GUIObject(40,50,240,36,GUIObjectLabel,_("Name:"));
root->addChild(obj);
obj=new GUIObject(60,80,480,36,GUIObjectTextBox,packName.c_str());
if(newPack)
obj->caption="";
obj->name="LvlpackName";
root->addChild(obj);
obj=new GUIObject(40,120,240,36,GUIObjectLabel,_("Description:"));
root->addChild(obj);
obj=new GUIObject(60,150,480,36,GUIObjectTextBox,levels->levelpackDescription.c_str());
if(newPack)
obj->caption="";
obj->name="LvlpackDescription";
root->addChild(obj);
obj=new GUIObject(40,190,240,36,GUIObjectLabel,_("Congratulation text:"));
root->addChild(obj);
obj=new GUIObject(60,220,480,36,GUIObjectTextBox,levels->congratulationText.c_str());
if(newPack)
obj->caption="";
obj->name="LvlpackCongratulation";
root->addChild(obj);
obj=new GUIObject(root->width*0.3,320-44,-1,36,GUIObjectButton,_("OK"),0,true,true,GUIGravityCenter);
obj->name="cfgOK";
obj->eventCallback=this;
root->addChild(obj);
obj=new GUIObject(root->width*0.7,320-44,-1,36,GUIObjectButton,_("Cancel"),0,true,true,GUIGravityCenter);
obj->name="cfgCancel";
obj->eventCallback=this;
root->addChild(obj);
//Create the gui overlay.
GUIOverlay* overlay=new GUIOverlay(root);
if(newPack){
packName.clear();
}
}
void LevelEditSelect::addLevel(){
//Open a message popup.
GUIObject* root=new GUIObject((SCREEN_WIDTH-600)/2,(SCREEN_HEIGHT-200)/2,600,200,GUIObjectFrame,_("Add level"));
GUIObject* obj;
obj=new GUIObject(40,80,240,36,GUIObjectLabel,_("File name:"));
root->addChild(obj);
char s[64];
sprintf(s,"map%02d.map",levels->getLevelCount()+1);
obj=new GUIObject(300,80,240,36,GUIObjectTextBox,s);
obj->name="LvlFile";
root->addChild(obj);
obj=new GUIObject(root->width*0.3,200-44,-1,36,GUIObjectButton,_("OK"),0,true,true,GUIGravityCenter);
obj->name="cfgAddOK";
obj->eventCallback=this;
root->addChild(obj);
obj=new GUIObject(root->width*0.7,200-44,-1,36,GUIObjectButton,_("Cancel"),0,true,true,GUIGravityCenter);
obj->name="cfgAddCancel";
obj->eventCallback=this;
root->addChild(obj);
//Dim the screen using the tempSurface.
GUIOverlay* overlay=new GUIOverlay(root);
}
void LevelEditSelect::moveLevel(){
//Open a message popup.
GUIObject* root=new GUIObject((SCREEN_WIDTH-600)/2,(SCREEN_HEIGHT-200)/2,600,200,GUIObjectFrame,_("Move level"));
GUIObject* obj;
obj=new GUIObject(40,60,240,36,GUIObjectLabel,_("Level: "));
root->addChild(obj);
obj=new GUIObject(300,60,240,36,GUIObjectTextBox,"1");
obj->name="MoveLevel";
root->addChild(obj);
obj=new GUISingleLineListBox(root->width*0.5,110,240,36,true,true,GUIGravityCenter);
obj->name="lstPlacement";
vector<string> v;
v.push_back(_("Before"));
v.push_back(_("After"));
v.push_back(_("Swap"));
(dynamic_cast<GUISingleLineListBox*>(obj))->item=v;
obj->value=0;
root->addChild(obj);
obj=new GUIObject(root->width*0.3,200-44,-1,36,GUIObjectButton,_("OK"),0,true,true,GUIGravityCenter);
obj->name="cfgMoveOK";
obj->eventCallback=this;
root->addChild(obj);
obj=new GUIObject(root->width*0.7,200-44,-1,36,GUIObjectButton,_("Cancel"),0,true,true,GUIGravityCenter);
obj->name="cfgMoveCancel";
obj->eventCallback=this;
root->addChild(obj);
//Create the gui overlay.
GUIOverlay* overlay=new GUIOverlay(root);
}
void LevelEditSelect::refresh(bool change){
int m=levels->getLevelCount();
if(change){
numbers.clear();
//clear the selected level
if(selectedNumber!=NULL){
selectedNumber=NULL;
}
//Disable the level specific buttons.
move->enabled=false;
remove->enabled=false;
edit->enabled=false;
for(int n=0;n<=m;n++){
numbers.push_back(Number());
}
}
for(int n=0;n<m;n++){
SDL_Rect box={(n%LEVELS_PER_ROW)*64+80,(n/LEVELS_PER_ROW)*64+184,0,0};
numbers[n].init(n,box);
}
SDL_Rect box={(m%LEVELS_PER_ROW)*64+80,(m/LEVELS_PER_ROW)*64+184,0,0};
numbers[m].init("+",box);
m++; //including the "+" button
if(m>LEVELS_DISPLAYED_IN_SCREEN){
levelScrollBar->maxValue=(m-LEVELS_DISPLAYED_IN_SCREEN+LEVELS_PER_ROW-1)/LEVELS_PER_ROW;
levelScrollBar->visible=true;
}else{
levelScrollBar->maxValue=0;
levelScrollBar->visible=false;
}
if(!levels->levelpackDescription.empty())
levelpackDescription->caption=_C(levels->getDictionaryManager(),levels->levelpackDescription);
else
levelpackDescription->caption="";
}
void LevelEditSelect::selectNumber(unsigned int number,bool selected){
if(selected){
levels->setCurrentLevel(number);
setNextState(STATE_LEVEL_EDITOR);
//Pick music from the current music list.
getMusicManager()->pickMusic();
}else{
if(number==numbers.size()-1){
addLevel();
}else if(number>=0 && number<numbers.size()){
selectedNumber=&numbers[number];
//Enable the level specific buttons.
//NOTE: We check if 'remove levelpack' is enabled, if not then it's the Levels levelpack.
if(removePack->enabled)
move->enabled=true;
remove->enabled=true;
edit->enabled=true;
}
}
}
void LevelEditSelect::render(){
//Let the levelselect render.
LevelSelect::render();
}
void LevelEditSelect::resize(){
//Let the levelselect resize.
LevelSelect::resize();
//Create the GUI.
createGUI(false);
//NOTE: This is a workaround for buttons failing when resizing.
if(packName=="Custom Levels"){
removePack->enabled=false;
propertiesPack->enabled=false;
}
if(selectedNumber)
selectNumber(selectedNumber->getNumber(),false);
}
void LevelEditSelect::renderTooltip(unsigned int number,int dy){
SDL_Color fg={0,0,0};
SDL_Surface* name;
if(number==(unsigned)levels->getLevelCount()){
//Render the name of the level.
name=TTF_RenderUTF8_Blended(fontText,_("Add level"),fg);
}else{
//Render the name of the level.
name=TTF_RenderUTF8_Blended(fontText,_C(levels->getDictionaryManager(),levels->getLevelName(number)),fg);
}
//Check if name isn't null.
if(name==NULL)
return;
//Now draw a square the size of the three texts combined.
SDL_Rect r=numbers[number].box;
r.y-=dy*64;
r.w=name->w;
r.h=name->h;
//Make sure the tooltip doesn't go outside the window.
if(r.y>SCREEN_HEIGHT-200){
r.y-=name->h+4;
}else{
r.y+=numbers[number].box.h+2;
}
if(r.x+r.w>SCREEN_WIDTH-50)
r.x=SCREEN_WIDTH-50-r.w;
//Draw a rectange
Uint32 color=0xFFFFFF00|240;
drawGUIBox(r.x-5,r.y-5,r.w+10,r.h+10,screen,color);
//Calc the position to draw.
SDL_Rect r2=r;
//Now we render the name if the surface isn't null.
if(name!=NULL){
//Draw the name.
SDL_BlitSurface(name,NULL,screen,&r2);
}
//And free the surfaces.
SDL_FreeSurface(name);
}
void LevelEditSelect::GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType){
//NOTE: We check for the levelpack change to enable/disable some levelpack buttons.
if(name=="cmdLvlPack"){
//We call changepack and return to prevent the LevelSelect to undo what we did.
changePack();
refresh();
return;
}
//Let the level select handle his GUI events.
LevelSelect::GUIEventCallback_OnEvent(name,obj,eventType);
//Check for the edit button.
if(name=="cmdNewLvlpack"){
//Create a new pack.
packProperties(true);
}else if(name=="cmdLvlpackProp"){
//Show the pack properties.
packProperties(false);
}else if(name=="cmdRmLvlpack"){
//Show an "are you sure" message.
if(msgBox(_("Are you sure?"),MsgBoxYesNo,_("Remove prompt"))==MsgBoxYes){
//Remove the directory.
if(!removeDirectory(levels->levelpackPath.c_str())){
cerr<<"ERROR: Unable to remove levelpack directory "<<levels->levelpackPath<<endl;
}
//Remove it from the vector (levelpack list).
vector<string>::iterator it;
it=find(levelpacks->item.begin(),levelpacks->item.end(),packName);
if(it!=levelpacks->item.end()){
levelpacks->item.erase(it);
}
//Remove it from the levelpackManager.
getLevelPackManager()->removeLevelPack(packName);
//And call changePack.
levelpacks->value=levelpacks->item.size()-1;
changePack();
refresh();
}
}else if(name=="cmdMoveMap"){
if(selectedNumber!=NULL){
moveLevel();
}
}else if(name=="cmdRmMap"){
if(selectedNumber!=NULL){
if(packName!="Custom Levels"){
if(!removeFile((levels->levelpackPath+"/"+levels->getLevel(selectedNumber->getNumber())->file).c_str())){
cerr<<"ERROR: Unable to remove level "<<(levels->levelpackPath+"/"+levels->getLevel(selectedNumber->getNumber())->file).c_str()<<endl;
}
levels->removeLevel(selectedNumber->getNumber());
levels->saveLevels(levels->levelpackPath+"/levels.lst");
}else{
//This is the levels levelpack so we just remove the file.
if(!removeFile(levels->getLevel(selectedNumber->getNumber())->file.c_str())){
cerr<<"ERROR: Unable to remove level "<<levels->getLevel(selectedNumber->getNumber())->file<<endl;
}
levels->removeLevel(selectedNumber->getNumber());
}
//And refresh the selection screen.
refresh();
}
}else if(name=="cmdEdit"){
if(selectedNumber!=NULL){
levels->setCurrentLevel(selectedNumber->getNumber());
setNextState(STATE_LEVEL_EDITOR);
//Pick music from the current music list.
getMusicManager()->pickMusic();
}
}
//Check for levelpack properties events.
if(name=="cfgOK"){
//Now loop throught the children of the GUIObjectRoot in search of the fields.
for(unsigned int i=0;i<GUIObjectRoot->childControls.size();i++){
if(GUIObjectRoot->childControls[i]->name=="LvlpackName"){
//Check if the name changed.
if(packName!=GUIObjectRoot->childControls[i]->caption){
//Delete the old one.
if(!packName.empty()){
if(!renameDirectory((getUserPath(USER_DATA)+"custom/levelpacks/"+packName).c_str(),(getUserPath(USER_DATA)+"custom/levelpacks/"+GUIObjectRoot->childControls[i]->caption).c_str())){
cerr<<"ERROR: Unable to move levelpack directory "<<(getUserPath(USER_DATA)+"custom/levelpacks/"+packName)<<" to "<<(getUserPath(USER_DATA)+"custom/levelpacks/"+GUIObjectRoot->childControls[i]->caption)<<endl;
}
//Remove the old one from the levelpack manager.
getLevelPackManager()->removeLevelPack(packName);
//And the levelpack list.
vector<string>::iterator it1;
it1=find(levelpacks->item.begin(),levelpacks->item.end(),packName);
if(it1!=levelpacks->item.end()){
levelpacks->item.erase(it1);
if((unsigned)levelpacks->value>levelpacks->item.size())
levelpacks->value=levelpacks->item.size()-1;
}
}else{
//It's a new levelpack so we need to change the levels array.
LevelPack* pack=new LevelPack;
levels=pack;
//Now create the dirs.
if(!createDirectory((getUserPath(USER_DATA)+"custom/levelpacks/"+GUIObjectRoot->childControls[i]->caption).c_str())){
cerr<<"ERROR: Unable to create levelpack directory "<<(getUserPath(USER_DATA)+"custom/levelpacks/"+GUIObjectRoot->childControls[i]->caption)<<endl;
}
if(!createFile((getUserPath(USER_DATA)+"custom/levelpacks/"+GUIObjectRoot->childControls[i]->caption+"/levels.lst").c_str())){
cerr<<"ERROR: Unable to create levelpack file "<<(getUserPath(USER_DATA)+"custom/levelpacks/"+GUIObjectRoot->childControls[i]->caption+"/levels.lst")<<endl;
}
}
//And set the new name.
packName=GUIObjectRoot->childControls[i]->caption;
levels->levelpackName=packName;
levels->levelpackPath=(getUserPath(USER_DATA)+"custom/levelpacks/"+packName+"/");
//Also add the levelpack location
getLevelPackManager()->addLevelPack(levels);
levelpacks->item.push_back(GUIObjectRoot->childControls[i]->caption);
levelpacks->value=levelpacks->item.size()-1;
//And call changePack.
changePack();
}
}
if(GUIObjectRoot->childControls[i]->name=="LvlpackDescription"){
levels->levelpackDescription=GUIObjectRoot->childControls[i]->caption;
}
if(GUIObjectRoot->childControls[i]->name=="LvlpackCongratulation"){
levels->congratulationText=GUIObjectRoot->childControls[i]->caption;
}
}
//Refresh the leveleditselect to show the correct information.
refresh();
//Save the configuration.
levels->saveLevels(getUserPath(USER_DATA)+"custom/levelpacks/"+packName+"/levels.lst");
getSettings()->setValue("lastlevelpack",packName);
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}else if(name=="cfgCancel"){
//Check if packName is empty, if so it was a new levelpack and we need to revert to an existing one.
if(packName.empty()){
packName=levelpacks->item[levelpacks->value];
changePack();
}
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}
//Check for add level events.
if(name=="cfgAddOK"){
//Check if the file name isn't null.
//Now loop throught the children of the GUIObjectRoot in search of the fields.
for(unsigned int i=0;i<GUIObjectRoot->childControls.size();i++){
if(GUIObjectRoot->childControls[i]->name=="LvlFile"){
if(GUIObjectRoot->childControls[i]->caption.empty()){
msgBox(_("No file name given for the new level."),MsgBoxOKOnly,_("Missing file name"));
return;
}else{
string tmp_caption = GUIObjectRoot->childControls[i]->caption;
//Replace all spaces with a underline.
size_t j;
for(;(j=tmp_caption.find(" "))!=string::npos;){
tmp_caption.replace(j,1,"_");
}
//If there isn't ".map" extension add it.
size_t found=tmp_caption.find_first_of(".");
if(found!=string::npos)
tmp_caption.replace(tmp_caption.begin()+found+1,tmp_caption.end(),"map");
else if (tmp_caption.substr(found+1)!="map")
tmp_caption.append(".map");
/* Create path and file in it */
string path=(levels->levelpackPath+"/"+tmp_caption);
if(packName=="Custom Levels"){
path=(getUserPath(USER_DATA)+"/custom/levels/"+tmp_caption);
}
//First check if the file doesn't exist already.
FILE* f;
f=fopen(path.c_str(),"rb");
//Check if it exists.
if(f){
//Close the file.
fclose(f);
//Let the currentState render once to prevent multiple GUI overlapping and prevent the screen from going black.
currentState->render();
levelEditGUIObjectRoot->render();
//Notify the user.
msgBox(("The file "+tmp_caption+" already exists.").c_str(),MsgBoxOKOnly,"Error");
return;
}
if(!createFile(path.c_str())){
cerr<<"ERROR: Unable to create level file "<<path<<endl;
}else{
//Update statistics.
statsMgr.newAchievement("create1");
if((++statsMgr.createdLevels)>=50) statsMgr.newAchievement("create50");
}
levels->addLevel(path);
if(packName!="Custom Levels")
levels->saveLevels(getUserPath(USER_DATA)+"custom/levelpacks/"+packName+"/levels.lst");
refresh();
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
return;
}
}
}
}
}else if(name=="cfgAddCancel"){
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}
//Check for move level events.
if(name=="cfgMoveOK"){
//Check if the entered level number is valid.
//Now loop throught the children of the GUIObjectRoot in search of the fields.
int level=0;
int placement=0;
for(unsigned int i=0;i<GUIObjectRoot->childControls.size();i++){
if(GUIObjectRoot->childControls[i]->name=="MoveLevel"){
level=atoi(GUIObjectRoot->childControls[i]->caption.c_str());
if(level<=0 || level>levels->getLevelCount()){
msgBox(_("The entered level number isn't valid!"),MsgBoxOKOnly,_("Illegal number"));
return;
}
}
if(GUIObjectRoot->childControls[i]->name=="lstPlacement"){
placement=GUIObjectRoot->childControls[i]->value;
}
}
//Now we execute the swap/move.
//Check for the place before.
if(placement==0){
//We place the selected level before the entered level.
levels->moveLevel(selectedNumber->getNumber(),level-1);
}else if(placement==1){
//We place the selected level after the entered level.
if(level<selectedNumber->getNumber())
levels->moveLevel(selectedNumber->getNumber(),level);
else
levels->moveLevel(selectedNumber->getNumber(),level+1);
}else if(placement==2){
//We swap the selected level with the entered level.
levels->swapLevel(selectedNumber->getNumber(),level-1);
}
//And save the change.
if(packName!="Custom Levels")
levels->saveLevels(getUserPath(USER_DATA)+"custom/levelpacks/"+packName+"/levels.lst");
refresh();
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}else if(name=="cfgMoveCancel"){
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}
}
diff --git a/src/LevelEditSelect.h b/src/LevelEditSelect.h
index 05b30fc..304bb07 100644
--- a/src/LevelEditSelect.h
+++ b/src/LevelEditSelect.h
@@ -1,98 +1,102 @@
/*
* Copyright (C) 2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LEVELEDITSELECT_H
#define LEVELEDITSELECT_H
#include "LevelSelect.h"
#include "GameState.h"
#include "GameObjects.h"
#include "Player.h"
#include "GUIObject.h"
-#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#include <SDL_ttf/SDL_ttf.h>
+#else
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
+#endif
#include <vector>
#include <string>
//This is the LevelEditSelect state, here you can select levelpacks and levels.
class LevelEditSelect :public LevelSelect{
private:
//Pointer to the GUIObjectRoot of the levelselect main gui.
GUIObject* levelEditGUIObjectRoot;
//Pointer to the new levelpack textfield.
GUIObject* levelpackName;
//Pointer to the remove levelpack button.
GUIObject* propertiesPack;
//Pointer to the remove levelpack button.
GUIObject* removePack;
//Pointer to the move map button.
GUIObject* move;
//Pointer to the remove map button.
GUIObject* remove;
//Pointer to the edit map button.
GUIObject* edit;
//String that contains the name of the current levelpack.
std::string packName;
//Method that will create the GUI elements.
//initial: Boolean if it is the first time the gui is created.
void createGUI(bool initial);
//Method that should be called when changing the current levelpack in an abnormal way.
void changePack();
//This method will show a popup with levelpack specific settings.
//newPack: Boolean if it's a new levelpack.
void packProperties(bool newPack);
//This method will show an add level dialog.
void addLevel();
//This method will show an move level dialog.
void moveLevel();
public:
//Constructor.
LevelEditSelect();
//Destructor.
~LevelEditSelect();
//Inherited from LevelSelect.
//change: Boolean if the levelpack changed, if not we only have to rearrange the numbers.
void refresh(bool change=true);
void selectNumber(unsigned int number,bool selected);
//Inherited from GameState.
void render();
//Inherited from GameState.
void resize();
//Inherited from LevelSelect.
void renderTooltip(unsigned int number,int dy);
//GUI events will be handled here.
void GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType);
};
#endif
diff --git a/src/LevelEditor.h b/src/LevelEditor.h
index d855bca..731d6dd 100644
--- a/src/LevelEditor.h
+++ b/src/LevelEditor.h
@@ -1,283 +1,287 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LEVELEDITOR_H
#define LEVELEDITOR_H
#include "GameState.h"
#include "GameObjects.h"
#include "Player.h"
#include "Game.h"
#include "GUIObject.h"
#include <vector>
#include <map>
#include <string>
-#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#include <SDL_ttf/SDL_ttf.h>
+#else
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
+#endif
//Class that represents a moving position for moving blocks.
class MovingPosition{
public:
//Integer containing the relative time used to store in the level.
int time;
//The x location.
int x;
//The x location.
int y;
//Constructor.
//x: The x position relative to the moving block's position.
//y: The y position relative to the moving block's position.
//time: The time it takes from the previous position to here.
MovingPosition(int x,int y,int time);
//Destructor.
~MovingPosition();
//This will update the moving position.
//x: The x position relative to the moving block's position.
//y: The y position relative to the moving block's position.
void updatePosition(int x,int y);
};
//internal tool box class
class LevelEditorToolbox;
//internal selection popup class
class LevelEditorSelectionPopup;
//The LevelEditor state, it's based on the Game state.
class LevelEditor: public Game{
friend class LevelEditorToolbox;
friend class LevelEditorSelectionPopup;
private:
//Boolean if the user isplaying/testing the level.
bool playMode;
//Enumaration containing the tools.
//SELECT: The select tool, for selecting/dragging blocks.
//ADD: For adding blocks.
//REMOVE: For removing blocks.
//CONFIGURE: Used to configure special blocks.
enum Tools{
SELECT,
ADD,
REMOVE,
CONFIGURE,
NUMBER_TOOLS
};
//The tool the user has selected.
Tools tool;
//The toolbar surface.
SDL_Surface* toolbar;
//Rectangle the size and location of the toolbar on screen.
SDL_Rect toolbarRect;
//The editor tool box (if any)
LevelEditorToolbox* toolbox;
//The selection popup (if any)
LevelEditorSelectionPopup* selectionPopup;
//Vector containing pointers to the selected GameObjects.
vector<GameObject*> selection;
//The selection square.
SDL_Surface* selectionMark;
//Surface used for drawing transparent selection/dragging.
SDL_Surface* placement;
//A circle at the location of moving positions in configure mode.
SDL_Surface* movingMark;
//The current type of block to place in Add mode.
int currentType;
//Boolean if the shift button is pressed.
bool pressedShift;
//Boolean if the left mouse button is pressed.
bool pressedLeftMouse;
//Boolean if the mouse is dragged. (Left button pressed and moved)
bool dragging;
//The camera x velocity.
int cameraXvel;
int cameraYvel;
//SDL_Rect used to store the camera's location when entering playMode.
SDL_Rect cameraSave;
//Boolean if the selection is dragged.
bool selectionDrag;
//Pointer to the gameobject that's the center of the drag.
GameObject* dragCenter;
//Integer containing a unique id.
//Everytime a new id is needed it will increase by one.
unsigned int currentId;
//Vector containing the trigger GameObjects.
map<GameObject*,vector<GameObject*> > triggers;
//Boolean used in configure mode when linking triggers with their targets.
bool linking;
//Pointer to the trigger that's is being linked.
GameObject* linkingTrigger;
//Vector containing the moving GameObjects.
map<GameObject*,vector<MovingPosition> > movingBlocks;
//Integer containing the speed the block is moving for newly added blocks.
//The movingSpeed is capped at 100.
int movingSpeed;
//Boolean used in configure mode when configuring moving blocks.
bool moving;
//Pointer to the moving block that's is being configured.
GameObject* movingBlock;
//Value used for placing the Movespeed label
int movingSpeedWidth;
//The clipboard.
vector<map<string,string> > clipboard;
//Pointer to a GUIObject for a property of the object.
//Only used in the configure tool.
GUIObject* objectProperty;
//Pointer to a GUIObject for a property of the object.
//Only used in the configure tool.
GUIObject* secondObjectProperty;
//Pointer to the object that is being configured.
GameObject* configuredObject;
//String containing the levelTheme.
std::string levelTheme;
//Integer containing the button of which a tool tip should be shown.
int tooltip;
//GUI event handling is done here.
void GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType);
//Method that will let you configure the levelSettings.
void levelSettings();
//Method used to save the level.
//fileName: Thge filename to write the level to.
void saveLevel(string fileName);
//Method used to convert a given x and y to snap to grid.
//x: Pointer to the x location.
//y: Pointer to the y location.
void snapToGrid(int* x,int* y);
public:
//Array containing the ids of different block types in a wanted order
//Maybe also useful to disable deprecated block types in the editor
//PLEASE NOTE: Must be updated for new block types
//Ordered for Edward Liis proposal:
//Normal->Shadow->Spikes->Fragile
//Normal moving->Shadow moving->Moving spikes
//Conveyor belt->Shadow conveyor belt
//Button->Switch->Portal->Swap->Checkpoint->Notification block
//Player start->Shadow start->Exit
static const int EDITOR_ORDER_MAX=19;
static const int editorTileOrder[EDITOR_ORDER_MAX];
protected:
//Inherits the function loadLevelFromNode from Game class.
virtual void loadLevelFromNode(TreeStorageNode* obj, const std::string& fileName);
public:
//Constructor.
LevelEditor();
//Destructor.
~LevelEditor();
//Method that will reset some default values.
void reset();
//Inherited from Game(State).
void handleEvents();
void logic();
void render();
void resize();
//Method used to draw the currentType on the placement surface.
//This will only be called when the tool is ADD.
void showCurrentObject();
//Method used to draw the selection that's being dragged.
void showSelectionDrag();
//Method used to draw configure tool specific things like moving positions, teleport lines.
void showConfigure();
//Method that will render the HUD.
//It will be rendered after the placement suface but before the toolbar.
void renderHUD();
//Method called after loading a level.
//It will fill the triggers vector.
void postLoad();
//Event that is invoked when there's a mouse click on an object.
//obj: Pointer to the GameObject clicked on.
//selected: Boolean if the GameObject that has been clicked on was selected.
void onClickObject(GameObject* obj,bool selected);
//Event that is invoked when there's a right mouse button click on an object.
//obj: Pointer to the GameObject clicked on.
//selected: Boolean if the GameObject that has been clicked on was selected.
void onRightClickObject(GameObject* obj,bool selected);
//Event that is invoked when there's a mouse click but not on any object.
//x: The x location of the click on the game field (+= camera.x).
//y: The y location of the click on the game field (+= camera.y).
void onClickVoid(int x,int y);
//Event that is invoked when the dragging starts.
//x: The x location the drag started. (mouse.x+camera.x)
//y: The y location the drag started. (mouse.y+camera.y)
void onDragStart(int x,int y);
//Event that is invoked when the mouse is dragged.
//dx: The relative x distance the mouse dragged.
//dy: The relative y distance the mouse dragged.
void onDrag(int dx,int dy);
//Event that is invoked when the mouse stopped dragging.
//x: The x location the drag stopped. (mouse.x+camera.x)
//y: The y location the drag stopped. (mouse.y+camera.y)
void onDrop(int x,int y);
//Event that is invoked when the camera is moved.
//dx: The relative x distance the camera moved.
//dy: The relative y distance the camera moved.
void onCameraMove(int dx,int dy);
//Event that is invoked when enter is pressed above an object.
//obj: Pointer to the GameObject entered above.
void onEnterObject(GameObject* obj);
//Method used to add a GameObject to the level.
//obj: Pointer to the gameobject to add.
void addObject(GameObject* obj);
//Method used to move a GameObject from the level.
//obj: Pointer to the gameobject to move.
//x: The new x location of the GameObject.
//y: The new y location of the GameObject.
void moveObject(GameObject* obj,int x,int y);
//Method used to remove a GameObject from the level.
//obj: Pointer to the gameobject to remove.
void removeObject(GameObject* obj);
};
#endif
diff --git a/src/LevelPack.h b/src/LevelPack.h
index b0e9c65..ea1141b 100644
--- a/src/LevelPack.h
+++ b/src/LevelPack.h
@@ -1,184 +1,188 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LEVELPACK_H
#define LEVELPACK_H
-#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#include <SDL_ttf/SDL_ttf.h>
+#else
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
+#endif
#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();
//Destructor.
~LevelPack();
//gettext function
inline tinygettext::DictionaryManager* getDictionaryManager() const{
return dictionaryManager;
}
//Method for updating the language to the configured one.
//NOTE: This is called when changing the translation in the Options menu.
void updateLanguage();
//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] containing 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
diff --git a/src/LevelPackManager.h b/src/LevelPackManager.h
index 3285d1a..d579b83 100644
--- a/src/LevelPackManager.h
+++ b/src/LevelPackManager.h
@@ -1,81 +1,85 @@
/*
* Copyright (C) 2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LEVELPACKMANAGER_H
#define LEVELPACKMANAGER_H
#include "LevelPack.h"
#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_image/SDL_image.h>
+#else
#include <SDL/SDL_image.h>
+#endif
#include <string>
#include <map>
#include <vector>
//Class for loading and managing levelpacks.
class LevelPackManager{
public:
//Constructor.
LevelPackManager(){}
//Destructor.
~LevelPackManager();
//Load a levelpack and add it to the map.
//name: The name of the levelpack files.
void loadLevelPack(std::string name);
//Insert a levelpack in the LevelPackManager.
//levelpack: Pointer to the levelpack to add.
void addLevelPack(LevelPack* levelpack);
//Removes a levelpack from the LevelPackManager.
//name: The name of the levelpack to remove.
void removeLevelPack(std::string name);
//Method that will return a levelpack.
//name: The name of the levelpack.
//Returns: Pointer to the requested levelpack.
LevelPack* getLevelPack(std::string name);
//Method that will return a vector containing all (or a subset) of the levelpacks.
//type: The list type, default is ALL_PACKS.
std::vector<std::string> enumLevelPacks(int type=ALL_PACKS);
//Method that will update the translation of the levelpacks.
//NOTE: This is called when changing the language in the Options menu.
void updateLanguage();
//Destroys the levelpacks.
void destroy();
//Enumeration containing the different types of levelpack lists.
enum LevelPackLists
{
//This list contains every levelpack.
ALL_PACKS,
//This list contains all the custom levelpacks (and Levels).
CUSTOM_PACKS
};
private:
//Map containing the levelpacks.
//The key is the name of the levelpack and the value is a pointer to the levelpack.
std::map<std::string,LevelPack*> levelpacks;
};
#endif
diff --git a/src/LevelPlaySelect.cpp b/src/LevelPlaySelect.cpp
index 96e8967..38bee2e 100644
--- a/src/LevelPlaySelect.cpp
+++ b/src/LevelPlaySelect.cpp
@@ -1,458 +1,461 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "LevelPlaySelect.h"
#include "GameState.h"
#include "Functions.h"
#include "FileManager.h"
#include "Globals.h"
#include "Objects.h"
#include "LevelSelect.h"
#include "GUIObject.h"
#include "GUIListBox.h"
#include "GUIScrollBar.h"
#include "InputManager.h"
#include "Game.h"
+#ifdef __APPLE__
+#include <SDL_ttf/SDL_ttf.h>
+#else
#include <SDL/SDL_ttf.h>
-#include <SDL/SDL.h>
+#endif
#include <stdio.h>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
/////////////////////LEVEL SELECT/////////////////////
static string levelDescription,levelMedal2,levelMedal3,levelTime,levelRecs;
static string bestTimeFilePath,bestRecordingFilePath;
LevelPlaySelect::LevelPlaySelect():LevelSelect(_("Select Level")){
//Load the play button if needed.
playButtonImage=loadImage(getDataPath()+"gfx/playbutton.png");
timeIcon=loadImage(getDataPath()+"gfx/time.png");
recordingsIcon=loadImage(getDataPath()+"gfx/recordings.png");
//Create the gui.
createGUI(true);
//Show level list
refresh();
}
LevelPlaySelect::~LevelPlaySelect(){
play=NULL;
recordingsIcon=NULL;
timeIcon=NULL;
}
void LevelPlaySelect::createGUI(bool initial){
//Create the play button.
if(initial){
play=new GUIObject(SCREEN_WIDTH-240,SCREEN_HEIGHT-60,240,32,GUIObjectButton,_("Play"));
}else{
play->left=SCREEN_WIDTH-240;
play->top=SCREEN_HEIGHT-60;
}
play->name="cmdPlay";
play->eventCallback=this;
play->enabled=false;
if(initial)
GUIObjectRoot->addChild(play);
}
void LevelPlaySelect::refresh(bool change){
int m=levels->getLevelCount();
numbers.clear();
//clear the selected level
if(selectedNumber!=NULL){
delete selectedNumber;
selectedNumber=NULL;
}
//Recreate the non selected number.
selectedNumber=new Number();
SDL_Rect box={40,SCREEN_HEIGHT-130,50,50};
selectedNumber->init(" ",box);
selectedNumber->setLocked(true);
levelDescription=_("Choose a level");
levelMedal2=string(_("Time:"));
levelMedal3=string(_("Recordings:"));
levelTime=string("- / -");
levelRecs=string("- / -");
bestTimeFilePath.clear();
bestRecordingFilePath.clear();
//Disable the play button.
play->enabled=false;
for(int n=0; n<m; n++){
numbers.push_back(Number());
}
for(int n=0; n<m; n++){
SDL_Rect box={(n%LEVELS_PER_ROW)*64+(SCREEN_WIDTH*0.2)/2,(n/LEVELS_PER_ROW)*64+184,0,0};
numbers[n].init(n,box);
numbers[n].setLocked(levels->getLocked(n));
int medal=levels->getLevel(n)->won;
if(medal){
if(levels->getLevel(n)->targetTime<0 || levels->getLevel(n)->time<=levels->getLevel(n)->targetTime)
medal++;
if(levels->getLevel(n)->targetRecordings<0 || levels->getLevel(n)->recordings<=levels->getLevel(n)->targetRecordings)
medal++;
}
numbers[n].setMedal(medal);
}
if(m>LEVELS_DISPLAYED_IN_SCREEN){
levelScrollBar->maxValue=(m-LEVELS_DISPLAYED_IN_SCREEN+(LEVELS_PER_ROW-1))/LEVELS_PER_ROW;
levelScrollBar->visible=true;
}else{
levelScrollBar->maxValue=0;
levelScrollBar->visible=false;
}
if(!levels->levelpackDescription.empty())
levelpackDescription->caption=_C(levels->getDictionaryManager(),levels->levelpackDescription);
else
levelpackDescription->caption="";
}
void LevelPlaySelect::selectNumber(unsigned int number,bool selected){
if(selected){
levels->setCurrentLevel(number);
setNextState(STATE_GAME);
//Pick music from the current music list.
getMusicManager()->pickMusic();
}else{
displayLevelInfo(number);
}
}
void LevelPlaySelect::checkMouse(){
int x,y;
//Get the current mouse location.
SDL_GetMouseState(&x,&y);
//Check if we should replay the record.
if(selectedNumber!=NULL){
SDL_Rect mouse={x,y,0,0};
if(!bestTimeFilePath.empty()){
SDL_Rect box={SCREEN_WIDTH-420,SCREEN_HEIGHT-130,372,32};
if(checkCollision(box,mouse)){
Game::recordFile=bestTimeFilePath;
levels->setCurrentLevel(selectedNumber->getNumber());
setNextState(STATE_GAME);
//Pick music from the current music list.
getMusicManager()->pickMusic();
return;
}
}
if(!bestRecordingFilePath.empty()){
SDL_Rect box={SCREEN_WIDTH-420,SCREEN_HEIGHT-98,372,32};
if(checkCollision(box,mouse)){
Game::recordFile=bestRecordingFilePath;
levels->setCurrentLevel(selectedNumber->getNumber());
setNextState(STATE_GAME);
//Pick music from the current music list.
getMusicManager()->pickMusic();
return;
}
}
}
//Call the base method from the super class.
LevelSelect::checkMouse();
}
void LevelPlaySelect::displayLevelInfo(int number){
//Update currently selected level
if(selectedNumber==NULL){
selectedNumber=new Number();
}
SDL_Rect box={40,SCREEN_HEIGHT-130,50,50};
selectedNumber->init(number,box);
selectedNumber->setLocked(false);
//Show level description
levelDescription=levels->getLevelName(number);
//Show level medal
int medal=levels->getLevel(number)->won;
int time=levels->getLevel(number)->time;
int targetTime=levels->getLevel(number)->targetTime;
int recordings=levels->getLevel(number)->recordings;
int targetRecordings=levels->getLevel(number)->targetRecordings;
if(medal){
if(targetTime<0){
medal=-1;
}else{
if(targetTime<0 || time<=targetTime)
medal++;
if(targetRecordings<0 || recordings<=targetRecordings)
medal++;
}
}
selectedNumber->setMedal(medal);
//Show best time and recordings
if(medal){
char s[64];
if(time>0)
if(targetTime>0)
sprintf(s,"%-.2fs / %-.2fs",time/40.0f,targetTime/40.0f);
else
sprintf(s,"%-.2fs / -",time/40.0f);
else
s[0]='\0';
levelTime=string(s);
if(recordings>=0)
if(targetRecordings>=0)
sprintf(s,"%5d / %d",recordings,targetRecordings);
else
sprintf(s,"%5d / -",recordings);
else
s[0]='\0';
levelRecs=string(s);
}else{
levelTime=string("- / -");
levelRecs=string("- / -");
}
//Show the play button.
play->enabled=true;
//Check if there is auto record file
levels->getLevelAutoSaveRecordPath(number,bestTimeFilePath,bestRecordingFilePath,false);
if(!bestTimeFilePath.empty()){
FILE *f;
f=fopen(bestTimeFilePath.c_str(),"rb");
if(f==NULL){
bestTimeFilePath.clear();
}else{
fclose(f);
}
}
if(!bestRecordingFilePath.empty()){
FILE *f;
f=fopen(bestRecordingFilePath.c_str(),"rb");
if(f==NULL){
bestRecordingFilePath.clear();
}else{
fclose(f);
}
}
}
void LevelPlaySelect::render(){
//First let the levelselect render.
LevelSelect::render();
int x,y,dy=0,m=levels->getLevelCount();
//Get the current mouse location.
SDL_GetMouseState(&x,&y);
if(levelScrollBar)
dy=levelScrollBar->value;
//Upper bound of levels we'd like to display.
if(m>dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN)
m=dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN;
y+=dy*64;
SDL_Rect mouse={x,y,0,0};
//Show currently selected level (if any)
if(selectedNumber!=NULL){
selectedNumber->show(0);
SDL_Surface* bm;
if(!levelDescription.empty()){
bm=TTF_RenderUTF8_Blended(fontText,_C(levels->getDictionaryManager(),levelDescription.c_str()),themeTextColor);
applySurface(100,SCREEN_HEIGHT-130+(50-bm->h)/2,bm,screen,NULL);
SDL_FreeSurface(bm);
}
//Only show the replay if the level is completed (won).
if(selectedNumber->getNumber()>=0 && selectedNumber->getNumber()<levels->getLevelCount()) {
if(levels->getLevel(selectedNumber->getNumber())->won){
if(!bestTimeFilePath.empty()){
SDL_Rect r={0,0,32,32};
SDL_Rect box={SCREEN_WIDTH-420,SCREEN_HEIGHT-130,372,32};
if(checkCollision(box,mouse)){
r.x=32;
SDL_FillRect(screen,&box,0xFFCCCCCC);
}
applySurface(SCREEN_WIDTH-80,SCREEN_HEIGHT-130,playButtonImage,screen,&r);
}
if(!bestRecordingFilePath.empty()){
SDL_Rect r={0,0,32,32};
SDL_Rect box={SCREEN_WIDTH-420,SCREEN_HEIGHT-98,372,32};
if(checkCollision(box,mouse)){
r.x=32;
SDL_FillRect(screen,&box,0xFFCCCCCC);
}
applySurface(SCREEN_WIDTH-80,SCREEN_HEIGHT-98,playButtonImage,screen,&r);
}
}
}
if(!levelMedal2.empty()){
//Draw the icon.
applySurface(SCREEN_WIDTH-405,SCREEN_HEIGHT-130+3,timeIcon,screen,NULL);
//Now draw the text (title).
bm=TTF_RenderUTF8_Blended(fontText,levelMedal2.c_str(),themeTextColor);
applySurface(SCREEN_WIDTH-380,SCREEN_HEIGHT-130+3,bm,screen,NULL);
SDL_FreeSurface(bm);
//Now draw the second text (value).
bm=TTF_RenderUTF8_Blended(fontText,levelTime.c_str(),themeTextColor);
applySurface(SCREEN_WIDTH-bm->w-80,SCREEN_HEIGHT-130+3,bm,screen,NULL);
SDL_FreeSurface(bm);
}
if(!levelMedal3.empty()){
//Draw the icon.
applySurface(SCREEN_WIDTH-405,SCREEN_HEIGHT-98+(6)/2,recordingsIcon,screen,NULL);
//Now draw the text (title).
bm=TTF_RenderUTF8_Blended(fontText,levelMedal3.c_str(),themeTextColor);
applySurface(SCREEN_WIDTH-380,SCREEN_HEIGHT-98+(32-bm->h)/2,bm,screen,NULL);
SDL_FreeSurface(bm);
//Now draw the second text (value).
bm=TTF_RenderUTF8_Blended(fontText,levelRecs.c_str(),themeTextColor);
applySurface(SCREEN_WIDTH-bm->w-80,SCREEN_HEIGHT-98+(32-bm->h)/2,bm,screen,NULL);
SDL_FreeSurface(bm);
}
}
}
void LevelPlaySelect::renderTooltip(unsigned int number,int dy){
SDL_Color themeTextColor={0,0,0};
char s[64];
//Render the name of the level.
SDL_Surface* name=TTF_RenderUTF8_Blended(fontText,_C(levels->getDictionaryManager(),levels->getLevelName(number)),themeTextColor);
SDL_Surface* time=NULL;
SDL_Surface* recordings=NULL;
//The time it took.
if(levels->getLevel(number)->time>0){
sprintf(s,"%-.2fs",levels->getLevel(number)->time/40.0f);
time=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
}
//The number of recordings it took.
if(levels->getLevel(number)->recordings>=0){
sprintf(s,"%d",levels->getLevel(number)->recordings);
recordings=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
}
//Now draw a square the size of the three texts combined.
SDL_Rect r=numbers[number].box;
r.y-=dy*64;
if(time!=NULL && recordings!=NULL){
r.w=(name->w)>(25+time->w+40+recordings->w)?(name->w):(25+time->w+40+recordings->w);
r.h=name->h+5+20;
}else{
r.w=name->w;
r.h=name->h;
}
//Make sure the tooltip doesn't go outside the window.
if(r.y>SCREEN_HEIGHT-200){
r.y-=name->h+4;
}else{
r.y+=numbers[number].box.h+2;
}
if(r.x+r.w>SCREEN_WIDTH-50)
r.x=SCREEN_WIDTH-50-r.w;
//Draw a rectange
Uint32 color=0xFFFFFF00|240;
drawGUIBox(r.x-5,r.y-5,r.w+10,r.h+10,screen,color);
//Calc the position to draw.
SDL_Rect r2=r;
//Now we render the name if the surface isn't null.
if(name!=NULL){
//Draw the name.
SDL_BlitSurface(name,NULL,screen,&r2);
}
//Increase the height to leave a gap between name and stats.
r2.y+=30;
if(time!=NULL){
//Now draw the time.
applySurface(r2.x,r2.y,timeIcon,screen,NULL);
r2.x+=25;
SDL_BlitSurface(time,NULL,screen,&r2);
r2.x+=time->w+15;
}
if(recordings!=NULL){
//Now draw the recordings.
applySurface(r2.x,r2.y,recordingsIcon,screen,NULL);
r2.x+=25;
SDL_BlitSurface(recordings,NULL,screen,&r2);
}
//And free the surfaces.
SDL_FreeSurface(name);
SDL_FreeSurface(time);
SDL_FreeSurface(recordings);
}
void LevelPlaySelect::resize(){
//Let the LevelSelect do his stuff.
LevelSelect::resize();
//Now create our gui again.
createGUI(false);
}
void LevelPlaySelect::GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType){
//Let the level select handle his GUI events.
LevelSelect::GUIEventCallback_OnEvent(name,obj,eventType);
//Check for the play button.
if(name=="cmdPlay"){
if(selectedNumber!=NULL){
levels->setCurrentLevel(selectedNumber->getNumber());
setNextState(STATE_GAME);
//Pick music from the current music list.
getMusicManager()->pickMusic();
}
}
}
diff --git a/src/LevelPlaySelect.h b/src/LevelPlaySelect.h
index 5b3096e..4afd185 100644
--- a/src/LevelPlaySelect.h
+++ b/src/LevelPlaySelect.h
@@ -1,81 +1,85 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LEVELPLAYSELECT_H
#define LEVELPLAYSELECT_H
#include "GameState.h"
#include "LevelSelect.h"
#include "GameObjects.h"
#include "Player.h"
#include "GUIObject.h"
-#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#include <SDL_ttf/SDL_ttf.h>
+#else
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
+#endif
#include <vector>
#include <string>
//This is the LevelSelect state, here you can select levelpacks and levels.
class LevelPlaySelect : public LevelSelect{
private:
//Pointer to the play button, it is only shown when a level is selected.
GUIObject* play;
//Image of a play icon used as button to start replays.
SDL_Surface* playButtonImage;
//Image containing the time icon.
SDL_Surface* timeIcon;
//Image containing the recordings icon.
SDL_Surface* recordingsIcon;
//Method that will create the GUI elements.
//initial: Boolean if it is the first time the gui is created.
void createGUI(bool initial);
//display level info.
void displayLevelInfo(int number);
//Check where and if the mouse clicked on a number.
//If so it will start the level.
void checkMouse();
public:
//Constructor.
LevelPlaySelect();
//Destructor.
~LevelPlaySelect();
//Inherited from LevelSelect.
void refresh(bool change=true);
void selectNumber(unsigned int number,bool selected);
//Inherited from GameState.
void render();
//Inherited from GameState.
void resize();
//Inherited from LevelSelect.
void renderTooltip(unsigned int number,int dy);
//GUI events will be handled here.
void GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType);
};
#endif
diff --git a/src/LevelSelect.cpp b/src/LevelSelect.cpp
index 1bed634..5d8556e 100644
--- a/src/LevelSelect.cpp
+++ b/src/LevelSelect.cpp
@@ -1,418 +1,421 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GameState.h"
#include "Functions.h"
#include "FileManager.h"
#include "Globals.h"
#include "Objects.h"
#include "LevelSelect.h"
#include "GUIObject.h"
#include "GUIListBox.h"
#include "GUIScrollBar.h"
#include "InputManager.h"
#include "Game.h"
+#ifdef __APPLE__
+#include <SDL_ttf/SDL_ttf.h>
+#else
#include <SDL/SDL_ttf.h>
-#include <SDL/SDL.h>
+#endif
#include <stdio.h>
#include <string>
#include <sstream>
#include <iostream>
#include "libs/tinyformat/tinyformat.h"
using namespace std;
////////////////////NUMBER////////////////////////
Number::Number(){
image=NULL;
number=0;
medal=0;
selected=false;
locked=false;
//Set the default dimensions.
box.x=0;
box.y=0;
box.h=50;
box.w=50;
//Load the medals image.
medals=loadImage(getDataPath()+"gfx/medals.png");
}
Number::~Number(){
//We only need to free the SDLSurface.
if(image) SDL_FreeSurface(image);
}
void Number::init(int number,SDL_Rect box){
//First set the number and update our status.
this->number=number;
//Write our text, number+1 since the counting doens't start with 0, but with 1.
std::stringstream text;
number++;
text<<number;
//Create the text image.
SDL_Color black={0,0,0};
if(image) SDL_FreeSurface(image);
//Create the text image.
//Also check which font to use, if the number is higher than 100 use the small font.
image=TTF_RenderUTF8_Blended(fontGUI,text.str().c_str(),black);
//Set the new location of the number.
this->box.x=box.x;
this->box.y=box.y;
//Load background blocks.
objThemes.getBlock(TYPE_BLOCK,true)->createInstance(&block);
block.changeState("unlocked");
objThemes.getBlock(TYPE_SHADOW_BLOCK,true)->createInstance(&blockLocked);
blockLocked.changeState("locked");
}
void Number::init(std::string text,SDL_Rect box){
//First set the number and update our status.
this->number=-1;
//Create the text image.
SDL_Color black={0,0,0};
if(image) SDL_FreeSurface(image);
image=TTF_RenderUTF8_Blended(fontGUI,text.c_str(),black);
//Set the new location of the number.
this->box.x=box.x;
this->box.y=box.y;
//Load background blocks.
objThemes.getBlock(TYPE_BLOCK,true)->createInstance(&block);
block.changeState("unlocked");
objThemes.getBlock(TYPE_SHADOW_BLOCK,true)->createInstance(&blockLocked);
blockLocked.changeState("locked");
}
void Number::show(int dy){
//First draw the background, also apply the yOffset(dy).
if(!locked)
block.draw(screen,box.x,box.y-dy);
else
blockLocked.draw(screen,box.x,box.y-dy);
//Now draw the text image over the background.
//We draw it centered inside the box.
applySurface((box.x+25-(image->w/2)),box.y-dy,image,screen,NULL);
//Draw the selection mark.
if(selected){
drawGUIBox(box.x,box.y-dy,50,50,screen,0xFFFFFF23);
}
//Draw the medal.
if(medal>0){
SDL_Rect r={(medal-1)*30,0,30,30};
applySurface(box.x+30,(box.y+30)-dy,medals,screen,&r);
}
}
void Number::setLocked(bool locked){
this->locked=locked;
}
void Number::setMedal(int medal){
this->medal=medal;
}
/////////////////////LEVEL SELECT/////////////////////
LevelSelect::LevelSelect(string titleText,LevelPackManager::LevelPackLists packType){
//clear the selected level
selectedNumber=NULL;
//Calculate the LEVELS_PER_ROW and LEVEL_ROWS if they aren't calculated already.
calcRows();
//Render the title.
title=TTF_RenderUTF8_Blended(fontTitle,titleText.c_str(),themeTextColor);
//create GUI (test only)
GUIObject* obj;
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
GUIObjectRoot=new GUIObject(0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
//the level select scroll bar
levelScrollBar=new GUIScrollBar(SCREEN_WIDTH*0.9,184,16,SCREEN_HEIGHT-344,ScrollBarVertical,0,0,0,1,4,true,false);
GUIObjectRoot->addChild(levelScrollBar);
//level pack description
levelpackDescription=new GUIObject(0,140,SCREEN_WIDTH,32,GUIObjectLabel,"",0,true,true,GUIGravityCenter);
GUIObjectRoot->addChild(levelpackDescription);
levelpacks=new GUISingleLineListBox((SCREEN_WIDTH-500)/2,104,500,32);
levelpacks->name="cmdLvlPack";
levelpacks->eventCallback=this;
vector<string> v=getLevelPackManager()->enumLevelPacks(packType);
levelpacks->item=v;
levelpacks->value=0;
//Check if we can find the lastlevelpack.
for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
if(*i==getSettings()->getValue("lastlevelpack")){
levelpacks->value=i-v.begin();
}
}
//Get the name of the selected levelpack.
string levelpackName=levelpacks->item[levelpacks->value];
string s1=getUserPath(USER_DATA)+"progress/"+levelpackName+".progress";
//Load the progress.
levels=getLevelPackManager()->getLevelPack(v[levelpacks->value]);
levels->loadProgress(s1);
//And add the levelpack single line listbox to the GUIObjectRoot.
GUIObjectRoot->addChild(levelpacks);
obj=new GUIObject(20,20,-1,32,GUIObjectButton,_("Back"));
obj->name="cmdBack";
obj->eventCallback=this;
GUIObjectRoot->addChild(obj);
section=1;
}
LevelSelect::~LevelSelect(){
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
levelScrollBar=NULL;
levelpackDescription=NULL;
selectedNumber=NULL;
//Free the rendered title surface.
SDL_FreeSurface(title);
}
void LevelSelect::calcRows(){
//Calculate the number of rows and the number of levels per row.
LEVELS_PER_ROW=(SCREEN_WIDTH*0.8)/64;
int LEVEL_ROWS=(SCREEN_HEIGHT-344)/64;
LEVELS_DISPLAYED_IN_SCREEN=LEVELS_PER_ROW*LEVEL_ROWS;
}
void LevelSelect::selectNumberKeyboard(int x,int y){
if(section==2){
//Move selection
int realNumber=0;
if(selectedNumber)
realNumber=selectedNumber->getNumber()+x+(y*LEVELS_PER_ROW);
//If selection is outside of the map grid, change section
if(realNumber<0 || realNumber>(int)numbers.size()-1){
section=1;
for(int i=0;i<levels->getLevelCount();i++){
numbers[i].selected=false;
refresh();
}
}else{
//If not, move selection
if(!numbers[realNumber].getLocked()){
for(int i=0;i<levels->getLevelCount();i++){
numbers[i].selected=(i==realNumber);
}
selectNumber(realNumber,false);
}
}
}else if(section==1){
//Loop through levelpacks and update GUI
levelpacks->value+=x;
if(levelpacks->value<0){
levelpacks->value=levelpacks->item.size()-1;
}else if(levelpacks->value>(int)levelpacks->item.size()-1){
levelpacks->value=0;
}
GUIEventCallback_OnEvent("cmdLvlPack",static_cast<GUIObject*>(levelpacks),0);
//If up is pressed, change section
if(y==1){
section=2;
selectNumber(0,false);
numbers[0].selected=true;
}
}else{
section=clamp(section+y,0,2);
}
}
void LevelSelect::handleEvents(){
//Check for an SDL_QUIT event.
if(event.type==SDL_QUIT){
setNextState(STATE_EXIT);
}
//Check for a mouse click.
if(event.type==SDL_MOUSEBUTTONUP && event.button.button==SDL_BUTTON_LEFT){
checkMouse();
}
//Check focus movement
if(inputMgr.isKeyDownEvent(INPUTMGR_RIGHT)){
selectNumberKeyboard(1,0);
}else if(inputMgr.isKeyDownEvent(INPUTMGR_LEFT)){
selectNumberKeyboard(-1,0);
}else if(inputMgr.isKeyDownEvent(INPUTMGR_UP)){
selectNumberKeyboard(0,-1);
}else if(inputMgr.isKeyDownEvent(INPUTMGR_DOWN)){
selectNumberKeyboard(0,1);
}
//Check if enter is pressed
if(section==2 && inputMgr.isKeyUpEvent(INPUTMGR_SELECT)){
selectNumber(selectedNumber->getNumber(),true);
}
//Check if escape is pressed.
if(inputMgr.isKeyUpEvent(INPUTMGR_ESCAPE)){
setNextState(STATE_MENU);
}
//Check for scrolling down and up.
if(event.type==SDL_MOUSEBUTTONDOWN && event.button.button==SDL_BUTTON_WHEELDOWN && levelScrollBar){
if(levelScrollBar->value<levelScrollBar->maxValue) levelScrollBar->value++;
return;
}else if(event.type==SDL_MOUSEBUTTONDOWN && event.button.button==SDL_BUTTON_WHEELUP && levelScrollBar){
if(levelScrollBar->value>0) levelScrollBar->value--;
return;
}
}
void LevelSelect::checkMouse(){
int x,y,dy=0,m=numbers.size();
//Get the current mouse location.
SDL_GetMouseState(&x,&y);
//Check if there's a scrollbar, if so get the value.
if(levelScrollBar)
dy=levelScrollBar->value;
//Upper bound of levels we'd like to display.
if(m>dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN)
m=dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN;
y+=dy*64;
SDL_Rect mouse={x,y,0,0};
for(int n=dy*LEVELS_PER_ROW; n<m; n++){
if(!numbers[n].getLocked()){
if(checkCollision(mouse,numbers[n].box)==true){
if(numbers[n].selected){
selectNumber(n,true);
}else{
//Select current level
for(int i=0;i<levels->getLevelCount();i++){
numbers[i].selected=(i==n);
}
selectNumber(n,false);
}
section=2;
break;
}
}
}
}
void LevelSelect::logic(){}
void LevelSelect::render(){
int x,y,dy=0,m=numbers.size();
int idx=-1;
//Get the current mouse location.
SDL_GetMouseState(&x,&y);
if(levelScrollBar)
dy=levelScrollBar->value;
//Upper bound of levels we'd like to display.
if(m>dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN)
m=dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN;
y+=dy*64;
SDL_Rect mouse={x,y,0,0};
//Draw background.
objThemes.getBackground(true)->draw(screen);
objThemes.getBackground(true)->updateAnimation();
//Draw the title.
applySurface((SCREEN_WIDTH-title->w)/2,40-TITLE_FONT_RAISE,title,screen,NULL);
//Loop through the level blocks and draw them.
for(int n=dy*LEVELS_PER_ROW;n<m;n++){
numbers[n].show(dy*64);
if(numbers[n].getLocked()==false && checkCollision(mouse,numbers[n].box)==true)
idx=n;
}
//Show the tool tip text.
if(idx>=0){
renderTooltip(idx,dy);
}
}
void LevelSelect::resize(){
calcRows();
refresh(false);
//NOTE: We don't need to recreate the listbox and the back button, only resize the list.
levelpacks->left=(SCREEN_WIDTH-500)/2;
levelpackDescription->width = SCREEN_WIDTH;
}
void LevelSelect::GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType){
string s;
if(name=="cmdLvlPack"){
getSettings()->setValue("lastlevelpack",static_cast<GUISingleLineListBox*>(obj)->item[obj->value]);
}else if(name=="cmdBack"){
setNextState(STATE_MENU);
return;
}else{
return;
}
//new: reset the level list scroll bar
if(levelScrollBar)
levelScrollBar->value=0;
string s1=getUserPath(USER_DATA)+"progress/"+static_cast<GUISingleLineListBox*>(obj)->item[obj->value]+".progress";
levels=getLevelPackManager()->getLevelPack(static_cast<GUISingleLineListBox*>(obj)->item[obj->value]);
//Load the progress file.
levels->loadProgress(s1);
//And refresh the numbers.
refresh();
}
diff --git a/src/LevelSelect.h b/src/LevelSelect.h
index 9a484c9..abe3407 100644
--- a/src/LevelSelect.h
+++ b/src/LevelSelect.h
@@ -1,167 +1,171 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LEVELSELECT_H
#define LEVELSELECT_H
#include "GameState.h"
#include "GameObjects.h"
#include "Player.h"
#include "GUIObject.h"
#include "GUIScrollBar.h"
#include "GUIListBox.h"
-#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#include <SDL_ttf/SDL_ttf.h>
+#else
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
+#endif
#include <vector>
#include <string>
//Class that represents a level in the levelselect menu.
class Number{
private:
//The background image of the number.
ThemeBlockInstance block;
//The background image of the number when it's locked.
ThemeBlockInstance blockLocked;
//The (text) image of the number.
SDL_Surface* image;
//Image containing the three stars a player can earn.
SDL_Surface* medals;
//The number (or text).
int number;
//Integer containing the medal the player got.
//0 = none, 1 = bronze, 2 = silver, 3 = gold
int medal;
//Boolean if the number is locked or not.
bool locked;
public:
//The location and size of the number.
SDL_Rect box;
//If the Number is selected then we draw something indicates it.
bool selected;
//Constructor.
Number();
//Destructor.
~Number();
//Method used for initialising the number.
//number: The number.
//box: The location and size of the number.
void init(int number,SDL_Rect box);
//Method used for initialising the number.
//text: The caption of the number.
//box: The location and size of the number.
void init(std::string text,SDL_Rect box);
//get current number.
inline int getNumber(){return number;}
//Method used to set the locked status of the number.
//locked: Boolean if it should be locked or not.
void setLocked(bool locked=true);
//Method used to retrieve the locked status of the number.
//Returns: True if the number is locked.
inline bool getLocked(){return locked;}
//Method used to set the medal for this number.
//medal: The new medal for this number.
void setMedal(int medal);
//Method that is used to draw the number.
//dy: The y offset.
void show(int dy);
};
//This is the LevelSelect state, here you can select levelpacks and levels.
class LevelSelect : public GameState,public GUIEventCallback{
protected:
//Surface containing the title.
SDL_Surface* title;
//Vector containing the numbers.
std::vector<Number> numbers;
//Contains selected level number (displayed at bottom left corner).
//If it's NULL then nothing selected.
Number* selectedNumber;
//Pointer to the scrollbar.
GUIScrollBar* levelScrollBar;
//Pointer to the description.
GUIObject* levelpackDescription;
//Pointer to the levelpack list.
GUISingleLineListBox* levelpacks;
//Check where and if the mouse clicked on a number.
//If so select that number.
virtual void checkMouse();
//Selected section for keyboard/gamepad control
int section;
//The number of blocks in a row.
int LEVELS_PER_ROW;
//The number of levels displayed on screen at once.
int LEVELS_DISPLAYED_IN_SCREEN;
public:
//Constructor.
//titleText: The title that is shown at the top of the screen.
//packType: The type of levelpacks that should be listed (See LevelPackManager.h).
LevelSelect(std::string titleText,LevelPackManager::LevelPackLists packType=LevelPackManager::ALL_PACKS);
//Destructor.
virtual ~LevelSelect();
//Method that will calculate the number of rows and the number of levels per row.
void calcRows();
//Method used to update the numbers and the scrollbar.
//change: Boolean if the levelpack changed, if not only the numbers need to be replaced.
virtual void refresh(bool change=true)=0;
//Method that is called when a number is selected.
//number: The selected number.
//selected: Boolean if the number was already selected.
virtual void selectNumber(unsigned int number,bool selected)=0;
//Used for keyboard/gamepad navigation
void selectNumberKeyboard(int x,int y);
//Inherited from GameState.
void handleEvents();
void logic();
void render();
void resize();
//Method that is called to render the tooltip.
//number: The number that the tooltip should be drawn for.
//dy: The y offset of the number, used to draw the tooltip in the right place.
virtual void renderTooltip(unsigned int number,int dy)=0;
//GUI events will be handled here.
virtual void GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType)=0;
};
#endif
diff --git a/src/Main.cpp b/src/Main.cpp
index 80e524e..5be3bd2 100644
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -1,237 +1,240 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Functions.h"
#include "Timer.h"
#include "Objects.h"
#include "Globals.h"
#include "TitleMenu.h"
#include "GUIObject.h"
#include "InputManager.h"
#include "MD5.h"
#include "StatisticsManager.h"
#include <SDL/SDL.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#ifdef HARDWARE_ACCELERATION
#include <GL/gl.h>
#include <GL/glu.h>
#endif
//Variables for recording.
//To enable picture recording uncomment the next line:
//#define RECORD_PICUTRE_SEQUENCE
#ifdef RECORD_PICUTRE_SEQUENCE
bool recordPictureSequence=false;
int recordPictureIndex=0;
#endif
-
+#ifdef __APPLE__
+int SDL_main(int argc, char** argv) {
+#else
int main(int argc, char** argv) {
+#endif
#ifdef _MSC_VER
//Fix the non-latin file name bug under Visual Studio
setlocale(LC_ALL,"");
#endif
//First parse the comand line arguments.
int s=parseArguments(argc,argv);
if(s==-1){
printf("Usage: %s [OPTIONS] ...\n",argv[0]);
printf("%s","Available options:\n");
printf(" %-5s%-30s %s\n","","--data-dir <dir>","Specifies the data directory.");
printf(" %-5s%-30s %s\n","","--user-dir <dir>","Specifies the user preferences directory.");
printf(" %-5s%-30s %s\n","-f,","--fullscreen","Run the game fullscreen.");
printf(" %-5s%-30s %s\n","-w,","--windowed","Run the game windowed.");
printf(" %-5s%-30s %s\n","-mv,","--music <volume>","Set the music volume.");
printf(" %-5s%-30s %s\n","-sv,","--sound <volume>","Set the sound volume.");
printf(" %-5s%-30s %s\n","-s,","--set <setting> <value>","Change a setting to a given value.");
printf(" %-5s%-30s %s\n","-v,","--version","Display the version and quit.");
printf(" %-5s%-30s %s\n","-h,","--help","Display this help message.");
return 0;
}else if(s==0){
return 0;
}
//Try to configure the dataPath, userPath, etc...
if(configurePaths()==false){
fprintf(stderr,"FATAL ERROR: Failed to configure paths.\n");
return 1;
}
//Load the settings.
if(loadSettings()==false){
fprintf(stderr,"FATAL ERROR: Failed to load config file.\n");
return 1;
}
//Initialise some stuff like SDL, the window, SDL_Mixer.
if(init()==false) {
fprintf(stderr,"FATAL ERROR: Failed to initalize game.\n");
return 1;
}
//Load some important files like the background music, default theme.
if(loadFiles()==false){
fprintf(stderr,"FATAL ERROR: Failed to load necessary files.\n");
return 1;
}
//Set the currentState id to the main menu and create it.
stateID=STATE_MENU;
currentState=new Menu();
//Seed random.
srand((unsigned)time(NULL));
//Set the fadeIn value to zero.
int fadeIn=0;
//Keep the last resize event, this is to only process one.
SDL_Event lastResize={};
//Start the game loop.
while(stateID!=STATE_EXIT){
//We start the timer.
FPS.start();
//Loop the SDL events.
while(SDL_PollEvent(&event)){
//Check if user resizes the window.
if(event.type==SDL_VIDEORESIZE){
lastResize=event;
//Don't let other objects process this event (?)
continue;
}
//Check if the fullscreen toggle shortcut is pressed (Alt+Enter).
if(event.type==SDL_KEYUP && event.key.keysym.sym==SDLK_RETURN && (event.key.keysym.mod & KMOD_ALT)){
getSettings()->setValue("fullscreen",getSettings()->getBoolValue("fullscreen")?"0":"1");
//We need to create a new screen.
if(!createScreen()){
//Screen creation failed so set to safe settings.
getSettings()->setValue("fullscreen","0");
getSettings()->setValue("width","800");
getSettings()->setValue("height","600");
//Try it with the safe settings.
if(!createScreen()){
//Everything fails so quit.
setNextState(STATE_EXIT);
cerr<<"ERROR: Unable to create screen."<<endl;
}
}
//The screen is created, now load the (menu) theme.
if(!loadTheme("")){
//Loading the theme failed so quit.
setNextState(STATE_EXIT);
cerr<<"ERROR: Unable to load theme after toggling fullscreen."<<endl;
}
//Don't let other objects process this event.
continue;
}
#ifdef RECORD_PICUTRE_SEQUENCE
if(event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_F10){
recordPictureSequence=!recordPictureSequence;
printf("Record Picture Sequence %s\n",recordPictureSequence?"ON":"OFF");
}
#endif
//Let the input manager handle the events.
inputMgr.updateState(true);
//Let the currentState handle the events.
currentState->handleEvents();
//Also pass the events to the GUI.
GUIObjectHandleEvents();
}
//Process the resize event.
if(lastResize.type==SDL_VIDEORESIZE){
event=lastResize;
onVideoResize();
//After resize we erase the event type
lastResize.type=SDL_NOEVENT;
}
//maybe we should add a check here (??) to fix some bugs (ticket #47)
if(nextState!=STATE_NULL){
fadeIn=17;
changeState();
}
if(stateID==STATE_EXIT) break;
//update input state (??)
inputMgr.updateState(false);
//Now it's time for the state to do his logic.
currentState->logic();
currentState->render();
//TODO: Shouldn't the gamestate take care of rendering the GUI?
if(GUIObjectRoot) GUIObjectRoot->render();
//draw new achievements (if any)
statsMgr.render();
//draw fading effect
if(fadeIn>0&&fadeIn<255){
SDL_BlitSurface(screen,NULL,tempSurface,NULL);
SDL_FillRect(screen,NULL,0);
SDL_SetAlpha(tempSurface, SDL_SRCALPHA, fadeIn);
SDL_BlitSurface(tempSurface,NULL,screen,NULL);
fadeIn+=17;
}
#ifdef RECORD_PICUTRE_SEQUENCE
if(recordPictureSequence){
char s[64];
recordPictureIndex++;
sprintf(s,"pic%08d.bmp",recordPictureIndex);
printf("Save screen to %s\n",s);
SDL_SaveBMP(screen,(getUserPath(USER_CACHE)+s).c_str());
}
#endif
//And draw the screen surface to the actual screen.
flipScreen();
//Check if nextState is set, meaning we should fade in and change state.
if(nextState!=STATE_NULL){
fadeIn=17;
changeState();
}
//Now calcualte how long we need to wait to keep a constant framerate.
int t=FPS.getTicks();
t=(1000/g_FPS)-t;
if(t>0){
SDL_Delay(t);
}
}
//The game has ended, save the settings just to be sure.
saveSettings();
//Clean everything up.
clean();
//End of program.
return 0;
}
diff --git a/src/MusicManager.h b/src/MusicManager.h
index a488a0f..3f530c2 100644
--- a/src/MusicManager.h
+++ b/src/MusicManager.h
@@ -1,141 +1,145 @@
/*
* Copyright (C) 2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MUSICMANAGER_H
#define MUSICMANAGER_H
#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#else
#include <SDL/SDL_mixer.h>
+#endif
#include <string>
#include <map>
#include <vector>
//Class for loading and playing the music.
class MusicManager{
private:
//This structure is used to hold music information.
struct Music{
//Pointer to the actual music.
Mix_Music* music;
//Pointer to the loop music, if any.
Mix_Music* loop;
//String containing the name of the music.
//This is the same name as in the musicCollection.
std::string name;
//String containing the track name of the music.
//This is the name given by the author.
std::string trackName;
//String containing the name of the author.
std::string author;
//String containing the license the music is released under.
std::string license;
//Integer containing the time where to start playing.
int start;
//The volume to play the music with.
//Scale 0-128.
int volume;
//Integer containing the loopstart.
int loopStart;
//Integer containing the loopend.
//NOTE: loopend doesn't work and is thus ignored.
int loopEnd;
//Integer used to keep track when which music was played.
int lastTime;
};
public:
//Constructor.
MusicManager();
//Destructor.
~MusicManager();
//Destroys the music.
void destroy();
//Method that will either disable or enable music.
//enable: Boolean if the musicManager should be enabled or not.
void setEnabled(bool enable=true);
//Method that will set the volume of the music.
//NOTE: The set volume isn't presistent, only use this to update the volume after a change to the music setting.
//volume: The new volume.
void setVolume(int volume);
//This method will load one music file and add it to the collection.
//file: The filename of the music file.
//Returns: String containing the loaded music comma sperated, it's empty if it fails.
std::string loadMusic(const std::string &file);
//This method will load from a music list.
//file: The filename of the music list file.
//Returns: True if no error occurs.
bool loadMusicList(const std::string &file);
//This method will start playing a music file.
//name: The name of the song.
//fade: Boolean if it should fade the current one out or not.
void playMusic(const std::string &name,bool fade=true);
//This method will pick music from the current music list.
void pickMusic();
//Method that will be called when a music stopped.
void musicStopped();
//Set the music list.
//list: The name of the list.
void setMusicList(const std::string &list);
//Method that will create credits text for the (loaded) music tracks.
//NOTE: This is only used by the Credits screen.
//Returns: A vector containing the lines of credits.
std::vector<std::string> createCredits();
private:
//Boolean if the MusicManager is enabled or not.
//The default value is false meaning that the MusicManager has to be enabled before the music starts.
bool enabled;
//Integer that is used to keep track of the last played song.
int lastTime;
//Pointer to the music struct that is currently playing.
Music* playing;
//String containing the name of the music to play when the previous one stopped.
//This means that it will be checked in the musicStopped method.
std::string nextMusic;
//String containing the name of the current music list.
std::string currentList;
//Map containing the music.
//The key is the name of the music and the value is a pointer to the Mix_Music.
std::map<std::string,Music*> musicCollection;
//Map containing the music lists.
//The key is the name of the list and the value is an array of music names.
std::map<std::string,std::vector<std::string> > musicLists;
};
#endif
diff --git a/src/Player.cpp b/src/Player.cpp
index ebfff49..6bf5e8d 100644
--- a/src/Player.cpp
+++ b/src/Player.cpp
@@ -1,1405 +1,1410 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Player.h"
#include "Game.h"
#include "Functions.h"
#include "FileManager.h"
#include "Globals.h"
#include "Objects.h"
#include "InputManager.h"
#include "StatisticsManager.h"
#include "MD5.h"
#include <iostream>
#include <fstream>
-#include <SDL/SDL_mixer.h>
#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#include <SDL_ttf/SDL_ttf.h>
+#else
+#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
+#endif
using namespace std;
#ifdef RECORD_FILE_DEBUG
string recordKeyPressLog,recordKeyPressLog_saved;
vector<SDL_Rect> recordPlayerPosition,recordPlayerPosition_saved;
#endif
Player::Player(Game* objParent):xVelBase(0),yVelBase(0),objParent(objParent){
//Set the dimensions of the player.
//The size of the player is 21x40.
box.x=0;
box.y=0;
box.w=21;
box.h=40;
//Set his velocity to zero.
xVel=0;
yVel=0;
//Set the start position.
fx=0;
fy=0;
//Set some default values.
inAir=true;
isJump=false;
onGround=true;
shadowCall=false;
shadow=false;
canMove=true;
holdingOther=false;
dead=false;
record=false;
downKeyPressed=false;
spaceKeyPressed=false;
recordIndex=-1;
#ifdef RECORD_FILE_DEBUG
recordKeyPressLog.clear();
recordKeyPressLog_saved.clear();
recordPlayerPosition.clear();
recordPlayerPosition_saved.clear();
#endif
objNotificationBlock=NULL;
//Some default values for animation variables.
direction=0;
jumpTime=0;
state=0;
//xVelSaved is used to store if there's a state saved or not.
xVelSaved=0x80000000;
}
Player::~Player(){
//Do nothing here
}
bool Player::isPlayFromRecord(){
return recordIndex>=0; // && recordIndex<(int)recordButton.size();
}
//get the game record object.
std::vector<int>* Player::getRecord(){
return &recordButton;
}
#ifdef RECORD_FILE_DEBUG
string& Player::keyPressLog(){
return recordKeyPressLog;
}
vector<SDL_Rect>& Player::playerPosition(){
return recordPlayerPosition;
}
#endif
//play the record.
void Player::playRecord(){
//TODO:
recordIndex=0;
}
void Player::spaceKeyDown(class Shadow* shadow){
//Start recording or stop, depending on the recording state.
if(record==false){
//We start recording.
if(shadow->called==true){
//The shadow is still busy so first stop him before we can start recording.
shadowCall=false;
shadow->called=false;
shadow->playerButton.clear();
}else if(!dead){
//The shadow isn't moving and we aren't dead so start recording.
record=true;
//We start a recording meaning we need to increase recordings by one.
objParent->recordings++;
}
}else{
//The player is recording so stop recording and call the shadow.
record=false;
shadowCall=true;
}
}
void Player::handleInput(class Shadow* shadow){
//Check if we should read the input from record file.
//Actually, we read input from record file in
//another function shadowSetState.
bool readFromRecord=false;
if(recordIndex>=0 && recordIndex<(int)recordButton.size()) readFromRecord=true;
if(!readFromRecord){
//Reset horizontal velocity.
xVel=0;
if(inputMgr.isKeyDown(INPUTMGR_RIGHT)){
//Walking to the right.
xVel+=7;
}
if(inputMgr.isKeyDown(INPUTMGR_LEFT)){
//Walking to the left.
xVel-=7;
}
//Check if a key has been released.
if(/*event.type==SDL_KEYUP || */!inputMgr.isKeyDown(INPUTMGR_ACTION)){
//It has so downKeyPressed can't be true.
downKeyPressed=false;
}
/*
//Don't reset spaceKeyPressed or when you press the space key
//and release another key then the bug occurs. (ticket #44)
if(event.type==SDL_KEYUP || !inputMgr.isKeyDown(INPUTMGR_SPACE)){
spaceKeyPressed=false;
}*/
}
//Check if a key is pressed (down).
if(inputMgr.isKeyDownEvent(INPUTMGR_JUMP) && !readFromRecord){
//The up key, if we aren't in the air we start jumping.
//Fixed a potential bug
if(!inAir && !isJump){
#ifdef RECORD_FILE_DEBUG
char c[64];
sprintf(c,"[%05d] Jump key pressed\n",objParent->time);
cout<<c;
recordKeyPressLog+=c;
#endif
isJump=true;
}
}else if(inputMgr.isKeyDownEvent(INPUTMGR_SPACE) && !readFromRecord){
//Fixed a potential bug
if(!spaceKeyPressed){
#ifdef RECORD_FILE_DEBUG
char c[64];
sprintf(c,"[%05d] Space key pressed\n",objParent->time);
cout<<c;
recordKeyPressLog+=c;
#endif
spaceKeyDown(shadow);
spaceKeyPressed=true;
}
}else if(record && !readFromRecord && inputMgr.isKeyDownEvent(INPUTMGR_CANCELRECORDING)){
//Cancel current recording
//Search the recorded button and clear the last space key press
int i=recordButton.size()-1;
for(;i>=0;i--){
if(recordButton[i] & PlayerButtonSpace){
recordButton[i] &= ~PlayerButtonSpace;
break;
}
}
if(i>=0){
//Clear the recording at the player's side.
playerButton.clear();
line.clear();
//reset the record flag
record=false;
//decrese the record count
objParent->recordings--;
}else{
cout<<"Failed to find last recording"<<endl;
}
}else if(inputMgr.isKeyDownEvent(INPUTMGR_ACTION)){
//Downkey is pressed.
//Fixed a potential bug
if(!downKeyPressed){
#ifdef RECORD_FILE_DEBUG
char c[64];
sprintf(c,"[%05d] Action key pressed\n",objParent->time);
cout<<c;
recordKeyPressLog+=c;
#endif
downKeyPressed=true;
}
}else if(inputMgr.isKeyDownEvent(INPUTMGR_SAVE)){
//F2 only works in the level editor.
if(!(dead || shadow->dead) && stateID==STATE_LEVEL_EDITOR){
//Save the state. (delayed)
if(objParent)
objParent->saveStateNextTime=true;
}
}else if(inputMgr.isKeyDownEvent(INPUTMGR_LOAD) && !readFromRecord){
//F3 is used to load the last state.
if(objParent)
objParent->loadStateNextTime=true;
}else if(inputMgr.isKeyDownEvent(INPUTMGR_SWAP)){
//F4 will swap the player and the shadow, but only in the level editor.
if(!(dead || shadow->dead) && stateID==STATE_LEVEL_EDITOR){
swapState(shadow);
}
}else if(inputMgr.isKeyDownEvent(INPUTMGR_TELEPORT)){
//F5 will revive and teleoprt the player to the cursor. Only works in the level editor.
//Shift+F5 teleports the shadow.
if(stateID==STATE_LEVEL_EDITOR){
//get the position of the cursor.
int x,y;
SDL_GetMouseState(&x,&y);
x+=camera.x;
y+=camera.y;
if(inputMgr.isKeyDown(INPUTMGR_SHIFT)){
//teleports the shadow.
shadow->dead=false;
shadow->box.x=x;
shadow->box.y=y;
}else{
//teleports the player.
dead=false;
box.x=x;
box.y=y;
}
//play sound?
if(getSettings()->getBoolValue("sound")){
Mix_PlayChannel(-1,swapSound,0);
}
}
}else if(inputMgr.isKeyDownEvent(INPUTMGR_SUICIDE)){
//F12 is suicide and only works in the leveleditor.
if(stateID==STATE_LEVEL_EDITOR){
die();
shadow->die();
}
}
}
void Player::setPosition(int x,int y){
box.x=x;
box.y=y;
}
void Player::move(vector<GameObject*> &levelObjects){
//Pointer to a checkpoint.
GameObject* objCheckPoint=NULL;
//Pointer to a swap.
GameObject* objSwap=NULL;
//Set the objShadowBlock to NULL.
//Only for swapping to prevent the shadow from swapping in a shadow block.
objShadowBlock=NULL;
//Set the objNotificationBlock to NULL.
objNotificationBlock=NULL;
//Boolean if the player can teleport.
bool canTeleport=true;
//Set the object the player is currently standing to NULL.
objCurrentStand=NULL;
//Check if the player is still alive.
if(dead==false){
//Add gravity
if(inAir==true){
yVel+=1;
//Cap fall speed to 13.
if(yVel>13){
yVel=13;
}
}
//Boolean if the player is moved, used for squash detection.
bool playerMoved=false;
//The current location of the player, used to set the player back if he's squashed to prevent displacement.
int lastX=box.x;
int lastY=box.y;
//Check if the player can move.
if(canMove==true){
//Check if the player is moving or not.
if(xVel>0){
direction=0;
onGround=false;
if(appearance.currentStateName!="walkright"){
appearance.changeState("walkright");
}
}else if(xVel<0){
direction=1;
onGround=false;
if(appearance.currentStateName!="walkleft"){
appearance.changeState("walkleft");
}
}else if(xVel==0){
onGround=true;
if(direction==1){
appearance.changeState("standleft");
}else{
appearance.changeState("standright");
}
}
//Move the player.
box.x+=xVel;
//Loop through the levelobjects.
for(unsigned int o=0; o<levelObjects.size(); o++){
//Check if the player can walk on the object.
if(levelObjects[o]->queryProperties(GameObjectProperty_PlayerCanWalkOn,this)){
//Get the collision box of the levelobject.
SDL_Rect r=levelObjects[o]->getBox();
//Check collision with the player.
if(checkCollision(box,r)){
//We have collision, get the velocity of the box.
SDL_Rect v=levelObjects[o]->getBox(BoxType_Delta);
//Check on which side of the box the player is.
if(box.x + box.w/2 <= r.x + r.w/2){
//The left side of the block.
if(xVel+xVelBase>v.x){
if(box.x>r.x-box.w){
box.x=r.x-box.w;
playerMoved=true;
}
}
}else{
//The right side of the block.
if(xVel+xVelBase<v.x){
if(box.x<r.x+r.w){
box.x=r.x+r.w;
playerMoved=true;
}
}
}
}
}
}
}
//Now apply the yVel. (gravity, jumping, etc..)
box.y+=yVel;
//Pointer to the object the player standed on.
GameObject* lastStand=NULL;
//???
inAir=true;
canMove=true;
//Loop through all the levelObjects.
for(unsigned int o=0; o<levelObjects.size(); o++){
//Check if the object is solid.
if(levelObjects[o]->queryProperties(GameObjectProperty_PlayerCanWalkOn,this)){
SDL_Rect r=levelObjects[o]->getBox();
if(checkCollision(r,box)==true){ //TODO:fix some bug
SDL_Rect v=levelObjects[o]->getBox(BoxType_Delta);
if(box.y+box.h/2<=r.y+r.h/2){
if(yVel>=v.y || yVel>=0){
inAir=false;
box.y=r.y-box.h;
yVel=1; //???
lastStand=levelObjects[o];
lastStand->onEvent(GameObjectEvent_PlayerIsOn);
//The player is moved, if it's a moving block check for squating.
if(v.y!=0){
playerMoved=true;
}
}
}else{
//FIXME: The player can have a yVel of 0 and get squashed if he is standing on the other.
bool holding=objParent->shadow.holdingOther;
if(shadow)
holding=objParent->player.holdingOther;
if(yVel<=v.y+1 || holding){
yVel=v.y>0?v.y:0;
if(box.y<r.y+r.h){
if(!holding)
box.y=r.y+r.h;
//The player is moved, if it's a moving block check for squating.
if(v.y!=0){
playerMoved=true;
}
}
}
}
}
}
//Check if the object is a checkpoint.
if(levelObjects[o]->type==TYPE_CHECKPOINT && checkCollision(box,levelObjects[o]->getBox())){
//If we're not the shadow set the gameTip to Checkpoint.
if(!shadow && objParent!=NULL)
objParent->gameTipIndex=TYPE_CHECKPOINT;
//And let objCheckPoint point to this object.
objCheckPoint=levelObjects[o];
}
//Check if the object is a swap.
if(levelObjects[o]->type==TYPE_SWAP && checkCollision(box,levelObjects[o]->getBox())){
//If we're not the shadow set the gameTip to swap.
if(!shadow && objParent!=NULL)
objParent->gameTipIndex=TYPE_SWAP;
//And let objSwap point to this object.
objSwap=levelObjects[o];
}
//Check if the object is an exit.
//This doesn't work if the state is Level editor.
if(levelObjects[o]->type==TYPE_EXIT && stateID!=STATE_LEVEL_EDITOR && checkCollision(box,levelObjects[o]->getBox())){
//Check to see if we have enough keys to finish the level
if (objParent->currentCollectables>=objParent->totalCollectables){
//We can't just handle the winning here (in the middle of the update cycle)/
//So set won in Game true.
objParent->won=true;
}
}
//Check if the object is a portal.
if(levelObjects[o]->type==TYPE_PORTAL && checkCollision(box,levelObjects[o]->getBox())){
//Check if the teleport id isn't empty.
if((dynamic_cast<Block*>(levelObjects[o]))->id.empty()){
cerr<<"Warning: Invalid teleport id!"<<endl;
canTeleport=false;
}
//If we're not the shadow set the gameTip to portal.
if(!shadow && objParent!=NULL)
objParent->gameTipIndex=TYPE_PORTAL;
//Check if we can teleport and should (downkey -or- auto).
if(canTeleport && (downKeyPressed || (levelObjects[o]->queryProperties(GameObjectProperty_Flags,this)&1))){
canTeleport=false;
if(downKeyPressed || levelObjects[o]!=objLastTeleport){
downKeyPressed=false;
//Loop the levelobjects again to find the destination.
for(unsigned int oo=o+1;;){
//We started at our index+1.
//Meaning that if we reach the end of the vector then we need to start at the beginning.
if(oo>=levelObjects.size())
oo-=(int)levelObjects.size();
//It also means that if we reach the same index we need to stop.
//If the for loop breaks this way then we have no succes.
if(oo==o){
//Couldn't teleport so play the error sound.
if(getSettings()->getBoolValue("sound")){
Mix_PlayChannel(-1,errorSound,0);
}
break;
}
//Check if the second (oo) object is a portal.
if(levelObjects[oo]->type==TYPE_PORTAL){
//Check the id against the destination of the first portal.
if((dynamic_cast<Block*>(levelObjects[o]))->destination==(dynamic_cast<Block*>(levelObjects[oo]))->id){
//Call the event.
levelObjects[o]->onEvent(GameObjectEvent_OnToggle);
objLastTeleport=levelObjects[oo];
//Get the destination location and teleport the player.
SDL_Rect r=levelObjects[oo]->getBox();
box.x=r.x+5;
box.y=r.y+2;
//Check if music/sound is enabled.
if(getSettings()->getBoolValue("sound")){
Mix_PlayChannel(-1,swapSound,0);
}
break;
}
}
//Increase oo.
oo++;
}
}
}
}
//Check if the object is a switch.
if(levelObjects[o]->type==TYPE_SWITCH && checkCollision(box,levelObjects[o]->getBox())){
//If we're not the shadow set the gameTip to switch.
if(!shadow && objParent!=NULL)
objParent->gameTipIndex=TYPE_SWITCH;
//If the down key is pressed then invoke an event.
if(downKeyPressed){
//Play the animation.
levelObjects[o]->playAnimation(1);
//Check if sound is enabled, if so play the toggle sound.
if(getSettings()->getBoolValue("sound")==true){
Mix_PlayChannel(-1,toggleSound,0);
}
if(objParent!=NULL){
//Make sure that the id isn't emtpy.
if(!(dynamic_cast<Block*>(levelObjects[o]))->id.empty()){
objParent->broadcastObjectEvent(0x10000 | (levelObjects[o]->queryProperties(GameObjectProperty_Flags,this)&3),
-1,(dynamic_cast<Block*>(levelObjects[o]))->id.c_str());
}else{
cerr<<"Warning: invalid switch id!"<<endl;
}
}
}
}
//Check if the object is a shadow block, only if we are the player.
if((levelObjects[o]->type==TYPE_SHADOW_BLOCK || levelObjects[o]->type==TYPE_MOVING_SHADOW_BLOCK) && checkCollision(box,levelObjects[o]->getBox()) && !shadow){
objShadowBlock=levelObjects[o];
}
//Check if the object is a notification block, only if we are the player.
if(levelObjects[o]->type==TYPE_NOTIFICATION_BLOCK && checkCollision(box,levelObjects[o]->getBox()) && !shadow){
objNotificationBlock=levelObjects[o];
}
//Check if the object is a collectable
if(levelObjects[o]->type==TYPE_COLLECTABLE && checkCollision(box,levelObjects[o]->getBox())){
//Check if collectable is active (if it's not it's equal to 1(inactive))
if (levelObjects[o]->queryProperties(GameObjectProperty_Flags, this)==0) {
//Toggle an event
levelObjects[o]->onEvent(GameObjectEvent_OnToggle);
//Increase the current number of collectables
objParent->currentCollectables++;
if(getSettings()->getBoolValue("sound"))
Mix_PlayChannel(-1,collectSound,0);
//Open exit(s)
if (objParent->currentCollectables>=objParent->totalCollectables){
for(unsigned int i=0;i<levelObjects.size();i++){
if(levelObjects[i]->type==TYPE_EXIT){
Block *obj=dynamic_cast<Block*>(levelObjects[i]);
if(obj!=NULL){
levelObjects[i]->onEvent(GameObjectEvent_OnSwitchOn);
}
}
}
}
}
}
//Check if the object is deadly.
if(levelObjects[o]->queryProperties(GameObjectProperty_IsSpikes,this)){
//It is so get the collision box.
SDL_Rect r=levelObjects[o]->getBox();
//TODO: pixel-accuracy hit test.
//For now we shrink the box.
r.x+=2;
r.y+=2;
r.w-=4;
r.h-=4;
//Check collision, if the player collides then let him die.
if(checkCollision(box,r)){
//Now make sure we don't collide with a different block.
for(unsigned int oo=o+1;;){
//We started at our index+1.
//Meaning that if we reach the end of the vector then we need to start at the beginning.
if(oo>=levelObjects.size())
oo-=(int)levelObjects.size();
//It also means that if we reach the same index we need to stop.
//If the for loop breaks this way then we have no succes.
if(oo==o){
//Nothing found so call the die method.
die();
break;
}
//Check if the second (oo) object is a block.
if(levelObjects[oo]->queryProperties(GameObjectProperty_PlayerCanWalkOn,this)){
//Get the collision box.
SDL_Rect r2=levelObjects[oo]->getBox();
if(checkCollision(box,r2)){
//Check if the top isn't covered.
if(r2.y>r.y){
//It isn't covered so create a box for collision detection
SDL_Rect tmp={r2.x,r2.y,r2.w,r2.y-r.y};
if(checkCollision(box,tmp)){
//We hit spikes so die?
die();
break;
}
}
//Check if the left side isn't covered.
if(r2.x>r.x){
//It isn't covered so create a box for collision detection
SDL_Rect tmp={r2.x,r2.y,r2.x-r.x,r2.h};
if(checkCollision(box,tmp)){
//We hit spikes so die?
die();
break;
}
}
//Check if the right side isn't covered.
if(r2.x+r2.w>r.x+r.w){
//It isn't covered so create a box for collision detection
SDL_Rect tmp={r.x+r.w,r2.y,(r2.x+r2.w)-(r.x+r.w),r2.h};
if(checkCollision(box,tmp)){
//We hit spikes so die?
die();
break;
}
}
//Check if the bottom isn't covered.
if(r2.y+r2.h>r.y+r.h){
//It isn't covered so create a box for collision detection
SDL_Rect tmp={r2.x,r.y+r.h,r2.w,(r2.y+r2.h)-(r.y+r.h)};
if(checkCollision(box,tmp)){
//We hit spikes so die?
die();
break;
}
}
//Check collision with the player and the block and with the block and the spikes.
if(checkCollision(box,r)){
//We break the loop to prevent going round (and calling the die() method).
break;
}
}
}
//Increase oo.
oo++;
}
}
}
}
//Check if the player was moved, if so check if the player is squashed.
if(playerMoved){
for(unsigned int o=0;o<levelObjects.size();o++){
SDL_Rect r2=levelObjects[o]->getBox();
if(levelObjects[o]->queryProperties(GameObjectProperty_PlayerCanWalkOn,this) && checkCollision(box,r2)){
//The player is squashed so first move him back.
box.x=lastX;
box.y=lastY;
//Update statistics.
if(!dead && !objParent->player.isPlayFromRecord() && !objParent->interlevel){
if(shadow) statsMgr.shadowSquashed++;
else statsMgr.playerSquashed++;
switch(statsMgr.playerSquashed+statsMgr.shadowSquashed){
case 1:
statsMgr.newAchievement("squash1");
break;
case 50:
statsMgr.newAchievement("squash50");
break;
}
}
//Now call the die method.
die();
}
}
}
//Check if the player fell of the level, if so let him die but without animation.
if(box.y>LEVEL_HEIGHT)
die(false);
//Check if the player changed blocks, meaning stepped onto a block.
objCurrentStand=lastStand;
if(lastStand!=objLastStand){
objLastStand=lastStand;
if(lastStand){
//Call the walk on event of the laststand.
lastStand->onEvent(GameObjectEvent_PlayerWalkOn);
//Bugfix for Fragile blocks.
if(lastStand->type==TYPE_FRAGILE && !lastStand->queryProperties(GameObjectProperty_PlayerCanWalkOn,this)){
inAir=true;
onGround=false;
isJump=false;
}
}
}
//Check if the player can teleport.
if(canTeleport)
objLastTeleport=NULL;
//Check the checkpoint pointer only if the downkey is pressed.
//new: don't save the game if playing game record
if(objParent!=NULL && downKeyPressed && objCheckPoint!=NULL && !isPlayFromRecord()){
//Checkpoint thus save the state.
if(objParent->canSaveState()){
objParent->saveStateNextTime=true;
objParent->objLastCheckPoint=objCheckPoint;
}
}
//Check the swap pointer only if the down key is pressed.
if(objSwap!=NULL && downKeyPressed && objParent!=NULL){
//Now check if the shadow we're the shadow or not.
if(shadow){
if(!(dead || objParent->player.dead)){
//Check if the player isn't in front of a shadow block.
if(!objParent->player.objShadowBlock){
objParent->player.swapState(this);
objSwap->playAnimation(1);
}else{
//We can't swap so play the error sound.
if(getSettings()->getBoolValue("sound")==true){
Mix_PlayChannel(-1,errorSound,0);
}
}
}
}else{
if(!(dead || objParent->shadow.dead)){
//Check if the player isn't in front of a shadow block.
if(!objShadowBlock){
swapState(&objParent->shadow);
objSwap->playAnimation(1);
}else{
//We can't swap so play the error sound.
if(getSettings()->getBoolValue("sound")==true){
Mix_PlayChannel(-1,errorSound,0);
}
}
}
}
}
//Check for jump appearance (inAir).
if(inAir && !dead){
if(direction==1){
if(yVel>0){
if(appearance.currentStateName!="fallleft")
appearance.changeState("fallleft");
}else{
if(appearance.currentStateName!="jumpleft")
appearance.changeState("jumpleft");
}
}else{
if(yVel>0){
if(appearance.currentStateName!="fallright")
appearance.changeState("fallright");
}else{
if(appearance.currentStateName!="jumpright")
appearance.changeState("jumpright");
}
}
}
}
//Finally we reset some stuff.
downKeyPressed=false;
xVelBase=0;
yVelBase=0;
}
void Player::jump(){
//Check if the player is dead or not.
if(dead==true){
//The player can't jump if he's dead.
isJump=false;
}
//Check if the player can jump.
if(isJump==true && inAir==false){
//Set the jump velocity.
yVel=-13;
inAir=true;
isJump=false;
jumpTime++;
//Update statistics
if(!objParent->player.isPlayFromRecord() && !objParent->interlevel){
if(shadow) statsMgr.shadowJumps++;
else statsMgr.playerJumps++;
if(statsMgr.playerJumps+statsMgr.shadowJumps==1000) statsMgr.newAchievement("frog");
}
//Check if sound is enabled, if so play the jump sound.
if(getSettings()->getBoolValue("sound")==true){
Mix_PlayChannel(-1,jumpSound,0);
}
}
}
void Player::show(){
//Check if we should render the recorded line.
//Only do this when we're recording and we're not the shadow.
if(shadow==false && record==true){
//FIXME: Adding an entry not in update but in render?
line.push_back(SDL_Rect());
line[line.size()-1].x=box.x+11;
line[line.size()-1].y=box.y+20;
//Loop through the line dots and draw them.
for(int l=0; l<(signed)line.size(); l++){
appearance.drawState("line",screen,line[l].x-camera.x,line[l].y-camera.y,NULL);
}
}
//NOTE: We do logic here, because it's only needed by the appearance.
appearance.updateAnimation();
appearance.draw(screen, box.x-camera.x, box.y-camera.y, NULL);
}
void Player::shadowSetState(){
int currentKey=0;
/*//debug
extern int block_test_count;
extern bool block_test_only;
if(SDL_GetKeyState(NULL)[SDLK_p]){
block_test_count=recordButton.size();
}
if(block_test_count==(int)recordButton.size()){
block_test_only=true;
}*/
//Check if we should read the input from record file.
if(recordIndex>=0){ // && recordIndex<(int)recordButton.size()){
//read the input from record file
if(recordIndex<(int)recordButton.size()){
currentKey=recordButton[recordIndex];
recordIndex++;
}
//Reset horizontal velocity.
xVel=0;
if(currentKey&PlayerButtonRight){
//Walking to the right.
xVel+=7;
}
if(currentKey&PlayerButtonLeft){
//Walking to the left.
xVel-=7;
}
if(currentKey&PlayerButtonJump){
//The up key, if we aren't in the air we start jumping.
if(inAir==false){
isJump=true;
}else{
//Shouldn't go here
cout<<"Replay BUG"<<endl;
}
}
//check the down key
downKeyPressed=(currentKey&PlayerButtonDown)!=0;
//check the space key
if(currentKey&PlayerButtonSpace){
spaceKeyDown(&objParent->shadow);
}
}else{
//read the input from keyboard.
recordIndex=-1;
//Check for xvelocity.
if(xVel>0)
currentKey|=PlayerButtonRight;
if(xVel<0)
currentKey|=PlayerButtonLeft;
//Check for jumping.
if(isJump){
#ifdef RECORD_FILE_DEBUG
char c[64];
sprintf(c,"[%05d] Jump key recorded\n",objParent->time-1);
cout<<c;
recordKeyPressLog+=c;
#endif
currentKey|=PlayerButtonJump;
}
//Check if the downbutton is pressed.
if(downKeyPressed){
#ifdef RECORD_FILE_DEBUG
char c[64];
sprintf(c,"[%05d] Action key recorded\n",objParent->time-1);
cout<<c;
recordKeyPressLog+=c;
#endif
currentKey|=PlayerButtonDown;
}
if(spaceKeyPressed){
#ifdef RECORD_FILE_DEBUG
char c[64];
sprintf(c,"[%05d] Space key recorded\n",objParent->time-1);
cout<<c;
recordKeyPressLog+=c;
#endif
currentKey|=PlayerButtonSpace;
}
//Record it.
recordButton.push_back(currentKey);
}
#ifdef RECORD_FILE_DEBUG
if(recordIndex>=0){
if(recordIndex>0 && recordIndex<=int(recordPlayerPosition.size())/2){
SDL_Rect &r1=recordPlayerPosition[recordIndex*2-2];
SDL_Rect &r2=recordPlayerPosition[recordIndex*2-1];
if(r1.x!=box.x || r1.y!=box.y || r2.x!=objParent->shadow.box.x || r2.y!=objParent->shadow.box.y){
char c[192];
sprintf(c,"Replay ERROR [%05d] %d %d %d %d Expected: %d %d %d %d\n",
objParent->time-1,box.x,box.y,objParent->shadow.box.x,objParent->shadow.box.y,r1.x,r1.y,r2.x,r2.y);
cout<<c;
}
}
}else{
recordPlayerPosition.push_back(box);
recordPlayerPosition.push_back(objParent->shadow.box);
}
#endif
//reset spaceKeyPressed.
spaceKeyPressed=false;
//Only add an entry if the player is recording.
if(record){
//Add the action.
if(!dead){
playerButton.push_back(currentKey);
//Change the state.
state++;
}
}
}
void Player::shadowGiveState(Shadow* shadow){
//Check if the player calls the shadow.
if(shadowCall==true){
//Clear any recording still with the shadow.
shadow->playerButton.clear();
//Loop the recorded moves and add them to the one of the shadow.
for(unsigned int s=0;s<playerButton.size();s++){
shadow->playerButton.push_back(playerButton[s]);
}
//Reset the state of both the player and the shadow.
stateReset();
shadow->stateReset();
//Clear the recording at the player's side.
playerButton.clear();
line.clear();
//Set shadowCall false
shadowCall=false;
//And let the shadow know that the player called him.
shadow->meCall();
}
}
void Player::stateReset(){
//Reset the state by setting it to 0.
state=0;
}
void Player::otherCheck(class Player* other){
//First make sure the player isn't dead.
//And check for velocity of the block the player is standing on.
if(!dead){
if(objCurrentStand!=NULL){
//Now get the velocity of the object the player is standing on.
SDL_Rect v=objCurrentStand->getBox(BoxType_Velocity);
//Set the base velocity to the velocity of the object.
xVelBase=v.x;
yVelBase=v.y;
//Already move the player box.
box.x+=v.x;
box.y+=v.y;
}
}
//Now do the same for the shadow.
if(!other->dead){
if(other->objCurrentStand!=NULL){
//Now get the velocity of the object the shadow is standing on.
SDL_Rect v=other->objCurrentStand->getBox(BoxType_Velocity);
//Set the base velocity to the velocity of the object.
other->xVelBase=v.x;
other->yVelBase=v.y;
//Already move the shadow box.
other->box.x+=v.x;
other->box.y+=v.y;
}
}
//Now check if the player is on the shadow.
//First make sure they are both alive.
if(!dead && !other->dead){
//Get the box of the shadow.
SDL_Rect boxShadow=other->getBox();
//Check if the player is on top of the shadow.
if(checkCollision(box,boxShadow)==true){
//We have collision now check if the other is standing on top of you.
if(box.y+box.h<=boxShadow.y+13 && !other->inAir){
int yVelocity=yVel-1;
if(yVelocity>0){
box.y-=yVel;
box.y+=boxShadow.y-(box.y+box.h);
inAir=false;
canMove=false;
onGround=true;
other->holdingOther=true;
other->appearance.changeState("holding");
//Change our own appearance to standing.
if(direction==1){
appearance.changeState("standleft");
}else{
appearance.changeState("standright");
}
//Apply the velocity the shadow has.
box.x+=other->xVelBase;
box.y+=other->yVelBase;
}
}else if(boxShadow.y+boxShadow.h<=box.y+13 && !inAir){
int yVelocity=other->yVel-1;
if(yVelocity>0){
other->box.y-=other->yVel;
other->box.y+=box.y-(other->box.y+other->box.h);
other->inAir=false;
other->canMove=false;
other->onGround=true;
holdingOther=true;
appearance.changeState("holding");
//Change our own appearance to standing.
if(other->direction==1){
other->appearance.changeState("standleft");
}else{
other->appearance.changeState("standright");
}
//Apply the velocity the shadow has.
other->box.x+=xVelBase;
other->box.y+=yVelBase;
}
}
}else{
holdingOther=false;
other->holdingOther=false;
}
}
//And set currentStand to null.
objCurrentStand=NULL;
other->objCurrentStand=NULL;
}
SDL_Rect Player::getBox(){
return box;
}
void Player::setMyCamera(){
//Only change the camera when the player isn't dead.
if(dead)
return;
//Check if the level fit's horizontally inside the camera.
if(camera.w>LEVEL_WIDTH){
camera.x=-(camera.w-LEVEL_WIDTH)/2;
}else{
//Check if the player is halfway pass the halfright of the screen.
if(box.x>camera.x+(SCREEN_WIDTH/2+50)){
//It is so ease the camera to the right.
camera.x+=(box.x-camera.x-(SCREEN_WIDTH/2))>>4;
//Check if the camera isn't going too far.
if(box.x<camera.x+(SCREEN_WIDTH/2+50)){
camera.x=box.x-(SCREEN_WIDTH/2+50);
}
}
//Check if the player is halfway pass the halfleft of the screen.
if(box.x<camera.x+(SCREEN_WIDTH/2-50)){
//It is so ease the camera to the left.
camera.x+=(box.x-camera.x-(SCREEN_WIDTH/2))>>4;
//Check if the camera isn't going too far.
if(box.x>camera.x+(SCREEN_WIDTH/2-50)){
camera.x=box.x-(SCREEN_WIDTH/2-50);
}
}
//If the camera is too far to the left we set it to 0.
if(camera.x<0){
camera.x=0;
}
//If the camera is too far to the right we set it to the max right.
if(camera.x+camera.w>LEVEL_WIDTH){
camera.x=LEVEL_WIDTH-camera.w;
}
}
//Check if the level fit's vertically inside the camera.
if(camera.h>LEVEL_HEIGHT){
//We don't centre vertical because the bottom line of the level (deadly) will be mid air.
camera.y=-(camera.h-LEVEL_HEIGHT);
}else{
//Check if the player is halfway pass the lower half of the screen.
if(box.y>camera.y+(SCREEN_HEIGHT/2+50)){
//If is so ease the camera down.
camera.y+=(box.y-camera.y-(SCREEN_HEIGHT/2))>>4;
//Check if the camera isn't going too far.
if(box.y<camera.y+(SCREEN_HEIGHT/2+50)){
camera.y=box.y-(SCREEN_HEIGHT/2+50);
}
}
//Check if the player is halfway pass the upper half of the screen.
if(box.y<camera.y+(SCREEN_HEIGHT/2-50)){
//It is so ease the camera up.
camera.y+=(box.y-camera.y-(SCREEN_HEIGHT/2))>>4;
//Check if the camera isn't going too far.
if(box.y>camera.y+(SCREEN_HEIGHT/2-50)){
camera.y=box.y-(SCREEN_HEIGHT/2-50);
}
}
//If the camera is too far up we set it to 0.
if(camera.y<0){
camera.y=0;
}
//If the camera is too far down we set it to the max down.
if(camera.y+camera.h>LEVEL_HEIGHT){
camera.y=LEVEL_HEIGHT-camera.h;
}
}
}
void Player::reset(bool save){
//Set the location of the player to it's initial state.
box.x=fx;
box.y=fy;
//Reset back to default value.
inAir=true;
isJump=false;
onGround=true;
shadowCall=false;
canMove=true;
holdingOther=false;
dead=false;
record=false;
downKeyPressed=false;
spaceKeyPressed=false;
//Some animation variables.
appearance.resetAnimation(save);
appearance.changeState("standright");
direction=0;
state=0;
xVel=0; //??? fixed a strange bug in game replay
yVel=0;
objCurrentStand=NULL;
objNotificationBlock=NULL;
//Clear the recording.
line.clear();
playerButton.clear();
recordButton.clear();
recordIndex=-1;
#ifdef RECORD_FILE_DEBUG
recordKeyPressLog.clear();
recordPlayerPosition.clear();
#endif
//xVelSaved is used to indicate if there's a state saved or not.
if(save){
xVelSaved=0x80000000;
}
}
void Player::saveState(){
//We can only save the state when the player isn't dead.
if(!dead){
boxSaved.x=box.x;
boxSaved.y=box.y;
xVelSaved=xVel;
yVelSaved=yVel;
inAirSaved=inAir;
isJumpSaved=isJump;
onGroundSaved=onGround;
canMoveSaved=canMove;
holdingOtherSaved=holdingOther;
stateSaved=state;
//Let the appearance save.
appearance.saveAnimation();
//Save any recording stuff.
recordSaved=record;
playerButtonSaved=playerButton;
lineSaved=line;
//Save the record
savedRecordButton=recordButton;
#ifdef RECORD_FILE_DEBUG
recordKeyPressLog_saved=recordKeyPressLog;
recordPlayerPosition_saved=recordPlayerPosition;
#endif
//Only play the sound when it's enabled.
if(getSettings()->getBoolValue("sound")==true){
//To prevent playing the sound twice, only the player can cause the sound.
if(!shadow)
Mix_PlayChannel(-1,saveSound,0);
}
}
}
void Player::loadState(){
//Check with xVelSaved if there's a saved state.
if(xVelSaved==int(0x80000000)){
//There isn't so reset the game to load the first initial state.
//NOTE: There's no need in removing the saved state since there is none.
reset(false);
return;
}
//Restore the saved values.
box.x=boxSaved.x;
box.y=boxSaved.y;
//xVel is set to 0 since it's saved counterpart is used to indicate a saved state.
xVel=0;
yVel=yVelSaved;
//Restore the saved values.
inAir=inAirSaved;
isJump=isJumpSaved;
onGround=onGroundSaved;
canMove=canMoveSaved;
holdingOther=holdingOtherSaved;
dead=false;
record=false;
shadowCall=false;
state=stateSaved;
//Restore the appearance.
appearance.loadAnimation();
//Restore any recorded stuff.
record=recordSaved;
playerButton=playerButtonSaved;
line=lineSaved;
//Load the previously saved record
recordButton=savedRecordButton;
#ifdef RECORD_FILE_DEBUG
recordKeyPressLog=recordKeyPressLog_saved;
recordPlayerPosition=recordPlayerPosition_saved;
#endif
}
void Player::swapState(Player* other){
//We need to swap the values of the player with the ones of the given player.
swap(box.x,other->box.x);
swap(box.y,other->box.y);
//NOTE: xVel isn't there since it's used for something else.
swap(yVel,other->yVel);
swap(inAir,other->inAir);
swap(isJump,other->isJump);
swap(onGround,other->onGround);
swap(canMove,other->canMove);
swap(holdingOther,other->holdingOther);
swap(dead,other->dead);
//Also reset the state of the other.
other->stateReset();
//Play the swap sound.
if(getSettings()->getBoolValue("sound")==true){
Mix_PlayChannel(-1,swapSound,0);
}
}
bool Player::canSaveState(){
//We can only save the state if the player isn't dead.
return !dead;
}
bool Player::canLoadState(){
//We use xVelSaved to indicate if a state is saved or not.
return xVelSaved != int(0x80000000);
}
void Player::die(bool animation){
//Make sure the player isn't already dead.
if(!dead){
dead=true;
//If sound is enabled run the hit sound.
if(getSettings()->getBoolValue("sound")==true){
Mix_PlayChannel(-1,hitSound,0);
}
//Change the apearance to die (if animation is true).
if(animation){
if(appearance.currentStateName.find("right")!=std::string::npos){
appearance.changeState("dieright");
}else{
appearance.changeState("dieleft");
}
}
//Update statistics
if(!objParent->player.isPlayFromRecord() && !objParent->interlevel){
if(shadow) statsMgr.shadowDies++;
else statsMgr.playerDies++;
switch(statsMgr.playerDies+statsMgr.shadowDies){
case 1:
statsMgr.newAchievement("die1");
break;
case 50:
statsMgr.newAchievement("die50");
break;
case 1000:
statsMgr.newAchievement("die1000");
break;
}
if(objParent->player.dead && objParent->shadow.dead) statsMgr.newAchievement("doubleKill");
}
}
//We set the jumpTime to 120 when this is the shadow.
//That's the countdown for the "Your shadow has died." message.
if(shadow){
jumpTime=80;
}
}
diff --git a/src/Player.h b/src/Player.h
index c55aa53..4925478 100644
--- a/src/Player.h
+++ b/src/Player.h
@@ -1,248 +1,253 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLAYER_H
#define PLAYER_H
#include "ThemeManager.h"
#include <vector>
#include <string>
-#include <SDL/SDL_mixer.h>
#include <SDL/SDL.h>
+#ifdef __APPLE__
+#include <SDL_mixer/SDL_mixer.h>
+#include <SDL_ttf/SDL_ttf.h>
+#else
+#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
+#endif
//Debug the game record file.
//#define RECORD_FILE_DEBUG
class GameObject;
class Game;
//The different player buttons.
//The right arrow.
const int PlayerButtonRight=0x01;
//The left arrow.
const int PlayerButtonLeft=0x02;
//The up arrow for jumping.
const int PlayerButtonJump=0x04;
//The down arrow for actions.
const int PlayerButtonDown=0x08;
//space bar for recording. (Only in recordButton)
const int PlayerButtonSpace=0x10;
class Player{
protected:
//Vector used to store the player actions in when recording.
//These can be given to the shadow so he can execute them.
std::vector<int> playerButton;
//Vector used to store the playerButton vector when saving the player's state (checkpoint).
std::vector<int> playerButtonSaved;
private:
//Vector used to record the whole game play.
//And saved record in checkpoint.
std::vector<int> recordButton,savedRecordButton;
//record index. -1 means read input from keyboard,
//otherwise read input from recordings (recordButton[recordIndex]).
int recordIndex;
//Vector containing squares along the path the player takes when recording.
//It will be drawn as a trail of squares.
std::vector<SDL_Rect> line;
//Vector that will hold the line vector when saving the player's state (checkpoint).
std::vector<SDL_Rect> lineSaved;
//Boolean if the player called the shadow to copy his moves.
bool shadowCall;
//Boolean if the player is recording his moves.
bool record,recordSaved;
//The following variables are to store a state.
//Rectangle containing the players location.
SDL_Rect boxSaved;
//Boolean if the player is in the air.
bool inAirSaved;
//Boolean if the player is (going to) jump(ing).
bool isJumpSaved;
//Boolean if the player is (still) on the ground.
bool onGroundSaved;
//Boolean if the player can move.
bool canMoveSaved;
//Boolean if the player is holding the other (shadow).
bool holdingOtherSaved;
//The x velocity.
//NOTE: The x velocity is used to indicate that there's a state saved.
int xVelSaved;
//The y velocity.
int yVelSaved;
//The state.
int stateSaved;
protected:
//Rectangle containing the player's location.
SDL_Rect box;
//The x and y velocity.
int xVel, yVel;
//The base x and y velocity, used for standing on moving blocks.
int xVelBase, yVelBase;
//Boolean if the player is in the air.
bool inAir;
//Boolean if the player is (going to) jump(ing).
bool isJump;
//Boolean if the player is (still) on the ground.
bool onGround;
//Boolean if the player can move.
bool canMove;
//Boolean if the player is alive/
bool dead;
//The direction the player is walking, 0=right, 1=left.
int direction;
//Integer containing the state of the player.
int state;
//The time the player is in the air (jumping).
int jumpTime;
//Boolean if the player is in fact the shadow.
bool shadow;
//Pointer to the Game state.
friend class Game;
Game* objParent;
//Boolean if the downkey is pressed.
bool downKeyPressed;
//Boolean if the space keu is pressed.
bool spaceKeyPressed;
//Pointer to the object that is currently been stand on by the player.
//This is always a valid pointer.
GameObject* objCurrentStand;
//Pointer to the object the player stood last on.
//NOTE: This is a weak reference only.
GameObject* objLastStand;
//Pointer to the teleporter the player last took.
//NOTE: This is a weak reference only.
GameObject* objLastTeleport;
//Pointer to the notification block the player is in front of.
//This is always a valid pointer.
GameObject* objNotificationBlock;
//Pointer to the shadow block the player is in front of.
//This is always a valid pointer.
GameObject* objShadowBlock;
public:
//X and y location where the player starts and gets when reseted.
int fx, fy;
//The appearance of the player.
ThemeCharacterInstance appearance;
//Boolean if the player is holding the other.
bool holdingOther;
//Constructor.
//objParent: Pointer to the Game state.
Player(Game* objParent);
//Destructor.
~Player();
//Method used to set the position of the player.
//x: The new x location of the player.
//y: The new y location of the player.
void setPosition(int x,int y);
//Method used to handle (key) input.
//shadow: Pointer to the shadow used for recording/calling.
void handleInput(class Shadow* shadow);
//Method used to do the movement of the player.
//levelObjects: Array containing the levelObjects, used to check collision.
void move(std::vector<GameObject*> &levelObjects);
//Method used to check if the player can jump and executes the jump.
void jump();
//This method will render the player to the screen.
void show();
//Method that stores the actions if the player is recording.
void shadowSetState();
//Method that will reset the state to 0.
virtual void stateReset();
//This method checks the player against the other to see if they stand on eachother.
//other: The shadow or the player.
void otherCheck(class Player* other);
//Method that will ease the camera so that the player is in the center.
void setMyCamera();
//This method will reset the player to it's initial position.
//save: Boolean if the saved state should also be deleted.
void reset(bool save);
//Method used to retrieve the current location of the player.
//Returns: SDL_Rect containing the player's location.
SDL_Rect getBox();
//This method will
void shadowGiveState(class Shadow* shadow);
//Method that will save the current state.
//NOTE: The special <name>Saved variables will be used.
virtual void saveState();
//Method that will retrieve the last saved state.
//If there is none it will reset the player.
virtual void loadState();
//Method that checks if the player can save the state.
//Returns: True if the player can save his state.
virtual bool canSaveState();
//Method that checks if the player can load a state.
//Returns: True if the player can load a state.
virtual bool canLoadState();
//Method that will swap the state of the player with the other.
//other: The player or the shadow.
void swapState(Player* other);
//Check if this player is in fact the shadow.
//Returns: True if this is the shadow.
inline bool isShadow(){
return shadow;
}
//Let the player die when he falls of or hits spikes.
//animation: Boolean if the death animation should be played, default is true.
void die(bool animation=true);
//Check if currently it's play from record file.
bool isPlayFromRecord();
//get the game record object.
std::vector<int>* getRecord();
#ifdef RECORD_FILE_DEBUG
std::string& keyPressLog();
std::vector<SDL_Rect>& playerPosition();
#endif
//play the record.
void playRecord();
private:
//The space key is down. call this function from handleInput and another function.
void spaceKeyDown(class Shadow* shadow);
};
#endif
diff --git a/src/StatisticsScreen.cpp b/src/StatisticsScreen.cpp
index 9dcecad..19d7c9a 100644
--- a/src/StatisticsScreen.cpp
+++ b/src/StatisticsScreen.cpp
@@ -1,410 +1,415 @@
/*
* Copyright (C) 2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include "StatisticsManager.h"
#include "StatisticsScreen.h"
#include "Globals.h"
#include "Functions.h"
#include "ThemeManager.h"
#include "InputManager.h"
#include "GUIListBox.h"
#include "GUIScrollBar.h"
+#ifdef __APPLE__
+#include <SDL_image/SDL_image.h>
+#include <SDL_gfx/SDL_gfxPrimitives.h>
+#else
#include <SDL/SDL_image.h>
#include <SDL/SDL_gfxPrimitives.h>
+#endif
using namespace std;
//GUI events are handled here.
//name: The name of the element that invoked the event.
//obj: Pointer to the object that invoked the event.
//eventType: Integer containing the type of event.
void StatisticsScreen::GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType){
//Check what type of event it was.
if(eventType==GUIEventClick){
if(name=="cmdBack"){
//Goto the main menu.
setNextState(STATE_MENU);
}
}
}
#define DRAW_PLAYER_STATISTICS(name,var,format) { \
surface=TTF_RenderUTF8_Blended(fontGUISmall,name,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(0,y,surface,stats,NULL); \
y+=(h1=surface->h); \
SDL_FreeSurface(surface); \
sprintf(s,format,statsMgr.player##var+statsMgr.shadow##var); \
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(400-surface->w,y-(surface->h+h1)/2,surface,stats,NULL); \
SDL_FreeSurface(surface); \
sprintf(s,format,statsMgr.player##var); \
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(520-surface->w,y-(surface->h+h1)/2,surface,stats,NULL); \
SDL_FreeSurface(surface); \
sprintf(s,format,statsMgr.shadow##var); \
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(640-surface->w,y-(surface->h+h1)/2,surface,stats,NULL); \
SDL_FreeSurface(surface); \
}
#define DRAW_MISC_STATISTICS_1(name1,var1,format1) { \
surface=TTF_RenderUTF8_Blended(fontGUISmall,name1,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(0,y,surface,stats,NULL); \
x=surface->w+8; \
y+=(h1=surface->h); \
SDL_FreeSurface(surface); \
sprintf(s,format1,statsMgr.var1); \
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(x,y-(surface->h+h1)/2,surface,stats,NULL); \
SDL_FreeSurface(surface); \
}
//we are so lazy that we just use height of the first one, ignore second one
#define DRAW_MISC_STATISTICS_2(name1,var1,format1,name2,var2,format2) { \
surface=TTF_RenderUTF8_Blended(fontGUISmall,name1,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(0,y,surface,stats,NULL); \
x=surface->w+8; \
y+=(h1=surface->h); \
SDL_FreeSurface(surface); \
sprintf(s,format1,statsMgr.var1); \
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(x,y-(surface->h+h1)/2,surface,stats,NULL); \
SDL_FreeSurface(surface); \
surface=TTF_RenderUTF8_Blended(fontGUISmall,name2,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(320,y-surface->h,surface,stats,NULL); \
x=surface->w+328; \
SDL_FreeSurface(surface); \
sprintf(s,format2,statsMgr.var2); \
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(x,y-(surface->h+h1)/2,surface,stats,NULL); \
SDL_FreeSurface(surface); \
}
//Constructor.
StatisticsScreen::StatisticsScreen(){
//update in-game time
statsMgr.updatePlayTime();
//Load needed pictures.
//Note: we don't use ImageManager because we need to process these pictures.
SDL_Surface *bmPlayer=IMG_Load((getDataPath()+"themes/Cloudscape/player.png").c_str());
SDL_Surface *bmShadow=IMG_Load((getDataPath()+"themes/Cloudscape/shadow.png").c_str());
SDL_Surface *bmMedal=IMG_Load((getDataPath()+"gfx/medals.png").c_str());
//disable the alpha channel
SDL_SetAlpha(bmPlayer,0,0xFF);
SDL_SetAlpha(bmShadow,0,0xFF);
SDL_SetAlpha(bmMedal,0,0xFF);
//Render the title.
title=TTF_RenderUTF8_Blended(fontTitle,_("Achievements and Statistics"),themeTextColor);
//Render stats.
Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
stats=SDL_CreateRGBSurface(SDL_SWSURFACE,640,400,32,rmask,gmask,bmask,amask);
char s[64];
SDL_Surface *surface;
SDL_Rect r;
int x,y=0,h1;
Uint32 clr=SDL_MapRGB(stats->format,themeTextColor.r,themeTextColor.g,themeTextColor.b);
//Player and shadow specific statistics
surface=TTF_RenderUTF8_Blended(fontGUISmall,_("Total"),themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(400-surface->w,40-surface->h,surface,stats,NULL);
SDL_FreeSurface(surface);
r.x=0;r.y=0;r.w=23;r.h=40;
applySurface(520-r.w,0,bmPlayer,stats,&r);
applySurface(640-r.w,0,bmShadow,stats,&r);
y+=40;
DRAW_PLAYER_STATISTICS(_("Traveling distance (m)"),TravelingDistance,"%0.2f");
DRAW_PLAYER_STATISTICS(_("Jump times"),Jumps,"%d");
DRAW_PLAYER_STATISTICS(_("Die times"),Dies,"%d");
DRAW_PLAYER_STATISTICS(_("Squashed times"),Squashed,"%d");
//Game specific statistics
r.x=0;r.y=y;r.w=stats->w;r.h=2;
SDL_FillRect(stats,&r,clr);
y+=2;
DRAW_MISC_STATISTICS_2(_("Recordings:"),recordTimes,"%d",_("Switch pulled times:"),switchTimes,"%d");
DRAW_MISC_STATISTICS_1(_("Swap times:"),swapTimes,"%d");
//Level specific statistics
r.x=0;r.y=y;r.w=stats->w;r.h=2;
SDL_FillRect(stats,&r,clr);
y+=2;
surface=TTF_RenderUTF8_Blended(fontGUISmall,_("Completed levels:"),themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(0,y,surface,stats,NULL);
x=surface->w+8;
y+=(h1=surface->h);
SDL_FreeSurface(surface);
sprintf(s,"%d",statsMgr.completedLevels);
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(x,y-(surface->h+h1)/2,surface,stats,NULL);
SDL_FreeSurface(surface);
sprintf(s,"%d",statsMgr.completedLevels-statsMgr.goldLevels-statsMgr.silverLevels);
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(400-surface->w,y-(surface->h+h1)/2,surface,stats,NULL);
r.x=0;r.y=0;r.w=30;r.h=30;
applySurface(400-surface->w-30,y-(30+h1)/2,bmMedal,stats,&r);
SDL_FreeSurface(surface);
sprintf(s,"%d",statsMgr.silverLevels);
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(520-surface->w,y-(surface->h+h1)/2,surface,stats,NULL);
r.x+=30;
applySurface(520-surface->w-30,y-(30+h1)/2,bmMedal,stats,&r);
SDL_FreeSurface(surface);
sprintf(s,"%d",statsMgr.goldLevels);
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(640-surface->w,y-(surface->h+h1)/2,surface,stats,NULL);
r.x+=30;
applySurface(640-surface->w-30,y-(30+h1)/2,bmMedal,stats,&r);
SDL_FreeSurface(surface);
//Other statistics
r.x=0;r.y=y;r.w=stats->w;r.h=2;
SDL_FillRect(stats,&r,clr);
y+=2;
surface=TTF_RenderUTF8_Blended(fontGUISmall,_("In-game time:"),themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(0,y,surface,stats,NULL);
x=surface->w+8;
y+=(h1=surface->h);
SDL_FreeSurface(surface);
sprintf(s,"%02d:%02d:%02d",statsMgr.playTime/3600,(statsMgr.playTime/60)%60,statsMgr.playTime%60);
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(x,y-(surface->h+h1)/2,surface,stats,NULL);
SDL_FreeSurface(surface);
surface=TTF_RenderUTF8_Blended(fontGUISmall,_("Level editing time:"),themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(320,y-surface->h,surface,stats,NULL);
x=surface->w+328;
SDL_FreeSurface(surface);
sprintf(s,"%02d:%02d:%02d",statsMgr.levelEditTime/3600,(statsMgr.levelEditTime/60)%60,statsMgr.levelEditTime%60);
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(x,y-(surface->h+h1)/2,surface,stats,NULL);
SDL_FreeSurface(surface);
DRAW_MISC_STATISTICS_1(_("Created levels:"),createdLevels,"%d");
//Free loaded surface
SDL_FreeSurface(bmPlayer);
SDL_FreeSurface(bmShadow);
SDL_FreeSurface(bmMedal);
//Create GUI
achievements=NULL;
createGUI();
}
//Destructor.
StatisticsScreen::~StatisticsScreen(){
//Delete the GUI.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
//Free images
SDL_FreeSurface(title);
SDL_FreeSurface(stats);
SDL_FreeSurface(achievements);
}
//Method that will create the GUI for the options menu.
void StatisticsScreen::createGUI(){
//Draw achievements
if(achievements) SDL_FreeSurface(achievements);
vector<SDL_Surface*> surfaces;
int w=SCREEN_WIDTH-128-16,h=0;
for(map<string,AchievementInfo*>::iterator it=statsMgr.achievements.begin();
it!=statsMgr.achievements.end();it++)
{
SDL_Rect r={0,0,w,0};
SDL_Surface *surface=statsMgr.createAchievementSurface(it->second,NULL,&r,false);
if(surface!=NULL){
//Draw single smooth line for separating items in a list.
lineRGBA(surface,0,surface->h-1,surface->w,surface->h-1,0,0,0,128);
lineRGBA(surface,0,surface->h-2,surface->w,surface->h-2,0,0,0,32);
lineRGBA(surface,0,0,surface->w,0,0,0,0,32);
surfaces.push_back(surface);
h+=r.h;
}
}
if(surfaces.empty()){
achievements=TTF_RenderUTF8_Blended(fontText,_("You don't have any achievements now. Play the game and try to earn some!"),themeTextColor);
}else{
achievements=SDL_CreateRGBSurface(SDL_HWSURFACE,w,h,
screen->format->BitsPerPixel,screen->format->Rmask,screen->format->Gmask,screen->format->Bmask,0);
h=0;
for(unsigned int i=0;i<surfaces.size();i++){
SDL_Rect r={0,h,0,0};
SDL_BlitSurface(surfaces[i],NULL,achievements,&r);
h+=surfaces[i]->h;
SDL_FreeSurface(surfaces[i]);
}
}
//Create the root element of the GUI.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
GUIObjectRoot=new GUIObject(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,GUIObjectNone);
//Create back button.
GUIObject* obj=new GUIObject(SCREEN_WIDTH*0.5,SCREEN_HEIGHT-60,-1,36,GUIObjectButton,_("Back"),0,true,true,GUIGravityCenter);
obj->name="cmdBack";
obj->eventCallback=this;
GUIObjectRoot->addChild(obj);
//Create list box
listBox=new GUISingleLineListBox((SCREEN_WIDTH-500)/2,104,500,32);
listBox->item.push_back(_("Achievements"));
listBox->item.push_back(_("Statistics"));
listBox->value=0;
GUIObjectRoot->addChild(listBox);
//Create vertical scrollbar.
h-=SCREEN_HEIGHT-144-80;
if(h<0) h=0;
scrollbarV=new GUIScrollBar(SCREEN_WIDTH-64-16,144,16,SCREEN_HEIGHT-144-80,1,0,0,h,16,SCREEN_HEIGHT-144-80,true,false);
GUIObjectRoot->addChild(scrollbarV);
}
//In this method all the key and mouse events should be handled.
//Note: The GUIEvents won't be handled here.
void StatisticsScreen::handleEvents(){
//Check if we need to quit, if so enter the exit state.
if(event.type==SDL_QUIT){
setNextState(STATE_EXIT);
}
//Check if the escape button is pressed, if so go back to the main menu.
if(inputMgr.isKeyUpEvent(INPUTMGR_ESCAPE)){
setNextState(STATE_MENU);
}
//Check for scrolling down and up with mouse scroll wheel.
if(event.type==SDL_MOUSEBUTTONDOWN && event.button.button==SDL_BUTTON_WHEELDOWN && scrollbarV->visible){
if(scrollbarV->value<scrollbarV->maxValue)
scrollbarV->value+=scrollbarV->smallChange*4;
if(scrollbarV->value>scrollbarV->maxValue)
scrollbarV->value=scrollbarV->maxValue;
return;
}else if(event.type==SDL_MOUSEBUTTONDOWN && event.button.button==SDL_BUTTON_WHEELUP && scrollbarV->visible){
if(scrollbarV->value>0)
scrollbarV->value-=scrollbarV->smallChange*4;
if(scrollbarV->value<0)
scrollbarV->value=0;
return;
}
}
//All the logic that needs to be done should go in this method.
void StatisticsScreen::logic(){
}
//This method handles all the rendering.
void StatisticsScreen::render(){
//Draw background.
objThemes.getBackground(true)->draw(screen);
objThemes.getBackground(true)->updateAnimation();
//Draw title.
applySurface((SCREEN_WIDTH-title->w)/2,40-TITLE_FONT_RAISE,title,screen,NULL);
switch(listBox->value){
case 0:
//achievements
{
scrollbarV->visible=(scrollbarV->maxValue>0);
SDL_Rect r1={0,scrollbarV->value,achievements->w,SCREEN_HEIGHT-144-80};
SDL_Rect r2={64,144,0,0};
SDL_BlitSurface(achievements,&r1,screen,&r2);
if(scrollbarV->visible)
drawGUIBox(63,144,achievements->w+3,SCREEN_HEIGHT-144-80,screen,SDL_MapRGB(screen->format,0,0,0));
else
drawGUIBox(63,144,achievements->w+1,achievements->h,screen,SDL_MapRGB(screen->format,0,0,0));
}
break;
case 1:
//statistics
scrollbarV->visible=false;
applySurface((SCREEN_WIDTH-stats->w)/2,144,stats,screen,NULL);
break;
}
}
//Method that will be called when the screen size has been changed in runtime.
void StatisticsScreen::resize(){
//Recreate the gui to fit the new resolution.
createGUI();
}
diff --git a/src/ThemeManager.cpp b/src/ThemeManager.cpp
index 987eb46..059d4a0 100644
--- a/src/ThemeManager.cpp
+++ b/src/ThemeManager.cpp
@@ -1,985 +1,989 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ThemeManager.h"
#include "POASerializer.h"
#include "Functions.h"
#include "FileManager.h"
#include "Game.h"
+#ifdef __APPLE__
+#include <SDL_gfx/SDL_rotozoom.h>
+#else
#include <SDL/SDL_rotozoom.h>
+#endif
#include <string.h>
#include <iostream>
using namespace std;
//The ThemeStack that is be used by the GameState.
ThemeStack objThemes;
bool ThemeManager::loadFile(const string& fileName){
POASerializer objSerializer;
TreeStorageNode objNode;
//First we destroy the current ThemeManager.
destroy();
//Now we try to load the file, if it fails we return false.
if(!objSerializer.loadNodeFromFile(fileName.c_str(),&objNode,true)){
cerr<<"ERROR: Unable to open theme file: "<<fileName<<endl;
return false;
}
//Set the themePath.
themePath=pathFromFileName(fileName);
//Retrieve the name of the theme from the file.
{
vector<string> &v=objNode.attributes["name"];
if(!v.empty()) themeName=v[0];
}
//Reset themeable colors to default
themeTextColor.r=themeTextColor.g=themeTextColor.b=0;
themeTextColorDialog.r=themeTextColorDialog.g=themeTextColorDialog.b=0;
//Read themeable colors if any
vector<string> &ct=objNode.attributes["textColor"];
if(!ct.empty()){
themeTextColor.r=atoi(ct[0].c_str());
themeTextColor.g=atoi(ct[1].c_str());
themeTextColor.b=atoi(ct[2].c_str());
}
vector<string> &ct2=objNode.attributes["textColorDialog"];
if(!ct2.empty()){
themeTextColorDialog.r=atoi(ct2[0].c_str());
themeTextColorDialog.g=atoi(ct2[1].c_str());
themeTextColorDialog.b=atoi(ct2[2].c_str());
}
//Loop the subnodes of the theme.
for(unsigned int i=0;i<objNode.subNodes.size();i++){
TreeStorageNode *obj=objNode.subNodes[i];
//Check if it's a block or a background.
if(obj->name=="block" && !obj->value.empty()){
map<string,int>::iterator it=Game::blockNameMap.find(obj->value[0]);
if(it!=Game::blockNameMap.end()){
int idx=it->second;
if(!objBlocks[idx]) objBlocks[idx]=new ThemeBlock;
if(!objBlocks[idx]->loadFromNode(obj,themePath)){
cerr<<"ERROR: Unable to load "<<Game::blockName[idx]<<" for theme "<<fileName<<endl;
delete objBlocks[idx];
objBlocks[idx]=NULL;
return false;
}
}
}else if(obj->name=="background" && !obj->value.empty()){
if(!objBackground) objBackground=new ThemeBackground();
if(!objBackground->addPictureFromNode(obj,themePath)){
cerr<<"ERROR: Unable to load background for theme "<<fileName<<endl;
delete objBackground;
objBackground=NULL;
return false;
}
}else if(obj->name=="character" && !obj->value.empty()){
if(obj->value[0]=="Shadow"){
if(!shadow) shadow=new ThemeCharacter();
if(!shadow->loadFromNode(obj,themePath)){
cerr<<"ERROR: Unable to load shadow for theme "<<fileName<<endl;
delete shadow;
shadow=NULL;
return false;
}
}else if(obj->value[0]=="Player"){
if(!player) player=new ThemeCharacter();
if(!player->loadFromNode(obj,themePath)){
cerr<<"ERROR: Unable to load player for theme "<<fileName<<endl;
delete player;
player=NULL;
return false;
}
}
}else if(obj->name=="menuBackground" && !obj->value.empty()){
if(!menuBackground) menuBackground=new ThemeBackground();
if(!menuBackground->addPictureFromNode(obj,themePath)){
cerr<<"ERROR: Unable to load background for theme "<<fileName<<endl;
delete menuBackground;
menuBackground=NULL;
return false;
}
}else if(obj->name=="menu" && obj->value[0]=="Block"){
if(!menuBlock) menuBlock=new ThemeBlock;
if(!menuBlock->loadFromNode(obj,themePath)){
cerr<<"ERROR: Unable to load menu block for theme "<<fileName<<endl;
delete menuBlock;
menuBlock=NULL;
return false;
}
}
}
//Done and nothing went wrong so return true.
return true;
}
bool ThemeBlock::loadFromNode(TreeStorageNode* objNode, string themePath){
destroy();
//Loop the subNodes.
for(unsigned int i=0;i<objNode->subNodes.size();i++){
TreeStorageNode *obj=objNode->subNodes[i];
//Check if the subnode is an editorPicture or a blockState.
if(obj->name=="editorPicture"){
if(!editorPicture.loadFromNode(obj,themePath)) return false;
}else if(obj->name=="blockState" && !obj->value.empty()){
string& s=obj->value[0];
map<string,ThemeBlockState*>::iterator it=blockStates.find(s);
if(it==blockStates.end()) blockStates[s]=new ThemeBlockState;
if(!blockStates[s]->loadFromNode(obj,themePath)) return false;
}
}
//Done and nothing went wrong so return true.
return true;
}
bool ThemeBlockState::loadFromNode(TreeStorageNode* objNode, string themePath){
destroy();
//Retrieve the oneTimeAnimation attribute.
{
vector<string> &v=objNode->attributes["oneTimeAnimation"];
//Check if there are enough values for the oneTimeAnimation attribute.
if(v.size()>=2 && !v[0].empty()){
oneTimeAnimationLength=atoi(v[0].c_str());
nextState=v[1];
}
}
//Loop the subNodes.
for(unsigned int i=0;i<objNode->subNodes.size();i++){
TreeStorageNode *obj=objNode->subNodes[i];
if(obj->name=="object"){
ThemeObject *obj1=new ThemeObject();
if(!obj1->loadFromNode(obj,themePath)){
delete obj1;
return false;
}
themeObjects.push_back(obj1);
}
}
//Done and nothing went wrong so return true.
return true;
}
bool ThemeCharacter::loadFromNode(TreeStorageNode* objNode,string themePath){
destroy();
//Loop the subNodes.
for(unsigned int i=0;i<objNode->subNodes.size();i++){
TreeStorageNode *obj=objNode->subNodes[i];
//Check if the subnode is an characterState.
if(obj->name=="characterState" && !obj->value.empty()){
string& s=obj->value[0];
map<string,ThemeCharacterState*>::iterator it=characterStates.find(s);
if(it==characterStates.end()) characterStates[s]=new ThemeCharacterState;
if(!characterStates[s]->loadFromNode(obj,themePath)) return false;
}
}
//Done and nothing went wrong so return true.
return true;
}
bool ThemeCharacterState::loadFromNode(TreeStorageNode* objNode,string themePath){
destroy();
//Retrieve the oneTimeAnimation attribute.
{
vector<string> &v=objNode->attributes["oneTimeAnimation"];
//Check if there are enough values for the oneTimeAnimation attribute.
if(v.size()>=2 && !v[0].empty()){
oneTimeAnimationLength=atoi(v[0].c_str());
nextState=v[1];
}
}
//Loop the subNodes.
for(unsigned int i=0;i<objNode->subNodes.size();i++){
TreeStorageNode *obj=objNode->subNodes[i];
if(obj->name=="object"){
ThemeObject *obj1=new ThemeObject();
if(!obj1->loadFromNode(obj,themePath)){
delete obj1;
return false;
}
themeObjects.push_back(obj1);
}
}
//Done and nothing went wrong so return true.
return true;
}
bool ThemeObject::loadFromNode(TreeStorageNode* objNode,string themePath){
destroy();
//Retrieve the animation attribute.
{
vector<string> &v=objNode->attributes["animation"];
if(v.size()>=2){
animationLength=atoi(v[0].c_str());
animationLoopPoint=atoi(v[1].c_str());
}
}
//Retrieve the oneTimeAnimation attribute.
{
vector<string> &v=objNode->attributes["oneTimeAnimation"];
if(v.size()>=2){
animationLength=atoi(v[0].c_str());
animationLoopPoint=atoi(v[1].c_str())|0x80000000;
}
}
//Retrieve the invisibleAtRunTime attribute.
{
vector<string> &v=objNode->attributes["invisibleAtRunTime"];
if(!v.empty() && !v[0].empty()){
invisibleAtRunTime=atoi(v[0].c_str())?true:false;
}
}
//Retrieve the invisibleAtDesignTime attribute.
{
vector<string> &v=objNode->attributes["invisibleAtDesignTime"];
if(!v.empty() && !v[0].empty()){
invisibleAtDesignTime=atoi(v[0].c_str())?true:false;
}
}
//Loop the subnodes.
for(unsigned int i=0;i<objNode->subNodes.size();i++){
TreeStorageNode *obj=objNode->subNodes[i];
if(obj->name=="picture" || obj->name=="pictureAnimation"){
if(!picture.loadFromNode(obj,themePath)){
return false;
}
}else if(obj->name=="editorPicture"){
if(!editorPicture.loadFromNode(obj,themePath)){
return false;
}
}else if(obj->name=="optionalPicture" && obj->value.size()>=6){
ThemePicture *objPic=new ThemePicture();
double f=atof(obj->value[5].c_str());
if(!objPic->loadFromNode(obj,themePath)){
delete objPic;
return false;
}
optionalPicture.push_back(pair<double,ThemePicture*>(f,objPic));
}else if(obj->name=="offset" || obj->name=="offsetAnimation"){
if(!offset.loadFromNode(obj)) return false;
}
}
//Done and nothing went wrong so return true.
return true;
}
bool ThemePicture::loadFromNode(TreeStorageNode* objNode,string themePath){
destroy();
//Check if the node has enough values.
if(!objNode->value.empty()){
//Load teh picture.
picture=loadImage(themePath+objNode->value[0]);
if(picture==NULL) return false;
//Check if it's an animation.
if(objNode->name=="pictureAnimation"){
if(!offset.loadFromNode(objNode)) return false;
return true;
}else if(objNode->value.size()>=5){
typeOffsetPoint r={atoi(objNode->value[1].c_str()),
atoi(objNode->value[2].c_str()),
atoi(objNode->value[3].c_str()),
atoi(objNode->value[4].c_str()),0,0};
offset.offsetData.push_back(r);
offset.length=0;
return true;
}
}
//Done and nothing went wrong so return true.
return false;
}
bool ThemeOffsetData::loadFromNode(TreeStorageNode* objNode){
destroy();
//Check what kind of offset it is.
if(objNode->name=="pictureAnimation"){
for(unsigned int i=0;i<objNode->subNodes.size();i++){
TreeStorageNode* obj=objNode->subNodes[i];
if(obj->name=="point" && obj->value.size()>=4){
typeOffsetPoint r={atoi(obj->value[0].c_str()),
atoi(obj->value[1].c_str()),
atoi(obj->value[2].c_str()),
atoi(obj->value[3].c_str()),1,1};
if(obj->value.size()>=5) r.frameCount=atoi(obj->value[4].c_str());
if(obj->value.size()>=6) r.frameDisplayTime=atoi(obj->value[5].c_str());
offsetData.push_back(r);
length+=r.frameCount*r.frameDisplayTime;
}
}
return true;
}else if(objNode->name=="offsetAnimation"){
for(unsigned int i=0;i<objNode->subNodes.size();i++){
TreeStorageNode* obj=objNode->subNodes[i];
if(obj->name=="point" && obj->value.size()>=2){
typeOffsetPoint r={atoi(obj->value[0].c_str()),
atoi(obj->value[1].c_str()),0,0,1,1};
if(obj->value.size()>=3) r.frameCount=atoi(obj->value[2].c_str());
if(obj->value.size()>=4) r.frameDisplayTime=atoi(obj->value[3].c_str());
offsetData.push_back(r);
length+=r.frameCount*r.frameDisplayTime;
}
}
return true;
}else if(objNode->name=="offset" && objNode->value.size()>=2){
typeOffsetPoint r={atoi(objNode->value[0].c_str()),
atoi(objNode->value[1].c_str()),0,0,0,0};
offsetData.push_back(r);
length=0;
return true;
}
//Done and nothing went wrong so return true.
return false;
}
void ThemeObjectInstance::draw(SDL_Surface *dest,int x,int y,SDL_Rect *clipRect){
//Get the picture.
SDL_Surface *src=picture->picture;
if(src==NULL) return;
int ex=0,ey=0,xx=0,yy=0,ww=0,hh=0;
int animationNew=animation&0x7FFFFFFF;
{
vector<typeOffsetPoint> &v=picture->offset.offsetData;
if(picture->offset.length==0 || animationNew<v[0].frameDisplayTime){
xx=v[0].x;
yy=v[0].y;
ww=v[0].w;
hh=v[0].h;
}else if(animationNew>=picture->offset.length){
int i=v.size()-1;
xx=v[i].x;
yy=v[i].y;
ww=v[i].w;
hh=v[i].h;
}else{
int t=animationNew-v[0].frameDisplayTime;
for(unsigned int i=1;i<v.size();i++){
int tt=t/v[i].frameDisplayTime;
if(tt>=0 && tt<v[i].frameCount){
xx=(int)((float)v[i-1].x+(float)(v[i].x-v[i-1].x)*(float)(tt+1)/(float)v[i].frameCount+0.5f);
yy=(int)((float)v[i-1].y+(float)(v[i].y-v[i-1].y)*(float)(tt+1)/(float)v[i].frameCount+0.5f);
ww=(int)((float)v[i-1].w+(float)(v[i].w-v[i-1].w)*(float)(tt+1)/(float)v[i].frameCount+0.5f);
hh=(int)((float)v[i-1].h+(float)(v[i].h-v[i-1].h)*(float)(tt+1)/(float)v[i].frameCount+0.5f);
break;
}else{
t-=v[i].frameCount*v[i].frameDisplayTime;
}
}
}
}
//Get the offset.
{
vector<typeOffsetPoint> &v=parent->offset.offsetData;
if(v.empty()){
ex=0;
ey=0;
}else if(parent->offset.length==0 || animationNew<v[0].frameDisplayTime){
ex=v[0].x;
ey=v[0].y;
}else if(animationNew>=parent->offset.length){
int i=v.size()-1;
ex=v[i].x;
ey=v[i].y;
}else{
int t=animationNew-v[0].frameDisplayTime;
for(unsigned int i=1;i<v.size();i++){
int tt=t/v[i].frameDisplayTime;
if(tt>=0 && tt<v[i].frameCount){
ex=(int)((float)v[i-1].x+(float)(v[i].x-v[i-1].x)*(float)(tt+1)/(float)v[i].frameCount+0.5f);
ey=(int)((float)v[i-1].y+(float)(v[i].y-v[i-1].y)*(float)(tt+1)/(float)v[i].frameCount+0.5f);
break;
}else{
t-=v[i].frameCount*v[i].frameDisplayTime;
}
}
}
}
//And finally draw the ThemeObjectInstance.
if(clipRect){
int d;
d=clipRect->x-ex;
if(d>0){
ex+=d;
xx+=d;
ww-=d;
}
d=clipRect->y-ey;
if(d>0){
ey+=d;
yy+=d;
hh-=d;
}
if(ww>clipRect->w) ww=clipRect->w;
if(hh>clipRect->h) hh=clipRect->h;
}
if(ww>0&&hh>0){
SDL_Rect r1={xx,yy,ww,hh};
SDL_Rect r2={x+ex,y+ey,0,0};
SDL_BlitSurface(src,&r1,dest,&r2);
}
}
void ThemeObjectInstance::updateAnimation(){
//First get the animation length.
int m;
m=parent->animationLength;
//If it's higher than 0 then we have an animation.
if(m>0 && animation>=0){
//Increase the animation frame.
animation++;
//Check if the animation is beyond the length, if so set it to the looppoint.
if(animation>=m)
animation=parent->animationLoopPoint;
}
}
void ThemeBlockInstance::updateAnimation(){
//Make sure the currentState isn't null.
if(currentState!=NULL){
//Call the updateAnimation method of the currentState.
currentState->updateAnimation();
//Get the length of the animation.
int m=currentState->parent->oneTimeAnimationLength;
//If it's higher than 0 then we have an animation.
//Also check if it's past the lenght, meaning done.
if(m>0 && currentState->animation>=m){
//Now we can change the state to the nextState.
changeState(currentState->parent->nextState);
}
}
}
void ThemeCharacterInstance::updateAnimation(){
//Make sure the currentState isn't null.
if(currentState!=NULL){
//Call the updateAnimation method of the currentState.
currentState->updateAnimation();
//Get the length of the animation.
int m=currentState->parent->oneTimeAnimationLength;
//If it's higher than 0 then we have an animation.
//Also check if it's past the lenght, meaning done.
if(m>0 && currentState->animation>=m){
//Now we can change the state to the nextState.
changeState(currentState->parent->nextState);
}
}
}
void ThemeBlock::createInstance(ThemeBlockInstance* obj){
//Make sure the given ThemeBlockInstance is ready.
obj->blockStates.clear();
obj->currentState=NULL;
//Loop through the blockstates.
for(map<string,ThemeBlockState*>::iterator it=blockStates.begin();it!=blockStates.end();++it){
//Get the themeBlockStateInstance of the given ThemeBlockInstance.
ThemeBlockStateInstance &obj1=obj->blockStates[it->first];
//Set the parent of the state instance.
obj1.parent=it->second;
//Get the vector with themeObjects.
vector<ThemeObject*> &v=it->second->themeObjects;
//Loop through them.
for(unsigned int i=0;i<v.size();i++){
//Create an instance for every one.
ThemeObjectInstance p;
//Set the parent.
p.parent=v[i];
//Choose the picture.
if(stateID==STATE_LEVEL_EDITOR){
if(p.parent->invisibleAtDesignTime)
continue;
if(p.parent->editorPicture.picture!=NULL)
p.picture=&p.parent->editorPicture;
}else{
if(p.parent->invisibleAtRunTime)
continue;
}
//Get the number of optional Pictures.
int m=p.parent->optionalPicture.size();
//If p.picture is null, not an editor picture, and there are optional pictures then give one random.
if(p.picture==NULL && m>0){
double f=0.0,f1=1.0/256.0;
for(int j=0;j<8;j++){
f+=f1*(double)(rand()&0xff);
f1*=(1.0/256.0);
}
for(int j=0;j<m;j++){
f-=p.parent->optionalPicture[j].first;
if(f<0.0){
p.picture=p.parent->optionalPicture[j].second;
break;
}
}
}
//If random turned out to give nothing then give the non optional picture.
if(p.picture==NULL && p.parent->picture.picture!=NULL)
p.picture=&p.parent->picture;
//If the picture isn't null then can we give it to the ThemeBlockStateInstance.
if(p.picture!=NULL)
obj1.objects.push_back(p);
}
}
//Change the state to the default one.
//FIXME: Is that needed?
obj->changeState("default");
}
void ThemeCharacter::createInstance(ThemeCharacterInstance* obj){
//Make sure the given ThemeCharacterInstance is ready.
obj->characterStates.clear();
obj->currentState=NULL;
//Loop through the characterstates.
for(map<string,ThemeCharacterState*>::iterator it=characterStates.begin();it!=characterStates.end();++it){
//Get the themeCharacterStateInstance of the given ThemeCharacterInstance.
ThemeCharacterStateInstance &obj1=obj->characterStates[it->first];
//Set the parent of the state instance.
obj1.parent=it->second;
//Get the vector with themeObjects.
vector<ThemeObject*> &v=it->second->themeObjects;
//Loop through them.
for(unsigned int i=0;i<v.size();i++){
//Create an instance for every one.
ThemeObjectInstance p;
//Set the parent.
p.parent=v[i];
//Make sure it isn't invisible at runtime.
if(p.parent->invisibleAtRunTime)
continue;
//Get the number of optional Pictures.
int m=p.parent->optionalPicture.size();
//If p.picture is null, not an editor picture, and there are optional pictures then give one random.
if(p.picture==NULL && m>0){
double f=0.0,f1=1.0/256.0;
for(int j=0;j<8;j++){
f+=f1*(double)(rand()&0xff);
f1*=(1.0/256.0);
}
for(int j=0;j<m;j++){
f-=p.parent->optionalPicture[j].first;
if(f<0.0){
p.picture=p.parent->optionalPicture[j].second;
break;
}
}
}
//If random turned out to give nothing then give the non optional picture.
if(p.picture==NULL && p.parent->picture.picture!=NULL)
p.picture=&p.parent->picture;
//If the picture isn't null then can we give it to the ThemeCharacterStateInstance.
if(p.picture!=NULL)
obj1.objects.push_back(p);
}
}
//Set it to the standing right state.
obj->changeState("standright");
}
void ThemePicture::draw(SDL_Surface *dest,int x,int y,int animation,SDL_Rect *clipRect){
//Get the Picture.
if(picture==NULL) return;
int ex=0,ey=0,xx,yy,ww,hh;
{
vector<typeOffsetPoint> &v=offset.offsetData;
if(offset.length==0 || animation<v[0].frameDisplayTime){
xx=v[0].x;
yy=v[0].y;
ww=v[0].w;
hh=v[0].h;
}else if(animation>=offset.length){
int i=v.size()-1;
xx=v[i].x;
yy=v[i].y;
ww=v[i].w;
hh=v[i].h;
}else{
int t=animation-v[0].frameDisplayTime;
for(unsigned int i=1;i<v.size();i++){
int tt=t/v[i].frameDisplayTime;
if(tt>=0 && tt<v[i].frameCount){
xx=(int)((float)v[i-1].x+(float)(v[i].x-v[i-1].x)*(float)(tt+1)/(float)v[i].frameCount+0.5f);
yy=(int)((float)v[i-1].y+(float)(v[i].y-v[i-1].y)*(float)(tt+1)/(float)v[i].frameCount+0.5f);
ww=(int)((float)v[i-1].w+(float)(v[i].w-v[i-1].w)*(float)(tt+1)/(float)v[i].frameCount+0.5f);
hh=(int)((float)v[i-1].h+(float)(v[i].h-v[i-1].h)*(float)(tt+1)/(float)v[i].frameCount+0.5f);
break;
}else{
t-=v[i].frameCount*v[i].frameDisplayTime;
}
}
}
}
//Draw the Picture.
if(clipRect){
int d;
d=clipRect->x-ex;
if(d>0){
ex+=d;
xx+=d;
ww-=d;
}
d=clipRect->y-ey;
if(d>0){
ey+=d;
yy+=d;
hh-=d;
}
if(ww>clipRect->w) ww=clipRect->w;
if(hh>clipRect->h) hh=clipRect->h;
}
if(ww>0&&hh>0){
SDL_Rect r1={xx,yy,ww,hh};
SDL_Rect r2={x+ex,y+ey,0,0};
SDL_BlitSurface(picture,&r1,dest,&r2);
}
}
//This method will scale the background picture (if needed and configured) to the current SCREEN_WIDTH and SCREEN_HEIGHT.
void ThemeBackgroundPicture::scaleToScreen(){
//Only scale if needed.
if(scale){
//Free the surface of the scaled picture, if scaled.
if(picture!=cachedPicture)
SDL_FreeSurface(picture);
//Set src and destSize back to the initial cached value.
srcSize=cachedSrcSize;
destSize=cachedDestSize;
//Scale the image.
//Calculate the x and y factors.
double xFactor=double(SCREEN_WIDTH)/double(100);
double yFactor=double(SCREEN_HEIGHT)/double(100);
//The default scaling method is chosen (destSize in precentages).
destSize.x*=xFactor;
destSize.w*=xFactor;
destSize.y*=yFactor;
destSize.h*=yFactor;
//Now update the image.
xFactor=(double(destSize.w)/double(srcSize.w));
yFactor=(double(destSize.h)/double(srcSize.h));
if(xFactor!=1 || yFactor!=1){
picture=zoomSurface(cachedPicture,xFactor,yFactor,0);
//Also update the source size.
srcSize.x*=xFactor;
srcSize.y*=yFactor;
srcSize.w*=xFactor;
srcSize.h*=yFactor;
}else{
//We don't need to scale the image
picture=cachedPicture;
}
}
}
void ThemeBackgroundPicture::draw(SDL_Surface *dest){
//Check if the picture is visible.
if(!(picture&&srcSize.w>0&&srcSize.h>0&&destSize.w>0&&destSize.h>0))
return;
//Calculate the draw area.
int sx=(int)((float)destSize.x+currentX-cameraX*(float)camera.x+0.5f);
int sy=(int)((float)destSize.y+currentY-cameraY*(float)camera.y+0.5f);
int ex,ey;
//Include repeating.
if(repeatX){
sx%=destSize.w;
if(sx>0) sx-=destSize.w;
ex=SCREEN_WIDTH;
}else{
if(sx<=-(int)destSize.w || sx>=SCREEN_WIDTH) return;
ex=sx+1;
}
if(repeatY){
sy%=destSize.h;
if(sy>0) sy-=destSize.h;
ey=SCREEN_HEIGHT;
}else{
if(sy<=-(int)destSize.h || sy>=SCREEN_HEIGHT) return;
ey=sy+1;
}
//And finally draw the ThemeBackgroundPicture.
for(int x=sx;x<ex;x+=destSize.w){
for(int y=sy;y<ey;y+=destSize.h){
SDL_Rect r={x,y,0,0};
SDL_BlitSurface(picture,&srcSize,dest,&r);
}
}
}
bool ThemeBackgroundPicture::loadFromNode(TreeStorageNode* objNode,string themePath){
//Load the picture.
picture=loadImage(themePath+objNode->value[0]);
//Store pointer to the cached picture.
cachedPicture=picture;
if(picture==NULL) return false;
//Retrieve the source size.
{
vector<string> &v=objNode->attributes["srcSize"];
if(v.size()>=4){
srcSize.x=atoi(v[0].c_str());
srcSize.y=atoi(v[1].c_str());
srcSize.w=atoi(v[2].c_str());
srcSize.h=atoi(v[3].c_str());
}else{
srcSize.x=0;
srcSize.y=0;
srcSize.w=picture->w;
srcSize.h=picture->h;
}
//Cache the sourcesize.
cachedSrcSize=srcSize;
}
//Retrieve the destination size.
{
vector<string> &v=objNode->attributes["destSize"];
if(v.size()>=4){
destSize.x=atoi(v[0].c_str());
destSize.y=atoi(v[1].c_str());
destSize.w=atoi(v[2].c_str());
destSize.h=atoi(v[3].c_str());
}else{
destSize.x=0;
destSize.y=0;
destSize.w=100;
destSize.h=100;
}
//Cache the destsize.
cachedDestSize=destSize;
}
//Retrieve if we should scale to screen.
{
//Get scaleToScreen.
vector<string> &v=objNode->attributes["scaleToScreen"];
//Boolean if the image should be scaled, default is true.
scale=true;
if(v.size()>=1){
scale=atoi(v[0].c_str());
}
//Now scaleToScreen.
//NOTE: We don't check if scaleToScreen is true or false since that is done in scaleToScreen();
scaleToScreen();
}
//Retrieve if it should be repeated.
{
vector<string> &v=objNode->attributes["repeat"];
if(v.size()>=2){
repeatX=atoi(v[0].c_str())?true:false;
repeatY=atoi(v[1].c_str())?true:false;
}else{
repeatX=true;
repeatY=true;
}
}
//Retrieve the speed.
{
vector<string> &v=objNode->attributes["speed"];
if(v.size()>=2){
speedX=atof(v[0].c_str());
speedY=atof(v[1].c_str());
}else{
speedX=0.0f;
speedY=0.0f;
}
}
//Retrieve the camera speed.
{
vector<string> &v=objNode->attributes["cameraSpeed"];
if(v.size()>=2){
cameraX=atof(v[0].c_str());
cameraY=atof(v[1].c_str());
}else{
cameraX=0.0f;
cameraY=0.0f;
}
}
//Done and nothing went wrong so return true.
return true;
}
//Constructor.
ThemeStack::ThemeStack(){
}
//Destructor.
ThemeStack::~ThemeStack(){
//Loop through the themes and delete them.
for(unsigned int i=0;i<objThemes.size();i++)
delete objThemes[i];
}
//Method that will destroy the ThemeStack.
void ThemeStack::destroy(){
//Loop through the themes and delete them.
for(unsigned int i=0;i<objThemes.size();i++)
delete objThemes[i];
//Clear the vector to prevent dangling pointers.
objThemes.clear();
}
//Method that will append a theme to the stack.
//obj: The ThemeManager to add.
void ThemeStack::appendTheme(ThemeManager* obj){
objThemes.push_back(obj);
//debug
#if defined(DEBUG) || defined(_DEBUG)
cout<<"ThemeStack::appendTheme(): theme count="<<objThemes.size()<<endl;
#endif
}
//Method that will remove the last theme added to the stack.
void ThemeStack::removeTheme(){
//Make sure that the stack isn't empty.
if(!objThemes.empty()){
delete objThemes.back();
objThemes.pop_back();
}
}
//Method that will append a theme that will be loaded from file.
//fileName: The file to load the theme from.
//Returns: Pointer to the newly added theme, NULL if failed.
ThemeManager* ThemeStack::appendThemeFromFile(const string& fileName){
//Create a new themeManager.
ThemeManager* obj=new ThemeManager();
//Let it load from the given file.
if(!obj->loadFile(fileName)){
//Failed thus delete the theme and return null.
cerr<<"ERROR: Failed loading theme "<<fileName<<endl;
delete obj;
return NULL;
}else{
//Succeeded, add it to the stack and return it.
objThemes.push_back(obj);
return obj;
}
}
//Method that is used to let the themes scale.
void ThemeStack::scaleToScreen(){
//Loop through the themes and call their scaleToScreen method.
for(unsigned int i=0;i<objThemes.size();i++)
objThemes[i]->scaleToScreen();
}
//Get a pointer to the ThemeBlock of a given block type.
//index: The type of block.
//Returns: Pointer to the ThemeBlock.
ThemeBlock* ThemeStack::getBlock(int index,bool menu){
//Loop through the themes from top to bottom.
for(int i=objThemes.size()-1;i>=0;i--){
//Get the block from the theme.
ThemeBlock* obj=objThemes[i]->getBlock(index,menu);
//Check if it isn't null.
if(obj)
return obj;
}
//Nothing found.
return NULL;
}
//Get a pointer to the ThemeCharacter of the shadow or the player.
//isShadow: Boolean if it's the shadow
//Returns: Pointer to the ThemeCharacter.
ThemeCharacter* ThemeStack::getCharacter(bool isShadow){
//Loop through the themes from top to bottom.
for(int i=objThemes.size()-1;i>=0;i--){
//Get the ThemeCharacter from the theme.
ThemeCharacter* obj=objThemes[i]->getCharacter(isShadow);
//Check if it isn't null.
if(obj)
return obj;
}
//Nothing found.
return NULL;
}
//Get a pointer to the ThemeBackground of the theme.
//Returns: Pointer to the ThemeBackground.
ThemeBackground* ThemeStack::getBackground(bool menu){
//Loop through the themes from top to bottom.
for(int i=objThemes.size()-1;i>=0;i--){
//Get the ThemeBackground from the theme.
ThemeBackground* obj=objThemes[i]->getBackground(menu);
//Check if it isn't null.
if(obj)
return obj;
}
//Nothing found.
return NULL;
}
diff --git a/src/ThemeManager.h b/src/ThemeManager.h
index 5d7b322..26a931f 100644
--- a/src/ThemeManager.h
+++ b/src/ThemeManager.h
@@ -1,1066 +1,1070 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef THEMEMANAGER_H
#define THEMEMANAGER_H
#include "Globals.h"
#include "TreeStorageNode.h"
+#ifdef __APPLE__
+#include <SDL_gfx/SDL_rotozoom.h>
+#else
#include <SDL/SDL_rotozoom.h>
+#endif
#include <string.h>
#include <math.h>
#include <string>
#include <vector>
#include <utility>
#include <iostream>
using namespace std;
//Structure containing offset data for one frame.
struct typeOffsetPoint{
//The location (x,y) and size (w,h).
int x,y,w,h;
//The frame to which this offset applies.
int frameCount;
//The number of frames this offset is shown.
int frameDisplayTime;
};
//We already need the classes so declare them here.
class ThemeOffsetData;
class ThemePicture;
class ThemeObject;
class ThemeBlockState;
class ThemeBlock;
class ThemeCharacterState;
class ThemeCharacter;
//Instance class of a ThemeObject, this is used by the other Instance classes.
class ThemeObjectInstance{
public:
//Pointer to the picture.
ThemePicture* picture;
//Pointer to the parent the object an instance os is.
ThemeObject* parent;
//Integer containing the current animation frame.
int animation;
//Integer containing the saved animation frame.
int savedAnimation;
public:
//Constructor.
ThemeObjectInstance():picture(NULL),parent(NULL),animation(0),savedAnimation(0){}
//Method used to draw the ThemeObject.
//dest: The destination surface to draw the ThemeObject on.
//x: The x location on the dest surface.
//y: The y location on the dest surface.
//clipRect: Rectangle used to clip.
void draw(SDL_Surface* dest,int x,int y,SDL_Rect* clipRect=NULL);
//Method that will update the animation.
void updateAnimation();
//Method that will reset the animation.
//save: Boolean if the saved animation should be deleted.
void resetAnimation(bool save){
animation=0;
if(save){
savedAnimation=0;
}
}
//Method that will save the animation.
void saveAnimation(){
savedAnimation=animation;
}
//Method that will load a saved animation.
void loadAnimation(){
animation=savedAnimation;
}
};
//Instance class of a ThemeBlockState, this is used by the ThemeBlockInstance.
class ThemeBlockStateInstance{
public:
//Pointer to the parent the state an instance of is.
ThemeBlockState *parent;
//Vector containing the ThemeObjectInstances.
vector<ThemeObjectInstance> objects;
//Integer containing the current animation frame.
int animation;
//Integer containing the saved animation frame.
int savedAnimation;
public:
//Constructor.
ThemeBlockStateInstance():parent(NULL),animation(0),savedAnimation(0){}
//Method used to draw the ThemeBlockState.
//dest: The destination surface to draw the ThemeBlockState on.
//x: The x location on the dest surface.
//y: The y location on the dest surface.
//clipRect: Rectangle used to clip.
void draw(SDL_Surface *dest,int x,int y,SDL_Rect *clipRect=NULL){
for(unsigned int i=0;i<objects.size();i++){
objects[i].draw(dest,x,y,clipRect);
}
}
//Method that will update the animation.
void updateAnimation(){
for(unsigned int i=0;i<objects.size();i++){
objects[i].updateAnimation();
}
animation++;
}
//Method that will reset the animation.
//save: Boolean if the saved state should be deleted.
void resetAnimation(bool save){
for(unsigned int i=0;i<objects.size();i++){
objects[i].resetAnimation(save);
}
animation=0;
if(save){
savedAnimation=0;
}
}
//Method that will save the animation.
void saveAnimation(){
for(unsigned int i=0;i<objects.size();i++){
objects[i].saveAnimation();
}
savedAnimation=animation;
}
//Method that will load a saved animation.
void loadAnimation(){
for(unsigned int i=0;i<objects.size();i++){
objects[i].loadAnimation();
}
animation=savedAnimation;
}
};
//Instance of a ThemeBlock, this is used by blocks in the game to prevent changing the theme in game.
//It also allows animation to run independently.
class ThemeBlockInstance{
public:
//Pointer to the current state.
ThemeBlockStateInstance* currentState;
//The name of the current state.
string currentStateName;
//Map containing the blockStates.
map<string,ThemeBlockStateInstance> blockStates;
//String containing the name of the saved state.
string savedStateName;
public:
//Constructor.
ThemeBlockInstance():currentState(NULL){}
//Method used to draw the ThemeBlock.
//dest: The destination surface to draw the ThemeBlock on.
//x: The x location on the dest surface.
//y: The y location on the dest surface.
//clipRect: Rectangle used to clip.
//Returns: True if it succeeds.
bool draw(SDL_Surface *dest,int x,int y,SDL_Rect *clipRect=NULL){
if(currentState!=NULL){
currentState->draw(dest,x,y,clipRect);
return true;
}
return false;
}
//Method that will draw a specific state.
//s: The name of the state to draw.
//dest: The destination surface to draw the ThemeBlock on.
//x: The x location on the dest surface.
//y: The y location on the dest surface.
//clipRect: Rectangle used to clip.
//Returns: True if it succeeds.
bool drawState(const string& s,SDL_Surface *dest,int x,int y,SDL_Rect *clipRect=NULL){
map<string,ThemeBlockStateInstance>::iterator it=blockStates.find(s);
if(it!=blockStates.end()){
it->second.draw(dest,x,y,clipRect);
return true;
}
return false;
}
//Method that will change the current state.
//s: The name of the state to change to.
//reset: Boolean if the animation should reset.
//Returns: True if it succeeds (exists).
bool changeState(const string& s,bool reset=true){
//Get the new state.
map<string,ThemeBlockStateInstance>::iterator it=blockStates.find(s);
//Check if it exists.
if(it!=blockStates.end()){
//Set the state.
currentState=&(it->second);
currentStateName=it->first;
//FIXME: Is it needed to set the savedStateName here?
if(savedStateName.empty())
savedStateName=currentStateName;
//If reset then reset the animation.
if(reset)
currentState->resetAnimation(true);
return true;
}
//It doesn't so return false.
return false;
}
//Method that will update the animation.
void updateAnimation();
//Method that will reset the animation.
//save: Boolean if the saved state should be deleted.
void resetAnimation(bool save){
for(map<string,ThemeBlockStateInstance>::iterator it=blockStates.begin();it!=blockStates.end();++it){
it->second.resetAnimation(save);
}
if(save){
savedStateName.clear();
}
}
//Method that will save the animation.
void saveAnimation(){
for(map<string,ThemeBlockStateInstance>::iterator it=blockStates.begin();it!=blockStates.end();++it){
it->second.saveAnimation();
}
savedStateName=currentStateName;
}
//Method that will restore a saved animation.
void loadAnimation(){
for(map<string,ThemeBlockStateInstance>::iterator it=blockStates.begin();it!=blockStates.end();++it){
it->second.loadAnimation();
}
changeState(savedStateName,false);
}
};
//Instance class of a ThemeCharacterState, this is used by the ThemeCharacterInstance.
class ThemeCharacterStateInstance{
public:
//Pointer to the parent the state an instance of is.
ThemeCharacterState* parent;
//Vector containing the ThemeObjectInstances.
vector<ThemeObjectInstance> objects;
//Integer containing the current animation frame.
int animation;
//Integer containing the saved animation frame.
int savedAnimation;
public:
//Constructor.
ThemeCharacterStateInstance():parent(NULL),animation(0),savedAnimation(0){}
//Method used to draw the ThemeCharacterState.
//dest: The destination surface to draw the ThemeCharacterState on.
//x: The x location on the dest surface.
//y: The y location on the dest surface.
//clipRect: Rectangle used to clip.
void draw(SDL_Surface *dest,int x,int y,SDL_Rect *clipRect=NULL){
for(unsigned int i=0;i<objects.size();i++){
objects[i].draw(dest,x,y,clipRect);
}
}
//Method that will update the animation.
void updateAnimation(){
for(unsigned int i=0;i<objects.size();i++){
objects[i].updateAnimation();
}
animation++;
}
//Method that will reset the animation.
//save: Boolean if the saved state should be deleted.
void resetAnimation(bool save){
for(unsigned int i=0;i<objects.size();i++){
objects[i].resetAnimation(save);
}
animation=0;
if(save)
savedAnimation=0;
}
//Method that will save the animation.
void saveAnimation(){
for(unsigned int i=0;i<objects.size();i++){
objects[i].saveAnimation();
}
savedAnimation=animation;
}
//Method that will load a saved animation.
void loadAnimation(){
for(unsigned int i=0;i<objects.size();i++){
objects[i].loadAnimation();
}
animation=savedAnimation;
}
};
//Instance of a ThemeCharacter.
class ThemeCharacterInstance{
public:
//Pointer to the current state.
ThemeCharacterStateInstance* currentState;
//The name of the current state.
string currentStateName;
//Map containing the ThemeCharacterStates.
map<string,ThemeCharacterStateInstance> characterStates;
//String containing the name of the saved state.
string savedStateName;
public:
//Constructor.
ThemeCharacterInstance():currentState(NULL){}
//Method used to draw the ThemeCharacter.
//dest: The destination surface to draw the ThemeCharacter on.
//x: The x location on the dest surface.
//y: The y location on the dest surface.
//clipRect: Rectangle used to clip.
//Returns: True if it succeeds.
bool draw(SDL_Surface *dest,int x,int y,SDL_Rect *clipRect=NULL){
if(currentState!=NULL){
currentState->draw(dest,x,y,clipRect);
return true;
}
return false;
}
//Method that will draw a specific state.
//s: The name of the state to draw.
//dest: The destination surface to draw the ThemeCharacter on.
//x: The x location on the dest surface.
//y: The y location on the dest surface.
//clipRect: Rectangle used to clip.
//Returns: True if it succeeds.
bool drawState(const string& s,SDL_Surface *dest,int x,int y,SDL_Rect *clipRect=NULL){
map<string,ThemeCharacterStateInstance>::iterator it=characterStates.find(s);
if(it!=characterStates.end()){
it->second.draw(dest,x,y,clipRect);
return true;
}
return false;
}
//Method that will change the current state.
//s: The name of the state to change to.
//reset: Boolean if the animation should reset.
//Returns: True if it succeeds (exists).
bool changeState(const string& s,bool reset=true){
//Get the new state.
map<string,ThemeCharacterStateInstance>::iterator it=characterStates.find(s);
//Check if it exists.
if(it!=characterStates.end()){
//Set the state.
currentState=&(it->second);
currentStateName=it->first;
//FIXME: Is it needed to set the savedStateName here?
if(savedStateName.empty())
savedStateName=currentStateName;
//If reset then reset the animation.
if(reset)
currentState->resetAnimation(true);
return true;
}
//It doesn't so return false.
return false;
}
//Method that will update the animation.
void updateAnimation();
//Method that will reset the animation.
//save: Boolean if the saved state should be deleted.
void resetAnimation(bool save){
for(map<string,ThemeCharacterStateInstance>::iterator it=characterStates.begin();it!=characterStates.end();++it){
it->second.resetAnimation(save);
}
if(save)
savedStateName.clear();
}
//Method that will save the animation.
void saveAnimation(){
for(map<string,ThemeCharacterStateInstance>::iterator it=characterStates.begin();it!=characterStates.end();++it){
it->second.saveAnimation();
}
savedStateName=currentStateName;
}
//Method that will restore a saved animation.
void loadAnimation(){
for(map<string,ThemeCharacterStateInstance>::iterator it=characterStates.begin();it!=characterStates.end();++it){
it->second.loadAnimation();
}
changeState(savedStateName,false);
}
};
//Class containing the offset data.
class ThemeOffsetData{
public:
//Vector containing the offsetDatas.
vector<typeOffsetPoint> offsetData;
//The length of the "animation" in frames.
int length;
public:
//Constructor.
ThemeOffsetData():length(0){}
//Destructor.
~ThemeOffsetData(){}
//Method used to destroy the offsetData.
void destroy(){
//Set length to zero.
length=0;
//And clear the offsetData vector.
offsetData.clear();
}
//Method that will load the offsetData from a node.
//objNode: Pointer to the TreeStorageNode to read the data from.
//Returns: True if it succeeds without errors.
bool loadFromNode(TreeStorageNode* objNode);
};
//This is the lowest level of the theme system.
//It's a picture with offset data.
class ThemePicture{
public:
//The SDL_Surface containing the picture.
SDL_Surface* picture;
//Offset data for the picture.
ThemeOffsetData offset;
public:
//Constructor.
ThemePicture():picture(NULL){}
//Destructor.
~ThemePicture(){}
//Method used to destroy the picture.
void destroy(){
//FIXME: Shouldn't the image be freed? (ImageManager)
picture=NULL;
//Destroy the offset data.
offset.destroy();
}
bool loadFromNode(TreeStorageNode* objNode, string themePath);
//Method that will draw the ThemePicture.
//dest: The destination surface.
//x: The x location on the dest to draw the picture.
//y: The y location on the dest to draw the picture.
//animation: The frame of the animation to draw.
//clipRect: Rectangle to clip the picture.
void draw(SDL_Surface* dest,int x,int y,int animation=0,SDL_Rect* clipRect=NULL);
};
//The ThemeObject class is used to contain a basic theme element.
//Contains the picture, animation information, etc...
class ThemeObject{
public:
//Integer containing the length of the animation.
int animationLength;
//Integer containing the frame from where the animation is going to loop.
int animationLoopPoint;
//Boolean if the animation is invisible at run time (Game state).
bool invisibleAtRunTime;
//Boolean if the animation is invisible at design time (Level editor).
bool invisibleAtDesignTime;
//Picture of the ThemeObject.
ThemePicture picture;
//Picture of the ThemeObject shown when in the level editor.
ThemePicture editorPicture;
//Vector containing optionalPicture for the ThemeObject.
vector<pair<double,ThemePicture*> > optionalPicture;
//ThemeOffsetData for the ThemeObject.
ThemeOffsetData offset;
public:
//Constructor.
ThemeObject():animationLength(0),animationLoopPoint(0),invisibleAtRunTime(false),invisibleAtDesignTime(false){}
//Destructor.
~ThemeObject(){
//Loop through the optionalPicture and delete them.
for(unsigned int i=0;i<optionalPicture.size();i++){
delete optionalPicture[i].second;
}
}
//Method that will destroy the ThemeObject.
void destroy(){
//Loop through the optionalPicture and delete them.
for(unsigned int i=0;i<optionalPicture.size();i++){
delete optionalPicture[i].second;
}
optionalPicture.clear();
animationLength=0;
animationLoopPoint=0;
invisibleAtRunTime=false;
invisibleAtDesignTime=false;
picture.destroy();
editorPicture.destroy();
offset.destroy();
}
//Method that will load a ThemeObject from a node.
//objNode: The TreeStorageNode to read the object from.
//themePath: Path to the theme.
//Returns: True if it succeeds.
bool loadFromNode(TreeStorageNode* objNode,string themePath);
};
//Class containing a single state of a themed block.
class ThemeBlockState{
public:
//The length in frames of the oneTimeAnimation.
int oneTimeAnimationLength;
//String containing the name of the next state.
string nextState;
//Vector containing the themeObjects that make up this state.
vector<ThemeObject*> themeObjects;
public:
//Constructor.
ThemeBlockState():oneTimeAnimationLength(0){}
//Destructor.
~ThemeBlockState(){
//Loop through the ThemeObjects and delete them.
for(unsigned int i=0;i<themeObjects.size();i++){
delete themeObjects[i];
}
}
//Method that will destroy the ThemeBlockState.
void destroy(){
//Loop through the ThemeObjects and delete them.
for(unsigned int i=0;i<themeObjects.size();i++){
delete themeObjects[i];
}
//Clear the themeObjects vector.
themeObjects.clear();
//Set the length to 0.
oneTimeAnimationLength=0;
//Clear the nextState string.
nextState.clear();
}
//Method that will load a ThemeBlockState from a node.
//objNode: The TreeStorageNode to read the state from.
//themePath: Path to the theme.
//Returns: True if it succeeds.
bool loadFromNode(TreeStorageNode* objNode,string themePath);
};
//Class containing the needed things for a themed block.
class ThemeBlock{
public:
//Picture that is shown only in the level editor.
ThemePicture editorPicture;
//Map containing ThemeBlockStates for the different states of a block.
map<string,ThemeBlockState*> blockStates;
public:
//Constructor.
ThemeBlock(){}
//Destructor/
~ThemeBlock(){
//Loop through the ThemeBlockStates and delete them,
for(map<string,ThemeBlockState*>::iterator i=blockStates.begin();i!=blockStates.end();++i){
delete i->second;
}
}
//Method that will destroy the ThemeBlock.
void destroy(){
//Loop through the ThemeBlockStates and delete them,
for(map<string,ThemeBlockState*>::iterator i=blockStates.begin();i!=blockStates.end();++i){
delete i->second;
}
//Clear the blockStates map.
blockStates.clear();
editorPicture.destroy();
}
//Method that will load a ThemeBlock from a node.
//objNode: The TreeStorageNode to load the ThemeBlock from.
//themePath: The path to the theme.
//Returns: True if it succeeds.
bool loadFromNode(TreeStorageNode* objNode,string themePath);
//Method that will create a ThemeBlockInstance.
//obj: Pointer that will be filled with the instance.
void createInstance(ThemeBlockInstance* obj);
};
//Class containing one state of a ThemeCharacter
class ThemeCharacterState{
public:
//The length in frames of the oneTimeAnimation.
int oneTimeAnimationLength;
//String containing the name of the next id.
string nextState;
//Vector with the themeObjects in the character state.
vector<ThemeObject*> themeObjects;
public:
//Constructor.
ThemeCharacterState():oneTimeAnimationLength(0){}
//Destructor.
~ThemeCharacterState(){
//Loop through the themeObjects and delete them.
for(unsigned int i=0;i<themeObjects.size();i++){
delete themeObjects[i];
}
}
//Method used to destroy the ThemeCharacterState.
void destroy(){
//Loop through the themeObjects and delete them.
for(unsigned int i=0;i<themeObjects.size();i++){
delete themeObjects[i];
}
//Clear the themeObjects vector.
themeObjects.clear();
//Set oneTimeAnimation to zero.
oneTimeAnimationLength=0;
//Clear the nextState string.
nextState.clear();
}
//Method that will load the ThemeCharacterState from a node.
//objNode: The TreeStorageNode to load the state from.
//themePath: Path to the theme.
//Returns: True if it succeeds.
bool loadFromNode(TreeStorageNode* objNode,string themePath);
};
//Class containing the things needed for a themed character.
class ThemeCharacter{
public:
//Map containing ThemeCharacterStates for the different states of a character.
map<string,ThemeCharacterState*> characterStates;
public:
//Constructor.
ThemeCharacter(){}
//Destructor.
~ThemeCharacter(){
//Loop through the states and delete them.
for(map<string,ThemeCharacterState*>::iterator i=characterStates.begin();i!=characterStates.end();++i){
delete i->second;
}
}
//Method that will destroy the ThemeCharacter.
void destroy(){
//Loop through the states and delete them.
for(map<string,ThemeCharacterState*>::iterator i=characterStates.begin();i!=characterStates.end();++i){
delete i->second;
}
//Clear the characterStates map.
characterStates.clear();
}
//Method that will load a ThemeCharacter from a node.
//objNode: The TreeStorageNode to load the ThemeCharacter from.
//themePath: The path to the theme.
//Returns: True if it succeeds.
bool loadFromNode(TreeStorageNode* objNode,string themePath);
//Method that will create a ThemeCharacterInstance.
//obj: Pointer that will be filled with the instance.
void createInstance(ThemeCharacterInstance* obj);
};
//ThemeBackgroundPicture is a class containing the picture for the background.
class ThemeBackgroundPicture{
private:
//Pointer to the SDL_Surface cached by the ImageManager.
//This is used to rescale the theme.
SDL_Surface* cachedPicture;
//Rectangle that should be taken from the picture.
//NOTE The size is pixels of the image.
SDL_Rect cachedSrcSize;
//Rectangle with the size it will have on the destination (screen).
//NOTE The size is in pixels or in precentages (if scaleToScreen is true).
SDL_Rect cachedDestSize;
//SDL_Surface containing the picture.
//NOTE: This could point to the same surface as cachedPicture.
SDL_Surface* picture;
//Rectangle that should be taken from the picture.
//NOTE The size is pixels of the image.
SDL_Rect srcSize;
//Rectangle with the size it will have on the destination (screen).
//NOTE The size is in pixels even though the loaded value from the theme description file can be in precentages (if scaleToScreen is true).
SDL_Rect destSize;
//Boolean if the background picture should be scaled to screen.
bool scale;
//Boolean if the image should be repeated over the x-axis.
bool repeatX;
//Boolean if the image should be repeated over the y-axis.
bool repeatY;
//Float containing the speed the background picture moves along the x-axis.
float speedX;
//Float containing the speed the background picture moves along the y-axis.
float speedY;
//Float containing the horizontal speed the picture will have when moving the camera (horizontally).
float cameraX;
//Float containing the vertical speed the picture will have when moving the camera (vertically).
float cameraY;
private:
//Float with the current x position.
float currentX;
//Float with the current y position.
float currentY;
//Stored x location for when loading a state.
float savedX;
//Stored y location for when loading a state.
float savedY;
public:
//Constructor.
ThemeBackgroundPicture(){
//Set some default values.
picture=NULL;
cachedPicture=NULL;
memset(&srcSize,0,sizeof(srcSize));
memset(&destSize,0,sizeof(destSize));
memset(&cachedSrcSize,0,sizeof(cachedSrcSize));
memset(&cachedDestSize,0,sizeof(cachedDestSize));
scale=true;
repeatX=true;
repeatY=true;
speedX=0.0f;
speedY=0.0f;
cameraX=0.0f;
cameraY=0.0f;
currentX=0.0f;
currentY=0.0f;
savedX=0.0f;
savedY=0.0f;
}
//Method that will update the animation.
void updateAnimation(){
//Move the picture along the x-axis.
currentX+=speedX;
if(repeatX && destSize.w>0){
float f=(float)destSize.w;
if(currentX>f || currentX<-f) currentX-=f*floor(currentX/f);
}
//Move the picture along the y-axis.
currentY+=speedY;
if(repeatY && destSize.h>0){
float f=(float)destSize.h;
if(currentY>f || currentY<-f) currentY-=f*floor(currentY/f);
}
}
//Method that will reset the animation.
//save: Boolean if the saved state should be deleted.
void resetAnimation(bool save){
currentX=0.0f;
currentY=0.0f;
if(save){
savedX=0.0f;
savedY=0.0f;
}
}
//Method that will save the animation.
void saveAnimation(){
savedX=currentX;
savedY=currentY;
}
//Method that will load the animation.
void loadAnimation(){
currentX=savedX;
currentY=savedY;
}
//Method used to draw the ThemeBackgroundPicture.
//dest: Pointer to the SDL_Surface the picture should be drawn.
void draw(SDL_Surface *dest);
//Method used to load the ThemeBackgroundPicture from a node.
//objNode: The TreeStorageNode to load the picture from.
//themePath: The path to the theme.
bool loadFromNode(TreeStorageNode* objNode,string themePath);
//This method will scale the background picture (if needed and configured) to the current SCREEN_WIDTH and SCREEN_HEIGHT.
void scaleToScreen();
};
//Class that forms the complete background of a theme.
//It is in fact nothing more than a vector containing multiple ThemeBackgroundPictures.
class ThemeBackground{
private:
//Vector containing the ThemeBackgroundPictures.
vector<ThemeBackgroundPicture> picture;
public:
//Method that will update the animation of all the background pictures.
void updateAnimation(){
for(unsigned int i=0;i<picture.size();i++){
picture[i].updateAnimation();
}
}
//Method that will reset the animation of all the background pictures.
//save: Boolean if the saved state should be deleted.
void resetAnimation(bool save){
for(unsigned int i=0;i<picture.size();i++){
picture[i].resetAnimation(save);
}
}
//Method that will save the animation of all the background pictures.
void saveAnimation(){
for(unsigned int i=0;i<picture.size();i++){
picture[i].saveAnimation();
}
}
//Method that will load the animation of all the background pictures.
void loadAnimation(){
for(unsigned int i=0;i<picture.size();i++){
picture[i].loadAnimation();
}
}
//Method that will scale the background pictures (if set) to the current screen resolution.
void scaleToScreen(){
for(unsigned int i=0;i<picture.size();i++){
picture[i].scaleToScreen();
}
}
//This method will draw all the background pictures.
//dest: Pointer to the SDL_Surface to draw them on.
void draw(SDL_Surface* dest){
for(unsigned int i=0;i<picture.size();i++){
picture[i].draw(dest);
}
}
//Method that will add a ThemeBackgroundPicture to the ThemeBackground.
//objNode: The treeStorageNode to read from.
//themePath: The path to the theme.
//Returns: True if it succeeds.
bool addPictureFromNode(TreeStorageNode* objNode,string themePath){
picture.push_back(ThemeBackgroundPicture());
return picture.back().loadFromNode(objNode,themePath);
}
};
//The ThemeManager is actually a whole theme, filled with ThemeBlocks, ThemeCharacter and ThemeBackground.
class ThemeManager{
private:
//The ThemeCharacter of the shadow.
ThemeCharacter* shadow;
//The ThemeCharacter of the player.
ThemeCharacter* player;
//Array containing a ThemeBlock for every block type.
ThemeBlock* objBlocks[TYPE_MAX];
//The ThemeBackground.
ThemeBackground* objBackground;
//ThemeBackground for menu.
ThemeBackground* menuBackground;
//Level selection background block.
ThemeBlock* menuBlock;
public:
//String containing the path to the string.
string themePath;
//String containing the theme name.
string themeName;
public:
//Constructor.
ThemeManager(){
//Make sure the pointers are set to NULL.
objBackground=NULL;
//Reserve enough memory for the ThemeBlocks.
memset(objBlocks,0,sizeof(objBlocks));
shadow=NULL;
player=NULL;
menuBackground=NULL;
menuBlock=NULL;
}
//Destructor.
~ThemeManager(){
//Delete the ThemeCharacter of the shadow.
if(shadow)
delete shadow;
//Delete the ThemeCharacter of the player.
if(player)
delete player;
//Loop through the ThemeBlocks and delete them.
for(int i=0;i<TYPE_MAX;i++){
if(objBlocks[i])
delete objBlocks[i];
}
//Delete the ThemeBackgrounds.
if(objBackground)
delete objBackground;
if(menuBackground)
delete menuBackground;
if(menuBlock)
delete menuBlock;
}
//Method used to destroy the ThemeManager.
void destroy(){
//Delete the ThemeCharacter of the shadow.
if(shadow)
delete shadow;
//Delete the ThemeCharacter of the player.
if(player)
delete player;
//Loop through the ThemeBlocks and delete them.
for(int i=0;i<TYPE_MAX;i++){
if(objBlocks[i])
delete objBlocks[i];
}
//Delete the ThemeBackground.
if(objBackground)
delete objBackground;
//And clear the themeName.
themeName.clear();
}
//Method that will load the theme from a file.
//fileName: The file to load the theme from.
//Returns: True if it succeeds.
bool loadFile(const string& fileName);
//Method that will scale the theme to the current SCREEN_WIDTH and SCREEN_HEIGHT.
void scaleToScreen(){
//We only need to scale the background.
if(objBackground)
objBackground->scaleToScreen();
}
//Get a pointer to the ThemeBlock of a given block type.
//index: The type of block.
//menu: Boolean if get spefial blocks for menu
//Returns: Pointer to the ThemeBlock.
ThemeBlock* getBlock(int index,bool menu){
if(!menu)
return objBlocks[index];
else
if(index==TYPE_BLOCK)
if(menuBlock)
return menuBlock;
else
return objBlocks[TYPE_BLOCK];
else if(index==TYPE_SHADOW_BLOCK)
if(menuBlock)
return menuBlock;
else
return objBlocks[TYPE_SHADOW_BLOCK];
else
return objBlocks[index];
}
//Get a pointer to the ThemeCharacter of the shadow or the player.
//isShadow: Boolean if it's the shadow
//Returns: Pointer to the ThemeCharacter.
ThemeCharacter* getCharacter(bool isShadow){
if(isShadow)
return shadow;
return player;
}
//Get a pointer to the ThemeBackground of the theme.
//bool: Boolean if get menu background
//Returns: Pointer to the ThemeBackground.
ThemeBackground* getBackground(bool menu){
if(menu&&menuBackground)
return menuBackground;
else
return objBackground;
}
};
//Class that combines multiple ThemeManager into one stack.
//If a file is not in a certain theme it will use one of a lower theme.
class ThemeStack{
private:
//Vector containing the themes in the stack.
vector<ThemeManager*> objThemes;
public:
//Constructor.
ThemeStack();
//Destructor.
~ThemeStack();
//Method that will destroy the ThemeStack.
void destroy();
//Method that will append a theme to the stack.
//obj: The ThemeManager to add.
void appendTheme(ThemeManager* obj);
//Method that will remove the last theme added to the stack.
void removeTheme();
//Method that will append a theme that will be loaded from file.
//fileName: The file to load the theme from.
//Returns: Pointer to the newly added theme, NULL if failed.
ThemeManager* appendThemeFromFile(const string& fileName);
//Method that is used to let the themes scale.
void scaleToScreen();
//Get the number of themes in the stack.
//Returns: The theme count.
int themeCount(){
return (int)objThemes.size();
}
//Operator overloading so that the themes can be accesed using the [] operator.
//i: The index.
ThemeManager* operator[](int i){
return objThemes[i];
}
//Get a pointer to the ThemeBlock of a given block type.
//index: The type of block.
//Returns: Pointer to the ThemeBlock.
ThemeBlock* getBlock(int index,bool menu=false);
//Get a pointer to the ThemeCharacter of the shadow or the player.
//isShadow: Boolean if it's the shadow
//Returns: Pointer to the ThemeCharacter.
ThemeCharacter* getCharacter(bool isShadow);
//Get a pointer to the ThemeBackground of the theme.
//Returns: Pointer to the ThemeBackground.
ThemeBackground* getBackground(bool menu);
};
//The ThemeStack that is be used by the GameState.
extern ThemeStack objThemes;
#endif
diff --git a/src/mac/meandmyshadow.xcodeproj/project.pbxproj b/src/mac/meandmyshadow.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..5626446
--- /dev/null
+++ b/src/mac/meandmyshadow.xcodeproj/project.pbxproj
@@ -0,0 +1,764 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 77019F9415D2C4F90085E7EC /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77019F9315D2C4F90085E7EC /* OpenGL.framework */; };
+ 77019F9615D2C5020085E7EC /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77019F9515D2C5020085E7EC /* Cocoa.framework */; };
+ 77019FA615D2D09A0085E7EC /* SDL_gfx.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77019F9C15D2D0890085E7EC /* SDL_gfx.framework */; settings = {ATTRIBUTES = (Required, ); }; };
+ 77019FA715D2D09A0085E7EC /* SDL_image.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77019F9D15D2D0890085E7EC /* SDL_image.framework */; };
+ 77019FA815D2D09A0085E7EC /* SDL_mixer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77019F9E15D2D0890085E7EC /* SDL_mixer.framework */; };
+ 77019FA915D2D09A0085E7EC /* SDL_ttf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77019F9F15D2D0890085E7EC /* SDL_ttf.framework */; };
+ 77019FAA15D2D09A0085E7EC /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77019FA015D2D08A0085E7EC /* SDL.framework */; };
+ 77019FAB15D2D0BF0085E7EC /* SDL_gfx.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 77019F9C15D2D0890085E7EC /* SDL_gfx.framework */; };
+ 77019FAC15D2D0BF0085E7EC /* SDL_image.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 77019F9D15D2D0890085E7EC /* SDL_image.framework */; };
+ 77019FAD15D2D0BF0085E7EC /* SDL_mixer.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 77019F9E15D2D0890085E7EC /* SDL_mixer.framework */; };
+ 77019FAE15D2D0BF0085E7EC /* SDL_ttf.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 77019F9F15D2D0890085E7EC /* SDL_ttf.framework */; };
+ 77019FAF15D2D0BF0085E7EC /* SDL.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 77019FA015D2D08A0085E7EC /* SDL.framework */; };
+ 775B108615D2B06E007AEED5 /* osx_helpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 775B108515D2B06E007AEED5 /* osx_helpers.mm */; };
+ 775D751515D29DC3007A415E /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 775D751415D29DC3007A415E /* libcrypto.dylib */; };
+ 775D759B15D29E7B007A415E /* Addons.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D752D15D29E7B007A415E /* Addons.cpp */; };
+ 775D759C15D29E7B007A415E /* Block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D752F15D29E7B007A415E /* Block.cpp */; };
+ 775D759D15D29E7B007A415E /* config.h.in in Resources */ = {isa = PBXBuildFile; fileRef = 775D753115D29E7B007A415E /* config.h.in */; };
+ 775D759E15D29E7B007A415E /* FileManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D753215D29E7B007A415E /* FileManager.cpp */; };
+ 775D759F15D29E7B007A415E /* Functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D753415D29E7B007A415E /* Functions.cpp */; };
+ 775D75A015D29E7B007A415E /* Game.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D753615D29E7B007A415E /* Game.cpp */; };
+ 775D75A115D29E7B007A415E /* GameObjects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D753815D29E7B007A415E /* GameObjects.cpp */; };
+ 775D75A215D29E7B007A415E /* Globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D753B15D29E7B007A415E /* Globals.cpp */; };
+ 775D75A315D29E7B007A415E /* GUIListBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D753D15D29E7B007A415E /* GUIListBox.cpp */; };
+ 775D75A415D29E7B007A415E /* GUIObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D753F15D29E7B007A415E /* GUIObject.cpp */; };
+ 775D75A515D29E7B007A415E /* GUIOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D754115D29E7B007A415E /* GUIOverlay.cpp */; };
+ 775D75A615D29E7B007A415E /* GUIScrollBar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D754315D29E7B007A415E /* GUIScrollBar.cpp */; };
+ 775D75A715D29E7B007A415E /* GUISlider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D754515D29E7B007A415E /* GUISlider.cpp */; };
+ 775D75A815D29E7B007A415E /* GUITextArea.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D754715D29E7B007A415E /* GUITextArea.cpp */; };
+ 775D75A915D29E7B007A415E /* ImageManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D754915D29E7B007A415E /* ImageManager.cpp */; };
+ 775D75AA15D29E7B007A415E /* InputManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D754B15D29E7B007A415E /* InputManager.cpp */; };
+ 775D75AB15D29E7B007A415E /* LevelEditor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D754F15D29E7B007A415E /* LevelEditor.cpp */; };
+ 775D75AC15D29E7B007A415E /* LevelEditSelect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D755115D29E7B007A415E /* LevelEditSelect.cpp */; };
+ 775D75AD15D29E7B007A415E /* LevelPack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D755315D29E7B007A415E /* LevelPack.cpp */; };
+ 775D75AE15D29E7B007A415E /* LevelPackManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D755515D29E7B007A415E /* LevelPackManager.cpp */; };
+ 775D75AF15D29E7B007A415E /* LevelPlaySelect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D755715D29E7B007A415E /* LevelPlaySelect.cpp */; };
+ 775D75B015D29E7B007A415E /* LevelSelect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D755915D29E7B007A415E /* LevelSelect.cpp */; };
+ 775D75B115D29E7B007A415E /* findlocale.c in Sources */ = {isa = PBXBuildFile; fileRef = 775D755D15D29E7B007A415E /* findlocale.c */; };
+ 775D75B215D29E7B007A415E /* dictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D756215D29E7B007A415E /* dictionary.cpp */; };
+ 775D75B315D29E7B007A415E /* dictionary_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D756415D29E7B007A415E /* dictionary_manager.cpp */; };
+ 775D75B415D29E7B007A415E /* language.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D756715D29E7B007A415E /* language.cpp */; };
+ 775D75B515D29E7B007A415E /* log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D756915D29E7B007A415E /* log.cpp */; };
+ 775D75B615D29E7B007A415E /* plural_forms.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D756C15D29E7B007A415E /* plural_forms.cpp */; };
+ 775D75B715D29E7B007A415E /* po_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D756E15D29E7B007A415E /* po_parser.cpp */; };
+ 775D75B815D29E7B007A415E /* tinygettext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D757015D29E7B007A415E /* tinygettext.cpp */; };
+ 775D75B915D29E7B007A415E /* unix_file_system.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D757215D29E7B007A415E /* unix_file_system.cpp */; };
+ 775D75BA15D29E7B007A415E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 775D757615D29E7B007A415E /* InfoPlist.strings */; };
+ 775D75BB15D29E7B007A415E /* meandmyshadow-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 775D757815D29E7B007A415E /* meandmyshadow-Info.plist */; };
+ 775D75BD15D29E7B007A415E /* meandmyshadow.icns in Resources */ = {isa = PBXBuildFile; fileRef = 775D757C15D29E7B007A415E /* meandmyshadow.icns */; };
+ 775D75BE15D29E7B007A415E /* Main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D758015D29E7B007A415E /* Main.cpp */; };
+ 775D75BF15D29E7B007A415E /* MD5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D758115D29E7B007A415E /* MD5.cpp */; };
+ 775D75C015D29E7B007A415E /* MusicManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D758315D29E7B007A415E /* MusicManager.cpp */; };
+ 775D75C115D29E7B007A415E /* Objects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D758515D29E7B007A415E /* Objects.cpp */; };
+ 775D75C215D29E7B007A415E /* Player.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D758715D29E7B007A415E /* Player.cpp */; };
+ 775D75C315D29E7B007A415E /* POASerializer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D758915D29E7B007A415E /* POASerializer.cpp */; };
+ 775D75C415D29E7B007A415E /* Settings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D758B15D29E7B007A415E /* Settings.cpp */; };
+ 775D75C515D29E7B007A415E /* Shadow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D758D15D29E7B007A415E /* Shadow.cpp */; };
+ 775D75C615D29E7B007A415E /* StatisticsManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D758F15D29E7B007A415E /* StatisticsManager.cpp */; };
+ 775D75C715D29E7B007A415E /* StatisticsScreen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D759115D29E7B007A415E /* StatisticsScreen.cpp */; };
+ 775D75C815D29E7B007A415E /* ThemeManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D759315D29E7B007A415E /* ThemeManager.cpp */; };
+ 775D75C915D29E7B007A415E /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D759515D29E7B007A415E /* Timer.cpp */; };
+ 775D75CA15D29E7B007A415E /* TitleMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D759715D29E7B007A415E /* TitleMenu.cpp */; };
+ 775D75CB15D29E7B007A415E /* TreeStorageNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 775D759915D29E7B007A415E /* TreeStorageNode.cpp */; };
+ 775D75CD15D29E9D007A415E /* data in Resources */ = {isa = PBXBuildFile; fileRef = 775D75CC15D29E9D007A415E /* data */; };
+ 775D75D015D2A4D1007A415E /* libarchive.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 775D75CE15D2A4C7007A415E /* libarchive.dylib */; };
+ 775D75D315D2A4E6007A415E /* libcurl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 775D75D115D2A4DE007A415E /* libcurl.dylib */; };
+ 7771221115D290B800F09E41 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7771220F15D290B800F09E41 /* InfoPlist.strings */; };
+ 77ED9D9A15D29AD1009B0CE9 /* meandmyshadow.icns in Resources */ = {isa = PBXBuildFile; fileRef = 77ED9D9915D29AD1009B0CE9 /* meandmyshadow.icns */; };
+ 77ED9D9D15D29D0E009B0CE9 /* SDLMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 77ED9D9C15D29CFB009B0CE9 /* SDLMain.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 775B108715D2B765007AEED5 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ 77019FAB15D2D0BF0085E7EC /* SDL_gfx.framework in CopyFiles */,
+ 77019FAC15D2D0BF0085E7EC /* SDL_image.framework in CopyFiles */,
+ 77019FAD15D2D0BF0085E7EC /* SDL_mixer.framework in CopyFiles */,
+ 77019FAE15D2D0BF0085E7EC /* SDL_ttf.framework in CopyFiles */,
+ 77019FAF15D2D0BF0085E7EC /* SDL.framework in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 77019F9315D2C4F90085E7EC /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
+ 77019F9515D2C5020085E7EC /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
+ 77019F9C15D2D0890085E7EC /* SDL_gfx.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL_gfx.framework; path = /Library/Frameworks/SDL_gfx.framework; sourceTree = "<absolute>"; };
+ 77019F9D15D2D0890085E7EC /* SDL_image.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL_image.framework; path = /Library/Frameworks/SDL_image.framework; sourceTree = "<absolute>"; };
+ 77019F9E15D2D0890085E7EC /* SDL_mixer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL_mixer.framework; path = /Library/Frameworks/SDL_mixer.framework; sourceTree = "<absolute>"; };
+ 77019F9F15D2D0890085E7EC /* SDL_ttf.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL_ttf.framework; path = /Library/Frameworks/SDL_ttf.framework; sourceTree = "<absolute>"; };
+ 77019FA015D2D08A0085E7EC /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = /Library/Frameworks/SDL.framework; sourceTree = "<absolute>"; };
+ 775B108515D2B06E007AEED5 /* osx_helpers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = osx_helpers.mm; sourceTree = "<group>"; };
+ 775D751415D29DC3007A415E /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; };
+ 775D752D15D29E7B007A415E /* Addons.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Addons.cpp; sourceTree = "<group>"; };
+ 775D752E15D29E7B007A415E /* Addons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Addons.h; sourceTree = "<group>"; };
+ 775D752F15D29E7B007A415E /* Block.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Block.cpp; sourceTree = "<group>"; };
+ 775D753015D29E7B007A415E /* Block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Block.h; sourceTree = "<group>"; };
+ 775D753115D29E7B007A415E /* config.h.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = config.h.in; sourceTree = "<group>"; };
+ 775D753215D29E7B007A415E /* FileManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileManager.cpp; sourceTree = "<group>"; };
+ 775D753315D29E7B007A415E /* FileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileManager.h; sourceTree = "<group>"; };
+ 775D753415D29E7B007A415E /* Functions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Functions.cpp; sourceTree = "<group>"; };
+ 775D753515D29E7B007A415E /* Functions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Functions.h; sourceTree = "<group>"; };
+ 775D753615D29E7B007A415E /* Game.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Game.cpp; sourceTree = "<group>"; };
+ 775D753715D29E7B007A415E /* Game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Game.h; sourceTree = "<group>"; };
+ 775D753815D29E7B007A415E /* GameObjects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GameObjects.cpp; sourceTree = "<group>"; };
+ 775D753915D29E7B007A415E /* GameObjects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameObjects.h; sourceTree = "<group>"; };
+ 775D753A15D29E7B007A415E /* GameState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameState.h; sourceTree = "<group>"; };
+ 775D753B15D29E7B007A415E /* Globals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Globals.cpp; sourceTree = "<group>"; };
+ 775D753C15D29E7B007A415E /* Globals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Globals.h; sourceTree = "<group>"; };
+ 775D753D15D29E7B007A415E /* GUIListBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIListBox.cpp; sourceTree = "<group>"; };
+ 775D753E15D29E7B007A415E /* GUIListBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIListBox.h; sourceTree = "<group>"; };
+ 775D753F15D29E7B007A415E /* GUIObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIObject.cpp; sourceTree = "<group>"; };
+ 775D754015D29E7B007A415E /* GUIObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIObject.h; sourceTree = "<group>"; };
+ 775D754115D29E7B007A415E /* GUIOverlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIOverlay.cpp; sourceTree = "<group>"; };
+ 775D754215D29E7B007A415E /* GUIOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIOverlay.h; sourceTree = "<group>"; };
+ 775D754315D29E7B007A415E /* GUIScrollBar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIScrollBar.cpp; sourceTree = "<group>"; };
+ 775D754415D29E7B007A415E /* GUIScrollBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIScrollBar.h; sourceTree = "<group>"; };
+ 775D754515D29E7B007A415E /* GUISlider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUISlider.cpp; sourceTree = "<group>"; };
+ 775D754615D29E7B007A415E /* GUISlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUISlider.h; sourceTree = "<group>"; };
+ 775D754715D29E7B007A415E /* GUITextArea.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUITextArea.cpp; sourceTree = "<group>"; };
+ 775D754815D29E7B007A415E /* GUITextArea.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUITextArea.h; sourceTree = "<group>"; };
+ 775D754915D29E7B007A415E /* ImageManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageManager.cpp; sourceTree = "<group>"; };
+ 775D754A15D29E7B007A415E /* ImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageManager.h; sourceTree = "<group>"; };
+ 775D754B15D29E7B007A415E /* InputManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InputManager.cpp; sourceTree = "<group>"; };
+ 775D754C15D29E7B007A415E /* InputManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputManager.h; sourceTree = "<group>"; };
+ 775D754D15D29E7B007A415E /* ITreeSerializer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ITreeSerializer.h; sourceTree = "<group>"; };
+ 775D754E15D29E7B007A415E /* ITreeStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ITreeStorage.h; sourceTree = "<group>"; };
+ 775D754F15D29E7B007A415E /* LevelEditor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LevelEditor.cpp; sourceTree = "<group>"; };
+ 775D755015D29E7B007A415E /* LevelEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelEditor.h; sourceTree = "<group>"; };
+ 775D755115D29E7B007A415E /* LevelEditSelect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LevelEditSelect.cpp; sourceTree = "<group>"; };
+ 775D755215D29E7B007A415E /* LevelEditSelect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelEditSelect.h; sourceTree = "<group>"; };
+ 775D755315D29E7B007A415E /* LevelPack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LevelPack.cpp; sourceTree = "<group>"; };
+ 775D755415D29E7B007A415E /* LevelPack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelPack.h; sourceTree = "<group>"; };
+ 775D755515D29E7B007A415E /* LevelPackManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LevelPackManager.cpp; sourceTree = "<group>"; };
+ 775D755615D29E7B007A415E /* LevelPackManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelPackManager.h; sourceTree = "<group>"; };
+ 775D755715D29E7B007A415E /* LevelPlaySelect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LevelPlaySelect.cpp; sourceTree = "<group>"; };
+ 775D755815D29E7B007A415E /* LevelPlaySelect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelPlaySelect.h; sourceTree = "<group>"; };
+ 775D755915D29E7B007A415E /* LevelSelect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LevelSelect.cpp; sourceTree = "<group>"; };
+ 775D755A15D29E7B007A415E /* LevelSelect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelSelect.h; sourceTree = "<group>"; };
+ 775D755D15D29E7B007A415E /* findlocale.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = findlocale.c; sourceTree = "<group>"; };
+ 775D755E15D29E7B007A415E /* findlocale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = findlocale.h; sourceTree = "<group>"; };
+ 775D756015D29E7B007A415E /* tinyformat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tinyformat.h; sourceTree = "<group>"; };
+ 775D756215D29E7B007A415E /* dictionary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dictionary.cpp; sourceTree = "<group>"; };
+ 775D756315D29E7B007A415E /* dictionary.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = dictionary.hpp; sourceTree = "<group>"; };
+ 775D756415D29E7B007A415E /* dictionary_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dictionary_manager.cpp; sourceTree = "<group>"; };
+ 775D756515D29E7B007A415E /* dictionary_manager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = dictionary_manager.hpp; sourceTree = "<group>"; };
+ 775D756615D29E7B007A415E /* file_system.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = file_system.hpp; sourceTree = "<group>"; };
+ 775D756715D29E7B007A415E /* language.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = language.cpp; sourceTree = "<group>"; };
+ 775D756815D29E7B007A415E /* language.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = language.hpp; sourceTree = "<group>"; };
+ 775D756915D29E7B007A415E /* log.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = log.cpp; sourceTree = "<group>"; };
+ 775D756A15D29E7B007A415E /* log.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = log.hpp; sourceTree = "<group>"; };
+ 775D756B15D29E7B007A415E /* log_stream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = log_stream.hpp; sourceTree = "<group>"; };
+ 775D756C15D29E7B007A415E /* plural_forms.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = plural_forms.cpp; sourceTree = "<group>"; };
+ 775D756D15D29E7B007A415E /* plural_forms.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = plural_forms.hpp; sourceTree = "<group>"; };
+ 775D756E15D29E7B007A415E /* po_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = po_parser.cpp; sourceTree = "<group>"; };
+ 775D756F15D29E7B007A415E /* po_parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = po_parser.hpp; sourceTree = "<group>"; };
+ 775D757015D29E7B007A415E /* tinygettext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinygettext.cpp; sourceTree = "<group>"; };
+ 775D757115D29E7B007A415E /* tinygettext.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = tinygettext.hpp; sourceTree = "<group>"; };
+ 775D757215D29E7B007A415E /* unix_file_system.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unix_file_system.cpp; sourceTree = "<group>"; };
+ 775D757315D29E7B007A415E /* unix_file_system.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = unix_file_system.hpp; sourceTree = "<group>"; };
+ 775D757715D29E7B007A415E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ 775D757815D29E7B007A415E /* meandmyshadow-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "meandmyshadow-Info.plist"; sourceTree = "<group>"; };
+ 775D757915D29E7B007A415E /* meandmyshadow-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "meandmyshadow-Prefix.pch"; sourceTree = "<group>"; };
+ 775D757A15D29E7B007A415E /* SDLMain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLMain.h; sourceTree = "<group>"; };
+ 775D757B15D29E7B007A415E /* SDLMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLMain.m; sourceTree = "<group>"; };
+ 775D757C15D29E7B007A415E /* meandmyshadow.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = meandmyshadow.icns; sourceTree = "<group>"; };
+ 775D757D15D29E7B007A415E /* meandmyshadow.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = meandmyshadow.xcodeproj; sourceTree = "<group>"; };
+ 775D758015D29E7B007A415E /* Main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Main.cpp; sourceTree = "<group>"; };
+ 775D758115D29E7B007A415E /* MD5.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MD5.cpp; sourceTree = "<group>"; };
+ 775D758215D29E7B007A415E /* MD5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MD5.h; sourceTree = "<group>"; };
+ 775D758315D29E7B007A415E /* MusicManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MusicManager.cpp; sourceTree = "<group>"; };
+ 775D758415D29E7B007A415E /* MusicManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MusicManager.h; sourceTree = "<group>"; };
+ 775D758515D29E7B007A415E /* Objects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Objects.cpp; sourceTree = "<group>"; };
+ 775D758615D29E7B007A415E /* Objects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Objects.h; sourceTree = "<group>"; };
+ 775D758715D29E7B007A415E /* Player.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Player.cpp; sourceTree = "<group>"; };
+ 775D758815D29E7B007A415E /* Player.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Player.h; sourceTree = "<group>"; };
+ 775D758915D29E7B007A415E /* POASerializer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = POASerializer.cpp; sourceTree = "<group>"; };
+ 775D758A15D29E7B007A415E /* POASerializer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = POASerializer.h; sourceTree = "<group>"; };
+ 775D758B15D29E7B007A415E /* Settings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Settings.cpp; sourceTree = "<group>"; };
+ 775D758C15D29E7B007A415E /* Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Settings.h; sourceTree = "<group>"; };
+ 775D758D15D29E7B007A415E /* Shadow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Shadow.cpp; sourceTree = "<group>"; };
+ 775D758E15D29E7B007A415E /* Shadow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shadow.h; sourceTree = "<group>"; };
+ 775D758F15D29E7B007A415E /* StatisticsManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StatisticsManager.cpp; sourceTree = "<group>"; };
+ 775D759015D29E7B007A415E /* StatisticsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatisticsManager.h; sourceTree = "<group>"; };
+ 775D759115D29E7B007A415E /* StatisticsScreen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StatisticsScreen.cpp; sourceTree = "<group>"; };
+ 775D759215D29E7B007A415E /* StatisticsScreen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatisticsScreen.h; sourceTree = "<group>"; };
+ 775D759315D29E7B007A415E /* ThemeManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThemeManager.cpp; sourceTree = "<group>"; };
+ 775D759415D29E7B007A415E /* ThemeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThemeManager.h; sourceTree = "<group>"; };
+ 775D759515D29E7B007A415E /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Timer.cpp; sourceTree = "<group>"; };
+ 775D759615D29E7B007A415E /* Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Timer.h; sourceTree = "<group>"; };
+ 775D759715D29E7B007A415E /* TitleMenu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TitleMenu.cpp; sourceTree = "<group>"; };
+ 775D759815D29E7B007A415E /* TitleMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TitleMenu.h; sourceTree = "<group>"; };
+ 775D759915D29E7B007A415E /* TreeStorageNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TreeStorageNode.cpp; sourceTree = "<group>"; };
+ 775D759A15D29E7B007A415E /* TreeStorageNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TreeStorageNode.h; sourceTree = "<group>"; };
+ 775D75CC15D29E9D007A415E /* data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = data; path = ../../../data; sourceTree = "<group>"; };
+ 775D75CE15D2A4C7007A415E /* libarchive.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libarchive.dylib; path = usr/lib/libarchive.dylib; sourceTree = SDKROOT; };
+ 775D75D115D2A4DE007A415E /* libcurl.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcurl.dylib; path = usr/lib/libcurl.dylib; sourceTree = SDKROOT; };
+ 775D75D815D2A890007A415E /* archive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive.h; sourceTree = "<group>"; };
+ 775D75D915D2A890007A415E /* archive_crc32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_crc32.h; sourceTree = "<group>"; };
+ 775D75DA15D2A890007A415E /* archive_endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_endian.h; sourceTree = "<group>"; };
+ 775D75DB15D2A890007A415E /* archive_entry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_entry.h; sourceTree = "<group>"; };
+ 775D75DC15D2A890007A415E /* archive_entry_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_entry_private.h; sourceTree = "<group>"; };
+ 775D75DD15D2A890007A415E /* archive_hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_hash.h; sourceTree = "<group>"; };
+ 775D75DE15D2A890007A415E /* archive_platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_platform.h; sourceTree = "<group>"; };
+ 775D75DF15D2A890007A415E /* archive_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_private.h; sourceTree = "<group>"; };
+ 775D75E015D2A890007A415E /* archive_read_disk_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_read_disk_private.h; sourceTree = "<group>"; };
+ 775D75E115D2A890007A415E /* archive_read_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_read_private.h; sourceTree = "<group>"; };
+ 775D75E215D2A890007A415E /* archive_string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_string.h; sourceTree = "<group>"; };
+ 775D75E315D2A890007A415E /* archive_windows.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_windows.h; sourceTree = "<group>"; };
+ 775D75E415D2A890007A415E /* archive_write_disk_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_write_disk_private.h; sourceTree = "<group>"; };
+ 775D75E515D2A890007A415E /* archive_write_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_write_private.h; sourceTree = "<group>"; };
+ 775D75E615D2A890007A415E /* config_freebsd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config_freebsd.h; sourceTree = "<group>"; };
+ 775D75E715D2A890007A415E /* filter_fork.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filter_fork.h; sourceTree = "<group>"; };
+ 7771220215D290B800F09E41 /* meandmyshadow.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = meandmyshadow.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7771220915D290B800F09E41 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
+ 7771220A15D290B800F09E41 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
+ 7771220B15D290B800F09E41 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 7771220E15D290B800F09E41 /* meandmyshadow-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "meandmyshadow-Info.plist"; sourceTree = "<group>"; };
+ 7771221015D290B800F09E41 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ 7771221415D290B800F09E41 /* meandmyshadow-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "meandmyshadow-Prefix.pch"; sourceTree = "<group>"; };
+ 77ED9D9915D29AD1009B0CE9 /* meandmyshadow.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = meandmyshadow.icns; sourceTree = SOURCE_ROOT; };
+ 77ED9D9B15D29CFB009B0CE9 /* SDLMain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLMain.h; sourceTree = "<group>"; };
+ 77ED9D9C15D29CFB009B0CE9 /* SDLMain.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLMain.m; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 777121FF15D290B800F09E41 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 77019FA615D2D09A0085E7EC /* SDL_gfx.framework in Frameworks */,
+ 77019FA715D2D09A0085E7EC /* SDL_image.framework in Frameworks */,
+ 77019FA815D2D09A0085E7EC /* SDL_mixer.framework in Frameworks */,
+ 77019FA915D2D09A0085E7EC /* SDL_ttf.framework in Frameworks */,
+ 77019FAA15D2D09A0085E7EC /* SDL.framework in Frameworks */,
+ 77019F9615D2C5020085E7EC /* Cocoa.framework in Frameworks */,
+ 77019F9415D2C4F90085E7EC /* OpenGL.framework in Frameworks */,
+ 775D75D315D2A4E6007A415E /* libcurl.dylib in Frameworks */,
+ 775D75D015D2A4D1007A415E /* libarchive.dylib in Frameworks */,
+ 775D751515D29DC3007A415E /* libcrypto.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 775D752C15D29E7B007A415E /* src */ = {
+ isa = PBXGroup;
+ children = (
+ 775D752D15D29E7B007A415E /* Addons.cpp */,
+ 775D752E15D29E7B007A415E /* Addons.h */,
+ 775D752F15D29E7B007A415E /* Block.cpp */,
+ 775D753015D29E7B007A415E /* Block.h */,
+ 775D753115D29E7B007A415E /* config.h.in */,
+ 775D753215D29E7B007A415E /* FileManager.cpp */,
+ 775D753315D29E7B007A415E /* FileManager.h */,
+ 775D753415D29E7B007A415E /* Functions.cpp */,
+ 775D753515D29E7B007A415E /* Functions.h */,
+ 775D753615D29E7B007A415E /* Game.cpp */,
+ 775D753715D29E7B007A415E /* Game.h */,
+ 775D753815D29E7B007A415E /* GameObjects.cpp */,
+ 775D753915D29E7B007A415E /* GameObjects.h */,
+ 775D753A15D29E7B007A415E /* GameState.h */,
+ 775D753B15D29E7B007A415E /* Globals.cpp */,
+ 775D753C15D29E7B007A415E /* Globals.h */,
+ 775D753D15D29E7B007A415E /* GUIListBox.cpp */,
+ 775D753E15D29E7B007A415E /* GUIListBox.h */,
+ 775D753F15D29E7B007A415E /* GUIObject.cpp */,
+ 775D754015D29E7B007A415E /* GUIObject.h */,
+ 775D754115D29E7B007A415E /* GUIOverlay.cpp */,
+ 775D754215D29E7B007A415E /* GUIOverlay.h */,
+ 775D754315D29E7B007A415E /* GUIScrollBar.cpp */,
+ 775D754415D29E7B007A415E /* GUIScrollBar.h */,
+ 775D754515D29E7B007A415E /* GUISlider.cpp */,
+ 775D754615D29E7B007A415E /* GUISlider.h */,
+ 775D754715D29E7B007A415E /* GUITextArea.cpp */,
+ 775D754815D29E7B007A415E /* GUITextArea.h */,
+ 775D754915D29E7B007A415E /* ImageManager.cpp */,
+ 775D754A15D29E7B007A415E /* ImageManager.h */,
+ 775D754B15D29E7B007A415E /* InputManager.cpp */,
+ 775D754C15D29E7B007A415E /* InputManager.h */,
+ 775D754D15D29E7B007A415E /* ITreeSerializer.h */,
+ 775D754E15D29E7B007A415E /* ITreeStorage.h */,
+ 775D754F15D29E7B007A415E /* LevelEditor.cpp */,
+ 775D755015D29E7B007A415E /* LevelEditor.h */,
+ 775D755115D29E7B007A415E /* LevelEditSelect.cpp */,
+ 775D755215D29E7B007A415E /* LevelEditSelect.h */,
+ 775D755315D29E7B007A415E /* LevelPack.cpp */,
+ 775D755415D29E7B007A415E /* LevelPack.h */,
+ 775D755515D29E7B007A415E /* LevelPackManager.cpp */,
+ 775D755615D29E7B007A415E /* LevelPackManager.h */,
+ 775D755715D29E7B007A415E /* LevelPlaySelect.cpp */,
+ 775D755815D29E7B007A415E /* LevelPlaySelect.h */,
+ 775D755915D29E7B007A415E /* LevelSelect.cpp */,
+ 775D755A15D29E7B007A415E /* LevelSelect.h */,
+ 775D755B15D29E7B007A415E /* libs */,
+ 775D757415D29E7B007A415E /* mac */,
+ 775D758015D29E7B007A415E /* Main.cpp */,
+ 775D758115D29E7B007A415E /* MD5.cpp */,
+ 775D758215D29E7B007A415E /* MD5.h */,
+ 775D758315D29E7B007A415E /* MusicManager.cpp */,
+ 775D758415D29E7B007A415E /* MusicManager.h */,
+ 775D758515D29E7B007A415E /* Objects.cpp */,
+ 775D758615D29E7B007A415E /* Objects.h */,
+ 775D758715D29E7B007A415E /* Player.cpp */,
+ 775D758815D29E7B007A415E /* Player.h */,
+ 775D758915D29E7B007A415E /* POASerializer.cpp */,
+ 775D758A15D29E7B007A415E /* POASerializer.h */,
+ 775D758B15D29E7B007A415E /* Settings.cpp */,
+ 775D758C15D29E7B007A415E /* Settings.h */,
+ 775D758D15D29E7B007A415E /* Shadow.cpp */,
+ 775D758E15D29E7B007A415E /* Shadow.h */,
+ 775D758F15D29E7B007A415E /* StatisticsManager.cpp */,
+ 775D759015D29E7B007A415E /* StatisticsManager.h */,
+ 775D759115D29E7B007A415E /* StatisticsScreen.cpp */,
+ 775D759215D29E7B007A415E /* StatisticsScreen.h */,
+ 775D759315D29E7B007A415E /* ThemeManager.cpp */,
+ 775D759415D29E7B007A415E /* ThemeManager.h */,
+ 775D759515D29E7B007A415E /* Timer.cpp */,
+ 775D759615D29E7B007A415E /* Timer.h */,
+ 775D759715D29E7B007A415E /* TitleMenu.cpp */,
+ 775D759815D29E7B007A415E /* TitleMenu.h */,
+ 775D759915D29E7B007A415E /* TreeStorageNode.cpp */,
+ 775D759A15D29E7B007A415E /* TreeStorageNode.h */,
+ );
+ name = src;
+ path = ../..;
+ sourceTree = "<group>";
+ };
+ 775D755B15D29E7B007A415E /* libs */ = {
+ isa = PBXGroup;
+ children = (
+ 775D755C15D29E7B007A415E /* findlocale */,
+ 775D755F15D29E7B007A415E /* tinyformat */,
+ 775D756115D29E7B007A415E /* tinygettext */,
+ );
+ path = libs;
+ sourceTree = "<group>";
+ };
+ 775D755C15D29E7B007A415E /* findlocale */ = {
+ isa = PBXGroup;
+ children = (
+ 775D755D15D29E7B007A415E /* findlocale.c */,
+ 775D755E15D29E7B007A415E /* findlocale.h */,
+ );
+ path = findlocale;
+ sourceTree = "<group>";
+ };
+ 775D755F15D29E7B007A415E /* tinyformat */ = {
+ isa = PBXGroup;
+ children = (
+ 775D756015D29E7B007A415E /* tinyformat.h */,
+ );
+ path = tinyformat;
+ sourceTree = "<group>";
+ };
+ 775D756115D29E7B007A415E /* tinygettext */ = {
+ isa = PBXGroup;
+ children = (
+ 775D756215D29E7B007A415E /* dictionary.cpp */,
+ 775D756315D29E7B007A415E /* dictionary.hpp */,
+ 775D756415D29E7B007A415E /* dictionary_manager.cpp */,
+ 775D756515D29E7B007A415E /* dictionary_manager.hpp */,
+ 775D756615D29E7B007A415E /* file_system.hpp */,
+ 775D756715D29E7B007A415E /* language.cpp */,
+ 775D756815D29E7B007A415E /* language.hpp */,
+ 775D756915D29E7B007A415E /* log.cpp */,
+ 775D756A15D29E7B007A415E /* log.hpp */,
+ 775D756B15D29E7B007A415E /* log_stream.hpp */,
+ 775D756C15D29E7B007A415E /* plural_forms.cpp */,
+ 775D756D15D29E7B007A415E /* plural_forms.hpp */,
+ 775D756E15D29E7B007A415E /* po_parser.cpp */,
+ 775D756F15D29E7B007A415E /* po_parser.hpp */,
+ 775D757015D29E7B007A415E /* tinygettext.cpp */,
+ 775D757115D29E7B007A415E /* tinygettext.hpp */,
+ 775D757215D29E7B007A415E /* unix_file_system.cpp */,
+ 775D757315D29E7B007A415E /* unix_file_system.hpp */,
+ );
+ path = tinygettext;
+ sourceTree = "<group>";
+ };
+ 775D757415D29E7B007A415E /* mac */ = {
+ isa = PBXGroup;
+ children = (
+ 775D757515D29E7B007A415E /* meandmyshadow */,
+ 775D757C15D29E7B007A415E /* meandmyshadow.icns */,
+ 775D757D15D29E7B007A415E /* meandmyshadow.xcodeproj */,
+ );
+ path = mac;
+ sourceTree = "<group>";
+ };
+ 775D757515D29E7B007A415E /* meandmyshadow */ = {
+ isa = PBXGroup;
+ children = (
+ 775D757615D29E7B007A415E /* InfoPlist.strings */,
+ 775D757815D29E7B007A415E /* meandmyshadow-Info.plist */,
+ 775D757915D29E7B007A415E /* meandmyshadow-Prefix.pch */,
+ 775D757A15D29E7B007A415E /* SDLMain.h */,
+ 775D757B15D29E7B007A415E /* SDLMain.m */,
+ );
+ path = meandmyshadow;
+ sourceTree = "<group>";
+ };
+ 775D757E15D29E7B007A415E /* Products */ = {
+ isa = PBXGroup;
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 775D75D715D2A890007A415E /* archive */ = {
+ isa = PBXGroup;
+ children = (
+ 775D75D815D2A890007A415E /* archive.h */,
+ 775D75D915D2A890007A415E /* archive_crc32.h */,
+ 775D75DA15D2A890007A415E /* archive_endian.h */,
+ 775D75DB15D2A890007A415E /* archive_entry.h */,
+ 775D75DC15D2A890007A415E /* archive_entry_private.h */,
+ 775D75DD15D2A890007A415E /* archive_hash.h */,
+ 775D75DE15D2A890007A415E /* archive_platform.h */,
+ 775D75DF15D2A890007A415E /* archive_private.h */,
+ 775D75E015D2A890007A415E /* archive_read_disk_private.h */,
+ 775D75E115D2A890007A415E /* archive_read_private.h */,
+ 775D75E215D2A890007A415E /* archive_string.h */,
+ 775D75E315D2A890007A415E /* archive_windows.h */,
+ 775D75E415D2A890007A415E /* archive_write_disk_private.h */,
+ 775D75E515D2A890007A415E /* archive_write_private.h */,
+ 775D75E615D2A890007A415E /* config_freebsd.h */,
+ 775D75E715D2A890007A415E /* filter_fork.h */,
+ );
+ path = archive;
+ sourceTree = "<group>";
+ };
+ 777121F715D290B800F09E41 = {
+ isa = PBXGroup;
+ children = (
+ 7771220C15D290B800F09E41 /* meandmyshadow */,
+ 7771220515D290B800F09E41 /* Frameworks */,
+ 7771220315D290B800F09E41 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ 7771220315D290B800F09E41 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 7771220215D290B800F09E41 /* meandmyshadow.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 7771220515D290B800F09E41 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 77019F9C15D2D0890085E7EC /* SDL_gfx.framework */,
+ 77019F9D15D2D0890085E7EC /* SDL_image.framework */,
+ 77019F9E15D2D0890085E7EC /* SDL_mixer.framework */,
+ 77019F9F15D2D0890085E7EC /* SDL_ttf.framework */,
+ 77019FA015D2D08A0085E7EC /* SDL.framework */,
+ 77019F9515D2C5020085E7EC /* Cocoa.framework */,
+ 77019F9315D2C4F90085E7EC /* OpenGL.framework */,
+ 775D75D115D2A4DE007A415E /* libcurl.dylib */,
+ 775D75CE15D2A4C7007A415E /* libarchive.dylib */,
+ 775D751415D29DC3007A415E /* libcrypto.dylib */,
+ 7771220815D290B800F09E41 /* Other Frameworks */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 7771220815D290B800F09E41 /* Other Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 7771220915D290B800F09E41 /* AppKit.framework */,
+ 7771220A15D290B800F09E41 /* CoreData.framework */,
+ 7771220B15D290B800F09E41 /* Foundation.framework */,
+ );
+ name = "Other Frameworks";
+ sourceTree = "<group>";
+ };
+ 7771220C15D290B800F09E41 /* meandmyshadow */ = {
+ isa = PBXGroup;
+ children = (
+ 775D75D715D2A890007A415E /* archive */,
+ 775D752C15D29E7B007A415E /* src */,
+ 77ED9D9B15D29CFB009B0CE9 /* SDLMain.h */,
+ 77ED9D9C15D29CFB009B0CE9 /* SDLMain.m */,
+ 7771220D15D290B800F09E41 /* Supporting Files */,
+ 775B108515D2B06E007AEED5 /* osx_helpers.mm */,
+ );
+ path = meandmyshadow;
+ sourceTree = "<group>";
+ };
+ 7771220D15D290B800F09E41 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 775D75CC15D29E9D007A415E /* data */,
+ 77ED9D9915D29AD1009B0CE9 /* meandmyshadow.icns */,
+ 7771220E15D290B800F09E41 /* meandmyshadow-Info.plist */,
+ 7771220F15D290B800F09E41 /* InfoPlist.strings */,
+ 7771221415D290B800F09E41 /* meandmyshadow-Prefix.pch */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 7771220115D290B800F09E41 /* meandmyshadow */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7771222015D290B800F09E41 /* Build configuration list for PBXNativeTarget "meandmyshadow" */;
+ buildPhases = (
+ 777121FE15D290B800F09E41 /* Sources */,
+ 777121FF15D290B800F09E41 /* Frameworks */,
+ 7771220015D290B800F09E41 /* Resources */,
+ 775B108715D2B765007AEED5 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = meandmyshadow;
+ productName = meandmyshadow;
+ productReference = 7771220215D290B800F09E41 /* meandmyshadow.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 777121F915D290B800F09E41 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0430;
+ ORGANIZATIONNAME = "General Arcade";
+ };
+ buildConfigurationList = 777121FC15D290B800F09E41 /* Build configuration list for PBXProject "meandmyshadow" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 777121F715D290B800F09E41;
+ productRefGroup = 7771220315D290B800F09E41 /* Products */;
+ projectDirPath = "";
+ projectReferences = (
+ {
+ ProductGroup = 775D757E15D29E7B007A415E /* Products */;
+ ProjectRef = 775D757D15D29E7B007A415E /* meandmyshadow.xcodeproj */;
+ },
+ );
+ projectRoot = "";
+ targets = (
+ 7771220115D290B800F09E41 /* meandmyshadow */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 7771220015D290B800F09E41 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7771221115D290B800F09E41 /* InfoPlist.strings in Resources */,
+ 77ED9D9A15D29AD1009B0CE9 /* meandmyshadow.icns in Resources */,
+ 775D759D15D29E7B007A415E /* config.h.in in Resources */,
+ 775D75BA15D29E7B007A415E /* InfoPlist.strings in Resources */,
+ 775D75BB15D29E7B007A415E /* meandmyshadow-Info.plist in Resources */,
+ 775D75BD15D29E7B007A415E /* meandmyshadow.icns in Resources */,
+ 775D75CD15D29E9D007A415E /* data in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 777121FE15D290B800F09E41 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 77ED9D9D15D29D0E009B0CE9 /* SDLMain.m in Sources */,
+ 775D759B15D29E7B007A415E /* Addons.cpp in Sources */,
+ 775D759C15D29E7B007A415E /* Block.cpp in Sources */,
+ 775D759E15D29E7B007A415E /* FileManager.cpp in Sources */,
+ 775D759F15D29E7B007A415E /* Functions.cpp in Sources */,
+ 775D75A015D29E7B007A415E /* Game.cpp in Sources */,
+ 775D75A115D29E7B007A415E /* GameObjects.cpp in Sources */,
+ 775D75A215D29E7B007A415E /* Globals.cpp in Sources */,
+ 775D75A315D29E7B007A415E /* GUIListBox.cpp in Sources */,
+ 775D75A415D29E7B007A415E /* GUIObject.cpp in Sources */,
+ 775D75A515D29E7B007A415E /* GUIOverlay.cpp in Sources */,
+ 775D75A615D29E7B007A415E /* GUIScrollBar.cpp in Sources */,
+ 775D75A715D29E7B007A415E /* GUISlider.cpp in Sources */,
+ 775D75A815D29E7B007A415E /* GUITextArea.cpp in Sources */,
+ 775D75A915D29E7B007A415E /* ImageManager.cpp in Sources */,
+ 775D75AA15D29E7B007A415E /* InputManager.cpp in Sources */,
+ 775D75AB15D29E7B007A415E /* LevelEditor.cpp in Sources */,
+ 775D75AC15D29E7B007A415E /* LevelEditSelect.cpp in Sources */,
+ 775D75AD15D29E7B007A415E /* LevelPack.cpp in Sources */,
+ 775D75AE15D29E7B007A415E /* LevelPackManager.cpp in Sources */,
+ 775D75AF15D29E7B007A415E /* LevelPlaySelect.cpp in Sources */,
+ 775D75B015D29E7B007A415E /* LevelSelect.cpp in Sources */,
+ 775D75B115D29E7B007A415E /* findlocale.c in Sources */,
+ 775D75B215D29E7B007A415E /* dictionary.cpp in Sources */,
+ 775D75B315D29E7B007A415E /* dictionary_manager.cpp in Sources */,
+ 775D75B415D29E7B007A415E /* language.cpp in Sources */,
+ 775D75B515D29E7B007A415E /* log.cpp in Sources */,
+ 775D75B615D29E7B007A415E /* plural_forms.cpp in Sources */,
+ 775D75B715D29E7B007A415E /* po_parser.cpp in Sources */,
+ 775D75B815D29E7B007A415E /* tinygettext.cpp in Sources */,
+ 775D75B915D29E7B007A415E /* unix_file_system.cpp in Sources */,
+ 775D75BE15D29E7B007A415E /* Main.cpp in Sources */,
+ 775D75BF15D29E7B007A415E /* MD5.cpp in Sources */,
+ 775D75C015D29E7B007A415E /* MusicManager.cpp in Sources */,
+ 775D75C115D29E7B007A415E /* Objects.cpp in Sources */,
+ 775D75C215D29E7B007A415E /* Player.cpp in Sources */,
+ 775D75C315D29E7B007A415E /* POASerializer.cpp in Sources */,
+ 775D75C415D29E7B007A415E /* Settings.cpp in Sources */,
+ 775D75C515D29E7B007A415E /* Shadow.cpp in Sources */,
+ 775D75C615D29E7B007A415E /* StatisticsManager.cpp in Sources */,
+ 775D75C715D29E7B007A415E /* StatisticsScreen.cpp in Sources */,
+ 775D75C815D29E7B007A415E /* ThemeManager.cpp in Sources */,
+ 775D75C915D29E7B007A415E /* Timer.cpp in Sources */,
+ 775D75CA15D29E7B007A415E /* TitleMenu.cpp in Sources */,
+ 775D75CB15D29E7B007A415E /* TreeStorageNode.cpp in Sources */,
+ 775B108615D2B06E007AEED5 /* osx_helpers.mm in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 775D757615D29E7B007A415E /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 775D757715D29E7B007A415E /* en */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+ 7771220F15D290B800F09E41 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 7771221015D290B800F09E41 /* en */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 7771221E15D290B800F09E41 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ COPY_PHASE_STRIP = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.7;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = macosx;
+ };
+ name = Debug;
+ };
+ 7771221F15D290B800F09E41 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.7;
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
+ 7771222115D290B800F09E41 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ FRAMEWORK_SEARCH_PATHS = /Library/Frameworks/;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "meandmyshadow/meandmyshadow-Prefix.pch";
+ HEADER_SEARCH_PATHS = /Library/Frameworks/SDL.framework/Headers;
+ INFOPLIST_FILE = "meandmyshadow/meandmyshadow-Info.plist";
+ MACOSX_DEPLOYMENT_TARGET = 10.5;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ USER_HEADER_SEARCH_PATHS = "";
+ WRAPPER_EXTENSION = app;
+ };
+ name = Debug;
+ };
+ 7771222215D290B800F09E41 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ FRAMEWORK_SEARCH_PATHS = /Library/Frameworks/;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "meandmyshadow/meandmyshadow-Prefix.pch";
+ HEADER_SEARCH_PATHS = /Library/Frameworks/SDL.framework/Headers;
+ INFOPLIST_FILE = "meandmyshadow/meandmyshadow-Info.plist";
+ MACOSX_DEPLOYMENT_TARGET = 10.5;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ USER_HEADER_SEARCH_PATHS = "";
+ WRAPPER_EXTENSION = app;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 777121FC15D290B800F09E41 /* Build configuration list for PBXProject "meandmyshadow" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7771221E15D290B800F09E41 /* Debug */,
+ 7771221F15D290B800F09E41 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7771222015D290B800F09E41 /* Build configuration list for PBXNativeTarget "meandmyshadow" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7771222115D290B800F09E41 /* Debug */,
+ 7771222215D290B800F09E41 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 777121F915D290B800F09E41 /* Project object */;
+}
diff --git a/src/mac/meandmyshadow.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/src/mac/meandmyshadow.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..989fcda
--- /dev/null
+++ b/src/mac/meandmyshadow.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:meandmyshadow.xcodeproj">
+ </FileRef>
+</Workspace>
diff --git a/src/mac/meandmyshadow/SDLMain.h b/src/mac/meandmyshadow/SDLMain.h
new file mode 100644
index 0000000..c56d90c
--- /dev/null
+++ b/src/mac/meandmyshadow/SDLMain.h
@@ -0,0 +1,16 @@
+/* SDLMain.m - main entry point for our Cocoa-ized SDL app
+ Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
+ Non-NIB-Code & other changes: Max Horn <max@quendi.de>
+
+ Feel free to customize this file to suit your needs
+*/
+
+#ifndef _SDLMain_h_
+#define _SDLMain_h_
+
+#import <Cocoa/Cocoa.h>
+
+@interface SDLMain : NSObject
+@end
+
+#endif /* _SDLMain_h_ */
diff --git a/src/mac/meandmyshadow/SDLMain.m b/src/mac/meandmyshadow/SDLMain.m
new file mode 100644
index 0000000..2434f81
--- /dev/null
+++ b/src/mac/meandmyshadow/SDLMain.m
@@ -0,0 +1,381 @@
+/* SDLMain.m - main entry point for our Cocoa-ized SDL app
+ Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
+ Non-NIB-Code & other changes: Max Horn <max@quendi.de>
+
+ Feel free to customize this file to suit your needs
+*/
+
+#include "SDL.h"
+#include "SDLMain.h"
+#include <sys/param.h> /* for MAXPATHLEN */
+#include <unistd.h>
+
+/* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
+ but the method still is there and works. To avoid warnings, we declare
+ it ourselves here. */
+@interface NSApplication(SDL_Missing_Methods)
+- (void)setAppleMenu:(NSMenu *)menu;
+@end
+
+/* Use this flag to determine whether we use SDLMain.nib or not */
+#define SDL_USE_NIB_FILE 0
+
+/* Use this flag to determine whether we use CPS (docking) or not */
+#define SDL_USE_CPS 1
+#ifdef SDL_USE_CPS
+/* Portions of CPS.h */
+typedef struct CPSProcessSerNum
+{
+ UInt32 lo;
+ UInt32 hi;
+} CPSProcessSerNum;
+
+extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
+extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
+extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
+
+#endif /* SDL_USE_CPS */
+
+static int gArgc;
+static char **gArgv;
+static BOOL gFinderLaunch;
+static BOOL gCalledAppMainline = FALSE;
+
+static NSString *getApplicationName(void)
+{
+ const NSDictionary *dict;
+ NSString *appName = 0;
+
+ /* Determine the application name */
+ dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
+ if (dict)
+ appName = [dict objectForKey: @"CFBundleName"];
+
+ if (![appName length])
+ appName = [[NSProcessInfo processInfo] processName];
+
+ return appName;
+}
+
+#if SDL_USE_NIB_FILE
+/* A helper category for NSString */
+@interface NSString (ReplaceSubString)
+- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
+@end
+#endif
+
+@interface NSApplication (SDLApplication)
+@end
+
+@implementation NSApplication (SDLApplication)
+/* Invoked from the Quit menu item */
+- (void)terminate:(id)sender
+{
+ /* Post a SDL_QUIT event */
+ SDL_Event event;
+ event.type = SDL_QUIT;
+ SDL_PushEvent(&event);
+}
+@end
+
+/* The main class of the application, the application's delegate */
+@implementation SDLMain
+
+/* Set the working directory to the .app's parent directory */
+- (void) setupWorkingDirectory:(BOOL)shouldChdir
+{
+ if (shouldChdir)
+ {
+ char parentdir[MAXPATHLEN];
+ CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+ CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
+ if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) {
+ chdir(parentdir); /* chdir to the binary app's parent */
+ }
+ CFRelease(url);
+ CFRelease(url2);
+ }
+}
+
+#if SDL_USE_NIB_FILE
+
+/* Fix menu to contain the real app name instead of "SDL App" */
+- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
+{
+ NSRange aRange;
+ NSEnumerator *enumerator;
+ NSMenuItem *menuItem;
+
+ aRange = [[aMenu title] rangeOfString:@"SDL App"];
+ if (aRange.length != 0)
+ [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
+
+ enumerator = [[aMenu itemArray] objectEnumerator];
+ while ((menuItem = [enumerator nextObject]))
+ {
+ aRange = [[menuItem title] rangeOfString:@"SDL App"];
+ if (aRange.length != 0)
+ [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
+ if ([menuItem hasSubmenu])
+ [self fixMenu:[menuItem submenu] withAppName:appName];
+ }
+}
+
+#else
+
+static void setApplicationMenu(void)
+{
+ /* warning: this code is very odd */
+ NSMenu *appleMenu;
+ NSMenuItem *menuItem;
+ NSString *title;
+ NSString *appName;
+
+ appName = getApplicationName();
+ appleMenu = [[NSMenu alloc] initWithTitle:@""];
+
+ /* Add menu items */
+ title = [@"About " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ title = [@"Hide " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
+
+ menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+ [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
+
+ [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ title = [@"Quit " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
+
+
+ /* Put menu into the menubar */
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+ [menuItem setSubmenu:appleMenu];
+ [[NSApp mainMenu] addItem:menuItem];
+
+ /* Tell the application object that this is now the application menu */
+ [NSApp setAppleMenu:appleMenu];
+
+ /* Finally give up our references to the objects */
+ [appleMenu release];
+ [menuItem release];
+}
+
+/* Create a window menu */
+static void setupWindowMenu(void)
+{
+ NSMenu *windowMenu;
+ NSMenuItem *windowMenuItem;
+ NSMenuItem *menuItem;
+
+ windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+
+ /* "Minimize" item */
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
+ [windowMenu addItem:menuItem];
+ [menuItem release];
+
+ /* Put menu into the menubar */
+ windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
+ [windowMenuItem setSubmenu:windowMenu];
+ [[NSApp mainMenu] addItem:windowMenuItem];
+
+ /* Tell the application object that this is now the window menu */
+ [NSApp setWindowsMenu:windowMenu];
+
+ /* Finally give up our references to the objects */
+ [windowMenu release];
+ [windowMenuItem release];
+}
+
+/* Replacement for NSApplicationMain */
+static void CustomApplicationMain (int argc, char **argv)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ SDLMain *sdlMain;
+
+ /* Ensure the application object is initialised */
+ [NSApplication sharedApplication];
+
+#ifdef SDL_USE_CPS
+ {
+ CPSProcessSerNum PSN;
+ /* Tell the dock about us */
+ if (!CPSGetCurrentProcess(&PSN))
+ if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
+ if (!CPSSetFrontProcess(&PSN))
+ [NSApplication sharedApplication];
+ }
+#endif /* SDL_USE_CPS */
+
+ /* Set up the menubar */
+ [NSApp setMainMenu:[[NSMenu alloc] init]];
+ setApplicationMenu();
+ setupWindowMenu();
+
+ /* Create SDLMain and make it the app delegate */
+ sdlMain = [[SDLMain alloc] init];
+ [NSApp setDelegate:sdlMain];
+
+ /* Start the main event loop */
+ [NSApp run];
+
+ [sdlMain release];
+ [pool release];
+}
+
+#endif
+
+
+/*
+ * Catch document open requests...this lets us notice files when the app
+ * was launched by double-clicking a document, or when a document was
+ * dragged/dropped on the app's icon. You need to have a
+ * CFBundleDocumentsType section in your Info.plist to get this message,
+ * apparently.
+ *
+ * Files are added to gArgv, so to the app, they'll look like command line
+ * arguments. Previously, apps launched from the finder had nothing but
+ * an argv[0].
+ *
+ * This message may be received multiple times to open several docs on launch.
+ *
+ * This message is ignored once the app's mainline has been called.
+ */
+- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
+{
+ const char *temparg;
+ size_t arglen;
+ char *arg;
+ char **newargv;
+
+ if (!gFinderLaunch) /* MacOS is passing command line args. */
+ return FALSE;
+
+ if (gCalledAppMainline) /* app has started, ignore this document. */
+ return FALSE;
+
+ temparg = [filename UTF8String];
+ arglen = SDL_strlen(temparg) + 1;
+ arg = (char *) SDL_malloc(arglen);
+ if (arg == NULL)
+ return FALSE;
+
+ newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
+ if (newargv == NULL)
+ {
+ SDL_free(arg);
+ return FALSE;
+ }
+ gArgv = newargv;
+
+ SDL_strlcpy(arg, temparg, arglen);
+ gArgv[gArgc++] = arg;
+ gArgv[gArgc] = NULL;
+ return TRUE;
+}
+
+
+/* Called when the internal event loop has just started running */
+- (void) applicationDidFinishLaunching: (NSNotification *) note
+{
+ int status;
+
+ /* Set the working directory to the .app's parent directory */
+ [self setupWorkingDirectory:gFinderLaunch];
+
+#if SDL_USE_NIB_FILE
+ /* Set the main menu to contain the real app name instead of "SDL App" */
+ [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
+#endif
+
+ /* Hand off to main application code */
+ gCalledAppMainline = TRUE;
+ status = SDL_main (gArgc, gArgv);
+
+ /* We're done, thank you for playing */
+ exit(status);
+}
+@end
+
+
+@implementation NSString (ReplaceSubString)
+
+- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
+{
+ unsigned int bufferSize;
+ unsigned int selfLen = [self length];
+ unsigned int aStringLen = [aString length];
+ unichar *buffer;
+ NSRange localRange;
+ NSString *result;
+
+ bufferSize = selfLen + aStringLen - aRange.length;
+ buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));
+
+ /* Get first part into buffer */
+ localRange.location = 0;
+ localRange.length = aRange.location;
+ [self getCharacters:buffer range:localRange];
+
+ /* Get middle part into buffer */
+ localRange.location = 0;
+ localRange.length = aStringLen;
+ [aString getCharacters:(buffer+aRange.location) range:localRange];
+
+ /* Get last part into buffer */
+ localRange.location = aRange.location + aRange.length;
+ localRange.length = selfLen - localRange.location;
+ [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
+
+ /* Build output string */
+ result = [NSString stringWithCharacters:buffer length:bufferSize];
+
+ NSDeallocateMemoryPages(buffer, bufferSize);
+
+ return result;
+}
+
+@end
+
+
+
+#ifdef main
+# undef main
+#endif
+
+
+/* Main entry point to executable - should *not* be SDL_main! */
+int main (int argc, char **argv)
+{
+ /* Copy the arguments into a global variable */
+ /* This is passed if we are launched by double-clicking */
+ if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
+ gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
+ gArgv[0] = argv[0];
+ gArgv[1] = NULL;
+ gArgc = 1;
+ gFinderLaunch = YES;
+ } else {
+ int i;
+ gArgc = argc;
+ gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
+ for (i = 0; i <= argc; i++)
+ gArgv[i] = argv[i];
+ gFinderLaunch = NO;
+ }
+
+#if SDL_USE_NIB_FILE
+ NSApplicationMain (argc, argv);
+#else
+ CustomApplicationMain (argc, argv);
+#endif
+ return 0;
+}
+
diff --git a/src/mac/meandmyshadow/archive/archive.h b/src/mac/meandmyshadow/archive/archive.h
new file mode 100644
index 0000000..f9dbec6
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive.h
@@ -0,0 +1,741 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libarchive/archive.h.in,v 1.50 2008/05/26 17:00:22 kientzle Exp $
+ */
+
+#ifndef ARCHIVE_H_INCLUDED
+#define ARCHIVE_H_INCLUDED
+
+/*
+ * Note: archive.h is for use outside of libarchive; the configuration
+ * headers (config.h, archive_platform.h, etc.) are purely internal.
+ * Do NOT use HAVE_XXX configuration macros to control the behavior of
+ * this header! If you must conditionalize, use predefined compiler and/or
+ * platform macros.
+ */
+#if defined(__BORLANDC__) && __BORLANDC__ >= 0x560
+# define __LA_STDINT_H <stdint.h>
+#elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__)
+# define __LA_STDINT_H <inttypes.h>
+#endif
+
+#include <sys/stat.h>
+#include <sys/types.h> /* Linux requires this for off_t */
+#ifdef __LA_STDINT_H
+# include __LA_STDINT_H /* int64_t, etc. */
+#endif
+#include <stdio.h> /* For FILE * */
+
+/* Get appropriate definitions of standard POSIX-style types. */
+/* These should match the types used in 'struct stat' */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#define __LA_INT64_T __int64
+# if defined(_SSIZE_T_DEFINED)
+# define __LA_SSIZE_T ssize_t
+# elif defined(_WIN64)
+# define __LA_SSIZE_T __int64
+# else
+# define __LA_SSIZE_T long
+# endif
+# if defined(__BORLANDC__)
+# define __LA_UID_T uid_t
+# define __LA_GID_T gid_t
+# else
+# define __LA_UID_T short
+# define __LA_GID_T short
+# endif
+#else
+#include <unistd.h> /* ssize_t, uid_t, and gid_t */
+#define __LA_INT64_T int64_t
+#define __LA_SSIZE_T ssize_t
+#define __LA_UID_T uid_t
+#define __LA_GID_T gid_t
+#endif
+
+/*
+ * On Windows, define LIBARCHIVE_STATIC if you're building or using a
+ * .lib. The default here assumes you're building a DLL. Only
+ * libarchive source should ever define __LIBARCHIVE_BUILD.
+ */
+#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC)
+# ifdef __LIBARCHIVE_BUILD
+# ifdef __GNUC__
+# define __LA_DECL __attribute__((dllexport)) extern
+# else
+# define __LA_DECL __declspec(dllexport)
+# endif
+# else
+# ifdef __GNUC__
+# define __LA_DECL __attribute__((dllimport)) extern
+# else
+# define __LA_DECL __declspec(dllimport)
+# endif
+# endif
+#else
+/* Static libraries or non-Windows needs no special declaration. */
+# define __LA_DECL
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The version number is provided as both a macro and a function.
+ * The macro identifies the installed header; the function identifies
+ * the library version (which may not be the same if you're using a
+ * dynamically-linked version of the library). Of course, if the
+ * header and library are very different, you should expect some
+ * strangeness. Don't do that.
+ */
+
+/*
+ * The version number is expressed as a single integer that makes it
+ * easy to compare versions at build time: for version a.b.c, the
+ * version number is printf("%d%03d%03d",a,b,c). For example, if you
+ * know your application requires version 2.12.108 or later, you can
+ * assert that ARCHIVE_VERSION >= 2012108.
+ *
+ * This single-number format was introduced with libarchive 1.9.0 in
+ * the libarchive 1.x family and libarchive 2.2.4 in the libarchive
+ * 2.x family. The following may be useful if you really want to do
+ * feature detection for earlier libarchive versions (which defined
+ * ARCHIVE_API_VERSION and ARCHIVE_API_FEATURE instead):
+ *
+ * #ifndef ARCHIVE_VERSION_NUMBER
+ * #define ARCHIVE_VERSION_NUMBER \
+ * (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
+ * #endif
+ */
+#define ARCHIVE_VERSION_NUMBER 2008003
+__LA_DECL int archive_version_number(void);
+
+/*
+ * Textual name/version of the library, useful for version displays.
+ */
+#define ARCHIVE_VERSION_STRING "libarchive 2.8.3"
+__LA_DECL const char * archive_version_string(void);
+
+#if ARCHIVE_VERSION_NUMBER < 3000000
+/*
+ * Deprecated; these are older names that will be removed in favor of
+ * the simpler definitions above.
+ */
+#define ARCHIVE_VERSION_STAMP ARCHIVE_VERSION_NUMBER
+__LA_DECL int archive_version_stamp(void);
+#define ARCHIVE_LIBRARY_VERSION ARCHIVE_VERSION_STRING
+__LA_DECL const char * archive_version(void);
+#define ARCHIVE_API_VERSION (ARCHIVE_VERSION_NUMBER / 1000000)
+__LA_DECL int archive_api_version(void);
+#define ARCHIVE_API_FEATURE ((ARCHIVE_VERSION_NUMBER / 1000) % 1000)
+__LA_DECL int archive_api_feature(void);
+#endif
+
+#if ARCHIVE_VERSION_NUMBER < 3000000
+/* This should never have been here in the first place. */
+/* Legacy of old tar assumptions, will be removed in libarchive 3.0. */
+#define ARCHIVE_BYTES_PER_RECORD 512
+#define ARCHIVE_DEFAULT_BYTES_PER_BLOCK 10240
+#endif
+
+/* Declare our basic types. */
+struct archive;
+struct archive_entry;
+
+/*
+ * Error codes: Use archive_errno() and archive_error_string()
+ * to retrieve details. Unless specified otherwise, all functions
+ * that return 'int' use these codes.
+ */
+#define ARCHIVE_EOF 1 /* Found end of archive. */
+#define ARCHIVE_OK 0 /* Operation was successful. */
+#define ARCHIVE_RETRY (-10) /* Retry might succeed. */
+#define ARCHIVE_WARN (-20) /* Partial success. */
+/* For example, if write_header "fails", then you can't push data. */
+#define ARCHIVE_FAILED (-25) /* Current operation cannot complete. */
+/* But if write_header is "fatal," then this archive is dead and useless. */
+#define ARCHIVE_FATAL (-30) /* No more operations are possible. */
+
+/*
+ * As far as possible, archive_errno returns standard platform errno codes.
+ * Of course, the details vary by platform, so the actual definitions
+ * here are stored in "archive_platform.h". The symbols are listed here
+ * for reference; as a rule, clients should not need to know the exact
+ * platform-dependent error code.
+ */
+/* Unrecognized or invalid file format. */
+/* #define ARCHIVE_ERRNO_FILE_FORMAT */
+/* Illegal usage of the library. */
+/* #define ARCHIVE_ERRNO_PROGRAMMER_ERROR */
+/* Unknown or unclassified error. */
+/* #define ARCHIVE_ERRNO_MISC */
+
+/*
+ * Callbacks are invoked to automatically read/skip/write/open/close the
+ * archive. You can provide your own for complex tasks (like breaking
+ * archives across multiple tapes) or use standard ones built into the
+ * library.
+ */
+
+/* Returns pointer and size of next block of data from archive. */
+typedef __LA_SSIZE_T archive_read_callback(struct archive *,
+ void *_client_data, const void **_buffer);
+
+/* Skips at most request bytes from archive and returns the skipped amount */
+#if ARCHIVE_VERSION_NUMBER < 2000000
+/* Libarchive 1.0 used ssize_t for the return, which is only 32 bits
+ * on most 32-bit platforms; not large enough. */
+typedef __LA_SSIZE_T archive_skip_callback(struct archive *,
+ void *_client_data, size_t request);
+#elif ARCHIVE_VERSION_NUMBER < 3000000
+/* Libarchive 2.0 used off_t here, but that is a bad idea on Linux and a
+ * few other platforms where off_t varies with build settings. */
+typedef off_t archive_skip_callback(struct archive *,
+ void *_client_data, off_t request);
+#else
+/* Libarchive 3.0 uses int64_t here, which is actually guaranteed to be
+ * 64 bits on every platform. */
+typedef __LA_INT64_T archive_skip_callback(struct archive *,
+ void *_client_data, __LA_INT64_T request);
+#endif
+
+/* Returns size actually written, zero on EOF, -1 on error. */
+typedef __LA_SSIZE_T archive_write_callback(struct archive *,
+ void *_client_data,
+ const void *_buffer, size_t _length);
+
+#if ARCHIVE_VERSION_NUMBER < 3000000
+/* Open callback is actually never needed; remove it in libarchive 3.0. */
+typedef int archive_open_callback(struct archive *, void *_client_data);
+#endif
+
+typedef int archive_close_callback(struct archive *, void *_client_data);
+
+/*
+ * Codes for archive_compression.
+ */
+#define ARCHIVE_COMPRESSION_NONE 0
+#define ARCHIVE_COMPRESSION_GZIP 1
+#define ARCHIVE_COMPRESSION_BZIP2 2
+#define ARCHIVE_COMPRESSION_COMPRESS 3
+#define ARCHIVE_COMPRESSION_PROGRAM 4
+#define ARCHIVE_COMPRESSION_LZMA 5
+#define ARCHIVE_COMPRESSION_XZ 6
+#define ARCHIVE_COMPRESSION_UU 7
+#define ARCHIVE_COMPRESSION_RPM 8
+
+/*
+ * Codes returned by archive_format.
+ *
+ * Top 16 bits identifies the format family (e.g., "tar"); lower
+ * 16 bits indicate the variant. This is updated by read_next_header.
+ * Note that the lower 16 bits will often vary from entry to entry.
+ * In some cases, this variation occurs as libarchive learns more about
+ * the archive (for example, later entries might utilize extensions that
+ * weren't necessary earlier in the archive; in this case, libarchive
+ * will change the format code to indicate the extended format that
+ * was used). In other cases, it's because different tools have
+ * modified the archive and so different parts of the archive
+ * actually have slightly different formts. (Both tar and cpio store
+ * format codes in each entry, so it is quite possible for each
+ * entry to be in a different format.)
+ */
+#define ARCHIVE_FORMAT_BASE_MASK 0xff0000
+#define ARCHIVE_FORMAT_CPIO 0x10000
+#define ARCHIVE_FORMAT_CPIO_POSIX (ARCHIVE_FORMAT_CPIO | 1)
+#define ARCHIVE_FORMAT_CPIO_BIN_LE (ARCHIVE_FORMAT_CPIO | 2)
+#define ARCHIVE_FORMAT_CPIO_BIN_BE (ARCHIVE_FORMAT_CPIO | 3)
+#define ARCHIVE_FORMAT_CPIO_SVR4_NOCRC (ARCHIVE_FORMAT_CPIO | 4)
+#define ARCHIVE_FORMAT_CPIO_SVR4_CRC (ARCHIVE_FORMAT_CPIO | 5)
+#define ARCHIVE_FORMAT_SHAR 0x20000
+#define ARCHIVE_FORMAT_SHAR_BASE (ARCHIVE_FORMAT_SHAR | 1)
+#define ARCHIVE_FORMAT_SHAR_DUMP (ARCHIVE_FORMAT_SHAR | 2)
+#define ARCHIVE_FORMAT_TAR 0x30000
+#define ARCHIVE_FORMAT_TAR_USTAR (ARCHIVE_FORMAT_TAR | 1)
+#define ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE (ARCHIVE_FORMAT_TAR | 2)
+#define ARCHIVE_FORMAT_TAR_PAX_RESTRICTED (ARCHIVE_FORMAT_TAR | 3)
+#define ARCHIVE_FORMAT_TAR_GNUTAR (ARCHIVE_FORMAT_TAR | 4)
+#define ARCHIVE_FORMAT_ISO9660 0x40000
+#define ARCHIVE_FORMAT_ISO9660_ROCKRIDGE (ARCHIVE_FORMAT_ISO9660 | 1)
+#define ARCHIVE_FORMAT_ZIP 0x50000
+#define ARCHIVE_FORMAT_EMPTY 0x60000
+#define ARCHIVE_FORMAT_AR 0x70000
+#define ARCHIVE_FORMAT_AR_GNU (ARCHIVE_FORMAT_AR | 1)
+#define ARCHIVE_FORMAT_AR_BSD (ARCHIVE_FORMAT_AR | 2)
+#define ARCHIVE_FORMAT_MTREE 0x80000
+#define ARCHIVE_FORMAT_RAW 0x90000
+#define ARCHIVE_FORMAT_XAR 0xA0000
+
+/*-
+ * Basic outline for reading an archive:
+ * 1) Ask archive_read_new for an archive reader object.
+ * 2) Update any global properties as appropriate.
+ * In particular, you'll certainly want to call appropriate
+ * archive_read_support_XXX functions.
+ * 3) Call archive_read_open_XXX to open the archive
+ * 4) Repeatedly call archive_read_next_header to get information about
+ * successive archive entries. Call archive_read_data to extract
+ * data for entries of interest.
+ * 5) Call archive_read_finish to end processing.
+ */
+__LA_DECL struct archive *archive_read_new(void);
+
+/*
+ * The archive_read_support_XXX calls enable auto-detect for this
+ * archive handle. They also link in the necessary support code.
+ * For example, if you don't want bzlib linked in, don't invoke
+ * support_compression_bzip2(). The "all" functions provide the
+ * obvious shorthand.
+ */
+__LA_DECL int archive_read_support_compression_all(struct archive *);
+__LA_DECL int archive_read_support_compression_bzip2(struct archive *);
+__LA_DECL int archive_read_support_compression_compress(struct archive *);
+__LA_DECL int archive_read_support_compression_gzip(struct archive *);
+__LA_DECL int archive_read_support_compression_lzma(struct archive *);
+__LA_DECL int archive_read_support_compression_none(struct archive *);
+__LA_DECL int archive_read_support_compression_program(struct archive *,
+ const char *command);
+__LA_DECL int archive_read_support_compression_program_signature
+ (struct archive *, const char *,
+ const void * /* match */, size_t);
+
+__LA_DECL int archive_read_support_compression_rpm(struct archive *);
+__LA_DECL int archive_read_support_compression_uu(struct archive *);
+__LA_DECL int archive_read_support_compression_xz(struct archive *);
+
+__LA_DECL int archive_read_support_format_all(struct archive *);
+__LA_DECL int archive_read_support_format_ar(struct archive *);
+__LA_DECL int archive_read_support_format_cpio(struct archive *);
+__LA_DECL int archive_read_support_format_empty(struct archive *);
+__LA_DECL int archive_read_support_format_gnutar(struct archive *);
+__LA_DECL int archive_read_support_format_iso9660(struct archive *);
+__LA_DECL int archive_read_support_format_mtree(struct archive *);
+__LA_DECL int archive_read_support_format_raw(struct archive *);
+__LA_DECL int archive_read_support_format_tar(struct archive *);
+__LA_DECL int archive_read_support_format_xar(struct archive *);
+__LA_DECL int archive_read_support_format_zip(struct archive *);
+
+
+/* Open the archive using callbacks for archive I/O. */
+__LA_DECL int archive_read_open(struct archive *, void *_client_data,
+ archive_open_callback *, archive_read_callback *,
+ archive_close_callback *);
+__LA_DECL int archive_read_open2(struct archive *, void *_client_data,
+ archive_open_callback *, archive_read_callback *,
+ archive_skip_callback *, archive_close_callback *);
+
+/*
+ * A variety of shortcuts that invoke archive_read_open() with
+ * canned callbacks suitable for common situations. The ones that
+ * accept a block size handle tape blocking correctly.
+ */
+/* Use this if you know the filename. Note: NULL indicates stdin. */
+__LA_DECL int archive_read_open_filename(struct archive *,
+ const char *_filename, size_t _block_size);
+/* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
+__LA_DECL int archive_read_open_file(struct archive *,
+ const char *_filename, size_t _block_size);
+/* Read an archive that's stored in memory. */
+__LA_DECL int archive_read_open_memory(struct archive *,
+ void * buff, size_t size);
+/* A more involved version that is only used for internal testing. */
+__LA_DECL int archive_read_open_memory2(struct archive *a, void *buff,
+ size_t size, size_t read_size);
+/* Read an archive that's already open, using the file descriptor. */
+__LA_DECL int archive_read_open_fd(struct archive *, int _fd,
+ size_t _block_size);
+/* Read an archive that's already open, using a FILE *. */
+/* Note: DO NOT use this with tape drives. */
+__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file);
+
+/* Parses and returns next entry header. */
+__LA_DECL int archive_read_next_header(struct archive *,
+ struct archive_entry **);
+
+/* Parses and returns next entry header using the archive_entry passed in */
+__LA_DECL int archive_read_next_header2(struct archive *,
+ struct archive_entry *);
+
+/*
+ * Retrieve the byte offset in UNCOMPRESSED data where last-read
+ * header started.
+ */
+__LA_DECL __LA_INT64_T archive_read_header_position(struct archive *);
+
+/* Read data from the body of an entry. Similar to read(2). */
+__LA_DECL __LA_SSIZE_T archive_read_data(struct archive *,
+ void *, size_t);
+
+/*
+ * A zero-copy version of archive_read_data that also exposes the file offset
+ * of each returned block. Note that the client has no way to specify
+ * the desired size of the block. The API does guarantee that offsets will
+ * be strictly increasing and that returned blocks will not overlap.
+ */
+#if ARCHIVE_VERSION_NUMBER < 3000000
+__LA_DECL int archive_read_data_block(struct archive *a,
+ const void **buff, size_t *size, off_t *offset);
+#else
+__LA_DECL int archive_read_data_block(struct archive *a,
+ const void **buff, size_t *size,
+ __LA_INT64_T *offset);
+#endif
+
+/*-
+ * Some convenience functions that are built on archive_read_data:
+ * 'skip': skips entire entry
+ * 'into_buffer': writes data into memory buffer that you provide
+ * 'into_fd': writes data to specified filedes
+ */
+__LA_DECL int archive_read_data_skip(struct archive *);
+__LA_DECL int archive_read_data_into_buffer(struct archive *,
+ void *buffer, __LA_SSIZE_T len);
+__LA_DECL int archive_read_data_into_fd(struct archive *, int fd);
+
+/*
+ * Set read options.
+ */
+/* Apply option string to the format only. */
+__LA_DECL int archive_read_set_format_options(struct archive *_a,
+ const char *s);
+/* Apply option string to the filter only. */
+__LA_DECL int archive_read_set_filter_options(struct archive *_a,
+ const char *s);
+/* Apply option string to both the format and the filter. */
+__LA_DECL int archive_read_set_options(struct archive *_a,
+ const char *s);
+
+/*-
+ * Convenience function to recreate the current entry (whose header
+ * has just been read) on disk.
+ *
+ * This does quite a bit more than just copy data to disk. It also:
+ * - Creates intermediate directories as required.
+ * - Manages directory permissions: non-writable directories will
+ * be initially created with write permission enabled; when the
+ * archive is closed, dir permissions are edited to the values specified
+ * in the archive.
+ * - Checks hardlinks: hardlinks will not be extracted unless the
+ * linked-to file was also extracted within the same session. (TODO)
+ */
+
+/* The "flags" argument selects optional behavior, 'OR' the flags you want. */
+
+/* Default: Do not try to set owner/group. */
+#define ARCHIVE_EXTRACT_OWNER (0x0001)
+/* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */
+#define ARCHIVE_EXTRACT_PERM (0x0002)
+/* Default: Do not restore mtime/atime. */
+#define ARCHIVE_EXTRACT_TIME (0x0004)
+/* Default: Replace existing files. */
+#define ARCHIVE_EXTRACT_NO_OVERWRITE (0x0008)
+/* Default: Try create first, unlink only if create fails with EEXIST. */
+#define ARCHIVE_EXTRACT_UNLINK (0x0010)
+/* Default: Do not restore ACLs. */
+#define ARCHIVE_EXTRACT_ACL (0x0020)
+/* Default: Do not restore fflags. */
+#define ARCHIVE_EXTRACT_FFLAGS (0x0040)
+/* Default: Do not restore xattrs. */
+#define ARCHIVE_EXTRACT_XATTR (0x0080)
+/* Default: Do not try to guard against extracts redirected by symlinks. */
+/* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */
+#define ARCHIVE_EXTRACT_SECURE_SYMLINKS (0x0100)
+/* Default: Do not reject entries with '..' as path elements. */
+#define ARCHIVE_EXTRACT_SECURE_NODOTDOT (0x0200)
+/* Default: Create parent directories as needed. */
+#define ARCHIVE_EXTRACT_NO_AUTODIR (0x0400)
+/* Default: Overwrite files, even if one on disk is newer. */
+#define ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER (0x0800)
+/* Detect blocks of 0 and write holes instead. */
+#define ARCHIVE_EXTRACT_SPARSE (0x1000)
+
+__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
+ int flags);
+__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *,
+ struct archive * /* dest */);
+__LA_DECL void archive_read_extract_set_progress_callback(struct archive *,
+ void (*_progress_func)(void *), void *_user_data);
+
+/* Record the dev/ino of a file that will not be written. This is
+ * generally set to the dev/ino of the archive being read. */
+__LA_DECL void archive_read_extract_set_skip_file(struct archive *,
+ dev_t, ino_t);
+
+/* Close the file and release most resources. */
+__LA_DECL int archive_read_close(struct archive *);
+/* Release all resources and destroy the object. */
+/* Note that archive_read_finish will call archive_read_close for you. */
+#if ARCHIVE_VERSION_NUMBER < 2000000
+/* Erroneously declared to return void in libarchive 1.x */
+__LA_DECL void archive_read_finish(struct archive *);
+#else
+__LA_DECL int archive_read_finish(struct archive *);
+#endif
+
+/*-
+ * To create an archive:
+ * 1) Ask archive_write_new for a archive writer object.
+ * 2) Set any global properties. In particular, you should set
+ * the compression and format to use.
+ * 3) Call archive_write_open to open the file (most people
+ * will use archive_write_open_file or archive_write_open_fd,
+ * which provide convenient canned I/O callbacks for you).
+ * 4) For each entry:
+ * - construct an appropriate struct archive_entry structure
+ * - archive_write_header to write the header
+ * - archive_write_data to write the entry data
+ * 5) archive_write_close to close the output
+ * 6) archive_write_finish to cleanup the writer and release resources
+ */
+__LA_DECL struct archive *archive_write_new(void);
+__LA_DECL int archive_write_set_bytes_per_block(struct archive *,
+ int bytes_per_block);
+__LA_DECL int archive_write_get_bytes_per_block(struct archive *);
+/* XXX This is badly misnamed; suggestions appreciated. XXX */
+__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *,
+ int bytes_in_last_block);
+__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *);
+
+/* The dev/ino of a file that won't be archived. This is used
+ * to avoid recursively adding an archive to itself. */
+__LA_DECL int archive_write_set_skip_file(struct archive *, dev_t, ino_t);
+
+__LA_DECL int archive_write_set_compression_bzip2(struct archive *);
+__LA_DECL int archive_write_set_compression_compress(struct archive *);
+__LA_DECL int archive_write_set_compression_gzip(struct archive *);
+__LA_DECL int archive_write_set_compression_lzma(struct archive *);
+__LA_DECL int archive_write_set_compression_none(struct archive *);
+__LA_DECL int archive_write_set_compression_program(struct archive *,
+ const char *cmd);
+__LA_DECL int archive_write_set_compression_xz(struct archive *);
+/* A convenience function to set the format based on the code or name. */
+__LA_DECL int archive_write_set_format(struct archive *, int format_code);
+__LA_DECL int archive_write_set_format_by_name(struct archive *,
+ const char *name);
+/* To minimize link pollution, use one or more of the following. */
+__LA_DECL int archive_write_set_format_ar_bsd(struct archive *);
+__LA_DECL int archive_write_set_format_ar_svr4(struct archive *);
+__LA_DECL int archive_write_set_format_cpio(struct archive *);
+__LA_DECL int archive_write_set_format_cpio_newc(struct archive *);
+__LA_DECL int archive_write_set_format_mtree(struct archive *);
+/* TODO: int archive_write_set_format_old_tar(struct archive *); */
+__LA_DECL int archive_write_set_format_pax(struct archive *);
+__LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
+__LA_DECL int archive_write_set_format_shar(struct archive *);
+__LA_DECL int archive_write_set_format_shar_dump(struct archive *);
+__LA_DECL int archive_write_set_format_ustar(struct archive *);
+__LA_DECL int archive_write_set_format_zip(struct archive *);
+__LA_DECL int archive_write_open(struct archive *, void *,
+ archive_open_callback *, archive_write_callback *,
+ archive_close_callback *);
+__LA_DECL int archive_write_open_fd(struct archive *, int _fd);
+__LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
+/* A deprecated synonym for archive_write_open_filename() */
+__LA_DECL int archive_write_open_file(struct archive *, const char *_file);
+__LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
+/* _buffSize is the size of the buffer, _used refers to a variable that
+ * will be updated after each write into the buffer. */
+__LA_DECL int archive_write_open_memory(struct archive *,
+ void *_buffer, size_t _buffSize, size_t *_used);
+
+/*
+ * Note that the library will truncate writes beyond the size provided
+ * to archive_write_header or pad if the provided data is short.
+ */
+__LA_DECL int archive_write_header(struct archive *,
+ struct archive_entry *);
+#if ARCHIVE_VERSION_NUMBER < 2000000
+/* This was erroneously declared to return "int" in libarchive 1.x. */
+__LA_DECL int archive_write_data(struct archive *,
+ const void *, size_t);
+#else
+/* Libarchive 2.0 and later return ssize_t here. */
+__LA_DECL __LA_SSIZE_T archive_write_data(struct archive *,
+ const void *, size_t);
+#endif
+
+#if ARCHIVE_VERSION_NUMBER < 3000000
+/* Libarchive 1.x and 2.x use off_t for the argument, but that's not
+ * stable on Linux. */
+__LA_DECL __LA_SSIZE_T archive_write_data_block(struct archive *,
+ const void *, size_t, off_t);
+#else
+/* Libarchive 3.0 uses explicit int64_t to ensure consistent 64-bit support. */
+__LA_DECL __LA_SSIZE_T archive_write_data_block(struct archive *,
+ const void *, size_t, __LA_INT64_T);
+#endif
+__LA_DECL int archive_write_finish_entry(struct archive *);
+__LA_DECL int archive_write_close(struct archive *);
+#if ARCHIVE_VERSION_NUMBER < 2000000
+/* Return value was incorrect in libarchive 1.x. */
+__LA_DECL void archive_write_finish(struct archive *);
+#else
+/* Libarchive 2.x and later returns an error if this fails. */
+/* It can fail if the archive wasn't already closed, in which case
+ * archive_write_finish() will implicitly call archive_write_close(). */
+__LA_DECL int archive_write_finish(struct archive *);
+#endif
+
+/*
+ * Set write options.
+ */
+/* Apply option string to the format only. */
+__LA_DECL int archive_write_set_format_options(struct archive *_a,
+ const char *s);
+/* Apply option string to the compressor only. */
+__LA_DECL int archive_write_set_compressor_options(struct archive *_a,
+ const char *s);
+/* Apply option string to both the format and the compressor. */
+__LA_DECL int archive_write_set_options(struct archive *_a,
+ const char *s);
+
+
+/*-
+ * ARCHIVE_WRITE_DISK API
+ *
+ * To create objects on disk:
+ * 1) Ask archive_write_disk_new for a new archive_write_disk object.
+ * 2) Set any global properties. In particular, you probably
+ * want to set the options.
+ * 3) For each entry:
+ * - construct an appropriate struct archive_entry structure
+ * - archive_write_header to create the file/dir/etc on disk
+ * - archive_write_data to write the entry data
+ * 4) archive_write_finish to cleanup the writer and release resources
+ *
+ * In particular, you can use this in conjunction with archive_read()
+ * to pull entries out of an archive and create them on disk.
+ */
+__LA_DECL struct archive *archive_write_disk_new(void);
+/* This file will not be overwritten. */
+__LA_DECL int archive_write_disk_set_skip_file(struct archive *,
+ dev_t, ino_t);
+/* Set flags to control how the next item gets created.
+ * This accepts a bitmask of ARCHIVE_EXTRACT_XXX flags defined above. */
+__LA_DECL int archive_write_disk_set_options(struct archive *,
+ int flags);
+/*
+ * The lookup functions are given uname/uid (or gname/gid) pairs and
+ * return a uid (gid) suitable for this system. These are used for
+ * restoring ownership and for setting ACLs. The default functions
+ * are naive, they just return the uid/gid. These are small, so reasonable
+ * for applications that don't need to preserve ownership; they
+ * are probably also appropriate for applications that are doing
+ * same-system backup and restore.
+ */
+/*
+ * The "standard" lookup functions use common system calls to lookup
+ * the uname/gname, falling back to the uid/gid if the names can't be
+ * found. They cache lookups and are reasonably fast, but can be very
+ * large, so they are not used unless you ask for them. In
+ * particular, these match the specifications of POSIX "pax" and old
+ * POSIX "tar".
+ */
+__LA_DECL int archive_write_disk_set_standard_lookup(struct archive *);
+/*
+ * If neither the default (naive) nor the standard (big) functions suit
+ * your needs, you can write your own and register them. Be sure to
+ * include a cleanup function if you have allocated private data.
+ */
+__LA_DECL int archive_write_disk_set_group_lookup(struct archive *,
+ void * /* private_data */,
+ __LA_GID_T (*)(void *, const char *, __LA_GID_T),
+ void (* /* cleanup */)(void *));
+__LA_DECL int archive_write_disk_set_user_lookup(struct archive *,
+ void * /* private_data */,
+ __LA_UID_T (*)(void *, const char *, __LA_UID_T),
+ void (* /* cleanup */)(void *));
+
+/*
+ * ARCHIVE_READ_DISK API
+ *
+ * This is still evolving and somewhat experimental.
+ */
+__LA_DECL struct archive *archive_read_disk_new(void);
+/* The names for symlink modes here correspond to an old BSD
+ * command-line argument convention: -L, -P, -H */
+/* Follow all symlinks. */
+__LA_DECL int archive_read_disk_set_symlink_logical(struct archive *);
+/* Follow no symlinks. */
+__LA_DECL int archive_read_disk_set_symlink_physical(struct archive *);
+/* Follow symlink initially, then not. */
+__LA_DECL int archive_read_disk_set_symlink_hybrid(struct archive *);
+/* TODO: Handle Linux stat32/stat64 ugliness. <sigh> */
+__LA_DECL int archive_read_disk_entry_from_file(struct archive *,
+ struct archive_entry *, int /* fd */, const struct stat *);
+/* Look up gname for gid or uname for uid. */
+/* Default implementations are very, very stupid. */
+__LA_DECL const char *archive_read_disk_gname(struct archive *, __LA_GID_T);
+__LA_DECL const char *archive_read_disk_uname(struct archive *, __LA_UID_T);
+/* "Standard" implementation uses getpwuid_r, getgrgid_r and caches the
+ * results for performance. */
+__LA_DECL int archive_read_disk_set_standard_lookup(struct archive *);
+/* You can install your own lookups if you like. */
+__LA_DECL int archive_read_disk_set_gname_lookup(struct archive *,
+ void * /* private_data */,
+ const char *(* /* lookup_fn */)(void *, __LA_GID_T),
+ void (* /* cleanup_fn */)(void *));
+__LA_DECL int archive_read_disk_set_uname_lookup(struct archive *,
+ void * /* private_data */,
+ const char *(* /* lookup_fn */)(void *, __LA_UID_T),
+ void (* /* cleanup_fn */)(void *));
+
+/*
+ * Accessor functions to read/set various information in
+ * the struct archive object:
+ */
+/* Bytes written after compression or read before decompression. */
+__LA_DECL __LA_INT64_T archive_position_compressed(struct archive *);
+/* Bytes written to compressor or read from decompressor. */
+__LA_DECL __LA_INT64_T archive_position_uncompressed(struct archive *);
+
+__LA_DECL const char *archive_compression_name(struct archive *);
+__LA_DECL int archive_compression(struct archive *);
+__LA_DECL int archive_errno(struct archive *);
+__LA_DECL const char *archive_error_string(struct archive *);
+__LA_DECL const char *archive_format_name(struct archive *);
+__LA_DECL int archive_format(struct archive *);
+__LA_DECL void archive_clear_error(struct archive *);
+__LA_DECL void archive_set_error(struct archive *, int _err,
+ const char *fmt, ...);
+__LA_DECL void archive_copy_error(struct archive *dest,
+ struct archive *src);
+__LA_DECL int archive_file_count(struct archive *);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* These are meaningless outside of this header. */
+#undef __LA_DECL
+#undef __LA_GID_T
+#undef __LA_UID_T
+
+/* These need to remain defined because they're used in the
+ * callback type definitions. XXX Fix this. This is ugly. XXX */
+/* #undef __LA_INT64_T */
+/* #undef __LA_SSIZE_T */
+
+#endif /* !ARCHIVE_H_INCLUDED */
diff --git a/src/mac/meandmyshadow/archive/archive_crc32.h b/src/mac/meandmyshadow/archive/archive_crc32.h
new file mode 100644
index 0000000..103e5df
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_crc32.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2009 Joerg Sonnenberger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_crc32.h 201102 2009-12-28 03:11:36Z kientzle $
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+/*
+ * When zlib is unavailable, we should still be able to validate
+ * uncompressed zip archives. That requires us to be able to compute
+ * the CRC32 check value. This is a drop-in compatible replacement
+ * for crc32() from zlib. It's slower than the zlib implementation,
+ * but still pretty fast: This runs about 300MB/s on my 3GHz P4
+ * compared to about 800MB/s for the zlib implementation.
+ */
+static unsigned long
+crc32(unsigned long crc, const void *_p, size_t len)
+{
+ unsigned long crc2, b, i;
+ const unsigned char *p = _p;
+ static volatile int crc_tbl_inited = 0;
+ static unsigned long crc_tbl[256];
+
+ if (!crc_tbl_inited) {
+ for (b = 0; b < 256; ++b) {
+ crc2 = b;
+ for (i = 8; i > 0; --i) {
+ if (crc2 & 1)
+ crc2 = (crc2 >> 1) ^ 0xedb88320UL;
+ else
+ crc2 = (crc2 >> 1);
+ }
+ crc_tbl[b] = crc2;
+ }
+ crc_tbl_inited = 1;
+ }
+
+ crc = crc ^ 0xffffffffUL;
+ while (len--)
+ crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
+ return (crc ^ 0xffffffffUL);
+}
diff --git a/src/mac/meandmyshadow/archive/archive_endian.h b/src/mac/meandmyshadow/archive/archive_endian.h
new file mode 100644
index 0000000..edc90ee
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_endian.h
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 2002 Thomas Moestl <tmm@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_endian.h 201085 2009-12-28 02:17:15Z kientzle $
+ *
+ * Borrowed from FreeBSD's <sys/endian.h>
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+/* Note: This is a purely internal header! */
+/* Do not use this outside of libarchive internal code! */
+
+#ifndef ARCHIVE_ENDIAN_H_INCLUDED
+#define ARCHIVE_ENDIAN_H_INCLUDED
+
+
+/*
+ * Disabling inline keyword for compilers known to choke on it:
+ * - Watcom C++ in C code. (For any version?)
+ * - SGI MIPSpro
+ * - Microsoft Visual C++ 6.0 (supposedly newer versions too)
+ */
+#if defined(__WATCOMC__) || defined(__sgi) || defined(__hpux) || defined(__BORLANDC__)
+#define inline
+#elif defined(_MSC_VER)
+#define inline __inline
+#endif
+
+/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */
+
+static inline uint16_t
+archive_be16dec(const void *pp)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ return ((p[0] << 8) | p[1]);
+}
+
+static inline uint32_t
+archive_be32dec(const void *pp)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+static inline uint64_t
+archive_be64dec(const void *pp)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ return (((uint64_t)archive_be32dec(p) << 32) | archive_be32dec(p + 4));
+}
+
+static inline uint16_t
+archive_le16dec(const void *pp)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ return ((p[1] << 8) | p[0]);
+}
+
+static inline uint32_t
+archive_le32dec(const void *pp)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
+}
+
+static inline uint64_t
+archive_le64dec(const void *pp)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ return (((uint64_t)archive_le32dec(p + 4) << 32) | archive_le32dec(p));
+}
+
+static inline void
+archive_be16enc(void *pp, uint16_t u)
+{
+ unsigned char *p = (unsigned char *)pp;
+
+ p[0] = (u >> 8) & 0xff;
+ p[1] = u & 0xff;
+}
+
+static inline void
+archive_be32enc(void *pp, uint32_t u)
+{
+ unsigned char *p = (unsigned char *)pp;
+
+ p[0] = (u >> 24) & 0xff;
+ p[1] = (u >> 16) & 0xff;
+ p[2] = (u >> 8) & 0xff;
+ p[3] = u & 0xff;
+}
+
+static inline void
+archive_be64enc(void *pp, uint64_t u)
+{
+ unsigned char *p = (unsigned char *)pp;
+
+ archive_be32enc(p, u >> 32);
+ archive_be32enc(p + 4, u & 0xffffffff);
+}
+
+static inline void
+archive_le16enc(void *pp, uint16_t u)
+{
+ unsigned char *p = (unsigned char *)pp;
+
+ p[0] = u & 0xff;
+ p[1] = (u >> 8) & 0xff;
+}
+
+static inline void
+archive_le32enc(void *pp, uint32_t u)
+{
+ unsigned char *p = (unsigned char *)pp;
+
+ p[0] = u & 0xff;
+ p[1] = (u >> 8) & 0xff;
+ p[2] = (u >> 16) & 0xff;
+ p[3] = (u >> 24) & 0xff;
+}
+
+static inline void
+archive_le64enc(void *pp, uint64_t u)
+{
+ unsigned char *p = (unsigned char *)pp;
+
+ archive_le32enc(p, u & 0xffffffff);
+ archive_le32enc(p + 4, u >> 32);
+}
+
+#endif
diff --git a/src/mac/meandmyshadow/archive/archive_entry.h b/src/mac/meandmyshadow/archive/archive_entry.h
new file mode 100644
index 0000000..d572817
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_entry.h
@@ -0,0 +1,524 @@
+/*-
+ * Copyright (c) 2003-2008 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_entry.h 201096 2009-12-28 02:41:27Z kientzle $
+ */
+
+#ifndef ARCHIVE_ENTRY_H_INCLUDED
+#define ARCHIVE_ENTRY_H_INCLUDED
+
+/*
+ * Note: archive_entry.h is for use outside of libarchive; the
+ * configuration headers (config.h, archive_platform.h, etc.) are
+ * purely internal. Do NOT use HAVE_XXX configuration macros to
+ * control the behavior of this header! If you must conditionalize,
+ * use predefined compiler and/or platform macros.
+ */
+
+#include <sys/types.h>
+#include <stddef.h> /* for wchar_t */
+#include <time.h>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <windows.h>
+#endif
+
+/* Get appropriate definitions of standard POSIX-style types. */
+/* These should match the types used in 'struct stat' */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#define __LA_INT64_T __int64
+# if defined(__BORLANDC__)
+# define __LA_UID_T uid_t
+# define __LA_GID_T gid_t
+# define __LA_DEV_T dev_t
+# define __LA_MODE_T mode_t
+# else
+# define __LA_UID_T short
+# define __LA_GID_T short
+# define __LA_DEV_T unsigned int
+# define __LA_MODE_T unsigned short
+# endif
+#else
+#include <unistd.h>
+#define __LA_INT64_T int64_t
+#define __LA_UID_T uid_t
+#define __LA_GID_T gid_t
+#define __LA_DEV_T dev_t
+#define __LA_MODE_T mode_t
+#endif
+
+/*
+ * XXX Is this defined for all Windows compilers? If so, in what
+ * header? It would be nice to remove the __LA_INO_T indirection and
+ * just use plain ino_t everywhere. Likewise for the other types just
+ * above.
+ */
+#define __LA_INO_T ino_t
+
+
+/*
+ * On Windows, define LIBARCHIVE_STATIC if you're building or using a
+ * .lib. The default here assumes you're building a DLL. Only
+ * libarchive source should ever define __LIBARCHIVE_BUILD.
+ */
+#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC)
+# ifdef __LIBARCHIVE_BUILD
+# ifdef __GNUC__
+# define __LA_DECL __attribute__((dllexport)) extern
+# else
+# define __LA_DECL __declspec(dllexport)
+# endif
+# else
+# ifdef __GNUC__
+# define __LA_DECL __attribute__((dllimport)) extern
+# else
+# define __LA_DECL __declspec(dllimport)
+# endif
+# endif
+#else
+/* Static libraries on all platforms and shared libraries on non-Windows. */
+# define __LA_DECL
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Description of an archive entry.
+ *
+ * You can think of this as "struct stat" with some text fields added in.
+ *
+ * TODO: Add "comment", "charset", and possibly other entries that are
+ * supported by "pax interchange" format. However, GNU, ustar, cpio,
+ * and other variants don't support these features, so they're not an
+ * excruciatingly high priority right now.
+ *
+ * TODO: "pax interchange" format allows essentially arbitrary
+ * key/value attributes to be attached to any entry. Supporting
+ * such extensions may make this library useful for special
+ * applications (e.g., a package manager could attach special
+ * package-management attributes to each entry).
+ */
+struct archive_entry;
+
+/*
+ * File-type constants. These are returned from archive_entry_filetype()
+ * and passed to archive_entry_set_filetype().
+ *
+ * These values match S_XXX defines on every platform I've checked,
+ * including Windows, AIX, Linux, Solaris, and BSD. They're
+ * (re)defined here because platforms generally don't define the ones
+ * they don't support. For example, Windows doesn't define S_IFLNK or
+ * S_IFBLK. Instead of having a mass of conditional logic and system
+ * checks to define any S_XXX values that aren't supported locally,
+ * I've just defined a new set of such constants so that
+ * libarchive-based applications can manipulate and identify archive
+ * entries properly even if the hosting platform can't store them on
+ * disk.
+ *
+ * These values are also used directly within some portable formats,
+ * such as cpio. If you find a platform that varies from these, the
+ * correct solution is to leave these alone and translate from these
+ * portable values to platform-native values when entries are read from
+ * or written to disk.
+ */
+#define AE_IFMT 0170000
+#define AE_IFREG 0100000
+#define AE_IFLNK 0120000
+#define AE_IFSOCK 0140000
+#define AE_IFCHR 0020000
+#define AE_IFBLK 0060000
+#define AE_IFDIR 0040000
+#define AE_IFIFO 0010000
+
+/*
+ * Basic object manipulation
+ */
+
+__LA_DECL struct archive_entry *archive_entry_clear(struct archive_entry *);
+/* The 'clone' function does a deep copy; all of the strings are copied too. */
+__LA_DECL struct archive_entry *archive_entry_clone(struct archive_entry *);
+__LA_DECL void archive_entry_free(struct archive_entry *);
+__LA_DECL struct archive_entry *archive_entry_new(void);
+
+/*
+ * Retrieve fields from an archive_entry.
+ *
+ * There are a number of implicit conversions among these fields. For
+ * example, if a regular string field is set and you read the _w wide
+ * character field, the entry will implicitly convert narrow-to-wide
+ * using the current locale. Similarly, dev values are automatically
+ * updated when you write devmajor or devminor and vice versa.
+ *
+ * In addition, fields can be "set" or "unset." Unset string fields
+ * return NULL, non-string fields have _is_set() functions to test
+ * whether they've been set. You can "unset" a string field by
+ * assigning NULL; non-string fields have _unset() functions to
+ * unset them.
+ *
+ * Note: There is one ambiguity in the above; string fields will
+ * also return NULL when implicit character set conversions fail.
+ * This is usually what you want.
+ */
+__LA_DECL time_t archive_entry_atime(struct archive_entry *);
+__LA_DECL long archive_entry_atime_nsec(struct archive_entry *);
+__LA_DECL int archive_entry_atime_is_set(struct archive_entry *);
+__LA_DECL time_t archive_entry_birthtime(struct archive_entry *);
+__LA_DECL long archive_entry_birthtime_nsec(struct archive_entry *);
+__LA_DECL int archive_entry_birthtime_is_set(struct archive_entry *);
+__LA_DECL time_t archive_entry_ctime(struct archive_entry *);
+__LA_DECL long archive_entry_ctime_nsec(struct archive_entry *);
+__LA_DECL int archive_entry_ctime_is_set(struct archive_entry *);
+__LA_DECL dev_t archive_entry_dev(struct archive_entry *);
+__LA_DECL dev_t archive_entry_devmajor(struct archive_entry *);
+__LA_DECL dev_t archive_entry_devminor(struct archive_entry *);
+__LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *);
+__LA_DECL void archive_entry_fflags(struct archive_entry *,
+ unsigned long * /* set */,
+ unsigned long * /* clear */);
+__LA_DECL const char *archive_entry_fflags_text(struct archive_entry *);
+__LA_DECL __LA_GID_T archive_entry_gid(struct archive_entry *);
+__LA_DECL const char *archive_entry_gname(struct archive_entry *);
+__LA_DECL const wchar_t *archive_entry_gname_w(struct archive_entry *);
+__LA_DECL const char *archive_entry_hardlink(struct archive_entry *);
+__LA_DECL const wchar_t *archive_entry_hardlink_w(struct archive_entry *);
+__LA_DECL __LA_INO_T archive_entry_ino(struct archive_entry *);
+__LA_DECL __LA_INT64_T archive_entry_ino64(struct archive_entry *);
+__LA_DECL __LA_MODE_T archive_entry_mode(struct archive_entry *);
+__LA_DECL time_t archive_entry_mtime(struct archive_entry *);
+__LA_DECL long archive_entry_mtime_nsec(struct archive_entry *);
+__LA_DECL int archive_entry_mtime_is_set(struct archive_entry *);
+__LA_DECL unsigned int archive_entry_nlink(struct archive_entry *);
+__LA_DECL const char *archive_entry_pathname(struct archive_entry *);
+__LA_DECL const wchar_t *archive_entry_pathname_w(struct archive_entry *);
+__LA_DECL dev_t archive_entry_rdev(struct archive_entry *);
+__LA_DECL dev_t archive_entry_rdevmajor(struct archive_entry *);
+__LA_DECL dev_t archive_entry_rdevminor(struct archive_entry *);
+__LA_DECL const char *archive_entry_sourcepath(struct archive_entry *);
+__LA_DECL __LA_INT64_T archive_entry_size(struct archive_entry *);
+__LA_DECL int archive_entry_size_is_set(struct archive_entry *);
+__LA_DECL const char *archive_entry_strmode(struct archive_entry *);
+__LA_DECL const char *archive_entry_symlink(struct archive_entry *);
+__LA_DECL const wchar_t *archive_entry_symlink_w(struct archive_entry *);
+__LA_DECL __LA_UID_T archive_entry_uid(struct archive_entry *);
+__LA_DECL const char *archive_entry_uname(struct archive_entry *);
+__LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *);
+
+/*
+ * Set fields in an archive_entry.
+ *
+ * Note that string 'set' functions do not copy the string, only the pointer.
+ * In contrast, 'copy' functions do copy the object pointed to.
+ *
+ * Note: As of libarchive 2.4, 'set' functions do copy the string and
+ * are therefore exact synonyms for the 'copy' versions. The 'copy'
+ * names will be retired in libarchive 3.0.
+ */
+
+__LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long);
+__LA_DECL void archive_entry_unset_atime(struct archive_entry *);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *,
+ BY_HANDLE_FILE_INFORMATION *);
+#endif
+__LA_DECL void archive_entry_set_birthtime(struct archive_entry *, time_t, long);
+__LA_DECL void archive_entry_unset_birthtime(struct archive_entry *);
+__LA_DECL void archive_entry_set_ctime(struct archive_entry *, time_t, long);
+__LA_DECL void archive_entry_unset_ctime(struct archive_entry *);
+__LA_DECL void archive_entry_set_dev(struct archive_entry *, dev_t);
+__LA_DECL void archive_entry_set_devmajor(struct archive_entry *, dev_t);
+__LA_DECL void archive_entry_set_devminor(struct archive_entry *, dev_t);
+__LA_DECL void archive_entry_set_filetype(struct archive_entry *, unsigned int);
+__LA_DECL void archive_entry_set_fflags(struct archive_entry *,
+ unsigned long /* set */, unsigned long /* clear */);
+/* Returns pointer to start of first invalid token, or NULL if none. */
+/* Note that all recognized tokens are processed, regardless. */
+__LA_DECL const char *archive_entry_copy_fflags_text(struct archive_entry *,
+ const char *);
+__LA_DECL const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *,
+ const wchar_t *);
+__LA_DECL void archive_entry_set_gid(struct archive_entry *, __LA_GID_T);
+__LA_DECL void archive_entry_set_gname(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_gname(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *);
+__LA_DECL int archive_entry_update_gname_utf8(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_set_hardlink(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
+__LA_DECL int archive_entry_update_hardlink_utf8(struct archive_entry *, const char *);
+#if ARCHIVE_VERSION_NUMBER >= 3000000
+/* Starting with libarchive 3.0, this will be synonym for ino64. */
+__LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INT64_T);
+#else
+__LA_DECL void archive_entry_set_ino(struct archive_entry *, unsigned long);
+#endif
+__LA_DECL void archive_entry_set_ino64(struct archive_entry *, __LA_INT64_T);
+__LA_DECL void archive_entry_set_link(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *);
+__LA_DECL int archive_entry_update_link_utf8(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_set_mode(struct archive_entry *, __LA_MODE_T);
+__LA_DECL void archive_entry_set_mtime(struct archive_entry *, time_t, long);
+__LA_DECL void archive_entry_unset_mtime(struct archive_entry *);
+__LA_DECL void archive_entry_set_nlink(struct archive_entry *, unsigned int);
+__LA_DECL void archive_entry_set_pathname(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_pathname(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *);
+__LA_DECL int archive_entry_update_pathname_utf8(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_set_perm(struct archive_entry *, __LA_MODE_T);
+__LA_DECL void archive_entry_set_rdev(struct archive_entry *, dev_t);
+__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, dev_t);
+__LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, dev_t);
+__LA_DECL void archive_entry_set_size(struct archive_entry *, __LA_INT64_T);
+__LA_DECL void archive_entry_unset_size(struct archive_entry *);
+__LA_DECL void archive_entry_copy_sourcepath(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_set_symlink(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_symlink(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *);
+__LA_DECL int archive_entry_update_symlink_utf8(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_set_uid(struct archive_entry *, __LA_UID_T);
+__LA_DECL void archive_entry_set_uname(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_uname(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *);
+__LA_DECL int archive_entry_update_uname_utf8(struct archive_entry *, const char *);
+/*
+ * Routines to bulk copy fields to/from a platform-native "struct
+ * stat." Libarchive used to just store a struct stat inside of each
+ * archive_entry object, but this created issues when trying to
+ * manipulate archives on systems different than the ones they were
+ * created on.
+ *
+ * TODO: On Linux, provide both stat32 and stat64 versions of these functions.
+ */
+__LA_DECL const struct stat *archive_entry_stat(struct archive_entry *);
+__LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *);
+
+
+/*
+ * ACL routines. This used to simply store and return text-format ACL
+ * strings, but that proved insufficient for a number of reasons:
+ * = clients need control over uname/uid and gname/gid mappings
+ * = there are many different ACL text formats
+ * = would like to be able to read/convert archives containing ACLs
+ * on platforms that lack ACL libraries
+ *
+ * This last point, in particular, forces me to implement a reasonably
+ * complete set of ACL support routines.
+ *
+ * TODO: Extend this to support NFSv4/NTFS permissions. That should
+ * allow full ACL support on Mac OS, in particular, which uses
+ * POSIX.1e-style interfaces to manipulate NFSv4/NTFS permissions.
+ */
+
+/*
+ * Permission bits mimic POSIX.1e. Note that I've not followed POSIX.1e's
+ * "permset"/"perm" abstract type nonsense. A permset is just a simple
+ * bitmap, following long-standing Unix tradition.
+ */
+#define ARCHIVE_ENTRY_ACL_EXECUTE 1
+#define ARCHIVE_ENTRY_ACL_WRITE 2
+#define ARCHIVE_ENTRY_ACL_READ 4
+
+/* We need to be able to specify either or both of these. */
+#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 256
+#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 512
+
+/* Tag values mimic POSIX.1e */
+#define ARCHIVE_ENTRY_ACL_USER 10001 /* Specified user. */
+#define ARCHIVE_ENTRY_ACL_USER_OBJ 10002 /* User who owns the file. */
+#define ARCHIVE_ENTRY_ACL_GROUP 10003 /* Specified group. */
+#define ARCHIVE_ENTRY_ACL_GROUP_OBJ 10004 /* Group who owns the file. */
+#define ARCHIVE_ENTRY_ACL_MASK 10005 /* Modify group access. */
+#define ARCHIVE_ENTRY_ACL_OTHER 10006 /* Public. */
+
+/*
+ * Set the ACL by clearing it and adding entries one at a time.
+ * Unlike the POSIX.1e ACL routines, you must specify the type
+ * (access/default) for each entry. Internally, the ACL data is just
+ * a soup of entries. API calls here allow you to retrieve just the
+ * entries of interest. This design (which goes against the spirit of
+ * POSIX.1e) is useful for handling archive formats that combine
+ * default and access information in a single ACL list.
+ */
+__LA_DECL void archive_entry_acl_clear(struct archive_entry *);
+__LA_DECL void archive_entry_acl_add_entry(struct archive_entry *,
+ int /* type */, int /* permset */, int /* tag */,
+ int /* qual */, const char * /* name */);
+__LA_DECL void archive_entry_acl_add_entry_w(struct archive_entry *,
+ int /* type */, int /* permset */, int /* tag */,
+ int /* qual */, const wchar_t * /* name */);
+
+/*
+ * To retrieve the ACL, first "reset", then repeatedly ask for the
+ * "next" entry. The want_type parameter allows you to request only
+ * access entries or only default entries.
+ */
+__LA_DECL int archive_entry_acl_reset(struct archive_entry *, int /* want_type */);
+__LA_DECL int archive_entry_acl_next(struct archive_entry *, int /* want_type */,
+ int * /* type */, int * /* permset */, int * /* tag */,
+ int * /* qual */, const char ** /* name */);
+__LA_DECL int archive_entry_acl_next_w(struct archive_entry *, int /* want_type */,
+ int * /* type */, int * /* permset */, int * /* tag */,
+ int * /* qual */, const wchar_t ** /* name */);
+
+/*
+ * Construct a text-format ACL. The flags argument is a bitmask that
+ * can include any of the following:
+ *
+ * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include access entries.
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include default entries.
+ * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
+ * each ACL entry. (As used by 'star'.)
+ * ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each
+ * default ACL entry.
+ */
+#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
+#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
+__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *,
+ int /* flags */);
+
+/* Return a count of entries matching 'want_type' */
+__LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */);
+
+/*
+ * Private ACL parser. This is private because it handles some
+ * very weird formats that clients should not be messing with.
+ * Clients should only deal with their platform-native formats.
+ * Because of the need to support many formats cleanly, new arguments
+ * are likely to get added on a regular basis. Clients who try to use
+ * this interface are likely to be surprised when it changes.
+ *
+ * You were warned!
+ *
+ * TODO: Move this declaration out of the public header and into
+ * a private header. Warnings above are silly.
+ */
+__LA_DECL int __archive_entry_acl_parse_w(struct archive_entry *,
+ const wchar_t *, int /* type */);
+
+/*
+ * extended attributes
+ */
+
+__LA_DECL void archive_entry_xattr_clear(struct archive_entry *);
+__LA_DECL void archive_entry_xattr_add_entry(struct archive_entry *,
+ const char * /* name */, const void * /* value */,
+ size_t /* size */);
+
+/*
+ * To retrieve the xattr list, first "reset", then repeatedly ask for the
+ * "next" entry.
+ */
+
+__LA_DECL int archive_entry_xattr_count(struct archive_entry *);
+__LA_DECL int archive_entry_xattr_reset(struct archive_entry *);
+__LA_DECL int archive_entry_xattr_next(struct archive_entry *,
+ const char ** /* name */, const void ** /* value */, size_t *);
+
+/*
+ * Utility to match up hardlinks.
+ *
+ * The 'struct archive_entry_linkresolver' is a cache of archive entries
+ * for files with multiple links. Here's how to use it:
+ * 1. Create a lookup object with archive_entry_linkresolver_new()
+ * 2. Tell it the archive format you're using.
+ * 3. Hand each archive_entry to archive_entry_linkify().
+ * That function will return 0, 1, or 2 entries that should
+ * be written.
+ * 4. Call archive_entry_linkify(resolver, NULL) until
+ * no more entries are returned.
+ * 5. Call archive_entry_link_resolver_free(resolver) to free resources.
+ *
+ * The entries returned have their hardlink and size fields updated
+ * appropriately. If an entry is passed in that does not refer to
+ * a file with multiple links, it is returned unchanged. The intention
+ * is that you should be able to simply filter all entries through
+ * this machine.
+ *
+ * To make things more efficient, be sure that each entry has a valid
+ * nlinks value. The hardlink cache uses this to track when all links
+ * have been found. If the nlinks value is zero, it will keep every
+ * name in the cache indefinitely, which can use a lot of memory.
+ *
+ * Note that archive_entry_size() is reset to zero if the file
+ * body should not be written to the archive. Pay attention!
+ */
+struct archive_entry_linkresolver;
+
+/*
+ * There are three different strategies for marking hardlinks.
+ * The descriptions below name them after the best-known
+ * formats that rely on each strategy:
+ *
+ * "Old cpio" is the simplest, it always returns any entry unmodified.
+ * As far as I know, only cpio formats use this. Old cpio archives
+ * store every link with the full body; the onus is on the dearchiver
+ * to detect and properly link the files as they are restored.
+ * "tar" is also pretty simple; it caches a copy the first time it sees
+ * any link. Subsequent appearances are modified to be hardlink
+ * references to the first one without any body. Used by all tar
+ * formats, although the newest tar formats permit the "old cpio" strategy
+ * as well. This strategy is very simple for the dearchiver,
+ * and reasonably straightforward for the archiver.
+ * "new cpio" is trickier. It stores the body only with the last
+ * occurrence. The complication is that we might not
+ * see every link to a particular file in a single session, so
+ * there's no easy way to know when we've seen the last occurrence.
+ * The solution here is to queue one link until we see the next.
+ * At the end of the session, you can enumerate any remaining
+ * entries by calling archive_entry_linkify(NULL) and store those
+ * bodies. If you have a file with three links l1, l2, and l3,
+ * you'll get the following behavior if you see all three links:
+ * linkify(l1) => NULL (the resolver stores l1 internally)
+ * linkify(l2) => l1 (resolver stores l2, you write l1)
+ * linkify(l3) => l2, l3 (all links seen, you can write both).
+ * If you only see l1 and l2, you'll get this behavior:
+ * linkify(l1) => NULL
+ * linkify(l2) => l1
+ * linkify(NULL) => l2 (at end, you retrieve remaining links)
+ * As the name suggests, this strategy is used by newer cpio variants.
+ * It's noticably more complex for the archiver, slightly more complex
+ * for the dearchiver than the tar strategy, but makes it straightforward
+ * to restore a file using any link by simply continuing to scan until
+ * you see a link that is stored with a body. In contrast, the tar
+ * strategy requires you to rescan the archive from the beginning to
+ * correctly extract an arbitrary link.
+ */
+
+__LA_DECL struct archive_entry_linkresolver *archive_entry_linkresolver_new(void);
+__LA_DECL void archive_entry_linkresolver_set_strategy(
+ struct archive_entry_linkresolver *, int /* format_code */);
+__LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *);
+__LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *,
+ struct archive_entry **, struct archive_entry **);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* This is meaningless outside of this header. */
+#undef __LA_DECL
+
+#endif /* !ARCHIVE_ENTRY_H_INCLUDED */
diff --git a/src/mac/meandmyshadow/archive/archive_entry_private.h b/src/mac/meandmyshadow/archive/archive_entry_private.h
new file mode 100644
index 0000000..5ab4f75
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_entry_private.h
@@ -0,0 +1,184 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_entry_private.h 201096 2009-12-28 02:41:27Z kientzle $
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_ENTRY_PRIVATE_H_INCLUDED
+#define ARCHIVE_ENTRY_PRIVATE_H_INCLUDED
+
+#include "archive_string.h"
+
+/*
+ * Handle wide character (i.e., Unicode) and non-wide character
+ * strings transparently.
+ */
+
+struct aes {
+ struct archive_string aes_mbs;
+ struct archive_string aes_utf8;
+ const wchar_t *aes_wcs;
+ /* Bitmap of which of the above are valid. Because we're lazy
+ * about malloc-ing and reusing the underlying storage, we
+ * can't rely on NULL pointers to indicate whether a string
+ * has been set. */
+ int aes_set;
+#define AES_SET_MBS 1
+#define AES_SET_UTF8 2
+#define AES_SET_WCS 4
+};
+
+struct ae_acl {
+ struct ae_acl *next;
+ int type; /* E.g., access or default */
+ int tag; /* E.g., user/group/other/mask */
+ int permset; /* r/w/x bits */
+ int id; /* uid/gid for user/group */
+ struct aes name; /* uname/gname */
+};
+
+struct ae_xattr {
+ struct ae_xattr *next;
+
+ char *name;
+ void *value;
+ size_t size;
+};
+
+/*
+ * Description of an archive entry.
+ *
+ * Basically, this is a "struct stat" with a few text fields added in.
+ *
+ * TODO: Add "comment", "charset", and possibly other entries
+ * that are supported by "pax interchange" format. However, GNU, ustar,
+ * cpio, and other variants don't support these features, so they're not an
+ * excruciatingly high priority right now.
+ *
+ * TODO: "pax interchange" format allows essentially arbitrary
+ * key/value attributes to be attached to any entry. Supporting
+ * such extensions may make this library useful for special
+ * applications (e.g., a package manager could attach special
+ * package-management attributes to each entry). There are tricky
+ * API issues involved, so this is not going to happen until
+ * there's a real demand for it.
+ *
+ * TODO: Design a good API for handling sparse files.
+ */
+struct archive_entry {
+ /*
+ * Note that ae_stat.st_mode & AE_IFMT can be 0!
+ *
+ * This occurs when the actual file type of the object is not
+ * in the archive. For example, 'tar' archives store
+ * hardlinks without marking the type of the underlying
+ * object.
+ */
+
+ /*
+ * Read archive_entry_copy_stat.c for an explanation of why I
+ * don't just use "struct stat" instead of "struct aest" here
+ * and why I have this odd pointer to a separately-allocated
+ * struct stat.
+ */
+ void *stat;
+ int stat_valid; /* Set to 0 whenever a field in aest changes. */
+
+ struct aest {
+ int64_t aest_atime;
+ uint32_t aest_atime_nsec;
+ int64_t aest_ctime;
+ uint32_t aest_ctime_nsec;
+ int64_t aest_mtime;
+ uint32_t aest_mtime_nsec;
+ int64_t aest_birthtime;
+ uint32_t aest_birthtime_nsec;
+ gid_t aest_gid;
+ int64_t aest_ino;
+ mode_t aest_mode;
+ uint32_t aest_nlink;
+ uint64_t aest_size;
+ uid_t aest_uid;
+ /*
+ * Because converting between device codes and
+ * major/minor values is platform-specific and
+ * inherently a bit risky, we only do that conversion
+ * lazily. That way, we will do a better job of
+ * preserving information in those cases where no
+ * conversion is actually required.
+ */
+ int aest_dev_is_broken_down;
+ dev_t aest_dev;
+ dev_t aest_devmajor;
+ dev_t aest_devminor;
+ int aest_rdev_is_broken_down;
+ dev_t aest_rdev;
+ dev_t aest_rdevmajor;
+ dev_t aest_rdevminor;
+ } ae_stat;
+
+ int ae_set; /* bitmap of fields that are currently set */
+#define AE_SET_HARDLINK 1
+#define AE_SET_SYMLINK 2
+#define AE_SET_ATIME 4
+#define AE_SET_CTIME 8
+#define AE_SET_MTIME 16
+#define AE_SET_BIRTHTIME 32
+#define AE_SET_SIZE 64
+
+ /*
+ * Use aes here so that we get transparent mbs<->wcs conversions.
+ */
+ struct aes ae_fflags_text; /* Text fflags per fflagstostr(3) */
+ unsigned long ae_fflags_set; /* Bitmap fflags */
+ unsigned long ae_fflags_clear;
+ struct aes ae_gname; /* Name of owning group */
+ struct aes ae_hardlink; /* Name of target for hardlink */
+ struct aes ae_pathname; /* Name of entry */
+ struct aes ae_symlink; /* symlink contents */
+ struct aes ae_uname; /* Name of owner */
+
+ /* Not used within libarchive; useful for some clients. */
+ struct aes ae_sourcepath; /* Path this entry is sourced from. */
+
+ /* ACL support. */
+ struct ae_acl *acl_head;
+ struct ae_acl *acl_p;
+ int acl_state; /* See acl_next for details. */
+ wchar_t *acl_text_w;
+
+ /* extattr support. */
+ struct ae_xattr *xattr_head;
+ struct ae_xattr *xattr_p;
+
+ /* Miscellaneous. */
+ char strmode[12];
+};
+
+
+#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
diff --git a/src/mac/meandmyshadow/archive/archive_hash.h b/src/mac/meandmyshadow/archive/archive_hash.h
new file mode 100644
index 0000000..7991587
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_hash.h
@@ -0,0 +1,232 @@
+/*-
+ * Copyright (c) 2009 Joerg Sonnenberger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_hash.h 201171 2009-12-29 06:39:07Z kientzle $
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#if defined(__APPLE__)
+#include <CommonCrypto/CommonDigest.h>
+#endif
+
+/*
+ * Hash function support in various Operating Systems:
+ *
+ * NetBSD:
+ * - MD5 and SHA1 in libc: without _ after algorithm name
+ * - SHA2 in libc: with _ after algorithm name
+ *
+ * OpenBSD:
+ * - MD5, SHA1 and SHA2 in libc: without _ after algorithm name
+ * - OpenBSD 4.4 and earlier have SHA2 in libc with _ after algorithm name
+ *
+ * DragonFly and FreeBSD (XXX not used yet):
+ * - MD5 and SHA1 in libmd: without _ after algorithm name
+ * - SHA256: with _ after algorithm name
+ *
+ * OpenSSL:
+ * - MD5, SHA1 and SHA2 in libcrypto: with _ after algorithm name
+ */
+
+#if defined(HAVE_MD5_H) && defined(HAVE_MD5INIT)
+# include <md5.h>
+# define ARCHIVE_HAS_MD5
+typedef MD5_CTX archive_md5_ctx;
+# define archive_md5_init(ctx) MD5Init(ctx)
+# define archive_md5_final(ctx, buf) MD5Final(buf, ctx)
+# define archive_md5_update(ctx, buf, n) MD5Update(ctx, buf, n)
+#elif defined(HAVE_OPENSSL_MD5_H)
+# include <openssl/md5.h>
+# define ARCHIVE_HAS_MD5
+typedef MD5_CTX archive_md5_ctx;
+# define archive_md5_init(ctx) MD5_Init(ctx)
+# define archive_md5_final(ctx, buf) MD5_Final(buf, ctx)
+# define archive_md5_update(ctx, buf, n) MD5_Update(ctx, buf, n)
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(CALG_MD5)
+# define ARCHIVE_HAS_MD5
+typedef MD5_CTX archive_md5_ctx;
+# define archive_md5_init(ctx) MD5_Init(ctx)
+# define archive_md5_final(ctx, buf) MD5_Final(buf, ctx)
+# define archive_md5_update(ctx, buf, n) MD5_Update(ctx, buf, n)
+#elif defined(__APPLE__)
+# define ARCHIVE_HAS_MD5
+typedef CC_MD5_CTX archive_md5_ctx;
+# define archive_md5_init(ctx) CC_MD5_Init(ctx)
+# define archive_md5_final(ctx, buf) CC_MD5_Final(buf, ctx)
+# define archive_md5_update(ctx, buf, n) CC_MD5_Update(ctx, buf, n)
+#endif
+
+#if defined(HAVE_RMD160_H) && defined(HAVE_RMD160INIT)
+# include <rmd160.h>
+# define ARCHIVE_HAS_RMD160
+typedef RMD160_CTX archive_rmd160_ctx;
+# define archive_rmd160_init(ctx) RMD160Init(ctx)
+# define archive_rmd160_final(ctx, buf) RMD160Final(buf, ctx)
+# define archive_rmd160_update(ctx, buf, n) RMD160Update(ctx, buf, n)
+#elif defined(HAVE_OPENSSL_RIPEMD_H)
+# include <openssl/ripemd.h>
+# define ARCHIVE_HAS_RMD160
+typedef RIPEMD160_CTX archive_rmd160_ctx;
+# define archive_rmd160_init(ctx) RIPEMD160_Init(ctx)
+# define archive_rmd160_final(ctx, buf) RIPEMD160_Final(buf, ctx)
+# define archive_rmd160_update(ctx, buf, n) RIPEMD160_Update(ctx, buf, n)
+#elif defined(__APPLE__)
+// XXX: 4528609
+#endif
+
+#if defined(HAVE_SHA1_H) && defined(HAVE_SHA1INIT)
+# include <sha1.h>
+# define ARCHIVE_HAS_SHA1
+typedef SHA1_CTX archive_sha1_ctx;
+# define archive_sha1_init(ctx) SHA1Init(ctx)
+# define archive_sha1_final(ctx, buf) SHA1Final(buf, ctx)
+# define archive_sha1_update(ctx, buf, n) SHA1Update(ctx, buf, n)
+#elif defined(HAVE_OPENSSL_SHA_H)
+# include <openssl/sha.h>
+# define ARCHIVE_HAS_SHA1
+typedef SHA_CTX archive_sha1_ctx;
+# define archive_sha1_init(ctx) SHA1_Init(ctx)
+# define archive_sha1_final(ctx, buf) SHA1_Final(buf, ctx)
+# define archive_sha1_update(ctx, buf, n) SHA1_Update(ctx, buf, n)
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(CALG_SHA1)
+# define ARCHIVE_HAS_SHA1
+typedef SHA1_CTX archive_sha1_ctx;
+# define archive_sha1_init(ctx) SHA1_Init(ctx)
+# define archive_sha1_final(ctx, buf) SHA1_Final(buf, ctx)
+# define archive_sha1_update(ctx, buf, n) SHA1_Update(ctx, buf, n)
+#elif defined(__APPLE__)
+# define ARCHIVE_HAS_SHA1
+typedef CC_SHA1_CTX archive_sha1_ctx;
+# define archive_sha1_init(ctx) CC_SHA1_Init(ctx)
+# define archive_sha1_final(ctx, buf) CC_SHA1_Final(buf, ctx)
+# define archive_sha1_update(ctx, buf, n) CC_SHA1_Update(ctx, buf, n)
+#endif
+
+#if defined(HAVE_SHA2_H) && defined(HAVE_SHA256_INIT)
+# include <sha2.h>
+# define ARCHIVE_HAS_SHA256
+typedef SHA256_CTX archive_sha256_ctx;
+# define archive_sha256_init(ctx) SHA256_Init(ctx)
+# define archive_sha256_final(ctx, buf) SHA256_Final(buf, ctx)
+# define archive_sha256_update(ctx, buf, n) SHA256_Update(ctx, buf, n)
+#elif defined(HAVE_SHA2_H) && defined(HAVE_SHA256INIT)
+# include <sha2.h>
+# define ARCHIVE_HAS_SHA256
+typedef SHA256_CTX archive_sha256_ctx;
+# define archive_sha256_init(ctx) SHA256Init(ctx)
+# define archive_sha256_final(ctx, buf) SHA256Final(buf, ctx)
+# define archive_sha256_update(ctx, buf, n) SHA256Update(ctx, buf, n)
+#elif defined(HAVE_OPENSSL_SHA_H) && defined(HAVE_OPENSSL_SHA256_INIT)
+# include <openssl/sha.h>
+# define ARCHIVE_HAS_SHA256
+typedef SHA256_CTX archive_sha256_ctx;
+# define archive_sha256_init(ctx) SHA256_Init(ctx)
+# define archive_sha256_final(ctx, buf) SHA256_Final(buf, ctx)
+# define archive_sha256_update(ctx, buf, n) SHA256_Update(ctx, buf, n)
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(CALG_SHA_256)
+# define ARCHIVE_HAS_SHA256
+typedef SHA256_CTX archive_sha256_ctx;
+# define archive_sha256_init(ctx) SHA256_Init(ctx)
+# define archive_sha256_final(ctx, buf) SHA256_Final(buf, ctx)
+# define archive_sha256_update(ctx, buf, n) SHA256_Update(ctx, buf, n)
+#elif defined(__APPLE__)
+# define ARCHIVE_HAS_SHA256
+typedef CC_SHA256_CTX archive_sha256_ctx;
+# define archive_sha256_init(ctx) CC_SHA256_Init(ctx)
+# define archive_sha256_final(ctx, buf) CC_SHA256_Final(buf, ctx)
+# define archive_sha256_update(ctx, buf, n) CC_SHA256_Update(ctx, buf, n)
+#endif
+
+#if defined(HAVE_SHA2_H) && defined(HAVE_SHA384_INIT)
+# include <sha2.h>
+# define ARCHIVE_HAS_SHA384
+typedef SHA384_CTX archive_sha384_ctx;
+# define archive_sha384_init(ctx) SHA384_Init(ctx)
+# define archive_sha384_final(ctx, buf) SHA384_Final(buf, ctx)
+# define archive_sha384_update(ctx, buf, n) SHA384_Update(ctx, buf, n)
+#elif defined(HAVE_SHA2_H) && defined(HAVE_SHA384INIT)
+# include <sha2.h>
+# define ARCHIVE_HAS_SHA384
+typedef SHA384_CTX archive_sha384_ctx;
+# define archive_sha384_init(ctx) SHA384Init(ctx)
+# define archive_sha384_final(ctx, buf) SHA384Final(buf, ctx)
+# define archive_sha384_update(ctx, buf, n) SHA384Update(ctx, buf, n)
+#elif defined(HAVE_OPENSSL_SHA_H) && defined(HAVE_OPENSSL_SHA384_INIT)
+# include <openssl/sha.h>
+# define ARCHIVE_HAS_SHA384
+typedef SHA512_CTX archive_sha384_ctx;
+# define archive_sha384_init(ctx) SHA384_Init(ctx)
+# define archive_sha384_final(ctx, buf) SHA384_Final(buf, ctx)
+# define archive_sha384_update(ctx, buf, n) SHA384_Update(ctx, buf, n)
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(CALG_SHA_384)
+# define ARCHIVE_HAS_SHA384
+typedef SHA512_CTX archive_sha384_ctx;
+# define archive_sha384_init(ctx) SHA384_Init(ctx)
+# define archive_sha384_final(ctx, buf) SHA384_Final(buf, ctx)
+# define archive_sha384_update(ctx, buf, n) SHA384_Update(ctx, buf, n)
+#elif defined(__APPLE__)
+# define ARCHIVE_HAS_SHA384
+typedef CC_SHA512_CTX archive_sha384_ctx;
+# define archive_sha384_init(ctx) CC_SHA384_Init(ctx)
+# define archive_sha384_final(ctx, buf) CC_SHA384_Final(buf, ctx)
+# define archive_sha384_update(ctx, buf, n) CC_SHA384_Update(ctx, buf, n)
+#endif
+
+#if defined(HAVE_SHA2_H) && defined(HAVE_SHA512_INIT)
+# include <sha2.h>
+# define ARCHIVE_HAS_SHA512
+typedef SHA512_CTX archive_sha512_ctx;
+# define archive_sha512_init(ctx) SHA512_Init(ctx)
+# define archive_sha512_final(ctx, buf) SHA512_Final(buf, ctx)
+# define archive_sha512_update(ctx, buf, n) SHA512_Update(ctx, buf, n)
+#elif defined(HAVE_SHA2_H) && defined(HAVE_SHA512INIT)
+# include <sha2.h>
+# define ARCHIVE_HAS_SHA512
+typedef SHA512_CTX archive_sha512_ctx;
+# define archive_sha512_init(ctx) SHA512Init(ctx)
+# define archive_sha512_final(ctx, buf) SHA512Final(buf, ctx)
+# define archive_sha512_update(ctx, buf, n) SHA512Update(ctx, buf, n)
+#elif defined(HAVE_OPENSSL_SHA_H) && defined(HAVE_OPENSSL_SHA512_INIT)
+# include <openssl/sha.h>
+# define ARCHIVE_HAS_SHA512
+typedef SHA512_CTX archive_sha512_ctx;
+# define archive_sha512_init(ctx) SHA512_Init(ctx)
+# define archive_sha512_final(ctx, buf) SHA512_Final(buf, ctx)
+# define archive_sha512_update(ctx, buf, n) SHA512_Update(ctx, buf, n)
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(CALG_SHA_512)
+# define ARCHIVE_HAS_SHA512
+typedef SHA512_CTX archive_sha512_ctx;
+# define archive_sha512_init(ctx) SHA512_Init(ctx)
+# define archive_sha512_final(ctx, buf) SHA512_Final(buf, ctx)
+# define archive_sha512_update(ctx, buf, n) SHA512_Update(ctx, buf, n)
+#elif defined(__APPLE__)
+# define ARCHIVE_HAS_SHA512
+typedef CC_SHA512_CTX archive_sha512_ctx;
+# define archive_sha512_init(ctx) CC_SHA512_Init(ctx)
+# define archive_sha512_final(ctx, buf) CC_SHA512_Final(buf, ctx)
+# define archive_sha512_update(ctx, buf, n) CC_SHA512_Update(ctx, buf, n)
+#endif
diff --git a/src/mac/meandmyshadow/archive/archive_platform.h b/src/mac/meandmyshadow/archive/archive_platform.h
new file mode 100644
index 0000000..ce2f482
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_platform.h
@@ -0,0 +1,165 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_platform.h 201090 2009-12-28 02:22:04Z kientzle $
+ */
+
+/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */
+
+/*
+ * This header is the first thing included in any of the libarchive
+ * source files. As far as possible, platform-specific issues should
+ * be dealt with here and not within individual source files. I'm
+ * actively trying to minimize #if blocks within the main source,
+ * since they obfuscate the code.
+ */
+
+#ifndef ARCHIVE_PLATFORM_H_INCLUDED
+#define ARCHIVE_PLATFORM_H_INCLUDED
+
+/* archive.h and archive_entry.h require this. */
+#define __LIBARCHIVE_BUILD 1
+
+#if defined(PLATFORM_CONFIG_H)
+/* Use hand-built config.h in environments that need it. */
+#include PLATFORM_CONFIG_H
+#elif defined(HAVE_CONFIG_H)
+/* Most POSIX platforms use the 'configure' script to build config.h */
+#include "config.h"
+#else
+/* Warn if the library hasn't been (automatically or manually) configured. */
+#error Oops: No config.h and no pre-built configuration in archive_platform.h.
+#endif
+
+/* It should be possible to get rid of this by extending the feature-test
+ * macros to cover Windows API functions, probably along with non-trivial
+ * refactoring of code to find structures that sit more cleanly on top of
+ * either Windows or Posix APIs. */
+#if (defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)
+#include "archive_windows.h"
+#endif
+
+/*
+ * The config files define a lot of feature macros. The following
+ * uses those macros to select/define replacements and include key
+ * headers as required.
+ */
+
+/* Get a real definition for __FBSDID if we can */
+#if HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+/* If not, define it so as to avoid dangling semicolons. */
+#ifndef __FBSDID
+#define __FBSDID(a) struct _undefined_hack
+#endif
+
+/* Try to get standard C99-style integer type definitions. */
+#if HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+/* Borland warns about its own constants! */
+#if defined(__BORLANDC__)
+# if HAVE_DECL_UINT64_MAX
+# undef UINT64_MAX
+# undef HAVE_DECL_UINT64_MAX
+# endif
+# if HAVE_DECL_UINT64_MIN
+# undef UINT64_MIN
+# undef HAVE_DECL_UINT64_MIN
+# endif
+# if HAVE_DECL_INT64_MAX
+# undef INT64_MAX
+# undef HAVE_DECL_INT64_MAX
+# endif
+# if HAVE_DECL_INT64_MIN
+# undef INT64_MIN
+# undef HAVE_DECL_INT64_MIN
+# endif
+#endif
+
+/* Some platforms lack the standard *_MAX definitions. */
+#if !HAVE_DECL_SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+#if !HAVE_DECL_SSIZE_MAX
+#define SSIZE_MAX ((ssize_t)(SIZE_MAX >> 1))
+#endif
+#if !HAVE_DECL_UINT32_MAX
+#define UINT32_MAX (~(uint32_t)0)
+#endif
+#if !HAVE_DECL_UINT64_MAX
+#define UINT64_MAX (~(uint64_t)0)
+#endif
+#if !HAVE_DECL_INT64_MAX
+#define INT64_MAX ((int64_t)(UINT64_MAX >> 1))
+#endif
+#if !HAVE_DECL_INT64_MIN
+#define INT64_MIN ((int64_t)(~INT64_MAX))
+#endif
+
+/*
+ * If this platform has <sys/acl.h>, acl_create(), acl_init(),
+ * acl_set_file(), and ACL_USER, we assume it has the rest of the
+ * POSIX.1e draft functions used in archive_read_extract.c.
+ */
+#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE && HAVE_ACL_USER
+#define HAVE_POSIX_ACL 1
+#endif
+
+/*
+ * If we can't restore metadata using a file descriptor, then
+ * for compatibility's sake, close files before trying to restore metadata.
+ */
+#if defined(HAVE_FCHMOD) || defined(HAVE_FUTIMES) || defined(HAVE_ACL_SET_FD) || defined(HAVE_ACL_SET_FD_NP) || defined(HAVE_FCHOWN)
+#define CAN_RESTORE_METADATA_FD
+#endif
+
+/* Set up defaults for internal error codes. */
+#ifndef ARCHIVE_ERRNO_FILE_FORMAT
+#if HAVE_EFTYPE
+#define ARCHIVE_ERRNO_FILE_FORMAT EFTYPE
+#else
+#if HAVE_EILSEQ
+#define ARCHIVE_ERRNO_FILE_FORMAT EILSEQ
+#else
+#define ARCHIVE_ERRNO_FILE_FORMAT EINVAL
+#endif
+#endif
+#endif
+
+#ifndef ARCHIVE_ERRNO_PROGRAMMER
+#define ARCHIVE_ERRNO_PROGRAMMER EINVAL
+#endif
+
+#ifndef ARCHIVE_ERRNO_MISC
+#define ARCHIVE_ERRNO_MISC (-1)
+#endif
+
+#endif /* !ARCHIVE_PLATFORM_H_INCLUDED */
diff --git a/src/mac/meandmyshadow/archive/archive_private.h b/src/mac/meandmyshadow/archive/archive_private.h
new file mode 100644
index 0000000..63384b8
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_private.h
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_private.h 201098 2009-12-28 02:58:14Z kientzle $
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_PRIVATE_H_INCLUDED
+#define ARCHIVE_PRIVATE_H_INCLUDED
+
+#include "archive.h"
+#include "archive_string.h"
+
+#if defined(__GNUC__) && (__GNUC__ > 2 || \
+ (__GNUC__ == 2 && __GNUC_MINOR__ >= 5))
+#define __LA_DEAD __attribute__((__noreturn__))
+#else
+#define __LA_DEAD
+#endif
+
+#define ARCHIVE_WRITE_MAGIC (0xb0c5c0deU)
+#define ARCHIVE_READ_MAGIC (0xdeb0c5U)
+#define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)
+#define ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U)
+
+#define ARCHIVE_STATE_ANY 0xFFFFU
+#define ARCHIVE_STATE_NEW 1U
+#define ARCHIVE_STATE_HEADER 2U
+#define ARCHIVE_STATE_DATA 4U
+#define ARCHIVE_STATE_DATA_END 8U
+#define ARCHIVE_STATE_EOF 0x10U
+#define ARCHIVE_STATE_CLOSED 0x20U
+#define ARCHIVE_STATE_FATAL 0x8000U
+
+struct archive_vtable {
+ int (*archive_close)(struct archive *);
+ int (*archive_finish)(struct archive *);
+ int (*archive_write_header)(struct archive *,
+ struct archive_entry *);
+ int (*archive_write_finish_entry)(struct archive *);
+ ssize_t (*archive_write_data)(struct archive *,
+ const void *, size_t);
+ ssize_t (*archive_write_data_block)(struct archive *,
+ const void *, size_t, off_t);
+};
+
+struct archive {
+ /*
+ * The magic/state values are used to sanity-check the
+ * client's usage. If an API function is called at a
+ * ridiculous time, or the client passes us an invalid
+ * pointer, these values allow me to catch that.
+ */
+ unsigned int magic;
+ unsigned int state;
+
+ /*
+ * Some public API functions depend on the "real" type of the
+ * archive object.
+ */
+ struct archive_vtable *vtable;
+
+ int archive_format;
+ const char *archive_format_name;
+
+ int compression_code; /* Currently active compression. */
+ const char *compression_name;
+
+ /* Position in UNCOMPRESSED data stream. */
+ int64_t file_position;
+ /* Position in COMPRESSED data stream. */
+ int64_t raw_position;
+ /* Number of file entries processed. */
+ int file_count;
+
+ int archive_error_number;
+ const char *error;
+ struct archive_string error_string;
+};
+
+/* Check magic value and state; exit if it isn't valid. */
+void __archive_check_magic(struct archive *, unsigned int magic,
+ unsigned int state, const char *func);
+
+void __archive_errx(int retvalue, const char *msg) __LA_DEAD;
+
+int __archive_parse_options(const char *p, const char *fn,
+ int keysize, char *key, int valsize, char *val);
+
+#define err_combine(a,b) ((a) < (b) ? (a) : (b))
+
+#if defined(__BORLANDC__) || (defined(_MSC_VER) && _MSC_VER <= 1300)
+# define ARCHIVE_LITERAL_LL(x) x##i64
+# define ARCHIVE_LITERAL_ULL(x) x##ui64
+#else
+# define ARCHIVE_LITERAL_LL(x) x##ll
+# define ARCHIVE_LITERAL_ULL(x) x##ull
+#endif
+
+#endif
diff --git a/src/mac/meandmyshadow/archive/archive_read_disk_private.h b/src/mac/meandmyshadow/archive/archive_read_disk_private.h
new file mode 100644
index 0000000..b674b71
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_read_disk_private.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2003-2009 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_read_disk_private.h 201105 2009-12-28 03:20:54Z kientzle $
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
+#define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
+
+struct archive_read_disk {
+ struct archive archive;
+
+ /*
+ * Symlink mode is one of 'L'ogical, 'P'hysical, or 'H'ybrid,
+ * following an old BSD convention. 'L' follows all symlinks,
+ * 'P' follows none, 'H' follows symlinks only for the first
+ * item.
+ */
+ char symlink_mode;
+
+ /*
+ * Since symlink interaction changes, we need to track whether
+ * we're following symlinks for the current item. 'L' mode above
+ * sets this true, 'P' sets it false, 'H' changes it as we traverse.
+ */
+ char follow_symlinks; /* Either 'L' or 'P'. */
+
+ const char * (*lookup_gname)(void *private, gid_t gid);
+ void (*cleanup_gname)(void *private);
+ void *lookup_gname_data;
+ const char * (*lookup_uname)(void *private, gid_t gid);
+ void (*cleanup_uname)(void *private);
+ void *lookup_uname_data;
+};
+
+#endif
diff --git a/src/mac/meandmyshadow/archive/archive_read_private.h b/src/mac/meandmyshadow/archive/archive_read_private.h
new file mode 100644
index 0000000..5a85018
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_read_private.h
@@ -0,0 +1,199 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_read_private.h 201088 2009-12-28 02:18:55Z kientzle $
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_READ_PRIVATE_H_INCLUDED
+#define ARCHIVE_READ_PRIVATE_H_INCLUDED
+
+#include "archive.h"
+#include "archive_string.h"
+#include "archive_private.h"
+
+struct archive_read;
+struct archive_read_filter_bidder;
+struct archive_read_filter;
+
+/*
+ * How bidding works for filters:
+ * * The bid manager reads the first block from the current source.
+ * * It shows that block to each registered bidder.
+ * * The bid manager creates a new filter structure for the winning
+ * bidder and gives the winning bidder a chance to initialize it.
+ * * The new filter becomes the top filter in the archive_read structure
+ * and we repeat the process.
+ * This ends only when no bidder provides a non-zero bid.
+ */
+struct archive_read_filter_bidder {
+ /* Configuration data for the bidder. */
+ void *data;
+ /* Taste the upstream filter to see if we handle this. */
+ int (*bid)(struct archive_read_filter_bidder *,
+ struct archive_read_filter *);
+ /* Initialize a newly-created filter. */
+ int (*init)(struct archive_read_filter *);
+ /* Set an option for the filter bidder. */
+ int (*options)(struct archive_read_filter_bidder *,
+ const char *key, const char *value);
+ /* Release the bidder's configuration data. */
+ int (*free)(struct archive_read_filter_bidder *);
+};
+
+/*
+ * This structure is allocated within the archive_read core
+ * and initialized by archive_read and the init() method of the
+ * corresponding bidder above.
+ */
+struct archive_read_filter {
+ /* Essentially all filters will need these values, so
+ * just declare them here. */
+ struct archive_read_filter_bidder *bidder; /* My bidder. */
+ struct archive_read_filter *upstream; /* Who I read from. */
+ struct archive_read *archive; /* Associated archive. */
+ /* Return next block. */
+ ssize_t (*read)(struct archive_read_filter *, const void **);
+ /* Skip forward this many bytes. */
+ int64_t (*skip)(struct archive_read_filter *self, int64_t request);
+ /* Close (just this filter) and free(self). */
+ int (*close)(struct archive_read_filter *self);
+ /* My private data. */
+ void *data;
+
+ const char *name;
+ int code;
+
+ /* Used by reblocking logic. */
+ char *buffer;
+ size_t buffer_size;
+ char *next; /* Current read location. */
+ size_t avail; /* Bytes in my buffer. */
+ const void *client_buff; /* Client buffer information. */
+ size_t client_total;
+ const char *client_next;
+ size_t client_avail;
+ int64_t position;
+ char end_of_file;
+ char fatal;
+};
+
+/*
+ * The client looks a lot like a filter, so we just wrap it here.
+ *
+ * TODO: Make archive_read_filter and archive_read_client identical so
+ * that users of the library can easily register their own
+ * transformation filters. This will probably break the API/ABI and
+ * so should be deferred at least until libarchive 3.0.
+ */
+struct archive_read_client {
+ archive_read_callback *reader;
+ archive_skip_callback *skipper;
+ archive_close_callback *closer;
+};
+
+struct archive_read {
+ struct archive archive;
+
+ struct archive_entry *entry;
+
+ /* Dev/ino of the archive being read/written. */
+ dev_t skip_file_dev;
+ ino_t skip_file_ino;
+
+ /*
+ * Used by archive_read_data() to track blocks and copy
+ * data to client buffers, filling gaps with zero bytes.
+ */
+ const char *read_data_block;
+ off_t read_data_offset;
+ off_t read_data_output_offset;
+ size_t read_data_remaining;
+
+ /* Callbacks to open/read/write/close client archive stream. */
+ struct archive_read_client client;
+
+ /* Registered filter bidders. */
+ struct archive_read_filter_bidder bidders[8];
+
+ /* Last filter in chain */
+ struct archive_read_filter *filter;
+
+ /* File offset of beginning of most recently-read header. */
+ off_t header_position;
+
+ /*
+ * Format detection is mostly the same as compression
+ * detection, with one significant difference: The bidders
+ * use the read_ahead calls above to examine the stream rather
+ * than having the supervisor hand them a block of data to
+ * examine.
+ */
+
+ struct archive_format_descriptor {
+ void *data;
+ const char *name;
+ int (*bid)(struct archive_read *);
+ int (*options)(struct archive_read *, const char *key,
+ const char *value);
+ int (*read_header)(struct archive_read *, struct archive_entry *);
+ int (*read_data)(struct archive_read *, const void **, size_t *, off_t *);
+ int (*read_data_skip)(struct archive_read *);
+ int (*cleanup)(struct archive_read *);
+ } formats[9];
+ struct archive_format_descriptor *format; /* Active format. */
+
+ /*
+ * Various information needed by archive_extract.
+ */
+ struct extract *extract;
+ int (*cleanup_archive_extract)(struct archive_read *);
+};
+
+int __archive_read_register_format(struct archive_read *a,
+ void *format_data,
+ const char *name,
+ int (*bid)(struct archive_read *),
+ int (*options)(struct archive_read *, const char *, const char *),
+ int (*read_header)(struct archive_read *, struct archive_entry *),
+ int (*read_data)(struct archive_read *, const void **, size_t *, off_t *),
+ int (*read_data_skip)(struct archive_read *),
+ int (*cleanup)(struct archive_read *));
+
+struct archive_read_filter_bidder
+ *__archive_read_get_bidder(struct archive_read *a);
+
+const void *__archive_read_ahead(struct archive_read *, size_t, ssize_t *);
+const void *__archive_read_filter_ahead(struct archive_read_filter *,
+ size_t, ssize_t *);
+ssize_t __archive_read_consume(struct archive_read *, size_t);
+ssize_t __archive_read_filter_consume(struct archive_read_filter *, size_t);
+int64_t __archive_read_skip(struct archive_read *, int64_t);
+int64_t __archive_read_skip_lenient(struct archive_read *, int64_t);
+int64_t __archive_read_filter_skip(struct archive_read_filter *, int64_t);
+int __archive_read_program(struct archive_read_filter *, const char *);
+#endif
diff --git a/src/mac/meandmyshadow/archive/archive_string.h b/src/mac/meandmyshadow/archive/archive_string.h
new file mode 100644
index 0000000..25d7a8b
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_string.h
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_string.h 201092 2009-12-28 02:26:06Z kientzle $
+ *
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_STRING_H_INCLUDED
+#define ARCHIVE_STRING_H_INCLUDED
+
+#include <stdarg.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* required for wchar_t on some systems */
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_WCHAR_H
+#include <wchar.h>
+#endif
+
+/*
+ * Basic resizable/reusable string support a la Java's "StringBuffer."
+ *
+ * Unlike sbuf(9), the buffers here are fully reusable and track the
+ * length throughout.
+ *
+ * Note that all visible symbols here begin with "__archive" as they
+ * are internal symbols not intended for anyone outside of this library
+ * to see or use.
+ */
+
+struct archive_string {
+ char *s; /* Pointer to the storage */
+ size_t length; /* Length of 's' */
+ size_t buffer_length; /* Length of malloc-ed storage */
+};
+
+/* Initialize an archive_string object on the stack or elsewhere. */
+#define archive_string_init(a) \
+ do { (a)->s = NULL; (a)->length = 0; (a)->buffer_length = 0; } while(0)
+
+/* Append a C char to an archive_string, resizing as necessary. */
+struct archive_string *
+__archive_strappend_char(struct archive_string *, char);
+#define archive_strappend_char __archive_strappend_char
+
+/* Convert a wide-char string to UTF-8 and append the result. */
+struct archive_string *
+__archive_strappend_w_utf8(struct archive_string *, const wchar_t *);
+#define archive_strappend_w_utf8 __archive_strappend_w_utf8
+
+/* Convert a wide-char string to current locale and append the result. */
+/* Returns NULL if conversion fails. */
+struct archive_string *
+__archive_strappend_w_mbs(struct archive_string *, const wchar_t *);
+#define archive_strappend_w_mbs __archive_strappend_w_mbs
+
+/* Basic append operation. */
+struct archive_string *
+__archive_string_append(struct archive_string *as, const char *p, size_t s);
+
+/* Copy one archive_string to another */
+void
+__archive_string_copy(struct archive_string *dest, struct archive_string *src);
+#define archive_string_copy(dest, src) \
+ __archive_string_copy(dest, src)
+
+/* Concatenate one archive_string to another */
+void
+__archive_string_concat(struct archive_string *dest, struct archive_string *src);
+#define archive_string_concat(dest, src) \
+ __archive_string_concat(dest, src)
+
+/* Ensure that the underlying buffer is at least as large as the request. */
+struct archive_string *
+__archive_string_ensure(struct archive_string *, size_t);
+#define archive_string_ensure __archive_string_ensure
+
+/* Append C string, which may lack trailing \0. */
+/* The source is declared void * here because this gets used with
+ * "signed char *", "unsigned char *" and "char *" arguments.
+ * Declaring it "char *" as with some of the other functions just
+ * leads to a lot of extra casts. */
+struct archive_string *
+__archive_strncat(struct archive_string *, const void *, size_t);
+#define archive_strncat __archive_strncat
+
+/* Append a C string to an archive_string, resizing as necessary. */
+#define archive_strcat(as,p) __archive_string_append((as),(p),strlen(p))
+
+/* Copy a C string to an archive_string, resizing as necessary. */
+#define archive_strcpy(as,p) \
+ ((as)->length = 0, __archive_string_append((as), (p), p == NULL ? 0 : strlen(p)))
+
+/* Copy a C string to an archive_string with limit, resizing as necessary. */
+#define archive_strncpy(as,p,l) \
+ ((as)->length=0, archive_strncat((as), (p), (l)))
+
+/* Return length of string. */
+#define archive_strlen(a) ((a)->length)
+
+/* Set string length to zero. */
+#define archive_string_empty(a) ((a)->length = 0)
+
+/* Release any allocated storage resources. */
+void __archive_string_free(struct archive_string *);
+#define archive_string_free __archive_string_free
+
+/* Like 'vsprintf', but resizes the underlying string as necessary. */
+void __archive_string_vsprintf(struct archive_string *, const char *,
+ va_list);
+#define archive_string_vsprintf __archive_string_vsprintf
+
+void __archive_string_sprintf(struct archive_string *, const char *, ...);
+#define archive_string_sprintf __archive_string_sprintf
+
+/* Allocates a fresh buffer and converts as (assumed to be UTF-8) into it.
+ * Returns NULL if conversion failed in any way. */
+wchar_t *__archive_string_utf8_w(struct archive_string *as);
+
+
+#endif
diff --git a/src/mac/meandmyshadow/archive/archive_windows.h b/src/mac/meandmyshadow/archive/archive_windows.h
new file mode 100644
index 0000000..b68e72e
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_windows.h
@@ -0,0 +1,422 @@
+/*-
+ * Copyright (c) 2009 Michihiro NAKAJIMA
+ * Copyright (c) 2003-2006 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+/*
+ * TODO: A lot of stuff in here isn't actually used by libarchive and
+ * can be trimmed out. Note that this file is used by libarchive and
+ * libarchive_test but nowhere else. (But note that it gets compiled
+ * with many different Windows environments, including MinGW, Visual
+ * Studio, and Cygwin. Significant changes should be tested in all three.)
+ */
+
+/*
+ * TODO: Don't use off_t in here. Use __int64 instead. Note that
+ * Visual Studio and the Windows SDK define off_t as 32 bits; Win32's
+ * more modern file handling APIs all use __int64 instead of off_t.
+ */
+
+#ifndef LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED
+#define LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED
+
+/* Start of configuration for native Win32 */
+
+#include <errno.h>
+#define set_errno(val) ((errno)=val)
+#include <io.h>
+#include <stdlib.h> //brings in NULL
+#if defined(HAVE_STDINT_H)
+#include <stdint.h>
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <process.h>
+#include <direct.h>
+#define NOCRYPT
+#include <windows.h>
+//#define EFTYPE 7
+
+#if !defined(STDIN_FILENO)
+#define STDIN_FILENO 0
+#endif
+
+#if !defined(STDOUT_FILENO)
+#define STDOUT_FILENO 1
+#endif
+
+#if !defined(STDERR_FILENO)
+#define STDERR_FILENO 2
+#endif
+
+
+#if defined(_MSC_VER)
+/* TODO: Fix the code, don't suppress the warnings. */
+#pragma warning(disable:4244) /* 'conversion' conversion from 'type1' to 'type2', possible loss of data */
+#endif
+#if defined(__BORLANDC__)
+#pragma warn -8068 /* Constant out of range in comparison. */
+#pragma warn -8072 /* Suspicious pointer arithmetic. */
+#endif
+
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+#endif
+
+/* Alias the Windows _function to the POSIX equivalent. */
+#define access _access
+#define chdir __la_chdir
+#define chmod __la_chmod
+#define close _close
+#define fcntl __la_fcntl
+#ifndef fileno
+#define fileno _fileno
+#endif
+#define fstat __la_fstat
+#define ftruncate __la_ftruncate
+#define futimes __la_futimes
+#define getcwd _getcwd
+#define link __la_link
+#define lseek __la_lseek
+#define lstat __la_stat
+#define mbstowcs __la_mbstowcs
+#define mkdir(d,m) __la_mkdir(d, m)
+#define mktemp _mktemp
+#define open __la_open
+#define read __la_read
+#define rmdir __la_rmdir
+#if !defined(__BORLANDC__)
+#define setmode _setmode
+#endif
+#define stat(path,stref) __la_stat(path,stref)
+#if !defined(__BORLANDC__)
+#define strdup _strdup
+#endif
+#define tzset _tzset
+#if !defined(__BORLANDC__)
+#define umask _umask
+#endif
+#define unlink __la_unlink
+#define utimes __la_utimes
+#define waitpid __la_waitpid
+#define write __la_write
+
+#ifndef O_RDONLY
+#define O_RDONLY _O_RDONLY
+#define O_WRONLY _O_WRONLY
+#define O_TRUNC _O_TRUNC
+#define O_CREAT _O_CREAT
+#define O_EXCL _O_EXCL
+#define O_BINARY _O_BINARY
+#endif
+
+#ifndef _S_IFIFO
+ #define _S_IFIFO 0010000 /* pipe */
+#endif
+#ifndef _S_IFCHR
+ #define _S_IFCHR 0020000 /* character special */
+#endif
+#ifndef _S_IFDIR
+ #define _S_IFDIR 0040000 /* directory */
+#endif
+#ifndef _S_IFBLK
+ #define _S_IFBLK 0060000 /* block special */
+#endif
+#ifndef _S_IFLNK
+ #define _S_IFLNK 0120000 /* symbolic link */
+#endif
+#ifndef _S_IFSOCK
+ #define _S_IFSOCK 0140000 /* socket */
+#endif
+#ifndef _S_IFREG
+ #define _S_IFREG 0100000 /* regular */
+#endif
+#ifndef _S_IFMT
+ #define _S_IFMT 0170000 /* file type mask */
+#endif
+
+#ifndef S_IFIFO
+#define S_IFIFO _S_IFIFO
+#endif
+//#define S_IFCHR _S_IFCHR
+//#define S_IFDIR _S_IFDIR
+#ifndef S_IFBLK
+#define S_IFBLK _S_IFBLK
+#endif
+#ifndef S_IFLNK
+#define S_IFLNK _S_IFLNK
+#endif
+#ifndef S_IFSOCK
+#define S_IFSOCK _S_IFSOCK
+#endif
+//#define S_IFREG _S_IFREG
+//#define S_IFMT _S_IFMT
+
+#ifndef S_ISBLK
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) /* block special */
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) /* fifo or socket */
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) /* char special */
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) /* directory */
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) /* regular file */
+#endif
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) /* Symbolic link */
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) /* Socket */
+
+#define _S_ISUID 0004000 /* set user id on execution */
+#define _S_ISGID 0002000 /* set group id on execution */
+#define _S_ISVTX 0001000 /* save swapped text even after use */
+
+#define S_ISUID _S_ISUID
+#define S_ISGID _S_ISGID
+#define S_ISVTX _S_ISVTX
+
+#define _S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC)
+#define _S_IXUSR _S_IEXEC /* read permission, user */
+#define _S_IWUSR _S_IWRITE /* write permission, user */
+#define _S_IRUSR _S_IREAD /* execute/search permission, user */
+#define _S_IRWXG (_S_IRWXU >> 3)
+#define _S_IXGRP (_S_IXUSR >> 3) /* read permission, group */
+#define _S_IWGRP (_S_IWUSR >> 3) /* write permission, group */
+#define _S_IRGRP (_S_IRUSR >> 3) /* execute/search permission, group */
+#define _S_IRWXO (_S_IRWXG >> 3)
+#define _S_IXOTH (_S_IXGRP >> 3) /* read permission, other */
+#define _S_IWOTH (_S_IWGRP >> 3) /* write permission, other */
+#define _S_IROTH (_S_IRGRP >> 3) /* execute/search permission, other */
+
+#ifndef S_IRWXU
+#define S_IRWXU _S_IRWXU
+#define S_IXUSR _S_IXUSR
+#define S_IWUSR _S_IWUSR
+#define S_IRUSR _S_IRUSR
+#endif
+#define S_IRWXG _S_IRWXG
+#define S_IXGRP _S_IXGRP
+#define S_IWGRP _S_IWGRP
+#define S_IRGRP _S_IRGRP
+#define S_IRWXO _S_IRWXO
+#define S_IXOTH _S_IXOTH
+#define S_IWOTH _S_IWOTH
+#define S_IROTH _S_IROTH
+
+#define F_DUPFD 0 /* Duplicate file descriptor. */
+#define F_GETFD 1 /* Get file descriptor flags. */
+#define F_SETFD 2 /* Set file descriptor flags. */
+#define F_GETFL 3 /* Get file status flags. */
+#define F_SETFL 4 /* Set file status flags. */
+#define F_GETOWN 5 /* Get owner (receiver of SIGIO). */
+#define F_SETOWN 6 /* Set owner (receiver of SIGIO). */
+#define F_GETLK 7 /* Get record locking info. */
+#define F_SETLK 8 /* Set record locking info (non-blocking). */
+#define F_SETLKW 9 /* Set record locking info (blocking). */
+
+/* XXX missing */
+#define F_GETLK64 7 /* Get record locking info. */
+#define F_SETLK64 8 /* Set record locking info (non-blocking). */
+#define F_SETLKW64 9 /* Set record locking info (blocking). */
+
+/* File descriptor flags used with F_GETFD and F_SETFD. */
+#define FD_CLOEXEC 1 /* Close on exec. */
+
+//NOT SURE IF O_NONBLOCK is OK here but at least the 0x0004 flag is not used by anything else...
+#define O_NONBLOCK 0x0004 /* Non-blocking I/O. */
+//#define O_NDELAY O_NONBLOCK
+
+/* Symbolic constants for the access() function */
+#if !defined(F_OK)
+ #define R_OK 4 /* Test for read permission */
+ #define W_OK 2 /* Test for write permission */
+ #define X_OK 1 /* Test for execute permission */
+ #define F_OK 0 /* Test for existence of file */
+#endif
+
+
+#ifdef _LARGEFILE_SOURCE
+# define __USE_LARGEFILE 1 /* declare fseeko and ftello */
+#endif
+
+#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64
+# define __USE_FILE_OFFSET64 1 /* replace 32-bit functions by 64-bit ones */
+#endif
+
+#if __USE_LARGEFILE && __USE_FILE_OFFSET64
+/* replace stat and seek by their large-file equivalents */
+#undef stat
+#define stat _stati64
+
+#undef lseek
+#define lseek _lseeki64
+#define lseek64 _lseeki64
+#define tell _telli64
+#define tell64 _telli64
+
+#ifdef __MINGW32__
+# define fseek fseeko64
+# define fseeko fseeko64
+# define ftell ftello64
+# define ftello ftello64
+# define ftell64 ftello64
+#endif /* __MINGW32__ */
+#endif /* LARGE_FILES */
+
+#ifdef USE_WINSOCK_TIMEVAL
+/* Winsock timeval has long size tv_sec. */
+#define __timeval timeval
+#else
+struct _timeval64i32 {
+ time_t tv_sec;
+ long tv_usec;
+};
+#define __timeval _timeval64i32
+#endif
+
+/* Message digest define */
+#if !defined(HAVE_OPENSSL_MD5_H) && !defined(HAVE_OPENSSL_SHA_H)
+# if defined(_MSC_VER) && _MSC_VER < 1300
+# define _WIN32_WINNT 0x0400
+# endif
+#include <wincrypt.h>
+typedef struct {
+ int valid;
+ HCRYPTPROV cryptProv;
+ HCRYPTHASH hash;
+} Digest_CTX;
+#endif
+
+#if !defined(HAVE_OPENSSL_MD5_H) && defined(CALG_MD5)
+#define MD5_DIGEST_LENGTH 16
+#define HAVE_MD5 1
+#define MD5_CTX Digest_CTX
+#endif
+#ifndef HAVE_OPENSSL_SHA_H
+#ifdef CALG_SHA1
+#define SHA1_DIGEST_LENGTH 20
+#define HAVE_SHA1 1
+#define SHA1_CTX Digest_CTX
+#endif
+#ifdef CALG_SHA_256
+#define SHA256_DIGEST_LENGTH 32
+#define HAVE_SHA256 1
+#define SHA256_CTX Digest_CTX
+#endif
+#ifdef CALG_SHA_384
+#define SHA384_DIGEST_LENGTH 48
+#define HAVE_SHA384 1
+#define SHA384_CTX Digest_CTX
+#endif
+#ifdef CALG_SHA_512
+#define SHA512_DIGEST_LENGTH 64
+#define HAVE_SHA512 1
+#define SHA512_CTX Digest_CTX
+#endif
+#endif /* HAVE_OPENSSL_SHA_H */
+
+/* End of Win32 definitions. */
+
+/* Tell libarchive code that we have simulations for these. */
+#ifndef HAVE_FTRUNCATE
+#define HAVE_FTRUNCATE 1
+#endif
+#ifndef HAVE_FUTIMES
+#define HAVE_FUTIMES 1
+#endif
+#ifndef HAVE_UTIMES
+#define HAVE_UTIMES 1
+#endif
+#ifndef HAVE_LINK
+#define HAVE_LINK 1
+#endif
+
+/* Replacement POSIX function */
+extern int __la_chdir(const char *path);
+extern int __la_chmod(const char *path, mode_t mode);
+extern int __la_fcntl(int fd, int cmd, int val);
+extern int __la_fstat(int fd, struct stat *st);
+extern int __la_ftruncate(int fd, off_t length);
+extern int __la_futimes(int fd, const struct __timeval *times);
+extern int __la_link(const char *src, const char *dst);
+extern __int64 __la_lseek(int fd, __int64 offset, int whence);
+extern size_t __la_mbstowcs(wchar_t *wcstr, const char *mbstr, size_t nwchars);
+extern int __la_mkdir(const char *path, mode_t mode);
+extern int __la_open(const char *path, int flags, ...);
+extern ssize_t __la_read(int fd, void *buf, size_t nbytes);
+extern int __la_rmdir(const char *path);
+extern int __la_stat(const char *path, struct stat *st);
+extern int __la_unlink(const char *path);
+extern int __la_utimes(const char *name, const struct __timeval *times);
+extern pid_t __la_waitpid(pid_t wpid, int *status, int option);
+extern ssize_t __la_write(int fd, const void *buf, size_t nbytes);
+
+#define _stat64i32(path, st) __la_stat(path, st)
+#define _stat64(path, st) __la_stat(path, st)
+/* for status returned by la_waitpid */
+#define WIFEXITED(sts) ((sts & 0x100) == 0)
+#define WEXITSTATUS(sts) (sts & 0x0FF)
+
+/* Message digest function */
+#if !defined(HAVE_OPENSSL_MD5_H) && !defined(HAVE_OPENSSL_SHA_H)
+#ifdef MD5_DIGEST_LENGTH
+extern void MD5_Init(Digest_CTX *ctx);
+extern void MD5_Update(Digest_CTX *ctx, const unsigned char *buf,
+ size_t len);
+extern void MD5_Final(unsigned char *buf, Digest_CTX *ctx);
+#endif
+#ifdef SHA1_DIGEST_LENGTH
+extern void SHA1_Init(Digest_CTX *ctx);
+extern void SHA1_Update(Digest_CTX *ctx, const unsigned char *buf,
+ size_t len);
+extern void SHA1_Final(unsigned char *buf, Digest_CTX *ctx);
+#endif
+#ifdef SHA256_DIGEST_LENGTH
+extern void SHA256_Init(Digest_CTX *ctx);
+extern void SHA256_Update(Digest_CTX *ctx, const unsigned char *buf,
+ size_t len);
+extern void SHA256_Final(unsigned char *buf, Digest_CTX *ctx);
+#endif
+#ifdef SHA384_DIGEST_LENGTH
+extern void SHA384_Init(Digest_CTX *ctx);
+extern void SHA384_Update(Digest_CTX *ctx, const unsigned char *buf,
+ size_t len);
+extern void SHA384_Final(unsigned char *buf, Digest_CTX *ctx);
+#endif
+#ifdef SHA512_DIGEST_LENGTH
+extern void SHA512_Init(Digest_CTX *ctx);
+extern void SHA512_Update(Digest_CTX *ctx, const unsigned char *buf,
+ size_t len);
+extern void SHA512_Final(unsigned char *buf, Digest_CTX *ctx);
+#endif
+#endif
+
+#endif /* LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED */
diff --git a/src/mac/meandmyshadow/archive/archive_write_disk_private.h b/src/mac/meandmyshadow/archive/archive_write_disk_private.h
new file mode 100644
index 0000000..707c0cf
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_write_disk_private.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_write_disk_private.h 201086 2009-12-28 02:17:53Z kientzle $
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
+#define ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
+
+struct archive_write_disk;
+
+#endif
diff --git a/src/mac/meandmyshadow/archive/archive_write_private.h b/src/mac/meandmyshadow/archive/archive_write_private.h
new file mode 100644
index 0000000..f9b6565
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/archive_write_private.h
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_write_private.h 201155 2009-12-29 05:20:12Z kientzle $
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_WRITE_PRIVATE_H_INCLUDED
+#define ARCHIVE_WRITE_PRIVATE_H_INCLUDED
+
+#include "archive.h"
+#include "archive_string.h"
+#include "archive_private.h"
+
+struct archive_write {
+ struct archive archive;
+
+ /* Dev/ino of the archive being written. */
+ dev_t skip_file_dev;
+ int64_t skip_file_ino;
+
+ /* Utility: Pointer to a block of nulls. */
+ const unsigned char *nulls;
+ size_t null_length;
+
+ /* Callbacks to open/read/write/close archive stream. */
+ archive_open_callback *client_opener;
+ archive_write_callback *client_writer;
+ archive_close_callback *client_closer;
+ void *client_data;
+
+ /*
+ * Blocking information. Note that bytes_in_last_block is
+ * misleadingly named; I should find a better name. These
+ * control the final output from all compressors, including
+ * compression_none.
+ */
+ int bytes_per_block;
+ int bytes_in_last_block;
+
+ /*
+ * These control whether data within a gzip/bzip2 compressed
+ * stream gets padded or not. If pad_uncompressed is set,
+ * the data will be padded to a full block before being
+ * compressed. The pad_uncompressed_byte determines the value
+ * that will be used for padding. Note that these have no
+ * effect on compression "none."
+ */
+ int pad_uncompressed;
+ int pad_uncompressed_byte; /* TODO: Support this. */
+
+ /*
+ * On write, the client just invokes an archive_write_set function
+ * which sets up the data here directly.
+ */
+ struct {
+ void *data;
+ void *config;
+ int (*init)(struct archive_write *);
+ int (*options)(struct archive_write *,
+ const char *key, const char *value);
+ int (*finish)(struct archive_write *);
+ int (*write)(struct archive_write *, const void *, size_t);
+ } compressor;
+
+ /*
+ * Pointers to format-specific functions for writing. They're
+ * initialized by archive_write_set_format_XXX() calls.
+ */
+ void *format_data;
+ const char *format_name;
+ int (*format_init)(struct archive_write *);
+ int (*format_options)(struct archive_write *,
+ const char *key, const char *value);
+ int (*format_finish)(struct archive_write *);
+ int (*format_destroy)(struct archive_write *);
+ int (*format_finish_entry)(struct archive_write *);
+ int (*format_write_header)(struct archive_write *,
+ struct archive_entry *);
+ ssize_t (*format_write_data)(struct archive_write *,
+ const void *buff, size_t);
+};
+
+/*
+ * Utility function to format a USTAR header into a buffer. If
+ * "strict" is set, this tries to create the absolutely most portable
+ * version of a ustar header. If "strict" is set to 0, then it will
+ * relax certain requirements.
+ *
+ * Generally, format-specific declarations don't belong in this
+ * header; this is a rare example of a function that is shared by
+ * two very similar formats (ustar and pax).
+ */
+int
+__archive_write_format_header_ustar(struct archive_write *, char buff[512],
+ struct archive_entry *, int tartype, int strict);
+
+#endif
diff --git a/src/mac/meandmyshadow/archive/config_freebsd.h b/src/mac/meandmyshadow/archive/config_freebsd.h
new file mode 100644
index 0000000..fad4087
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/config_freebsd.h
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/config_freebsd.h 201079 2009-12-28 02:01:42Z kientzle $
+ */
+
+/* FreeBSD 5.0 and later have ACL and extattr support. */
+#if __FreeBSD__ > 4
+#define HAVE_ACL_CREATE_ENTRY 1
+#define HAVE_ACL_GET_LINK_NP 1
+#define HAVE_ACL_GET_PERM_NP 1
+#define HAVE_ACL_INIT 1
+#define HAVE_ACL_SET_FD 1
+#define HAVE_ACL_SET_FD_NP 1
+#define HAVE_ACL_SET_FILE 1
+#define HAVE_ACL_USER 1
+#define HAVE_EXTATTR_GET_FILE 1
+#define HAVE_EXTATTR_LIST_FILE 1
+#define HAVE_EXTATTR_SET_FD 1
+#define HAVE_EXTATTR_SET_FILE 1
+#define HAVE_SYS_ACL_H 1
+#define HAVE_SYS_EXTATTR_H 1
+#endif
+
+#ifdef WITH_OPENSSL
+#define HAVE_OPENSSL_MD5_H 1
+#define HAVE_OPENSSL_RIPEMD_H 1
+#define HAVE_OPENSSL_SHA_H 1
+#define HAVE_SHA384 1
+#define HAVE_SHA512 1
+#endif
+
+#define HAVE_BSDXML_H 1
+#define HAVE_BZLIB_H 1
+#define HAVE_CHFLAGS 1
+#define HAVE_CHOWN 1
+#define HAVE_DECL_INT64_MAX 1
+#define HAVE_DECL_INT64_MIN 1
+#define HAVE_DECL_SIZE_MAX 1
+#define HAVE_DECL_SSIZE_MAX 1
+#define HAVE_DECL_STRERROR_R 1
+#define HAVE_DECL_UINT32_MAX 1
+#define HAVE_DECL_UINT64_MAX 1
+#define HAVE_DIRENT_H 1
+#define HAVE_EFTYPE 1
+#define HAVE_EILSEQ 1
+#define HAVE_ERRNO_H 1
+#define HAVE_FCHDIR 1
+#define HAVE_FCHFLAGS 1
+#define HAVE_FCHMOD 1
+#define HAVE_FCHOWN 1
+#define HAVE_FCNTL 1
+#define HAVE_FCNTL_H 1
+#define HAVE_FSEEKO 1
+#define HAVE_FSTAT 1
+#define HAVE_FTRUNCATE 1
+#define HAVE_FUTIMES 1
+#define HAVE_GETEUID 1
+#define HAVE_GETPID 1
+#define HAVE_GRP_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_LCHFLAGS 1
+#define HAVE_LCHMOD 1
+#define HAVE_LCHOWN 1
+#define HAVE_LIMITS_H 1
+#define HAVE_LINK 1
+#define HAVE_LSTAT 1
+#define HAVE_LUTIMES 1
+#define HAVE_MALLOC 1
+#define HAVE_MD5 1
+#define HAVE_MD5_H 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MKDIR 1
+#define HAVE_MKFIFO 1
+#define HAVE_MKNOD 1
+#define HAVE_PIPE 1
+#define HAVE_POLL 1
+#define HAVE_POLL_H 1
+#define HAVE_PWD_H 1
+#define HAVE_READLINK 1
+#define HAVE_RMD160 1
+#define HAVE_SELECT 1
+#define HAVE_SETENV 1
+#define HAVE_SHA_H 1
+#define HAVE_SHA1 1
+#define HAVE_SHA256 1
+#define HAVE_SHA256_H 1
+#define HAVE_SIGNAL_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRCHR 1
+#define HAVE_STRDUP 1
+#define HAVE_STRERROR 1
+#define HAVE_STRERROR_R 1
+#define HAVE_STRINGS_H 1
+#define HAVE_STRING_H 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
+#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1
+#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1
+#define HAVE_STRUCT_STAT_ST_FLAGS 1
+#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
+#define HAVE_SYMLINK 1
+#define HAVE_SYS_CDEFS_H 1
+#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SYS_SELECT_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TYPES_H 1
+#undef HAVE_SYS_UTIME_H
+#define HAVE_SYS_WAIT_H 1
+#define HAVE_TIMEGM 1
+#define HAVE_TZSET 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UNSETENV 1
+#define HAVE_UTIME 1
+#define HAVE_UTIMES 1
+#define HAVE_UTIME_H 1
+#define HAVE_VFORK 1
+#define HAVE_WCHAR_H 1
+#define HAVE_WCSCPY 1
+#define HAVE_WCSLEN 1
+#define HAVE_WCTOMB 1
+#define HAVE_WMEMCMP 1
+#define HAVE_WMEMCPY 1
+#define HAVE_ZLIB_H 1
+#define TIME_WITH_SYS_TIME 1
+
+/* FreeBSD 4 and earlier lack intmax_t/uintmax_t */
+#if __FreeBSD__ < 5
+#define intmax_t int64_t
+#define uintmax_t uint64_t
+#endif
diff --git a/src/mac/meandmyshadow/archive/filter_fork.h b/src/mac/meandmyshadow/archive/filter_fork.h
new file mode 100644
index 0000000..453d032
--- /dev/null
+++ b/src/mac/meandmyshadow/archive/filter_fork.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/filter_fork.h 201087 2009-12-28 02:18:26Z kientzle $
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef FILTER_FORK_H
+#define FILTER_FORK_H
+
+pid_t
+__archive_create_child(const char *path, int *child_stdin, int *child_stdout);
+
+void
+__archive_check_child(int in, int out);
+
+#endif
diff --git a/src/mac/meandmyshadow/en.lproj/InfoPlist.strings b/src/mac/meandmyshadow/en.lproj/InfoPlist.strings
new file mode 100644
index 0000000..477b28f
--- /dev/null
+++ b/src/mac/meandmyshadow/en.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+/* Localized versions of Info.plist keys */
+
diff --git a/src/mac/meandmyshadow/meandmyshadow-Info.plist b/src/mac/meandmyshadow/meandmyshadow-Info.plist
new file mode 100644
index 0000000..502ae6f
--- /dev/null
+++ b/src/mac/meandmyshadow/meandmyshadow-Info.plist
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>Me &amp; My Shadow</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>meandmyshadow.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>net.sourceforge.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>0.5</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSApplicationCategoryType</key>
+ <string>public.app-category.puzzle-games</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>GPL v3</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/src/mac/meandmyshadow/meandmyshadow-Prefix.pch b/src/mac/meandmyshadow/meandmyshadow-Prefix.pch
new file mode 100644
index 0000000..907f284
--- /dev/null
+++ b/src/mac/meandmyshadow/meandmyshadow-Prefix.pch
@@ -0,0 +1,7 @@
+//
+// Prefix header for all source files of the 'meandmyshadow' target in the 'meandmyshadow' project
+//
+
+#ifdef __OBJC__
+ #import <Cocoa/Cocoa.h>
+#endif
diff --git a/src/mac/meandmyshadow/osx_helpers.mm b/src/mac/meandmyshadow/osx_helpers.mm
new file mode 100644
index 0000000..4e43b2a
--- /dev/null
+++ b/src/mac/meandmyshadow/osx_helpers.mm
@@ -0,0 +1,11 @@
+//
+// osx_helpers.m
+// meandmyshadow
+//
+#include <string>
+#import <CoreFoundation/CoreFoundation.h>
+
+std::string get_data_path () {
+ NSBundle* myBundle = [NSBundle mainBundle];
+ return std::string([[myBundle resourcePath] UTF8String])+"/data/";
+}
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Sat, May 16, 4:36 PM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
64179
Default Alt Text
(543 KB)

Event Timeline