TrophyRace: Fix game never eliminating any hogs after a hog skipped or ran out of time
Warning: This commit _might_ invalidate past records, but I'm not sure if
this is actually the case. Note that only the eliminiation part of the
script is touched, not the actual race logic.
Even if records are actually broken by this, I and sheepluva have decided that
it's more imporant to fix this very, VERY stupid and old bug than to preserve
records.
/*
* Hedgewars-iOS, a Hedgewars port for iOS devices
* Copyright (c) 2009-2012 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import "GameInterfaceBridge.h"
#import "EngineProtocolNetwork.h"
#import "StatsPageViewController.h"
static UIViewController *callingController;
@implementation GameInterfaceBridge
@synthesize blackView, savePath, port;
#pragma mark -
#pragma mark Instance methods for engine interaction
// prepares the controllers for hosting a game
-(void) earlyEngineLaunch:(NSDictionary *)optionsOrNil {
[self retain];
[[AudioManagerController mainManager] fadeOutBackgroundMusic];
EngineProtocolNetwork *engineProtocol = [[EngineProtocolNetwork alloc] init];
self.port = engineProtocol.enginePort;
engineProtocol.delegate = self;
[engineProtocol spawnThread:self.savePath withOptions:optionsOrNil];
[engineProtocol release];
// add a black view hiding the background
UIWindow *thisWindow = [[HedgewarsAppDelegate sharedAppDelegate] uiwindow];
self.blackView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.blackView.opaque = YES;
self.blackView.backgroundColor = [UIColor blackColor];
self.blackView.alpha = 0;
self.blackView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[UIView beginAnimations:@"fade out" context:NULL];
[UIView setAnimationDuration:1];
self.blackView.alpha = 1;
[UIView commitAnimations];
[thisWindow addSubview:self.blackView];
[self.blackView release];
// keep the point of return for games that completed loading
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:self.savePath forKey:@"savedGamePath"];
[userDefaults setObject:[NSNumber numberWithBool:NO] forKey:@"saveIsValid"];
[userDefaults synchronize];
// let's launch the engine using this -perfomSelector so that the runloop can deal with queued messages first
[self performSelector:@selector(engineLaunch) withObject:nil afterDelay:0.1f];
}
// cleans up everything
-(void) lateEngineLaunch {
// notify views below that they are getting the spotlight again
[[[HedgewarsAppDelegate sharedAppDelegate] uiwindow] makeKeyAndVisible];
[callingController viewWillAppear:YES];
// remove completed games notification
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:@"" forKey:@"savedGamePath"];
[userDefaults synchronize];
// remove the cover view with a transition
self.blackView.alpha = 1;
[UIView beginAnimations:@"fade in" context:NULL];
[UIView setAnimationDuration:1];
self.blackView.alpha = 0;
[UIView commitAnimations];
[self.blackView performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:1];
// can remove the savefile if the replay has ended
if ([HWUtils gameType] == gtSave)
[[NSFileManager defaultManager] removeItemAtPath:self.savePath error:nil];
// restart music and we're done
[[AudioManagerController mainManager] fadeInBackgroundMusic];
[HWUtils setGameStatus:gsNone];
[HWUtils setGameType:gtNone];
[self release];
}
// main routine for calling the actual game engine
-(void) engineLaunch {
CGFloat width, height;
CGFloat screenScale = [[UIScreen mainScreen] safeScale];
NSString *ipcString = [[NSString alloc] initWithFormat:@"%d",self.port];
NSString *localeString = [[NSString alloc] initWithFormat:@"%@.txt", [HWUtils languageID]];
NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
CGRect screenBounds = [[UIScreen mainScreen] safeBounds];
width = screenBounds.size.width;
height = screenBounds.size.height;
NSString *horizontalSize = [[NSString alloc] initWithFormat:@"%d", (int)(width * screenScale)];
NSString *verticalSize = [[NSString alloc] initWithFormat:@"%d", (int)(height * screenScale)];
NSString *resourcePath = [[NSString alloc] initWithFormat:@"%@/Data", [[NSBundle mainBundle] resourcePath]];
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 ammomenu animation
tmpQuality = tmpQuality | 0x00000080;
// disable tooltips on iPhone
if (IS_IPAD() == NO)
tmpQuality = tmpQuality | 0x00000400;
NSString *rawQuality = [NSString stringWithFormat:@"%d",tmpQuality];
NSString *documentsDirectory = DOCUMENTS_FOLDER();
NSMutableArray *gameParameters = [[NSMutableArray alloc] initWithObjects:
@"--internal",
@"--port", ipcString,
@"--width", horizontalSize,
@"--height", verticalSize,
@"--raw-quality", rawQuality,
@"--locale", localeString,
@"--prefix", resourcePath,
@"--user-prefix", documentsDirectory,
nil];
[verticalSize release];
[horizontalSize release];
[resourcePath release];
[localeString release];
[ipcString release];
NSString *username = [settings objectForKey:@"username"];
if ([username length] > 0) {
[gameParameters addObject:@"--nick"];
[gameParameters addObject: username];
}
if ([[settings objectForKey:@"sound"] boolValue] == NO)
[gameParameters addObject:@"--nosound"];
if ([[settings objectForKey:@"music"] boolValue] == NO)
[gameParameters addObject:@"--nomusic"];
if([[settings objectForKey:@"alternate"] boolValue] == YES)
[gameParameters addObject:@"--altdmg"];
#ifdef DEBUG
[gameParameters addObject:@"--showfps"];
#endif
if ([HWUtils gameType] == gtSave)
[gameParameters addObject:self.savePath];
[HWUtils setGameStatus:gsLoading];
int argc = [gameParameters count];
const char **argv = (const char **)malloc(sizeof(const char*)*argc);
for (int i = 0; i < argc; i++)
argv[i] = strdup([[gameParameters objectAtIndex:i] UTF8String]);
[gameParameters release];
// this is the pascal function that starts the game
RunEngine(argc, argv);
// cleanup
for (int i = 0; i < argc; i++)
free((void *)argv[i]);
free(argv);
// moar cleanup
[self lateEngineLaunch];
}
-(void) dealloc {
releaseAndNil(blackView);
releaseAndNil(savePath);
[super dealloc];
}
#pragma mark -
#pragma mark EngineProtocolDelegate methods
-(void) gameEndedWithStatistics:(NSArray *)stats {
if (stats != nil) {
StatsPageViewController *statsPage = [[StatsPageViewController alloc] init];
statsPage.statsArray = stats;
statsPage.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[callingController presentViewController:statsPage animated:YES completion:nil];
[statsPage release];
}
}
#pragma mark -
#pragma mark Class methods for setting up the engine from outsite
+(void) registerCallingController:(UIViewController *)controller {
callingController = controller;
}
+(void) startGame:(TGameType) type atPath:(NSString *)path withOptions:(NSDictionary *)config {
[HWUtils setGameType:type];
id bridge = [[self alloc] init];
[bridge setSavePath:path];
[bridge earlyEngineLaunch:config];
[bridge release];
}
+(void) startLocalGame:(NSDictionary *)withOptions {
NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
[outputFormatter setDateFormat:@"yyyy-MM-dd '@' HH.mm"];
NSString *savePath = [[NSString alloc] initWithFormat:@"%@%@.hws",SAVES_DIRECTORY(),[outputFormatter stringFromDate:[NSDate date]]];
[outputFormatter release];
// in the rare case in which a savefile with the same name exists the older one must be removed (otherwise it gets corrupted)
if ([[NSFileManager defaultManager] fileExistsAtPath:savePath])
[[NSFileManager defaultManager] removeItemAtPath:savePath error:nil];
[self startGame:gtLocal atPath:savePath withOptions:withOptions];
[savePath release];
}
+(void) startSaveGame:(NSString *)atPath {
[self startGame:gtSave atPath:atPath withOptions:nil];
}
+(void) startMissionGame:(NSString *)withScript {
NSString *seedCmd = [self seedCommand];
NSString *missionPath = [[NSString alloc] initWithFormat:@"escript Missions/Training/%@.lua",withScript];
NSDictionary *missionDict = [[NSDictionary alloc] initWithObjectsAndKeys:missionPath, @"mission_command", seedCmd, @"seed_command", nil];
[missionPath release];
[seedCmd release];
[self startGame:gtMission atPath:nil withOptions:missionDict];
[missionDict release];
}
+(NSString *) seedCommand {
// generate a seed
NSString *seed = [HWUtils seed];
NSString *seedCmd = [[NSString alloc] initWithFormat:@"eseed {%@}", seed];
[seed release];
return seedCmd;
}
+(void) startCampaignMissionGameWithScript:(NSString *)missionScriptName forCampaign:(NSString *)campaignName {
NSString *seedCmd = [self seedCommand];
NSString *campaignMissionPath = [[NSString alloc] initWithFormat:@"escript Missions/Campaign/%@/%@", campaignName, missionScriptName];
NSDictionary *campaignMissionDict = [[NSDictionary alloc] initWithObjectsAndKeys:campaignMissionPath, @"mission_command", seedCmd, @"seed_command", nil];
[campaignMissionPath release];
[seedCmd release];
[self startGame:gtCampaign atPath:nil withOptions:campaignMissionDict];
[campaignMissionDict release];
}
+(void) startSimpleGame {
NSString *seedCmd = [self seedCommand];
// pick a random static map
NSArray *listOfMaps = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:MAPS_DIRECTORY() error:NULL];
NSString *mapName = [listOfMaps objectAtIndex:arc4random_uniform((int)[listOfMaps count])];
NSString *fileCfg = [[NSString alloc] initWithFormat:@"%@/%@/map.cfg",MAPS_DIRECTORY(),mapName];
NSString *contents = [[NSString alloc] initWithContentsOfFile:fileCfg encoding:NSUTF8StringEncoding error:NULL];
[fileCfg release];
NSArray *split = [contents componentsSeparatedByString:@"\n"];
[contents release];
NSString *themeCommand = [[NSString alloc] initWithFormat:@"etheme %@", [split objectAtIndex:0]];
NSString *staticMapCommand = [[NSString alloc] initWithFormat:@"emap %@", mapName];
// select teams with two different colors
NSArray *colorArray = [HWUtils teamColors];
NSInteger firstColorIndex, secondColorIndex;
do {
firstColorIndex = arc4random_uniform((int)[colorArray count]);
secondColorIndex = arc4random_uniform((int)[colorArray count]);
} while (firstColorIndex == secondColorIndex);
unsigned int firstColor = [[colorArray objectAtIndex:firstColorIndex] intValue];
unsigned int secondColor = [[colorArray objectAtIndex:secondColorIndex] intValue];
NSDictionary *firstTeam = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:4],@"number",
[NSNumber numberWithUnsignedInt:firstColor],@"color",
@"Ninjas.plist",@"team",nil];
NSDictionary *secondTeam = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:4],@"number",
[NSNumber numberWithUnsignedInt:secondColor],@"color",
@"Robots.plist",@"team",nil];
NSArray *listOfTeams = [[NSArray alloc] initWithObjects:firstTeam,secondTeam,nil];
[firstTeam release];
[secondTeam release];
// create the configuration
NSDictionary *gameDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
seedCmd,@"seed_command",
@"e$template_filter 0",@"templatefilter_command",
@"e$mapgen 0",@"mapgen_command",
@"e$maze_size 0",@"mazesize_command",
themeCommand,@"theme_command",
staticMapCommand,@"staticmap_command",
listOfTeams,@"teams_list",
@"Default.plist",@"scheme",
@"Default.plist",@"weapon",
@"",@"mission_command",
nil];
[listOfTeams release];
[staticMapCommand release];
[themeCommand release];
[seedCmd release];
// launch game
[GameInterfaceBridge startLocalGame:gameDictionary];
[gameDictionary release];
}
@end