Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
95 KB
Referenced Files
None
Subscribers
None
diff --git a/data/themes/Cloudscape/theme.mnmstheme b/data/themes/Cloudscape/theme.mnmstheme
index 801934d..b3b94fa 100644
--- a/data/themes/Cloudscape/theme.mnmstheme
+++ b/data/themes/Cloudscape/theme.mnmstheme
@@ -1,484 +1,484 @@
name="Cloudscape"
background(background.png){
repeat=0,0
}
block(Block){
editorPicture(tiles/tiles.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,0,0,50,50)
optionalPicture(tiles/tiles.png,50,0,50,50,0.15)
optionalPicture(tiles/tiles.png,100,0,50,50,0.15)
}
}
}
block(ShadowBlock){
editorPicture(tiles/tiles.png,0,50,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,0,50,50,50)
}
}
}
character(Player){
- characterState(standleft){
+ state(standleft){
object{
picture(characters/player.png,115,0,23,40)
}
}
- characterState(standright){
+ state(standright){
object{
picture(characters/player.png,0,0,23,40)
}
}
- characterState(walkleft){
+ state(walkleft){
object{
animation=20,0
pictureAnimation(characters/player.png){
point(138,0,23,40,1,5)
point(230,0,23,40,4,5)
}
}
}
- characterState(walkright){
+ state(walkright){
object{
animation=20,0
pictureAnimation(characters/player.png){
point(23,0,23,40,1,5)
point(115,0,23,40,4,5)
}
}
}
- characterState(jumpleft){
+ state(jumpleft){
object{
picture(characters/player.png,276,0,23,40)
}
}
- characterState(fallleft){
+ state(fallleft){
object{
picture(characters/player.png,299,0,23,40)
}
}
- characterState(jumpright){
+ state(jumpright){
object{
picture(characters/player.png,230,0,23,40)
}
}
- characterState(fallright){
+ state(fallright){
object{
picture(characters/player.png,253,0,23,40)
}
}
- characterState(holding){
+ state(holding){
object{
picture(characters/player.png,322,0,23,40)
}
}
- characterState(line){
+ state(line){
object{
picture(characters/line.png,0,0,5,5)
}
}
- characterState(dieright){
+ state(dieright){
oneTimeAnimation=8,dead
object{
offset(0,-14)
animation=8,0
pictureAnimation(characters/deathright.png){
point(0,0,23,54,1,2)
point(92,0,23,54,4,2)
}
}
}
- characterState(dieleft){
+ state(dieleft){
oneTimeAnimation=8,dead
object{
offset(0,-14)
animation=8,0
pictureAnimation(characters/deathleft.png){
point(0,0,23,54,1,2)
point(92,0,23,54,4,2)
}
}
}
- characterState(dead){
+ state(dead){
object{
picture(characters/player.png,0,0,23,40)
invisibleAtRunTime=1
}
}
}
character(Shadow){
- characterState(standleft){
+ state(standleft){
object{
picture(characters/shadow.png,115,0,23,40)
}
}
- characterState(standright){
+ state(standright){
object{
picture(characters/shadow.png,0,0,23,40)
}
}
- characterState(walkleft){
+ state(walkleft){
object{
animation=20,0
pictureAnimation(characters/shadow.png){
point(138,0,23,40,1,5)
point(230,0,23,40,4,5)
}
}
}
- characterState(walkright){
+ state(walkright){
object{
animation=20,0
pictureAnimation(characters/shadow.png){
point(23,0,23,40,1,5)
point(115,0,23,40,4,5)
}
}
}
- characterState(jumpleft){
+ state(jumpleft){
object{
picture(characters/shadow.png,276,0,23,40)
}
}
- characterState(fallleft){
+ state(fallleft){
object{
picture(characters/shadow.png,299,0,23,40)
}
}
- characterState(jumpright){
+ state(jumpright){
object{
picture(characters/shadow.png,230,0,23,40)
}
}
- characterState(fallright){
+ state(fallright){
object{
picture(characters/shadow.png,253,0,23,40)
}
}
- characterState(holding){
+ state(holding){
object{
picture(characters/shadow.png,322,0,23,40)
}
}
- characterState(line){
+ state(line){
object{
picture(characters/line.png,0,0,5,5)
}
}
- characterState(dieright){
+ state(dieright){
oneTimeAnimation=8,dead
object{
offset(0,-14)
animation=8,0
pictureAnimation(characters/shadowdeathright.png){
point(0,0,23,54,1,2)
point(92,0,23,54,4,2)
}
}
}
- characterState(dieleft){
+ state(dieleft){
oneTimeAnimation=8,dead
object{
offset(0,-14)
animation=8,0
pictureAnimation(characters/shadowdeathleft.png){
point(0,0,23,54,1,2)
point(92,0,23,54,4,2)
}
}
}
- characterState(dead){
+ state(dead){
object{
picture(characters/player.png,0,0,23,40)
invisibleAtRunTime=1
}
}
}
block(Fragile){
editorPicture(tiles/tiles.png,150,0,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,150,0,50,50)
}
}
transitionState(default,fragile1){
oneTimeAnimation=20,fragile1
object{
oneTimeAnimation=20,6
pictureAnimation(tiles/tiles.png){
point(200,0,50,50,1,5)
point(250,0,50,50,1,5)
}
}
}
- blockState(fragile1){
+ state(fragile1){
object{
picture(tiles/tiles.png,250,0,50,50)
}
}
transitionState(fragile1,fragile2){
oneTimeAnimation=20,fragile2
object{
oneTimeAnimation=20,6
pictureAnimation(tiles/tiles.png){
point(300,0,50,50,1,5)
point(350,0,50,50,1,5)
}
}
}
- blockState(fragile2){
+ state(fragile2){
object{
picture(tiles/tiles.png,350,0,50,50)
}
}
- blockState(fragile3){
+ state(fragile3){
oneTimeAnimation=6,fragile3_1
object{
animation=20,0
pictureAnimation(tiles/tiles.png){
point(150,50,50,100,1,2)
point(250,50,50,100,2,2)
}
}
}
- blockState(fragile3_1){
+ state(fragile3_1){
object{
picture(tiles/tiles.png,250,50,50,100)
invisibleAtRunTime=1
}
}
}
block(MovingBlock){
editorPicture(tiles/tiles.png,350,200,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,0,0,50,50)
optionalPicture(tiles/tiles.png,50,0,50,50,0.15)
optionalPicture(tiles/tiles.png,100,0,50,50,0.15)
editorPicture(tiles/tiles.png,350,200,50,50)
}
}
}
block(MovingShadowBlock){
editorPicture(tiles/tiles.png,300,200,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,0,50,50,50)
editorPicture(tiles/tiles.png,300,200,50,50)
}
}
}
block(Exit){
editorPicture(tiles/tiles.png,150,200,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,150,200,50,50)
}
}
- blockState(closed){
+ state(closed){
object{
picture(tiles/tiles.png,0,200,50,50)
}
}
transitionState(closed,default){
oneTimeAnimation=6,open
object{
animation=80,0
pictureAnimation(tiles/tiles.png){
point(50,200,50,50,1,2)
point(150,200,50,50,2,2)
}
}
}
}
block(Spikes){
editorPicture(tiles/tiles.png,450,0,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,450,0,50,50)
optionalPicture(tiles/tiles.png,450,50,50,50,0.5)
}
}
}
block(MovingSpikes){
editorPicture(tiles/tiles.png,400,200,50,50)
- blockState(default){
+ state(default){
object{
editorPicture(tiles/tiles.png,400,200,50,50)
picture(tiles/tiles.png,450,0,50,50)
optionalPicture(tiles/tiles.png,450,50,50,50,0.5)
}
}
}
block(Checkpoint){
editorPicture(tiles/tiles.png,50,50,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,50,50,50,50)
}
}
- blockState(activated){
+ state(activated){
object{
animation=16,0
picture(tiles/tiles.png,100,50,50,50)
offsetAnimation{
point(0,0)
point(0,-4,4,1)
point(0,4,8,1)
point(0,0,4,1)
}
}
}
}
block(Swap){
editorPicture(tiles/swap.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/swap.png,0,0,50,50)
}
}
- blockState(activated){
+ state(activated){
oneTimeAnimation=24,default
object{
animation=12,0
pictureAnimation(tiles/swap.png){
point(0,0,50,50)
point(600,0,50,50,12,1)
}
}
}
}
block(Teleporter){
editorPicture(tiles/tiles.png,300,50,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,300,50,50,50)
}
}
- blockState(activated){
+ state(activated){
oneTimeAnimation=9,default
object{
animation=3,0
pictureAnimation(tiles/tiles.png){
point(300,50,50,50)
point(450,50,50,50,3,1)
}
}
}
}
block(Switch){
editorPicture(tiles/tiles.png,0,100,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,0,100,50,50)
}
}
transitionState(default,activated){
oneTimeAnimation=3,activated
object{
animation=3,0
pictureAnimation(tiles/tiles.png){
point(0,100,50,50)
point(150,100,50,50,3,1)
}
}
}
- blockState(activated){
+ state(activated){
object{
picture(tiles/tiles.png,100,100,50,50)
}
}
transitionState(activated,default){
oneTimeAnimation=3,default
object{
animation=3,0
pictureAnimation(tiles/tiles.png){
point(100,100,50,50)
point(-50,100,50,50,3,1)
}
}
}
}
block(Button){
editorPicture(tiles/tiles.png,450,200,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,0,0,50,50)
optionalPicture(tiles/tiles.png,50,0,50,50,0.15)
optionalPicture(tiles/tiles.png,100,0,50,50,0.15)
}
}
- blockState(button){
+ state(button){
object{
# TODO:
picture(tiles/tiles.png,300,100,50,16)
}
}
}
block(NotificationBlock){
editorPicture(tiles/tiles.png,350,100,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,350,100,50,50)
}
}
}
block(ConveyorBelt){
editorPicture(tiles/tiles.png,450,100,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,450,100,50,50)
editorPicture(tiles/tiles.png,450,100,50,50)
}
}
}
block(ShadowConveyorBelt){
editorPicture(tiles/tiles.png,400,100,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,400,100,50,50)
}
}
}
block(PlayerStart){
editorPicture(tiles/tiles.png,250,200,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,250,200,50,50)
invisibleAtRunTime=1
}
}
}
block(ShadowStart){
editorPicture(tiles/tiles.png,200,200,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,200,200,50,50)
invisibleAtRunTime=1
}
}
}
block(Collectable){
editorPicture(tiles/collectable.png,0,0,50,50)
- blockState(inactive){
+ state(inactive){
object{
}
}
- blockState(default){
+ state(default){
object{
picture(tiles/collectable.png,0,0,50,50)
}
}
}
block(Pushable){
editorPicture(tiles/tiles.png,350,200,50,50)
- blockState(default){
+ state(default){
object{
picture(tiles/tiles.png,350,200,50,50)
editorPicture(tiles/tiles.png,350,200,50,50)
}
}
}
diff --git a/data/themes/classic/theme.mnmstheme b/data/themes/classic/theme.mnmstheme
index 4786528..5d0cd43 100644
--- a/data/themes/classic/theme.mnmstheme
+++ b/data/themes/classic/theme.mnmstheme
@@ -1,379 +1,379 @@
name="Default Theme"
background(background.png){
cameraSpeed=0.2,0
}
block(Block){
editorPicture(blocks/block.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/block.png,0,0,50,50)
optionalPicture(blocks/block2.png,0,0,50,50,0.1)
optionalPicture(blocks/block3.png,0,0,50,50,0.1)
}
}
}
block(PlayerStart){
editorPicture(blocks/playerstart.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/playerstart.png,0,0,50,50)
invisibleAtRunTime=1
}
}
}
block(ShadowStart){
editorPicture(blocks/shadowstart.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/shadowstart.png,0,0,50,50)
invisibleAtRunTime=1
}
}
}
block(Exit){
editorPicture(blocks/exit.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/exit.png,0,0,50,50)
}
}
}
block(ShadowBlock){
editorPicture(blocks/shadowblock.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/shadowblock.png,0,0,50,50)
}
}
}
block(Spikes){
editorPicture(blocks/spikes.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/spikes.png,0,0,50,50)
}
}
}
block(Checkpoint){
editorPicture(blocks/checkpoint.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/checkpoint.png,0,0,50,50)
}
}
- blockState(activated){
+ state(activated){
object{
animation=16,0
picture(blocks/checkpoint.png,50,0,50,50)
offsetAnimation{
point(0,0)
point(0,-8,4,1)
point(0,8,8,1)
point(0,0,4,1)
}
}
}
}
block(Swap){
editorPicture(blocks/swap.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/swap.png,0,0,50,50)
}
}
- blockState(activated){
+ state(activated){
oneTimeAnimation=24,default
object{
animation=12,0
pictureAnimation(blocks/swap.png){
point(0,0,50,50)
point(600,0,50,50,12,1)
}
}
}
}
block(Fragile){
editorPicture(blocks/fragile.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/fragile.png,0,0,50,50)
}
}
- blockState(fragile1){
+ state(fragile1){
object{
picture(blocks/fragile.png,50,0,50,50)
}
}
- blockState(fragile2){
+ state(fragile2){
object{
picture(blocks/fragile.png,100,0,50,50)
}
}
- blockState(fragile3){
+ state(fragile3){
object{
picture(blocks/fragile.png,150,0,50,50)
invisibleAtRunTime=1
}
}
}
block(MovingBlock){
editorPicture(blocks/moving_block.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/block.png,0,0,50,50)
optionalPicture(blocks/block2.png,0,0,50,50,0.1)
optionalPicture(blocks/block3.png,0,0,50,50,0.1)
editorPicture(blocks/moving_block.png,0,0,50,50)
}
}
- blockState(base){
+ state(base){
object{
picture(blocks/moving_block.png,50,0,50,50)
invisibleAtRunTime=1
}
}
}
block(MovingShadowBlock){
editorPicture(blocks/moving_shadowblock.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/shadowblock.png,0,0,50,50)
editorPicture(blocks/moving_shadowblock.png,0,0,50,50)
}
}
- blockState(base){
+ state(base){
object{
picture(blocks/moving_shadowblock.png,50,0,50,50)
invisibleAtRunTime=1
}
}
}
block(MovingSpikes){
editorPicture(blocks/moving_spikes.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/spikes.png,0,0,50,50)
editorPicture(blocks/moving_spikes.png,0,0,50,50)
}
}
- blockState(base){
+ state(base){
object{
picture(blocks/moving_spikes.png,50,0,50,50)
invisibleAtRunTime=1
}
}
}
block(Teleporter){
editorPicture(blocks/portal.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/portal.png,0,0,50,50)
}
}
}
block(Button){
editorPicture(blocks/button.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/block.png,0,0,50,50)
optionalPicture(blocks/block2.png,0,0,50,50,0.1)
optionalPicture(blocks/block3.png,0,0,50,50,0.1)
}
}
- blockState(button){
+ state(button){
object{
# TODO:
picture(blocks/button.png,50,0,50,16)
}
}
}
block(Switch){
editorPicture(blocks/switch.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/switch.png,0,0,50,50)
}
}
- blockState(activated){
+ state(activated){
object{
picture(blocks/switch.png,50,0,50,50)
}
}
}
block(ConveyorBelt){
editorPicture(blocks/moving_block_2.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/block.png,0,0,50,50)
editorPicture(blocks/moving_block_2.png,0,0,50,50)
}
}
}
block(ShadowConveyorBelt){
editorPicture(blocks/moving_shadowblock_2.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/shadowblock.png,0,0,50,50)
editorPicture(blocks/moving_shadowblock_2.png,0,0,50,50)
}
}
}
block(NotificationBlock){
editorPicture(blocks/notification.png,0,0,50,50)
- blockState(default){
+ state(default){
object{
picture(blocks/notification.png,0,0,50,50)
}
}
}
character(Player){
- characterState(standleft){
+ state(standleft){
object{
picture(player/playerleft.png,23,0,23,40)
}
}
- characterState(standright){
+ state(standright){
object{
picture(player/playerright.png,23,0,23,40)
}
}
- characterState(walkleft){
+ state(walkleft){
object{
animation=20,0
pictureAnimation(player/playerleft.png){
point(0,0,23,40,1,10)
point(46,0,23,40,2,10)
}
}
}
- characterState(walkright){
+ state(walkright){
object{
animation=20,0
pictureAnimation(player/playerright.png){
point(0,0,23,40,1,10)
point(46,0,23,40,2,10)
}
}
}
- characterState(jumpleft){
+ state(jumpleft){
object{
picture(player/jumpleft.png,0,0,23,40)
}
}
- characterState(fallleft){
+ state(fallleft){
object{
picture(player/jumpleft.png,0,0,23,40)
}
}
- characterState(jumpright){
+ state(jumpright){
object{
picture(player/jumpright.png,0,0,23,40)
}
}
- characterState(fallright){
+ state(fallright){
object{
picture(player/jumpright.png,0,0,23,40)
}
}
- characterState(holding){
+ state(holding){
object{
picture(player/playerholdingright.png,0,0,23,40)
}
}
- characterState(line){
+ state(line){
object{
picture(player/line.png,0,0,5,5)
}
}
- characterState(dieright){
+ state(dieright){
object{
picture(player/playerright.png,23,0,23,40)
invisibleAtRunTime=1
}
}
- characterState(dieleft){
+ state(dieleft){
object{
picture(player/playerright.png,23,0,23,40)
invisibleAtRunTime=1
}
}
- characterState(dead){
+ state(dead){
object{
picture(player/playerright.png,23,0,23,40)
invisibleAtRunTime=1
}
}
}
character(Shadow){
- characterState(standleft){
+ state(standleft){
object{
picture(shadow/shadowleft.png,23,0,23,40)
}
}
- characterState(standright){
+ state(standright){
object{
picture(shadow/shadowright.png,23,0,23,40)
}
}
- characterState(walkleft){
+ state(walkleft){
object{
animation=20,0
pictureAnimation(shadow/shadowleft.png){
point(0,0,23,40,1,10)
point(46,0,23,40,2,10)
}
}
}
- characterState(walkright){
+ state(walkright){
object{
animation=20,0
pictureAnimation(shadow/shadowright.png){
point(0,0,23,40,1,10)
point(46,0,23,40,2,10)
}
}
}
- characterState(jumpleft){
+ state(jumpleft){
object{
picture(shadow/jumpleftshadow.png,0,0,23,40)
}
}
- characterState(fallleft){
+ state(fallleft){
object{
picture(shadow/jumpleftshadow.png,0,0,23,40)
}
}
- characterState(jumpright){
+ state(jumpright){
object{
picture(shadow/jumprightshadow.png,0,0,23,40)
}
}
- characterState(fallright){
+ state(fallright){
object{
picture(shadow/jumprightshadow.png,0,0,23,40)
}
}
- characterState(holding){
+ state(holding){
object{
picture(shadow/shadowholdingright.png,0,0,23,40)
}
}
- characterState(dieright){
+ state(dieright){
object{
picture(player/playerright.png,23,0,23,40)
invisibleAtRunTime=1
}
}
- characterState(dieleft){
+ state(dieleft){
object{
picture(player/playerright.png,23,0,23,40)
invisibleAtRunTime=1
}
}
- characterState(dead){
+ state(dead){
object{
picture(player/playerright.png,23,0,23,40)
invisibleAtRunTime=1
}
}
}
diff --git a/src/Player.h b/src/Player.h
index d836920..ce20517 100644
--- a/src/Player.h
+++ b/src/Player.h
@@ -1,268 +1,268 @@
/*
* 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.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 Block;
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 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.
Block* objCurrentStand;
//Pointer to the object the player stood last on.
//NOTE: This is a weak reference only.
Block* objLastStand;
//Pointer to the teleporter the player last took.
//NOTE: This is a weak reference only.
Block* objLastTeleport;
//Pointer to the notification block the player is in front of.
//This is always a valid pointer.
Block* objNotificationBlock;
//Pointer to the shadow block the player is in front of.
//This is always a valid pointer.
Block* objShadowBlock;
//The save variable for the GameObject pointers.
//FIXME: Also save the other game object pointers?
Block* objCurrentStandSave;
Block* objLastStandSave;
public:
//X and y location where the player starts and gets when reseted.
int fx, fy;
//The appearance of the player.
- ThemeCharacterInstance appearance;
+ ThemeBlockInstance 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 setLocation(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<Block*> &levelObjects);
//Method used to check if the player can jump and executes the jump.
//strength: The strength of the jump.
void jump(int strength=13);
//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;
}
//Method for returning the objCurrentStand pointer.
//Returns: Pointer to the gameobject the player is standing on.
inline Block* getObjCurrentStand(){
return objCurrentStand;
}
//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);
//Method that will handle the actual movement.
//levelObjects: Array containing the levelObjects, used to check collision.
void collision(std::vector<Block*> &levelObjects);
};
#endif
diff --git a/src/ThemeManager.cpp b/src/ThemeManager.cpp
index bc81118..c7ef4ed 100644
--- a/src/ThemeManager.cpp
+++ b/src/ThemeManager.cpp
@@ -1,1012 +1,887 @@
/*
* 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) shadow=new ThemeBlock();
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) player=new ThemeBlock();
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()){
+ //NOTE: blockState and characterState are for backwards compatability, use state instead.
+ }else if((obj->name=="blockState" || obj->name=="characterState" || obj->name=="state") && !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;
}else if(obj->name=="transitionState" && obj->value.size()==2){
pair<string,string> s=pair<string,string>(obj->value[0],obj->value[1]);
map<pair<string,string>,ThemeBlockState*>::iterator it=transitions.find(s);
if(it==transitions.end()) transitions[s]=new ThemeBlockState;
if(!transitions[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 the 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->transitions.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;
//Create the state instance.
createStateInstance(&obj1);
}
//Loop through the transitions.
for(map<pair<string,string>,ThemeBlockState*>::iterator it=transitions.begin();it!=transitions.end();++it){
//Get the themeBlockStateInstance of the given ThemeBlockInstance.
ThemeBlockStateInstance &obj1=obj->transitions[it->first];
//Set the parent of the state instance.
obj1.parent=it->second;
//Create the state instance.
createStateInstance(&obj1);
}
//Change the state to the default one.
//FIXME: Is that needed?
obj->changeState("default");
}
void ThemeBlock::createStateInstance(ThemeBlockStateInstance* obj){
//Get the vector with themeObjects.
vector<ThemeObject*> &v=obj->parent->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)
obj->objects.push_back(p);
}
}
-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.empty()){
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.
+//Get a pointer to the ThemeBlock of the shadow or the player.
//isShadow: Boolean if it's the shadow
-//Returns: Pointer to the ThemeCharacter.
-ThemeCharacter* ThemeStack::getCharacter(bool isShadow){
+//Returns: Pointer to the ThemeBlock.
+ThemeBlock* 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);
+ //Get the ThemeBlock from the theme.
+ ThemeBlock* 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 15dcc07..6efccf7 100644
--- a/src/ThemeManager.h
+++ b/src/ThemeManager.h
@@ -1,1108 +1,868 @@
/*
* 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;
//Map containing the blockTransitionStates.
map<pair<string,string>,ThemeBlockStateInstance> transitions;
//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){
bool newState=false;
//First check if there's a transition.
{
pair<string,string> s1=pair<string,string>(currentStateName,s);
map<pair<string,string>,ThemeBlockStateInstance>::iterator it=transitions.find(s1);
if(it!=transitions.end()){
currentState=&it->second;
//NOTE: We set the currentState name to target state name.
//Worst case senario is that the animation is skipped when saving/loading at a checkpoint.
currentStateName=s;
newState=true;
}
}
//If there isn't a transition go directly to the state.
if(!newState){
//Get the new state.
map<string,ThemeBlockStateInstance>::iterator it=blockStates.find(s);
//Check if it exists.
if(it!=blockStates.end()){
currentState=&it->second;
currentStateName=it->first;
newState=true;
}
}
//Check if a state has been found.
if(newState){
//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;
//Map containing the transition states between blocks states.
map<pair<string,string>,ThemeBlockState*> transitions;
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;
}
//Loop through the ThemeBlockStates and delete them,
for(map<pair<string,string>,ThemeBlockState*>::iterator i=transitions.begin();i!=transitions.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;
}
//Loop through the ThemeBlockStates transitions and delete them,
for(map<pair<string,string>,ThemeBlockState*>::iterator i=transitions.begin();i!=transitions.end();++i){
delete i->second;
}
//Clear the blockStates map.
blockStates.clear();
transitions.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);
private:
//Method that will create a ThemeBlockStateInstance.
//obj: Pointer that will be filled with the instance.
void createStateInstance(ThemeBlockStateInstance* 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.
+//The ThemeManager is actually a whole theme, filled with ThemeBlocks and ThemeBackground.
class ThemeManager{
private:
- //The ThemeCharacter of the shadow.
- ThemeCharacter* shadow;
- //The ThemeCharacter of the player.
- ThemeCharacter* player;
+ //The ThemeBlock of the shadow.
+ ThemeBlock* shadow;
+ //The ThemeBlock of the player.
+ ThemeBlock* 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.
+ //Delete the ThemeBlock of the shadow.
if(shadow)
delete shadow;
- //Delete the ThemeCharacter of the player.
+ //Delete the ThemeBlock 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.
+ //Delete the ThemeBlock of the shadow.
if(shadow)
delete shadow;
- //Delete the ThemeCharacter of the player.
+ //Delete the ThemeBlock 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.
+ //Get a pointer to the ThemeBlock of the shadow or the player.
//isShadow: Boolean if it's the shadow
- //Returns: Pointer to the ThemeCharacter.
- ThemeCharacter* getCharacter(bool isShadow){
+ //Returns: Pointer to the ThemeBlock.
+ ThemeBlock* 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.
+ //Get a pointer to the ThemeBlock of the shadow or the player.
//isShadow: Boolean if it's the shadow
- //Returns: Pointer to the ThemeCharacter.
- ThemeCharacter* getCharacter(bool isShadow);
+ //Returns: Pointer to the ThemeBlock.
+ ThemeBlock* 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

File Metadata

Mime Type
text/x-diff
Expires
Sat, May 16, 6:05 PM (1 d, 8 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
64183
Default Alt Text
(95 KB)

Event Timeline