ftp.nice.ch/Attic/openStep/games/Empire.0.6.m.NIS.bs.tgz#/Empire.0.6/src/EditorController.m

This is EditorController.m in view mode; [Download] [Up]

//
// $Id: EditorController.m,v 1.11 1997/10/31 04:51:41 nygard Exp $
//

//
//  This file is a part of Empire, a game of exploration and conquest.
//  Copyright (C) 1996  Steve Nygard
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//  You may contact the author by:
//     e-mail:  nygard@telusplanet.net
//

#import "Empire.h"

RCSID ("$Id: EditorController.m,v 1.11 1997/10/31 04:51:41 nygard Exp $");

#import "EditorController.h"

#import "Brain.h"
#import "Map.h"
#import "MapView.h"
#import "SNRandom.h"
#import "WorldMapController.h"

//======================================================================
// The Editor Controller provides simple "painting" of terrain in
// order to create maps.  There are a couple of different ways of
// "growing" terrain to help.
//
// Additionally, there is some prototype code for trying to automate
// map generation.  I was trying to parameterize it based on the size
// of the map, possibly with the option of being able to select between
// different sets of parameters (i.e. create a world with may small
// islands, or one with a few larger continents, etc.)
//
// I've also tried another method, basically draw a random line through
// the map, raise the elevation on one side, and repeat many times.
// Then create the land based on the elevation.  Unfortunately, while
// this seems to produce nice coastlines, especially with larger maps,
// I end up with one large land mass...  I've got a separate application
// that I was experimenting with this method.
//
// Automated city placement can happen once terrain generation is
// working.
//======================================================================

@implementation EditorController

- (void) awakeFromNib
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *imagePath;
    NSImage *image;
    BOOL okay;
    id tmp;

    [mapView setCursorEnabled:NO];

    imagePath = [[NSBundle mainBundle] pathForImageResource:@"mwi_map_editor.tiff"];
    NSAssert (imagePath != nil, @"Couldn't find mwi_map_editor.tiff");

    image = [[[NSImage alloc] initWithContentsOfFile:imagePath] autorelease];
    NSAssert (image != nil, @"Couldn't load mwi_map_editor.tiff");

    [mapEditorWindow setMiniwindowImage:image];
    okay = [mapEditorWindow setFrameAutosaveName:@"Map Editor"];
    if (okay == NO)
        NSLog (@"Could not set frame autosave name of editor window.");

    okay = [newMapPanel setFrameAutosaveName:@"New Map Panel"];
    if (okay == NO)
        NSLog (@"Could not set frame autosave name of new map panel.");

    tmp = [defaults stringForKey:DK_MapWidth];
    [widthTextfield setStringValue:tmp];

    tmp = [defaults stringForKey:DK_MapHeight];
    [heightTextfield setStringValue:tmp];
}

//----------------------------------------------------------------------

- init
{
    NSString *nibFile;
    BOOL loaded;

    [super init];

    nibFile = @"MapEditor.nib";
    loaded = [NSBundle loadNibNamed:nibFile owner:self];
    if (loaded == NO)
    {
        NSLog (@"Could not load %@.", nibFile);
        [super dealloc];
        return nil;
    }

    map = nil;

    brushType = 0;
    tokenType = EMCreateMapToken (t_water, p_neutral, i_none, YES);

    mapName = nil;

    terrainCounts[0] = 0;
    terrainCounts[1] = 0;
    terrainCounts[2] = 0;
    terrainCounts[3] = 0;

    lastDirectory = nil;
    rng = [[SNRandom instance] retain];

    return self;
}

//----------------------------------------------------------------------

- (void) dealloc
{
    SNRelease (mapEditorWindow);
    SNRelease (map);
    SNRelease (mapName);
    SNRelease (worldMapController);
    SNRelease (rng);

    [super dealloc];
}

//----------------------------------------------------------------------

- (Map *) map
{
    return map;
}

//----------------------------------------------------------------------

- (void) setMap:(Map *)newMap
{
    SNRelease (map);

    map = newMap;
    [map retain];

    [mapView setMap:newMap];
    if (worldMapController != nil)
    {
        [worldMapController setMap:map];
    }
}

//----------------------------------------------------------------------

- (void) takeBrushTypeFrom:sender
{
    brushType = [sender state];
}

//----------------------------------------------------------------------

- (void) takeTokenTypeFrom:sender
{
    static Terrain tokens[] = {t_water, t_land, t_city};
  
    tokenType = EMCreateMapToken (tokens[[[sender selectedCell] tag]], p_neutral, i_none, YES); 
}

//----------------------------------------------------------------------

- (BOOL) validateMenuItem:(NSMenuItem *)menuCell
{
    SEL action = [menuCell action];
    BOOL valid = NO;

    if (action == @selector (showWorldMap:))
    {
        valid = YES;
    }
    else if (action == @selector (open:))
    {
        valid = YES;
    }
    else if (action == @selector (save:)
             || action == @selector (saveAs:)
             || action == @selector (saveTo:))
    {
        valid = YES;
    }

    return valid;
}

//----------------------------------------------------------------------

- (void) showWorldMap:sender
{
    if (worldMapController == nil)
    {
        worldMapController = [[WorldMapController alloc] init];
        [worldMapController setMap:map];
        [worldMapController setDelegate:self];
        [worldMapController setTitle:@"Map Editor World Map" autosaveFrame:YES];
    }

    [worldMapController showPanel];
}

//----------------------------------------------------------------------

- (void) newMapStopAction:sender
{
    //[NSApp stopModal];
    [newMapPanel orderOut:self]; 
}

//----------------------------------------------------------------------

- (void) okayAction:sender
{
    EMMapSize mapSize;
    Map *tmp;
    int count;
  
    mapSize.width = [widthTextfield intValue];
    mapSize.height = [heightTextfield intValue];

    if (mapSize.width < 1)
    {
        NSRunAlertPanel (@"New Map", @"The width of the map must be greater than zero.", @"OK", nil, nil);
        return;
    }

    if (mapSize.height < 1)
    {
        NSRunAlertPanel (@"New Map", @"The height of the map must be greater than zero.", @"OK", nil, nil);
        return;
    }

    [newMapPanel orderOut:self];

    count = mapSize.width * mapSize.height;

    if (count >= 1000000)
    {
        int alertValue;

        alertValue = NSRunAlertPanel (@"Warning", @"Large map size (%d) selected.", @"Cancel", @"Create Map", NULL, count);

        if (alertValue != NSAlertAlternateReturn)
            return;
    }

    tmp = [[[Map alloc] initMapWithSize:mapSize] autorelease];
    NSAssert (tmp != nil, @"New map is nil");

    [tmp clearMapTo:EMCreateMapToken (t_water, p_neutral, i_none, YES)];

    [self setMap:tmp];

    [mapEditorWindow setTitleWithRepresentedFilename:@"UNTITLED.map"];
    [mapEditorWindow makeKeyAndOrderFront:self];
}

//----------------------------------------------------------------------

- (void) takeLastDirectoryFromSavePanel:(NSSavePanel *)savePanel
{
    if (lastDirectory != nil)
    {
        SNRelease (lastDirectory);
    }

    lastDirectory = [[savePanel directory] retain];
}
  
//----------------------------------------------------------------------

- (void) newMap
{
    [newMapPanel makeKeyAndOrderFront:nil];
}

//----------------------------------------------------------------------

- (void) open:sender
{
    NSArray *types = [NSArray arrayWithObject:@"map"];
    NSOpenPanel *openPanel = [NSOpenPanel openPanel];
    NSString *filename;
    Map *newMap;

    [openPanel setDirectory:lastDirectory];
    [openPanel setAllowsMultipleSelection:NO];

    if ([openPanel runModalForTypes:types] == NSOKButton)
    {
        [self takeLastDirectoryFromSavePanel:openPanel];

        filename = [openPanel filename];
        newMap = [NSUnarchiver unarchiveObjectWithFile:filename];

        NSAssert1 (newMap != nil, @"Error loading map '%@'\n", filename);

        [self setMap:newMap];

        [mapEditorWindow setTitleWithRepresentedFilename:filename];
        [mapEditorWindow makeKeyAndOrderFront:self];
        [mapEditorWindow setDocumentEdited:NO];

        SNRelease (mapName);
    
        mapName = [filename retain];
    }
}

//----------------------------------------------------------------------

- (void) save:sender
{
    [self saveMode:sm_save];
}

//----------------------------------------------------------------------

- (void) saveAs:sender
{
    [self saveMode:sm_save_as];
}

//----------------------------------------------------------------------

- (void) saveTo:sender
{
    [self saveMode:sm_save_to];
}

//----------------------------------------------------------------------

- (BOOL) saveMode:(SaveMode)sm
{
    NSSavePanel *savePanel = [NSSavePanel savePanel];
    NSString *targetFile;

    BOOL rflag;

    [savePanel setDirectory:lastDirectory];
    [savePanel setRequiredFileType:@"map"];

    if (sm == sm_save && mapName == nil)
        sm = sm_save_as;

    if (sm == sm_save)
    {
        targetFile = mapName;
    }
    else //(sm != sm_save)
    {
        if ([savePanel runModal] != NSOKButton)
            return NO;

        [self takeLastDirectoryFromSavePanel:savePanel];
        targetFile = [savePanel filename];
    }

    rflag = [NSArchiver archiveRootObject:map toFile:targetFile];

    if (sm == sm_save_as)
    {
        [mapEditorWindow setTitleWithRepresentedFilename:targetFile];
    }

    [mapEditorWindow setDocumentEdited:NO];

    return rflag;
}

//----------------------------------------------------------------------

#define FLIP_Y  0x01
#define FLIP_X  0x02
#define FLIP_XY 0x04

- (void) growTerrain:(MapToken)token fromLocation:(EMMapLocation)source toLocation:(EMMapLocation)target
{
    int dx;
    int dy;
    int d;
    int increment_E;
    int increment_SE;
    int octant;
    int row = source.row;
    int col = source.column;
    EMMapLocation tmp;

    dx = target.column - source.column;
    dy = target.row - source.row;

    octant = 0;

    if (dy < 0)
    {
        octant |= FLIP_Y;
        dy = -dy;
        row = -row;
        target.row = -target.row;
    }

    if (dx < 0)
    {
        octant |= FLIP_X;
        dx = -dx;
        col = -col;
        target.column = -target.column;
    }

    if (dx < dy)
    {
        int tmp;
        octant |= FLIP_XY;
        tmp = dx;
        dx = dy;
        dy = tmp;

        tmp = row;
        row = col;
        col = tmp;

        tmp = target.row;
        target.row = target.column;
        target.column = tmp;
    }

    d = 2 * dy - dx;

    increment_E = 2 * dy;
    increment_SE = 2 * (dy - dx);
  
    if ([map tokenAtLocation:source] != token)
    {
        [map setToken:token atLocation:source];
    }
    else
    {
        while (col < target.column)
        {
            if (d <= 0)
            {
                d += increment_E;
                col++;
            }
            else
            {
                d += increment_SE;
                col++;
                row++;
            }

            if (octant & FLIP_XY)
            {
                tmp.row = col;
                tmp.column = row;
            }
            else
            {
                tmp.row = row;
                tmp.column = col;
            }

            if (octant & FLIP_X)
                tmp.column = -tmp.column;
            if (octant & FLIP_Y)
                tmp.row = -tmp.row;

            if ([map tokenAtLocation:tmp] != token)
            {
                [map setToken:token atLocation:tmp];
                break;
            }
        }
    }
}

//----------------------------------------------------------------------

- (void) branchTerrain:(MapToken)token fromLocation:(EMMapLocation)source toLocation:(EMMapLocation)target
{
    int dx;
    int dy;
    int d;
    int increment_E;
    int increment_SE;
    int octant;
    int row;
    int col;
    EMMapLocation tmp, foo;
    EMMapSize mapSize;
  
    //NSLog (@"source: (%d,%d), target: (%d,%d)", source.row, source.column, target.row, target.column);

    // Seed the initial location
    [map setToken:token atLocation:source];
#if 0
    foo = source;
    source = target;
    target = foo;
#endif
    mapSize = [map mapSize];
    row = source.row;
    col = source.column;
    dx = target.column - source.column;
    dy = target.row - source.row;

    octant = 0;

    if (dy < 0)
    {
        octant |= FLIP_Y;
        dy = -dy;
        row = -row;
        target.row = -target.row;
    }

    if (dx < 0)
    {
        octant |= FLIP_X;
        dx = -dx;
        col = -col;
        target.column = -target.column;
    }

    if (dx < dy)
    {
        int tmp;
        octant |= FLIP_XY;
        tmp = dx;
        dx = dy;
        dy = tmp;

        tmp = row;
        row = col;
        col = tmp;

        tmp = target.row;
        target.row = target.column;
        target.column = tmp;
    }

    d = 2 * dy - dx;

    increment_E = 2 * dy;
    increment_SE = 2 * (dy - dx);

    while (col < target.column)
    {
        if (d <= 0)
        {
            d += increment_E;
            col++;
        }
        else
        {
            d += increment_SE;
            col++;
            row++;
        }

        if (octant & FLIP_XY)
        {
            tmp.row = col;
            tmp.column = row;
        }
        else
        {
            tmp.row = row;
            tmp.column = col;
        }

        if (octant & FLIP_X)
            tmp.column = -tmp.column;
        if (octant & FLIP_Y)
            tmp.row = -tmp.row;

        if (tmp.row >= 0 && tmp.column >= 0 && tmp.row < mapSize.height && tmp.column < mapSize.width)
        {
            if ([self location:tmp adjacentToTerrain:EMTerrainComponent (token)] == NO)
            {
                //[map setToken:token atLocation:tmp];
                break;
            }
        }

        foo = tmp;
    }

    if (foo.row >= 0 && foo.column >= 0 && foo.row < mapSize.height && foo.column < mapSize.width)
    {
        [map setToken:token atLocation:foo];
    }
}

//----------------------------------------------------------------------

- (void) growTerrain:(MapToken)token fromLocation:(EMMapLocation)source
{
    EMMapLocation destination;
    int theta = [rng randomNumberModulo:360];
    double x = (theta * 2 * 3.14159265) / 360;

    destination.row = source.row + 1000 * sin (x);
    destination.column = source.column + 1000 * cos (x);

    [self growTerrain:token fromLocation:source toLocation:destination];
}

//----------------------------------------------------------------------

- (void) branchTerrain:(MapToken)token fromLocation:(EMMapLocation)source
{
    EMMapLocation destination;
    int theta = [rng randomNumberModulo:360];
    double x = (theta * 2 * 3.14159265) / 360;

    destination.row = source.row + 1000 * sin (x);
    destination.column = source.column + 1000 * cos (x);

    [self branchTerrain:token fromLocation:source toLocation:destination];
}

//----------------------------------------------------------------------

- (BOOL) location:(EMMapLocation)target adjacentToTerrain:(Terrain)terrain
{
    BOOL adjacent = NO;
    MapToken tokens[9];
    int l;

    [map get3x3Tokens:tokens aroundLocation:target];
    for (l = 0; l < 9; l++)
    {
        if (EMTerrainComponent (tokens[l]) == terrain)
        {
            adjacent = YES;
            break;
        }
    }

    return adjacent;
}

//----------------------------------------------------------------------

- (void) clearToCurrent:sender
{
    [map clearMapTo:tokenType];
}


//----------------------------------------------------------------------

- (void) suspendMainMapUpdate
{
}

//----------------------------------------------------------------------

- (void) resumeMainMapUpdate
{
}

//======================================================================
// Build World
//======================================================================

- (void) recalculateTerrainDistribution:sender
{
    EMMapSize mapSize;

    terrainCounts[0] = 0;
    terrainCounts[1] = 0;
    terrainCounts[2] = 0;
    terrainCounts[3] = 0;

    if (map != nil)
    {
        mapSize = [map mapSize];

        terrainCounts[0] = mapSize.width * mapSize.height;
        terrainCounts[t_water] = [map countTerrainType:t_water];
        terrainCounts[t_land] = [map countTerrainType:t_land];
        terrainCounts[t_city] = [map countTerrainType:t_city];
    }

    //NSLog (@"%d, %d, %d, %d", terrainCounts[0], terrainCounts[1], terrainCounts[2], terrainCounts[3]);

    [terrainSummaryTableview reloadData];
}

//----------------------------------------------------------------------

- (void) build:sender
{
    EMMapSize mapSize = [map mapSize];
    EMMapLocation source;
    int islandCount;
    int minimumSize;
    int maximumSize;
    int count;
    int l, m, n;
    int buildType;
    //int lastIndex = 0;

    islandCount = [islandCountTextfield intValue];
    minimumSize = [minimumSizeTextfield intValue];
    maximumSize = [maximumSizeTextfield intValue];
    buildType = [[buildTypeMatrix selectedCell] tag];

    [mapEditorWindow setDocumentEdited:YES];
    [mapEditorWindow disableFlushWindow];

    if (buildType == 0)
    {
        for (l = 0; l < islandCount; l++)
        {
            count = [rng randomNumberBetween:minimumSize:maximumSize];
            source.row = [rng randomNumberModulo:mapSize.height];
            source.column = [rng randomNumberModulo:mapSize.width];

            for (m = 0; m < count; m++)
            {
                //source = [self meanderFromLocation:source lastDirectionIndex:&lastIndex];
                for (n = 0; n < 2; n++)
                    [self growTerrain:tokenType fromLocation:source];
            }
        }
    }
    else
    {
        for (l = 0; l < islandCount; l++)
        {
            count = [rng randomNumberBetween:minimumSize:maximumSize];
            source.row = [rng randomNumberModulo:mapSize.height];
            source.column = [rng randomNumberModulo:mapSize.width];

            for (m = 0; m < count; m++)
            {
                //source = [self meanderFromLocation:source lastDirectionIndex:&lastIndex];
                for (n = 0; n < 2; n++)
                    [self branchTerrain:tokenType fromLocation:source];
            }
        }
    }

    [mapEditorWindow enableFlushWindow];
    [self recalculateTerrainDistribution:nil];
}

//----------------------------------------------------------------------

- (void) clearSingleTerrains:sender
{
    EMMapSize mapSize = [map mapSize];
    MapToken tokens[9];
    EMMapLocation target;
    BOOL flag = YES;
    int l;
    int count = 0;

    [mapEditorWindow setDocumentEdited:YES];
    for (target.row = 0; target.row < mapSize.height; target.row++)
    {
        for (target.column = 0; target.column < mapSize.width; target.column++)
        {
            flag = YES;
            [map get3x3Tokens:tokens aroundLocation:target];
            if (tokens[4] != EMCreateMapToken (t_city, p_neutral, i_none, YES))
            {
                count++;

                for (l = 0; l < 9; l++)
                {
                    if (l != 4 && tokens[l] == tokens[4])
                    {
                        flag = NO;
                        break;
                    }
                }

                if (flag == YES)
                {
                    //NSLog (@"tokens: %@", EMFormatNineComponents (tokens));
                    if (EMTerrainComponent (tokens[4]) == t_water)
                        [map setToken:EMCreateMapToken (t_land, p_neutral, i_none, YES) atLocation:target];
                    else
                        [map setToken:EMCreateMapToken (t_water, p_neutral, i_none, YES) atLocation:target];
                        
                    //[map setToken:tokens[0] atLocation:target];
                }
            }
        }
    }
}

//----------------------------------------------------------------------

- (EMMapLocation) meanderFromLocation:(EMMapLocation)location
                   lastDirectionIndex:(int *)lastIndex
                               origin:(EMMapLocation)origin
                                 size:(EMMapSize)size
{
    EMMapLocation target;

    target = [self meanderFromLocation:location lastDirectionIndex:lastIndex];

    if (target.row < origin.row || target.column < origin.column
        || target.row > origin.row + size.height || target.column > origin.column + size.width)
    {
        *lastIndex = (*lastIndex + 4) % 9;
    }

    return target;
}

//----------------------------------------------------------------------

- (EMMapLocation) meanderFromLocation:(EMMapLocation)location lastDirectionIndex:(int *)lastIndex
{
    //EMMapSize mapSize = [map mapSize];

    Direction directions[8] = {d_northwest, d_north, d_northeast, d_east, d_southeast, d_south, d_southwest, d_west};
    Direction dir;
    int turn;

    int dy[9] = {-1, -1, -1,  0,  0,  0,  1,  1,  1};
    int dx[9] = {-1,  0,  1, -1,  0,  1, -1,  0,  1};

    turn = [rng randomNumberBetween:-1:1];
    turn += *lastIndex;

    if (turn < 0)
        turn += 8;
    else if (turn > 7)
        turn -= 8;

    dir = directions[turn];
    *lastIndex = turn;

    location.row += dy[dir];
    location.column += dx[dir];

    return location;
}

//----------------------------------------------------------------------

- (void) meander:sender
{
    EMMapSize mapSize = [map mapSize];
    EMMapLocation source;
    int buildType;
    int m;
    int lastIndex = 0;

    [mapEditorWindow setDocumentEdited:YES];

    buildType = [[buildTypeMatrix selectedCell] tag];
    source.row = [rng randomNumberModulo:mapSize.height];
    source.column = [rng randomNumberModulo:mapSize.width];

    [map setToken:tokenType atLocation:source];
    for (m = 0; m < 20; m++)
    {
        source = [self meanderFromLocation:source lastDirectionIndex:&lastIndex];
        [map setToken:tokenType atLocation:source];
    }
}

//----------------------------------------------------------------------

- (int) numberOfRowsInTableView:(NSTableView *)aTableView
{
    return 4;
}

//----------------------------------------------------------------------

- tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
    NSString *terrainNames[] = {
        @"Total",
        @"Water",
        @"Land",
        @"City"
    };
    id identifier;
    id tmp = nil;
    Terrain terrain;

    identifier = [aTableColumn identifier];
    terrain = (rowIndex >= 3) ? t_unknown : t_water + rowIndex;

    if ([identifier isEqual:@"Terrain"] == YES)
    {
        tmp = terrainNames[terrain];
    }
    else if ([identifier isEqual:@"Count"] == YES)
    {
        tmp = [NSNumber numberWithInt:terrainCounts[terrain]];
    }
    else if ([identifier isEqual:@"Percent"] == YES)
    {
        if (terrainCounts[t_unknown] != 0)
            tmp = [NSString stringWithFormat:@"%.2f", terrainCounts[terrain] * 100.0 / terrainCounts[t_unknown]];
    }

    return tmp;
}

//======================================================================
// MapView Delegate
//======================================================================

- (void) mouseDown:(unsigned int)modifierFlags atLocation:(EMMapLocation)target
{
    EMMapLocation destination;
    
    [mapEditorWindow setDocumentEdited:YES];
    [mapView scrollLocationToVisible:target];

    if ((modifierFlags & NSControlKeyMask) != 0)
    {
        int theta = [rng randomNumberModulo:360];
        double x = (theta * 2 * 3.14159265) / 360;

        destination.row = target.row + 1000 * sin (x);
        destination.column = target.column + 1000 * cos (x);
        [self growTerrain:tokenType fromLocation:target toLocation:destination];

        //[self growTerrain:tokenType fromLocation:target toLocation:0:0];
        //[self growTerrain:tokenType fromLocation:target toLocation:49:79];
        //[self growTerrain:tokenType fromLocation:target toLocation:49:0];
        //[self growTerrain:tokenType fromLocation:target toLocation:destrow:destcol];
    }
    else if ((modifierFlags & NSCommandKeyMask) != 0)
    {
        int theta = [rng randomNumberModulo:360];
        double x = (theta * 2 * 3.14159265) / 360;

        destination.row = target.row + 1000 * sin (x);
        destination.column = target.column + 1000 * cos (x);
        [self branchTerrain:tokenType fromLocation:target toLocation:destination];

        //[self growTerrain:tokenType fromLocation:target toLocation:0:0];
        //[self growTerrain:tokenType fromLocation:target toLocation:49:79];
        //[self growTerrain:tokenType fromLocation:target toLocation:49:0];
        //[self growTerrain:tokenType fromLocation:target toLocation:destrow:destcol];
    }
    else
    {
        switch (brushType)
        {
          case 0:
              [map setToken:tokenType atLocation:target];
              break;

          default:
              [map set3x3TokensTo:tokenType aroundLocation:target];
              break;
        }
    } 
}

//----------------------------------------------------------------------

- (void) mouseUp:(unsigned int)modifierFlags atLocation:(EMMapLocation)target
{
}

//----------------------------------------------------------------------

- (void) rightMouseDown:(unsigned int)modifierFlags atLocation:(EMMapLocation)target
{
}

//----------------------------------------------------------------------

- (void) rightMouseUp:(unsigned int)modifierFlags atLocation:(EMMapLocation)target
{
}

//----------------------------------------------------------------------

- (void) keyDown:(NSEvent *)theEvent
{
}

//======================================================================
// Window Delegate
//======================================================================

- (void) windowDidBecomeKey:(NSNotification *)notification
{
}

//----------------------------------------------------------------------

- (void) windowDidResignKey:(NSNotification *)notification
{
}

//----------------------------------------------------------------------

- (void) windowWillMiniaturize:(NSNotification *)notification
{
    NSWindow *theWindow = [notification object];

    [theWindow setAutodisplay:NO];
}

//----------------------------------------------------------------------

- (void) windowDidDeminiaturize:(NSNotification *)notification
{
    NSWindow *theWindow = [notification object];

    [theWindow setAutodisplay:YES];
    [theWindow displayIfNeeded];
}

@end

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.