Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F118555
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
95 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
R79 meandmyshadow
Attached
Detach File
Event Timeline