project_files/HedgewarsMobile/Classes/OverlayViewController.m
branchhedgeroid
changeset 7855 ddcdedd3330b
parent 6350 41b0a9955c47
parent 7854 0b447175594f
child 7857 2bc61f8841a1
equal deleted inserted replaced
6350:41b0a9955c47 7855:ddcdedd3330b
     1 /*
       
     2  * Hedgewars-iOS, a Hedgewars port for iOS devices
       
     3  * Copyright (c) 2009-2011 Vittorio Giovara <vittorio.giovara@gmail.com>
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License as published by
       
     7  * the Free Software Foundation; version 2 of the License
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    15  * along with this program; if not, write to the Free Software
       
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
       
    17  *
       
    18  * File created on 16/03/2010.
       
    19  */
       
    20 
       
    21 
       
    22 #import "OverlayViewController.h"
       
    23 #import "InGameMenuViewController.h"
       
    24 #import "HelpPageViewController.h"
       
    25 #import "AmmoMenuViewController.h"
       
    26 #import "CGPointUtils.h"
       
    27 #import "ObjcExports.h"
       
    28 
       
    29 
       
    30 #define HIDING_TIME_DEFAULT [NSDate dateWithTimeIntervalSinceNow:2.7]
       
    31 #define HIDING_TIME_NEVER   [NSDate dateWithTimeIntervalSinceNow:10000]
       
    32 #define doDim()             [dimTimer setFireDate: (IS_DUALHEAD()) ? HIDING_TIME_NEVER : HIDING_TIME_DEFAULT]
       
    33 #define doNotDim()          [dimTimer setFireDate:HIDING_TIME_NEVER]
       
    34 
       
    35 
       
    36 static OverlayViewController *mainOverlay;
       
    37 
       
    38 @implementation OverlayViewController
       
    39 @synthesize popoverController, popupMenu, helpPage, amvc, initialScreenCount, loadingIndicator,
       
    40             confirmButton, grenadeTimeSegment;
       
    41 
       
    42 #pragma mark -
       
    43 #pragma mark rotation
       
    44 
       
    45 -(BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation {
       
    46     return rotationManager(interfaceOrientation);
       
    47 }
       
    48 
       
    49 #pragma mark -
       
    50 #pragma mark View Management
       
    51 -(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
       
    52     if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
       
    53         isAttacking = NO;
       
    54         isPopoverVisible = NO;
       
    55         initialScreenCount = (IS_DUALHEAD() ? 2 : 1);
       
    56         loadingIndicator = nil;
       
    57         mainOverlay = self;
       
    58     }
       
    59     return self;
       
    60 }
       
    61 
       
    62 +(OverlayViewController *)mainOverlay {
       
    63     return mainOverlay;
       
    64 }
       
    65 
       
    66 -(void) viewDidLoad {
       
    67     // fill all the screen available as sdlview disables autoresizing
       
    68     CGRect rect = [[UIScreen mainScreen] bounds];
       
    69     self.view.frame = CGRectMake(0, 0, rect.size.height, rect.size.width);
       
    70 
       
    71     // the timer used to dim the overlay
       
    72     dimTimer = [[NSTimer alloc] initWithFireDate:(IS_DUALHEAD()) ? HIDING_TIME_NEVER : [NSDate dateWithTimeIntervalSinceNow:6]
       
    73                                         interval:1000
       
    74                                           target:self
       
    75                                         selector:@selector(dimOverlay)
       
    76                                         userInfo:nil
       
    77                                          repeats:YES];
       
    78     // add timer to runloop, otherwise it doesn't work
       
    79     [[NSRunLoop currentRunLoop] addTimer:dimTimer forMode:NSDefaultRunLoopMode];
       
    80 
       
    81     // display the help page, required by the popover on ipad
       
    82     [[NSNotificationCenter defaultCenter] addObserver:self
       
    83                                              selector:@selector(showHelp:)
       
    84                                                  name:@"show help ingame"
       
    85                                                object:nil];
       
    86 
       
    87     if (IS_IPAD()) {
       
    88         [[NSNotificationCenter defaultCenter] addObserver:self
       
    89                                                  selector:@selector(numberOfScreensIncreased)
       
    90                                                      name:UIScreenDidConnectNotification
       
    91                                                    object:nil];
       
    92         
       
    93         [[NSNotificationCenter defaultCenter] addObserver:self
       
    94                                                  selector:@selector(numberOfScreensDecreased)
       
    95                                                      name:UIScreenDidDisconnectNotification
       
    96                                                    object:nil];
       
    97     }
       
    98     
       
    99     // present the overlay
       
   100     self.view.alpha = 0;
       
   101     [UIView beginAnimations:@"showing overlay" context:NULL];
       
   102     [UIView setAnimationDuration:2];
       
   103     self.view.alpha = 1;
       
   104     [UIView commitAnimations];
       
   105 }
       
   106 
       
   107 -(void) viewDidUnload {
       
   108     [[NSNotificationCenter defaultCenter] removeObserver:self];
       
   109 
       
   110     [NSObject cancelPreviousPerformRequestsWithTarget:self
       
   111                                              selector:@selector(unsetPreciseStatus)
       
   112                                                object:nil];
       
   113 
       
   114     // only objects initialized in viewDidLoad should be here
       
   115     dimTimer = nil;
       
   116     mainOverlay = nil;
       
   117     self.helpPage = nil;
       
   118     [self dismissPopover];
       
   119     self.popoverController = nil;
       
   120     self.amvc = nil;
       
   121     self.loadingIndicator = nil;
       
   122     MSG_DIDUNLOAD();
       
   123     [super viewDidUnload];
       
   124 }
       
   125 
       
   126 -(void) didReceiveMemoryWarning {
       
   127     if (self.popupMenu.view.superview == nil)
       
   128         self.popupMenu = nil;
       
   129     if (self.helpPage.view.superview == nil)
       
   130         self.helpPage = nil;
       
   131     if (self.amvc.view.superview == nil)
       
   132         self.amvc = nil;
       
   133     if (self.loadingIndicator.superview == nil)
       
   134         self.loadingIndicator = nil;
       
   135     if (self.confirmButton.superview == nil)
       
   136         self.confirmButton = nil;
       
   137     if (self.grenadeTimeSegment.superview == nil)
       
   138         self.grenadeTimeSegment = nil;
       
   139     if (IS_IPAD())
       
   140         if (((UIPopoverController *)self.popoverController).contentViewController.view.superview == nil)
       
   141             self.popoverController = nil;
       
   142 
       
   143     MSG_MEMCLEAN();
       
   144     [super didReceiveMemoryWarning];
       
   145 }
       
   146 
       
   147 -(void) dealloc {
       
   148     releaseAndNil(popupMenu);
       
   149     releaseAndNil(helpPage);
       
   150     releaseAndNil(popoverController);
       
   151     releaseAndNil(amvc);
       
   152     releaseAndNil(loadingIndicator);
       
   153     releaseAndNil(confirmButton);
       
   154     releaseAndNil(grenadeTimeSegment);
       
   155     // dimTimer is autoreleased
       
   156     [super dealloc];
       
   157 }
       
   158 
       
   159 -(void) numberOfScreensIncreased {
       
   160     if (self.initialScreenCount == 1) {
       
   161         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"New display detected"
       
   162                                                         message:NSLocalizedString(@"Hedgewars supports multi-monitor configurations, but the screen has to be connected before launching the game.",@"")
       
   163                                                        delegate:nil
       
   164                                               cancelButtonTitle:@"Ok"
       
   165                                               otherButtonTitles:nil];
       
   166         [alert show];
       
   167         [alert release];
       
   168         HW_pause();
       
   169     }
       
   170 }
       
   171 
       
   172 -(void) numberOfScreensDecreased {
       
   173     if (self.initialScreenCount == 2) {
       
   174         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Oh noes! Display disconnected"
       
   175                                                         message:NSLocalizedString(@"A monitor has been disconnected while playing and this has ended the match! You need to restart the game if you wish to use the second display again.",@"")
       
   176                                                        delegate:nil
       
   177                                               cancelButtonTitle:@"Ok"
       
   178                                               otherButtonTitles:nil];
       
   179         [alert show];
       
   180         [alert release];
       
   181         HW_terminate(NO);
       
   182     }
       
   183 }
       
   184 
       
   185 #pragma mark -
       
   186 #pragma mark overlay appearance
       
   187 // nice transition for dimming, should be called only by the timer himself
       
   188 -(void) dimOverlay {
       
   189     if ([HWUtils isGameRunning]) {
       
   190         [UIView beginAnimations:@"overlay dim" context:NULL];
       
   191         [UIView setAnimationDuration:0.6];
       
   192         self.view.alpha = 0.2;
       
   193         [UIView commitAnimations];
       
   194     }
       
   195 }
       
   196 
       
   197 // set the overlay visible and put off the timer for enough time
       
   198 -(void) activateOverlay {
       
   199     self.view.alpha = 1;
       
   200     doNotDim();
       
   201 }
       
   202 
       
   203 -(void) removeOverlay {
       
   204     [self.popupMenu performSelectorOnMainThread:@selector(dismiss) withObject:nil waitUntilDone:YES];
       
   205     [self.popoverController performSelectorOnMainThread:@selector(dismissPopoverAnimated:) withObject:nil waitUntilDone:YES];
       
   206     [self.view performSelectorOnMainThread:@selector(removeFromSuperview) withObject:nil waitUntilDone:YES];
       
   207     [self performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:YES];
       
   208     mainOverlay = nil;
       
   209 }
       
   210 
       
   211 #pragma mark -
       
   212 #pragma mark overlay user interaction
       
   213 // dim the overlay when there's no more input for a certain amount of time
       
   214 -(IBAction) buttonReleased:(id) sender {
       
   215     if ([HWUtils isGameRunning] == NO)
       
   216         return;
       
   217 
       
   218     UIButton *theButton = (UIButton *)sender;
       
   219 
       
   220     switch (theButton.tag) {
       
   221         case 0:
       
   222         case 1:
       
   223         case 2:
       
   224         case 3:
       
   225             [NSObject cancelPreviousPerformRequestsWithTarget:self
       
   226                                                      selector:@selector(unsetPreciseStatus)
       
   227                                                        object:nil];
       
   228             HW_walkingKeysUp();
       
   229             break;
       
   230         case 4:
       
   231         case 5:
       
   232         case 6:
       
   233             HW_otherKeysUp();
       
   234             break;
       
   235         default:
       
   236             DLog(@"Nope");
       
   237             break;
       
   238     }
       
   239 
       
   240     isAttacking = NO;
       
   241     doDim();
       
   242 }
       
   243 
       
   244 // issue certain action based on the tag of the button
       
   245 -(IBAction) buttonPressed:(id) sender {
       
   246     [self activateOverlay];
       
   247     
       
   248     if ([HWUtils isGameRunning] == NO)
       
   249         return;
       
   250     
       
   251     if (isPopoverVisible)
       
   252         [self dismissPopover];
       
   253     
       
   254     UIButton *theButton = (UIButton *)sender;
       
   255     switch (theButton.tag) {
       
   256         case 0:
       
   257             if (isAttacking == NO)
       
   258                 HW_walkLeft();
       
   259             break;
       
   260         case 1:
       
   261             if (isAttacking == NO)
       
   262                 HW_walkRight();
       
   263             break;
       
   264         case 2:
       
   265             [self performSelector:@selector(unsetPreciseStatus) withObject:nil afterDelay:0.8];
       
   266             HW_preciseSet(!HW_isWeaponRope());
       
   267             HW_aimUp();
       
   268             break;
       
   269         case 3:
       
   270             [self performSelector:@selector(unsetPreciseStatus) withObject:nil afterDelay:0.8];
       
   271             HW_preciseSet(!HW_isWeaponRope());
       
   272             HW_aimDown();
       
   273             break;
       
   274         case 4:
       
   275             HW_shoot();
       
   276             isAttacking = YES;
       
   277             break;
       
   278         case 5:
       
   279             HW_jump();
       
   280             break;
       
   281         case 6:
       
   282             HW_backjump();
       
   283             break;
       
   284         case 10:
       
   285             [AudioManagerController playClickSound];
       
   286             clearView();
       
   287             HW_pause();
       
   288             if (self.amvc.isVisible && IS_DUALHEAD() == NO) {
       
   289                 doDim();
       
   290                 [self.amvc disappear];
       
   291             }
       
   292             clearView();
       
   293             [self showPopover];
       
   294             break;
       
   295         case 11:
       
   296             [AudioManagerController playClickSound];
       
   297             clearView();
       
   298             
       
   299             if (IS_DUALHEAD() || [[[NSUserDefaults standardUserDefaults] objectForKey:@"classic_menu"] boolValue] == NO) {
       
   300                 if (self.amvc == nil)
       
   301                     self.amvc = [[AmmoMenuViewController alloc] init];
       
   302 
       
   303                 if (self.amvc.isVisible) {
       
   304                     doDim();
       
   305                     [self.amvc disappear];
       
   306                 } else {
       
   307                     if (HW_isAmmoMenuNotAllowed() == NO) {
       
   308                         doNotDim();
       
   309                         [self.amvc appearInView:self.view];
       
   310                     }
       
   311                 }
       
   312             } else
       
   313                 HW_ammoMenu();
       
   314             break;
       
   315         default:
       
   316             DLog(@"Nope");
       
   317             break;
       
   318     }
       
   319 }
       
   320 
       
   321 -(void) unsetPreciseStatus {
       
   322     HW_preciseSet(NO);
       
   323 }
       
   324 
       
   325 -(void) sendHWClick {
       
   326     HW_click();
       
   327     clearView();
       
   328     doDim();
       
   329 }
       
   330 
       
   331 -(void) setGrenadeTime:(id) sender {
       
   332     UISegmentedControl *theSegment = (UISegmentedControl *)sender;
       
   333     if ([ObjcExports grenadeTime] != theSegment.selectedSegmentIndex) {
       
   334         HW_setGrenadeTime(theSegment.selectedSegmentIndex + 1);
       
   335         [ObjcExports setGrenadeTime:theSegment.selectedSegmentIndex];
       
   336     }
       
   337 }
       
   338 
       
   339 #pragma mark -
       
   340 #pragma mark in-game menu and help page
       
   341 -(void) showHelp:(id) sender {
       
   342     if (self.helpPage == nil) {
       
   343         NSString *xibName = (IS_IPAD() ? @"HelpPageInGameViewController-iPad" : @"HelpPageInGameViewController-iPhone");
       
   344         self.helpPage = [[HelpPageViewController alloc] initWithNibName:xibName bundle:nil];
       
   345     }
       
   346     self.helpPage.view.alpha = 0;
       
   347     [self.view addSubview:helpPage.view];
       
   348     [UIView beginAnimations:@"helpingame" context:NULL];
       
   349     self.helpPage.view.alpha = 1;
       
   350     [UIView commitAnimations];
       
   351     doNotDim();
       
   352 }
       
   353 
       
   354 // show up a popover containing a popupMenuViewController; we hook it with setPopoverContentSize
       
   355 // on iphone instead just use the tableViewController directly (and implement manually all animations)
       
   356 -(IBAction) showPopover{
       
   357     CGRect screen = [[UIScreen mainScreen] bounds];
       
   358     isPopoverVisible = YES;
       
   359 
       
   360     if (IS_IPAD()) {
       
   361         if (self.popupMenu == nil)
       
   362             self.popupMenu = [[InGameMenuViewController alloc] initWithStyle:UITableViewStylePlain];
       
   363         if (self.popoverController == nil) {
       
   364             self.popoverController = [[UIPopoverController alloc] initWithContentViewController:self.popupMenu];
       
   365             [self.popoverController setPopoverContentSize:CGSizeMake(220, 200) animated:YES];
       
   366             [self.popoverController setPassthroughViews:[NSArray arrayWithObject:self.view]];
       
   367         }
       
   368 
       
   369         [self.popoverController presentPopoverFromRect:CGRectMake(screen.size.height / 2, screen.size.width / 2, 1, 1)
       
   370                                            inView:self.view
       
   371                          permittedArrowDirections:UIPopoverArrowDirectionAny
       
   372                                          animated:YES];
       
   373     } else {
       
   374         if (self.popupMenu == nil)
       
   375             self.popupMenu = [[InGameMenuViewController alloc] initWithStyle:UITableViewStyleGrouped];
       
   376 
       
   377         [self.view addSubview:popupMenu.view];
       
   378         [self.popupMenu present];
       
   379     }
       
   380     self.popupMenu.tableView.scrollEnabled = NO;
       
   381 }
       
   382 
       
   383 // on ipad just dismiss it, on iphone transtion to the right
       
   384 -(void) dismissPopover {
       
   385     if (YES == isPopoverVisible) {
       
   386         isPopoverVisible = NO;
       
   387         if (HW_isPaused())
       
   388             HW_pauseToggle();
       
   389 
       
   390         [self.popupMenu dismiss];
       
   391         if (IS_IPAD())
       
   392             [self.popoverController dismissPopoverAnimated:YES];
       
   393 
       
   394         [self buttonReleased:nil];
       
   395     }
       
   396 }
       
   397 
       
   398 #pragma mark -
       
   399 #pragma mark Custom touch event handling
       
   400 -(BOOL) shouldIgnoreTouch:(NSSet *)allTouches {
       
   401     if ([HWUtils isGameRunning] == NO)
       
   402         return YES;
       
   403 
       
   404     // ignore activity near the dpad and buttons
       
   405     CGPoint touchPoint = [[[allTouches allObjects] objectAtIndex:0] locationInView:self.view];
       
   406     CGSize screen = [[UIScreen mainScreen] bounds].size;
       
   407 
       
   408     if ((touchPoint.x < 160 && touchPoint.y > screen.width - 155 ) || 
       
   409         (touchPoint.x > screen.height - 135 && touchPoint.y > screen.width - 140))
       
   410         return YES;
       
   411     return NO;
       
   412 }
       
   413 
       
   414 -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
       
   415     NSSet *allTouches = [event allTouches];
       
   416     UITouch *first, *second;
       
   417 
       
   418     if ([self shouldIgnoreTouch:allTouches] == YES)
       
   419         return;
       
   420 
       
   421     // hide in-game menu
       
   422     if (isPopoverVisible)
       
   423         [self dismissPopover];
       
   424 
       
   425     if (self.amvc.isVisible && IS_DUALHEAD() == NO) {
       
   426         doDim();
       
   427         [self.amvc disappear];
       
   428     }
       
   429     // reset default dimming
       
   430     doDim();
       
   431 
       
   432     HW_setPianoSound([allTouches count]);
       
   433 
       
   434     switch ([allTouches count]) {
       
   435         case 1:
       
   436             startingPoint = [[[allTouches allObjects] objectAtIndex:0] locationInView:self.view];
       
   437             if (2 == [[[allTouches allObjects] objectAtIndex:0] tapCount])
       
   438                 HW_zoomReset();
       
   439             break;
       
   440         case 2:
       
   441             if (2 == [[[allTouches allObjects] objectAtIndex:0] tapCount])
       
   442                 HW_screenshot();
       
   443             else {
       
   444                 // pinching
       
   445                 first = [[allTouches allObjects] objectAtIndex:0];
       
   446                 second = [[allTouches allObjects] objectAtIndex:1];
       
   447                 initialDistanceForPinching = distanceBetweenPoints([first locationInView:self.view], [second locationInView:self.view]);
       
   448             }
       
   449             break;
       
   450         default:
       
   451             break;
       
   452     }
       
   453 }
       
   454 
       
   455 -(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
       
   456     NSSet *allTouches = [event allTouches];
       
   457     if ([self shouldIgnoreTouch:allTouches] == YES)
       
   458         return;
       
   459 
       
   460     CGRect screen = [[UIScreen mainScreen] bounds];
       
   461     CGPoint currentPosition = [[[allTouches allObjects] objectAtIndex:0] locationInView:self.view];
       
   462 
       
   463     switch ([allTouches count]) {
       
   464         case 1:
       
   465             // if we're in the menu we just click in the point
       
   466             if (HW_isAmmoMenuOpen()) {
       
   467                 HW_setCursor(HWXZ(currentPosition.x), HWYZ(currentPosition.y));
       
   468                 // this click doesn't need any wrapping because the ammoMenu already limits the cursor
       
   469                 HW_click();
       
   470             } else
       
   471                 // if weapon requires a further click, ask for tapping again
       
   472                 if (HW_isWeaponRequiringClick()) {
       
   473                     // here don't have to wrap thanks to isCursorVisible magic
       
   474                     HW_setCursor(HWX(currentPosition.x), HWY(currentPosition.y));
       
   475 
       
   476                     // draw the button at the last touched point (which is the current position)
       
   477                     if (self.confirmButton == nil) {
       
   478                         UIButton *tapAgain = [UIButton buttonWithType:UIButtonTypeRoundedRect];
       
   479                         [tapAgain addTarget:self action:@selector(sendHWClick) forControlEvents:UIControlEventTouchUpInside];
       
   480                         [tapAgain setTitle:NSLocalizedString(@"Set!",@"on the overlay") forState:UIControlStateNormal];
       
   481                         self.confirmButton = tapAgain;
       
   482                     }
       
   483                     self.confirmButton.alpha = 0;
       
   484                     self.confirmButton.frame = CGRectMake(currentPosition.x - 75, currentPosition.y + 25, 150, 40);
       
   485                     [self.view addSubview:self.confirmButton];
       
   486 
       
   487                     // animation ftw!
       
   488                     [UIView beginAnimations:@"inserting button" context:NULL];
       
   489                     [UIView setAnimationDuration:ANIMATION_DURATION];
       
   490                     self.confirmButton.alpha = 1;
       
   491                     [UIView commitAnimations];
       
   492 
       
   493                     // keep the overlay active, or the button will fade
       
   494                     [self activateOverlay];
       
   495                     doNotDim();
       
   496                 } else
       
   497                     if (HW_isWeaponTimerable()) {
       
   498                         if (self.grenadeTimeSegment.tag != 0) {
       
   499                             [UIView beginAnimations:@"removing segmented control" context:NULL];
       
   500                             [UIView setAnimationDuration:ANIMATION_DURATION];
       
   501                             self.grenadeTimeSegment.alpha = 0;
       
   502                             [UIView commitAnimations];
       
   503 
       
   504                             [self.grenadeTimeSegment performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:ANIMATION_DURATION];
       
   505                             self.grenadeTimeSegment.tag = 0;
       
   506                         } else {
       
   507                             if (self.grenadeTimeSegment == nil) {
       
   508                                 NSArray *items = [[NSArray alloc] initWithObjects:@"1",@"2",@"3",@"4",@"5",nil];
       
   509                                 UISegmentedControl *grenadeSegment = [[UISegmentedControl alloc] initWithItems:items];
       
   510                                 [items release];
       
   511                                 [grenadeSegment addTarget:self action:@selector(setGrenadeTime:) forControlEvents:UIControlEventValueChanged];
       
   512                                 self.grenadeTimeSegment = grenadeSegment;
       
   513                                 [grenadeSegment release];
       
   514                             }
       
   515                             self.grenadeTimeSegment.frame = CGRectMake(screen.size.height / 2 - 125, screen.size.width, 250, 50);
       
   516                             self.grenadeTimeSegment.selectedSegmentIndex = [ObjcExports grenadeTime];
       
   517                             self.grenadeTimeSegment.alpha = 1;
       
   518                             [self.view addSubview:self.grenadeTimeSegment];
       
   519 
       
   520                             [UIView beginAnimations:@"inserting segmented control" context:NULL];
       
   521                             [UIView setAnimationDuration:ANIMATION_DURATION];
       
   522                             [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
       
   523                             self.grenadeTimeSegment.frame = CGRectMake(screen.size.height / 2 - 125, screen.size.width - 100, 250, 50);
       
   524                             [UIView commitAnimations];
       
   525 
       
   526                             self.grenadeTimeSegment.tag++;
       
   527                             [self activateOverlay];
       
   528                             doNotDim();
       
   529                         }
       
   530                     } else
       
   531                         if (HW_isWeaponSwitch())
       
   532                             HW_tab();
       
   533             break;
       
   534         case 2:
       
   535             HW_allKeysUp();
       
   536             break;
       
   537         default:
       
   538             break;
       
   539     }
       
   540 
       
   541     initialDistanceForPinching = 0;
       
   542 }
       
   543 
       
   544 -(void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
       
   545     [self touchesEnded:touches withEvent:event];
       
   546 }
       
   547 
       
   548 -(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
       
   549     NSSet *allTouches = [event allTouches];
       
   550     if ([self shouldIgnoreTouch:allTouches] == YES)
       
   551         return;
       
   552 
       
   553     CGRect screen = [[UIScreen mainScreen] bounds];
       
   554     int x, y, dx, dy;
       
   555     UITouch *touch, *first, *second;
       
   556 
       
   557     switch ([allTouches count]) {
       
   558         case 1:
       
   559             touch = [[allTouches allObjects] objectAtIndex:0];
       
   560             CGPoint currentPosition = [touch locationInView:self.view];
       
   561 
       
   562             if (HW_isAmmoMenuOpen()) {
       
   563                 // no zoom consideration for this
       
   564                 HW_setCursor(HWXZ(currentPosition.x), HWYZ(currentPosition.y));
       
   565             } else
       
   566                 if (HW_isWeaponRequiringClick()) {
       
   567                     // moves the cursor around wrt zoom
       
   568                     HW_setCursor(HWX(currentPosition.x), HWY(currentPosition.y));
       
   569                 } else {
       
   570                     // panning \o/
       
   571                     dx = startingPoint.x - currentPosition.x;
       
   572                     dy = currentPosition.y - startingPoint.y;
       
   573                     HW_getCursor(&x, &y);
       
   574                     // momentum (or something like that)
       
   575                     /*if (abs(dx) > 40)
       
   576                         dx *= log(abs(dx)/4);
       
   577                     if (abs(dy) > 40)
       
   578                         dy *= log(abs(dy)/4);*/
       
   579                     HW_setCursor(x + dx/HW_zoomFactor(), y + dy/HW_zoomFactor());
       
   580                     startingPoint = currentPosition;
       
   581                 }
       
   582             break;
       
   583         case 2:
       
   584             first = [[allTouches allObjects] objectAtIndex:0];
       
   585             second = [[allTouches allObjects] objectAtIndex:1];
       
   586             CGFloat currentDistanceOfPinching = distanceBetweenPoints([first locationInView:self.view], [second locationInView:self.view]);
       
   587             const int pinchDelta = 40;
       
   588 
       
   589             if (0 != initialDistanceForPinching) {
       
   590                 if (currentDistanceOfPinching - initialDistanceForPinching > pinchDelta) {
       
   591                     HW_zoomIn();
       
   592                     initialDistanceForPinching = currentDistanceOfPinching;
       
   593                 }
       
   594                 else if (initialDistanceForPinching - currentDistanceOfPinching > pinchDelta) {
       
   595                     HW_zoomOut();
       
   596                     initialDistanceForPinching = currentDistanceOfPinching;
       
   597                 }
       
   598             } else
       
   599                 initialDistanceForPinching = currentDistanceOfPinching;
       
   600             break;
       
   601         default:
       
   602             break;
       
   603     }
       
   604 }
       
   605 
       
   606 @end