/* ---------------------------------------------------------
Super Star Trek
C++ Port Copyright 2008, James M. Curran <jamescurran@mvps.org>
based upon the C Port, Copyright 1996, Chris Nystrom
based upon the PC Basic port, Copyright 1978, Workman Publishing
based upon the HP Basic original, PD circa 1971, Mike Mayfield
C++ code licensed using the Code Project Open License v1.02
http://www.codeproject.com/info/cpol10.aspx
-------------------------------------------------------------- */
// Sector.cpp: implementation of the Sector class.
//
//////////////////////////////////////////////////////////////////////
#include <algorithm>
#include "util.h"
#include "Sector.h"
#include "Game.h"
#include "Random.h"
const string Sector::sector_map::sBase = ">B<"; // ">!<";
const string Sector::sector_map::sEnemy = "]K["; // "%+%";
const string Sector::sector_map::sStar = " * ";
const string Sector::sector_map::sShip = "<E>"; // "<*>";
enum Sector::sector_map::stuff Sector::sector_map::OutOfBounds = eOutOfBounds;
const string Sector::sector_map::sEmpty = " . "; // you may prefer " . " or " + " or " "
const int Sector::movement[2][10] = /* Used for location and movement */
{
{ 0, 0, -1, -1, -1, 0, 1, 1, 1, 0,},
{ 1, 1, 1, 0, -1, -1, -1, 0, 1, 1 }
};
void Sector::New(Quadrant& quad, const Ship& ship)
{
int i;
sect.Clear();
/* Position Enterprise, then Klingons, Starbases, and stars */
sect[ship.inSector()] = sector_map::eShip;
int enemy = quad.NumEnemy();
if (enemy > 0)
{
for (i = 0; i < enemy; i++)
{
Location L = sect.find_empty_place();
sect[L] = sector_map::eEnemy;
Opponents.push_back(Enemy(L, 100 + get_rand(200)));
}
}
if (quad.HasBase())
{
locBase = sect.find_empty_place();
sect[locBase] = sector_map::eBase;
}
for (i = quad.NumStars(); i > 0 ; i--)
{
Location L = sect.find_empty_place();
sect[L] = sector_map::eStar;
}
}
Location Sector::sector_map::find_empty_place()
{
Location loc;
do
{
loc = Location::random();
} while (at(loc) != sector_map::eEmpty);
return(loc);
}
void Sector::sector_map::Clear()
{
for (int i = 0; i < (sizeof(sect)/sizeof(sect[0])); i++)
for (int j = 0; j < (sizeof(sect[0])/sizeof(sect[0][0])); j++)
sect[i][j] = eEmpty;
}
string Sector::sector_map::GetLine(int i)
{
string str;
for (int j = 0; j < (sizeof(sect[0])/sizeof(sect[0][0])); j++)
{
stuff obj = sect[i-1][j];
switch (obj)
{
case eEmpty:
str += sEmpty;
break;
case eStar:
str += sStar;
break;
case eBase:
str += sBase;
break;
case eEnemy:
str += sEnemy;
break;
case eShip:
str += sShip;
break;
}
}
return(str);
}
void Sector::RemoveEnemy(iter_enemy enemy)
{
Clear(enemy->inSector());
enemy->TakeOnDamage(SHRT_MAX);
game.galaxy.RemoveEnemy();
}
void Sector::RemoveDeadEnemy()
{
Opponents.remove_if(std::mem_fun_ref(&Enemy::isDestroyed));
}
void Sector::RemoveEnemy(Location loc)
{
for(iter_enemy iter = Opponents.begin();
iter !=Opponents.end();
++iter)
{
if (iter->IsAt(loc))
{
RemoveEnemy(iter);
break;
}
}
}
bool Sector::RemoveBase()
{
Clear(this->BaseLocation());
return game.galaxy.RemoveBase();
}
void Sector::MoveEnemy()
{
for(iter_enemy iter = Opponents.begin();
iter !=Opponents.end();
++iter)
{
MoveEnemy(*iter);
}
}
void Sector::MoveEnemy(ILocatable& enemy)
{
Clear(enemy.inSector());
Location L = sect.find_empty_place();
sect[L] = sector_map::eEnemy;
enemy.inSector(L);
}
Destination Sector::MoveObject(Ship& ship, double direction, int distance)
{
return MoveObject(ship, direction, distance, nulldev, true, true);
}
Destination Sector::MoveObject(ILocatable& projectile, double direction, int distance, ostream& output, bool canLeaveQuad, bool drawObject )
{
if (drawObject)
{
sector_map::stuff objtype = sect[projectile.inSector()];
Clear(projectile.inSector());
}
int c2 = (int)(direction);
int c3 = c2 +1;
double x1 = movement[0][c2] + (movement[0][c3] - movement[0][c2]) * (direction - c2);
double y1 = movement[1][c2] + (movement[1][c3] - movement[1][c2]) * (direction - c2);
double x = projectile.inSector().x;
double y = projectile.inSector().y;
MoveResult result = Successful;
Location locHitee;
for(int i=1; i <= distance; ++i)
{
x += x1;
y+= y1;
if (x < 1.0 || x >= 9.0 || y < 1.0 || y >=9.0)
{
if (canLeaveQuad)
{
Ship& ship = static_cast<Ship&>(projectile);
result = game.galaxy.InterQuadrantMove(ship, x1, y1, distance);
x = ship.inSector().x;
y = ship.inSector().y;
}
else
{
result = MoveResult::NewQuadrant;
}
break;
}
else
{
output << " " << x << ", " << y << endl;
if (!sect.IsEmpty(x,y))
{
result = HitSomething;
sector_map::stuff hitee = sect.at(x,y);
locHitee = Location(x,y);
// Reposition projectile just before hit.
x -= x1;
y -= y1;
switch(hitee)
{
case sector_map::eBase:
result = HitBase;
break;
case sector_map::eEnemy:
result = HitEnemy;
break;
case sector_map::eStar:
result = HitStar;
break;
}
break;
}
}
}
projectile.inSector(x,y);
if (drawObject)
{
if (result != HitStar)
sect.at(x,y) = sector_map::eShip;
}
return std::make_pair(result, locHitee);
}
void Sector::EnemyReturnsFire(Ship& ship)
{
if (this->Opponents.size() == 0)
return;
if (ship.IsDocked())
{
cout << "Starbase shields protect the Enterprise." << endl << endl;
return;
}
for(iter_enemy iterE = Opponents.begin();
iterE !=Opponents.end();
++iterE)
{
iterE->FiresOn(ship);
}
}
bool Sector::CanDock(const Ship& ship)
{
Location loc = ship.inSector();
for(int x = loc.x-1; x <=loc.x+1; ++x)
for(int y = loc.y-1; y <=loc.y+1; ++y)
{
if (this->sect.at(x,y) == sector_map::eBase)
return true;
}
return false;
}