Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
59 KB
Referenced Files
None
Subscribers
None
diff --git a/data/gfx/actions.png b/data/gfx/actions.png
index 4abc820..b41bb51 100644
Binary files a/data/gfx/actions.png and b/data/gfx/actions.png differ
diff --git a/data/gfx/menu/credits.png b/data/gfx/menu/credits.png
index f55c100..7466f65 100644
Binary files a/data/gfx/menu/credits.png and b/data/gfx/menu/credits.png differ
diff --git a/data/gfx/menu/statistics.png b/data/gfx/menu/statistics.png
index f9908e2..277c2a5 100644
Binary files a/data/gfx/menu/statistics.png and b/data/gfx/menu/statistics.png differ
diff --git a/data/gfx/time.png b/data/gfx/time.png
index 9d008c1..a92d087 100644
Binary files a/data/gfx/time.png and b/data/gfx/time.png differ
diff --git a/data/themes/Cloudscape/background.png b/data/themes/Cloudscape/background.png
deleted file mode 100644
index f06e0d4..0000000
Binary files a/data/themes/Cloudscape/background.png and /dev/null differ
diff --git a/data/themes/Cloudscape/deathleft.png b/data/themes/Cloudscape/characters/deathleft.png
similarity index 100%
rename from data/themes/Cloudscape/deathleft.png
rename to data/themes/Cloudscape/characters/deathleft.png
diff --git a/data/themes/Cloudscape/deathright.png b/data/themes/Cloudscape/characters/deathright.png
similarity index 100%
rename from data/themes/Cloudscape/deathright.png
rename to data/themes/Cloudscape/characters/deathright.png
diff --git a/data/themes/Cloudscape/line.png b/data/themes/Cloudscape/characters/line.png
similarity index 100%
rename from data/themes/Cloudscape/line.png
rename to data/themes/Cloudscape/characters/line.png
diff --git a/data/themes/Cloudscape/player.png b/data/themes/Cloudscape/characters/player.png
similarity index 100%
rename from data/themes/Cloudscape/player.png
rename to data/themes/Cloudscape/characters/player.png
diff --git a/data/themes/Cloudscape/characters/shadow.png b/data/themes/Cloudscape/characters/shadow.png
new file mode 100644
index 0000000..0d10d4d
Binary files /dev/null and b/data/themes/Cloudscape/characters/shadow.png differ
diff --git a/data/themes/Cloudscape/shadowdeathleft.png b/data/themes/Cloudscape/characters/shadowdeathleft.png
similarity index 84%
rename from data/themes/Cloudscape/shadowdeathleft.png
rename to data/themes/Cloudscape/characters/shadowdeathleft.png
index 0ce4150..5182ef0 100644
Binary files a/data/themes/Cloudscape/shadowdeathleft.png and b/data/themes/Cloudscape/characters/shadowdeathleft.png differ
diff --git a/data/themes/Cloudscape/shadowdeathright.png b/data/themes/Cloudscape/characters/shadowdeathright.png
similarity index 66%
rename from data/themes/Cloudscape/shadowdeathright.png
rename to data/themes/Cloudscape/characters/shadowdeathright.png
index d838a95..767d261 100644
Binary files a/data/themes/Cloudscape/shadowdeathright.png and b/data/themes/Cloudscape/characters/shadowdeathright.png differ
diff --git a/data/themes/Cloudscape/shadow.png b/data/themes/Cloudscape/shadow.png
deleted file mode 100644
index 720e518..0000000
Binary files a/data/themes/Cloudscape/shadow.png and /dev/null differ
diff --git a/data/themes/Cloudscape/theme.mnmstheme b/data/themes/Cloudscape/theme.mnmstheme
index ed54fc7..801934d 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.png,0,0,50,50)
+ editorPicture(tiles/tiles.png,0,0,50,50)
blockState(default){
object{
- picture(tiles.png,0,0,50,50)
- optionalPicture(tiles.png,50,0,50,50,0.15)
- optionalPicture(tiles.png,100,0,50,50,0.15)
+ 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.png,0,50,50,50)
+ editorPicture(tiles/tiles.png,0,50,50,50)
blockState(default){
object{
- picture(tiles.png,0,50,50,50)
+ picture(tiles/tiles.png,0,50,50,50)
}
}
}
character(Player){
characterState(standleft){
object{
- picture(player.png,115,0,23,40)
+ picture(characters/player.png,115,0,23,40)
}
}
characterState(standright){
object{
- picture(player.png,0,0,23,40)
+ picture(characters/player.png,0,0,23,40)
}
}
characterState(walkleft){
object{
animation=20,0
- pictureAnimation(player.png){
+ pictureAnimation(characters/player.png){
point(138,0,23,40,1,5)
point(230,0,23,40,4,5)
}
}
}
characterState(walkright){
object{
animation=20,0
- pictureAnimation(player.png){
+ pictureAnimation(characters/player.png){
point(23,0,23,40,1,5)
point(115,0,23,40,4,5)
}
}
}
characterState(jumpleft){
object{
- picture(player.png,276,0,23,40)
+ picture(characters/player.png,276,0,23,40)
}
}
characterState(fallleft){
object{
- picture(player.png,299,0,23,40)
+ picture(characters/player.png,299,0,23,40)
}
}
characterState(jumpright){
object{
- picture(player.png,230,0,23,40)
+ picture(characters/player.png,230,0,23,40)
}
}
characterState(fallright){
object{
- picture(player.png,253,0,23,40)
+ picture(characters/player.png,253,0,23,40)
}
}
characterState(holding){
object{
- picture(player.png,322,0,23,40)
+ picture(characters/player.png,322,0,23,40)
}
}
characterState(line){
object{
- picture(line.png,0,0,5,5)
+ picture(characters/line.png,0,0,5,5)
}
}
characterState(dieright){
oneTimeAnimation=8,dead
object{
offset(0,-14)
animation=8,0
- pictureAnimation(deathright.png){
+ pictureAnimation(characters/deathright.png){
point(0,0,23,54,1,2)
point(92,0,23,54,4,2)
}
}
}
characterState(dieleft){
oneTimeAnimation=8,dead
object{
offset(0,-14)
animation=8,0
- pictureAnimation(deathleft.png){
+ pictureAnimation(characters/deathleft.png){
point(0,0,23,54,1,2)
point(92,0,23,54,4,2)
}
}
}
characterState(dead){
object{
- picture(player.png,0,0,23,40)
+ picture(characters/player.png,0,0,23,40)
invisibleAtRunTime=1
}
}
}
character(Shadow){
characterState(standleft){
object{
- picture(shadow.png,115,0,23,40)
+ picture(characters/shadow.png,115,0,23,40)
}
}
characterState(standright){
object{
- picture(shadow.png,0,0,23,40)
+ picture(characters/shadow.png,0,0,23,40)
}
}
characterState(walkleft){
object{
animation=20,0
- pictureAnimation(shadow.png){
+ pictureAnimation(characters/shadow.png){
point(138,0,23,40,1,5)
point(230,0,23,40,4,5)
}
}
}
characterState(walkright){
object{
animation=20,0
- pictureAnimation(shadow.png){
+ pictureAnimation(characters/shadow.png){
point(23,0,23,40,1,5)
point(115,0,23,40,4,5)
}
}
}
characterState(jumpleft){
object{
- picture(shadow.png,276,0,23,40)
+ picture(characters/shadow.png,276,0,23,40)
}
}
characterState(fallleft){
object{
- picture(shadow.png,299,0,23,40)
+ picture(characters/shadow.png,299,0,23,40)
}
}
characterState(jumpright){
object{
- picture(shadow.png,230,0,23,40)
+ picture(characters/shadow.png,230,0,23,40)
}
}
characterState(fallright){
object{
- picture(shadow.png,253,0,23,40)
+ picture(characters/shadow.png,253,0,23,40)
}
}
characterState(holding){
object{
- picture(shadow.png,322,0,23,40)
+ picture(characters/shadow.png,322,0,23,40)
}
}
characterState(line){
object{
- picture(line.png,0,0,5,5)
+ picture(characters/line.png,0,0,5,5)
}
}
characterState(dieright){
oneTimeAnimation=8,dead
object{
offset(0,-14)
animation=8,0
- pictureAnimation(shadowdeathright.png){
+ pictureAnimation(characters/shadowdeathright.png){
point(0,0,23,54,1,2)
point(92,0,23,54,4,2)
}
}
}
characterState(dieleft){
oneTimeAnimation=8,dead
object{
offset(0,-14)
animation=8,0
- pictureAnimation(shadowdeathleft.png){
+ pictureAnimation(characters/shadowdeathleft.png){
point(0,0,23,54,1,2)
point(92,0,23,54,4,2)
}
}
}
characterState(dead){
object{
- picture(player.png,0,0,23,40)
+ picture(characters/player.png,0,0,23,40)
invisibleAtRunTime=1
}
}
}
block(Fragile){
- editorPicture(tiles.png,150,0,50,50)
+ editorPicture(tiles/tiles.png,150,0,50,50)
blockState(default){
object{
- picture(tiles.png,150,0,50,50)
+ picture(tiles/tiles.png,150,0,50,50)
}
}
transitionState(default,fragile1){
oneTimeAnimation=20,fragile1
object{
oneTimeAnimation=20,6
- pictureAnimation(tiles.png){
+ pictureAnimation(tiles/tiles.png){
point(200,0,50,50,1,5)
point(250,0,50,50,1,5)
}
}
}
blockState(fragile1){
object{
- picture(tiles.png,250,0,50,50)
+ picture(tiles/tiles.png,250,0,50,50)
}
}
transitionState(fragile1,fragile2){
oneTimeAnimation=20,fragile2
object{
oneTimeAnimation=20,6
- pictureAnimation(tiles.png){
+ pictureAnimation(tiles/tiles.png){
point(300,0,50,50,1,5)
point(350,0,50,50,1,5)
}
}
}
blockState(fragile2){
object{
- picture(tiles.png,350,0,50,50)
+ picture(tiles/tiles.png,350,0,50,50)
}
}
blockState(fragile3){
oneTimeAnimation=6,fragile3_1
object{
animation=20,0
- pictureAnimation(tiles.png){
+ pictureAnimation(tiles/tiles.png){
point(150,50,50,100,1,2)
point(250,50,50,100,2,2)
}
}
}
blockState(fragile3_1){
object{
- picture(tiles.png,250,50,50,100)
+ picture(tiles/tiles.png,250,50,50,100)
invisibleAtRunTime=1
}
}
}
block(MovingBlock){
- editorPicture(tiles.png,350,200,50,50)
+ editorPicture(tiles/tiles.png,350,200,50,50)
blockState(default){
object{
- picture(tiles.png,0,0,50,50)
- optionalPicture(tiles.png,50,0,50,50,0.15)
- optionalPicture(tiles.png,100,0,50,50,0.15)
- editorPicture(tiles.png,350,200,50,50)
+ 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.png,300,200,50,50)
+ editorPicture(tiles/tiles.png,300,200,50,50)
blockState(default){
object{
- picture(tiles.png,0,50,50,50)
- editorPicture(tiles.png,300,200,50,50)
+ picture(tiles/tiles.png,0,50,50,50)
+ editorPicture(tiles/tiles.png,300,200,50,50)
}
}
}
block(Exit){
- editorPicture(tiles.png,150,200,50,50)
+ editorPicture(tiles/tiles.png,150,200,50,50)
blockState(default){
object{
- picture(tiles.png,150,200,50,50)
+ picture(tiles/tiles.png,150,200,50,50)
}
}
blockState(closed){
object{
- picture(tiles.png,0,200,50,50)
+ picture(tiles/tiles.png,0,200,50,50)
}
}
transitionState(closed,default){
oneTimeAnimation=6,open
object{
animation=80,0
- pictureAnimation(tiles.png){
+ pictureAnimation(tiles/tiles.png){
point(50,200,50,50,1,2)
point(150,200,50,50,2,2)
}
}
}
}
block(Spikes){
- editorPicture(tiles.png,450,0,50,50)
+ editorPicture(tiles/tiles.png,450,0,50,50)
blockState(default){
object{
- picture(tiles.png,450,0,50,50)
- optionalPicture(tiles.png,450,50,50,50,0.5)
+ picture(tiles/tiles.png,450,0,50,50)
+ optionalPicture(tiles/tiles.png,450,50,50,50,0.5)
}
}
}
block(MovingSpikes){
- editorPicture(tiles.png,400,200,50,50)
+ editorPicture(tiles/tiles.png,400,200,50,50)
blockState(default){
object{
- editorPicture(tiles.png,400,200,50,50)
- picture(tiles.png,450,0,50,50)
- optionalPicture(tiles.png,450,50,50,50,0.5)
+ 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.png,50,50,50,50)
+ editorPicture(tiles/tiles.png,50,50,50,50)
blockState(default){
object{
- picture(tiles.png,50,50,50,50)
+ picture(tiles/tiles.png,50,50,50,50)
}
}
blockState(activated){
object{
animation=16,0
- picture(tiles.png,100,50,50,50)
+ 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(swap.png,0,0,50,50)
+ editorPicture(tiles/swap.png,0,0,50,50)
blockState(default){
object{
- picture(swap.png,0,0,50,50)
+ picture(tiles/swap.png,0,0,50,50)
}
}
blockState(activated){
oneTimeAnimation=24,default
object{
animation=12,0
- pictureAnimation(swap.png){
+ pictureAnimation(tiles/swap.png){
point(0,0,50,50)
point(600,0,50,50,12,1)
}
}
}
}
block(Teleporter){
- editorPicture(tiles.png,300,50,50,50)
+ editorPicture(tiles/tiles.png,300,50,50,50)
blockState(default){
object{
- picture(tiles.png,300,50,50,50)
+ picture(tiles/tiles.png,300,50,50,50)
}
}
blockState(activated){
oneTimeAnimation=9,default
object{
animation=3,0
- pictureAnimation(tiles.png){
+ pictureAnimation(tiles/tiles.png){
point(300,50,50,50)
point(450,50,50,50,3,1)
}
}
}
}
block(Switch){
- editorPicture(tiles.png,0,100,50,50)
+ editorPicture(tiles/tiles.png,0,100,50,50)
blockState(default){
object{
- picture(tiles.png,0,100,50,50)
+ picture(tiles/tiles.png,0,100,50,50)
}
}
transitionState(default,activated){
oneTimeAnimation=3,activated
object{
animation=3,0
- pictureAnimation(tiles.png){
+ pictureAnimation(tiles/tiles.png){
point(0,100,50,50)
point(150,100,50,50,3,1)
}
}
}
blockState(activated){
object{
- picture(tiles.png,100,100,50,50)
+ picture(tiles/tiles.png,100,100,50,50)
}
}
transitionState(activated,default){
oneTimeAnimation=3,default
object{
animation=3,0
- pictureAnimation(tiles.png){
+ pictureAnimation(tiles/tiles.png){
point(100,100,50,50)
point(-50,100,50,50,3,1)
}
}
}
}
block(Button){
- editorPicture(tiles.png,450,200,50,50)
+ editorPicture(tiles/tiles.png,450,200,50,50)
blockState(default){
object{
- picture(tiles.png,0,0,50,50)
- optionalPicture(tiles.png,50,0,50,50,0.15)
- optionalPicture(tiles.png,100,0,50,50,0.15)
+ 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){
object{
# TODO:
- picture(tiles.png,300,100,50,16)
+ picture(tiles/tiles.png,300,100,50,16)
}
}
}
block(NotificationBlock){
- editorPicture(tiles.png,350,100,50,50)
+ editorPicture(tiles/tiles.png,350,100,50,50)
blockState(default){
object{
- picture(tiles.png,350,100,50,50)
+ picture(tiles/tiles.png,350,100,50,50)
}
}
}
block(ConveyorBelt){
- editorPicture(tiles.png,450,100,50,50)
+ editorPicture(tiles/tiles.png,450,100,50,50)
blockState(default){
object{
- picture(tiles.png,450,100,50,50)
- editorPicture(tiles.png,450,100,50,50)
+ picture(tiles/tiles.png,450,100,50,50)
+ editorPicture(tiles/tiles.png,450,100,50,50)
}
}
}
block(ShadowConveyorBelt){
- editorPicture(tiles.png,400,100,50,50)
+ editorPicture(tiles/tiles.png,400,100,50,50)
blockState(default){
object{
- picture(tiles.png,400,100,50,50)
+ picture(tiles/tiles.png,400,100,50,50)
}
}
}
block(PlayerStart){
- editorPicture(tiles.png,250,200,50,50)
+ editorPicture(tiles/tiles.png,250,200,50,50)
blockState(default){
object{
- picture(tiles.png,250,200,50,50)
+ picture(tiles/tiles.png,250,200,50,50)
invisibleAtRunTime=1
}
}
}
block(ShadowStart){
- editorPicture(tiles.png,200,200,50,50)
+ editorPicture(tiles/tiles.png,200,200,50,50)
blockState(default){
object{
- picture(tiles.png,200,200,50,50)
+ picture(tiles/tiles.png,200,200,50,50)
invisibleAtRunTime=1
}
}
}
block(Collectable){
- editorPicture(collectable.png,0,0,50,50)
+ editorPicture(tiles/collectable.png,0,0,50,50)
blockState(inactive){
object{
}
}
blockState(default){
object{
- picture(collectable.png,0,0,50,50)
+ picture(tiles/collectable.png,0,0,50,50)
}
}
}
block(Pushable){
- editorPicture(tiles.png,350,200,50,50)
+ editorPicture(tiles/tiles.png,350,200,50,50)
blockState(default){
object{
- picture(tiles.png,350,200,50,50)
- editorPicture(tiles.png,350,200,50,50)
+ picture(tiles/tiles.png,350,200,50,50)
+ editorPicture(tiles/tiles.png,350,200,50,50)
}
}
}
diff --git a/data/themes/Cloudscape/collectable.png b/data/themes/Cloudscape/tiles/collectable.png
similarity index 100%
rename from data/themes/Cloudscape/collectable.png
rename to data/themes/Cloudscape/tiles/collectable.png
diff --git a/data/themes/Cloudscape/tiles/scenery.png b/data/themes/Cloudscape/tiles/scenery.png
new file mode 100644
index 0000000..681ab6e
Binary files /dev/null and b/data/themes/Cloudscape/tiles/scenery.png differ
diff --git a/data/themes/Cloudscape/swap.png b/data/themes/Cloudscape/tiles/swap.png
similarity index 100%
rename from data/themes/Cloudscape/swap.png
rename to data/themes/Cloudscape/tiles/swap.png
diff --git a/data/themes/Cloudscape/tiles.png b/data/themes/Cloudscape/tiles/tiles.png
similarity index 100%
rename from data/themes/Cloudscape/tiles.png
rename to data/themes/Cloudscape/tiles/tiles.png
diff --git a/src/AchievementList.h b/src/AchievementList.h
index ed6e856..d5e2c59 100644
--- a/src/AchievementList.h
+++ b/src/AchievementList.h
@@ -1,104 +1,104 @@
/*
* Copyright (C) 2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
// Note: This is an internal file for all avaliable achievements.
// Don't include it in other files!
// Format: {id, name, file, pos, description, [type]}
// id: Identifier of achievement. Should not change once the new achievement is added,
// otherwise the old statistics will be lost.
// name: Name of achievement. Translatable.
// file: The icon file. NULL for no icon.
// pos: Specifies which part of the icon will be displayed (left, top, width, height).
// description: Description of achievement. Translatable. Can be multi-line text.
// type [optional]: Specifies the display type of achievement.
// ACHIEVEMENT_HIDDEN [default]: Show "Unknown achievement" when unfinished.
// ACHIEVEMENT_TITLE: Only show icon and title when unfinished.
// ACHIEVEMENT_ALL: Always show icon, title and description.
// ACHIEVEMENT_PROGRESS: Show icon, title and description and a progress bar.
// StatisticsManager::getAchievementProgress() function should return the progress (between 0 and 1).
AchievementInfo achievementList[]={
- {"newbie",__("Newbie"),"themes/Cloudscape/player.png",{0,0,23,40},__("Complete a level."),ACHIEVEMENT_ALL},
- {"experienced",__("Experienced player"),"themes/Cloudscape/player.png",{0,0,23,40},__("Complete 50 levels."),ACHIEVEMENT_PROGRESS},
+ {"newbie",__("Newbie"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Complete a level."),ACHIEVEMENT_ALL},
+ {"experienced",__("Experienced player"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Complete 50 levels."),ACHIEVEMENT_PROGRESS},
{"goodjob",__("Good job!"),"gfx/medals.png",{60,0,30,30},__("Receive a gold medal."),ACHIEVEMENT_ALL},
{"expert",__("Expert"),"gfx/medals.png",{60,0,30,30},__("Earn 50 gold medal."),ACHIEVEMENT_PROGRESS},
{"tutorial",__("Graduate"),"gfx/medals.png",{60,0,30,30},__("Complete the tutorial level pack."),ACHIEVEMENT_PROGRESS},
{"tutorialGold",__("Outstanding graduate"),"gfx/medals.png",{60,0,30,30},__("Complete the tutorial level pack with gold for all levels."),ACHIEVEMENT_PROGRESS},
- {"addicted",__("Hooked"),"themes/Cloudscape/player.png",{0,0,23,40},__("Play Me and My Shadow for more than 2 hours.")},
- {"loyalFan",__("Loyal fan of Me and My Shadow"),"themes/Cloudscape/player.png",{0,0,23,40},__("Play Me and My Shadow for more than 24 hours.")},
+ {"addicted",__("Hooked"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Play Me and My Shadow for more than 2 hours.")},
+ {"loyalFan",__("Loyal fan of Me and My Shadow"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Play Me and My Shadow for more than 24 hours.")},
{"constructor",__("Constructor"),"gfx/gui.png",{112,16,16,16},__("Use the level editor for more than 2 hours.")},
{"constructor2",__("The creator"),"gfx/gui.png",{112,16,16,16},__("Use the level editor for more than 24 hours.")},
{"create1",__("Look, cute level!"),"gfx/gui.png",{112,16,16,16},__("Create a level for the first time."),ACHIEVEMENT_ALL},
{"create50",__("The level museum"),"gfx/gui.png",{112,16,16,16},__("Create 50 levels."),ACHIEVEMENT_PROGRESS},
- {"frog",__("Frog"),"themes/Cloudscape/player.png",{0,0,23,40},__("Jump 1000 times."),ACHIEVEMENT_PROGRESS},
+ {"frog",__("Frog"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Jump 1000 times."),ACHIEVEMENT_PROGRESS},
- {"travel100",__("Wanderer"),"themes/Cloudscape/player.png",{0,0,23,40},__("Travel 100 meters."),ACHIEVEMENT_PROGRESS},
- {"travel1k",__("Runner"),"themes/Cloudscape/player.png",{0,0,23,40},__("Travel 1 kilometer."),ACHIEVEMENT_PROGRESS},
- {"travel10k",__("Long distance runner"),"themes/Cloudscape/player.png",{0,0,23,40},__("Travel 10 kilometers."),ACHIEVEMENT_PROGRESS},
- {"travel42k",__("Marathon runner"),"themes/Cloudscape/player.png",{0,0,23,40},__("Travel 42,195 meters."),ACHIEVEMENT_PROGRESS},
+ {"travel100",__("Wanderer"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Travel 100 meters."),ACHIEVEMENT_PROGRESS},
+ {"travel1k",__("Runner"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Travel 1 kilometer."),ACHIEVEMENT_PROGRESS},
+ {"travel10k",__("Long distance runner"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Travel 10 kilometers."),ACHIEVEMENT_PROGRESS},
+ {"travel42k",__("Marathon runner"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Travel 42,195 meters."),ACHIEVEMENT_PROGRESS},
- {"die1",__("Be careful!"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Die for the first time."),ACHIEVEMENT_ALL},
- {"die50",__("It doesn't matter..."),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Die 50 times.")},
- {"die1000",__("Expert of trial and error"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Die 1000 times.")},
+ {"die1",__("Be careful!"),"themes/Cloudscape/characters/deathright.png",{0,14,23,40},__("Die for the first time."),ACHIEVEMENT_ALL},
+ {"die50",__("It doesn't matter..."),"themes/Cloudscape/characters/deathright.png",{0,14,23,40},__("Die 50 times.")},
+ {"die1000",__("Expert of trial and error"),"themes/Cloudscape/characters/deathright.png",{0,14,23,40},__("Die 1000 times.")},
- {"squash1",__("Keep an eye for moving blocks!"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Get squashed for the first time.")},
- {"squash50",__("Potato masher"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Get squashed 50 times.")},
+ {"squash1",__("Keep an eye for moving blocks!"),"themes/Cloudscape/characters/deathright.png",{0,14,23,40},__("Get squashed for the first time.")},
+ {"squash50",__("Potato masher"),"themes/Cloudscape/characters/deathright.png",{0,14,23,40},__("Get squashed 50 times.")},
- {"doubleKill",__("Double kill"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Get both the player and the shadow dead.")},
+ {"doubleKill",__("Double kill"),"themes/Cloudscape/characters/deathright.png",{0,14,23,40},__("Get both the player and the shadow dead.")},
- {"die5in5",__("Bad luck"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Die 5 times in under 5 seconds.")},
- {"die10in5",__("This level is too dangerous"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Die 10 times in under 5 seconds.")},
+ {"die5in5",__("Bad luck"),"themes/Cloudscape/characters/deathright.png",{0,14,23,40},__("Die 5 times in under 5 seconds.")},
+ {"die10in5",__("This level is too dangerous"),"themes/Cloudscape/characters/deathright.png",{0,14,23,40},__("Die 10 times in under 5 seconds.")},
- {"forget",__("You forgot your friend"),"themes/Cloudscape/player.png",{0,0,23,40},__("Finish the level with the player or the shadow dead.")},
- {"jit",__("Just in time"),"themes/Cloudscape/player.png",{0,0,23,40},__("Reach the exit with the player and the shadow simultaneously.")},
+ {"forget",__("You forgot your friend"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Finish the level with the player or the shadow dead.")},
+ {"jit",__("Just in time"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Reach the exit with the player and the shadow simultaneously.")},
- {"record100",__("Recorder"),"themes/Cloudscape/player.png",{0,0,23,40},__("Record 100 times."),ACHIEVEMENT_PROGRESS},
+ {"record100",__("Recorder"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Record 100 times."),ACHIEVEMENT_PROGRESS},
{"record1k",__("Shadowmaster"),"themes/Cloudscape/shadow.png",{0,0,23,40},__("Record 1000 times."),ACHIEVEMENT_PROGRESS},
- {"switch100",__("Switch puller"),"themes/Cloudscape/player.png",{0,0,23,40},__("Pull the switch 100 times."),ACHIEVEMENT_PROGRESS},
- {"switch1k",__("The switch is broken!"),"themes/Cloudscape/player.png",{0,0,23,40},__("Pull the switch 1000 times.")},
+ {"switch100",__("Switch puller"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Pull the switch 100 times."),ACHIEVEMENT_PROGRESS},
+ {"switch1k",__("The switch is broken!"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Pull the switch 1000 times.")},
- {"swap100",__("Swapper"),"themes/Cloudscape/player.png",{0,0,23,40},__("Swap 100 times."),ACHIEVEMENT_PROGRESS},
- {"swap1k",__("Player to shadow to player to shadow..."),"themes/Cloudscape/player.png",{0,0,23,40},__("Swap 1000 times.")},
+ {"swap100",__("Swapper"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Swap 100 times."),ACHIEVEMENT_PROGRESS},
+ {"swap1k",__("Player to shadow to player to shadow..."),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Swap 1000 times.")},
- {"save1k",__("Play it save"),"themes/Cloudscape/player.png",{0,0,23,40},__("Save 1000 times.")},
- {"load1k",__("This game is too hard"),"themes/Cloudscape/player.png",{0,0,23,40},__("Load the game 1000 times.")},
+ {"save1k",__("Play it save"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Save 1000 times.")},
+ {"load1k",__("This game is too hard"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Load the game 1000 times.")},
- {"panicSave",__("Panic save"),"themes/Cloudscape/player.png",{0,0,23,40},__("Save twice in 1 second.")},
- {"panicLoad",__("Panic load"),"themes/Cloudscape/player.png",{0,0,23,40},__("Load twice in 1 second.")},
+ {"panicSave",__("Panic save"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Save twice in 1 second.")},
+ {"panicLoad",__("Panic load"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Load twice in 1 second.")},
- {"loadAndDie",__("Bad saving position"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Load the game and die within 1 second.")},
- {"loadAndDie100",__("This level is too hard"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Load the same save and die 100 times.")},
+ {"loadAndDie",__("Bad saving position"),"themes/Cloudscape/characters/deathright.png",{0,14,23,40},__("Load the game and die within 1 second.")},
+ {"loadAndDie100",__("This level is too hard"),"themes/Cloudscape/characters/deathright.png",{0,14,23,40},__("Load the same save and die 100 times.")},
- {"quickswap",__("Quick swap"),"themes/Cloudscape/player.png",{0,0,23,40},__("Swap twice in under a second.")},
+ {"quickswap",__("Quick swap"),"themes/Cloudscape/characters/player.png",{0,0,23,40},__("Swap twice in under a second.")},
//ripped from Achievements Unlocked
{"horizontal",__("Horizontal confusion"),"gfx/emotions.png",{0,0,23,40},__("Press left and right simultaneously.")},
{"programmer",__("Programmer"),"gfx/gui.png",{112,16,16,16},__("Play the development version of Me and My Shadow."),ACHIEVEMENT_TITLE},
//end of achievements
{}
};
diff --git a/src/ThemeManager.cpp b/src/ThemeManager.cpp
index e8ea0a4..bc81118 100644
--- a/src/ThemeManager.cpp
+++ b/src/ThemeManager.cpp
@@ -1,1012 +1,1012 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ThemeManager.h"
#include "POASerializer.h"
#include "Functions.h"
#include "FileManager.h"
#include "Game.h"
#ifdef __APPLE__
#include <SDL_gfx/SDL_rotozoom.h>
#else
#include <SDL/SDL_rotozoom.h>
#endif
#include <string.h>
#include <iostream>
using namespace std;
//The ThemeStack that is be used by the GameState.
ThemeStack objThemes;
bool ThemeManager::loadFile(const string& fileName){
POASerializer objSerializer;
TreeStorageNode objNode;
//First we destroy the current ThemeManager.
destroy();
//Now we try to load the file, if it fails we return false.
if(!objSerializer.loadNodeFromFile(fileName.c_str(),&objNode,true)){
cerr<<"ERROR: Unable to open theme file: "<<fileName<<endl;
return false;
}
//Set the themePath.
themePath=pathFromFileName(fileName);
//Retrieve the name of the theme from the file.
{
vector<string> &v=objNode.attributes["name"];
if(!v.empty()) themeName=v[0];
}
//Reset themeable colors to default
themeTextColor.r=themeTextColor.g=themeTextColor.b=0;
themeTextColorDialog.r=themeTextColorDialog.g=themeTextColorDialog.b=0;
//Read themeable colors if any
vector<string> &ct=objNode.attributes["textColor"];
if(!ct.empty()){
themeTextColor.r=atoi(ct[0].c_str());
themeTextColor.g=atoi(ct[1].c_str());
themeTextColor.b=atoi(ct[2].c_str());
}
vector<string> &ct2=objNode.attributes["textColorDialog"];
if(!ct2.empty()){
themeTextColorDialog.r=atoi(ct2[0].c_str());
themeTextColorDialog.g=atoi(ct2[1].c_str());
themeTextColorDialog.b=atoi(ct2[2].c_str());
}
//Loop the subnodes of the theme.
for(unsigned int i=0;i<objNode.subNodes.size();i++){
TreeStorageNode *obj=objNode.subNodes[i];
//Check if it's a block or a background.
if(obj->name=="block" && !obj->value.empty()){
map<string,int>::iterator it=Game::blockNameMap.find(obj->value[0]);
if(it!=Game::blockNameMap.end()){
int idx=it->second;
if(!objBlocks[idx]) objBlocks[idx]=new ThemeBlock;
if(!objBlocks[idx]->loadFromNode(obj,themePath)){
cerr<<"ERROR: Unable to load "<<Game::blockName[idx]<<" for theme "<<fileName<<endl;
delete objBlocks[idx];
objBlocks[idx]=NULL;
return false;
}
}
}else if(obj->name=="background" && !obj->value.empty()){
if(!objBackground) objBackground=new ThemeBackground();
if(!objBackground->addPictureFromNode(obj,themePath)){
cerr<<"ERROR: Unable to load background for theme "<<fileName<<endl;
delete objBackground;
objBackground=NULL;
return false;
}
}else if(obj->name=="character" && !obj->value.empty()){
if(obj->value[0]=="Shadow"){
if(!shadow) shadow=new ThemeCharacter();
if(!shadow->loadFromNode(obj,themePath)){
cerr<<"ERROR: Unable to load shadow for theme "<<fileName<<endl;
delete shadow;
shadow=NULL;
return false;
}
}else if(obj->value[0]=="Player"){
if(!player) player=new ThemeCharacter();
if(!player->loadFromNode(obj,themePath)){
cerr<<"ERROR: Unable to load player for theme "<<fileName<<endl;
delete player;
player=NULL;
return false;
}
}
}else if(obj->name=="menuBackground" && !obj->value.empty()){
if(!menuBackground) menuBackground=new ThemeBackground();
if(!menuBackground->addPictureFromNode(obj,themePath)){
cerr<<"ERROR: Unable to load background for theme "<<fileName<<endl;
delete menuBackground;
menuBackground=NULL;
return false;
}
}else if(obj->name=="menu" && obj->value[0]=="Block"){
if(!menuBlock) menuBlock=new ThemeBlock;
if(!menuBlock->loadFromNode(obj,themePath)){
cerr<<"ERROR: Unable to load menu block for theme "<<fileName<<endl;
delete menuBlock;
menuBlock=NULL;
return false;
}
}
}
//Done and nothing went wrong so return true.
return true;
}
bool ThemeBlock::loadFromNode(TreeStorageNode* objNode, string themePath){
destroy();
//Loop the subNodes.
for(unsigned int i=0;i<objNode->subNodes.size();i++){
TreeStorageNode *obj=objNode->subNodes[i];
//Check if the subnode is an editorPicture or a blockState.
if(obj->name=="editorPicture"){
if(!editorPicture.loadFromNode(obj,themePath)) return false;
}else if(obj->name=="blockState" && !obj->value.empty()){
string& s=obj->value[0];
map<string,ThemeBlockState*>::iterator it=blockStates.find(s);
if(it==blockStates.end()) blockStates[s]=new ThemeBlockState;
if(!blockStates[s]->loadFromNode(obj,themePath)) return false;
}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 teh picture.
+ //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.
//isShadow: Boolean if it's the shadow
//Returns: Pointer to the ThemeCharacter.
ThemeCharacter* ThemeStack::getCharacter(bool isShadow){
//Loop through the themes from top to bottom.
for(int i=objThemes.size()-1;i>=0;i--){
//Get the ThemeCharacter from the theme.
ThemeCharacter* obj=objThemes[i]->getCharacter(isShadow);
//Check if it isn't null.
if(obj)
return obj;
}
//Nothing found.
return NULL;
}
//Get a pointer to the ThemeBackground of the theme.
//Returns: Pointer to the ThemeBackground.
ThemeBackground* ThemeStack::getBackground(bool menu){
//Loop through the themes from top to bottom.
for(int i=objThemes.size()-1;i>=0;i--){
//Get the ThemeBackground from the theme.
ThemeBackground* obj=objThemes[i]->getBackground(menu);
//Check if it isn't null.
if(obj)
return obj;
}
//Nothing found.
return NULL;
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 12:40 AM (2 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
72431
Default Alt Text
(59 KB)

Event Timeline