rogue25b2/gods/
rogue25b2/player/
rogue25b2/space/planets/
rogue25b2/space/prototypes/
rogue25b2/space/ships/
rogue25b2/src/
/***************************************************************************\
[*]    ___    ____   ____   __   __  ____ [*]   ROGUE: ROM With Attitude  [*]
[*]   /#/ )  /#/  ) /#/  ) /#/  /#/ /#/   [*]    All rights reserved      [*]
[*]  /#/ <  /#/  / /#/ _  /#/  /#/ /#/--  [*]   Copyright(C) 2000-2001    [*]
[*] /#/   \(#(__/ (#(__/ (#(__/#/ (#(___  [*] Kenneth Conley (Mendanbar)  [*]
[*]  Expression of Digital Creativity..   [*]  roguemud@yahoogroups.com   [*]
[-]---------------------------------------+-+-----------------------------[-]
[*] File: space.cpp                                                       [*]
[*] Usage: Space and Vehicle Module                                       [*]
\***************************************************************************/

#include <math.h>
#include <stdarg.h>
#include <stdlib.h>

#include "merc.h"
#include "space.h"


LList<ShipData *>	ship_list;
LList<StarSystem *>	starsystem_list;
LList<StellarObject *>	stellar_objects;

// Type defs
enum State {
    Docked,
    Ready,
    Busy,
    Busy2,
    Busy3,
    Refueling,
    Launching,
    Launching2,
    Landing,
    Landing2,
    PreHyper,
    Hyperspace,
    Flying,
    Destroy
};

// Local Funcs
void SendSystem(ShipData *ship, ShipData *ignore, const char *fmt, ...);

// StarSystem stuff
StarSystem::StarSystem(void) {
    this->Init();
}

StarSystem::~StarSystem(void) {
    if (this->name)	free(this->name);
    if (this->filename)	free(this->filename);
}

void StarSystem::Init(void) {
    memset(this, 0, sizeof(*this));
}

void StarSystem::Update(void) {
    ShipData *ship;

    START_ITER(iter, ship, ShipData *, this->ships)
	ship->Update();
}

// StellarObject stuff
StellarObject::StellarObject(StellarObjectType objectType) {
    this->Init();

    this->clan = -1;
    this->zone = -1;
    this->type = objectType;
}

StellarObject::~StellarObject(void) {
    if (this->name)		free(this->name);
    if (this->filename)		free(this->filename);
}

void StellarObject::Init(void) {
    memset(this, 0, sizeof(*this));
}

void StellarObject::Update(void) {
// this would make them move about? if they are mobile?
}

// ShipData stuff
ShipData::ShipData(void) {
    this->Init();

    IN_ROOM(this) = NULL;
    this->state = Docked;
}

ShipData::~ShipData(void) {
    if (this->name)		free(this->name);
    if (this->home)		free(this->home);
    if (this->owner)		free(this->owner);
    if (this->pilot)		free(this->pilot);
    if (this->copilot)		free(this->copilot);
    if (this->filename)		free(this->filename);
    if (this->destination)	free(this->destination);

    for (int i = 0; i < MAX_SHIP_ROOMS; i++) {
	if (this->description[i]) {
	    free(this->description[i]);
	    this->description[i] = NULL;
	}
    }
}

void ShipData::Init(void) {
    memset(this, 0, sizeof(*this));
}

double ShipData::Distance(ShipData *target) {
    float x = this->vx - target->vx,
	y = this->vy - target->vy, z = this->vz - target->vz;
    return sqrt(x*x + y*y + z*z);
}

double ShipData::Distance(StellarObject *target) {
    float x = this->vx - target->x,
	y = this->vy - target->y, z = this->vz - target->z;
    return sqrt(x*x + y*y + z*z);
}

void ShipData::Extract(void) {
    if (this->Purged())
	return;

    if (IN_ROOM(this) != NULL)		this->FromRoom();
    if (this->starsystem)		this->FromSystem();

//    ship_list.Remove(this);
//    purged_ships.Add(this);
    this->Purge();
}

SInt32 ShipData::Send(const char *fmt, ...) {
    SInt32 size;
    va_list args;
    ROOM_INDEX_DATA *room;
    char sendBuffer[MAX_STRING_LENGTH];

    va_start(args, fmt);
    size = vsprintf(sendBuffer, fmt, args);
    va_end(args);

    START_ITER(iter, room, ROOM_INDEX_DATA *, this->rooms)
	room->Send("%s\n\r", sendBuffer);

    return size;
}

SInt32 ShipData::SendCockpit(const char *fmt, ...) {
    SInt32 size;
    va_list args;
    char sendBuffer[MAX_STRING_LENGTH];

    va_start(args, fmt);
    size = vsprintf(sendBuffer, fmt, args);
    va_end(args);

    this->pilotseat->Send("%s\n\r", sendBuffer);
    if (this->pilotseat != this->gunseat)
	this->gunseat->Send("%s\n\r", sendBuffer);
    if (this->pilotseat != this->viewscreen && this->viewscreen != this->gunseat)
	this->viewscreen->Send("%s\n\r", sendBuffer);

    return size;
}

bool ShipData::IsCloaked(void) {
    return false;
}

bool ShipData::CanSee(ShipData *target) {
    if (!this || !target)
	return false;

    if (target->IsCloaked()) {
	    return false;
    }
    return true;
}

void ShipData::Appear(void) {
/*
    Flags oldBits = SHIP_FLAGS(this) & (SHIP_CLOAKED);

    REMOVE_BIT(SHP_FLAGS(this), SHIP_CLOAKED);
    if (oldBits & SHIP_CLOAKED) {
	this->SendCockpit("`YThe ship becomes visible.`n");
	SendSystem(this, 0, "Space shimmers as %s slowly appears.", this->name);
    }
*/
}

void ShipData::Move(void) {
    StellarObject *object;

    if (!this->starsystem)
	return;

    if (this->speed > 0) {
	float nx, ny, nz;
	float change = sqrt(this->hx * this->hx + this->hy * this->hy + this->hz * this->hz);

	if (change > 0) {
	    nx = this->hx / change;
	    ny = this->hy / change;
	    nz = this->hz / change;
	    this->vx += nx * (this->speed / 5);
	    this->vy += ny * (this->speed / 5);
	    this->vz += nz * (this->speed / 5);
	}
    }

    // Insert gravity code here!  Autopilot auto-adjusts for gravity pull.
    if (!this->AutoPilot()) {
	START_ITER(o_iter, object, StellarObject *, this->starsystem->objects) {
	    if (this->vx != object->x)
		this->vx -= URANGE(-3, object->gravity / (this->vx - object->x) / 2, 3);
	    if (this->vy != object->y)
		this->vy -= URANGE(-3, object->gravity / (this->vy - object->y) / 2, 3);
	    if (this->vz != object->z)
		this->vz -= URANGE(-3, object->gravity / (this->vz - object->z) / 2, 3);

	    if (object->type == Star && this->Distance(object) < 10) {
		this->SendCockpit("`R`fYou float directly into the %s.`n", object->name);
		SendSystem(this, 0, "`y%s floats directly into %s!`n", this->name, object->name);
		this->Destroy();
		return;
	    }
	}
    }

    if (this->speed > 0) {
	StellarObject *planet;
	START_ITER(p_iter, planet, StellarObject *, this->starsystem->objects) {
	    if (planet->type != Star)
		continue;

	    if (this->Distance(planet) < 10) {
		this->SendCockpit("`YYou begin orbiting %s.`n", planet->name);
		SendSystem(this, 0, "`y%s begins orbiting %s.`n", this->name, planet->name);
		this->speed = 0;
		return;
	    }
	}
    }
}

void ShipData::Update(void) {
    ShipData *ship;
    StellarObject *object;

    if (this->state == Hyperspace) {
	this->hyperDistance -= this->hyperSpeed;

	if (this->hyperDistance > 0)
	    this->pilotseat->Send("Remaining jump distance: %d.\r\n", this->hyperDistance);
	else {
	    this->ToSystem(this->jumpSystem);
	    this->jumpSystem = NULL;

	    if (this->starsystem == NULL)
		this->SendCockpit("Ship lost during jump.  Make new calculations.\r\n");
	    else {
		this->pilotseat->Send("Hyperjump complete.\r\n");
		this->Send("The ship lurches slightly as it comes out of hyperspace.");
		SendSystem(this, 0, "%s enters the starsystem at %.0f %.0f %.0f.", this->name, this->vx, this->vy, this->vz);
		this->state = Ready;

		free(this->home);
		this->home = str_dup(this->starsystem->name);
	    }
	}
    }

    switch (this->state) {
	case Landing:		this->Land();		break;
	case Launching:		this->Launch();		break;
	case Busy:
	    this->pilotseat->Send("Manuever complete.\r\n");
	    this->state = Ready;
	    break;
	default:					break;
    }

    if (this->starsystem != NULL) {
	double distance, tooClose = speed + 50;

	if (this->speed > 0)
	    this->pilotseat->Send("`BSpeed: `C%d  `BCoords: `C%.0f %.0f %.0f`n", this->speed, this->vx, this->vy, this->vz);

	START_ITER(s_iter, ship, ShipData *, this->starsystem->ships) {
	    if (this == ship)	continue;
	    if ((distance = this->Distance(ship)) < (ship->speed + tooClose))
		this->SendCockpit("`RProximity alert: %s  %.0f %.0f %.0f (%.0f)`n", ship->name, distance, ship->vx, ship->vy, ship->vz);
	}

	tooClose = this->speed + 100;
	START_ITER(o_iter, object, StellarObject *, this->starsystem->objects) {
	    if (object->type != Star)
		continue;
	    if ((distance = this->Distance(object)) < tooClose)
		this->SendCockpit("`RProximity alert: %s  %.0f %.0f %.0f (%.0f)`n", object->name, object->x, object->y, object->z, distance);
	}
    }
}

bool ShipData::ToRoom(UInt32 vnum) {
return false;
}

void ShipData::FromRoom(void) {
}

void ShipData::ToSystem(StarSystem *system) {
}

void ShipData::FromSystem(void) {
}

void ShipData::Land(void) {
}

void ShipData::Launch(void) {
}

void ShipData::Destroy(void) {
}

bool ShipData::AutoPilot(void) {
return false;
}

// Local Functions
void SendSystem(ShipData *ship, ShipData *ignore, const char *fmt, ...) {
    va_list args;
    ShipData *target;
    char sendBuffer[MAX_STRING_LENGTH];

    if (!ship->starsystem || !fmt || !*fmt)
	return;

    va_start(args, fmt);
    vsprintf(sendBuffer, fmt, args);
    va_end(args);

    START_ITER(iter, target, ShipData *, ship->starsystem->ships) {
	if (target != ship && target != ignore && target->CanSee(ship))
	    target->SendCockpit(sendBuffer);
    }
    return;
}

void MoveShips(void) {
    ShipData *ship;

    START_ITER(siter, ship, ShipData *, ship_list)
	ship->Move();
}

void UpdateSpace(void) {
    ShipData *ship;
    StellarObject *object;

    START_ITER(iter1, ship, ShipData *, ship_list)
	ship->Update();

    START_ITER(iter2, object, StellarObject *, stellar_objects)
	object->Update();
}


// temp func
void load_space(void) {
return;
    ShipData *ship;
    StarSystem *system;
    StellarObject *object;

    ship = new ShipData();
    ship_list.Append(ship);
    ship->name = str_dup("Mendanbar's F496 StarFighter 001");

    system = new StarSystem();
    starsystem_list.Append(system);
    system->name = str_dup("Terra Prime");

    object = new StellarObject();
    stellar_objects.Append(object);
    object->name = str_dup("Planet Nevermind");
}