MSTE - MegaStorm Tile-based Engine  v1.10
 All Classes Functions Groups Pages
Example04_Custom.cpp
logotipo_mste.png

/**

/*----------------------------------------------
MegaStorm Tile-based Engine - Roberto Prieto
Copyright (C) 2007-2012 MegaStorm Systems
----------------------------------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Roberto Prieto
contact@megastormsystems.com
http://www.megastormsystems.com
Note that all library licenses (including the one for this library)
are located at /licenses directory. Please, include them on your applications.
--------------------------------------------------------------------------
How to use MSTE. Example 4: Custom map
-------------------------------------------------
- This example loads the MSM created by the previous example.
- Add our custom map to layer 0
- Before exit, the whole level including the custom map is saved to a MSM file.
- Basic functions:
Cursor keys Up/Down: for moving through the level.
'p': pause/restore the movement
'c': get the the cell position on layer 1 of current mouse cursor
's': enable/disable the smooth scroll rendering
'a': enable/disable autoscrolling feature on X axis
*/
// ---Includes---
#include "CRM32Pro.h"
#include "../source/MSTE.h"
#include "../source/MSTE_MapData.h"
// ---Defines---
#define EXAMPLE_VERSION "MSTE - Example04: Custom map"
// ---Global vars---
cMSTE *TE;
// ---Declaration of our custom map, derivated from cMSTE_MapBase---
class cMyCustomMap : public cMSTE_MapBase
{
public:
// Mandatory methods
// 1.1.Constructor
cMyCustomMap(int height,int width);
// 1.2.Method to be used by our maps factory to create an instance of this class
static cMSTE_MapBase *createInstance(int y,int x);
// Optional methods
// 2.1.Destructor
~cMyCustomMap();
// 2.2.My custom methods
int PrintInfo(char,int);
int SaveMapdataNode(int,int);
int LoadMapdataNode(int,int);
int CheckMap();
int CellRender(int map_x, int map_y, int surf_x, int surf_y, cMSTE *TE,int iOpacity);
public:
// Dynamic 2D array for my custom map
unsigned int **iCustomMap;
int iW, iH;
};
// ---Prototypes---
void RenderGraphics(int);
// -------------MAIN FUNCTION----------------
int main(int argc,char *argv[])
{
Uint8 done = 0;
SDL_Event event;
// -Log system initialize-
ILogSystem.Init("Example04_Custom.log",LOG_FILE,LOG_NORMAL,EXAMPLE_VERSION);
// -CRM32Pro and SDL initialize-
if(CRM32Pro.Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) < 0)
{
ILogSystem.Msg(LOG_NORMAL," [LOG] - Couldn't initialize CRM32Pro: %s\n",SDL_GetError());
return 1;
}
// -Desired config-
CRM32Pro.Config.Title = EXAMPLE_VERSION;
CRM32Pro.Config.VideoWidth = 640;
CRM32Pro.Config.VideoHeight = 400;
CRM32Pro.Config.bMTFriendly = 1;
// -Graphics system initialize-
if(!CRM32Pro.SetVideoMode())
{
CRM32Pro.Quit();
return 1;
}
// -Timer system-
ITimeSystem->Init();
ITimeSystem->SetRate(60,20);
CRM32Pro.SetRenderCallback(RenderGraphics);
// -Init scroll engine-
TE = new cMSTE;
TE->Init(2);
TE->SetRenderTarget(CRM32Pro.screen);
// -Load our previous saved level-
TE->LoadLevel("mylevel.msm");
// -Register our custom map-
// We add it to layer 0
cMyCustomMap *myMap;
if(TE->RegisterMapDataHandler(&cMyCustomMap::createInstance))
{
// Match the mapdata base size
myMap = new cMyCustomMap(TE->GetLayerMapData(0)->GetMapHeight(),TE->GetLayerMapData(0)->GetMapWidth());
// Cells with 10 will not render anything (this is what our custom map does! xD )
myMap->iCustomMap[2][2] = 10;
myMap->iCustomMap[3][3] = 10;
myMap->iCustomMap[4][4] = 10;
myMap->iCustomMap[5][5] = 10;
myMap->iCustomMap[6][6] = 10;
myMap->iCustomMap[7][7] = 10;
if(TE->AddCustomMapData(0,myMap) == 0) delete myMap;
}
// -Main loop-
int iPause = -1;
int iSmooth = -1;
int iAutoMoveFlag = -1;
while(!done)
{
// Update all layers
TE->Update();
// Main system update and events loop
while(CRM32Pro.Update(&event))
{
switch(event.type)
{
case SDL_QUIT:
done = 1;
break;
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_ESCAPE) done = 1;
if(event.key.keysym.sym == SDLK_c)
{
int iCX,iCY;
iCX = iCY = -1;
TE->Screen2LayerCell(1,CRM32Pro.mouse_x,CRM32Pro.mouse_y,&iCX,&iCY);
ILogSystem.Msg(LOG_NORMAL," [Screen2LayerCell(1) => (%d,%d)\n",iCX,iCY);
TE->Screen2LayerAbsolute(1,CRM32Pro.mouse_x,CRM32Pro.mouse_y,&iCX,&iCY);
ILogSystem.Msg(LOG_NORMAL," [Screen2LayerAbsolute(1) => (%d,%d)\n",iCX,iCY);
}
if(event.key.keysym.sym == SDLK_p)
{
iPause = iPause * (-1);
}
if(event.key.keysym.sym == SDLK_s)
{
iSmooth = iSmooth * (-1);
}
if(event.key.keysym.sym == SDLK_a)
{
iAutoMoveFlag = iAutoMoveFlag * (-1);
TE->SetLayerFlags(0,TE_LAYERFLAG_AUTOSCROLL,iAutoMoveFlag);
TE->SetLayerFlags(1,TE_LAYERFLAG_AUTOSCROLL,iAutoMoveFlag);
}
break;
default:
break;
}
}
if(CRM32Pro.GetKeystate(SDLK_UP)) TE->MoveLayer(1,0,-4);
if(CRM32Pro.GetKeystate(SDLK_DOWN)) TE->MoveLayer(1,0,4);
}
// -Save the level including our custom map-
// Now, you could load this custom map, just remember to register
// your custom map class before to try to load it
TE->SaveLevel("mylevel-custom.msm");
// -Free resources-
TE->InfoPrint();
TE->Quit();
delete TE;
// -End-
ITimeSystem->Info();
CRM32Pro.VideoInfo();
CRM32Pro.Quit();
return 0;
}
// ---Our render graphics function---
// We render our graphics if a logic frame occurred(bLogicUpdate = 1) or if CRM32Pro.IsRenderNeeded() return 1
void RenderGraphics(int bLogicUpdate)
{
TE->Render();
}
// ---Definition our custom map, derivated from cMapBase---
// Constructor: we have to call to base class constructor (MANDATORY)
cMyCustomMap::cMyCustomMap(int height,int width) : cMSTE_MapBase(height,width)
{
iW = width; iH = height;
if(iW > 0 && iH > 0)
{
iCustomMap = Create2DArray<unsigned int>(height,width);
// Loop filling our custom map with a default value
for(int y = 0; y < iH; y++)
for(int x = 0; x < iW; x++) iCustomMap[y][x] = 5;
}
else iCustomMap = NULL;
// Assign a new map type name
strcpy(sMapType,"MyMap");
}
// Method to be used by our maps factory to create an instance of this class (MANDATORY)
cMSTE_MapBase *cMyCustomMap::createInstance(int y,int x)
{
// Create an instance of this class.
return new cMyCustomMap(y,x);
}
// Destructor (OPTIONAL)
cMyCustomMap::~cMyCustomMap()
{
if(iCustomMap != NULL) Delete2DArray(iCustomMap);
iW = iH = 0;
iCustomMap = NULL;
}
// Update the given cell (OPTIONAL)
int cMyCustomMap::CellRender(int map_x, int map_y, int surf_x, int surf_y, cMSTE *TE, int iOpacity)
{
// Check our custom map first, if there is a value != 10, we proceed to update the cell of mapbase (render the tile)
if(iCustomMap[map_y][map_x] != 10)
cMSTE_MapBase::CellRender(map_x,map_y,surf_x,surf_y,TE,iOpacity);
return 1;
}
// Map validation (OPTIONAL)
int cMyCustomMap::CheckMap()
{
int iRet = 1;
unsigned int iMax;
// Check the base map
//if(cMSTE_MapBase::CheckMap() == 0) return 0;
// Previous check
if(iCustomMap == NULL) return 0;
if(iW == 0) return 0;
if(iH == 0) return 0;
iMax = 20;
// Loop through iCustomMap
for(int i = 0; i < iH; i++)
for(int j = 0; j < iW; j++)
{
if(iCustomMap[i][j] < 5)
{
ILogSystem.Msg(LOG_NORMAL," · [MyCustomMap] Warning: map[%d][%d] has a wrong value of %d.\n",i,j,iCustomMap[i][j]);
iRet = 0;
}
else if(iCustomMap[i][j] > iMax)
{
ILogSystem.Msg(LOG_NORMAL," · [MyCustomMap] Warning: map[%d][%d] has a wrong value of %d.\n",i,j,iCustomMap[i][j]);
iRet = 0;
}
}
// Return
return iRet;
}
// My custom PrintInfo
int cMyCustomMap::PrintInfo(char bTilesetReady, int iLogLevel)
{
// 1.First of all, call to mapbase info
cMSTE_MapBase::PrintInfo(bTilesetReady,iLogLevel);
// 2.Now print our custom info
ILogSystem.Msg(LOG_NORMAL," . Map type '%s' - Custom map size %dx%d\n",sMapType,iW,iH);
return 1;
}
// My custom SaveMapdataNode
int cMyCustomMap::SaveMapdataNode(int idXML, int iOutput)
{
char *szTmp = NULL;
int retvalue = 0;
// 1.Get our CSV string
retvalue = A2DtoCSV(iCustomMap,iW,iH,szTmp);
// 2.Select our type
switch(iOutput)
{
// TMX output
case 1:
// A1.Save first mapdata attributes as a data tag does not support properties tag (as of Tiled 0.81)
retvalue = CRM32Pro.XMLNodeChild(idXML); // Go back to "properties" block
retvalue = WriteTMXProperty(idXML,"custom-type",sMapType);
retvalue = WriteTMXProperty(idXML,"custom-width",iW);
retvalue = WriteTMXProperty(idXML,"custom-height",iH);
retvalue = WriteTMXProperty(idXML,"custom-data",szTmp);
CRM32Pro.XMLNodeParent(idXML); // Exit from "properties" block
// A2.Now, call to export base mapdata
break;
// MSM output
default:
case 0:
// B1.First of all, save the mapbase node
// B2.Now save our custom mapdata. These two fields are mandatory.
retvalue = CRM32Pro.XMLNodeCreate(idXML,"mapdata"); // Create a new node and point to it.
retvalue = CRM32Pro.XMLAttributeSet(idXML,"type",sMapType);
// B3.And finally, save our custom attributes
retvalue = CRM32Pro.XMLAttributeSet(idXML,"width",iW);
retvalue = CRM32Pro.XMLAttributeSet(idXML,"height",iH);
// B4.Save our CSV string
CRM32Pro.XMLTextSet(idXML,szTmp);
break;
}
// 3.Point back and return
if(szTmp != NULL) { delete []szTmp; szTmp = NULL; }
CRM32Pro.XMLNodeParent(idXML); // To our layer
return retvalue;
}
// My custom LoadMapdataNode
// idXML is pointing inside a mapdata/data subnode
int cMyCustomMap::LoadMapdataNode(int idXML, int iInput)
{
char *szTmp = NULL;
// 1.Select our type
switch(iInput)
{
// TMX input
case 1:
// First of all, load the mapbase node as we are on the data subnode
// Save current position and look for <properties>
CRM32Pro.XMLNodeStore(idXML); // save node pointer
CRM32Pro.XMLNodeParent(idXML); // go back to layer node
CRM32Pro.XMLNodeChild(idXML); // go to the first child
do
{
// Is it a properties node?
if(!strcmp(CRM32Pro.XMLNodeGetName(idXML),"properties"))
{
// Try to load our special layer properties
if(!ReadTMXProperty(idXML,"custom-width",&iW)) return 0;
if(!ReadTMXProperty(idXML,"custom-height",&iH)) return 0;
if(!ReadTMXProperty(idXML,"custom-data",&szTmp)) return 0;
}
} while(CRM32Pro.XMLNodeNext(idXML)); // next layer subnode
CRM32Pro.XMLNodeRestore(idXML); // restore node pointer
break;
// MSM input
default:
case 0:
// The mapbase is loaded on the LoadLevel() method
// Get attributes
if(!CRM32Pro.XMLAttributeGet(idXML,"width",&iW)) return 0;
if(!CRM32Pro.XMLAttributeGet(idXML,"height",&iH)) return 0;
// Some validations
if(iW <=0 || iH <= 0) return 0;
// B2.Create the iCustomMap and load the data
szTmp = CRM32Pro.XMLTextGet(idXML);
break;
}
// 2.Try to process de custom data
if(szTmp == NULL) return 0;
if(iCustomMap != NULL) delete []iCustomMap;
iCustomMap = Create2DArray<unsigned int>(iH,iW);
if(CSVtoA2D(iCustomMap,iW,iH,szTmp)) return 1;
// 3.End
return 0;
}