Click here to Skip to main content
15,885,366 members
Articles / Programming Languages / C++

The Object-Oriented Text Star Trek Game in C++

Rate me:
Please Sign up or sign in to vote.
4.74/5 (10 votes)
6 Aug 2008CPOL6 min read 42.4K   816   34  
The Classic Super Star Trek Game rewritten in modern Object-oriented C++
/* ---------------------------------------------------------
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;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) NovelTheory LLC
United States United States
20+ years as a developer : Assembly, C, C++ and C# (in that order) with sidelines in ASP/VBScript, ASP.Net, JavaScript, Perl, QuickBasic, VisualBasic, plus a few others which I'm not going to mention because if I did someone might ask me to use them again (shudder)

Microsoft MVP in VC++ (1994-2004)

I also run www.NJTheater.com as a hobby.

Full resume & stuff at NovelTheory.com

Underused blog at HonestIllusion.com

Comments and Discussions