Painter/PainterFactory.m

00001 //
00002 //  PainterFactory.m
00003 //  MacTrek
00004 //
00005 //  Created by Aqua on 19/06/2006.
00006 //  Copyright 2006 Luky Soft. All rights reserved.
00007 //
00008 
00009 #import "PainterFactory.h"
00010 
00011 @implementation PainterFactory
00012 
00013 
00014 #define ALERT_FILTER (PLAYER_GREEN | PLAYER_YELLOW | PLAYER_RED)
00015 
00016 - (id) init {
00017     self = [super init];
00018     if (self != nil) {
00019         // init vars
00020         backGroundStartPoint.x = 0;
00021         backGroundStartPoint.y = 0;
00022         debugLabels = NO;
00023         simple = NO;
00024         alert = PLAYER_GREEN;
00025         
00026         //create helpers
00027         trigonometry = [LLTrigonometry defaultInstance];
00028         shapes = [[LLShapes alloc] init];
00029         universe = [Universe defaultInstance];
00030         line = [[NSBezierPath alloc] init];        
00031         dashedLine = [[NSBezierPath alloc] init];
00032         float dash = { 1.0, 3.0 };
00033         [dashedLine setLineDash: dash count: 2 phase: 0.0]; 
00034         
00035         normalStateAttribute =[[NSDictionary dictionaryWithObjectsAndKeys:
00036         [NSColor whiteColor],NSForegroundColorAttributeName,nil] retain];
00037         // initial cache is in seperate thread
00038         [NSThread detachNewThreadSelector:@selector(cacheImagesInSeperateThread:) toTarget:self withObject:nil];
00039 
00040     }
00041     return self;
00042 }
00043 
00044 - (void) setSimplifyDrawing:(bool)simpleDraw {
00045     simple = simpleDraw;
00046 }
00047 
00048 - (void) setDebugLabels:(bool)debug {
00049     debugLabels = debug;
00050 }
00051 
00052 - (bool) debugLabels {
00053     return debugLabels;
00054 }
00055 
00056 - (int) maxScale {
00057     return 400; // 10* netrek zoom out
00058 }
00059 
00060 - (int) minScale {
00061     return 2;   // netrek game grid
00062 }
00063 
00064 // overrule in subclass to cache the images
00065 - (void) cacheImages {
00066     // takes about 5 seconds..
00067     sleep(2);
00068 }
00069 
00070 - (void) cacheImagesInSeperateThread:(id)sender {
00071     
00072     // create a private pool for this thread
00073     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00074     
00075     NSLog(@"PainterFactory.cacheImagesInSeperateThread: start running");
00076     [self cacheImages];
00077     NSLog(@"PainterFactory.cacheImagesInSeperateThread: complete");
00078     
00079     [notificationCenter postNotificationName:@"PF_IMAGES_CACHED"];
00080     
00081     // release the pool
00082     [pool release];
00083 }
00084 
00085 - (NSSize) backGroundImageSize {
00086     return PF_DEFAULT_BACKGROUND_IMAGE_SIZE;
00087 }
00088 
00089 - (NSColor*) colorForTeam:(Team*)team {
00090     return [team colorForTeam];
00091 }
00092 
00093 - (NSPoint) centreOfRect:(NSRect)aRect {
00094 
00095     return [shapes centreOfRect:aRect];
00096 }
00097 
00098 - (NSPoint) gamePointFromViewPoint:(NSPoint)point withMeInViewRect:(NSRect)bounds withScale:(int)scale {
00099      
00100     // our game pos
00101     NSPoint centrePos = [[universe playerThatIsMe] predictedPosition];
00102     return [self gamePointFromViewPoint:point viewRect:bounds gamePosInCentreOfView:centrePos withScale:scale];
00103 }
00104 
00105 - (NSPoint) gamePointFromViewPoint:(NSPoint)point viewRect:(NSRect)bounds 
00106              gamePosInCentreOfView:(NSPoint)centrePos withScale:(int)scale {
00107     
00108     // we are in the center of our view, thus bounds / 2
00109     // get the relative position in the view
00110     int deltaX = point.x - (bounds.size.width / 2);
00111     int deltaY = point.y - (bounds.size.height / 2);
00112 
00113     
00114     // the point is relative to me with scaling
00115     NSPoint gamePoint;
00116     gamePoint.x = centrePos.x + deltaX*scale;
00117     gamePoint.y = centrePos.y + deltaY*scale;
00118     
00119     return gamePoint;    
00120 }
00121 
00122 // warning: this does not effect the origin
00123 // for that i need to know the view bounds
00124 - (NSSize)  gameSizeFromViewSize:(NSSize)rect withScale:(int)scale {
00125     
00126     NSSize size;
00127     
00128     size.height = rect.height*scale;
00129     size.width  = rect.width*scale;
00130     
00131     return size;
00132 }
00133     
00134 - (NSRect) gameRectAround:(NSPoint)gamePoint forView:(NSRect)bounds withScale:(int)scale {
00135             
00136     // optimise a little
00137     static NSRect result;
00138     static NSRect previousBounds;
00139     static int previousScale;
00140 
00141     previousScale = scale;
00142     previousBounds = bounds;
00143     
00144     // resize the bounds to the right scale
00145     result.size = [self gameSizeFromViewSize:bounds.size withScale:scale];
00146     
00147     // the view frame starts at 0,0 but that is not the origin of
00148     // the game view
00149     result.origin = [self gamePointFromViewPoint:bounds.origin
00150                                         viewRect:bounds 
00151                            gamePosInCentreOfView:gamePoint 
00152                                        withScale:scale];  
00153     return result;
00154 }
00155 
00156 - (NSSize)  viewSizeFromGameSize:(NSSize)rect withScale:(int)scale{
00157     
00158     NSSize size;
00159     
00160     size.height = rect.height / scale;
00161     size.width  = rect.width / scale;
00162     
00163     return size;
00164 }
00165 
00166 - (NSPoint) viewPointFromGamePoint:(NSPoint)point withMeInViewRect:(NSRect)bounds withScale:(int)scale {    
00167     // our game pos
00168     NSPoint centrePos = [[universe playerThatIsMe] predictedPosition];
00169     return [self viewPointFromGamePoint:point viewRect:bounds gamePosInCentreOfView:centrePos withScale:scale];
00170 }
00171 
00172 - (NSPoint) viewPointFromGamePoint:(NSPoint)point viewRect:(NSRect)bounds 
00173              gamePosInCentreOfView:(NSPoint)centrePos withScale:(int)scale {
00174     // offset to the other point
00175     int deltaX = point.x - centrePos.x;
00176     int deltaY = point.y - centrePos.y;
00177     
00178     // we are in the center of our view, thus bounds / 2
00179     // the point is relative to me with scaling
00180     NSPoint viewPoint;
00181     viewPoint.x = (bounds.size.width / 2) + deltaX / scale;
00182     viewPoint.y = (bounds.size.height / 2) + deltaY / scale;
00183     
00184     return viewPoint;    
00185 }
00186 
00187 - (void) drawAlertBorder:(NSRect) bounds forMe:(Player *)me {
00188     
00189     // Change border color to signify alert status
00190     if (alert != ([me flags] & ALERT_FILTER)) {
00191         alert = ([me flags] & ALERT_FILTER);
00192         // probably START on change to RED, abort on all other
00193         [notificationCenter postNotificationName:@"PL_ALERT_STATUS_CHANGED" userInfo:[NSNumber numberWithInt:alert]]; 
00194     }
00195     if ([me flags] & ALERT_FILTER) {
00196         switch (alert) {
00197                         case PLAYER_GREEN :
00198                 [[NSColor greenColor] set];
00199                                 break;
00200                         case PLAYER_YELLOW :
00201                 [[NSColor yellowColor] set];
00202                                 break;
00203                         case PLAYER_RED :
00204                 [[NSColor redColor] set];
00205                                 break;
00206         }               
00207 
00208         // draw the border
00209         [line removeAllPoints];
00210         [line appendBezierPathWithRect:bounds];
00211         float oldWidth = [line lineWidth]; // remember
00212         [line setLineWidth: PF_ALERT_BORDER_WIDTH];
00213         [line stroke];
00214         [line setLineWidth:oldWidth]; // restore
00215     }
00216     
00217 }
00218 
00219 - (void) drawBackgroundInRect:(NSRect) drawingBounds ofViewBounds:(NSRect)viewBounds forMe:(Player*) me {
00220     
00221     // get the size of the stamp
00222     NSSize backGroundImageSize = [self backGroundImageSize];
00223     // use a local var so we can debug...
00224     NSPoint startPoint = backGroundStartPoint;
00225     
00226     // $$ scale the stars (nah don't do that)
00227     
00228     // move the start point away  in the oposite dir, based on my speed
00229     float course = [me course];
00230     
00231     startPoint.x -= cos(course) * (float)[me speed] / 4.0f;
00232     startPoint.y -= sin(course) * (float)[me speed] / 4.0f;
00233     
00234     //NSLog(@"### c %f sp (%f, %f)", course, startPoint.x, startPoint.y);
00235     
00236     // repeat the bitmap if it shifted completely out of view
00237     if(startPoint.x < -backGroundImageSize.width) {
00238         startPoint.x += backGroundImageSize.width;
00239     }
00240     else if(startPoint.x > 0.0f) {
00241         startPoint.x -= backGroundImageSize.width;
00242     } 
00243     if(startPoint.y < -backGroundImageSize.height) {
00244         startPoint.y += backGroundImageSize.height;
00245     }
00246     else if(startPoint.y > 0.0f) {
00247         startPoint.y -= backGroundImageSize.height;     
00248     }
00249     
00250     // paint the image all over the the bounds that have been given for view
00251     NSRect targetArea;
00252     // $$ do not scale the stars here?
00253     targetArea.size = backGroundImageSize;
00254     // go and paint 
00255     for(int y = (int)startPoint.y; y < viewBounds.size.height; y += backGroundImageSize.height) {
00256         for(int x = (int)startPoint.x; x < viewBounds.size.width; x += backGroundImageSize.width) {
00257             targetArea.origin.x = x;
00258             targetArea.origin.y = y;
00259             
00260             // is the image in the drawing rectangle?
00261             if (!NSIntersectsRect(targetArea, drawingBounds)) {
00262                 continue;
00263             } 
00264             
00265             [self drawBackgroundImageInRect: targetArea];
00266         }
00267     } 
00268     
00269     backGroundStartPoint = startPoint;
00270 }
00271 
00272 - (void) drawGalaxyEdgesInRect:(NSRect) drawingBounds forGameRect:(NSRect)gameBounds ofViewBounds:(NSRect)viewBounds withScale:(int)scale {
00273     
00274     // the line color
00275     [[NSColor brownColor] set];
00276     
00277     // orgin in view coordinates
00278     NSPoint upperLeft = [self viewPointFromGamePoint:NSMakePoint(0, 0) 
00279                                             viewRect:viewBounds
00280                                gamePosInCentreOfView:[self centreOfRect:gameBounds]
00281                                            withScale:scale];
00282     NSPoint lowerRight = [self viewPointFromGamePoint:NSMakePoint(UNIVERSE_PIXEL_SIZE, UNIVERSE_PIXEL_SIZE)
00283                                              viewRect:viewBounds 
00284                                 gamePosInCentreOfView:[self centreOfRect:gameBounds] 
00285                                             withScale:scale];
00286     
00287     // $$ but do we need to draw it ? check with drawingBounds to make sure...
00288     // $$ todo, but it is only a few lines    
00289     
00290     // are we near the north line?
00291     if (gameBounds.origin.y <= 0) {
00292         [line removeAllPoints];
00293         [line moveToPoint:upperLeft];
00294         [line lineToPoint:NSMakePoint(lowerRight.x, upperLeft.y)];
00295         [line stroke];        
00296     }
00297     
00298     // are we near the south line?
00299     if (gameBounds.origin.y + gameBounds.size.height > UNIVERSE_PIXEL_SIZE) {
00300         [line removeAllPoints];
00301         [line moveToPoint:lowerRight];
00302         [line lineToPoint:NSMakePoint(upperLeft.x, lowerRight.y)];
00303         [line stroke];        
00304     }
00305     
00306     // are we near the west line?
00307     if (gameBounds.origin.x <= 0) {       
00308         [line removeAllPoints];
00309         [line moveToPoint:upperLeft];
00310         [line lineToPoint:NSMakePoint(upperLeft.x, lowerRight.y)];
00311         [line stroke];        
00312     }
00313     
00314     // are we near the east line?
00315     if (gameBounds.origin.x + gameBounds.size.width > UNIVERSE_PIXEL_SIZE) {
00316         [line removeAllPoints];
00317         [line moveToPoint:lowerRight];
00318         [line lineToPoint:NSMakePoint(lowerRight.x, upperLeft.y)];
00319         [line stroke];        
00320     }
00321     
00322 }
00323 
00324 - (void)drawPlanetsInRect:(NSRect)drawingBounds forGameRect:(NSRect)gameBounds ofViewBounds:(NSRect)viewBounds withScale:(int)scale {
00325     
00326     NSRect planetGameBounds;
00327     NSRect planetViewBounds;
00328     Planet *planet;
00329     NSPoint centreOfGameBounds = [self centreOfRect:gameBounds];
00330     
00331     // request it once for efficiency, planets do not change maxFuse
00332     // (like explode)
00333     int maxFuse = [self maxFuseForPlanet];
00334     
00335     for (int i = 0; i < UNIVERSE_MAX_PLANETS; i++) {
00336         planet = [universe planetWithId:i];
00337         
00338         // ---
00339         // check for fuse and status changes
00340         // ---       
00341         // check fuse overrun (maxfuse (n) sets the number of frames 0..n-1)
00342         if ((!simple) &&([planet fuse] >= maxFuse)) {
00343             // reset the counter we will loop the images for  planets
00344             [planet setFuse:0];                
00345         }
00346         
00347         // ---
00348         // the actual drawing code
00349         // ---
00350         
00351         // get the rect around the planet in game coordinates
00352         planetGameBounds.origin = [planet predictedPosition];
00353         planetGameBounds.size = [planet size];
00354         // offset the origin to the upper left
00355         planetGameBounds.origin.x -= planetGameBounds.size.width / 2;
00356         planetGameBounds.origin.y -= planetGameBounds.size.height / 2;
00357         
00358         // convert to the view 
00359         planetViewBounds.size = [self viewSizeFromGameSize: planetGameBounds.size withScale: scale];
00360         planetViewBounds.origin = [self viewPointFromGamePoint: planetGameBounds.origin 
00361                                                       viewRect:viewBounds
00362                                          gamePosInCentreOfView:centreOfGameBounds
00363                                                      withScale:scale];
00364         
00365         // is the planet in the drawing rectangle?
00366         if (!NSIntersectsRect(planetViewBounds, drawingBounds)) {
00367             continue;
00368         } 
00369         
00370         // draw it
00371         [self drawPlanet: planet inRect:planetViewBounds];
00372         if (!simple) {   // in simple mode we do not increase counters
00373             [planet increaseFuse];
00374             //NSLog(@"PainterFactory.drawPlanet %@ increased fuse to %d", [planet name], [planet fuse]);
00375         }
00376                 
00377         // draw the name
00378         [self drawLabelForPlanet:planet belowRect:planetViewBounds];
00379     }
00380     
00381 }
00382 
00383 - (void)drawPlayersInRect:(NSRect)drawingBounds forGameRect:(NSRect)gameBounds ofViewBounds:(NSRect)viewBounds  withScale:(int)scale {
00384     
00385     NSRect playerGameBounds;
00386     NSRect playerViewBounds;
00387     Player *player;
00388     Player *me = [universe playerThatIsMe];
00389     NSPoint centreOfGameBounds = [self centreOfRect:gameBounds];
00390     
00391     for (int i = 0; i < UNIVERSE_MAX_PLAYERS; i++) {
00392         player = [universe playerWithId:i];
00393                
00394         // see if this player is active
00395         if (([player status] != PLAYER_ALIVE && [player status] != PLAYER_EXPLODE) || ([player flags] & PLAYER_OBSERV) != 0) {
00396             [player setPreviousStatus:[player status]];
00397             continue;
00398         }
00399         
00400         // handle the drawing of cloak phase frames
00401         if (([player flags] & PLAYER_CLOAK) != 0) {
00402             if ([player cloakPhase] < (PLAYER_CLOAK_PHASES - 1)) {
00403                 if([player isMe] && [player cloakPhase] == 0) {
00404                     [notificationCenter postNotificationName:@"PL_CLOAKING" userInfo:[NSNumber numberWithBool:YES]];                   
00405                 }
00406                 [player increaseCloakPhase];
00407             }
00408         }
00409         else if ([player cloakPhase] > 0) {
00410             if ([player cloakPhase] == PLAYER_CLOAK_PHASES - 1) {
00411                 // $$ do not report others YET
00412                 if ([player isMe]) {
00413                     [notificationCenter postNotificationName:@"PL_UNCLOAKING" userInfo:[NSNumber numberWithBool:NO]];
00414                 }
00415             }
00416             else {
00417                 // $$ do not report others YET
00418                 //[notificationCenter postNotificationName:@"PL_CLOAKING" userInfo:[NSNumber numberWithBool:YES]];
00419             }
00420             [player decreaseCloakPhase];
00421         }
00422         
00423         // ---
00424         // check for fuse and status changes
00425         // ---
00426         
00427         // check fuse overrun (maxfuse (n) sets the number of frames 0..n-1)
00428         if ([player fuse] >= [player maxfuse]) {
00429             // we have drawn all frames for this phase do we need to loop?
00430             if (([player status] == PLAYER_EXPLODE) &&
00431                 ([player previousStatus] == PLAYER_EXPLODE)) {
00432                 // report if i died
00433                 if ([player isMe]) {
00434                     [notificationCenter postNotificationName:@"PL_I_DIED" userInfo:player]; 
00435                 }
00436                 // we have completed the process of exploding
00437                 [player setStatus:PLAYER_OUTFIT];
00438                 // next state will be moving
00439                 [player setFuse:0];
00440                 [player setMaxFuse:[self maxFuseForMovingPlayer]];
00441                 // no need to draw it.
00442                 continue; 
00443             }
00444             // if we are not exploding we are moving, thus reset the counter
00445             // we will loop the images for moving players
00446             [player setFuse:0];                
00447         }
00448                
00449         // check for detonate
00450         if (([player status] == PLAYER_EXPLODE) &&
00451             ([player previousStatus] != PLAYER_EXPLODE)) {
00452             // set the fuse
00453             [player setFuse:0];
00454             [player setMaxFuse:[self maxFuseForExplodingPlayer]];
00455             // it just went boom
00456             [notificationCenter postNotificationName:@"PL_PLAYER_EXPLODED" userInfo:player];
00457         }
00458         
00459         // we have tested all status changes, so preserve the previous for
00460         // the next run
00461         [player setPreviousStatus:[player status]];            
00462         
00463         // ---
00464         // the actual drawing code of the player
00465         // ---   
00466 
00467         // get the rect around the player in game coordinates
00468         playerGameBounds.origin = [player predictedPosition];
00469         playerGameBounds.size = [[player ship] size];
00470         // offset the origin to the upper left
00471         playerGameBounds.origin.x -= playerGameBounds.size.width / 2;
00472         playerGameBounds.origin.y -= playerGameBounds.size.height / 2;
00473         
00474         // convert to the view         
00475         playerViewBounds.size = [self viewSizeFromGameSize: playerGameBounds.size withScale: scale];
00476         playerViewBounds.origin = [self viewPointFromGamePoint: playerGameBounds.origin 
00477                                                       viewRect:viewBounds
00478                                          gamePosInCentreOfView:centreOfGameBounds
00479                                                      withScale:scale];
00480         
00481         // is the player in the drawing rectangle?
00482         if (!NSIntersectsRect(playerViewBounds, drawingBounds)) {
00483             continue;
00484         } 
00485         
00486         // draw it
00487         [self rotateAndDrawPlayer: player inRect:playerViewBounds];
00488     
00489         [player increaseFuse]; // move to next image in frame
00490         
00491         // ---
00492         // the actual drawing code of the label
00493         // ---  
00494         
00495         // draw name
00496         [self drawLabelForPlayer:player belowRect:playerViewBounds];
00497         
00498         if (simple) {   // in simple mode we do not draw any weapons
00499             continue;
00500         }
00501         
00502         // ---
00503         // the actual drawing code of the shields
00504         // ---  
00505         
00506         // check shield raised, lowered
00507         if (([player flags] & PLAYER_SHIELD) &&
00508             !([player previousFlags] & PLAYER_SHIELD)) {
00509             // the player raised shields
00510             [notificationCenter postNotificationName:@"PL_SHIELD_UP_PLAYER" userInfo:player];
00511         }         
00512         if (!([player flags] & PLAYER_SHIELD) &&
00513             ([player previousFlags] & PLAYER_SHIELD)) {
00514             // the player lowered shields
00515             [notificationCenter postNotificationName:@"PL_SHIELD_DOWN_PLAYER" userInfo:player];
00516         }         
00517         [player setPreviousFlags:[player flags]];   
00518         
00519         // calculate in percent and draw shields
00520         if ([player flags] & PLAYER_SHIELD) {
00521             float shieldStrenght = 100.0;
00522             if ([player isMe]) {
00523                 shieldStrenght = [player shield] * 100 / [[player ship] maxShield];
00524             }
00525             [self drawShieldWithStrenght: shieldStrenght inRect:playerViewBounds];            
00526         }
00527         
00528         // save this value, we may need it again
00529         NSPoint playerPositionInView = [self viewPointFromGamePoint: [player predictedPosition] 
00530                                                            viewRect:viewBounds
00531                                               gamePosInCentreOfView:centreOfGameBounds
00532                                                           withScale:scale];        
00533         // ---
00534         // the actual drawing code of the phaser
00535         // ---  
00536         
00537         // draw the players phaser
00538         Phaser *phaser = [universe phaserWithId:[player phaserId]];
00539         NSPoint phaserEndPoint;
00540         
00541         if ([phaser status] != PHASER_FREE) {
00542             if([phaser previousStatus] == PHASER_FREE) { // from free to not free
00543                 if ([player isMe]) {
00544                     [notificationCenter postNotificationName:@"PL_MY_PHASER_FIRING" userInfo:phaser];
00545                 } else {
00546                     [notificationCenter postNotificationName:@"PL_OTHER_PHASER_FIRING" userInfo:phaser];
00547                 }                
00548             }
00549             
00550             float compute;
00551             switch ([phaser status]) { 
00552                                 case PHASER_MISS:
00553                                         // Here I will have to compute the end coordinate
00554                                         compute = PHASER_MAX_DISTANCE * ([[player ship] phaserDamage ] / 100.0f);
00555                     // use radian conversion or tri
00556                     //NSLog(@"deg %d rad %f, cos %f, sin %f disx %d disy %d, px %f, py %f", 
00557                     //[phaser course], [phaser dirInRad],
00558                     //      sinf([phaser dirInRad]), cosf([phaser dirInRad]),
00559                     //      (int) (compute * cosf([phaser dirInRad])), (int)(compute * sinf([phaser dirInRad])),
00560                     //      [player predictedPosition].x, [player predictedPosition].y);
00561                                         phaserEndPoint.x = (int)([player predictedPosition].x + (int)(compute * sinf([phaser dirInRad]))); 
00562                     phaserEndPoint.y = (int)([player predictedPosition].y - (int)(compute * cosf([phaser dirInRad]))); // flipped coordinates
00563                                         break;
00564                     
00565                                 case PHASER_HIT2:
00566                                         phaserEndPoint = [phaser predictedPosition];
00567                                         break;
00568                                 default:
00569                     phaserEndPoint = [[phaser target] predictedPosition];
00570                                         break;
00571             }
00572             
00573             NSPoint phaserStartPoint =[player predictedPosition];
00574             // phaser shooting exactly at me?
00575             if (phaserStartPoint.x != phaserEndPoint.x || phaserStartPoint.y != phaserEndPoint.y) {
00576                 if ([phaser status] == PHASER_MISS || (([phaser fuse] % 2) == 0) || [player team] != [me team]) {
00577                     // get the team color so that my phaser will not always be white
00578                     [[self colorForTeam:[player team]] set];
00579                 }
00580                 else {
00581                     [[NSColor whiteColor] set];
00582                 }
00583 
00584                 // project the phaser
00585                 phaserStartPoint = playerPositionInView; // we calculated this before...
00586                 
00587                 phaserEndPoint = [self viewPointFromGamePoint: phaserEndPoint 
00588                                                      viewRect:viewBounds
00589                                         gamePosInCentreOfView:centreOfGameBounds
00590                                                     withScale:scale];
00591                 
00592                 //NSLog(@"PainterFactory.playerPhaser firing at x=%f, y=%f", phaserEndPoint.x, phaserEndPoint.y);
00593                 
00594                 [line removeAllPoints];
00595                 [line moveToPoint:phaserStartPoint];
00596                 [line lineToPoint:phaserEndPoint];
00597                 [line stroke];
00598                 
00599                 // increase the faser duration
00600                 [phaser increaseFuse];
00601                 if([phaser fuse] > [phaser maxfuse]) {
00602                     [phaser setStatus: PHASER_FREE];
00603                 }
00604             }
00605         }
00606         
00607         // update
00608         [phaser setPreviousStatus:[phaser status]];
00609         
00610         // ---
00611         // the actual drawing code of the tractors/pressors
00612         // ---  
00613         
00614         // draw tractors/pressors         
00615         // needed?
00616         if(([player flags] & (PLAYER_TRACT | PLAYER_PRESS)) == 0 || [player status] != PLAYER_ALIVE) {
00617             continue;
00618         }
00619         
00620         // hmm no target?
00621         Player *tractee = [player tractorTarget];
00622         if(tractee == nil) {
00623             continue;
00624         }
00625         
00626         // dead target ?
00627         if ([tractee status] != PLAYER_ALIVE) {            
00628             // $$ we can tractor cloaked targets....
00629             //|| ((tractee.flags & PLAYER_CLOAK) != 0 && tractee.cloakphase == (PLAYER_CLOAK_PHASES - 1)) {
00630             continue;
00631             }
00632         
00633         NSPoint tractorStartPoint = playerPositionInView;    // we calculated this before    
00634         NSPoint tractorEndPoint = [self viewPointFromGamePoint: [tractee predictedPosition] 
00635                                                       viewRect:viewBounds
00636                                          gamePosInCentreOfView:centreOfGameBounds
00637                                                      withScale:scale];
00638         if (tractorStartPoint.x == tractorEndPoint.x && tractorStartPoint.y == tractorEndPoint.y) {
00639             continue;
00640         }
00641         
00642         //NSLog(@"PainterFactory.drawPlayers tractor from (%f, %f) to (%f, %f)",
00643         //      tractorStartPoint.x, tractorStartPoint.y,
00644         //      tractorEndPoint.x, tractorEndPoint.y);
00645         
00646         double theta = atan2((double)(tractorEndPoint.x - tractorStartPoint.x), 
00647                              (double)(tractorStartPoint.y - tractorEndPoint.y)) + pi / 2.0;
00648         //double dir = theta / pi * 128; // no need we can work in rad
00649                 
00650         //NSLog(@"PainterFactory.drawPlayers tractor from (%f / %f) to (%f)",
00651         //      ((double)(tractorEndPoint.x - tractorStartPoint.x)), 
00652         //      ((double)(tractorStartPoint.y - tractorEndPoint.y)) + pi / 2.0);
00653 
00654         // $$ fixed the colors here...
00655         if ([player flags] & PLAYER_PRESS) {
00656             [[NSColor purpleColor] set];
00657         } else {
00658             [[NSColor greenColor] set];
00659         }
00660         
00661         NSSize tracteeSize = [self viewSizeFromGameSize: [[tractee ship] size] withScale: scale];
00662         int width  = tracteeSize.width;
00663         int height = tracteeSize.height;
00664         double maxDim = ( width > height ? width : height) / 2.0;
00665         int yOffset = (int)(cos(theta) * maxDim);
00666         int xOffset = (int)(sin(theta) * maxDim);
00667         
00668         //NSLog(@"PainterFactory.drawPlayers tractor tetha %f xOff %d, yOff %d", theta, xOffset, yOffset);
00669         
00670         // draw it
00671         NSPoint p1 = NSMakePoint(tractorEndPoint.x + xOffset, tractorEndPoint.y + yOffset);
00672         NSPoint p2 = NSMakePoint(tractorEndPoint.x - xOffset, tractorEndPoint.y - yOffset);
00673         [dashedLine removeAllPoints];        
00674         [dashedLine moveToPoint:p1];
00675         [dashedLine lineToPoint:tractorStartPoint];
00676         [dashedLine lineToPoint:p2];
00677         [dashedLine stroke];
00678     }    
00679 }
00680 
00681 - (void)drawTorpsInRect:(NSRect)drawingBounds forGameRect:(NSRect)gameBounds ofViewBounds:(NSRect)viewBounds withScale:(int)scale {
00682     
00683     NSRect torpGameBounds;
00684     NSRect torpViewBounds;
00685     Player *player;
00686     NSPoint centreOfGameBounds = [self centreOfRect:gameBounds];
00687     
00688     // check all torps of all players
00689     for (int i = 0; i < UNIVERSE_MAX_PLAYERS; i++) {
00690         player = [universe playerWithId:i];
00691         
00692         NSArray *torps = [player torps];
00693         int freeTorps = UNIVERSE_MAX_TORPS;
00694         for (int t = 0; t < [torps count]; t++) {
00695             // check this torp
00696             Torp *torp = [torps objectAtIndex:t];            
00697             
00698             // check if we need to process this torp
00699             if ([torp status] == TORP_FREE) {
00700                 [torp setPreviousStatus:[torp status]];
00701                 continue;
00702             }            
00703             // it is not free
00704             freeTorps--;
00705         
00706             // ---
00707             // check for fuse and status changes
00708             // ---
00709             //NSLog(@"PainterFactory.drawTorpsInRect status %d, previous %d", [torp status], [torp previousStatus]);
00710 
00711             // check fuse overrun (maxfuse (n) sets the number of frames 0..n-1)
00712             if ([torp fuse] >= [torp maxfuse]) {
00713                 // we have drawn all frames for this phase do we need to loop?
00714                 if (([torp status] == TORP_EXPLODE) &&
00715                     ([torp previousStatus] == TORP_EXPLODE)) {
00716                     // we have completed the process of exploding
00717                     [torp setStatus:TORP_FREE];
00718                     // next state will be moving
00719                     [torp setFuse:0];
00720                     [torp setMaxFuse:[self maxFuseForMovingTorp]];
00721                     // no need to draw it.
00722                     continue; 
00723                 }
00724                 // if we are not exploding we are moving, thus reset the counter
00725                 // we will loop the images for moving torps
00726                 [torp setFuse:0];                
00727             }
00728             
00729             // check for launch
00730             if (([torp status] == TORP_MOVE) && 
00731                 ([torp previousStatus] != TORP_MOVE)) { 
00732                 // it should already be set to moving but can't hurt to do it again.
00733                 [torp setFuse:0];
00734                 [torp setMaxFuse:[self maxFuseForMovingTorp]];
00735                 // tell the soundplayer what happend
00736                 if ([player isMe]) {
00737                     [notificationCenter postNotificationName:@"PL_TORP_FIRED_BY_ME" userInfo:torp];
00738                 } else {
00739                     [notificationCenter postNotificationName:@"PL_TORP_FIRED_BY_OTHER" userInfo:torp];
00740                 }
00741             } 
00742              
00743             // check for detonate
00744             if (([torp status] == TORP_EXPLODE) &&
00745                 ([torp previousStatus] != TORP_EXPLODE)) {
00746                 // set the fuse
00747                 [torp setFuse:0];
00748                 [torp setMaxFuse:[self maxFuseForExplodingTorp]];
00749                 // it just went boom
00750                 [notificationCenter postNotificationName:@"PL_TORP_EXPLODED" userInfo:torp];
00751             }
00752             
00753             // we have tested all status changes, so preserve the previous for
00754             // the next run
00755             [torp setPreviousStatus:[torp status]];            
00756             
00757             // ---
00758             // the actual drawing code
00759             // ---
00760             
00761             // get the rect around the torp in game coordinates
00762             torpGameBounds.origin = [torp predictedPosition];
00763             if ([torp status] == TORP_EXPLODE) {
00764                 torpGameBounds.size = [torp explosionSize];
00765             } else {
00766                 torpGameBounds.size = [torp size];
00767             }
00768             // offset the origin to the upper left
00769             torpGameBounds.origin.x -= torpGameBounds.size.width / 2;
00770             torpGameBounds.origin.y -= torpGameBounds.size.height / 2;
00771             
00772             // convert to the view 
00773             torpViewBounds.size = [self viewSizeFromGameSize: torpGameBounds.size withScale: scale];
00774             torpViewBounds.origin = [self viewPointFromGamePoint: torpGameBounds.origin 
00775                                                         viewRect:viewBounds
00776                                            gamePosInCentreOfView:centreOfGameBounds
00777                                                        withScale:scale];
00778             
00779             // is the torp in the drawing rectangle?
00780             if (!NSIntersectsRect(torpViewBounds, drawingBounds)) {
00781                 continue;
00782             } 
00783             
00784             // draw it
00785             [self drawTorp: torp inRect:torpViewBounds];
00786             
00787             // and move to the next image to paint
00788             [torp increaseFuse]; 
00789         }
00790         [player setTorpCount:freeTorps];
00791     }
00792 }
00793 
00794 - (void)drawPlasmasInRect:(NSRect)drawingBounds forGameRect:(NSRect)gameBounds ofViewBounds:(NSRect)viewBounds  withScale:(int)scale  {
00795     
00796     NSRect plasmaGameBounds;
00797     NSRect plasmaViewBounds;
00798     Player *player;
00799     NSPoint centreOfGameBounds = [self centreOfRect:gameBounds];
00800     
00801     // check all plasmas of all players
00802     for (int i = 0; i < UNIVERSE_MAX_PLAYERS; i++) {
00803         player = [universe playerWithId:i];        
00804         Plasma *plasma = [universe plasmaWithId:[player plasmaId]];            
00805         
00806         if ([plasma status] == PLASMA_FREE) {
00807             [plasma setPreviousStatus:[plasma status]]; 
00808             continue;
00809         }
00810         
00811         // ---
00812         // check for fuse and status changes
00813         // ---
00814         
00815         // check fuse overrun (maxfuse (n) sets the number of frames 0..n-1)
00816         if ([plasma fuse] >= [plasma maxfuse]) {
00817             // we have drawn all frames for this phase do we need to loop?
00818             if (([plasma status] == PLASMA_EXPLODE) &&
00819                 ([plasma previousStatus] == PLASMA_EXPLODE)) {
00820                 // we have completed the process of exploding
00821                 [plasma setStatus:PLASMA_FREE];
00822                 // next state will be moving
00823                 [plasma setFuse:0];
00824                 [plasma setMaxFuse:[self maxFuseForMovingPlasma]];
00825                 // no need to draw it.
00826                 continue; 
00827             }
00828             // if we are not exploding we are moving, thus reset the counter
00829             // we will loop the images for moving plasmas
00830             [plasma setFuse:0];                
00831         }
00832         
00833         // check for launch
00834         if (([plasma status] == PLASMA_MOVE) && 
00835             ([plasma previousStatus] != PLASMA_MOVE)) { 
00836             // it should already be set to moving but can't hurt to do it again.
00837             [plasma setFuse:0];
00838             [plasma setMaxFuse:[self maxFuseForMovingPlasma]];
00839             // tell the soundplayer what happend
00840             if ([player isMe]) {
00841                 [notificationCenter postNotificationName:@"PL_PLASMA_FIRED_BY_ME" userInfo:plasma];
00842             } else {
00843                 [notificationCenter postNotificationName:@"PL_PLASMA_FIRED_BY_OTHER" userInfo:plasma];
00844             }
00845         } 
00846         
00847         // check for detonate
00848         if (([plasma status] == PLASMA_EXPLODE) &&
00849             ([plasma previousStatus] != PLASMA_EXPLODE)) {
00850             // set the fuse
00851             [plasma setFuse:0];
00852             [plasma setMaxFuse:[self maxFuseForExplodingPlasma]];
00853             // it just went boom
00854             [notificationCenter postNotificationName:@"PL_PLASMA_EXPLODED" userInfo:plasma];
00855         }
00856         
00857         // we have tested all status changes, so preserve the previous for
00858         // the next run
00859         [plasma setPreviousStatus:[plasma status]];            
00860         
00861         // ---
00862         // the actual drawing code
00863         // ---        
00864         
00865         // get the rect around the plasma in game coordinates
00866         plasmaGameBounds.origin = [plasma predictedPosition];
00867         if ([plasma status] == PLASMA_EXPLODE) {
00868             plasmaGameBounds.size = [plasma explosionSize];
00869         } else {
00870             plasmaGameBounds.size = [plasma size];
00871         }
00872         // offset the origin to the upper left
00873         plasmaGameBounds.origin.x -= plasmaGameBounds.size.width / 2;
00874         plasmaGameBounds.origin.y -= plasmaGameBounds.size.height / 2;
00875         
00876         // convert to the view 
00877         plasmaViewBounds.size = [self viewSizeFromGameSize: plasmaGameBounds.size withScale: scale];
00878         plasmaViewBounds.origin = [self viewPointFromGamePoint: plasmaGameBounds.origin 
00879                                                       viewRect:viewBounds
00880                                          gamePosInCentreOfView:centreOfGameBounds
00881                                                      withScale:scale];
00882         
00883         // is the player in the drawing rectangle?
00884         if (!NSIntersectsRect(plasmaViewBounds, drawingBounds)) {
00885             continue;
00886         } 
00887         
00888         // draw it
00889         [self drawPlasma: plasma inRect:plasmaViewBounds];
00890         
00891         // and move to the next image to paint
00892         [plasma increaseFuse];              
00893     }
00894 }
00895 
00896 - (void)drawLockInRect:(NSRect)drawingBounds forGameRect:(NSRect)gameBounds ofViewBounds:(NSRect)viewBounds withScale:(int)scale {
00897     
00898     Player *me = [universe playerThatIsMe];
00899     NSPoint triangleViewPoint;
00900     NSPoint triangleGamePoint;
00901 
00902     // default colour
00903     [[NSColor whiteColor] set];
00904         
00905     // are we locked?
00906     if ((([me flags] & PLAYER_PLOCK) != 0) || 
00907         (([me flags] & PLAYER_PLLOCK) != 0)) {        
00908         // yes
00909         if (([me flags] & PLAYER_PLOCK) != 0) {
00910             // locked onto a ship
00911             Player *player = [me playerLock];
00912             // player cloaked?
00913             if (([player flags] & PLAYER_CLOAK) == 0) {
00914                 // or outside screen?
00915                 if (NSPointInRect([player predictedPosition], gameBounds)) {
00916                     // find point
00917                     triangleGamePoint = [player predictedPosition];
00918                     // on top of ship
00919                     triangleGamePoint.y -= [[player ship] size].height / 2;
00920                     triangleViewPoint = [self viewPointFromGamePoint:triangleGamePoint 
00921                                                             viewRect:viewBounds
00922                                                gamePosInCentreOfView:[self centreOfRect:gameBounds]
00923                                                            withScale:scale];
00924                 } else {
00925                     return; // outside view
00926                 }
00927             } else {
00928                 return; // cloacked
00929             }
00930         } else { 
00931             // locked onto a planet
00932             Planet *planet = [me planetLock];
00933             // or outside screen?
00934             if (NSPointInRect([planet predictedPosition], gameBounds)) {
00935                 // find point
00936                 triangleGamePoint = [planet predictedPosition];
00937                 // on top of planet
00938                 triangleGamePoint.y -= [planet size].height / 2;
00939                 triangleViewPoint = [self viewPointFromGamePoint:triangleGamePoint 
00940                                                         viewRect:viewBounds
00941                                            gamePosInCentreOfView:[self centreOfRect:gameBounds]
00942                                                        withScale:scale];
00943             } else {
00944                 return; // outside view
00945             }
00946         }
00947         
00948         // set up the drawing erea
00949         NSRect rect;
00950         rect.size.width = (PF_TRIANGLE_WIDTH) / scale;
00951         rect.size.height = (PF_TRIANGLE_HEIGHT) / scale;
00952         // triangleViewPoint points at the notch
00953         rect.origin.x = triangleViewPoint.x - rect.size.width / 2;
00954         rect.origin.y = triangleViewPoint.y - rect.size.height;
00955         
00956         // is the player in the drawing rectangle?
00957         if (!NSIntersectsRect(rect, drawingBounds)) {
00958             return;
00959         }
00960         
00961         [shapes drawTriangleNotchDownInRect:rect];
00962     }
00963 }
00964 
00965 - (void) drawRect:(NSRect)drawingBounds ofViewBounds:(NSRect)viewBounds whichRepresentsGameBounds:(NSRect)gameBounds 
00966         withScale:(int)scale {
00967     
00968     // get some helpers
00969     Player *me = [universe playerThatIsMe];   
00970     
00971     // -------------------------------------------------------------------------
00972     // 0. gather some metrics
00973     // -------------------------------------------------------------------------
00974     
00975     static NSTimeInterval start, stop;
00976     start = [NSDate timeIntervalSinceReferenceDate];  
00977     if ((start-stop) > 0.1) {
00978         NSLog(@"PainterFactory.drawView: slept %f sec", (start-stop));
00979     }
00980     
00981     // -------------------------------------------------------------------------
00982     // 1. draw alert border (yellow/red/green)
00983     // -------------------------------------------------------------------------
00984     if (!simple) {
00985         [self drawAlertBorder:viewBounds forMe:me];
00986     }
00987     
00988     // make sure our border is respected
00989     // by schrinking the view
00990     viewBounds = NSInsetRect(viewBounds, PF_ALERT_BORDER_WIDTH, PF_ALERT_BORDER_WIDTH);
00991     
00992     // and cliping upon it
00993     [[NSBezierPath bezierPathWithRect:viewBounds] addClip];
00994     
00995     // -------------------------------------------------------------------------
00996     // 2. draw background stars
00997     //      these are small stars floating in the oposite direction
00998     //      the original calculations are based on the game view:
00999     //      - every update, we will have shifted aprox the same amount as the
01000     //        calculation below, but planets will move
01001     //      - by applying it to the local view the stars will move with respect
01002     //        to me thus should stay roughly on top of the planets.
01003     //      - because we draw in the view, we must respect the alert border too.
01004     // -------------------------------------------------------------------------
01005     
01006     // $$ i bet this goes wrong, i may need to know the dimensions of the whole
01007     // $$ view to find out where to start painting this patch
01008     if (!simple) {
01009             [self drawBackgroundInRect:drawingBounds ofViewBounds:viewBounds forMe:me];
01010     }
01011     
01012     // -------------------------------------------------------------------------
01013     // 3. draw galaxy edges 
01014     //      is a Rect measuring UNIVERSE_PIXEL_SIZE in the gameView
01015     // -------------------------------------------------------------------------
01016     [self drawGalaxyEdgesInRect:drawingBounds forGameRect:gameBounds ofViewBounds:viewBounds withScale:scale];
01017         
01018     // -------------------------------------------------------------------------
01019     // 4. draw the planets which are in the view
01020     // -------------------------------------------------------------------------
01021     [self drawPlanetsInRect:drawingBounds forGameRect:gameBounds ofViewBounds:viewBounds withScale:scale];
01022     
01023     // -------------------------------------------------------------------------
01024     // 5. draw the players which are in the view
01025     //      this includes phasers and tractors/pressors
01026     // -------------------------------------------------------------------------
01027     [self drawPlayersInRect:drawingBounds forGameRect:gameBounds ofViewBounds:viewBounds withScale:scale];
01028     
01029     // -------------------------------------------------------------------------
01030     // 6. draw torps
01031     // -------------------------------------------------------------------------
01032     if (!simple) {
01033         [self drawTorpsInRect:drawingBounds forGameRect:gameBounds ofViewBounds:viewBounds withScale:scale];
01034     }
01035     
01036     // -------------------------------------------------------------------------
01037     // 7. draw plasmas
01038     // -------------------------------------------------------------------------
01039     if (!simple) {
01040         [self drawPlasmasInRect:drawingBounds forGameRect:gameBounds ofViewBounds:viewBounds withScale:scale];    
01041     }
01042     
01043     // -------------------------------------------------------------------------
01044     // 8. draw locking triangle
01045     // -------------------------------------------------------------------------
01046     [self drawLockInRect:drawingBounds forGameRect:gameBounds ofViewBounds:viewBounds withScale:scale];
01047     
01048     // -------------------------------------------------------------------------
01049     // 0. gather some metrics
01050     // -------------------------------------------------------------------------
01051     stop = [NSDate timeIntervalSinceReferenceDate];  
01052     if ((stop - start) > 0.1) {
01053         NSLog(@"PainterFactory.drawView: %f sec", (stop-start));
01054     }
01055     
01056 }
01057 
01058 - (void) rotateAndDrawPlayer:(Player*) player inRect:(NSRect) Rect {
01059     
01060     float course = [player course];
01061     //float course = 0;
01062     
01063     // first save the GC
01064     [[NSGraphicsContext currentContext] saveGraphicsState];
01065     
01066     // set up the rotate
01067     NSAffineTransform *transform = [NSAffineTransform transform];
01068     
01069     // assume ship drawn at 0,0 and move to ship position
01070     NSPoint center = [self centreOfRect:Rect];
01071     // transforms are read in reverse so this reads: first rotate then translate!
01072     [transform translateXBy:center.x yBy:center.y];
01073     [transform rotateByDegrees:course];  
01074     // concat the transform
01075     [transform concat];
01076     
01077     // draw the ship around 0,0
01078     Rect.origin = NSZeroPoint;
01079     [self drawPlayer:player inRect:[shapes createRectAroundOrigin:Rect]];
01080     
01081     // and restore the GC
01082     [transform invert];
01083     [transform concat];
01084     [[NSGraphicsContext currentContext] restoreGraphicsState];
01085 }
01086 
01087 // --------
01088 // should be overwritten by subclasses
01089 // --------
01090 
01091 - (void)   drawPlayer:(Player*) player inRect:(NSRect) Rect {
01092     //NSLog(@"PainterFactory.drawPlayer course %f %@",course, 
01093     //      [NSString stringWithFormat:@"x=%f, y=%f, w=%f, h=%f", 
01094     //          Rect.origin.x, Rect.origin.y, Rect.size.width, Rect.size.height]);
01095     
01096     NSColor *col = [self colorForTeam:[player team]];
01097     if ([player cloakPhase] > 0) {
01098         // find out aplha value PF_MIN_ALPHA_VALUE (0.1) means fully cloaked
01099         // 1.0 means fully uncloaked
01100         float alpha = 1.0;
01101         alpha -= (((1.0 - PF_MIN_ALPHA_VALUE) * [player cloakPhase]) / PLAYER_CLOAK_PHASES);
01102         col = [col colorWithAlphaComponent:alpha];
01103     }
01104     
01105     [col set];
01106         
01107     // draw the ship in a sqrt(2)/2 size rect (inner circle)
01108     // sides should be 0.707 * rect.width thus reduced by 0,292893218813 / 2
01109     [shapes drawSpaceShipInRect:NSInsetRect(Rect, Rect.size.width*0.1515, Rect.size.height*0.1515)];
01110     
01111     /* draw as triangle 
01112     [self drawTriangleNotchUpInRect:NSInsetRect(Rect, Rect.size.width*0.1515, Rect.size.height*0.1515)];
01113     // $$ abuse line (very bad)
01114     [line fill];
01115     */
01116 }
01117 
01118 - (void)   drawShieldWithStrenght: (float)shieldPercentage inRect:(NSRect) Rect {
01119     
01120     // recalculate
01121     NSPoint centre = [self centreOfRect:Rect];
01122     // shield extends our ship by 1 point
01123     float radius = (Rect.size.width / 2) + 1; // assume Rect is square!!
01124     
01125     // get the colour
01126     NSColor *shieldColor = [NSColor greenColor];
01127     if (shieldPercentage < 50.0) {
01128         shieldColor = [NSColor yellowColor];
01129     }
01130     if (shieldPercentage < 25.0) {
01131         shieldColor = [NSColor redColor];
01132     }
01133     
01134     // get angle
01135     float angle = (360.0 * shieldPercentage / 100);
01136     
01137     //NSLog(@"PainterFactory.drawShield strenght %f, angle %f", shieldPercentage, angle);
01138     
01139     // draw
01140     [shieldColor set];
01141     
01142     // first the remaining strenght
01143     [line removeAllPoints];  
01144     [line appendBezierPathWithArcWithCenter:centre radius:radius startAngle:0.0 endAngle:angle];
01145     [line stroke]; 
01146     // then the lost shield
01147     if (angle < 360.0) {
01148         [dashedLine removeAllPoints];
01149         [dashedLine appendBezierPathWithArcWithCenter:centre radius:radius startAngle:angle endAngle:360.0];
01150         [dashedLine stroke];
01151     }
01152 
01153 }
01154 
01155 - (void)   drawPlanet:(Planet*) planet inRect:(NSRect) Rect {
01156     //NSLog(@"PainterFactory.drawPlanet %@", 
01157     //      [NSString stringWithFormat:@"x=%f, y=%f, w=%f, h=%f", 
01158     //          Rect.origin.x, Rect.origin.y, Rect.size.width, Rect.size.height]);
01159     [[self colorForTeam:[planet owner]] set];
01160     
01161     [shapes drawDoubleCircleInRect:Rect];
01162 }
01163 
01164 - (void)   drawTorp:(Torp*) torp       inRect:(NSRect) Rect {
01165 
01166     [[self colorForTeam:[[torp owner] team]] set];
01167     
01168     // do something with the fuse
01169     float delta = 0.0;
01170     // zoom up the torp
01171     if ([torp status] == TORP_EXPLODE) {
01172         delta += [torp fuse] * Rect.size.width; // up to maxfuse*current width        
01173     } else {
01174         delta += [torp fuse] * Rect.size.width / 2;
01175     }
01176     
01177     Rect = NSInsetRect(Rect, -delta, -delta); // use minus to make larger
01178     
01179     //NSLog(@"PainterFactory.drawTorp %@",  
01180     //     [NSString stringWithFormat:@"x=%f, y=%f, w=%f, h=%f", 
01181     //       Rect.origin.x, Rect.origin.y, Rect.size.width, Rect.size.height]);
01182     [shapes drawCircleInRect:Rect];
01183 }
01184 
01185 - (void)   drawPlasma:(Plasma*) plasma inRect:(NSRect) Rect {
01186     //NSLog(@"PainterFactory.drawPlasma %@", 
01187     //      [NSString stringWithFormat:@"x=%f, y=%f, w=%f, h=%f", 
01188     //          Rect.origin.x, Rect.origin.y, Rect.size.width, Rect.size.height]);
01189     [[self colorForTeam:[plasma team]] set];
01190     
01191     [shapes drawCircleInRect:Rect];
01192 }
01193 
01194 - (void)   drawBackgroundImageInRect:(NSRect) Rect {
01195     //NSLog(@"PainterFactory.drawBackgroundImageInRect %@",  
01196     //[NSString stringWithFormat:@"x=%f, y=%f, w=%f, h=%f", 
01197     //    Rect.origin.x, Rect.origin.y, Rect.size.width, Rect.size.height]);
01198 }
01199 
01200 - (void) drawLabelForPlanet:(Planet*)planet belowRect:(NSRect)planetViewBounds {
01201     
01202     // draw the name, 12pnt below the planet
01203     NSString *label = [NSString stringWithString:[planet nameWithArmiesIndicator]];
01204     
01205     // extended label?
01206     if ([planet showInfo] || debugLabels) {
01207         label = [NSString stringWithFormat:@"%@ %d [%c%c%c]",
01208             [planet name],
01209             [planet armies],
01210             ([planet flags] & PLANET_REPAIR ? 'R' : '-'),
01211             ([planet flags] & PLANET_FUEL ?   'F' : '-'),
01212             ([planet flags] & PLANET_AGRI ?   'A' : '-')
01213             ];
01214     }   
01215     
01216     [[NSColor whiteColor] set];
01217     NSPoint namePosition = planetViewBounds.origin;
01218     namePosition.y += planetViewBounds.size.height ;//+  [label sizeWithAttributes:normalStateAttribute].height;
01219         
01220     int labelWidth =  [label sizeWithAttributes:normalStateAttribute].width;
01221     namePosition.x += (planetViewBounds.size.width - labelWidth) / 2;
01222         
01223     [label drawAtPoint: namePosition withAttributes:normalStateAttribute];  
01224 }
01225 
01226 - (void) drawLabelForPlayer:(Player*)player belowRect:(NSRect)playerViewBounds {
01227     
01228     // draw the name, 12pnt below the player  
01229     NSString *label = [NSString stringWithFormat:@"%@", [player mapCharsWithKillIndicator]];
01230 
01231     // extended label?
01232     if ([player showInfo] || debugLabels) {
01233         label = // in debug we show status[NSString stringWithFormat:@"%@ %d(%d) %d %d [%c%c%c%c%c%c] %d %@",
01234             [player longNameWithKillIndicator],
01235             [player speed],
01236             [player requestedSpeed],
01237             [player kills],
01238             [player armies],
01239             ([player flags] & PLAYER_REPAIR ? 'R' : '-'),
01240             ([player flags] & PLAYER_BOMB ?   'B' : '-'),
01241             ([player flags] & PLAYER_ORBIT ?  'O' : '-'),
01242             ([player flags] & PLAYER_CLOAK ?  'C' : '-'),
01243             ([player flags] & PLAYER_BEAMUP ?  'U' : '-'),
01244             ([player flags] & PLAYER_BEAMDOWN ?  'D' : '-'),
01245             [player cloakPhase],
01246             (debugLabels ? [[player statusString] substringFromIndex:7] : @"") 
01247             ];
01248     }   
01249     
01250     [[NSColor whiteColor] set];
01251     NSPoint namePosition = playerViewBounds.origin;
01252     int labelHeight = [label sizeWithAttributes:normalStateAttribute].height;
01253     namePosition.y += playerViewBounds.size.height;// +  labelHeight;
01254         
01255     int labelWidth =  [label sizeWithAttributes:normalStateAttribute].width;
01256     namePosition.x += (playerViewBounds.size.width - labelWidth) / 2;
01257         
01258     [label drawAtPoint: namePosition withAttributes:normalStateAttribute];   
01259     
01260     if (debugLabels) {
01261         // prepare another line
01262         NSArray *torps = [player torps];
01263         label = // we know that there are 8 and this is debug[NSString stringWithFormat:@"T[%c(%c)%c%c%c%c%c%c%c] F[%d%d%d%d%d%d%d%d]",
01264             [[torps objectAtIndex:0] statusChar],  
01265             [[torps objectAtIndex:0] previousStatusChar],
01266             [[torps objectAtIndex:1] statusChar],
01267             [[torps objectAtIndex:2] statusChar],
01268             [[torps objectAtIndex:3] statusChar],
01269             [[torps objectAtIndex:4] statusChar],
01270             [[torps objectAtIndex:5] statusChar],
01271             [[torps objectAtIndex:6] statusChar],
01272             [[torps objectAtIndex:7] statusChar],
01273             [[torps objectAtIndex:0] fuse], 
01274             [[torps objectAtIndex:1] fuse],
01275             [[torps objectAtIndex:2] fuse],
01276             [[torps objectAtIndex:3] fuse],
01277             [[torps objectAtIndex:4] fuse],
01278             [[torps objectAtIndex:5] fuse],
01279             [[torps objectAtIndex:6] fuse],
01280             [[torps objectAtIndex:7] fuse]];
01281             
01282         namePosition.y += labelHeight;
01283         [label drawAtPoint: namePosition withAttributes:normalStateAttribute]; 
01284         
01285         // prepare another line
01286         Plasma *plasma = [universe plasmaWithId:[player plasmaId]];
01287         Phaser *phaser = [universe phaserWithId:[player phaserId]];
01288         label = [NSString stringWithFormat:@"PH[%c][%d] PL[%c][%d]",
01289             [phaser statusChar],
01290             [phaser fuse],
01291             [plasma statusChar],
01292             [plasma fuse]];
01293         
01294         namePosition.y += labelHeight;
01295         [label drawAtPoint: namePosition withAttributes:normalStateAttribute];  
01296     }
01297 }
01298 
01299 - (int)    maxFuseForMovingTorp {
01300     return 2; // two frames     
01301 }
01302 
01303 - (int)    maxFuseForExplodingTorp {
01304     return 10; // ten frames
01305 }
01306 
01307 
01308 - (int)    maxFuseForMovingPlasma {
01309     return 3; // two frames     
01310 }
01311 
01312 - (int)    maxFuseForExplodingPlasma {
01313     return 12; // ten frames
01314 }
01315 
01316 - (int)    maxFuseForMovingPlayer {
01317     return 1;
01318 } 
01319 
01320 - (int)    maxFuseForExplodingPlayer {
01321     return 10;
01322 }
01323 
01324 - (int)    maxFuseForPlanet {
01325     return 1;
01326 }
01327 
01328 @end

Generated on Sat Aug 26 21:14:16 2006 for MacTrek by  doxygen 1.4.7