merge sound changes into .17, and, why not everything else too.
--- a/hedgewars/PascalExports.pas Sun Nov 13 13:18:56 2011 -0500
+++ b/hedgewars/PascalExports.pas Sun Nov 13 14:41:02 2011 -0500
@@ -355,6 +355,12 @@
begin
exit(cMaxTeams);
end;
+
+procedure HW_memoryWarningCallback; cdecl; export;
+begin
+ ReleaseSound(false);
+end;
+
{$ENDIF}
end.
--- a/hedgewars/SDLh.pas Sun Nov 13 13:18:56 2011 -0500
+++ b/hedgewars/SDLh.pas Sun Nov 13 14:41:02 2011 -0500
@@ -956,6 +956,7 @@
function Mix_PauseMusic(music: PMixMusic): LongInt; cdecl; external SDL_MixerLibName;
function Mix_ResumeMusic(music: PMixMusic): LongInt; cdecl; external SDL_MixerLibName;
function Mix_HaltChannel(channel: LongInt): LongInt; cdecl; external SDL_MixerLibName;
+function Mix_HaltMusic: LongInt; cdecl; external SDL_MixerLibName;
function Mix_FadeInChannelTimed(channel: LongInt; chunk: PMixChunk; loops: LongInt; fadems: LongInt; ticks: LongInt): LongInt; cdecl; external SDL_MixerLibName;
function Mix_FadeOutChannel(channel: LongInt; fadems: LongInt): LongInt; cdecl; external SDL_MixerLibName;
--- a/hedgewars/uLandGraphics.pas Sun Nov 13 13:18:56 2011 -0500
+++ b/hedgewars/uLandGraphics.pas Sun Nov 13 14:41:02 2011 -0500
@@ -233,7 +233,7 @@
begin
by:= t div 2; bx:= i div 2;
end;
- if ((Land[t, i] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and not disableLandBack then
+ if ((Land[t, i] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then
begin
inc(cnt);
LandPixels[by, bx]:= LandBackPixel(i, t)
@@ -255,7 +255,7 @@
begin
by:= t div 2; bx:= i div 2;
end;
- if ((Land[t, i] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and not disableLandBack then
+ if ((Land[t, i] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then
begin
inc(cnt);
LandPixels[by, bx]:= LandBackPixel(i, t)
@@ -277,7 +277,7 @@
begin
by:= t div 2; bx:= i div 2;
end;
- if ((Land[t, i] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and not disableLandBack then
+ if ((Land[t, i] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then
begin
inc(cnt);
LandPixels[by, bx]:= LandBackPixel(i, t)
@@ -298,7 +298,7 @@
begin
by:= t div 2; bx:= i div 2;
end;
- if ((Land[t, i] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and not disableLandBack then
+ if ((Land[t, i] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and not (disableLandBack) then
begin
inc(cnt);
LandPixels[by, bx]:= LandBackPixel(i, t)
@@ -468,7 +468,7 @@
begin
by:= ty div 2; bx:= tx div 2;
end;
- if ((Land[ty, tx] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and not disableLandBack then
+ if ((Land[ty, tx] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then
LandPixels[by, bx]:= LandBackPixel(tx, ty)
else if ((Land[ty, tx] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then
LandPixels[by, bx]:= 0
@@ -588,7 +588,7 @@
begin
by:= ty div 2; bx:= tx div 2;
end;
- if ((Land[ty, tx] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and not disableLandBack then
+ if ((Land[ty, tx] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then
LandPixels[by, bx]:= LandBackPixel(tx, ty)
else if ((Land[ty, tx] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then
LandPixels[by, bx]:= 0;
--- a/hedgewars/uSound.pas Sun Nov 13 13:18:56 2011 -0500
+++ b/hedgewars/uSound.pas Sun Nov 13 14:41:02 2011 -0500
@@ -41,7 +41,7 @@
procedure freeModule;
procedure InitSound; // Initiates sound-system if isSoundEnabled.
-procedure ReleaseSound; // Releases sound-system and used resources.
+procedure ReleaseSound(complete: boolean); // Releases sound-system and used resources.
procedure SoundLoad; // Preloads some sounds for performance reasons.
@@ -176,24 +176,41 @@
ChangeVolume(cInitVolume)
end;
-procedure ReleaseSound;
+// when complete is false, this procedure just releases some of the chucks on inactive channels
+// this way music is not stopped, nor are chucks currently being plauyed
+procedure ReleaseSound(complete: boolean);
var i: TSound;
t: Longword;
begin
+ // release and nil all sounds
for t:= 0 to cMaxTeams do
if voicepacks[t].name <> '' then
for i:= Low(TSound) to High(TSound) do
if voicepacks[t].chunks[i] <> nil then
- Mix_FreeChunk(voicepacks[t].chunks[i]);
-
- if Mus <> nil then
- Mix_FreeMusic(Mus);
+ if complete or (Mix_Playing(lastChan[i]) = 0) then
+ begin
+ Mix_HaltChannel(lastChan[i]);
+ lastChan[i]:= -1;
+ Mix_FreeChunk(voicepacks[t].chunks[i]);
+ voicepacks[t].chunks[i]:= nil;
+ end;
- // make sure all instances of sdl_mixer are unloaded before continuing
- while Mix_Init(0) <> 0 do
- Mix_Quit();
+ // stop music
+ if complete then
+ begin
+ if Mus <> nil then
+ begin
+ Mix_HaltMusic();
+ Mix_FreeMusic(Mus);
+ Mus:= nil;
+ end;
- Mix_CloseAudio();
+ // make sure all instances of sdl_mixer are unloaded before continuing
+ while Mix_Init(0) <> 0 do
+ Mix_Quit();
+
+ Mix_CloseAudio();
+ end;
end;
procedure SoundLoad;
@@ -205,15 +222,16 @@
defVoicepack:= AskForVoicepack('Default');
+ // initialize all voices to nil so that they can be loaded when needed
for t:= 0 to cMaxTeams do
if voicepacks[t].name <> '' then
for i:= Low(TSound) to High(TSound) do
voicepacks[t].chunks[i]:= nil;
+ // preload all the big sound files (>32k) that would otherwise lockup the game
for i:= Low(TSound) to High(TSound) do
begin
defVoicepack^.chunks[i]:= nil;
- // preload all the big sound files (>32k) that would otherwise lockup the game
if (i in [sndBeeWater, sndBee, sndCake, sndHellishImpact1, sndHellish, sndHomerun,
sndMolotov, sndMortar, sndRideOfTheValkyries, sndYoohoo])
and (Soundz[i].Path <> ptVoices) and (Soundz[i].FileName <> '') then
@@ -289,7 +307,7 @@
if (not isSoundEnabled) or fastUntilLag or ((LastVoice.snd = snd) and (LastVoice.voicepack = voicepack)) then exit;
if (snd = sndVictory) or (snd = sndFlawless) then
begin
- for i:= 1 to Succ(chanTPU) do StopSound(i);
+ Mix_HaltChannel(-1);
for i:= 0 to 7 do VoiceList[i].snd:= sndNone;
LastVoice.snd:= sndNone;
end;
@@ -480,7 +498,7 @@
procedure freeModule;
begin
if isSoundEnabled then
- ReleaseSound();
+ ReleaseSound(true);
end;
end.
--- a/project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.h Sun Nov 13 13:18:56 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.h Sun Nov 13 14:41:02 2011 -0500
@@ -22,21 +22,15 @@
#import <Foundation/Foundation.h>
#import "SDL_net.h"
-@protocol EngineProtocolDelegate <NSObject>
-
--(void) gameHasEndedWithStats:(NSArray *)stats;
-
-@end
@interface EngineProtocolNetwork : NSObject {
- id<EngineProtocolDelegate> delegate;
-
+ NSArray *statsArray;
NSOutputStream *stream;
TCPsocket csd;
NSInteger enginePort;
}
-@property (nonatomic,assign) id<EngineProtocolDelegate> delegate;
+@property (nonatomic,assign) NSArray *statsArray;
@property (nonatomic,retain) NSOutputStream *stream;
@property (assign) TCPsocket csd;
@property (assign) NSInteger enginePort;
@@ -44,11 +38,10 @@
-(id) init;
-+(void) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary;
+-(void) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary;
+(NSInteger) activeEnginePort;
-(void) engineProtocol:(id) object;
--(void) gameHasEndedWithStats:(NSArray *)stats;
-(int) sendToEngine:(NSString *)string;
-(int) sendToEngineNoSave:(NSString *)string;
--- a/project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.m Sun Nov 13 13:18:56 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.m Sun Nov 13 14:41:02 2011 -0500
@@ -28,12 +28,11 @@
static NSInteger activeEnginePort;
@implementation EngineProtocolNetwork
-@synthesize delegate, stream, csd, enginePort;
+@synthesize statsArray, stream, csd, enginePort;
-(id) init {
if (self = [super init]) {
- self.delegate = nil;
-
+ self.statsArray = nil;
self.csd = NULL;
self.stream = nil;
self.enginePort = [HWUtils randomPort];
@@ -42,31 +41,22 @@
return self;
}
--(void) gameHasEndedWithStats:(NSArray *)stats {
- if (self.delegate != nil && [self.delegate respondsToSelector:@selector(gameHasEndedWithStats:)])
- [self.delegate gameHasEndedWithStats:stats];
- else
- DLog(@"Error! delegate == nil");
-}
-
-(void) dealloc {
- self.delegate = nil;
+ releaseAndNil(statsArray);
releaseAndNil(stream);
[super dealloc];
}
#pragma mark -
#pragma mark Spawner functions
-+(void) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary {
- id proto = [[self alloc] init];
- [proto setStream: (onSaveFile) ? [[NSOutputStream alloc] initToFileAtPath:onSaveFile append:YES] : nil];
- [[proto stream] open];
+-(void) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary {
+ self.stream = (onSaveFile) ? [[NSOutputStream alloc] initToFileAtPath:onSaveFile append:YES] : nil;
+ [self.stream open];
// +detachNewThreadSelector retain/release self automatically
[NSThread detachNewThreadSelector:@selector(engineProtocol:)
- toTarget:proto
+ toTarget:self
withObject:dictionary];
- [proto release];
}
+(NSInteger) activeEnginePort {
@@ -232,7 +222,7 @@
-(void) engineProtocol:(id) object {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *gameConfig = (NSDictionary *)object;
- NSMutableArray *statsArray = nil;
+ NSMutableArray *tempStats = nil;
TCPsocket sd;
IPaddress ip;
int eProto;
@@ -347,10 +337,10 @@
}
break;
case 'i':
- if (statsArray == nil) {
- statsArray = [[NSMutableArray alloc] initWithCapacity:10 - 2];
+ if (tempStats == nil) {
+ tempStats = [[NSMutableArray alloc] initWithCapacity:10 - 2];
NSMutableArray *ranking = [[NSMutableArray alloc] initWithCapacity:4];
- [statsArray insertObject:ranking atIndex:0];
+ [tempStats insertObject:ranking atIndex:0];
[ranking release];
}
NSString *tempStr = [NSString stringWithUTF8String:&buffer[2]];
@@ -359,16 +349,16 @@
int index = [arg length] + 3;
switch (buffer[1]) {
case 'r': // winning team
- [statsArray insertObject:[NSString stringWithUTF8String:&buffer[2]] atIndex:1];
+ [tempStats insertObject:[NSString stringWithUTF8String:&buffer[2]] atIndex:1];
break;
case 'D': // best shot
- [statsArray addObject:[NSString stringWithFormat:@"The best shot award won by %s (with %@ points)", &buffer[index], arg]];
+ [tempStats addObject:[NSString stringWithFormat:@"The best shot award won by %s (with %@ points)", &buffer[index], arg]];
break;
case 'k': // best hedgehog
- [statsArray addObject:[NSString stringWithFormat:@"The best killer is %s with %@ kills in a turn", &buffer[index], arg]];
+ [tempStats addObject:[NSString stringWithFormat:@"The best killer is %s with %@ kills in a turn", &buffer[index], arg]];
break;
case 'K': // number of hogs killed
- [statsArray addObject:[NSString stringWithFormat:@"%@ hedgehog(s) were killed during this round", arg]];
+ [tempStats addObject:[NSString stringWithFormat:@"%@ hedgehog(s) were killed during this round", arg]];
break;
case 'H': // team health/graph
break;
@@ -376,16 +366,16 @@
// still WIP in statsPage.cpp
break;
case 'P': // teams ranking
- [[statsArray objectAtIndex:0] addObject:tempStr];
+ [[tempStats objectAtIndex:0] addObject:tempStr];
break;
case 's': // self damage
- [statsArray addObject:[NSString stringWithFormat:@"%s thought it's good to shoot his own hedgehogs with %@ points", &buffer[index], arg]];
+ [tempStats addObject:[NSString stringWithFormat:@"%s thought it's good to shoot his own hedgehogs with %@ points", &buffer[index], arg]];
break;
case 'S': // friendly fire
- [statsArray addObject:[NSString stringWithFormat:@"%s killed %@ of his own hedgehogs", &buffer[index], arg]];
+ [tempStats addObject:[NSString stringWithFormat:@"%s killed %@ of his own hedgehogs", &buffer[index], arg]];
break;
case 'B': // turn skipped
- [statsArray addObject:[NSString stringWithFormat:@"%s was scared and skipped turn %@ times", &buffer[index], arg]];
+ [tempStats addObject:[NSString stringWithFormat:@"%s was scared and skipped turn %@ times", &buffer[index], arg]];
break;
default:
DLog(@"Unhandled stat message, see statsPage.cpp");
@@ -393,12 +383,15 @@
}
break;
case 'q':
- // game ended, can remove the savefile and present the statistics of the match
+ // game ended and match finished, statsArray is full of delicious statistics
[HWUtils setGameStatus:gsEnded];
- [self gameHasEndedWithStats:statsArray];
+ self.statsArray = [[NSArray arrayWithArray:tempStats] retain];
+ // closing connection here would trigger a "IPC connection lost" error, so we have to wait until recv fails
break;
case 'Q':
- // game exited but not completed, nothing to do (just don't save the message)
+ // game exited but not completed, skip this message in the savefile
+ [HWUtils setGameStatus:gsInterrupted];
+ // same here, don't set clientQuit to YES
break;
default:
[self dumpRawData:buffer ofSize:msgSize];
@@ -406,9 +399,10 @@
}
}
DLog(@"Engine exited, ending thread");
+
[self.stream close];
[self.stream release];
- [statsArray release];
+ [tempStats release];
// Close the client socket
SDLNet_TCP_Close(csd);
--- a/project_files/HedgewarsMobile/Classes/GameConfigViewController.m Sun Nov 13 13:18:56 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/GameConfigViewController.m Sun Nov 13 14:41:02 2011 -0500
@@ -223,6 +223,7 @@
script,@"mission_command",
nil];
+ [GameInterfaceBridge registerCallingController:self];
[GameInterfaceBridge startLocalGame:gameDictionary];
[gameDictionary release];
}
--- a/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.h Sun Nov 13 13:18:56 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.h Sun Nov 13 14:41:02 2011 -0500
@@ -21,15 +21,22 @@
#import <Foundation/Foundation.h>
+@class EngineProtocolNetwork;
@interface GameInterfaceBridge : NSObject {
UIView *blackView;
+ NSString *savePath;
+ EngineProtocolNetwork *proto;
}
@property (nonatomic,retain) UIView *blackView;
+@property (nonatomic,retain) NSString *savePath;
+@property (nonatomic,retain) EngineProtocolNetwork *proto;
+(void) startLocalGame:(NSDictionary *)withOptions;
+(void) startSaveGame:(NSString *)atPath;
+(void) startMissionGame:(NSString *)withScript;
++(void) registerCallingController:(UIViewController *)controller;
+
@end
--- a/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.m Sun Nov 13 13:18:56 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.m Sun Nov 13 14:41:02 2011 -0500
@@ -26,16 +26,22 @@
#import "AudioManagerController.h"
#import "ObjcExports.h"
+static UIViewController *callingController;
+
@implementation GameInterfaceBridge
-@synthesize blackView;
+@synthesize blackView, savePath, proto;
#pragma mark -
#pragma mark Instance methods for engine interaction
// prepares the controllers for hosting a game
--(void) earlyEngineLaunch:(NSString *)pathOrNil withOptions:(NSDictionary *)optionsOrNil {
+-(void) earlyEngineLaunch:(NSDictionary *)optionsOrNil {
[self retain];
[AudioManagerController stopBackgroundMusic];
- [EngineProtocolNetwork spawnThread:pathOrNil withOptions:optionsOrNil];
+
+ EngineProtocolNetwork *engineProtocol = [[EngineProtocolNetwork alloc] init];
+ self.proto = engineProtocol;
+ [engineProtocol release];
+ [self.proto spawnThread:self.savePath withOptions:optionsOrNil];
// add a black view hiding the background
CGRect theFrame = [[UIScreen mainScreen] bounds];
@@ -53,15 +59,19 @@
// keep track of uncompleted games
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
- [userDefaults setObject:pathOrNil forKey:@"savedGamePath"];
+ [userDefaults setObject:self.savePath forKey:@"savedGamePath"];
[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:pathOrNil afterDelay:0.1f];
+ [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"];
@@ -78,16 +88,36 @@
// the overlay is not needed any more and can be removed
[[OverlayViewController mainOverlay] removeOverlay];
+ // engine thread *should* be done by now
+ NSArray *stats = self.proto.statsArray;
+ if (stats != nil) {
+ StatsPageViewController *statsPage = [[StatsPageViewController alloc] initWithStyle:UITableViewStyleGrouped];
+ statsPage.statsArray = stats;
+ statsPage.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
+ if ([statsPage respondsToSelector:@selector(setModalPresentationStyle:)])
+ statsPage.modalPresentationStyle = UIModalPresentationPageSheet;
+
+ [callingController presentModalViewController:statsPage animated:YES];
+ [statsPage release];
+ }
+ [stats release]; // we retained the array before
+
+ // 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 playBackgroundMusic];
+ [HWUtils setGameStatus:gsNone];
+ [HWUtils setGameType:gtNone];
[self release];
}
// main routine for calling the actual game engine
--(void) engineLaunch:(NSString *)pathOrNil {
+-(void) engineLaunch {
const char *gameArgs[11];
CGFloat width, height;
- NSInteger enginePort = [EngineProtocolNetwork activeEnginePort];
+ NSInteger enginePort = self.proto.enginePort;
CGFloat screenScale = [[UIScreen mainScreen] safeScale];
NSString *ipcString = [[NSString alloc] initWithFormat:@"%d",enginePort];
NSString *localeString = [[NSString alloc] initWithFormat:@"%@.txt",[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]];
@@ -139,7 +169,7 @@
gameArgs[ 7] = [[[settings objectForKey:@"music"] stringValue] UTF8String]; //isMusicEnabled
gameArgs[ 8] = [[[settings objectForKey:@"alternate"] stringValue] UTF8String]; //cAltDamage
gameArgs[ 9] = [rotation UTF8String]; //rotateQt
- gameArgs[10] = ([HWUtils gameType] == gtSave) ? [pathOrNil UTF8String] : NULL; //recordFileName
+ gameArgs[10] = ([HWUtils gameType] == gtSave) ? [self.savePath UTF8String] : NULL; //recordFileName
[verticalSize release];
[horizontalSize release];
@@ -154,12 +184,24 @@
[self lateEngineLaunch];
}
+-(void) dealloc {
+ releaseAndNil(blackView);
+ releaseAndNil(savePath);
+ releaseAndNil(proto);
+ [super dealloc];
+}
+
#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 earlyEngineLaunch:path withOptions:config];
+ [bridge setSavePath:path];
+ [bridge earlyEngineLaunch:config];
[bridge release];
}
@@ -190,27 +232,5 @@
[missionLine release];
}
-/*
--(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 ([HWUtils gameType] == gtSave)
- [[NSFileManager defaultManager] removeItemAtPath:self.savePath error:nil];
- [self release];
-}
-*/
@end
--- a/project_files/HedgewarsMobile/Classes/HWUtils.h Sun Nov 13 13:18:56 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/HWUtils.h Sun Nov 13 14:41:02 2011 -0500
@@ -22,7 +22,7 @@
#import <Foundation/Foundation.h>
typedef enum {gtNone, gtLocal, gtSave, gtMission, gtNet} TGameType;
-typedef enum {gsNone, gsLoading, gsInGame, gsEnded} TGameStatus;
+typedef enum {gsNone, gsLoading, gsInGame, gsInterrupted, gsEnded} TGameStatus;
@interface HWUtils : NSObject {
--- a/project_files/HedgewarsMobile/Classes/HedgewarsAppDelegate.m Sun Nov 13 13:18:56 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/HedgewarsAppDelegate.m Sun Nov 13 14:41:02 2011 -0500
@@ -88,6 +88,7 @@
// don't stop music if it is playing
if ([HWUtils isGameLaunched]) {
[AudioManagerController releaseCache];
+ HW_memoryWarningCallback();
}
MSG_MEMCLEAN();
// don't clean mainMenuViewController here!!!
--- a/project_files/HedgewarsMobile/Classes/MainMenuViewController.m Sun Nov 13 13:18:56 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/MainMenuViewController.m Sun Nov 13 14:41:02 2011 -0500
@@ -27,7 +27,6 @@
#import "SavedGamesViewController.h"
#import "RestoreViewController.h"
#import "MissionTrainingViewController.h"
-#import "GameInterfaceBridge.h"
#import "Appirater.h"
#import "ServerProtocolNetwork.h"
@@ -114,7 +113,6 @@
// prompt for restoring any previous game
NSString *saveString = [userDefaults objectForKey:@"savedGamePath"];
if (saveString != nil && [saveString isEqualToString:@""] == NO) {
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(launchRestoredGame) name:@"launchRestoredGame" object:nil];
if (self.restoreViewController == nil) {
NSString *xibName = [@"RestoreViewController-" stringByAppendingString:(IS_IPAD() ? @"iPad" : @"iPhone")];
RestoreViewController *restored = [[RestoreViewController alloc] initWithNibName:xibName bundle:nil];
@@ -235,12 +233,6 @@
}
#pragma mark -
--(void) launchRestoredGame {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [GameInterfaceBridge startSaveGame:[[NSUserDefaults standardUserDefaults] objectForKey:@"savedGamePath"]];
-}
-
-#pragma mark -
-(void) viewDidUnload {
self.gameConfigViewController = nil;
self.settingsViewController = nil;
--- a/project_files/HedgewarsMobile/Classes/MissionTrainingViewController.m Sun Nov 13 13:18:56 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/MissionTrainingViewController.m Sun Nov 13 14:41:02 2011 -0500
@@ -74,6 +74,7 @@
[AudioManagerController playBackSound];
[[self parentViewController] dismissModalViewControllerAnimated:YES];
} else {
+ [GameInterfaceBridge registerCallingController:self];
[GameInterfaceBridge startMissionGame:self.missionName];
}
}
--- a/project_files/HedgewarsMobile/Classes/PascalImports.h Sun Nov 13 13:18:56 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/PascalImports.h Sun Nov 13 14:41:02 2011 -0500
@@ -98,6 +98,8 @@
int HW_getTurnsForCurrentTeam(void);
int HW_getMaxNumberOfHogs(void);
int HW_getMaxNumberOfTeams(void);
+
+ void HW_memoryWarningCallback(void);
#ifdef __cplusplus
}
--- a/project_files/HedgewarsMobile/Classes/RestoreViewController.m Sun Nov 13 13:18:56 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/RestoreViewController.m Sun Nov 13 14:41:02 2011 -0500
@@ -36,7 +36,8 @@
if (theButton.tag != 0) {
[AudioManagerController playClickSound];
- [[NSNotificationCenter defaultCenter] postNotificationName:@"launchRestoredGame" object:nil];
+ [GameInterfaceBridge registerCallingController:self.parentViewController];
+ [GameInterfaceBridge startSaveGame:[[NSUserDefaults standardUserDefaults] objectForKey:@"savedGamePath"]];
} else {
[AudioManagerController playBackSound];
[defaults setObject:@"" forKey:@"savedGamePath"];
--- a/project_files/HedgewarsMobile/Classes/SavedGamesViewController.m Sun Nov 13 13:18:56 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/SavedGamesViewController.m Sun Nov 13 14:41:02 2011 -0500
@@ -189,6 +189,7 @@
self.numberOfItems++;
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
+ [GameInterfaceBridge registerCallingController:self];
[GameInterfaceBridge startSaveGame:currentFilePath];
[currentFilePath release];
}
--- a/tools/PascalParser.hs Sun Nov 13 13:18:56 2011 -0500
+++ b/tools/PascalParser.hs Sun Nov 13 14:41:02 2011 -0500
@@ -23,7 +23,7 @@
data TypesAndVars = TypesAndVars [TypeVarDeclaration]
deriving Show
data TypeVarDeclaration = TypeDeclaration Identifier TypeDecl
- | VarDeclaration Bool ([Identifier], TypeDecl) (Maybe Expression)
+ | VarDeclaration Bool ([Identifier], TypeDecl) (Maybe InitExpression)
| FunctionDeclaration Identifier TypeDecl (Maybe Phrase)
deriving Show
data TypeDecl = SimpleType Identifier
@@ -49,7 +49,7 @@
| WhileCycle Expression Phrase
| RepeatCycle Expression [Phrase]
| ForCycle Identifier Expression Expression Phrase
- | WithBlock Expression Phrase
+ | WithBlock Reference Phrase
| Phrases [Phrase]
| SwitchCase Expression [(Expression, Phrase)] (Maybe Phrase)
| Assignment Reference Expression
@@ -61,17 +61,32 @@
| StringLiteral String
| CharCode String
| NumberLiteral String
+ | FloatLiteral String
| HexNumber String
| Reference Reference
| Null
deriving Show
data Reference = ArrayElement [Expression] Reference
| FunCall [Expression] Reference
+ | BuiltInFunCall [Expression] Reference
| SimpleReference Identifier
| Dereference Reference
| RecordField Reference Reference
| Address Reference
deriving Show
+data InitExpression = InitBinOp String InitExpression InitExpression
+ | InitPrefixOp String InitExpression
+ | InitReference Identifier
+ | InitArray [InitExpression]
+ | InitRecord [(Identifier, InitExpression)]
+ | InitFloat String
+ | InitNumber String
+ | InitHexNumber String
+ | InitString String
+ | InitChar String
+ | InitNull
+ deriving Show
+
pascalLanguageDef
= emptyDef
@@ -88,7 +103,8 @@
, "type", "var", "const", "out", "array", "packed"
, "procedure", "function", "with", "for", "to"
, "downto", "div", "mod", "record", "set", "nil"
- , "string", "shortstring"
+ , "string", "shortstring", "succ", "pred", "low"
+ , "high"
]
, reservedOpNames= []
, caseSensitive = False
@@ -183,7 +199,7 @@
init <- option Nothing $ do
char '='
comments
- e <- expression
+ e <- initExpression
comments
return (Just e)
return $ VarDeclaration False (ids, t) init
@@ -204,7 +220,7 @@
return ()
char '='
comments
- e <- expression
+ e <- initExpression
comments
return $ VarDeclaration False ([i], UnknownType) (Just e)
@@ -213,9 +229,9 @@
, try (string "shortstring") >> return String
, arrayDecl
, recordDecl
+ , sequenceDecl >>= return . Sequence
+ , try (identifier pas) >>= return . SimpleType . Identifier
, rangeDecl >>= return . RangeType
- , sequenceDecl >>= return . Sequence
- , identifier pas >>= return . SimpleType . Identifier
] <?> "type declaration"
where
arrayDecl = do
@@ -336,7 +352,7 @@
liftM Just functionBody
else
return Nothing
- return $ [FunctionDeclaration i ret Nothing]
+ return $ [FunctionDeclaration i ret b]
program = do
string "program"
@@ -371,6 +387,8 @@
where
term = comments >> choice [
parens pas $ expression
+ , try $ integer pas >>= \i -> notFollowedBy (char '.') >> (return . NumberLiteral . show) i
+ , try $ float pas >>= return . FloatLiteral . show
, try $ integer pas >>= return . NumberLiteral . show
, stringLiteral pas >>= return . StringLiteral
, char '#' >> many digit >>= return . CharCode
@@ -400,8 +418,8 @@
, Infix (try $ string "or" >> return (BinOp "or")) AssocLeft
, Infix (try $ string "xor" >> return (BinOp "xor")) AssocLeft
]
- , [ Infix (try $ string "shl" >> return (BinOp "and")) AssocNone
- , Infix (try $ string "shr" >> return (BinOp "or")) AssocNone
+ , [ Infix (try $ string "shl" >> return (BinOp "shl")) AssocNone
+ , Infix (try $ string "shr" >> return (BinOp "shr")) AssocNone
]
, [Prefix (try (string "not") >> return (PrefixOp "not"))]
]
@@ -459,12 +477,12 @@
withBlock = do
try $ string "with"
comments
- e <- expression
+ r <- reference
comments
string "do"
comments
o <- phrase
- return $ WithBlock e o
+ return $ WithBlock r o
repeatCycle = do
try $ string "repeat"
@@ -543,3 +561,54 @@
char ';'
comments
return u
+
+initExpression = buildExpressionParser table term <?> "initialization expression"
+ where
+ term = comments >> choice [
+ try $ parens pas (commaSep pas $ initExpression) >>= return . InitArray
+ , parens pas (semiSep pas $ recField) >>= return . InitRecord
+ , try $ integer pas >>= \i -> notFollowedBy (char '.') >> (return . InitNumber . show) i
+ , try $ float pas >>= return . InitFloat . show
+ , stringLiteral pas >>= return . InitString
+ , char '#' >> many digit >>= return . InitChar
+ , char '$' >> many hexDigit >>= return . InitHexNumber
+ , try $ string "nil" >> return InitNull
+ , iD >>= return . InitReference
+ ]
+
+ recField = do
+ i <- iD
+ spaces
+ char ':'
+ spaces
+ e <- initExpression
+ spaces
+ return (i ,e)
+
+ table = [
+ [ Infix (char '*' >> return (InitBinOp "*")) AssocLeft
+ , Infix (char '/' >> return (InitBinOp "/")) AssocLeft
+ , Infix (try (string "div") >> return (InitBinOp "div")) AssocLeft
+ , Infix (try (string "mod") >> return (InitBinOp "mod")) AssocLeft
+ ]
+ , [ Infix (char '+' >> return (InitBinOp "+")) AssocLeft
+ , Infix (char '-' >> return (InitBinOp "-")) AssocLeft
+ , Prefix (char '-' >> return (InitPrefixOp "-"))
+ ]
+ , [ Infix (try (string "<>") >> return (InitBinOp "<>")) AssocNone
+ , Infix (try (string "<=") >> return (InitBinOp "<=")) AssocNone
+ , Infix (try (string ">=") >> return (InitBinOp ">=")) AssocNone
+ , Infix (char '<' >> return (InitBinOp "<")) AssocNone
+ , Infix (char '>' >> return (InitBinOp ">")) AssocNone
+ , Infix (char '=' >> return (InitBinOp "=")) AssocNone
+ ]
+ , [ Infix (try $ string "and" >> return (InitBinOp "and")) AssocLeft
+ , Infix (try $ string "or" >> return (InitBinOp "or")) AssocLeft
+ , Infix (try $ string "xor" >> return (InitBinOp "xor")) AssocLeft
+ ]
+ , [ Infix (try $ string "shl" >> return (InitBinOp "and")) AssocNone
+ , Infix (try $ string "shr" >> return (InitBinOp "or")) AssocNone
+ ]
+ , [Prefix (try (string "not") >> return (InitPrefixOp "not"))]
+ ]
+
\ No newline at end of file
--- a/tools/pas2c.hs Sun Nov 13 13:18:56 2011 -0500
+++ b/tools/pas2c.hs Sun Nov 13 14:41:02 2011 -0500
@@ -4,8 +4,16 @@
import Text.PrettyPrint.HughesPJ
import Data.Maybe
import Data.Char
+import Text.Parsec.String
+pas2C :: String -> IO String
+pas2C fileName = do
+ ptree <- parseFromFile pascalUnit fileName
+ case ptree of
+ (Left a) -> return (show a)
+ (Right a) -> (return . render . pascal2C) a
+
pascal2C :: PascalUnit -> Doc
pascal2C (Unit unitName interface implementation init fin) = implementation2C implementation
@@ -21,17 +29,38 @@
tvar2C :: TypeVarDeclaration -> Doc
tvar2C (FunctionDeclaration (Identifier name) returnType Nothing) =
type2C returnType <+> text (name ++ "();")
-
-
tvar2C (FunctionDeclaration (Identifier name) returnType (Just phrase)) =
type2C returnType <+> text (name ++ "()")
$$
phrase2C phrase
-tvar2C _ = empty
+tvar2C (TypeDeclaration (Identifier i) t) = text "type" <+> text i <+> type2C t <> text ";"
+tvar2C (VarDeclaration isConst (ids, t) mInitExpr) =
+ if isConst then text "const" else empty
+ <+>
+ type2C t
+ <+>
+ (hsep . punctuate (char ',') . map (\(Identifier i) -> text i) $ ids)
+ <+>
+ initExpr mInitExpr
+ <>
+ text ";"
+ where
+ initExpr Nothing = empty
+ initExpr (Just e) = text "=" <+> initExpr2C e
+
+initExpr2C :: InitExpression -> Doc
+initExpr2C _ = text "<<expression>>"
type2C :: TypeDecl -> Doc
type2C UnknownType = text "void"
-type2C _ = text "<<type>>"
+type2C String = text "string"
+type2C (SimpleType (Identifier i)) = text i
+type2C (PointerTo t) = type2C t <> text "*"
+type2C (RecordType tvs) = text "{" $+$ (nest 4 . vcat . map tvar2C $ tvs) $+$ text "}"
+type2C (RangeType r) = text "<<range type>>"
+type2C (Sequence ids) = text "<<sequence type>>"
+type2C (ArrayDecl r t) = text "<<array type>>"
+
phrase2C :: Phrase -> Doc
phrase2C (Phrases p) = text "{" $+$ (nest 4 . vcat . map phrase2C $ p) $+$ text "}"
@@ -46,15 +75,18 @@
where
case2C :: (Expression, Phrase) -> Doc
case2C (e, p) = text "case" <+> parens (expr2C e) <> char ':' <> nest 4 (phrase2C p $+$ text "break;")
-{-
- | RepeatCycle Expression Phrase
- | ForCycle
- -}
-phrase2C _ = empty
+phrase2C (WithBlock ref p) = text "namespace" <> parens (ref2C ref) $$ (phrase2C $ wrapPhrase p)
+phrase2C (ForCycle (Identifier i) e1 e2 p) =
+ text "for" <> (parens . hsep . punctuate (char ';') $ [text i <+> text "=" <+> expr2C e1, text i <+> text "<=" <+> expr2C e2, text "++" <> text i])
+ $$
+ phrase2C (wrapPhrase p)
+phrase2C (RepeatCycle e p) = text "do" <+> phrase2C (Phrases p) <+> text "while" <> parens (text "!" <> parens (expr2C e))
+
wrapPhrase p@(Phrases _) = p
wrapPhrase p = Phrases [p]
+
expr2C :: Expression -> Doc
expr2C (Expression s) = text s
expr2C (BinOp op expr1 expr2) = parens $ (expr2C expr1) <+> op2C op <+> (expr2C expr2)
@@ -79,6 +111,7 @@
ref2C (FunCall params ref) = ref2C ref <> parens (hsep . punctuate (char ',') . map expr2C $ params)
ref2C (Address ref) = text "&" <> ref2C ref
+
op2C "or" = text "|"
op2C "and" = text "&"
op2C "not" = text "!"