18 * File created on 18/04/2011. |
18 * File created on 18/04/2011. |
19 */ |
19 */ |
20 |
20 |
21 |
21 |
22 #import "GameInterfaceBridge.h" |
22 #import "GameInterfaceBridge.h" |
23 #import "ServerSetup.h" |
|
24 #import "EngineProtocolNetwork.h" |
23 #import "EngineProtocolNetwork.h" |
25 #import "OverlayViewController.h" |
24 #import "OverlayViewController.h" |
26 #import "StatsPageViewController.h" |
25 #import "StatsPageViewController.h" |
27 #import "AudioManagerController.h" |
26 #import "AudioManagerController.h" |
28 #import "ObjcExports.h" |
27 #import "ObjcExports.h" |
29 |
28 |
30 @implementation GameInterfaceBridge |
29 @implementation GameInterfaceBridge |
31 @synthesize parentController, savePath, overlayController, engineProtocol, ipcPort, gameType; |
30 @synthesize blackView; |
32 |
|
33 -(id) initWithController:(id) viewController { |
|
34 if (self = [super init]) { |
|
35 self.ipcPort = [ServerSetup randomPort]; |
|
36 self.gameType = gtNone; |
|
37 self.savePath = nil; |
|
38 |
|
39 self.parentController = (UIViewController *)viewController; |
|
40 self.engineProtocol = [[EngineProtocolNetwork alloc] initOnPort:self.ipcPort]; |
|
41 self.engineProtocol.delegate = self; |
|
42 |
|
43 self.overlayController = [[OverlayViewController alloc] initWithNibName:@"OverlayViewController" bundle:nil]; |
|
44 } |
|
45 return self; |
|
46 } |
|
47 |
|
48 -(void) dealloc { |
|
49 releaseAndNil(engineProtocol); |
|
50 releaseAndNil(savePath); |
|
51 releaseAndNil(overlayController); |
|
52 [super dealloc]; |
|
53 } |
|
54 |
31 |
55 #pragma mark - |
32 #pragma mark - |
56 // overlay with controls, become visible later, with a transparency effect since the sdlwindow is not yet created |
33 #pragma mark Instance methods for engine interaction |
57 -(void) displayOverlayLater:(id) object { |
34 // prepares the controllers for hosting a game |
58 // in order to get rotation events we have to insert the view inside the first view of the second window |
35 -(void) earlyEngineLaunch:(NSString *)pathOrNil withOptions:(NSDictionary *)optionsOrNil { |
59 // when multihead we have to make sure that overlay is displayed in the touch-enabled window |
36 [self retain]; |
60 UIView *injected = (IS_DUALHEAD() ? self.parentController.view : UIVIEW_HW_SDLVIEW); |
37 [AudioManagerController stopBackgroundMusic]; |
61 [injected addSubview:self.overlayController.view]; |
38 [EngineProtocolNetwork spawnThread:pathOrNil withOptions:optionsOrNil]; |
|
39 |
|
40 // add a black view hiding the background |
|
41 CGRect theFrame = [[UIScreen mainScreen] bounds]; |
|
42 UIWindow *thisWindow = [[HedgewarsAppDelegate sharedAppDelegate] uiwindow]; |
|
43 self.blackView = [[UIView alloc] initWithFrame:theFrame]; |
|
44 self.blackView.opaque = YES; |
|
45 self.blackView.backgroundColor = [UIColor blackColor]; |
|
46 self.blackView.alpha = 0; |
|
47 [UIView beginAnimations:@"fade out" context:NULL]; |
|
48 [UIView setAnimationDuration:1]; |
|
49 self.blackView.alpha = 1; |
|
50 [UIView commitAnimations]; |
|
51 [thisWindow addSubview:self.blackView]; |
|
52 [self.blackView release]; |
|
53 |
|
54 // keep track of uncompleted games |
|
55 NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; |
|
56 [userDefaults setObject:pathOrNil forKey:@"savedGamePath"]; |
|
57 [userDefaults synchronize]; |
|
58 |
|
59 // let's launch the engine using this -perfomSelector so that the runloop can deal with queued messages first |
|
60 [self performSelector:@selector(engineLaunch:) withObject:pathOrNil afterDelay:0.1f]; |
|
61 } |
|
62 |
|
63 // cleans up everything |
|
64 -(void) lateEngineLaunch { |
|
65 // remove completed games notification |
|
66 NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; |
|
67 [userDefaults setObject:@"" forKey:@"savedGamePath"]; |
|
68 [userDefaults synchronize]; |
|
69 |
|
70 // remove the cover view with a transition |
|
71 self.blackView.alpha = 1; |
|
72 [UIView beginAnimations:@"fade in" context:NULL]; |
|
73 [UIView setAnimationDuration:1]; |
|
74 self.blackView.alpha = 0; |
|
75 [UIView commitAnimations]; |
|
76 [self.blackView performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:1]; |
|
77 |
|
78 // the overlay is not needed any more and can be removed |
|
79 [[OverlayViewController mainOverlay] removeOverlay]; |
|
80 |
|
81 // restart music and we're done |
|
82 [AudioManagerController playBackgroundMusic]; |
|
83 [self release]; |
62 } |
84 } |
63 |
85 |
64 // main routine for calling the actual game engine |
86 // main routine for calling the actual game engine |
65 -(void) engineLaunch { |
87 -(void) engineLaunch:(NSString *)pathOrNil { |
66 const char *gameArgs[11]; |
88 const char *gameArgs[11]; |
67 CGFloat width, height; |
89 CGFloat width, height; |
|
90 NSInteger enginePort = [EngineProtocolNetwork activeEnginePort]; |
68 CGFloat screenScale = [[UIScreen mainScreen] safeScale]; |
91 CGFloat screenScale = [[UIScreen mainScreen] safeScale]; |
69 NSString *ipcString = [[NSString alloc] initWithFormat:@"%d", self.ipcPort]; |
92 NSString *ipcString = [[NSString alloc] initWithFormat:@"%d",enginePort]; |
70 NSString *localeString = [[NSString alloc] initWithFormat:@"%@.txt", [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]]; |
93 NSString *localeString = [[NSString alloc] initWithFormat:@"%@.txt",[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]]; |
71 NSUserDefaults *settings = [NSUserDefaults standardUserDefaults]; |
94 NSUserDefaults *settings = [NSUserDefaults standardUserDefaults]; |
72 |
95 |
73 if (IS_DUALHEAD()) { |
96 if (IS_DUALHEAD()) { |
74 CGRect screenBounds = [[[UIScreen screens] objectAtIndex:1] bounds]; |
97 CGRect screenBounds = [[[UIScreen screens] objectAtIndex:1] bounds]; |
75 width = screenBounds.size.width; |
98 width = screenBounds.size.width; |
110 gameArgs[ 4] = "en.txt";//[localeString UTF8String]; //cLocaleFName |
136 gameArgs[ 4] = "en.txt";//[localeString UTF8String]; //cLocaleFName |
111 gameArgs[ 5] = [username UTF8String]; //UserNick |
137 gameArgs[ 5] = [username UTF8String]; //UserNick |
112 gameArgs[ 6] = [[[settings objectForKey:@"sound"] stringValue] UTF8String]; //isSoundEnabled |
138 gameArgs[ 6] = [[[settings objectForKey:@"sound"] stringValue] UTF8String]; //isSoundEnabled |
113 gameArgs[ 7] = [[[settings objectForKey:@"music"] stringValue] UTF8String]; //isMusicEnabled |
139 gameArgs[ 7] = [[[settings objectForKey:@"music"] stringValue] UTF8String]; //isMusicEnabled |
114 gameArgs[ 8] = [[[settings objectForKey:@"alternate"] stringValue] UTF8String]; //cAltDamage |
140 gameArgs[ 8] = [[[settings objectForKey:@"alternate"] stringValue] UTF8String]; //cAltDamage |
115 gameArgs[ 9] = [[[NSBundle mainBundle] resourcePath] UTF8String]; //PathPrefix |
141 gameArgs[ 9] = [resourcePath UTF8String]; //PathPrefix |
116 gameArgs[10] = (self.gameType == gtSave) ? [self.savePath UTF8String] : NULL; //recordFileName |
142 gameArgs[10] = ([HWUtils gameType] == gtSave) ? [pathOrNil UTF8String] : NULL; //recordFileName |
117 |
143 |
118 [verticalSize release]; |
144 [verticalSize release]; |
119 [horizontalSize release]; |
145 [horizontalSize release]; |
|
146 [resourcePath release]; |
120 [localeString release]; |
147 [localeString release]; |
121 [ipcString release]; |
148 [ipcString release]; |
122 |
149 |
123 [ObjcExports initialize]; |
150 [HWUtils setGameStatus:gsLoading]; |
124 |
151 |
125 // this is the pascal fuction that starts the game, wrapped around isInGame |
152 // this is the pascal function that starts the game |
126 [HedgewarsAppDelegate sharedAppDelegate].isInGame = YES; |
|
127 Game(gameArgs); |
153 Game(gameArgs); |
128 [HedgewarsAppDelegate sharedAppDelegate].isInGame = NO; |
154 [self lateEngineLaunch]; |
129 } |
155 } |
130 |
156 |
131 // prepares the controllers for hosting a game |
157 #pragma mark - |
132 -(void) prepareEngineLaunch { |
158 #pragma mark Class methods for setting up the engine from outsite |
133 // we add a black view hiding the background |
159 +(void) startGame:(TGameType) type atPath:(NSString *)path withOptions:(NSDictionary *)config { |
134 CGRect theFrame = CGRectMake(0, 0, self.parentController.view.frame.size.height, self.parentController.view.frame.size.width); |
160 [HWUtils setGameType:type]; |
135 UIView *blackView = [[UIView alloc] initWithFrame:theFrame]; |
161 GameInterfaceBridge *bridge = [[GameInterfaceBridge alloc] init]; |
136 [self.parentController.view addSubview:blackView]; |
162 [bridge earlyEngineLaunch:path withOptions:config]; |
137 blackView.opaque = YES; |
163 [bridge release]; |
138 blackView.backgroundColor = [UIColor blackColor]; |
164 } |
139 blackView.alpha = 0; |
165 |
140 // when dual screen we apply a little transition |
166 +(void) startLocalGame:(NSDictionary *)withOptions { |
141 if (IS_DUALHEAD()) { |
|
142 [UIView beginAnimations:@"fade out" context:NULL]; |
|
143 [UIView setAnimationDuration:1]; |
|
144 blackView.alpha = 1; |
|
145 [UIView commitAnimations]; |
|
146 } else |
|
147 blackView.alpha = 1; |
|
148 |
|
149 // prepare options for overlay and add it to the future sdl uiwindow |
|
150 [self performSelector:@selector(displayOverlayLater:) withObject:nil afterDelay:3]; |
|
151 |
|
152 // keep track of uncompleted games |
|
153 NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; |
|
154 [userDefaults setObject:self.savePath forKey:@"savedGamePath"]; |
|
155 [userDefaults synchronize]; |
|
156 |
|
157 [AudioManagerController pauseBackgroundMusic]; |
|
158 |
|
159 // SYSTEMS ARE GO!! |
|
160 [self engineLaunch]; |
|
161 |
|
162 // remove completed games notification |
|
163 [userDefaults setObject:@"" forKey:@"savedGamePath"]; |
|
164 [userDefaults synchronize]; |
|
165 |
|
166 // now we can remove the cover with a transition |
|
167 blackView.frame = theFrame; |
|
168 blackView.alpha = 1; |
|
169 [UIView beginAnimations:@"fade in" context:NULL]; |
|
170 [UIView setAnimationDuration:1]; |
|
171 blackView.alpha = 0; |
|
172 [UIView commitAnimations]; |
|
173 [blackView performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:1]; |
|
174 [blackView release]; |
|
175 |
|
176 // the overlay is not needed any more and can be removed |
|
177 [self.overlayController removeOverlay]; |
|
178 |
|
179 // warn our host that it's going to be visible again |
|
180 [self.parentController viewWillAppear:YES]; |
|
181 |
|
182 [AudioManagerController playBackgroundMusic]; |
|
183 } |
|
184 |
|
185 // set up variables for a local game |
|
186 -(void) startLocalGame:(NSDictionary *)withOptions { |
|
187 self.gameType = gtLocal; |
|
188 |
|
189 NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init]; |
167 NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init]; |
190 [outputFormatter setDateFormat:@"yyyy-MM-dd '@' HH.mm"]; |
168 [outputFormatter setDateFormat:@"yyyy-MM-dd '@' HH.mm"]; |
191 NSString *path = [[NSString alloc] initWithFormat:@"%@%@.hws",SAVES_DIRECTORY(),[outputFormatter stringFromDate:[NSDate date]]]; |
169 NSString *savePath = [[NSString alloc] initWithFormat:@"%@%@.hws",SAVES_DIRECTORY(),[outputFormatter stringFromDate:[NSDate date]]]; |
192 [outputFormatter release]; |
170 [outputFormatter release]; |
193 self.savePath = path; |
171 |
194 [path release]; |
172 // in the rare case in which a savefile with the same name exists the older one must be removed (otherwise it gets corrupted) |
195 |
173 if ([[NSFileManager defaultManager] fileExistsAtPath:savePath]) |
196 // in the rare case in which a savefile with the same name exists the older one must be removed (or it gets corrupted) |
174 [[NSFileManager defaultManager] removeItemAtPath:savePath error:nil]; |
197 if ([[NSFileManager defaultManager] fileExistsAtPath:self.savePath]) |
175 |
198 [[NSFileManager defaultManager] removeItemAtPath:self.savePath error:nil]; |
176 [self startGame:gtLocal atPath:savePath withOptions:withOptions]; |
199 |
177 [savePath release]; |
200 [self.engineProtocol spawnThread:self.savePath withOptions:withOptions]; |
178 } |
201 [self prepareEngineLaunch]; |
179 |
202 } |
180 +(void) startSaveGame:(NSString *)atPath { |
203 |
181 [self startGame:gtSave atPath:atPath withOptions:nil]; |
204 // set up variables for a save game |
182 } |
205 -(void) startSaveGame:(NSString *)atPath { |
183 |
206 self.gameType = gtSave; |
184 +(void) startMissionGame:(NSString *)withScript { |
207 self.savePath = atPath; |
|
208 |
|
209 [self.engineProtocol spawnThread:self.savePath]; |
|
210 [self prepareEngineLaunch]; |
|
211 } |
|
212 |
|
213 -(void) startMissionGame:(NSString *)withScript { |
|
214 self.gameType = gtMission; |
|
215 self.savePath = nil; |
|
216 |
|
217 NSString *missionPath = [[NSString alloc] initWithFormat:@"escript Missions/Training/%@.lua",withScript]; |
185 NSString *missionPath = [[NSString alloc] initWithFormat:@"escript Missions/Training/%@.lua",withScript]; |
218 NSDictionary *config = [NSDictionary dictionaryWithObject:missionPath forKey:@"mission_command"]; |
186 NSDictionary *missionLine = [[NSDictionary alloc] initWithObjectsAndKeys:missionPath,@"mission_command",nil]; |
219 [missionPath release]; |
187 [missionPath release]; |
220 [self.engineProtocol spawnThread:nil withOptions:config]; |
188 |
221 [self prepareEngineLaunch]; |
189 [self startGame:gtMission atPath:nil withOptions:missionLine]; |
222 } |
190 [missionLine release]; |
223 |
191 } |
|
192 |
|
193 /* |
224 -(void) gameHasEndedWithStats:(NSArray *)stats { |
194 -(void) gameHasEndedWithStats:(NSArray *)stats { |
225 // wrap this around a retain/realse to prevent being deallocated too soon |
195 // wrap this around a retain/realse to prevent being deallocated too soon |
226 [self retain]; |
196 [self retain]; |
227 // display stats page if there is something to display |
197 // display stats page if there is something to display |
228 if (stats != nil) { |
198 if (stats != nil) { |