Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial commit

  • Loading branch information...
commit 56e1c0606d47126b3f0fa50b9a94011dc3631948 0 parents
@micahflee micahflee authored
Showing with 5,674 additions and 0 deletions.
  1. +1 −0  .gitignore
  2. +79 −0 Classes/Achievements.h
  3. +118 −0 Classes/Achievements.m
  4. +37 −0 Classes/AchievementsScene.h
  5. +175 −0 Classes/AchievementsScene.m
  6. +28 −0 Classes/GameConfig.h
  7. +125 −0 Classes/GameData.h
  8. +557 −0 Classes/GameData.m
  9. +24 −0 Classes/GameDataKey.h
  10. +19 −0 Classes/GameDataKey.m
  11. +27 −0 Classes/GameMenuScene.h
  12. +135 −0 Classes/GameMenuScene.m
  13. +70 −0 Classes/GameScene.h
  14. +536 −0 Classes/GameScene.m
  15. +25 −0 Classes/GameTile.h
  16. +77 −0 Classes/GameTile.m
  17. +26 −0 Classes/Helpers.h
  18. +67 −0 Classes/Helpers.m
  19. +33 −0 Classes/InstructionsScene.h
  20. +150 −0 Classes/InstructionsScene.m
  21. +37 −0 Classes/Level.h
  22. +52 −0 Classes/Level.m
  23. +29 −0 Classes/Levels.h
  24. +99 −0 Classes/Levels.m
  25. +37 −0 Classes/MapScene.h
  26. +180 −0 Classes/MapScene.m
  27. +25 −0 Classes/MenuScene.h
  28. +96 −0 Classes/MenuScene.m
  29. +21 −0 Classes/NagScene.h
  30. +66 −0 Classes/NagScene.m
  31. +32 −0 Classes/Options.h
  32. +74 −0 Classes/Options.m
  33. +44 −0 Classes/OptionsScene.h
  34. +250 −0 Classes/OptionsScene.m
  35. +16 −0 Classes/RootViewController.h
  36. +152 −0 Classes/RootViewController.m
  37. +44 −0 Classes/SelectLevelScene.h
  38. +252 −0 Classes/SelectLevelScene.m
  39. +41 −0 Classes/SkeletonKeyAppDelegate.h
  40. +108 −0 Classes/SkeletonKeyAppDelegate.m
  41. +13 −0 Classes/SkeletonKeyWindow.h
  42. +26 −0 Classes/SkeletonKeyWindow.m
  43. +33 −0 Classes/Sound.h
  44. +98 −0 Classes/Sound.m
  45. BIN  Default.png
  46. BIN  Icon.png
  47. BIN  Icon@2x.png
  48. +23 −0 LICENSE.cocos2d
  49. +21 −0 LICENSE.cocosdenshion
  50. BIN  OtherFiles/graphics/Default.psd
  51. BIN  OtherFiles/graphics/Treasure Map.psd
  52. BIN  OtherFiles/graphics/achievements.psd
  53. BIN  OtherFiles/graphics/android_promo.psd
  54. BIN  OtherFiles/graphics/forest_background.psd
  55. BIN  OtherFiles/graphics/game.psd
  56. BIN  OtherFiles/graphics/game_backgrounds.psd
  57. BIN  OtherFiles/graphics/game_menu.psd
  58. BIN  OtherFiles/graphics/game_tiles.psd
  59. BIN  OtherFiles/graphics/icon.psd
  60. BIN  OtherFiles/graphics/instructions.psd
  61. BIN  OtherFiles/graphics/itunes_artwork.png
  62. BIN  OtherFiles/graphics/key.psd
  63. BIN  OtherFiles/graphics/map.psd
  64. BIN  OtherFiles/graphics/map_icons.psd
  65. BIN  OtherFiles/graphics/map_key_anim.psd
  66. BIN  OtherFiles/graphics/map_lock_anim.psd
  67. BIN  OtherFiles/graphics/map_select_destination.psd
  68. BIN  OtherFiles/graphics/menu.psd
  69. BIN  OtherFiles/graphics/mil400.psd
  70. BIN  OtherFiles/graphics/nag.psd
  71. BIN  OtherFiles/graphics/options.psd
  72. BIN  OtherFiles/graphics/select_level.psd
  73. BIN  OtherFiles/graphics/splash.psd
  74. BIN  OtherFiles/graphics/trophy.psd
  75. +9 −0 OtherFiles/levels/level1.txt
  76. +9 −0 OtherFiles/levels/level10.txt
  77. +9 −0 OtherFiles/levels/level100.txt
  78. +9 −0 OtherFiles/levels/level101.txt
  79. +9 −0 OtherFiles/levels/level102.txt
  80. +9 −0 OtherFiles/levels/level103.txt
  81. +9 −0 OtherFiles/levels/level104.txt
  82. +9 −0 OtherFiles/levels/level105.txt
  83. +9 −0 OtherFiles/levels/level106.txt
  84. +9 −0 OtherFiles/levels/level107.txt
  85. +9 −0 OtherFiles/levels/level108.txt
  86. +9 −0 OtherFiles/levels/level109.txt
  87. +9 −0 OtherFiles/levels/level11.txt
  88. +9 −0 OtherFiles/levels/level110.txt
  89. +9 −0 OtherFiles/levels/level111.txt
  90. +9 −0 OtherFiles/levels/level112.txt
  91. +9 −0 OtherFiles/levels/level113.txt
  92. +9 −0 OtherFiles/levels/level114.txt
  93. +9 −0 OtherFiles/levels/level115.txt
  94. +9 −0 OtherFiles/levels/level116.txt
  95. +9 −0 OtherFiles/levels/level117.txt
  96. +9 −0 OtherFiles/levels/level118.txt
  97. +9 −0 OtherFiles/levels/level119.txt
  98. +9 −0 OtherFiles/levels/level12.txt
  99. +9 −0 OtherFiles/levels/level120.txt
  100. +9 −0 OtherFiles/levels/level13.txt
  101. +9 −0 OtherFiles/levels/level14.txt
  102. +9 −0 OtherFiles/levels/level15.txt
  103. +9 −0 OtherFiles/levels/level16.txt
  104. +9 −0 OtherFiles/levels/level17.txt
  105. +9 −0 OtherFiles/levels/level18.txt
  106. +9 −0 OtherFiles/levels/level19.txt
  107. +9 −0 OtherFiles/levels/level2.txt
  108. +9 −0 OtherFiles/levels/level20.txt
  109. +9 −0 OtherFiles/levels/level21.txt
  110. +9 −0 OtherFiles/levels/level22.txt
  111. +9 −0 OtherFiles/levels/level23.txt
  112. +9 −0 OtherFiles/levels/level24.txt
  113. +9 −0 OtherFiles/levels/level25.txt
  114. +9 −0 OtherFiles/levels/level26.txt
  115. +9 −0 OtherFiles/levels/level27.txt
  116. +9 −0 OtherFiles/levels/level28.txt
  117. +9 −0 OtherFiles/levels/level29.txt
  118. +9 −0 OtherFiles/levels/level3.txt
  119. +9 −0 OtherFiles/levels/level30.txt
  120. +9 −0 OtherFiles/levels/level31.txt
  121. +9 −0 OtherFiles/levels/level32.txt
  122. +9 −0 OtherFiles/levels/level33.txt
  123. +9 −0 OtherFiles/levels/level34.txt
  124. +9 −0 OtherFiles/levels/level35.txt
  125. +9 −0 OtherFiles/levels/level36.txt
  126. +9 −0 OtherFiles/levels/level37.txt
  127. +9 −0 OtherFiles/levels/level38.txt
  128. +9 −0 OtherFiles/levels/level39.txt
  129. +9 −0 OtherFiles/levels/level4.txt
  130. +9 −0 OtherFiles/levels/level40.txt
  131. +9 −0 OtherFiles/levels/level41.txt
  132. +9 −0 OtherFiles/levels/level42.txt
  133. +9 −0 OtherFiles/levels/level43.txt
  134. +9 −0 OtherFiles/levels/level44.txt
  135. +9 −0 OtherFiles/levels/level45.txt
  136. +9 −0 OtherFiles/levels/level46.txt
  137. +9 −0 OtherFiles/levels/level47.txt
  138. +9 −0 OtherFiles/levels/level48.txt
  139. +9 −0 OtherFiles/levels/level49.txt
  140. +9 −0 OtherFiles/levels/level5.txt
  141. +9 −0 OtherFiles/levels/level50.txt
  142. +9 −0 OtherFiles/levels/level51.txt
  143. +9 −0 OtherFiles/levels/level52.txt
  144. +9 −0 OtherFiles/levels/level53.txt
  145. +9 −0 OtherFiles/levels/level54.txt
  146. +9 −0 OtherFiles/levels/level55.txt
  147. +9 −0 OtherFiles/levels/level56.txt
  148. +9 −0 OtherFiles/levels/level57.txt
  149. +9 −0 OtherFiles/levels/level58.txt
  150. +9 −0 OtherFiles/levels/level59.txt
  151. +9 −0 OtherFiles/levels/level6.txt
  152. +9 −0 OtherFiles/levels/level60.txt
  153. +9 −0 OtherFiles/levels/level61.txt
  154. +9 −0 OtherFiles/levels/level62.txt
  155. +9 −0 OtherFiles/levels/level63.txt
  156. +9 −0 OtherFiles/levels/level64.txt
  157. +9 −0 OtherFiles/levels/level65.txt
  158. +9 −0 OtherFiles/levels/level66.txt
  159. +9 −0 OtherFiles/levels/level67.txt
  160. +9 −0 OtherFiles/levels/level68.txt
  161. +9 −0 OtherFiles/levels/level69.txt
  162. +9 −0 OtherFiles/levels/level7.txt
  163. +9 −0 OtherFiles/levels/level70.txt
  164. +9 −0 OtherFiles/levels/level71.txt
  165. +9 −0 OtherFiles/levels/level72.txt
  166. +9 −0 OtherFiles/levels/level73.txt
  167. +9 −0 OtherFiles/levels/level74.txt
  168. +9 −0 OtherFiles/levels/level75.txt
  169. +9 −0 OtherFiles/levels/level76.txt
  170. +9 −0 OtherFiles/levels/level77.txt
  171. +9 −0 OtherFiles/levels/level78.txt
  172. +9 −0 OtherFiles/levels/level79.txt
  173. +9 −0 OtherFiles/levels/level8.txt
  174. +9 −0 OtherFiles/levels/level80.txt
  175. +9 −0 OtherFiles/levels/level81.txt
  176. +9 −0 OtherFiles/levels/level82.txt
  177. +9 −0 OtherFiles/levels/level83.txt
  178. +9 −0 OtherFiles/levels/level84.txt
  179. +9 −0 OtherFiles/levels/level85.txt
  180. +9 −0 OtherFiles/levels/level86.txt
  181. +9 −0 OtherFiles/levels/level87.txt
  182. +9 −0 OtherFiles/levels/level88.txt
  183. +9 −0 OtherFiles/levels/level89.txt
  184. +9 −0 OtherFiles/levels/level9.txt
  185. +9 −0 OtherFiles/levels/level90.txt
  186. +9 −0 OtherFiles/levels/level91.txt
  187. +9 −0 OtherFiles/levels/level92.txt
  188. +9 −0 OtherFiles/levels/level93.txt
  189. +9 −0 OtherFiles/levels/level94.txt
  190. +9 −0 OtherFiles/levels/level95.txt
  191. +9 −0 OtherFiles/levels/level96.txt
  192. +9 −0 OtherFiles/levels/level97.txt
  193. +9 −0 OtherFiles/levels/level98.txt
  194. +9 −0 OtherFiles/levels/level99.txt
  195. +120 −0 OtherFiles/levels/levels.dat
  196. +121 −0 OtherFiles/levels/levels.sql
  197. +18 −0 OtherFiles/levels/make_objc.php
  198. +19 −0 OtherFiles/levels/make_sql.php
  199. +40 −0 OtherFiles/levels/notes.txt
  200. BIN  OtherFiles/levels/solutions.ods
  201. +40 −0 README.md
  202. +58 −0 Resources/Info.plist
  203. BIN  Resources/ItunesArtwork
  204. BIN  Resources/fps_images.png
  205. BIN  Resources/graphics/achievements/achievements_back.png
  206. BIN  Resources/graphics/achievements/achievements_back2.png
  207. BIN  Resources/graphics/achievements/achievements_background.png
  208. BIN  Resources/graphics/achievements/achievements_menu.png
  209. BIN  Resources/graphics/achievements/achievements_menu2.png
  210. BIN  Resources/graphics/achievements/achievements_next.png
  211. BIN  Resources/graphics/achievements/achievements_next2.png
  212. BIN  Resources/graphics/achievements/achievements_shadow.png
  213. BIN  Resources/graphics/achievements/achievements_trophy.png
  214. BIN  Resources/graphics/achievements/achievements_trophy_locked.png
  215. BIN  Resources/graphics/achievements/gabriola.ttf
  216. BIN  Resources/graphics/backgrounds/background_forest_dark.png
  217. BIN  Resources/graphics/backgrounds/background_forest_light.png
  218. BIN  Resources/graphics/deutsch.ttf
  219. BIN  Resources/graphics/game/game_achievement_background.png
  220. BIN  Resources/graphics/game/game_background_beach.png
  221. BIN  Resources/graphics/game/game_background_caves.png
  222. BIN  Resources/graphics/game/game_background_forest.png
  223. BIN  Resources/graphics/game/game_background_ship.png
  224. BIN  Resources/graphics/game/game_frame.png
  225. BIN  Resources/graphics/game/game_level_complete.png
  226. BIN  Resources/graphics/game/game_level_complete_perfect.png
  227. BIN  Resources/graphics/game/game_menu.png
  228. BIN  Resources/graphics/game/game_menu2.png
  229. BIN  Resources/graphics/game/game_message_intro.png
  230. BIN  Resources/graphics/game/game_message_no_moves_menu.png
  231. BIN  Resources/graphics/game/game_message_no_moves_shake.png
  232. BIN  Resources/graphics/game/game_tiles_beach.png
  233. BIN  Resources/graphics/game/game_tiles_caves.png
  234. BIN  Resources/graphics/game/game_tiles_forest.png
  235. BIN  Resources/graphics/game/game_tiles_objects.png
  236. BIN  Resources/graphics/game/game_tiles_ship.png
  237. BIN  Resources/graphics/game_menu/game_menu_choose.png
  238. BIN  Resources/graphics/game_menu/game_menu_choose2.png
  239. BIN  Resources/graphics/game_menu/game_menu_header.png
  240. BIN  Resources/graphics/game_menu/game_menu_main.png
  241. BIN  Resources/graphics/game_menu/game_menu_main2.png
  242. BIN  Resources/graphics/game_menu/game_menu_options.png
  243. BIN  Resources/graphics/game_menu/game_menu_options2.png
  244. BIN  Resources/graphics/game_menu/game_menu_restart.png
  245. BIN  Resources/graphics/game_menu/game_menu_restart2.png
  246. BIN  Resources/graphics/game_menu/game_menu_resume.png
  247. BIN  Resources/graphics/game_menu/game_menu_resume2.png
  248. BIN  Resources/graphics/game_menu/game_menu_status_background.png
  249. BIN  Resources/graphics/instructions/instructions_back.png
  250. BIN  Resources/graphics/instructions/instructions_back2.png
  251. BIN  Resources/graphics/instructions/instructions_header.png
  252. BIN  Resources/graphics/instructions/instructions_menu.png
  253. BIN  Resources/graphics/instructions/instructions_menu2.png
  254. BIN  Resources/graphics/instructions/instructions_next.png
  255. BIN  Resources/graphics/instructions/instructions_next2.png
  256. BIN  Resources/graphics/instructions/instructions_page1.png
  257. BIN  Resources/graphics/instructions/instructions_page2.png
  258. BIN  Resources/graphics/instructions/instructions_page3.png
  259. BIN  Resources/graphics/instructions/instructions_page4.png
  260. BIN  Resources/graphics/map/map_background.png
  261. BIN  Resources/graphics/map/map_key.png
  262. BIN  Resources/graphics/map/map_lock.png
  263. BIN  Resources/graphics/map/map_select_destination.png
  264. BIN  Resources/graphics/map/map_sparkle.png
  265. BIN  Resources/graphics/menu/menu_achievements.png
  266. BIN  Resources/graphics/menu/menu_achievements2.png
  267. BIN  Resources/graphics/menu/menu_header.png
  268. BIN  Resources/graphics/menu/menu_instructions.png
  269. BIN  Resources/graphics/menu/menu_instructions2.png
  270. BIN  Resources/graphics/menu/menu_options.png
  271. BIN  Resources/graphics/menu/menu_options2.png
  272. BIN  Resources/graphics/menu/menu_play.png
  273. BIN  Resources/graphics/menu/menu_play2.png
  274. BIN  Resources/graphics/nag/nag_header.png
  275. BIN  Resources/graphics/nag/nag_no.png
  276. BIN  Resources/graphics/nag/nag_no2.png
  277. BIN  Resources/graphics/nag/nag_yes.png
  278. BIN  Resources/graphics/nag/nag_yes2.png
  279. BIN  Resources/graphics/options/options_back_game.png
  280. BIN  Resources/graphics/options/options_back_game2.png
  281. BIN  Resources/graphics/options/options_back_menu.png
  282. BIN  Resources/graphics/options/options_back_menu2.png
  283. BIN  Resources/graphics/options/options_background.png
  284. BIN  Resources/graphics/options/options_music_off.png
  285. BIN  Resources/graphics/options/options_music_on.png
  286. BIN  Resources/graphics/options/options_reset.png
  287. BIN  Resources/graphics/options/options_reset2.png
  288. BIN  Resources/graphics/options/options_reset_confirm_background.png
  289. BIN  Resources/graphics/options/options_reset_confirm_cancel.png
  290. BIN  Resources/graphics/options/options_reset_confirm_cancel2.png
  291. BIN  Resources/graphics/options/options_reset_confirm_yes.png
  292. BIN  Resources/graphics/options/options_reset_confirm_yes2.png
  293. BIN  Resources/graphics/options/options_shake_off.png
  294. BIN  Resources/graphics/options/options_shake_on.png
  295. BIN  Resources/graphics/options/options_sound_off.png
  296. BIN  Resources/graphics/options/options_sound_on.png
  297. BIN  Resources/graphics/select_level/select_level_back.png
  298. BIN  Resources/graphics/select_level/select_level_back2.png
  299. BIN  Resources/graphics/select_level/select_level_background_beach.png
  300. BIN  Resources/graphics/select_level/select_level_background_caves.png
Sorry, we could not display the entire diff because too many files (548) changed.
1  .gitignore
@@ -0,0 +1 @@
+build/
79 Classes/Achievements.h
@@ -0,0 +1,79 @@
+//
+// Achievements.h
+// Skeleton Key
+//
+// Created by micah on 12/30/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+// the achievements
+typedef enum {
+ AchievementBeginTheHunt = 0,
+ AchievementKnockKnock = 1,
+ AchievementTheDoorman = 2,
+ AchievementTheDoorToKnowhere = 3,
+ AchievementPerfectionist = 4,
+ AchievementProfessionalPerfectionist = 5,
+ AchievementEnterTheDarkness = 6,
+ AchievementEnjoyTheSun = 7,
+ AchievementArrrgh = 8,
+ AchievementTreasureHunter = 9,
+ AchievementAnAdventurerIsYou = 10,
+ AchievementIntrepidExplorer = 11,
+ AchievementMastermind = 12
+} AchievementNames;
+
+#define ACHIEVEMENT0_NAME @"Begin the Hunt"
+#define ACHIEVEMENT0_DESC @"Beat the first 10 levels"
+#define ACHIEVEMENT1_NAME @"Knock Knock"
+#define ACHIEVEMENT1_DESC @"Open a door"
+#define ACHIEVEMENT2_NAME @"The Doorman"
+#define ACHIEVEMENT2_DESC @"Open 50 doors"
+#define ACHIEVEMENT3_NAME @"The Door to Nowhere"
+#define ACHIEVEMENT3_DESC @"Can you find it?"
+#define ACHIEVEMENT4_NAME @"Perfectionist"
+#define ACHIEVEMENT4_DESC @"Play any 10 levels perfectly"
+#define ACHIEVEMENT5_NAME @"Professional Perfectionist"
+#define ACHIEVEMENT5_DESC @"Play any 30 levels perfectly"
+#define ACHIEVEMENT6_NAME @"Enter the Darkness"
+#define ACHIEVEMENT6_DESC @"Make it to the Caves"
+#define ACHIEVEMENT7_NAME @"Enjoy the Sun"
+#define ACHIEVEMENT7_DESC @"Make it to the Beach"
+#define ACHIEVEMENT8_NAME @"Arrrgh!"
+#define ACHIEVEMENT8_DESC @"Make it to the Pirate Ship"
+#define ACHIEVEMENT9_NAME @"Treasure Hunter"
+#define ACHIEVEMENT9_DESC @"Beat all level on Easy"
+#define ACHIEVEMENT10_NAME @"An Adventurer is You"
+#define ACHIEVEMENT10_DESC @"Beat all levels on Medium"
+#define ACHIEVEMENT11_NAME @"Intrepid Explorer"
+#define ACHIEVEMENT11_DESC @"Beat all levels on Hard"
+#define ACHIEVEMENT12_NAME @"Mastermind"
+#define ACHIEVEMENT12_DESC @"Beat all levels perfectly"
+
+#define ACHIEVEMENT_NUM 13
+
+@interface Achievements : NSObject {
+ NSMutableArray* achievements;
+ NSUInteger doorsOpened;
+ NSMutableArray* achieved;
+
+ NSUInteger numAchievements;
+}
+
+@property (nonatomic,retain) NSMutableArray* achievements;
+@property (readwrite) NSUInteger doorsOpened;
+@property (nonatomic,retain) NSMutableArray* achieved;
+@property (readwrite) NSUInteger numAchievements;
+
+- (NSString*)getFilePath;
+- (void) load;
+- (void) save;
+- (void) reset;
+- (bool) unlock:(int)achievementId;
+
+- (NSString*) getName:(int)i;
+- (NSString*) getDescription:(int)i;
+
+@end
118 Classes/Achievements.m
@@ -0,0 +1,118 @@
+//
+// Achievements.m
+// Skeleton Key
+//
+// Created by micah on 12/30/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import "Achievements.h"
+
+
+@implementation Achievements
+
+@synthesize achievements;
+@synthesize doorsOpened;
+@synthesize achieved;
+@synthesize numAchievements;
+
+- (id) init {
+ if((self = [super init])) {
+ NSLog(@"Achievements init");
+ numAchievements = 13;
+ achieved = [[NSMutableArray alloc] initWithCapacity:numAchievements];
+ [self load];
+ }
+ return self;
+}
+
+- (void) dealloc {
+ NSLog(@"Achievements dealloc");
+ [achieved dealloc];
+ [super dealloc];
+}
+
+- (NSString*)getFilePath {
+ NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ NSString* documentsDirectory = [paths objectAtIndex:0];
+ return [documentsDirectory stringByAppendingPathComponent:@"Achievements.plist"];
+}
+
+- (void) load {
+ if([[NSFileManager defaultManager] fileExistsAtPath:[self getFilePath]]) {
+ NSLog(@"Achievements load");
+ achievements = [NSArray arrayWithContentsOfFile:[self getFilePath]];
+ doorsOpened = [[achievements objectAtIndex:0] intValue];
+ for(NSUInteger i=1; i<=numAchievements; i++)
+ [achieved addObject:[achievements objectAtIndex:i]];
+ } else {
+ NSLog(@"Achievements create new file");
+ doorsOpened = 0;
+ for(NSUInteger i=1; i<=numAchievements; i++)
+ [achieved addObject:[NSNumber numberWithInt:0]];
+ [self save];
+ }
+}
+
+- (void) save {
+ NSLog(@"Achievements save");
+ achievements = [NSMutableArray arrayWithObject:[NSNumber numberWithInt:doorsOpened]];
+ for(NSUInteger i=0; i<numAchievements; i++)
+ [achievements addObject:[achieved objectAtIndex:i]];
+ [achievements writeToFile:[self getFilePath] atomically:YES];
+}
+
+- (void) reset {
+ [achieved dealloc];
+ achieved = [[NSMutableArray alloc] initWithCapacity:numAchievements];
+ for(NSUInteger i=1; i<=numAchievements; i++)
+ [achieved addObject:[NSNumber numberWithInt:0]];
+ [self save];
+}
+
+- (bool) unlock:(int)achievementId {
+ if([(NSNumber*)[achieved objectAtIndex:achievementId] intValue] == 1) return false;
+ [achieved replaceObjectAtIndex:achievementId withObject:[NSNumber numberWithInt:1]];
+ [self save];
+ return true;
+}
+
+- (NSString*) getName:(int)i {
+ switch(i) {
+ case 0: return ACHIEVEMENT0_NAME;
+ case 1: return ACHIEVEMENT1_NAME;
+ case 2: return ACHIEVEMENT2_NAME;
+ case 3: return ACHIEVEMENT3_NAME;
+ case 4: return ACHIEVEMENT4_NAME;
+ case 5: return ACHIEVEMENT5_NAME;
+ case 6: return ACHIEVEMENT6_NAME;
+ case 7: return ACHIEVEMENT7_NAME;
+ case 8: return ACHIEVEMENT8_NAME;
+ case 9: return ACHIEVEMENT9_NAME;
+ case 10: return ACHIEVEMENT10_NAME;
+ case 11: return ACHIEVEMENT11_NAME;
+ case 12: return ACHIEVEMENT12_NAME;
+ }
+ return @"";
+}
+
+- (NSString*) getDescription:(int)i {
+ switch(i) {
+ case 0: return ACHIEVEMENT0_DESC;
+ case 1: return ACHIEVEMENT1_DESC;
+ case 2: return ACHIEVEMENT2_DESC;
+ case 3: return ACHIEVEMENT3_DESC;
+ case 4: return ACHIEVEMENT4_DESC;
+ case 5: return ACHIEVEMENT5_DESC;
+ case 6: return ACHIEVEMENT6_DESC;
+ case 7: return ACHIEVEMENT7_DESC;
+ case 8: return ACHIEVEMENT8_DESC;
+ case 9: return ACHIEVEMENT9_DESC;
+ case 10: return ACHIEVEMENT10_DESC;
+ case 11: return ACHIEVEMENT11_DESC;
+ case 12: return ACHIEVEMENT12_DESC;
+ }
+ return @"";
+}
+
+@end
37 Classes/AchievementsScene.h
@@ -0,0 +1,37 @@
+//
+// AchievementsScene.h
+// Skeleton Key
+//
+// Created by micah on 12/30/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import "cocos2d.h"
+#import "Achievements.h"
+#import "Helpers.h"
+#import "Sound.h"
+
+@interface AchievementsScene : CCLayer {
+ Achievements* achievements;
+
+ NSInteger numPages;
+ NSInteger pageNumber;
+ CCMenuItemImage* back;
+ CCMenuItemImage* next;
+ CCLayer* pageLayer;
+
+ CGPoint touchStart;
+
+ Sound* sound;
+}
+
++ (id) scene;
+
+- (void) onBack:(id)sender;
+- (void) onNext:(id)sender;
+- (void) onMenu:(id)sender;
+- (void) moveBack;
+- (void) moveNext;
+- (void) scroll;
+
+@end
175 Classes/AchievementsScene.m
@@ -0,0 +1,175 @@
+//
+// AchievementsScene.m
+// Skeleton Key
+//
+// Created by micah on 12/30/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import "AchievementsScene.h"
+#import "MenuScene.h"
+#import "SkeletonKeyAppDelegate.h"
+
+@implementation AchievementsScene
+
++ (id) scene {
+ CCScene* scene = [CCScene node];
+ AchievementsScene* layer = [AchievementsScene node];
+ [scene addChild:layer];
+ return scene;
+}
+
+- (id) init {
+ if((self=[super init])) {
+ NSLog(@"AchievementsScene init");
+
+ self.isTouchEnabled = YES;
+ sound = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate)).sound;
+ achievements = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate)).achievements;
+
+ // background
+ CCSprite* background = [CCSprite spriteWithFile:@"achievements_background.png"];
+ background.position = ccp(160, 240);
+ [self addChild:background];
+
+ // menu
+ back = [CCMenuItemImage itemFromNormalImage:@"achievements_back.png"
+ selectedImage:@"achievements_back2.png"
+ target:self
+ selector:@selector(onBack:)];
+ back.opacity = 64;
+ next = [CCMenuItemImage itemFromNormalImage:@"achievements_next.png"
+ selectedImage:@"achievements_next2.png"
+ target:self
+ selector:@selector(onNext:)];
+ CCMenuItemImage* backToMenu = [CCMenuItemImage itemFromNormalImage:@"achievements_menu.png"
+ selectedImage:@"achievements_menu2.png"
+ target:self
+ selector:@selector(onMenu:)];
+ CCMenu* menu = [CCMenu menuWithItems:back, backToMenu, next, nil];
+ [menu alignItemsHorizontallyWithPadding:0];
+ menu.position = ccp(160, 28.5);
+ [self addChild:menu z:2];
+
+ // pages
+ pageNumber = 1;
+ numPages = (int)(achievements.numAchievements / 5);
+ if(achievements.numAchievements % 5 > 0)
+ numPages++;
+ pageLayer = [CCLayer node];
+ [self addChild:pageLayer];
+
+ // display achievements
+ for(NSUInteger i=0; i<achievements.numAchievements; i++) {
+ NSUInteger page = (int)(i / 5);
+ NSUInteger y = 4 - (i % 5);
+
+ NSString* topText = [achievements getName:i];
+ NSString* bottomText = [achievements getDescription:i];
+
+ // shadow
+ CCSprite* achievement_shadow = [CCSprite spriteWithFile:@"achievements_shadow.png"];
+ achievement_shadow.position = ccp(160+320*page, 92+68*y);
+ [pageLayer addChild:achievement_shadow z:2];
+
+ // text
+ CCLabelTTF* achievment_label_top = [CCLabelTTF labelWithString:topText fontName:@"gabriola.ttf" fontSize:29];
+ achievment_label_top.position = ccp(194+320*page, 107+68*y);
+ [pageLayer addChild:achievment_label_top z:3];
+ CCLabelTTF* achievment_label_bottom = [CCLabelTTF labelWithString:bottomText fontName:@"gabriola.ttf" fontSize:22];
+ achievment_label_bottom.position = ccp(194+320*page, 81+68*y);
+ [pageLayer addChild:achievment_label_bottom z:3];
+
+ if([achievements.achieved objectAtIndex:i] == [NSNumber numberWithInt:1]) {
+ // achieved
+ CCSprite* achievement_trophy = [CCSprite spriteWithFile:@"achievements_trophy.png"];
+ achievement_trophy.position = ccp(44+320*page, 92+68*y);
+ [pageLayer addChild:achievement_trophy z:3];
+ } else {
+ // have not yet achieved
+ CCSprite* achievement_trophy_locked = [CCSprite spriteWithFile:@"achievements_trophy_locked.png"];
+ achievement_trophy_locked.position = ccp(44+320*page, 92+68*y);
+ [pageLayer addChild:achievement_trophy_locked z:3];
+
+ // fade the text
+ achievment_label_top.opacity = 192;
+ achievment_label_bottom.opacity = 192;
+ }
+ }
+ }
+ return self;
+}
+
+- (void) onBack:(id)sender {
+ NSLog(@"AchievementsScene onBack");
+ [sound playClick];
+ [self moveBack];
+}
+
+- (void) onNext:(id)sender {
+ NSLog(@"AchievementsScene onNext");
+ [sound playClick];
+ [self moveNext];
+}
+
+- (void) onMenu:(id)sender {
+ NSLog(@"AchievementsScene onMenu");
+ [sound playClick];
+ [[CCDirector sharedDirector] replaceScene:[CCTransitionPageTurn transitionWithDuration:0.3 scene:[MenuScene scene] backwards:YES]];
+}
+
+- (void) moveBack {
+ if(pageNumber > 1) {
+ pageNumber--;
+ if(pageNumber == 1)
+ back.opacity = 64;
+ next.opacity = 255;
+ [self scroll];
+ }
+}
+
+- (void) moveNext {
+ if(pageNumber < numPages) {
+ pageNumber++;
+ if(pageNumber == numPages)
+ next.opacity = 64;
+ back.opacity = 255;
+ [self scroll];
+ }
+}
+
+- (void) scroll {
+ CGFloat x = (pageNumber-1)*-320;
+ [pageLayer runAction:[CCMoveTo actionWithDuration:0.2 position:ccp(x, 0)]];
+}
+
+- (void) registerWithTouchDispatcher {
+ [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
+}
+
+- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
+ touchStart = [self convertTouchToNodeSpace:touch];
+ return YES;
+}
+
+- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
+ CGPoint touchEnd = [self convertTouchToNodeSpace:touch];
+
+ switch([Helpers swipeDirectionStart:touchStart end:touchEnd]) {
+ case GameDirLeft:
+ [sound playKeyMove];
+ [self moveNext];
+ break;
+ case GameDirRight:
+ [sound playKeyMove];
+ [self moveBack];
+ break;
+ }
+}
+
+- (void) dealloc {
+ NSLog(@"AchievementsScene dealloc");
+ [super dealloc];
+}
+
+@end
28 Classes/GameConfig.h
@@ -0,0 +1,28 @@
+//
+// GameConfig.h
+// Skeleton Key
+//
+// Created by micah on 12/30/10.
+// Copyright __MyCompanyName__ 2010. All rights reserved.
+//
+
+#ifndef __GAME_CONFIG_H
+#define __GAME_CONFIG_H
+
+//
+// Supported Autorotations:
+// None,
+// UIViewController,
+// CCDirector
+//
+#define kGameAutorotationNone 0
+#define kGameAutorotationCCDirector 1
+#define kGameAutorotationUIViewController 2
+
+//
+// Define here the type of autorotation that you want for your game
+//
+#define GAME_AUTOROTATION kGameAutorotationUIViewController
+
+
+#endif // __GAME_CONFIG_H
125 Classes/GameData.h
@@ -0,0 +1,125 @@
+//
+// GameData.h
+// Skeleton Key
+//
+// Created by micah on 12/31/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "Helpers.h"
+#import "Levels.h"
+#import "Level.h"
+#import "Options.h"
+#import "Levels.h"
+#import "Sound.h"
+#import "GameDataKey.h"
+
+// game board dimensions
+#define GAME_BOARD_WIDTH 6
+#define GAME_BOARD_HEIGHT 8
+
+// levels
+#define TOTAL_LEVELS 120
+
+// stage names
+typedef enum {
+ GameStageForest = 0,
+ GameStageCaves = 1,
+ GameStageBeach = 2,
+ GameStageShip = 3,
+ GameStageNone = 4
+} GameStageNames;
+
+// difficulties
+typedef enum {
+ GameDifficultyEasy = 0,
+ GameDifficultyMedium = 1,
+ GameDifficultyHard = 2
+} GameDifficulties;
+
+// tile types
+typedef enum {
+ GameTileSpace = 0,
+ GameTileSolid4Sides = 1,
+ GameTileSolid3SidesTRB = 2,
+ GameTileSolid3SidesTRL = 3,
+ GameTileSolid3SidesTLB = 4,
+ GameTileSolid3SidesRBL = 5,
+ GameTileSolid2SidesTR = 6,
+ GameTileSolid2SidesTB = 7,
+ GameTileSolid2SidesTL = 8,
+ GameTileSolid2SidesRB = 9,
+ GameTileSolid2SidesRL = 10,
+ GameTileSolid2SidesBL = 11,
+ GameTileSolid1SidesT = 12,
+ GameTileSolid1SidesR = 13,
+ GameTileSolid1SidesB = 14,
+ GameTileSolid1SidesL = 15,
+ GameTileSolid0Sides = 16,
+ GameTileKey = 17,
+ GameTileChest = 18,
+ GameTileChestOpen = 19,
+ GameTileSwitch = 20,
+ GameTileDoorLRClosed = 21,
+ GameTileDoorLROpen = 22,
+ GameTileDoorTBClosed = 23,
+ GameTileDoorTBOpen = 24
+} GameTiles;
+
+@interface GameData : NSObject {
+ Options* options;
+ Levels* levels;
+ Sound* sound;
+
+ // is the game active?
+ BOOL activeGame;
+
+ // shared data
+ int stage;
+ int difficulty;
+ int level;
+ char tileString[49];
+ char tiles[6][8];
+ NSMutableArray* keys;
+ int movesLeft;
+ BOOL doorOpened;
+ BOOL returnToGame;
+}
+
+@property (readwrite) BOOL activeGame;
+@property (readwrite) int stage;
+@property (readwrite) int difficulty;
+@property (readwrite) int level;
+@property (nonatomic,retain) NSMutableArray* keys;
+@property (readwrite) int movesLeft;
+@property (readwrite) BOOL doorOpened;
+@property (readwrite) BOOL returnToGame;
+
+// getters, because obj-c is weird
+- (int) getTileTypeX:(int)x andY:(int)y;
+- (char*) getTileString;
+
+// saving, loading
+- (NSString*) savedGamePath;
+- (void) loadLevel;
+- (BOOL) loadGame;
+- (void) saveGame;
+- (BOOL) isSavedGame;
+- (void) deleteSavedGame;
+
+// gameplay mechanics
+- (void) moveKeys:(int)dir;
+- (BOOL) cannotMove;
+- (BOOL) isKeyAtPositionX:(int)x andY:(int)y;
+- (void) beatLevel;
+
+// misc
+- (BOOL) stageLocked:(int)stageToCheck;
+- (int) stageForLevel:(int)levelToCheck;
+- (NSString*) stageName;
+
+// memory
+- (void) freeKeys;
+
+@end
557 Classes/GameData.m
@@ -0,0 +1,557 @@
+//
+// GameData.m
+// Skeleton Key
+//
+// Created by micah on 12/31/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import "GameData.h"
+#import "SkeletonKeyAppDelegate.h"
+
+@implementation GameData
+
+@synthesize activeGame;
+@synthesize stage;
+@synthesize difficulty;
+@synthesize level;
+@synthesize keys;
+@synthesize movesLeft;
+@synthesize doorOpened;
+@synthesize returnToGame;
+
+- (id) init {
+ if((self=[super init])) {
+ NSLog(@"GameData init");
+
+ activeGame = FALSE;
+ options = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate)).options;
+ levels = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate)).levels;
+ sound = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate)).sound;
+
+ keys = [[NSMutableArray alloc] initWithCapacity:5];
+ }
+ return self;
+}
+
+- (void) dealloc {
+ NSLog(@"GameData dealloc");
+ [self freeKeys];
+ [super dealloc];
+}
+
+// getters, because obj-c is weird
+- (int) getTileTypeX:(int)x andY:(int)y {
+ return tiles[x][y];
+}
+- (char*) getTileString {
+ return tileString;
+}
+
+// saving, loading
+- (NSString*) savedGamePath {
+ NSString* savedGamePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
+ stringByAppendingPathComponent:@"SavedGame.plist"];
+ return savedGamePath;
+}
+- (void) loadLevel {
+ Level* l = [levels.levels objectAtIndex:level-1];
+
+ // tiles
+ NSLog(@"level data: %@", l.data);
+ strcpy(tileString, [l.data UTF8String]);
+
+ // moves
+ movesLeft = l.min_moves;
+
+ // make sure the stage is correct
+ stage = [self stageForLevel:level];
+
+ // set difficulty
+ difficulty = options.difficulty;
+
+ // update moves left based on difficulty
+ switch(difficulty) {
+ case GameDifficultyEasy: movesLeft += 10; break;
+ case GameDifficultyMedium: movesLeft += 6; break;
+ case GameDifficultyHard: movesLeft += 2; break;
+ }
+
+ // set up tiles
+ [self freeKeys];
+ keys = [[NSMutableArray alloc] initWithCapacity:5];
+ int keyId = 0;
+ int x, y;
+ for(x=0; x<GAME_BOARD_WIDTH; x++) {
+ for(y=0; y<GAME_BOARD_HEIGHT; y++) {
+ switch(tileString[GAME_BOARD_WIDTH*y+x]) {
+ case '.': // space
+ default:
+ tiles[x][y] = GameTileSpace;
+ break;
+ case '*': // solid
+ tiles[x][y] = GameTileSolid4Sides;
+ break;
+ case '!': // key
+ tiles[x][y] = GameTileSpace;
+ GameDataKey* k = [[GameDataKey alloc] init];
+ k.x = x;
+ k.y = y;
+ k.used = FALSE;
+ k.ident = keyId;
+ keyId++;
+ [keys addObject:k];
+ break;
+ case 'x': // chest
+ tiles[x][y] = GameTileChest;
+ break;
+ case 'X': // open chest
+ tiles[x][y] = GameTileChestOpen;
+ break;
+ case 'o': // door switch
+ tiles[x][y] = GameTileSwitch;
+ break;
+ case '|': // left-right door closed
+ tiles[x][y] = GameTileDoorLRClosed;
+ break;
+ case '#': // left-right door open
+ tiles[x][y] = GameTileDoorLROpen;
+ break;
+ case '-': // top-bottom door closed
+ tiles[x][y] = GameTileDoorTBClosed;
+ break;
+ case '=': // top-bottom door open
+ tiles[x][y] = GameTileDoorTBOpen;
+ break;
+ }
+ }
+ }
+ // figure out what all the walls should look like
+ BOOL top, right, bottom, left;
+ for(x=0; x<GAME_BOARD_WIDTH; x++) {
+ for(y=0; y<GAME_BOARD_HEIGHT; y++) {
+ if(tiles[x][y] == GameTileSolid4Sides) {
+ top = FALSE; right = FALSE; bottom = FALSE; left = FALSE;
+ if(y == 0 || (tiles[x][y-1] >= GameTileSolid4Sides && tiles[x][y-1] <= GameTileSolid0Sides))
+ top = TRUE;
+ if(x == GAME_BOARD_WIDTH-1 || (tiles[x+1][y] >= GameTileSolid4Sides && tiles[x+1][y] <= GameTileSolid0Sides))
+ right = TRUE;
+ if(y == GAME_BOARD_HEIGHT-1 || (tiles[x][y+1] >= GameTileSolid4Sides && tiles[x][y+1] <= GameTileSolid0Sides))
+ bottom = TRUE;
+ if(x == 0 || (tiles[x-1][y] >= GameTileSolid4Sides && tiles[x-1][y] <= GameTileSolid0Sides))
+ left = TRUE;
+
+ // set the walls tiles
+ if(top && right && bottom && left)
+ tiles[x][y] = GameTileSolid4Sides;
+ else if(top && right && bottom && !left)
+ tiles[x][y] = GameTileSolid3SidesTRB;
+ else if(top && right && !bottom && left)
+ tiles[x][y] = GameTileSolid3SidesTRL;
+ else if(top && !right && bottom && left)
+ tiles[x][y] = GameTileSolid3SidesTLB;
+ else if(!top && right && bottom && left)
+ tiles[x][y] = GameTileSolid3SidesRBL;
+ else if(top && right && !bottom && !left)
+ tiles[x][y] = GameTileSolid2SidesTR;
+ else if(top && !right && bottom && !left)
+ tiles[x][y] = GameTileSolid2SidesTB;
+ else if(top && !right && !bottom && left)
+ tiles[x][y] = GameTileSolid2SidesTL;
+ else if(!top && right && bottom && !left)
+ tiles[x][y] = GameTileSolid2SidesRB;
+ else if(!top && right && !bottom && left)
+ tiles[x][y] = GameTileSolid2SidesRL;
+ else if(!top && !right && bottom && left)
+ tiles[x][y] = GameTileSolid2SidesBL;
+ else if(top && !right && !bottom && !left)
+ tiles[x][y] = GameTileSolid1SidesT;
+ else if(!top && right && !bottom && !left)
+ tiles[x][y] = GameTileSolid1SidesR;
+ else if(!top && !right && bottom && !left)
+ tiles[x][y] = GameTileSolid1SidesB;
+ else if(!top && !right && !bottom && left)
+ tiles[x][y] = GameTileSolid1SidesL;
+ else if(!top && !right && !bottom && !left)
+ tiles[x][y] = GameTileSolid0Sides;
+ }
+ }
+ }
+}
+- (BOOL) loadGame {
+ if(![self isSavedGame])
+ return FALSE;
+
+ NSArray* savedGame = [NSArray arrayWithContentsOfFile:[self savedGamePath]];
+
+ // load saved game
+ stage = [[savedGame objectAtIndex:0] intValue];
+ difficulty = [[savedGame objectAtIndex:1] intValue];
+ options.difficulty = difficulty;
+ level = [[savedGame objectAtIndex:2] intValue];
+ movesLeft = [[savedGame objectAtIndex:4] intValue];
+
+ // tile string
+ strcpy(tileString, [[savedGame objectAtIndex:3] UTF8String]);
+
+ // keys are special (key string format is "x,y,used:x,y,used:x,y,used")
+ keys = [[NSMutableArray alloc] initWithCapacity:5];
+ NSString* keyString = [savedGame objectAtIndex:5];
+ NSMutableArray* keyPairs = [Helpers explodeDelimiter:@":" string:keyString];
+ int keyId = 0;
+ for(int i=0; i<[keyPairs count]; i++) {
+ NSMutableArray* keyPair = [Helpers explodeDelimiter:@"," string:[keyPairs objectAtIndex:i]];
+ GameDataKey* key = [[GameDataKey alloc] init];
+ key.x = [[keyPair objectAtIndex:0] intValue];
+ key.y = [[keyPair objectAtIndex:1] intValue];
+ key.used = (BOOL)[[keyPair objectAtIndex:2] intValue];
+ key.ident = keyId;
+ keyId++;
+
+ [keys addObject:key];
+ }
+
+ // set up the tiles
+ int x, y;
+ for(x=0; x<GAME_BOARD_WIDTH; x++)
+ for(y=0; y<GAME_BOARD_HEIGHT; y++)
+ tiles[x][y] = tileString[GAME_BOARD_WIDTH*y+x]-'A';
+
+ return TRUE;
+}
+- (void) saveGame {
+ // set up tile string
+ int x, y;
+ for(x=0; x<GAME_BOARD_WIDTH; x++)
+ for(y=0; y<GAME_BOARD_HEIGHT; y++)
+ tileString[GAME_BOARD_WIDTH*y+x] = tiles[x][y]+'A';
+ tileString[GAME_BOARD_WIDTH*GAME_BOARD_HEIGHT] = '\0';
+
+ // make the key string
+ NSString* keyString = @"";
+ for(int i=0; i<[keys count]; i++) {
+ GameDataKey* key = [keys objectAtIndex:i];
+ NSString* chunk = [NSString stringWithFormat:@"%i,%i,%i", key.x, key.y, key.used];
+ keyString = [keyString stringByAppendingString:chunk];
+ if(i < [keys count] - 1) {
+ keyString = [keyString stringByAppendingString:@":"];
+ }
+ }
+
+ // save the game
+ NSMutableArray* savedGame = [NSMutableArray arrayWithCapacity:5];
+ [savedGame addObject:[NSString stringWithFormat:@"%i", stage]];
+ [savedGame addObject:[NSString stringWithFormat:@"%i", difficulty]];
+ [savedGame addObject:[NSString stringWithFormat:@"%i", level]];
+ [savedGame addObject:[NSString stringWithFormat:@"%s", tileString]];
+ [savedGame addObject:[NSString stringWithFormat:@"%i", movesLeft]];
+ [savedGame addObject:[NSString stringWithFormat:@"%@", keyString]];
+ [savedGame writeToFile:[self savedGamePath] atomically:YES];
+}
+- (BOOL) isSavedGame {
+ return [[NSFileManager defaultManager] fileExistsAtPath:[self savedGamePath]];
+}
+
+- (void) deleteSavedGame {
+ [[NSFileManager defaultManager] removeItemAtPath:[self savedGamePath] error:nil];
+}
+
+// gameplay mechanics
+- (void) moveKeys:(int)dir {
+ int x, y, newX=-1, newY=-1;
+ int keysMoved = 0;
+ NSMutableArray* doorsSwitched = [NSMutableArray arrayWithCapacity:5];
+ unsigned int i,j;
+ GameDataKey* key;
+ GameDataKey* key2;
+ BOOL hitChest = FALSE; // debug
+
+ // loop through the keys
+ for(i=0; i < [keys count]; i++) {
+ key = (GameDataKey*)[keys objectAtIndex:i];
+ if(key.used == FALSE) {
+ // find the coordinates if the key moved
+ switch(dir) {
+ case GameDirLeft:
+ newX = key.x-1;
+ newY = key.y;
+ break;
+ case GameDirRight:
+ newX = key.x+1;
+ newY = key.y;
+ break;
+ case GameDirDown:
+ newX = key.x;
+ newY = key.y+1;
+ break;
+ }
+
+ // if it won't move off the board
+ if(newX >= 0 && newX < GAME_BOARD_WIDTH && newY >= 0 && newY < GAME_BOARD_HEIGHT) {
+ // if it hits nothing (or an open door), move it
+ if(tiles[newX][newY] == GameTileSpace || tiles[newX][newY] == GameTileDoorLROpen || tiles[newX][newY] == GameTileDoorTBOpen) {
+ key.x = newX;
+ key.y = newY;
+ keysMoved++;
+ }
+
+ // if it hits a chest, change it
+ else if(tiles[newX][newY] == GameTileChest) {
+ hitChest = TRUE; //debug
+ key.used = TRUE;
+ tiles[newX][newY] = GameTileChestOpen;
+ key.x = newX;
+ key.y = newY;
+ keysMoved++;
+ NSLog(@"GameData a key hit a chest!");
+
+ // play open chest sound
+ [sound playOpenChest];
+ }
+
+ // if it hits a door switch, open doors
+ else if(tiles[newX][newY] == GameTileSwitch) {
+ // move key
+ key.x = newX;
+ key.y = newY;
+ keysMoved++;
+ // toggle doors
+ [doorsSwitched addObject:[NSString stringWithFormat:@"%i,%i", newX, newY]];
+ NSLog(@"GameData a key hit a switch");
+ }
+ }
+ }
+ }
+
+ // now that the keys have moved, go back and undo any key stacking
+ BOOL keysAreStacked = TRUE;
+ while(keysAreStacked) {
+ keysAreStacked = FALSE;
+ // loop through keys
+ for(i=0; i<[keys count]; i++) {
+ key = (GameDataKey*)[keys objectAtIndex:i];
+
+ // if these keys aren't used yet
+ if(key.used == FALSE) {
+ // loop through keys again
+ for(j=0; j<[keys count]; j++) {
+ key2 = (GameDataKey*)[keys objectAtIndex:j];
+
+ // and if these ones aren't used
+ if(key2.used == FALSE) {
+ // and we're not looking at the same key
+ if(key.ident != key2.ident) {
+ // and if they have the same coordinates
+ if(key.x == key2.x && key.y == key2.y) {
+ NSLog(@"GameData keys are stacked, unstacking...");
+ keysAreStacked = TRUE;
+ switch(dir) {
+ case GameDirLeft:
+ newX = key.x+1;
+ newY = key.y;
+ keysMoved--;
+ break;
+ case GameDirRight:
+ newX = key.x-1;
+ newY = key.y;
+ keysMoved--;
+ break;
+ case GameDirDown:
+ newX = key.x;
+ newY = key.y-1;
+ keysMoved--;
+ break;
+ }
+ // if we unstack the key that hit the door, we didn't actually hit the door
+ if([doorsSwitched count] > 0) {
+ NSString* doorSwitchedString = [NSString stringWithFormat:@"%i,%i", key.x, key.y];
+ for(int index=0; index<[doorsSwitched count]; index++) {
+ if([(NSString*)[doorsSwitched objectAtIndex:index] compare:doorSwitchedString] == NSOrderedSame) {
+ NSLog(@"GameData nevermind, the key that hit the door switch moved back");
+ [doorsSwitched removeObjectAtIndex:index];
+ break;
+ }
+ }
+ }
+ key.x = newX;
+ key.y = newY;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // if doors have changed, lets make sure we haven't closed any doors on keys
+ if([doorsSwitched count] > 0) {
+ doorOpened = TRUE;
+ // play door sound
+ [sound playDoor];
+
+ // open/close doors
+ for(x=0; x<GAME_BOARD_WIDTH; x++) {
+ for(y=0; y<GAME_BOARD_HEIGHT; y++) {
+ // open closed doors
+ if(tiles[x][y] == GameTileDoorLRClosed) {
+ tiles[x][y] = GameTileDoorLROpen;
+ } else if(tiles[x][y] == GameTileDoorTBClosed) {
+ tiles[x][y] = GameTileDoorTBOpen;
+ }
+ // close open doors?
+ else if(tiles[x][y] == GameTileDoorLROpen || tiles[x][y] == GameTileDoorTBOpen) {
+ BOOL closeDoor = TRUE;
+ for(i=0; i<[keys count]; i++) {
+ key = (GameDataKey*)[keys objectAtIndex:i];
+
+ if(key.used == FALSE) {
+ // is there a key blocking this door?
+ if(key.x == x && key.y == y) {
+ closeDoor = FALSE;
+ NSLog(@"GameData can't close a door, there's a key in the way");
+ }
+ }
+ }
+ // if we're supposed to close, or we're supposed to not close a different door
+ if(closeDoor) {
+ // then close
+ if(tiles[x][y] == GameTileDoorLROpen) {
+ tiles[x][y] = GameTileDoorLRClosed;
+ } else {
+ tiles[x][y] = GameTileDoorTBClosed;
+ }
+ } else {
+ NSLog(@"close door should be FALSE, right?");
+ }
+ }
+ }
+ }
+ } else {
+ doorOpened = FALSE;
+ }
+
+ // if keys have indeed moved, substract from movesLeft
+ if(keysMoved > 0) {
+ movesLeft--;
+ // play key move sounds
+ [sound playKeyMove];
+ }
+
+ if(hitChest) {
+ hitChest = TRUE; // debug
+ }
+}
+- (BOOL) cannotMove {
+ int tile;
+ GameDataKey* key;
+
+ // loop through keys seeing if they can move
+ for(unsigned int i=0; i<[keys count]; i++) {
+ key = (GameDataKey*)[keys objectAtIndex:i];
+
+ if(key.used == FALSE) {
+ // left
+ if(key.x > 0) {
+ tile = tiles[key.x-1][key.y];
+ if((tile == GameTileSpace || tile == GameTileChest || tile == GameTileDoorLROpen || tile == GameTileDoorTBOpen || tile == GameTileSwitch) && ![self isKeyAtPositionX:key.x-1 andY:key.y]) {
+ return FALSE;
+ }
+ }
+
+ // right
+ if(key.x < GAME_BOARD_WIDTH-1) {
+ tile = tiles[key.x+1][key.y];
+ if((tile == GameTileSpace || tile == GameTileChest || tile == GameTileDoorLROpen || tile == GameTileDoorTBOpen || tile == GameTileSwitch) && ![self isKeyAtPositionX:key.x+1 andY:key.y]) {
+ return FALSE;
+ }
+ }
+
+ // down
+ if(key.y < GAME_BOARD_HEIGHT-1) {
+ tile = tiles[key.x][key.y+1];
+ if((tile == GameTileSpace || tile == GameTileChest || tile == GameTileDoorLROpen || tile == GameTileDoorTBOpen || tile == GameTileSwitch) && ![self isKeyAtPositionX:key.x andY:key.y+1]) {
+ return FALSE;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+- (BOOL) isKeyAtPositionX:(int)x andY:(int)y {
+ GameDataKey* key;
+ for(unsigned int i=0; i<[keys count]; i++) {
+ key = (GameDataKey*)[keys objectAtIndex:i];
+ if(key.x == x && key.y == y) return TRUE;
+ }
+ return FALSE;
+}
+
+- (void) beatLevel {
+ Level* l = (Level*)[levels.levels objectAtIndex:level-1];
+ l.complete = TRUE;
+ switch(difficulty) {
+ case GameDifficultyEasy: l.complete_easy = TRUE; break;
+ case GameDifficultyMedium: l.complete_medium = TRUE; break;
+ case GameDifficultyHard: l.complete_hard = TRUE; break;
+ }
+ [levels save];
+ NSLog(@"GameData marked level as complete");
+}
+
+// misc
+- (BOOL) stageLocked:(int)stageToCheck {
+ // levels per stage
+ int min, max;
+ switch(stageToCheck) {
+ default:
+ case GameStageCaves: // caves
+ min = 1; max = 30;
+ break;
+ case GameStageBeach: // beach
+ min = 31; max = 60;
+ break;
+ case GameStageShip: // pirate ship
+ min = 61; max = 90;
+ break;
+ }
+
+ // search the levels
+ BOOL locked = FALSE;
+ for(int i=min; i<=max; i++) {
+ if(![levels isComplete:i]) {
+ locked = TRUE;
+ break;
+ }
+ }
+ return locked;
+}
+- (int) stageForLevel:(int)levelToCheck {
+ if(levelToCheck <= 30)
+ return GameStageForest;
+ else if(levelToCheck >= 31 && levelToCheck <= 60)
+ return GameStageCaves;
+ else if(levelToCheck >= 61 && levelToCheck <= 90)
+ return GameStageBeach;
+ else
+ return GameStageShip;
+}
+
+- (NSString*) stageName {
+ if(stage == GameStageForest) return @"FOREST";
+ else if(stage == GameStageCaves) return @"CAVES";
+ else if(stage == GameStageBeach) return @"BEACH";
+ else return @"SHIP";
+}
+
+// memory
+- (void) freeKeys {
+ /*for(NSUInteger i=0; i<[keys count]; i++) {
+ [[keys objectAtIndex:i] dealloc];
+ }*/
+ [keys dealloc];
+}
+
+
+
+@end
24 Classes/GameDataKey.h
@@ -0,0 +1,24 @@
+//
+// GameDataKey.h
+// Skeleton Key
+//
+// Created by micah on 12/31/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+
+@interface GameDataKey : NSObject {
+ int x;
+ int y;
+ bool used;
+ int ident;
+}
+
+@property (readwrite) int x;
+@property (readwrite) int y;
+@property (readwrite) bool used;
+@property (readwrite) int ident;
+
+@end
19 Classes/GameDataKey.m
@@ -0,0 +1,19 @@
+//
+// GameDataKey.m
+// Skeleton Key
+//
+// Created by micah on 12/31/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import "GameDataKey.h"
+
+
+@implementation GameDataKey
+
+@synthesize x;
+@synthesize y;
+@synthesize used;
+@synthesize ident;
+
+@end
27 Classes/GameMenuScene.h
@@ -0,0 +1,27 @@
+//
+// GameMenuScene.h
+// Skeleton Key HD
+//
+// Created by micah on 1/4/11.
+// Copyright 2011 __MyCompanyName__. All rights reserved.
+//
+
+#import "cocos2d.h"
+#import "Sound.h"
+#import "GameData.h"
+
+@interface GameMenuScene : CCLayer {
+ Sound* sound;
+ GameData* gameData;
+}
+
++ (id) scene;
+
+// buttons
+- (void) onResume:(id)sender;
+- (void) onRestart:(id)sender;
+- (void) onChoose:(id)sender;
+- (void) onOptions:(id)sender;
+- (void) onMainMenu:(id)sender;
+
+@end
135 Classes/GameMenuScene.m
@@ -0,0 +1,135 @@
+//
+// GameMenu.m
+// Skeleton Key HD
+//
+// Created by micah on 1/4/11.
+// Copyright 2011 __MyCompanyName__. All rights reserved.
+//
+
+#import "GameMenuScene.h"
+#import "SkeletonKeyAppDelegate.h"
+#import "MenuScene.h"
+#import "OptionsScene.h"
+#import "GameScene.h"
+#import "MapScene.h"
+
+@implementation GameMenuScene
+
++ (id) scene {
+ CCScene* scene = [CCScene node];
+ GameMenuScene* layer = [GameMenuScene node];
+ [scene addChild:layer];
+ return scene;
+}
+
+- (id) init {
+ if((self=[super init])) {
+ NSLog(@"GameMenuScene init");
+
+ sound = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate)).sound;
+ gameData = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate)).gameData;
+
+ // background
+ CCSprite* background = [CCSprite spriteWithFile:@"background_forest_light.png"];
+ background.position = ccp(160, 240);
+ [self addChild:background];
+
+ // header
+ CCSprite* header = [CCSprite spriteWithFile:@"game_menu_header.png"];
+ header.position = ccp(160, 420);
+ [self addChild:header z:1];
+
+ // status
+ CCSprite* statusBackground = [CCSprite spriteWithFile:@"game_menu_status_background.png"];
+ statusBackground.position = ccp(160, 335);
+ [self addChild:statusBackground z:1];
+ CCLabelTTF* statusLabel = [CCLabelTTF labelWithString:[NSString stringWithFormat:@"%@ * LEVEL %i", [gameData stageName], gameData.level] fontName:@"gabriola.ttf" fontSize:25];
+ statusLabel.color = ccc3(147,213,18);
+ statusLabel.position = ccp(160, 330);
+ [self addChild:statusLabel z:2];
+
+ // top menu
+ CCMenuItemImage* resume = [CCMenuItemImage itemFromNormalImage:@"game_menu_resume.png"
+ selectedImage:@"game_menu_resume2.png"
+ target:self
+ selector:@selector(onResume:)];
+ CCMenuItemImage* restart = [CCMenuItemImage itemFromNormalImage:@"game_menu_restart.png"
+ selectedImage:@"game_menu_restart2.png"
+ target:self
+ selector:@selector(onRestart:)];
+ CCMenuItemImage* choose = [CCMenuItemImage itemFromNormalImage:@"game_menu_choose.png"
+ selectedImage:@"game_menu_choose2.png"
+ target:self
+ selector:@selector(onChoose:)];
+ CCMenu* top_menu = [CCMenu menuWithItems:resume, restart, choose, nil];
+ [top_menu alignItemsVerticallyWithPadding:0];
+ top_menu.position = ccp(160, 234.5);
+ [self addChild: top_menu z:2];
+
+ // bottom menu
+ CCMenuItemImage* options = [CCMenuItemImage itemFromNormalImage:@"game_menu_options.png"
+ selectedImage:@"game_menu_options2.png"
+ target:self
+ selector:@selector(onOptions:)];
+ CCMenuItemImage* main_menu = [CCMenuItemImage itemFromNormalImage:@"game_menu_main.png"
+ selectedImage:@"game_menu_main2.png"
+ target:self
+ selector:@selector(onMainMenu:)];
+ CCMenu* bottom_menu = [CCMenu menuWithItems:options, main_menu, nil];
+ [bottom_menu alignItemsVerticallyWithPadding:0];
+ bottom_menu.position = ccp(160, 80);
+ [self addChild: bottom_menu z:2];
+ }
+ return self;
+}
+
+- (void) onResume:(id)sender {
+ NSLog(@"GameMenuScene onResume");
+ [sound playClick];
+ [gameData loadGame];
+ [[CCDirector sharedDirector] replaceScene:[CCTransitionPageTurn transitionWithDuration:0.3 scene:[GameScene scene] backwards:YES]];
+}
+
+- (void) onRestart:(id)sender {
+ NSLog(@"GameMenuScene onRestart");
+ [sound playRestartLevel];
+ [gameData loadLevel];
+ [gameData saveGame];
+ [[CCDirector sharedDirector] replaceScene:[CCTransitionPageTurn transitionWithDuration:0.3 scene:[GameScene scene] backwards:YES]];
+}
+
+- (void) onChoose:(id)sender {
+ NSLog(@"GameMenuScene onChoose");
+ [sound playClick];
+ gameData.returnToGame = TRUE;
+ [[CCDirector sharedDirector] replaceScene:[CCTransitionPageTurn transitionWithDuration:0.3 scene:[MapScene scene] backwards:YES]];
+}
+
+- (void) onOptions:(id)sender {
+ NSLog(@"GameMenuScene onOptions");
+ [sound playClick];
+ gameData.returnToGame = TRUE;
+ [gameData loadGame];
+ [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:0.3 scene:[OptionsScene scene]]];
+}
+
+- (void) onMainMenu:(id)sender {
+ NSLog(@"GameMenuScene onMainMenu");
+ [sound playClick];
+
+ // delete saved game
+ [gameData deleteSavedGame];
+
+ // change music
+ [sound startMusicMenu];
+
+ // go to menu
+ [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:0.3 scene:[MenuScene scene]]];
+}
+
+- (void) dealloc {
+ NSLog(@"GameMenuScene dealloc");
+ [super dealloc];
+}
+
+@end
70 Classes/GameScene.h
@@ -0,0 +1,70 @@
+//
+// GameScene.h
+// Skeleton Key
+//
+// Created by micah on 12/30/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import "cocos2d.h"
+#import <UIKit/UIKit.h>
+#import "Sound.h"
+#import "Options.h"
+#import "GameData.h"
+#import "Achievements.h"
+#import "Levels.h"
+#import "GameTile.h"
+#import "Helpers.h"
+
+// tags
+typedef enum {
+ GameTagMoves = 1,
+ GameTagLevelCompleteBackground = 2,
+ GameTagLevelComplete = 3,
+ GameTagLevelCompleteLabel = 4,
+ GameTagLevelCompletePerfect = 5,
+ GameTagAchievementLayer = 6,
+ GameTagMessage = 7,
+ GameTagTiles = 100,
+ GameTagKeys = 200
+} GameTags;
+
+// messages
+typedef enum {
+ GameMessageNoMessage = 0,
+ GameMessageSwipeScreen = 1,
+ GameMessageNoMovesMenu = 2,
+ GameMessageNoMovesShake = 3
+} GameMessages;
+
+@interface GameScene : CCLayer {
+ Sound* sound;
+ Options* options;
+ GameData* gameData;
+ Achievements* achievements;
+ Levels* levels;
+
+ int message;
+ BOOL won;
+ BOOL firstMove;
+ BOOL isAchievementActive;
+
+ CGPoint touchStart;
+}
+
++ (id) scene;
+
+- (void) setCurrentGame;
+- (void) unsetCurrentGame;
+
+- (void) restartLevel;
+- (void) moveKeys:(int)dir;
+- (void) onCompletedLevel:(id)sender;
+- (void) messageDisplay:(int)messageToDisplay;
+- (void) onRemoveMessage:(id)sender;
+- (void) unlockAchievement:(int)achievementId;
+- (void) onRemoveAchievement:(id)sender;
+- (void) onMenu:(id)sender;
+- (void) shake;
+
+@end
536 Classes/GameScene.m
@@ -0,0 +1,536 @@
+//
+// GameScene.m
+// Skeleton Key
+//
+// Created by micah on 12/30/10.
+// Copyright 2010 __MyCompanyName__. All rights reserved.
+//
+
+#import "GameScene.h"
+#import "SkeletonKeyAppDelegate.h"
+#import "GameMenuScene.h"
+#import "MapScene.h"
+#import "SelectLevelScene.h"
+#import "MenuScene.h"
+
+@implementation GameScene
+
++ (id) scene {
+ CCScene* scene = [CCScene node];
+ GameScene* layer = [GameScene node];
+ [scene addChild:layer];
+ return scene;
+}
+
+- (id) init {
+ if((self=[super init])) {
+ NSLog(@"GameScene init");
+
+ [[UIAccelerometer sharedAccelerometer] setDelegate:self];
+
+ sound = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate)).sound;
+ options = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate)).options;
+ gameData = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate)).gameData;
+ achievements = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate)).achievements;
+ levels = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate)).levels;
+ self.isTouchEnabled = YES;
+
+ // set the game as active
+ gameData.activeGame = TRUE;
+
+ // start the level
+ [self restartLevel];
+ }
+ return self;
+}
+
+- (void) setCurrentGame {
+ // let the applicatin know who's in charge
+ SkeletonKeyAppDelegate* delegate = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate));
+ delegate.currentGame = self;
+}
+- (void) unsetCurrentGame {
+ // stop letting the applicatin know who's in charge
+ SkeletonKeyAppDelegate* delegate = ((SkeletonKeyAppDelegate*)([UIApplication sharedApplication].delegate));
+ delegate.currentGame = nil;
+}
+
+- (void) dealloc {
+ NSLog(@"GameScene dealloc");
+
+ gameData.activeGame = FALSE;
+ [gameData saveGame];
+ [super dealloc];
+}
+
+- (void) restartLevel {
+ // in case we've already been playing
+ [self removeAllChildrenWithCleanup:YES];
+ [self setCurrentGame];
+
+ // background
+ CCSprite* background;
+ NSString* backgroundFilename;
+ switch(gameData.stage) {
+ case GameStageForest: backgroundFilename = @"game_background_forest.png"; break;
+ case GameStageCaves: backgroundFilename = @"game_background_caves.png"; break;
+ case GameStageBeach: backgroundFilename = @"game_background_beach.png"; break;
+ case GameStageShip: backgroundFilename = @"game_background_ship.png"; break;
+ }
+ background = [CCSprite spriteWithFile:backgroundFilename];
+ background.position = ccp(160, 240);
+ [self addChild:background z:0];
+
+ // the frame
+ CCSprite* frame = [CCSprite spriteWithFile:@"game_frame.png"];
+ frame.position = ccp(160, 240);
+ [self addChild:frame z:3];
+
+ // menu button
+ CCMenuItemImage* menuItem = [CCMenuItemImage itemFromNormalImage:@"game_menu.png"
+ selectedImage:@"game_menu2.png"
+ target:self selector:@selector(onMenu:)];
+ CCMenu* menu = [CCMenu menuWithItems:menuItem, nil];
+ [menu alignItemsVerticallyWithPadding:0];
+ menu.position = ccp(54.5, 450.5);
+ [self addChild:menu z:4];
+
+ // heads up display
+ CCLabelTTF* level = [CCLabelTTF labelWithString:[NSString stringWithFormat:@"%i", [gameData level]] fontName:@"deutsch.ttf" fontSize:20];
+ level.position = ccp(160, 458);
+ [self addChild:level z:4];
+ CCLabelTTF* moves = [CCLabelTTF labelWithString:[NSString stringWithFormat:@"%i", [gameData movesLeft]] fontName:@"deutsch.ttf" fontSize:20];
+ moves.position = ccp(262, 458);
+ [self addChild:moves z:4 tag:GameTagMoves];
+
+ // draw the tiles
+ int x,y;
+ GameTile* tile;
+ for(x=0; x<GAME_BOARD_WIDTH; x++) {
+ for(y=0; y<GAME_BOARD_HEIGHT; y++) {
+ int tileType = [gameData getTileTypeX:x andY:y];
+ if(tileType != GameTileSpace) {
+ tile = [GameTile tileWithType:tileType andX:x andY:y];
+ [self addChild:tile z:2 tag:GameTagTiles+(GAME_BOARD_WIDTH*y+x)];
+ }
+ }
+ }
+
+ // draw the keys
+ for(int i=0; i < [gameData.keys count]; i++) {
+ GameDataKey* key = [gameData.keys objectAtIndex:i];
+ if(!key.used) {
+ tile = [GameTile tileWithType:GameTileKey andX:key.x andY:key.y];
+ [self addChild:tile z:2 tag:GameTagKeys+i];
+ }
+ }
+
+ // check for winning
+ won = FALSE;
+
+ // message
+ if(gameData.level == 1) {
+ [self messageDisplay:GameMessageSwipeScreen];
+ }
+
+ // only save the game if a move has been made
+ firstMove = FALSE;
+
+ // achievements
+ isAchievementActive = FALSE;
+}
+
+- (void) moveKeys:(int)dir {
+ if(won) return;
+
+ firstMove = TRUE;
+
+ int movesLeft = gameData.movesLeft;
+ if(movesLeft == 0) {
+ // out of moves, sorry
+ if(options.shake) {
+ [self messageDisplay:GameMessageNoMovesShake];
+ } else {
+ [self messageDisplay:GameMessageNoMovesMenu];
+ }
+ return;
+ }
+
+ // update moves left label?
+ [gameData moveKeys:dir];
+ if(gameData.doorOpened) {
+ // achievement "Knock Knock"
+ [self unlockAchievement:AchievementKnockKnock];
+ achievements.doorsOpened++;
+ [achievements save];
+
+ // check for achievement "The Doorman"
+ if(achievements.doorsOpened == 50) {
+ [self unlockAchievement:AchievementTheDoorman];
+ }
+
+ // check for achievement "The Door to Nowhere"
+ if(gameData.level == 85) {
+ [self unlockAchievement:AchievementTheDoorToKnowhere];
+ }
+ }
+ if(gameData.movesLeft != movesLeft) {
+ CCLabelTTF* moves = (CCLabelTTF*)[self getChildByTag:GameTagMoves];
+ [moves setString:[NSString stringWithFormat:@"%i", gameData.movesLeft]];
+ }
+
+ // update the tiles, keys
+ for(int x2=0; x2<GAME_BOARD_WIDTH; x2++) {
+ for(int y2=0; y2<GAME_BOARD_HEIGHT; y2++) {
+ GameTile* tile = (GameTile*)[self getChildByTag:GameTagTiles+(GAME_BOARD_WIDTH*y2+x2)];
+ if(tile != nil) {
+ int tileType = [gameData getTileTypeX:x2 andY:y2];
+ if(tileType != tile.tileType) {
+ [tile changeType:tileType];
+ }
+ }
+ }
+ }
+ // update the keys
+ for(int i=0; i<[gameData.keys count]; i++) {
+ GameTile* tile = (GameTile*)[self getChildByTag:GameTagKeys+i];
+ if(tile != nil) {
+ // if it's used now, remove it
+ GameDataKey* key = (GameDataKey*)[gameData.keys objectAtIndex:i];
+ if(key.used) {
+ [self removeChildByTag:GameTagKeys+i cleanup:YES];
+ } else {
+ // if the key has moved, update it
+ if(tile.x != key.x || tile.y != key.y)
+ [tile changePositionX:key.x andY:key.y];
+ }
+ }
+ }
+
+ // check for a win
+ BOOL checkForWin = TRUE;
+ for(int i=0; i<[gameData.keys count]; i++) {
+ GameDataKey* key = (GameDataKey*)[gameData.keys objectAtIndex:i];
+ if(key.used == FALSE)
+ checkForWin = FALSE;
+ }
+ if(checkForWin) {
+ won = TRUE;
+ [self runAction:[CCSequence actions:[CCDelayTime actionWithDuration:0.01], [CCCallFunc actionWithTarget:self selector:@selector(onCompletedLevel:)], nil]];
+ } else {
+ // check for stuck
+ if([gameData cannotMove]) {
+ if(options.shake) {
+ [self messageDisplay:GameMessageNoMovesShake];
+ } else {
+ [self messageDisplay:GameMessageNoMovesMenu];
+ }
+ }
+ }
+}
+
+- (void) onCompletedLevel:(id)sender {
+ NSLog(@"GameScene level complete!");
+ [self messageDisplay:GameMessageNoMessage];
+
+ // display the level complete nodes
+ CCLayerColor* levelCompleteLayer = [CCLayerColor layerWithColor:ccc4(0, 0, 0, 0)];
+ [levelCompleteLayer runAction:[CCFadeTo actionWithDuration:1.0 opacity:196]];
+ [self addChild:levelCompleteLayer z:5];
+ CCSprite* levelCompleteMessage = [CCSprite spriteWithFile:@"game_level_complete.png"];
+ [levelCompleteMessage runAction:[CCFadeIn actionWithDuration:0.5]];
+ levelCompleteMessage.position = ccp(160, 217);
+ [levelCompleteLayer addChild:levelCompleteMessage];
+
+
+ // figure out the level complete text
+ CCLabelTTF* levelCompleteLabel;
+ CCLabelTTF* levelCompleteLabel2;
+ CCLabelTTF* levelCompleteLabel3;
+ NSString* completeText;
+ int moves = gameData.movesLeft;
+ switch(gameData.difficulty) {
+ case GameDifficultyEasy: moves -= 10; break;
+ case GameDifficultyMedium: moves -= 6; break;
+ case GameDifficultyHard: moves -= 2; break;
+ }
+ moves *= -1;
+ if(moves <= 0) {
+ levelCompleteLabel = [CCLabelTTF labelWithString: @"Perfect!" fontName:@"gabriola.ttf" fontSize:35];
+ [levelCompleteLabel runAction:[CCFadeIn actionWithDuration:0.5]];
+ levelCompleteLabel.position = ccp(160, 160);
+ [levelCompleteLayer addChild:levelCompleteLabel];
+
+ CCSprite* levelCompletePerfect = [CCSprite spriteWithFile:@"game_level_complete_perfect.png"];
+ levelCompletePerfect.position = ccp(160, 204);
+ [levelCompletePerfect runAction:[CCFadeIn actionWithDuration:0.5]];
+ [levelCompleteLayer addChild:levelCompletePerfect];
+
+ // update level to be perfect
+ [levels markAsPerfect:gameData.level];
+
+ // check for perfectionist achievement
+ int perfectLevels = [levels perfectLevels];
+ if(perfectLevels >= 10) {
+ [self unlockAchievement:AchievementPerfectionist];
+ }
+ // check for professional perfectionist achievement
+ if(perfectLevels >= 30) {
+ [self unlockAchievement:AchievementProfessionalPerfectionist];
+ }
+ // check for mastermind
+ if(perfectLevels >= TOTAL_LEVELS) {
+ [self unlockAchievement:AchievementMastermind];
+ }
+ } else {
+ levelCompleteLabel = [CCLabelTTF labelWithString: @"Good Job!" fontName:@"gabriola.ttf" fontSize:30];
+ [levelCompleteLabel runAction:[CCFadeIn actionWithDuration:0.5]];
+ levelCompleteLabel.position = ccp(160, 210);
+ [levelCompleteLayer addChild:levelCompleteLabel];
+
+ if(moves == 1)
+ completeText = @"1 Move Away";
+ else
+ completeText = [NSString stringWithFormat:@"%i Moves Away", moves];
+ levelCompleteLabel2 = [CCLabelTTF labelWithString: completeText fontName:@"gabriola.ttf" fontSize:30];
+ [levelCompleteLabel2 runAction:[CCFadeIn actionWithDuration:0.5]];
+ levelCompleteLabel2.position = ccp(160, 177);
+ [levelCompleteLayer addChild:levelCompleteLabel2];
+
+ levelCompleteLabel3 = [CCLabelTTF labelWithString: @"From Perfect" fontName:@"gabriola.ttf" fontSize:30];
+ [levelCompleteLabel3 runAction:[CCFadeIn actionWithDuration:0.5]];
+ levelCompleteLabel3.position = ccp(160, 144);
+ [levelCompleteLayer addChild:levelCompleteLabel3];
+ }
+
+ [gameData beatLevel];
+
+ // delete the saved game - if they continue, then load the next one
+ [gameData deleteSavedGame];
+
+ // check for "Begin the Hunt" achievement
+ BOOL beginTheHunt = TRUE;
+ for(int i=0; i<10; i++) {
+ Level* l = (Level*)[levels.levels objectAtIndex:i];
+ if(l.complete == FALSE) {
+ beginTheHunt = FALSE;
+ break;
+ }
+ }
+ if(beginTheHunt) [self unlockAchievement:AchievementBeginTheHunt];
+
+ // check for "Enter the Darkness" achievement
+ BOOL enterTheDarkness = TRUE;
+ for(int i=0; i<30; i++) {
+ Level* l = (Level*)[levels.levels objectAtIndex:i];
+ if(l.complete == FALSE) {
+ enterTheDarkness = FALSE;
+ break;
+ }
+ }
+ if(enterTheDarkness) [self unlockAchievement:AchievementEnterTheDarkness];
+
+ // check for "Enjoy the Sun" achievement
+ BOOL enjoyTheSun = TRUE;
+ for(int i=30; i<60; i++) {
+ Level* l = (Level*)[levels.levels objectAtIndex:i];
+ if(l.complete == FALSE) {
+ enjoyTheSun = FALSE;
+ break;
+ }
+ }
+ if(enjoyTheSun) [self unlockAchievement:AchievementEnjoyTheSun];
+
+ // check for "Arrrgh!" achievement
+ BOOL arrrgh = TRUE;
+ for(int i=60; i<90; i++) {
+ Level* l = (Level*)[levels.levels objectAtIndex:i];
+ if(l.complete == FALSE) {
+ arrrgh = FALSE;
+ break;
+ }
+ }
+ if(arrrgh) [self unlockAchievement:AchievementArrrgh];
+
+ // check for difficulty achievements
+ BOOL treasureHunter = TRUE;
+ BOOL anAdventurerIsYou = TRUE;
+ BOOL intrepidExplorer = TRUE;
+ // check for "Treasure Hunter" achievement
+ for(int i=0; i<120; i++) {
+ Level* l = (Level*)[levels.levels objectAtIndex:i];
+ if(l.complete_easy == FALSE) treasureHunter = FALSE;
+ if(l.complete_medium == FALSE) anAdventurerIsYou = FALSE;
+ if(l.complete_hard == FALSE) intrepidExplorer = FALSE;
+ if(!treasureHunter && !anAdventurerIsYou && !intrepidExplorer) break;
+ }
+ if(treasureHunter) [self unlockAchievement:AchievementTreasureHunter];
+ if(anAdventurerIsYou) [self unlockAchievement:AchievementAnAdventurerIsYou];
+ if(intrepidExplorer) [self unlockAchievement:AchievementIntrepidExplorer];
+}
+
+- (void) messageDisplay:(int)messageToDisplay {
+ message = messageToDisplay;
+ CCSprite* spriteMessage = (CCSprite*)[self getChildByTag:GameTagMessage];
+ if(spriteMessage != nil) {
+ [self removeChildByTag:GameTagMessage cleanup:YES];
+ spriteMessage = nil;
+ }
+
+ // which message?
+ switch(messageToDisplay) {
+ case GameMessageNoMessage:
+ NSLog(@"GameScene getting rid of message");
+ break;
+ case GameMessageSwipeScreen:
+ NSLog(@"GameScene display message intro");
+ spriteMessage = [CCSprite spriteWithFile:@"game_message_intro.png"];
+ spriteMessage.position = ccp(160, 242);
+ break;
+ case GameMessageNoMovesMenu:
+ NSLog(@"GameScene display message no moves menu");
+ spriteMessage = [CCSprite spriteWithFile:@"game_message_no_moves_menu.png"];
+ spriteMessage.position = ccp(160, 293.5);
+ break;
+ case GameMessageNoMovesShake:
+ NSLog(@"GameScene display message no moves shake");
+ spriteMessage = [CCSprite spriteWithFile:@"game_message_no_moves_shake.png"];
+ spriteMessage.position = ccp(160, 293.5);
+ break;
+ }
+ if(spriteMessage != nil) {
+ spriteMessage.opacity = 0;
+ [spriteMessage runAction:[CCSequence actions:
+ [CCFadeIn actionWithDuration:1.0],
+ [CCDelayTime actionWithDuration:3.0],
+ [CCFadeOut actionWithDuration:1.0],
+ [CCCallFunc actionWithTarget:self selector:@selector(onRemoveMessage:)],
+ nil]];
+ [self addChild:spriteMessage z:5 tag:GameTagMessage];
+ }
+}
+
+- (void) onRemoveMessage:(id)sender {
+ [self removeChildByTag:GameTagMessage cleanup:YES];
+}
+
+- (void) unlockAchievement:(int)achievementId {
+ // unlock it
+ if([achievements unlock:achievementId]) {
+ [sound playUnlockAchievement];
+
+ // create achievement layer
+ CCLayer* achievementLayer = [CCLayer node];
+ [self addChild:achievementLayer z:5 tag:GameTagAchievementLayer];
+
+ // add background and labels to it
+ CCSprite* achievementBackground = [CCSprite spriteWithFile:@"game_achievement_background.png"];
+ achievementBackground.position = ccp(160, 108);
+ [achievementLayer addChild:achievementBackground z:0];
+ CCLabelTTF* achievementTitle = [CCLabelTTF labelWithString:[achievements getName:achievementId] fontName:@"gabriola.ttf" fontSize:26];
+ achievementTitle.color = ccc3(255, 255, 255);
+ achievementTitle.position = ccp(211, 61);
+ [achievementLayer addChild:achievementTitle z:1];
+ CCLabelTTF* achievementDesc = [CCLabelTTF labelWithString:[achievements getDescription:achievementId] fontName:@"gabriola.ttf" fontSize:20];
+ achievementDesc.color = ccc3(196, 207, 226);
+ achievementDesc.position = ccp(211, 37);
+ [achievementLayer addChild:achievementDesc z:1];
+
+ // animate it
+ achievementLayer.position = ccp(0, -220);
+ [achievementLayer runAction:[CCSequence actions:
+ [CCMoveTo actionWithDuration:1.0 position:ccp(0, 0)],
+ [CCDelayTime actionWithDuration:2.0],
+ [CCMoveTo actionWithDuration:1.0 position:ccp(0, -220)],
+ [CCCallFunc actionWithTarget:self selector:@selector(onRemoveAchievement:)],
+ nil]];
+ }
+}
+
+- (void) onRemoveAchievement:(id)sender {
+ [self removeChildByTag:GameTagAchievementLayer cleanup:YES];
+}
+
+- (void) onMenu:(id)sender {
+ if(won) return;
+ NSLog(@"GameScene onMenu");
+ [sound playClick];
+ [self unsetCurrentGame];
+ [[CCDirector sharedDirector] replaceScene:[CCTransitionPageTurn transitionWithDuration:0.3 scene:[GameMenuScene scene]]];
+}
+
+- (void) registerWithTouchDispatcher {
+ [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
+}
+
+- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
+ touchStart = [self convertTouchToNodeSpace:touch];
+ return YES;
+}
+
+- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
+ CGPoint touchEnd = [self convertTouchToNodeSpace:touch];
+
+ // remove swipe message, if it's there
+ if(message == GameMessageSwipeScreen) [self messageDisplay:GameMessageNoMessage];
+
+ // if the game has been won, ignore other touches and load next level
+ if(won) {
+ // if this is the last level, return to main menu
+ if(gameData.level == TOTAL_LEVELS) {
+ [sound playClick];
+ [sound startMusicMenu];
+ [self unsetCurrentGame];
+ [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:0.3 scene:[MenuScene scene]]];
+ } else {
+ // play click, change music
+ [sound playClick];
+ [sound startMusicGameplay];
+
+ // load the next level
+ int stage = [gameData stageForLevel:gameData.level];
+ int nextLevelStage = [gameData stageForLevel:gameData.level+1];
+ if(stage != nextLevelStage) {
+ // if the next stage is locked, go to select level scene instead
+ if([gameData stageLocked:nextLevelStage]) {
+ [self unsetCurrentGame];
+ [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:0.3 scene:[SelectLevelScene scene]]];
+ return;
+ } else {
+ // otherwise go to the map scene
+ [self unsetCurrentGame];
+ [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:0.3 scene:[MapScene sceneWithStage:nextLevelStage]]];
+ }
+ } else {
+ gameData.level++;
+ [gameData loadLevel];
+ [self restartLevel];
+ }
+ }
+ return;
+ }
+
+ // handle other touches
+ int direction = [Helpers swipeDirectionStart:touchStart end:touchEnd];
+ switch(direction) {
+ case GameDirUp: NSLog(@"GameScene swiped up"); break;
+ case GameDirDown: NSLog(@"GameScene swiped down"); break;
+ case GameDirLeft: NSLog(@"GameScene swiped left"); break;
+ case GameDirRight: NSLog(@"GameScene swiped right"); break;
+ }
+ if(direction == GameDirLeft || direction == GameDirRight || direction == GameDirDown) {
+ [self moveKeys:direction];
+ }
+}
+
+- (void) shake {
+ if(options.shake && firstMove) {
+ NSLog(@"GameScene shake detected, restarting level");
+ [sound playRestartLevel];
+ [gameData loadLevel];
+ [self restartLevel];
+ }
+}
+
+
+@end
25 Classes/GameTile.h
@@ -0,0 +1,25 @@
+//
+// GameTile.h
+// Skeleton Key
+//
+// Created by micah on 1/8/11.
+// Copyright 2011 __MyCompanyName__. All rights reserved.
+//
+
+#import "cocos2d.h"
+
+@interface GameTile : CCSprite {
+ int x;
+ int y;
+ int tileType;
+}
+
+@property (readwrite) int x;
+@property (readwrite) int y;
+@property (readwrite) int tileType;
+
++ (id) tileWithType:(int)tileType andX:(int)x andY:(int)y;
+- (void) changeType:(int)_tileType;
+- (void) changePositionX:(int)_x andY:(int)_y;
+
+@end
77 Classes/GameTile.m
@@ -0,0 +1,77 @@
+//
+// GameTile.m
+// Skeleton Key
+//
+// Created by micah on 1/8/11.
+// Copyright 2011 __MyCompanyName__. All rights reserved.
+//
+
+#import "GameTile.h"
+#import "GameData.h"
+#import "SkeletonKeyAppDelegate.h"
+
+@implementation GameTile
+
+@synthesize x;