//
// $Id: OMidpointMoveTo.m,v 1.1 1997/10/28 05:11:30 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: OMidpointMoveTo.m,v 1.1 1997/10/28 05:11:30 nygard Exp $");

#import "OMidpointMoveTo.h"

#import "Map.h"
#import "Unit.h"

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

//======================================================================
//
// This uses the midpoint line drawing algorithm to move a unit
// to a new location.
//
// If it is blocked, it tries using the simple algorithm, being
// careful to set a flag to make sure the parameters are
// recalculated to get the unit to the new location after a move off
// of the best path.
//
//======================================================================

#define OMidpointMoveTo_VERSION 1

@implementation OMidpointMoveTo

+ (void) initialize
{
    if (self == [OMidpointMoveTo class])
    {
        [self setVersion:OMidpointMoveTo_VERSION];
    }
}

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

- initForUnit:(Unit *)aUnit moveToLocation:(EMMapLocation)newLocation onMap:(Map *)map
{
    [super initForUnit:aUnit moveToLocation:newLocation onMap:map];

    firstFlag = YES;

    return self;
}

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

- (void) dealloc
{
    [super dealloc];
}

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

- (NSString *) orderText
{
    return [NSString stringWithFormat:@"Move to %d,%d", destination.row, destination.column];
}

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

- (Direction) nextMove
{
    Direction dir = d_none;

    if (blockedCount == 0)
    {
        dir = [self midpointAlgorithm];
    }
    else
    {
        dir = [super nextMove];
        firstFlag = YES;
    }

    return dir;
}

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

- (Direction) midpointAlgorithm
{
    Direction mapDirs[8][2] = {
        { d_east, d_southeast},
        { d_east, d_northeast},
        { d_west, d_southwest},
        { d_west, d_northwest},
        { d_south, d_southeast},
        { d_north, d_northeast},
        { d_south, d_southwest},
        { d_north, d_northwest}
    };

    Direction dir = d_none;
  
    if (firstFlag == YES)
    {
        EMMapLocation unitLocation = [unit unitLocation];
        dx = destination.column - unitLocation.column;
        dy = destination.row - unitLocation.row;

        octant = 0;

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

        if (dx < 0)
        {
            octant |= FLIP_X;
            dx = -dx;
        }

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

        d = 2 * dy - dx;

        incrementE = 2 * dy;
        incrementSE = 2 * (dy - dx);

        firstFlag = NO;
    }
  
    if (d <= 0)
    {
        d += incrementE;
        dir = mapDirs[octant][0];
    }
    else
    {
        d += incrementSE;
        dir = mapDirs[octant][1];
    }

    return dir;
}

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

- (BOOL) wasBlocked
{
    blockedCount++;

    // First try is midpoint algorithm, next 3 are simple algorithm.

    return blockedCount < 4;
}

@end
