00001
00002
00003
00004
00005
00006
00007
00008
00009 #import "GameView.h"
00010
00011
00012 @implementation GameView
00013
00014 - (void) awakeFromNib {
00015
00016 [super awakeFromNib];
00017
00018 step = GV_SCALE_STEP;
00019 keyMap = nil;
00020 scale = 40;
00021 trigonometry = [LLTrigonometry defaultInstance];
00022
00023 angleConvertor = [[Entity alloc] init];
00024 busyDrawing = NO;
00025
00026 inputMode = GV_NORMAL_MODE;
00027 }
00028
00029 - (void) setPainter:(PainterFactory*)newPainter {
00030 painter = newPainter;
00031
00032 inputMode = GV_NORMAL_MODE;
00033 }
00034
00035 - (NSPoint) gamePointRepresentingCentreOfView {
00036 return [[universe playerThatIsMe] predictedPosition];
00037 }
00038
00039 - (void) setScaleFullView {
00040 NSSize viewSize = [self bounds].size;
00041
00042 int minSize = (viewSize.height < viewSize.width ? viewSize.height : viewSize.width);
00043
00044
00045 scale = UNIVERSE_PIXEL_SIZE / minSize;
00046 }
00047
00048 - (void) setScale:(int)newScale {
00049 scale = newScale;
00050 }
00051
00052 - (int) scale {
00053 return scale;
00054 }
00055
00056
00057 - (void)drawRect:(NSRect)aRect {
00058
00059
00060
00061 if (busyDrawing) {
00062 NSLog(@"GameView.drawRect busy drawing");
00063 return;
00064 }
00065 busyDrawing = YES;
00066
00067
00068 if ([[universe synchronizeAccess] lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:MAX_WAIT_BEFORE_DRAW]]) {
00069
00070
00071 NSRect gameBounds = [painter gameRectAround:[self gamePointRepresentingCentreOfView]
00072 forView:[self bounds]
00073 withScale:scale];
00074
00075 [painter drawRect:aRect
00076 ofViewBounds:[self bounds]
00077 whichRepresentsGameBounds:gameBounds
00078 withScale:scale];
00079
00080 [[universe synchronizeAccess] unlock];
00081 } else {
00082 NSLog(@"GameView.drawRect waited %f seconds for lock, discarding", MAX_WAIT_BEFORE_DRAW);
00083
00084
00085 NSRect gameBounds = [painter gameRectAround:[self gamePointRepresentingCentreOfView]
00086 forView:[self bounds]
00087 withScale:scale];
00088
00089 [painter drawRect:aRect
00090 ofViewBounds:[self bounds]
00091 whichRepresentsGameBounds:gameBounds
00092 withScale:scale];
00093
00094
00095 }
00096 busyDrawing = NO;
00097 }
00098
00099 - (void) setKeyMap:(MTKeyMap *)newKeyMap {
00100 keyMap = newKeyMap;
00101 }
00102
00103
00104 - (void) keyDown:(NSEvent *)theEvent {
00105
00106 if (keyMap == nil) {
00107 NSLog(@"GameView.keyDown have no keymap");
00108 [super keyDown:theEvent];
00109 return;
00110 }
00111
00112 switch (inputMode) {
00113 case GV_NORMAL_MODE:
00114 NSLog(@"GameView.keyDown handle in normal mode");
00115 [self normalModeKeyDown:theEvent];
00116 break;
00117 case GV_MESSAGE_MODE:
00118 NSLog(@"GameView.keyDown handle in message mode");
00119 [self messageModeKeyDown:theEvent];
00120 break;
00121 case GV_MACRO_MODE:
00122 NSLog(@"GameView.keyDown handle in macro mode");
00123 [self macroModeKeyDown:theEvent];
00124 break;
00125 case GV_REFIT_MODE:
00126 NSLog(@"GameView.keyDown handle in refit mode");
00127 [self refitModeKeyDown:theEvent];
00128 break;
00129 default:
00130 NSLog(@"GameView.keyDown unknown mode %d", inputMode);
00131
00132 inputMode = GV_NORMAL_MODE;
00133 break;
00134 }
00135 }
00136
00137 - (void) normalModeKeyDown:(NSEvent *)theEvent {
00138
00139
00140 NSString *characters = [theEvent characters];
00141
00142 for (int i = 0; i < [characters length]; i++) {
00143 unichar theChar = [characters characterAtIndex:i];
00144 unsigned int modifierFlags = [theEvent modifierFlags];
00145
00146 int action = [keyMap actionForKey:theChar withModifierFlags:modifierFlags];
00147
00148
00149 if (action == ACTION_UNKNOWN) {
00150 [super keyDown:theEvent];
00151 }
00152 else {
00153 if ([self performAction: action] == NO) {
00154 [super keyDown:theEvent];
00155 }
00156 }
00157 }
00158 }
00159
00160 - (void) messageModeKeyDown:(NSEvent *)theEvent {
00161
00162
00163 inputMode = GV_NORMAL_MODE;
00164
00165
00166
00167
00168
00169 unichar theChar = [[theEvent characters] characterAtIndex:0];
00170 int playerId = -1;
00171
00172 switch (theChar) {
00173 case 'A':
00174
00175 [notificationCenter postNotificationName:@"GV_MESSAGE_DEST" userInfo:@"ALL"];
00176 return;
00177 break;
00178 case 'G':
00179 case 'g':
00180 [notificationCenter postNotificationName:@"GV_MESSAGE_DEST" userInfo:@"GOD"];
00181 return;
00182 break;
00183 case 'T':
00184 case 't':
00185 [notificationCenter postNotificationName:@"GV_MESSAGE_DEST" userInfo:@"TEAM"];
00186 return;
00187 break;
00188 case 'F':
00189
00190 [notificationCenter postNotificationName:@"GV_MESSAGE_DEST" userInfo:@"FED"];
00191 return;
00192 break;
00193 case 'K':
00194 case 'k':
00195 [notificationCenter postNotificationName:@"GV_MESSAGE_DEST" userInfo:@"KLI"];
00196 return;
00197 break;
00198 case 'R':
00199 case 'r':
00200 [notificationCenter postNotificationName:@"GV_MESSAGE_DEST" userInfo:@"ROM"];
00201 return;
00202 break;
00203 case 'O':
00204 case 'o':
00205 [notificationCenter postNotificationName:@"GV_MESSAGE_DEST" userInfo:@"ORI"];
00206 return;
00207 break;
00208 case '0':
00209 case '1':
00210 case '2':
00211 case '3':
00212 case '4':
00213 case '5':
00214 case '6':
00215 case '7':
00216 case '8':
00217 case '9':
00218 playerId = theChar - '0';
00219 break;
00220 case 'a':
00221 case 'b':
00222 case 'c':
00223 case 'd':
00224 case 'e':
00225 case 'f':
00226 playerId = theChar - 'a' + 10;
00227 break;
00228 default:
00229 [notificationCenter postNotificationName:@"PM_WARNING" userInfo:@"Unknown player. message not sent."];
00230 return;
00231 break;
00232 }
00233 [notificationCenter postNotificationName:@"GV_MESSAGE_DEST"
00234 userInfo:[[universe playerWithId:playerId] mapChars]];
00235 }
00236
00237 - (void) macroModeKeyDown:(NSEvent *)theEvent {
00238
00239 NSLog(@"GameView.macroModeKeyDown not implemented");
00240
00241 inputMode = GV_NORMAL_MODE;
00242 }
00243
00244 - (void) refitModeKeyDown:(NSEvent *)theEvent {
00245
00246 inputMode = GV_NORMAL_MODE;
00247
00248
00249 unichar theChar = [[theEvent characters] characterAtIndex:0];
00250
00251 char ship_type = SHIP_CA;
00252 switch(theChar) {
00253 case 's' : case 'S' :
00254 ship_type = SHIP_SC;
00255 break;
00256 case 'd' : case 'D' :
00257 ship_type = SHIP_DD;
00258 break;
00259 case 'c' : case 'C' :
00260 ship_type = SHIP_CA;
00261 break;
00262 case 'b' : case 'B' :
00263 ship_type = SHIP_BB;
00264 break;
00265 case 'g' : case 'G' :
00266 ship_type = SHIP_GA;
00267 break;
00268 case 'o' : case 'O' :
00269 ship_type = SHIP_SB;
00270 break;
00271 case 'a' : case 'A' :
00272 ship_type = SHIP_AS;
00273 break;
00274 default :
00275 return;
00276 }
00277 [notificationCenter postNotificationName:@"COMM_SEND_REFIT_REQ" userInfo:[NSNumber numberWithChar:ship_type]];
00278 }
00279
00280
00281 - (void) mouseDown:(NSEvent *)theEvent {
00282 [self performAction:ACTION_FIRE_TORPEDO];
00283 }
00284
00285 - (void) otherMouseDown:(NSEvent *)theEvent {
00286 [self performAction:ACTION_FIRE_PHASER];
00287 }
00288
00289 - (void) dummyMouseAction {
00290
00291
00292
00293 [[self window] makeKeyWindow];
00294 [self becomeFirstResponder];
00295
00296 NSEvent *evt = [NSEvent mouseEventWithType:NSRightMouseDown
00297 location:[painter centreOfRect:[self bounds]]
00298 modifierFlags:256
00299 timestamp:GetCurrentEventTime()
00300 windowNumber:[[self window] windowNumber]
00301 context:[NSGraphicsContext currentContext]
00302 eventNumber:0
00303 clickCount:1
00304 pressure:0];
00305
00306 [[NSApplication sharedApplication] postEvent:evt atStart:YES];
00307 }
00308
00309 - (void) rightMouseDown:(NSEvent *)theEvent {
00310
00311 [self performAction:ACTION_SET_COURSE];
00312 }
00313
00314 - (void) scrollWheel:(NSEvent *)theEvent {
00315 float mouseRole = [theEvent deltaY];
00316
00317
00318 if (mouseRole > 0) {
00319
00320 int newScale = scale - step*scale;
00321 if (newScale == scale) {
00322 newScale = scale - 1;
00323 }
00324
00325
00326 if (newScale > [painter minScale]) {
00327 scale = newScale;
00328 }
00329 } else {
00330
00331
00332
00333 int newScale = scale + step*scale;
00334 if (newScale == scale) {
00335 newScale = scale + 1;
00336 }
00337 if (newScale < [painter maxScale]) {
00338 scale = newScale;
00339 }
00340 }
00341 NSLog(@"GameView.scrollWheel setting scale to %d", scale);
00342 }
00343
00344
00345 - (void) sendSpeedReq:(int)speed {
00346 if (universe == nil) {
00347 NSLog(@"GameView.sendSpeedReq have no universe?");
00348 }
00349
00350 int maxSpeed = [[[universe playerThatIsMe] ship] maxSpeed];
00351 if (speed > maxSpeed) {
00352 speed = maxSpeed;
00353 }
00354
00355 [[universe playerThatIsMe] setRequestedSpeed:speed];
00356 [notificationCenter postNotificationName:@"COMM_SEND_SPEED_REQ" userInfo:[NSNumber numberWithInt:speed]];
00357 }
00358
00359 - (float) mouseDir {
00360
00361 NSPoint mouseLocation = [self mousePos];
00362
00363
00364 NSPoint ourLocation;
00365 NSRect bounds = [self bounds];
00366 ourLocation.x = bounds.size.width / 2;
00367 ourLocation.y = bounds.size.height / 2;
00368
00369
00370 float dir = [trigonometry angleDegBetween:mouseLocation andPoint:ourLocation];
00371 dir -= 90;
00372 if (dir < 0) {
00373 dir += 360;
00374 }
00375
00376
00377 return dir;
00378 }
00379
00380
00381 - (bool) performAction:(int) action {
00382
00383
00384
00385 int maxSpeed, speed;
00386 Player *target = nil;
00387 Planet *planet = nil;
00388 NSPoint targetGamePoint;
00389 Player *me = [universe playerThatIsMe];
00390
00391 switch (action) {
00392 case ACTION_UNKNOWN:
00393 NSLog(@"GameView.performAction unknown action %d", action);
00394 return NO;
00395 break;
00396 case ACTION_CLOAK:
00397 if ([[universe playerThatIsMe] flags] & PLAYER_CLOAK) {
00398 [notificationCenter postNotificationName:@"COMM_SEND_CLOAK_REQ" userInfo:[NSNumber numberWithBool:NO]];
00399 } else {
00400 [notificationCenter postNotificationName:@"COMM_SEND_CLOAK_REQ" userInfo:[NSNumber numberWithBool:YES]];
00401 }
00402 break;
00403 case ACTION_DET_ENEMY:
00404
00405
00406 [notificationCenter postNotificationName:@"COMM_SEND_DETONATE_REQ" userInfo:nil];
00407 break;
00408 case ACTION_DET_OWN:
00409 [notificationCenter postNotificationName:@"COMM_SEND_DET_MINE_ALL_REQ" userInfo:nil];
00410 break;
00411 case ACTION_FIRE_PLASMA:
00412
00413 [angleConvertor setCourse:[self mouseDir]];
00414 [notificationCenter postNotificationName:@"COMM_SEND_PLASMA_REQ" userInfo:[NSNumber numberWithChar:[angleConvertor netrekFormatCourse]]];
00415 break;
00416 case ACTION_FIRE_TORPEDO:
00417 [angleConvertor setCourse:[self mouseDir]];
00418 [notificationCenter postNotificationName:@"COMM_SEND_TORPS_REQ" userInfo:[NSNumber numberWithChar:[angleConvertor netrekFormatCourse]]];
00419 break;
00420 case ACTION_FIRE_PHASER:
00421 [angleConvertor setCourse:[self mouseDir]];
00422 [notificationCenter postNotificationName:@"COMM_SEND_PHASER_REQ" userInfo:[NSNumber numberWithChar:[angleConvertor netrekFormatCourse]]];
00423 break;
00424 case ACTION_SHIELDS:
00425 if ([me flags] & PLAYER_SHIELD) {
00426 [notificationCenter postNotificationName:@"COMM_SEND_SHIELD_REQ" userInfo:[NSNumber numberWithBool:NO]];
00427 } else {
00428 [notificationCenter postNotificationName:@"COMM_SEND_SHIELD_REQ" userInfo:[NSNumber numberWithBool:YES]];
00429 }
00430 break;
00431 case ACTION_TRACTOR:
00432
00433 targetGamePoint = [painter gamePointFromViewPoint:[self mousePos]
00434 viewRect:[self bounds]
00435 gamePosInCentreOfView:[self gamePointRepresentingCentreOfView]
00436 withScale:scale];
00437
00438 target = [universe playerNearPosition:targetGamePoint ofType:UNIVERSE_TARG_PLAYER];
00439
00440
00441 if ([[universe playerThatIsMe] flags] & PLAYER_TRACT) {
00442
00443 [notificationCenter postNotificationName:@"COMM_SEND_TRACTOR_OFF_REQ"
00444 userInfo:[NSNumber numberWithInt:[target playerId]]];
00445 } else {
00446 [notificationCenter postNotificationName:@"COMM_SEND_TRACTOR_ON_REQ"
00447 userInfo:[NSNumber numberWithInt:[target playerId]]];
00448 [[universe playerThatIsMe] setTractorTarget:target];
00449 }
00450 break;
00451 case ACTION_PRESSOR:
00452
00453 targetGamePoint = [painter gamePointFromViewPoint:[self mousePos]
00454 viewRect:[self bounds]
00455 gamePosInCentreOfView:[self gamePointRepresentingCentreOfView]
00456 withScale:scale];
00457
00458 target = [universe playerNearPosition:targetGamePoint ofType:UNIVERSE_TARG_PLAYER];
00459
00460
00461 if ([[universe playerThatIsMe] flags] & PLAYER_PRESS) {
00462
00463 [notificationCenter postNotificationName:@"COMM_SEND_REPRESSOR_OFF_REQ"
00464 userInfo:[NSNumber numberWithInt:[target playerId]]];
00465 } else {
00466 [notificationCenter postNotificationName:@"COMM_SEND_REPRESSOR_ON_REQ"
00467 userInfo:[NSNumber numberWithInt:[target playerId]]];
00468
00469
00470 [[universe playerThatIsMe] setTractorTarget:target];
00471 }
00472 break;
00473 case ACTION_WARP_0:
00474 [self sendSpeedReq:0];
00475 break;
00476 case ACTION_WARP_1:
00477 [self sendSpeedReq:1];
00478 break;
00479 case ACTION_WARP_2:
00480 [self sendSpeedReq:2];
00481 break;
00482 case ACTION_WARP_3:
00483 [self sendSpeedReq:3];
00484 break;
00485 case ACTION_WARP_4:
00486 [self sendSpeedReq:4];
00487 break;
00488 case ACTION_WARP_5:
00489 [self sendSpeedReq:5];
00490 break;
00491 case ACTION_WARP_6:
00492 [self sendSpeedReq:6];
00493 break;
00494 case ACTION_WARP_7:
00495 [self sendSpeedReq:7];
00496 break;
00497 case ACTION_WARP_8:
00498 [self sendSpeedReq:8];
00499 break;
00500 case ACTION_WARP_9:
00501 [self sendSpeedReq:9];
00502 break;
00503 case ACTION_WARP_10:
00504 [self sendSpeedReq:10];
00505 break;
00506 case ACTION_WARP_11:
00507 [self sendSpeedReq:11];
00508 break;
00509 case ACTION_WARP_12:
00510 [self sendSpeedReq:0];
00511 break;
00512 case ACTION_WARP_MAX:
00513 maxSpeed = [[[universe playerThatIsMe] ship] maxSpeed];
00514 [self sendSpeedReq:maxSpeed];
00515 break;
00516 case ACTION_WARP_HALF_MAX:
00517 maxSpeed = [[[universe playerThatIsMe] ship] maxSpeed];
00518 [self sendSpeedReq:maxSpeed / 2];
00519 break;
00520 case ACTION_WARP_INCREASE:
00521 speed = [[universe playerThatIsMe] speed];
00522 [self sendSpeedReq:speed + 1];
00523 break;
00524 case ACTION_WARP_DECREASE:
00525 speed = [[universe playerThatIsMe] speed];
00526 [self sendSpeedReq:speed - 1];
00527 break;
00528 case ACTION_SET_COURSE:
00529 [angleConvertor setCourse:[self mouseDir]];
00530 [notificationCenter postNotificationName:@"COMM_SEND_DIR_REQ" userInfo:[NSNumber numberWithChar:[angleConvertor netrekFormatCourse]]];
00531
00532 [me setFlags:[me flags] & ~(PLAYER_PLOCK | PLAYER_PLLOCK)];
00533 break;
00534 case ACTION_LOCK:
00535
00536 targetGamePoint = [painter gamePointFromViewPoint:[self mousePos]
00537 viewRect:[self bounds]
00538 gamePosInCentreOfView:[self gamePointRepresentingCentreOfView]
00539 withScale:scale];
00540
00541 target = [universe playerNearPosition:targetGamePoint ofType:UNIVERSE_TARG_PLAYER];
00542
00543 planet = [universe planetNearPosition:targetGamePoint];
00544
00545 if ([universe entity:target closerToPos:targetGamePoint than:planet]) {
00546
00547 [notificationCenter postNotificationName:@"COMM_SEND_PLAYER_LOCK_REQ"
00548 userInfo:[NSNumber numberWithInt:[target playerId]]];
00549 [me setPlayerLock:target];
00550 } else {
00551
00552 [notificationCenter postNotificationName:@"COMM_SEND_PLANET_LOCK_REQ"
00553 userInfo:[NSNumber numberWithInt:[planet planetId]]];
00554 [me setPlanetLock:planet];
00555 }
00556 break;
00557 case ACTION_PRACTICE_BOT:
00558 [notificationCenter postNotificationName:@"COMM_SEND_PRACTICE_REQ"];
00559 break;
00560 case ACTION_TRANSWARP:
00561
00562
00563 [notificationCenter postNotificationName:@"COMM_SEND_PRACTICE_REQ"];
00564 break;
00565 case ACTION_BOMB:
00566 if (([me flags] & PLAYER_BOMB) == 0) {
00567 [notificationCenter postNotificationName:@"COMM_SEND_BOMB_REQ"
00568 userInfo:[NSNumber numberWithBool:YES]];
00569 }
00570 break;
00571 case ACTION_ORBIT:
00572 [notificationCenter postNotificationName:@"COMM_SEND_ORBIT_REQ"
00573 userInfo:[NSNumber numberWithBool:YES]];
00574 break;
00575 case ACTION_BEAM_DOWN:
00576 if (([me flags] & PLAYER_BEAMDOWN) == 0) {
00577 [notificationCenter postNotificationName:@"COMM_SEND_BEAM_REQ"
00578 userInfo:[NSNumber numberWithBool:NO]];
00579 }
00580 break;
00581 case ACTION_BEAM_UP:
00582 if (([me flags] & PLAYER_BEAMUP) == 0) {
00583 [notificationCenter postNotificationName:@"COMM_SEND_BEAM_REQ"
00584 userInfo:[NSNumber numberWithBool:YES]];
00585 }
00586 break;
00587 case ACTION_DISTRESS_CALL:
00588 NSLog(@"GameView.performAction Marcro's not implemented");
00589 break;
00590 case ACTION_ARMIES_CARRIED_REPORT:
00591 NSLog(@"GameView.performAction Marcro's not implemented");
00592 break;
00593 case ACTION_MESSAGE:
00594
00595
00596 [notificationCenter postNotificationName:@"GV_MODE_INFO" userInfo:@"A=all, [TFORK]=team, [0..f]=player"];
00597 inputMode = GV_MESSAGE_MODE;
00598
00599
00600 break;
00601 case ACTION_DOCK_PERMISSION:
00602 if (([me flags] & PLAYER_DOCKOK) == 0) {
00603 [notificationCenter postNotificationName:@"COMM_SEND_DOCK_REQ"
00604 userInfo:[NSNumber numberWithBool:YES]];
00605 } else {
00606 [notificationCenter postNotificationName:@"COMM_SEND_DOCK_REQ"
00607 userInfo:[NSNumber numberWithBool:NO]];
00608 }
00609 break;
00610 case ACTION_INFO:
00611
00612 targetGamePoint = [painter gamePointFromViewPoint:[self mousePos]
00613 viewRect:[self bounds]
00614 gamePosInCentreOfView:[self gamePointRepresentingCentreOfView]
00615 withScale:scale];
00616
00617 target = [universe playerNearPosition:targetGamePoint ofType:(UNIVERSE_TARG_PLAYER | UNIVERSE_TARG_SELF)];
00618
00619 planet = [universe planetNearPosition:targetGamePoint];
00620
00621 if ([universe entity:target closerToPos:targetGamePoint than:planet]) {
00622
00623 [target setShowInfo:![target showInfo]];
00624 } else {
00625 [planet setShowInfo:![planet showInfo]];
00626 }
00627 break;
00628 case ACTION_REFIT:
00629
00630
00631 [notificationCenter postNotificationName:@"GV_MODE_INFO" userInfo:@"s=scout, d=destroyer, c=cruiser, b=battleship, a=assault, g=galaxy, o=starbase"];
00632 inputMode = GV_REFIT_MODE;
00633
00634 break;
00635 case ACTION_REPAIR:
00636
00637 [notificationCenter postNotificationName:@"COMM_SEND_REPAIR_REQ"
00638 userInfo:[NSNumber numberWithBool:YES]];
00639 break;
00640 case ACTION_QUIT:
00641
00642
00643 break;
00644 case ACTION_HELP:
00645 NSLog(@"GameView.performAction HELP not implemented");
00646 case ACTION_DEBUG:
00647 [painter setDebugLabels:![painter debugLabels]];
00648 break;
00649 default:
00650 NSLog(@"GameView.performAction unknown action %d", action);
00651 return NO;
00652 break;
00653 }
00654 return YES;
00655 }
00656
00657 @end