project_files/HedgewarsMobile/Classes/GameInterfaceBridge.m
author nemo
Sun, 02 Oct 2011 10:36:43 -0400
changeset 6081 537bbd5c1a62
parent 6078 8c0cc07731e5
child 6083 72c882c0fd0f
permissions -rw-r--r--
Basic test implementation of an ice flag. Allows for slick parts of terrain. Intended for ice gun, or "ice" mask on portions of land objects. In this test variant it is triggered on girders/objects/bridges of the snow/christmas theme, or on a map that uses blue as a mask colour. Probably needs sheepluva's slope detection to make slopes more slippery to climb.

/*
 * Hedgewars-iOS, a Hedgewars port for iOS devices
 * Copyright (c) 2009-2011 Vittorio Giovara <vittorio.giovara@gmail.com>
 *
 * This program 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; version 2 of the License
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * File created on 18/04/2011.
 */


#import "GameInterfaceBridge.h"
#import "ServerSetup.h"
#import "EngineProtocolNetwork.h"
#import "OverlayViewController.h"
#import "StatsPageViewController.h"
#import "AudioManagerController.h"
#import "ObjcExports.h"

@implementation GameInterfaceBridge
@synthesize parentController, savePath, overlayController, engineProtocol, ipcPort, gameType;

-(id) initWithController:(id) viewController {
    if (self = [super init]) {
        self.ipcPort = [ServerSetup randomPort];
        self.gameType = gtNone;
        self.savePath = nil;

        self.parentController = (UIViewController *)viewController;
        self.engineProtocol = [[EngineProtocolNetwork alloc] initOnPort:self.ipcPort];
        self.engineProtocol.delegate = self;

        self.overlayController = [[OverlayViewController alloc] initWithNibName:@"OverlayViewController" bundle:nil];
    }
    return self;
}

-(void) dealloc {
    releaseAndNil(engineProtocol);
    releaseAndNil(savePath);
    releaseAndNil(overlayController);
    [super dealloc];
}

#pragma mark -
// overlay with controls, become visible later, with a transparency effect since the sdlwindow is not yet created
-(void) displayOverlayLater:(id) object {
    // in order to get rotation events we have to insert the view inside the first view of the second window
    // when multihead we have to make sure that overlay is displayed in the touch-enabled window
    UIView *injected = (IS_DUALHEAD() ? self.parentController.view : UIVIEW_HW_SDLVIEW);
    [injected addSubview:self.overlayController.view];
}

// main routine for calling the actual game engine
-(void) startGameEngine {
    const char *gameArgs[11];
    NSInteger width, height;
    NSString *ipcString = [[NSString alloc] initWithFormat:@"%d", self.ipcPort];
    NSString *localeString = [[NSString alloc] initWithFormat:@"%@.txt", [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]];
    NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];

    if (IS_DUALHEAD()) {
        CGRect screenBounds = [[[UIScreen screens] objectAtIndex:1] bounds];
        width = (int) screenBounds.size.width;
        height = (int) screenBounds.size.height;
    } else {
        CGRect screenBounds = [[UIScreen mainScreen] bounds];
        width = (int) screenBounds.size.height;
        height = (int) screenBounds.size.width;
    }

    NSString *horizontalSize = [[NSString alloc] initWithFormat:@"%d", width * (int)[[UIScreen mainScreen] scale]];
    NSString *verticalSize = [[NSString alloc] initWithFormat:@"%d", height * (int)[[UIScreen mainScreen] scale]];
    NSString *rotation = [[NSString alloc] initWithString:@"0"];

    NSString *modelId = [HWUtils modelType];
    NSInteger tmpQuality;
    if ([modelId hasPrefix:@"iPhone1"] || [modelId hasPrefix:@"iPod1,1"] || [modelId hasPrefix:@"iPod2,1"])     // = iPhone and iPhone 3G or iPod Touch or iPod Touch 2G
        tmpQuality = 0x00000001 | 0x00000002 | 0x00000008 | 0x00000040;                 // rqLowRes | rqBlurryLand | rqSimpleRope | rqKillFlakes
    else if ([modelId hasPrefix:@"iPhone2"] || [modelId hasPrefix:@"iPod3"])                                    // = iPhone 3GS or iPod Touch 3G
        tmpQuality = 0x00000002 | 0x00000040;                                           // rqBlurryLand | rqKillFlakes
    else if ([modelId hasPrefix:@"iPad1"] || [modelId hasPrefix:@"iPod4"])                                      // = iPad 1G or iPod Touch 4G
        tmpQuality = 0x00000002;                                                        // rqBlurryLand
    else                                                                                                        // = everything else
        tmpQuality = 0;                                                                 // full quality

    // disable tooltips on iPhone
    if (IS_IPAD() == NO)
        tmpQuality = tmpQuality | 0x00000400;

    // prevents using an empty nickname
    NSString *username = [settings objectForKey:@"username"];
    if ([username length] == 0)
        username = [NSString stringWithFormat:@"MobileUser-%@",ipcString];

    gameArgs[ 0] = [ipcString UTF8String];                                                      //ipcPort
    gameArgs[ 1] = [horizontalSize UTF8String];                                                 //cScreenWidth
    gameArgs[ 2] = [verticalSize UTF8String];                                                   //cScreenHeight
    gameArgs[ 3] = [[NSString stringWithFormat:@"%d",tmpQuality] UTF8String];                   //quality
    gameArgs[ 4] = "en.txt";//[localeString UTF8String];                                        //cLocaleFName
    gameArgs[ 5] = [username UTF8String];                                                       //UserNick
    gameArgs[ 6] = [[[settings objectForKey:@"sound"] stringValue] UTF8String];                 //isSoundEnabled
    gameArgs[ 7] = [[[settings objectForKey:@"music"] stringValue] UTF8String];                 //isMusicEnabled
    gameArgs[ 8] = [[[settings objectForKey:@"alternate"] stringValue] UTF8String];             //cAltDamage
    gameArgs[ 9] = [rotation UTF8String];                                                       //rotateQt
    gameArgs[10] = (self.gameType == gtSave) ? [self.savePath UTF8String] : NULL;               //recordFileName

    [verticalSize release];
    [horizontalSize release];
    [rotation release];
    [localeString release];
    [ipcString release];

    [ObjcExports initialize];

    // this is the pascal fuction that starts the game, wrapped around isInGame
    [HedgewarsAppDelegate sharedAppDelegate].isInGame = YES;
    Game(gameArgs);
    [HedgewarsAppDelegate sharedAppDelegate].isInGame = NO;
}

// prepares the controllers for hosting a game
-(void) prepareEngineLaunch {
    // we add a black view hiding the background
    CGRect theFrame = CGRectMake(0, 0, self.parentController.view.frame.size.height, self.parentController.view.frame.size.width);
    UIView *blackView = [[UIView alloc] initWithFrame:theFrame];
    [self.parentController.view addSubview:blackView];
    blackView.opaque = YES;
    blackView.backgroundColor = [UIColor blackColor];
    blackView.alpha = 0;
    // when dual screen we apply a little transition
    if (IS_DUALHEAD()) {
        [UIView beginAnimations:@"fade out" context:NULL];
        [UIView setAnimationDuration:1];
        blackView.alpha = 1;
        [UIView commitAnimations];
    } else
        blackView.alpha = 1;

    // prepare options for overlay and add it to the future sdl uiwindow
    [self performSelector:@selector(displayOverlayLater:) withObject:nil afterDelay:3];

    // keep track of uncompleted games
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:self.savePath forKey:@"savedGamePath"];
    [userDefaults synchronize];

    [AudioManagerController pauseBackgroundMusic];

    // SYSTEMS ARE GO!!
    [self startGameEngine];
    
    // remove completed games notification
    [userDefaults setObject:@"" forKey:@"savedGamePath"];
    [userDefaults synchronize];

    // now we can remove the cover with a transition
    blackView.frame = theFrame;
    blackView.alpha = 1;
    [UIView beginAnimations:@"fade in" context:NULL];
    [UIView setAnimationDuration:1];
    blackView.alpha = 0;
    [UIView commitAnimations];
    [blackView performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:1];
    [blackView release];

    // the overlay is not needed any more and can be removed
    [self.overlayController removeOverlay];

    // warn our host that it's going to be visible again
    [self.parentController viewWillAppear:YES];

    [AudioManagerController playBackgroundMusic];
}

// set up variables for a local game
-(void) startLocalGame:(NSDictionary *)withDictionary {
    self.gameType = gtLocal;

    NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
    [outputFormatter setDateFormat:@"yyyy-MM-dd '@' HH.mm"];
    NSString *path = [[NSString alloc] initWithFormat:@"%@%@.hws",SAVES_DIRECTORY(),[outputFormatter stringFromDate:[NSDate date]]];
    [outputFormatter release];
    self.savePath = path;
    [path release];

    // in the rare case in which a savefile with the same name exists the older one must be removed (or it gets corrupted)
    if ([[NSFileManager defaultManager] fileExistsAtPath:self.savePath])
        [[NSFileManager defaultManager] removeItemAtPath:self.savePath error:nil];

    [self.engineProtocol spawnThread:self.savePath withOptions:withDictionary];
    [self prepareEngineLaunch];
}

// set up variables for a save game
-(void) startSaveGame:(NSString *)atPath {
    self.gameType = gtSave;
    self.savePath = atPath;

    [self.engineProtocol spawnThread:self.savePath];
    [self prepareEngineLaunch];
}

-(void) gameHasEndedWithStats:(NSArray *)stats {
    // wrap this around a retain/realse to prevent being deallocated too soon
    [self retain];
    // display stats page if there is something to display
    if (stats != nil) {
        StatsPageViewController *statsPage = [[StatsPageViewController alloc] initWithStyle:UITableViewStyleGrouped];
        statsPage.statsArray = stats;
        statsPage.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
        if ([statsPage respondsToSelector:@selector(setModalPresentationStyle:)])
            statsPage.modalPresentationStyle = UIModalPresentationPageSheet;

        [self.parentController presentModalViewController:statsPage animated:YES];
        [statsPage release];
    }

    // can remove the savefile if the replay has ended
    if (self.gameType == gtSave)
        [[NSFileManager defaultManager] removeItemAtPath:self.savePath error:nil];
    [self release];
}

@end