From d17521c8b9085a91d08fecfd0b51bbbf7b1dccac Mon Sep 17 00:00:00 2001 From: "milo24x7@gmail.com" Date: Sun, 7 Jul 2013 22:08:49 +0000 Subject: Updated open source license declaration and fixed some formatting issues. --- Stars45/Mfd.cpp | 2832 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 1428 insertions(+), 1404 deletions(-) (limited to 'Stars45/Mfd.cpp') diff --git a/Stars45/Mfd.cpp b/Stars45/Mfd.cpp index baa31c2..7c1e704 100644 --- a/Stars45/Mfd.cpp +++ b/Stars45/Mfd.cpp @@ -1,1404 +1,1428 @@ -/* Project Starshatter 5.0 - Destroyer Studios LLC - Copyright (C) 1997-2007. All Rights Reserved. - - SUBSYSTEM: Stars.exe - FILE: MFD.cpp - AUTHOR: John DiCamillo - - - OVERVIEW - ======== - Class for all Multi Function Displays -*/ - -#include "MemDebug.h" -#include "MFD.h" -#include "HUDView.h" -#include "Ship.h" -#include "NavSystem.h" -#include "Power.h" -#include "Shield.h" -#include "Sensor.h" -#include "Contact.h" -#include "ShipDesign.h" -#include "Shot.h" -#include "Weapon.h" -#include "WeaponGroup.h" -#include "Sim.h" -#include "StarSystem.h" -#include "Starshatter.h" -#include "Drive.h" -#include "QuantumDrive.h" -#include "Power.h" -#include "Instruction.h" - -#include "NetGame.h" - -#include "CameraView.h" -#include "Color.h" -#include "Font.h" -#include "FontMgr.h" -#include "Window.h" -#include "Video.h" -#include "Screen.h" -#include "DataLoader.h" -#include "Scene.h" -#include "Graphic.h" -#include "Sprite.h" -#include "Keyboard.h" -#include "Mouse.h" -#include "Game.h" - -static Bitmap sensor_fov; -static Bitmap sensor_fwd; -static Bitmap sensor_hsd; -static Bitmap sensor_3d; - -static BYTE* sensor_fov_shade; -static BYTE* sensor_fwd_shade; -static BYTE* sensor_hsd_shade; -static BYTE* sensor_3d_shade; - -static Color hud_color = Color::Black; -static Color txt_color = Color::Black; - -// +--------------------------------------------------------------------+ - -MFD::MFD(Window* c, int n) -: window(c), rect(0,0,0,0), index(n), mode(MFD_MODE_OFF), sprite(0), -ship(0), hidden(true), camview(0), lines(0), mouse_latch(0), mouse_in(false), -cockpit_hud_texture(0) -{ - sprite = new(__FILE__,__LINE__) Sprite(&sensor_fov); - - sprite->SetBlendMode(2); - sprite->SetFilter(0); - sprite->Hide(); - - Font* font = FontMgr::Find("HUD"); - - for (int i = 0; i < TXT_LAST; i++) { - mfd_text[i].font = font; - mfd_text[i].color = Color::White; - mfd_text[i].hidden = true; - } -} - -MFD::~MFD() -{ - GRAPHIC_DESTROY(sprite); -} - -// +--------------------------------------------------------------------+ - -void -MFD::Initialize() -{ - static int initialized = 0; - if (initialized) return; - - HUDView::PrepareBitmap("sensor_fov.pcx", sensor_fov, sensor_fov_shade); - HUDView::PrepareBitmap("sensor_fwd.pcx", sensor_fwd, sensor_fwd_shade); - HUDView::PrepareBitmap("sensor_hsd.pcx", sensor_hsd, sensor_hsd_shade); - HUDView::PrepareBitmap("sensor_3d.pcx", sensor_3d, sensor_3d_shade); - - sensor_fov.SetType(Bitmap::BMP_TRANSLUCENT); - sensor_fwd.SetType(Bitmap::BMP_TRANSLUCENT); - sensor_hsd.SetType(Bitmap::BMP_TRANSLUCENT); - sensor_3d.SetType(Bitmap::BMP_TRANSLUCENT); - - initialized = 1; -} - -void -MFD::Close() -{ - sensor_fov.ClearImage(); - sensor_fwd.ClearImage(); - sensor_hsd.ClearImage(); - sensor_3d.ClearImage(); - - delete [] sensor_fov_shade; - delete [] sensor_fwd_shade; - delete [] sensor_hsd_shade; - delete [] sensor_3d_shade; -} - -// +--------------------------------------------------------------------+ - -void -MFD::UseCameraView(CameraView* v) -{ - if (v && !camview) { - camview = v; - } -} - -void -MFD::SetColor(Color c) -{ - HUDView* hud = HUDView::GetInstance(); - - if (hud) { - hud_color = hud->GetHUDColor(); - txt_color = hud->GetTextColor(); - } - else { - hud_color = c; - txt_color = c; - } - - HUDView::ColorizeBitmap(sensor_fov, sensor_fov_shade, c); - HUDView::ColorizeBitmap(sensor_fwd, sensor_fwd_shade, c); - HUDView::ColorizeBitmap(sensor_hsd, sensor_hsd_shade, c); - HUDView::ColorizeBitmap(sensor_3d, sensor_3d_shade, c); -} - -void -MFD::SetText3DColor(Color c) -{ - for (int i = 0; i < TXT_LAST; i++) - mfd_text[i].color = c; -} - -// +--------------------------------------------------------------------+ - -void -MFD::Show() -{ - switch (mode) { - case MFD_MODE_FOV: - case MFD_MODE_HSD: - case MFD_MODE_3D: - if (sprite) - sprite->Show(); - break; - } - - hidden = false; -} - -void -MFD::Hide() -{ - if (sprite) - sprite->Hide(); - - for (int i = 0; i < TXT_LAST; i++) - HideMFDText(i); - - hidden = true; -} - -// +--------------------------------------------------------------------+ - -void -MFD::SetRect(const Rect& r) -{ - rect = r; - - if (sprite) - sprite->MoveTo(Point(rect.x + sprite->Width()/2, - rect.y + sprite->Height()/2, - 1)); -} - -// +--------------------------------------------------------------------+ - -void -MFD::SetMode(int m) -{ - if (m < MFD_MODE_OFF || m > MFD_MODE_3D) - mode = MFD_MODE_OFF; - else - mode = m; - - sprite->Hide(); - - for (int i = 0; i < TXT_LAST; i++) - HideMFDText(i); - - switch (mode) { - case MFD_MODE_GAME: - case MFD_MODE_SHIP: - lines = 0; - break; - - case MFD_MODE_FOV: - sprite->SetAnimation(&sensor_fov); - sprite->Show(); - sprite->Reshape(sensor_fov.Width()-8, 16); - break; - case MFD_MODE_HSD: - sprite->SetAnimation(&sensor_hsd); - sprite->Show(); - sprite->Reshape(sensor_hsd.Width()-8, 16); - break; - case MFD_MODE_3D: - sprite->SetAnimation(&sensor_3d); - sprite->Show(); - sprite->Reshape(sensor_3d.Width()-8, 16); - break; - } -} - -// +--------------------------------------------------------------------+ - -void -MFD::Draw() -{ - mouse_in = false; - - if (Mouse::LButton() == 0) - mouse_latch = 0; - - if (rect.Contains(Mouse::X(), Mouse::Y())) - mouse_in = true; - - // click to turn on MFD when off: - if (mode < MFD_MODE_FOV && Mouse::LButton() && !mouse_latch) { - mouse_latch = 1; - if (mouse_in) { - HUDView* hud = HUDView::GetInstance(); - if (hud) - hud->CycleMFDMode(index); - } - } - - for (int i = 0; i < TXT_LAST; i++) - HideMFDText(i); - - if (hidden || mode < MFD_MODE_FOV) { - if (cockpit_hud_texture) { - int x1 = index*128; - int y1 = 256; - int x2 = x1 + 128; - int y2 = y1 + 128; - - cockpit_hud_texture->FillRect(x1, y1, x2, y2, Color::Black); - } - - if (hidden) - return; - } - - if (sprite && !sprite->Hidden()) { - if (cockpit_hud_texture) { - int x1 = index*128; - int y1 = 256; - int w = sprite->Width(); - int h = sprite->Height(); - - cockpit_hud_texture->BitBlt(x1, y1, *sprite->Frame(), 0,0,w,h); - } - else { - int cx = rect.x + rect.w/2; - int cy = rect.y + rect.h/2; - int w2 = sprite->Width()/2; - int h2 = sprite->Height()/2; - - window->DrawBitmap(cx-w2, cy-h2, cx+w2, cy+h2, sprite->Frame(), Video::BLEND_ALPHA); - } - } - - switch (mode) { - default: - case MFD_MODE_OFF: break; - case MFD_MODE_GAME: DrawGameMFD(); break; - case MFD_MODE_SHIP: DrawStatusMFD(); break; - - // sensor sub-modes: - case MFD_MODE_FOV: DrawSensorMFD(); break; - case MFD_MODE_HSD: DrawHSD(); break; - case MFD_MODE_3D: Draw3D(); break; - } -} - -// +--------------------------------------------------------------------+ - -void -MFD::DrawSensorLabels(const char* mfd_mode) -{ - Sensor* sensor = ship->GetSensor(); - char mode_buf[8] = " "; - int scan_r = rect.w; - int scan_x = rect.x; - int scan_y = rect.y; - - switch (sensor->GetMode()) { - case Sensor::PAS: strcpy_s(mode_buf, Game::GetText("MFD.mode.passive").data()); break; - case Sensor::STD: strcpy_s(mode_buf, Game::GetText("MFD.mode.standard").data()); break; - case Sensor::ACM: strcpy_s(mode_buf, Game::GetText("MFD.mode.auto-combat").data()); break; - case Sensor::GM: strcpy_s(mode_buf, Game::GetText("MFD.mode.ground").data()); break; - case Sensor::PST: strcpy_s(mode_buf, Game::GetText("MFD.mode.passive").data()); break; - case Sensor::CST: strcpy_s(mode_buf, Game::GetText("MFD.mode.combined").data()); break; - default: break; - } - - Rect mode_rect(scan_x+2, scan_y+2, 40, 12); - DrawMFDText(0, mode_buf, mode_rect, DT_LEFT); - - char range_txt[12]; - double beam_range = sensor->GetBeamRange() + 1; - if (beam_range >= 1e6) - sprintf_s(range_txt, "-%dM+", (int) (beam_range / 1e6)); - else - sprintf_s(range_txt, "-%3d+", (int) (beam_range / 1e3)); - - Rect range_rect(scan_x+2, scan_y+scan_r-12, 40, 12); - DrawMFDText(1, range_txt, range_rect, DT_LEFT); - - Rect disp_rect(scan_x+scan_r-41, scan_y+2, 40, 12); - DrawMFDText(2, mfd_mode, disp_rect, DT_RIGHT); - - Rect probe_rect(scan_x+scan_r-41, scan_y+scan_r-12, 40, 12); - - if (ship->GetProbeLauncher()) { - char probes[32]; - sprintf_s(probes, "%s %02d", Game::GetText("MFD.probe").data(), ship->GetProbeLauncher()->Ammo()); - DrawMFDText(3, probes, probe_rect, DT_RIGHT); - } - else { - HideMFDText(3); - } - - if (Mouse::LButton() && !mouse_latch) { - mouse_latch = 1; - - if (mode_rect.Contains(Mouse::X(), Mouse::Y())) { - if (sensor->GetMode() < Sensor::PST) { - int sensor_mode = sensor->GetMode() + 1; - if (sensor_mode > Sensor::GM) - sensor_mode = Sensor::PAS; - - sensor->SetMode((Sensor::Mode) sensor_mode); - } - } - - else if (range_rect.Contains(Mouse::X(), Mouse::Y())) { - if (Mouse::X() > range_rect.x+range_rect.w/2) - sensor->IncreaseRange(); - else - sensor->DecreaseRange(); - } - - else if (disp_rect.Contains(Mouse::X(), Mouse::Y())) { - HUDView* hud = HUDView::GetInstance(); - if (hud) - hud->CycleMFDMode(index); - } - - else if (probe_rect.Contains(Mouse::X(), Mouse::Y())) { - ship->LaunchProbe(); - } - } -} - -// +--------------------------------------------------------------------+ - -// AZIMUTH-ELEVATION ANGULAR SCANNER - -void -MFD::DrawSensorMFD() -{ - int scan_r = rect.w; - int scan_x = cockpit_hud_texture ? (index*128) : rect.x; - int scan_y = cockpit_hud_texture ? 256 : rect.y; - int r = scan_r / 2; - - double xctr = (scan_r / 2.0) - 0.5; - double yctr = (scan_r / 2.0) + 0.5; - - Sensor* sensor = ship->GetSensor(); - if (!sensor) { - DrawMFDText(0, Game::GetText("MFD.inactive").data(), rect, DT_CENTER); - return; - } - - int w = sprite->Width(); - int h = sprite->Height(); - - if (w < sprite->Frame()->Width()) - w += 2; - - if (h < sprite->Frame()->Height()) - h += 16; - - sprite->Reshape(w, h); - sprite->Show(); - - if (h < sprite->Frame()->Height()) - return; - - double sweep_scale = r / (PI/2); - - if (sensor->GetBeamLimit() > 90*DEGREES) - sweep_scale = (double) r / (90*DEGREES); - - int az = (int) (sensor->GetBeamLimit() * sweep_scale); - int el = az; - int xc = (int) (scan_x + xctr); - int yc = (int) (scan_y + yctr); - - if (mode == MFD_MODE_FOV) { - if (sensor->GetMode() < Sensor::GM) { - if (cockpit_hud_texture) - cockpit_hud_texture->DrawEllipse(xc-az, yc-el, xc+az, yc+el, hud_color); - else - window->DrawEllipse(xc-az, yc-el, xc+az, yc+el, hud_color); - } - } - else { - char az_txt[8]; - sprintf_s(az_txt, "%d", (int) (sensor->GetBeamLimit() / DEGREES)); - - Rect az_rect(scan_x+2, scan_y+scan_r-12, 32, 12); - DrawMFDText(1, az_txt, az_rect, DT_LEFT); - - az_rect.x = scan_x + (scan_r/2) - (az_rect.w/2); - DrawMFDText(2, "0", az_rect, DT_CENTER); - - az_rect.x = scan_x + scan_r - az_rect.w - 2; - DrawMFDText(3, az_txt, az_rect, DT_RIGHT); - } - - // draw next nav point: - Instruction* navpt = ship->GetNextNavPoint(); - if (navpt && navpt->Region() == ship->GetRegion()) { - const Camera* cam = &ship->Cam(); - - // translate: - Point pt = navpt->Location().OtherHand() - ship->Location(); - - // rotate: - double tx = pt * cam->vrt(); - double ty = pt * cam->vup(); - double tz = pt * cam->vpn(); - - if (tz > 1.0) { - // convert to spherical coords: - double rng = pt.length(); - double az = asin(fabs(tx) / rng); - double el = asin(fabs(ty) / rng); - - if (tx < 0) az = -az; - if (ty < 0) el = -el; - - if (fabs(az) < 90*DEGREES) { - az *= sweep_scale; - el *= sweep_scale; - - int x = (int) (r + az); - int y = (int) (r - el); - - // clip again: - if (x > 0 && x < scan_r && - y > 0 && y < scan_r) { - - // draw: - int xc = scan_x + x; - int yc = scan_y + y; - - if (cockpit_hud_texture) { - cockpit_hud_texture->DrawLine(xc-2, yc-2, xc+2, yc+2, Color::White); - cockpit_hud_texture->DrawLine(xc-2, yc+2, xc+2, yc-2, Color::White); - } - else { - window->DrawLine(xc-2, yc-2, xc+2, yc+2, Color::White); - window->DrawLine(xc-2, yc+2, xc+2, yc-2, Color::White); - } - } - } - } - } - - int num_contacts = ship->NumContacts(); - ListIter iter = ship->ContactList(); - - while (++iter) { - Contact* contact = iter.value(); - Ship* c_ship = contact->GetShip(); - double az, el, rng; - bool aft = false; - - if (c_ship == ship) continue; - - contact->GetBearing(ship, az, el, rng); - - // clip (is in-front): - if (fabs(az) < 90*DEGREES) { - az *= sweep_scale; - el *= sweep_scale; - } - - // rear anulus: - else { - double len = sqrt(az*az + el*el); - - if (len > 1e-6) { - az = r * az/len; - el = r * el/len; - } - else { - az = -r; - el = 0; - } - - aft = true; - } - - int x = (int) (r + az); - int y = (int) (r - el); - - // clip again: - if (x < 0 || x > scan_r) continue; - if (y < 0 || y > scan_r) continue; - - // draw: - Color mark = HUDView::MarkerColor(contact); - - if (aft) - mark = mark * 0.75; - - int xc = scan_x + x; - int yc = scan_y + y; - int size = 1; - - if (c_ship && c_ship == ship->GetTarget()) - size = 2; - - if (cockpit_hud_texture) - cockpit_hud_texture->FillRect(xc-size, yc-size, xc+size, yc+size, mark); - else - window->FillRect(xc-size, yc-size, xc+size, yc+size, mark); - - if (contact->Threat(ship)) { - if (c_ship) { - if (cockpit_hud_texture) - cockpit_hud_texture->DrawEllipse(xc-4, yc-4, xc+3, yc+3, mark); - else - window->DrawEllipse(xc-4, yc-4, xc+3, yc+3, mark); - } - else { - if (cockpit_hud_texture) { - cockpit_hud_texture->DrawLine(xc, yc-5, xc+5, yc, mark); - cockpit_hud_texture->DrawLine(xc+5, yc, xc, yc+5, mark); - cockpit_hud_texture->DrawLine(xc, yc+5, xc-5, yc, mark); - cockpit_hud_texture->DrawLine(xc-5, yc, xc, yc-5, mark); - } - else { - window->DrawLine(xc, yc-5, xc+5, yc, mark); - window->DrawLine(xc+5, yc, xc, yc+5, mark); - window->DrawLine(xc, yc+5, xc-5, yc, mark); - window->DrawLine(xc-5, yc, xc, yc-5, mark); - } - } - } - } - - DrawSensorLabels(Game::GetText("MFD.mode.field-of-view").data()); -} - -// +--------------------------------------------------------------------+ - -// HORIZONTAL SITUATION DISPLAY - -void -MFD::DrawHSD() -{ - int scan_r = rect.w; - int scan_x = cockpit_hud_texture ? (index*128) : rect.x; - int scan_y = cockpit_hud_texture ? 256 : rect.y; - int r = scan_r / 2 - 4; - - double xctr = (scan_r / 2.0) - 0.5; - double yctr = (scan_r / 2.0) + 0.5; - - int xc = (int) xctr + scan_x; - int yc = (int) yctr + scan_y; - - Sensor* sensor = ship->GetSensor(); - if (!sensor) { - DrawMFDText(0, Game::GetText("MFD.inactive").data(), rect, DT_CENTER); - return; - } - - int w = sprite->Width(); - int h = sprite->Height(); - - if (w < sprite->Frame()->Width()) - w += 2; - - if (h < sprite->Frame()->Height()) - h += 16; - - sprite->Reshape(w, h); - sprite->Show(); - - if (h < sprite->Frame()->Height()) - return; - - if (sensor->GetMode() < Sensor::PST) { - double s = sin(sensor->GetBeamLimit()); - double c = cos(sensor->GetBeamLimit()); - - int x0 = (int) (0.1*r*s); - int y0 = (int) (0.1*r*c); - int x1 = (int) (1.0*r*s); - int y1 = (int) (1.0*r*c); - - if (cockpit_hud_texture) { - cockpit_hud_texture->DrawLine(xc-x0, yc-y0, xc-x1, yc-y1, hud_color); - cockpit_hud_texture->DrawLine(xc+x0, yc-y0, xc+x1, yc-y1, hud_color); - } - else { - window->DrawLine(xc-x0, yc-y0, xc-x1, yc-y1, hud_color); - window->DrawLine(xc+x0, yc-y0, xc+x1, yc-y1, hud_color); - } - } - - double rscale = (double) r/(sensor->GetBeamRange()); - - Camera hsd_cam = ship->Cam(); - Point look = ship->Location() + ship->Heading() * 1000; - look.y = ship->Location().y; - - hsd_cam.LookAt(look); - - // draw tick marks on range rings: - for (int dir = 0; dir < 4; dir++) { - Point tick; - - switch (dir) { - case 0: tick = Point( 0, 0, 1000); break; - case 1: tick = Point( 1000, 0, 0); break; - case 2: tick = Point( 0, 0, -1000); break; - case 3: tick = Point(-1000, 0, 0); break; - } - - double tx = tick * hsd_cam.vrt(); - double tz = tick * hsd_cam.vpn(); - double az = asin(fabs(tx) / 1000); - - if (tx < 0) az = -az; - - if (tz < 0) - if (az < 0) az = -PI - az; - else az = PI - az; - - for (double range = 0.3; range < 1; range += 0.3) { - int x0 = (int) (sin(az) * r * range); - int y0 = (int) (cos(az) * r * range); - int x1 = (int) (sin(az) * r * (range + 0.1)); - int y1 = (int) (cos(az) * r * (range + 0.1)); - - if (cockpit_hud_texture) { - cockpit_hud_texture->DrawLine(xc+x0, yc-y0, xc+x1, yc-y1, hud_color); - } - else { - window->DrawLine(xc+x0, yc-y0, xc+x1, yc-y1, hud_color); - } - } - } - - // draw next nav point: - Instruction* navpt = ship->GetNextNavPoint(); - if (navpt && navpt->Region() == ship->GetRegion()) { - const Camera* cam = &hsd_cam; - - // translate: - Point pt = navpt->Location().OtherHand() - ship->Location(); - - // rotate: - double tx = pt * cam->vrt(); - double ty = pt * cam->vup(); - double tz = pt * cam->vpn(); - - // convert to spherical coords: - double rng = pt.length(); - double az = asin(fabs(tx) / rng); - - if (rng > sensor->GetBeamRange()) - rng = sensor->GetBeamRange(); - - if (tx < 0) - az = -az; - - if (tz < 0) - if (az < 0) - az = -PI - az; - else - az = PI - az; - - // draw: - int x = (int) (xc + sin(az) * rng * rscale); - int y = (int) (yc - cos(az) * rng * rscale); - - if (cockpit_hud_texture) { - cockpit_hud_texture->DrawLine(x-2, y-2, x+2, y+2, Color::White); - cockpit_hud_texture->DrawLine(x-2, y+2, x+2, y-2, Color::White); - } - else { - window->DrawLine(x-2, y-2, x+2, y+2, Color::White); - window->DrawLine(x-2, y+2, x+2, y-2, Color::White); - } - } - - // draw contact markers: - double limit = sensor->GetBeamRange(); - ListIter contact = ship->ContactList(); - - while (++contact) { - Ship* c_ship = contact->GetShip(); - if (c_ship == ship) continue; - - // translate: - Point targ_pt = contact->Location() - hsd_cam.Pos(); - - // rotate: - double tx = targ_pt * hsd_cam.vrt(); - double rg = contact->Range(ship, limit); - double true_range = targ_pt.length(); - double az = asin(fabs(tx) / true_range); - - // clip: - if (rg > limit || rg <= 0) - continue; - - if (tx < 0) - az = -az; - - if (!contact->InFront(ship)) - if (az < 0) - az = -PI - az; - else - az = PI - az; - - // draw: - int x = (int) (xc + sin(az) * rg * rscale); - int y = (int) (yc - cos(az) * rg * rscale); - int size = 2; - - // clip again: - if (x < scan_x || y < scan_y) - continue; - - if (c_ship && c_ship == ship->GetTarget()) - size = 3; - - Color mark = HUDView::MarkerColor(contact.value()); - if (cockpit_hud_texture) { - cockpit_hud_texture->FillRect(x-size, y-size, x+size, y+size, mark); - } - else { - window->FillRect(x-size, y-size, x+size, y+size, mark); - } - - if (contact->Threat(ship)) { - if (c_ship) { - if (cockpit_hud_texture) { - cockpit_hud_texture->DrawEllipse(x-4, y-4, x+3, y+3, mark); - } - else { - window->DrawEllipse(x-4, y-4, x+3, y+3, mark); - } - } - else { - if (cockpit_hud_texture) { - cockpit_hud_texture->DrawLine(x, y-5, x+5, y, mark); - cockpit_hud_texture->DrawLine(x+5, y, x, y+5, mark); - cockpit_hud_texture->DrawLine(x, y+5, x-5, y, mark); - cockpit_hud_texture->DrawLine(x-5, y, x, y-5, mark); - } - else { - window->DrawLine(x, y-5, x+5, y, mark); - window->DrawLine(x+5, y, x, y+5, mark); - window->DrawLine(x, y+5, x-5, y, mark); - window->DrawLine(x-5, y, x, y-5, mark); - } - } - } - } - - DrawSensorLabels(Game::GetText("MFD.mode.horizontal").data()); -} - -// +--------------------------------------------------------------------+ - -// ELITE-STYLE 3D RADAR - -void -MFD::Draw3D() -{ - int scan_r = rect.w; - int scan_x = cockpit_hud_texture ? (index*128) : rect.x; - int scan_y = cockpit_hud_texture ? 256 : rect.y; - int r = scan_r / 2 - 4; - - double xctr = (scan_r / 2.0) - 0.5; - double yctr = (scan_r / 2.0) + 0.5; - - int xc = (int) xctr + scan_x; - int yc = (int) yctr + scan_y; - - Sensor* sensor = ship->GetSensor(); - if (!sensor) { - DrawMFDText(0, Game::GetText("MFD.inactive").data(), rect, DT_CENTER); - return; - } - - int w = sprite->Width(); - int h = sprite->Height(); - - if (w < sprite->Frame()->Width()) - w += 2; - - if (h < sprite->Frame()->Height()) - h += 16; - - sprite->Reshape(w, h); - sprite->Show(); - - if (h < sprite->Frame()->Height()) - return; - - double rscale = (double) r/(sensor->GetBeamRange()); - - Camera hsd_cam = ship->Cam(); - - if (ship->IsStarship()) { - Point look = ship->Location() + ship->Heading() * 1000; - look.y = ship->Location().y; - - hsd_cam.LookAt(look); - } - - - // draw next nav point: - Instruction* navpt = ship->GetNextNavPoint(); - if (navpt && navpt->Region() == ship->GetRegion()) { - const Camera* cam = &hsd_cam; - - // translate: - Point pt = navpt->Location().OtherHand() - ship->Location(); - - // rotate: - double tx = pt * cam->vrt(); - double ty = pt * cam->vup(); - double tz = pt * cam->vpn(); - - // convert to cylindrical coords: - double rng = pt.length(); - double az = asin(fabs(tx) / rng); - - if (rng > sensor->GetBeamRange()) - rng = sensor->GetBeamRange(); - - if (tx < 0) - az = -az; - - if (tz < 0) { - if (az < 0) - az = -PI - az; - else - az = PI - az; - } - - // accentuate vertical: - if (ty > 10) - ty = log10(ty-9) * r/8; - - else if (ty < -10) - ty = -log10(9-ty) * r/8; - - else - ty = 0; - - // draw: - int x = (int) (sin(az) * rng * rscale); - int y = (int) (cos(az) * rng * rscale/2); - int z = (int) (ty); - - int x0 = xc+x; - int y0 = yc-y-z; - - if (cockpit_hud_texture) { - cockpit_hud_texture->DrawLine(x0-2, y0-2, x0+2, y0+2, Color::White); - cockpit_hud_texture->DrawLine(x0-2, y0+2, x0+2, y0-2, Color::White); - } - else { - window->DrawLine(x0-2, y0-2, x0+2, y0+2, Color::White); - window->DrawLine(x0-2, y0+2, x0+2, y0-2, Color::White); - } - - if (cockpit_hud_texture) { - if (z > 0) - cockpit_hud_texture->DrawLine(x0, y0+1, x0, y0+z, Color::White); - else if (z < 0) - cockpit_hud_texture->DrawLine(x0, y0+z, x0, y0-1, Color::White); - } - else { - if (z > 0) - window->DrawLine(x0, y0+1, x0, y0+z, Color::White); - else if (z < 0) - window->DrawLine(x0, y0+z, x0, y0-1, Color::White); - } - } - - - // draw contact markers: - double limit = sensor->GetBeamRange(); - ListIter contact = ship->ContactList(); - - while (++contact) { - Ship* c_ship = contact->GetShip(); - if (c_ship == ship) continue; - - // translate: - Point targ_pt = contact->Location() - hsd_cam.Pos(); - - // rotate: - double tx = targ_pt * hsd_cam.vrt(); - double ty = targ_pt * hsd_cam.vup(); - double rg = contact->Range(ship, limit); - double true_range = targ_pt.length(); - double az = asin(fabs(tx) / true_range); - - // clip: - if (rg > limit || rg <= 0) - continue; - - if (tx < 0) - az = -az; - - if (!contact->InFront(ship)) - if (az < 0) - az = -PI - az; - else - az = PI - az; - - // accentuate vertical: - ty *= 4; - - // draw: - int x = (int) (sin(az) * rg * rscale); - int y = (int) (cos(az) * rg * rscale/2); - int z = (int) (ty * rscale/2); - int size = 1; - - int x0 = xc+x; - int y0 = yc-y-z; - - if (c_ship && c_ship == ship->GetTarget()) - size = 2; - - Color mark = HUDView::MarkerColor(contact.value()); - - if (cockpit_hud_texture) { - cockpit_hud_texture->FillRect(x0-size, y0-size, x0+size, y0+size, mark); - - if (contact->Threat(ship)) { - if (c_ship) { - cockpit_hud_texture->DrawEllipse(x0-4, y0-4, x0+3, y0+3, mark); - } - else { - cockpit_hud_texture->DrawLine(x0, y0-5, x0+5, y0, mark); - cockpit_hud_texture->DrawLine(x0+5, y0, x0, y0+5, mark); - cockpit_hud_texture->DrawLine(x0, y0+5, x0-5, y0, mark); - cockpit_hud_texture->DrawLine(x0-5, y0, x0, y0-5, mark); - } - } - - if (z > 0) - cockpit_hud_texture->FillRect(x0-1, y0+size, x0, y0+z, mark); - else if (z < 0) - cockpit_hud_texture->FillRect(x0-1, y0+z, x0, y0-size, mark); - } - else { - window->FillRect(x0-size, y0-size, x0+size, y0+size, mark); - - if (contact->Threat(ship)) { - if (c_ship) { - window->DrawEllipse(x0-4, y0-4, x0+3, y0+3, mark); - } - else { - window->DrawLine(x0, y0-5, x0+5, y0, mark); - window->DrawLine(x0+5, y0, x0, y0+5, mark); - window->DrawLine(x0, y0+5, x0-5, y0, mark); - window->DrawLine(x0-5, y0, x0, y0-5, mark); - } - } - - if (z > 0) - window->FillRect(x0-1, y0+size, x0, y0+z, mark); - else if (z < 0) - window->FillRect(x0-1, y0+z, x0, y0-size, mark); - } - } - - DrawSensorLabels(Game::GetText("MFD.mode.3D").data()); -} - -// +--------------------------------------------------------------------+ - -// GROUND MAP - -void -MFD::DrawMap() -{ - DrawMFDText(0, Game::GetText("MFD.mode.ground").data(), Rect(rect.x, rect.y, rect.w, 12), DT_CENTER); -} - -// +--------------------------------------------------------------------+ - -void -MFD::DrawGauge(int x, int y, int percent) -{ - if (cockpit_hud_texture) { - x += this->index * 128 - this->rect.x; - y += 256 - this->rect.y; - cockpit_hud_texture->DrawRect(x, y, x+53, y+8, Color::DarkGray); - } - else { - window->DrawRect(x, y, x+53, y+8, Color::DarkGray); - } - - if (percent < 3) return; - if (percent > 100) percent = 100; - - percent /= 2; - - if (cockpit_hud_texture) - cockpit_hud_texture->FillRect(x+2, y+2, x+2+percent, y+7, Color::Gray); - else - window->FillRect(x+2, y+2, x+2+percent, y+7, Color::Gray); -} - -void -MFD::DrawGameMFD() -{ - if (lines < 10) lines++; - - char txt[64]; - Rect txt_rect(rect.x, rect.y, rect.w, 12); - - int t = 0; - - if (!HUDView::IsArcade() && HUDView::ShowFPS()) { - sprintf_s(txt, "FPS: %6.2f", Game::FrameRate()); - DrawMFDText(t++, txt, txt_rect, DT_LEFT); - txt_rect.y += 10; - - if (lines <= 1) return; - - Starshatter* game = Starshatter::GetInstance(); - sprintf_s(txt, "Polys: %d", game->GetPolyStats().npolys); - DrawMFDText(t++, txt, txt_rect, DT_LEFT); - txt_rect.y += 10; - } - - if (ship) { - DrawMFDText(t++, ship->Name(), txt_rect, DT_LEFT); - txt_rect.y += 10; - } - - if (lines <= 2) return; - - int hours = (Game::GameTime() / 3600000) ; - int minutes = (Game::GameTime() / 60000) % 60; - int seconds = (Game::GameTime() / 1000) % 60; - - if (ship) { - DWORD clock = ship->MissionClock(); - - hours = (clock / 3600000) ; - minutes = (clock / 60000) % 60; - seconds = (clock / 1000) % 60; - } - - if (Game::TimeCompression() > 1) - sprintf_s(txt, "%02d:%02d:%02d x%d", hours, minutes, seconds, Game::TimeCompression()); //-V576 - else - sprintf_s(txt, "%02d:%02d:%02d", hours, minutes, seconds); - - DrawMFDText(t++, txt, txt_rect, DT_LEFT); - txt_rect.y += 10; - - if (HUDView::IsArcade() || lines <= 3) return; - - DrawMFDText(t++, ship->GetRegion()->Name(), txt_rect, DT_LEFT); - txt_rect.y += 10; - - if (lines <= 4) return; - - if (ship) { - switch (ship->GetFlightPhase()) { - case Ship::DOCKED: DrawMFDText(t++, Game::GetText("MFD.phase.DOCKED").data(), txt_rect, DT_LEFT); break; - case Ship::ALERT: DrawMFDText(t++, Game::GetText("MFD.phase.ALERT").data(), txt_rect, DT_LEFT); break; - case Ship::LOCKED: DrawMFDText(t++, Game::GetText("MFD.phase.LOCKED").data(), txt_rect, DT_LEFT); break; - case Ship::LAUNCH: DrawMFDText(t++, Game::GetText("MFD.phase.LAUNCH").data(), txt_rect, DT_LEFT); break; - case Ship::TAKEOFF: DrawMFDText(t++, Game::GetText("MFD.phase.TAKEOFF").data(), txt_rect, DT_LEFT); break; - case Ship::ACTIVE: DrawMFDText(t++, Game::GetText("MFD.phase.ACTIVE").data(), txt_rect, DT_LEFT); break; - case Ship::APPROACH: DrawMFDText(t++, Game::GetText("MFD.phase.APPROACH").data(), txt_rect, DT_LEFT); break; - case Ship::RECOVERY: DrawMFDText(t++, Game::GetText("MFD.phase.RECOVERY").data(), txt_rect, DT_LEFT); break; - case Ship::DOCKING: DrawMFDText(t++, Game::GetText("MFD.phase.DOCKING").data(), txt_rect, DT_LEFT); break; - } - } -} - -void -MFD::DrawStatusMFD() -{ - if (lines < 10) lines++; - - Rect status_rect(rect.x, rect.y, rect.w, 12); - int row = 0; - char txt[32]; - - if (ship) { - if (status_rect.y > 320 && !ship->IsStarship()) - status_rect.y += 32; - - Drive* drive = ship->GetDrive(); - if (drive) { - DrawMFDText(row++, Game::GetText("MFD.status.THRUST").data(), status_rect, DT_LEFT); - DrawGauge(status_rect.x+70, status_rect.y, (int) ship->Throttle()); - status_rect.y += 10; - } - - if (lines <= 1) return; - - if (ship->Reactors().size() > 0) { - PowerSource* reactor = ship->Reactors()[0]; - if (reactor) { - DrawMFDText(row++, Game::GetText("MFD.status.FUEL").data(), status_rect, DT_LEFT); - DrawGauge(status_rect.x+70, status_rect.y, reactor->Charge()); - status_rect.y += 10; - } - } - - if (lines <= 2) return; - - QuantumDrive* quantum_drive = ship->GetQuantumDrive(); - if (quantum_drive) { - DrawMFDText(row++, Game::GetText("MFD.status.QUANTUM").data(), status_rect, DT_LEFT); - DrawGauge(status_rect.x+70, status_rect.y, (int) quantum_drive->Charge()); - status_rect.y += 10; - } - - if (lines <= 3) return; - - double hull = ship->Integrity() / ship->Design()->integrity * 100; - int hull_status = System::CRITICAL; - - if (hull > 66) - hull_status = System::NOMINAL; - else if (hull > 33) - hull_status = System::DEGRADED; - - DrawMFDText(row++, Game::GetText("MFD.status.HULL").data(), status_rect, DT_LEFT); - DrawGauge(status_rect.x+70, status_rect.y, (int) hull); - status_rect.y += 10; - - if (lines <= 4) return; - - Shield* shield = ship->GetShield(); - if (shield) { - DrawMFDText(row++, Game::GetText("MFD.status.SHIELD").data(), status_rect, DT_LEFT); - DrawGauge(status_rect.x+70, status_rect.y, ship->ShieldStrength()); - status_rect.y += 10; - } - - if (lines <= 5) return; - - Weapon* primary = ship->GetPrimary(); - if (primary) { - DrawMFDText(row++, Game::GetText("MFD.status.GUNS").data(), status_rect, DT_LEFT); - DrawGauge(status_rect.x+70, status_rect.y, primary->Charge()); - status_rect.y += 10; - } - - if (lines <= 6) return; - - if (HUDView::IsArcade()) { - for (int i = 0; i < ship->Weapons().size() && i < 4; i++) { - WeaponGroup* w = ship->Weapons().at(i); - - if (w->IsMissile()) { - char ammo[8]; - - if (ship->GetSecondaryGroup() == w) - sprintf_s(ammo, "%d *", w->Ammo()); - else - sprintf_s(ammo, "%d", w->Ammo()); - - DrawMFDText(row++, (const char*) w->GetDesign()->name, status_rect, DT_LEFT); - status_rect.x += 70; - DrawMFDText(row++, ammo, status_rect, DT_LEFT); - status_rect.x -= 70; - status_rect.y += 10; - } - } - - if (ship->GetDecoy()) { - char ammo[8]; - sprintf_s(ammo, "%d", ship->GetDecoy()->Ammo()); - DrawMFDText(row++, Game::GetText("MFD.status.DECOY").data(), status_rect, DT_LEFT); - status_rect.x += 70; - DrawMFDText(row++, ammo, status_rect, DT_LEFT); - status_rect.x -= 70; - status_rect.y += 10; - } - - if (NetGame::GetInstance()) { - char lives[8]; - sprintf_s(lives, "%d", ship->RespawnCount() + 1); - DrawMFDText(row++, Game::GetText("MFD.status.LIVES").data(), status_rect, DT_LEFT); - status_rect.x += 70; - DrawMFDText(row++, lives, status_rect, DT_LEFT); - status_rect.x -= 70; - status_rect.y += 10; - } - - return; - } - - Sensor* sensor = ship->GetSensor(); - if (sensor) { - if (ship->GetFlightPhase() != Ship::ACTIVE) { - DrawMFDText(row++, Game::GetText("MFD.status.SENSOR").data(), status_rect, DT_LEFT); - status_rect.x += 70; - DrawMFDText(row++, Game::GetText("MFD.status.OFFLINE").data(), status_rect, DT_LEFT); - status_rect.x -= 70; - status_rect.y += 10; - } - - else { - DrawMFDText(row++, Game::GetText("MFD.status.EMCON").data(), status_rect, DT_LEFT); - status_rect.x += 70; - - sprintf_s(txt, "%s %d", Game::GetText("MFD.status.MODE").data(), ship->GetEMCON()); - - if (!sensor->IsPowerOn() || sensor->GetEnergy() == 0) { - if (!Game::Paused() && (Game::RealTime()/1000) & 2) - strcpy_s(txt, Game::GetText("MFD.status.SENSOR-OFF").data()); - } - - DrawMFDText(row++, txt, status_rect, DT_LEFT); - status_rect.x -= 70; - status_rect.y += 10; - } - } - - if (lines <= 7) return; - - DrawMFDText(row++, Game::GetText("MFD.status.SYSTEMS").data(), status_rect, DT_LEFT); - status_rect.x += 70; - DrawMFDText(row++, ship->GetDirectorInfo(), status_rect, DT_LEFT); - - if (NetGame::GetInstance()) { - char lives[8]; - sprintf_s(lives, "%d", ship->RespawnCount() + 1); - status_rect.x -= 70; - status_rect.y += 10; - DrawMFDText(row++, Game::GetText("MFD.status.LIVES").data(), status_rect, DT_LEFT); - status_rect.x += 70; - DrawMFDText(row++, lives, status_rect, DT_LEFT); - } - } -} - -// +--------------------------------------------------------------------+ - -void -MFD::SetStatusColor(int status) -{ - Color status_color; - - switch (status) { - default: - case System::NOMINAL: status_color = txt_color; break; - case System::DEGRADED: status_color = Color(255,255, 0); break; - case System::CRITICAL: status_color = Color(255, 0, 0); break; - case System::DESTROYED: status_color = Color( 0, 0, 0); break; - } -} - -// +--------------------------------------------------------------------+ - -bool MFD::IsMouseLatched() const -{ - return mouse_in; -} - -// +--------------------------------------------------------------------+ - -void MFD::DrawMFDText(int index, const char* txt, Rect& txt_rect, int align, int status) -{ - if (index >= MFD::TXT_LAST) { - Print("MFD DrawMFDText() invalid mfd_text index %d '%s'\n", index, txt); - } - else { - HUDText& mt = mfd_text[index]; - Color mc = mt.color; - - switch (status) { - default: - case System::NOMINAL: mc = txt_color; break; - case System::DEGRADED: mc = Color(255,255, 0); break; - case System::CRITICAL: mc = Color(255, 0, 0); break; - case System::DESTROYED: mc = Color( 0, 0, 0); break; - } - - char txt_buf[256]; - int n = strlen(txt); - - if (n > 250) n = 250; - int i; - - for (i = 0; i < n; i++) { - if (islower(txt[i])) - txt_buf[i] = toupper(txt[i]); - else - txt_buf[i] = txt[i]; - } - - txt_buf[i] = 0; - - - if (cockpit_hud_texture) { - Rect hud_rect(txt_rect); - - hud_rect.x = txt_rect.x + this->index * 128 - this->rect.x; - hud_rect.y = txt_rect.y + 256 - this->rect.y; - - mt.font->SetColor(mc); - mt.font->DrawText(txt_buf, 0, hud_rect, align | DT_SINGLELINE, cockpit_hud_texture); - mt.rect = rect; - mt.hidden = false; - } - else { - if (txt_rect.Contains(Mouse::X(), Mouse::Y())) - mc = Color::White; - - mt.font->SetColor(mc); - mt.font->DrawText(txt_buf, 0, txt_rect, align | DT_SINGLELINE); - mt.rect = rect; - mt.hidden = false; - } - - } -} - -void MFD::HideMFDText(int index) -{ - if (index >= MFD::TXT_LAST) - Print("MFD HideMFDText() invalid mfd_text index %d\n", index); - else - mfd_text[index].hidden = true; -} - - - - +/* Starshatter OpenSource Distribution + Copyright (c) 1997-2004, Destroyer Studios LLC. + All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name "Destroyer Studios" nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + SUBSYSTEM: Stars.exe + FILE: MFD.cpp + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Class for all Multi Function Displays +*/ + +#include "MemDebug.h" +#include "MFD.h" +#include "HUDView.h" +#include "Ship.h" +#include "NavSystem.h" +#include "Power.h" +#include "Shield.h" +#include "Sensor.h" +#include "Contact.h" +#include "ShipDesign.h" +#include "Shot.h" +#include "Weapon.h" +#include "WeaponGroup.h" +#include "Sim.h" +#include "StarSystem.h" +#include "Starshatter.h" +#include "Drive.h" +#include "QuantumDrive.h" +#include "Power.h" +#include "Instruction.h" + +#include "NetGame.h" + +#include "CameraView.h" +#include "Color.h" +#include "Font.h" +#include "FontMgr.h" +#include "Window.h" +#include "Video.h" +#include "Screen.h" +#include "DataLoader.h" +#include "Scene.h" +#include "Graphic.h" +#include "Sprite.h" +#include "Keyboard.h" +#include "Mouse.h" +#include "Game.h" + +static Bitmap sensor_fov; +static Bitmap sensor_fwd; +static Bitmap sensor_hsd; +static Bitmap sensor_3d; + +static BYTE* sensor_fov_shade; +static BYTE* sensor_fwd_shade; +static BYTE* sensor_hsd_shade; +static BYTE* sensor_3d_shade; + +static Color hud_color = Color::Black; +static Color txt_color = Color::Black; + +// +--------------------------------------------------------------------+ + +MFD::MFD(Window* c, int n) +: window(c), rect(0,0,0,0), index(n), mode(MFD_MODE_OFF), sprite(0), +ship(0), hidden(true), camview(0), lines(0), mouse_latch(0), mouse_in(false), +cockpit_hud_texture(0) +{ + sprite = new(__FILE__,__LINE__) Sprite(&sensor_fov); + + sprite->SetBlendMode(2); + sprite->SetFilter(0); + sprite->Hide(); + + Font* font = FontMgr::Find("HUD"); + + for (int i = 0; i < TXT_LAST; i++) { + mfd_text[i].font = font; + mfd_text[i].color = Color::White; + mfd_text[i].hidden = true; + } +} + +MFD::~MFD() +{ + GRAPHIC_DESTROY(sprite); +} + +// +--------------------------------------------------------------------+ + +void +MFD::Initialize() +{ + static int initialized = 0; + if (initialized) return; + + HUDView::PrepareBitmap("sensor_fov.pcx", sensor_fov, sensor_fov_shade); + HUDView::PrepareBitmap("sensor_fwd.pcx", sensor_fwd, sensor_fwd_shade); + HUDView::PrepareBitmap("sensor_hsd.pcx", sensor_hsd, sensor_hsd_shade); + HUDView::PrepareBitmap("sensor_3d.pcx", sensor_3d, sensor_3d_shade); + + sensor_fov.SetType(Bitmap::BMP_TRANSLUCENT); + sensor_fwd.SetType(Bitmap::BMP_TRANSLUCENT); + sensor_hsd.SetType(Bitmap::BMP_TRANSLUCENT); + sensor_3d.SetType(Bitmap::BMP_TRANSLUCENT); + + initialized = 1; +} + +void +MFD::Close() +{ + sensor_fov.ClearImage(); + sensor_fwd.ClearImage(); + sensor_hsd.ClearImage(); + sensor_3d.ClearImage(); + + delete [] sensor_fov_shade; + delete [] sensor_fwd_shade; + delete [] sensor_hsd_shade; + delete [] sensor_3d_shade; +} + +// +--------------------------------------------------------------------+ + +void +MFD::UseCameraView(CameraView* v) +{ + if (v && !camview) { + camview = v; + } +} + +void +MFD::SetColor(Color c) +{ + HUDView* hud = HUDView::GetInstance(); + + if (hud) { + hud_color = hud->GetHUDColor(); + txt_color = hud->GetTextColor(); + } + else { + hud_color = c; + txt_color = c; + } + + HUDView::ColorizeBitmap(sensor_fov, sensor_fov_shade, c); + HUDView::ColorizeBitmap(sensor_fwd, sensor_fwd_shade, c); + HUDView::ColorizeBitmap(sensor_hsd, sensor_hsd_shade, c); + HUDView::ColorizeBitmap(sensor_3d, sensor_3d_shade, c); +} + +void +MFD::SetText3DColor(Color c) +{ + for (int i = 0; i < TXT_LAST; i++) + mfd_text[i].color = c; +} + +// +--------------------------------------------------------------------+ + +void +MFD::Show() +{ + switch (mode) { + case MFD_MODE_FOV: + case MFD_MODE_HSD: + case MFD_MODE_3D: + if (sprite) + sprite->Show(); + break; + } + + hidden = false; +} + +void +MFD::Hide() +{ + if (sprite) + sprite->Hide(); + + for (int i = 0; i < TXT_LAST; i++) + HideMFDText(i); + + hidden = true; +} + +// +--------------------------------------------------------------------+ + +void +MFD::SetRect(const Rect& r) +{ + rect = r; + + if (sprite) + sprite->MoveTo(Point(rect.x + sprite->Width()/2, + rect.y + sprite->Height()/2, + 1)); +} + +// +--------------------------------------------------------------------+ + +void +MFD::SetMode(int m) +{ + if (m < MFD_MODE_OFF || m > MFD_MODE_3D) + mode = MFD_MODE_OFF; + else + mode = m; + + sprite->Hide(); + + for (int i = 0; i < TXT_LAST; i++) + HideMFDText(i); + + switch (mode) { + case MFD_MODE_GAME: + case MFD_MODE_SHIP: + lines = 0; + break; + + case MFD_MODE_FOV: + sprite->SetAnimation(&sensor_fov); + sprite->Show(); + sprite->Reshape(sensor_fov.Width()-8, 16); + break; + case MFD_MODE_HSD: + sprite->SetAnimation(&sensor_hsd); + sprite->Show(); + sprite->Reshape(sensor_hsd.Width()-8, 16); + break; + case MFD_MODE_3D: + sprite->SetAnimation(&sensor_3d); + sprite->Show(); + sprite->Reshape(sensor_3d.Width()-8, 16); + break; + } +} + +// +--------------------------------------------------------------------+ + +void +MFD::Draw() +{ + mouse_in = false; + + if (Mouse::LButton() == 0) + mouse_latch = 0; + + if (rect.Contains(Mouse::X(), Mouse::Y())) + mouse_in = true; + + // click to turn on MFD when off: + if (mode < MFD_MODE_FOV && Mouse::LButton() && !mouse_latch) { + mouse_latch = 1; + if (mouse_in) { + HUDView* hud = HUDView::GetInstance(); + if (hud) + hud->CycleMFDMode(index); + } + } + + for (int i = 0; i < TXT_LAST; i++) + HideMFDText(i); + + if (hidden || mode < MFD_MODE_FOV) { + if (cockpit_hud_texture) { + int x1 = index*128; + int y1 = 256; + int x2 = x1 + 128; + int y2 = y1 + 128; + + cockpit_hud_texture->FillRect(x1, y1, x2, y2, Color::Black); + } + + if (hidden) + return; + } + + if (sprite && !sprite->Hidden()) { + if (cockpit_hud_texture) { + int x1 = index*128; + int y1 = 256; + int w = sprite->Width(); + int h = sprite->Height(); + + cockpit_hud_texture->BitBlt(x1, y1, *sprite->Frame(), 0,0,w,h); + } + else { + int cx = rect.x + rect.w/2; + int cy = rect.y + rect.h/2; + int w2 = sprite->Width()/2; + int h2 = sprite->Height()/2; + + window->DrawBitmap(cx-w2, cy-h2, cx+w2, cy+h2, sprite->Frame(), Video::BLEND_ALPHA); + } + } + + switch (mode) { + default: + case MFD_MODE_OFF: break; + case MFD_MODE_GAME: DrawGameMFD(); break; + case MFD_MODE_SHIP: DrawStatusMFD(); break; + + // sensor sub-modes: + case MFD_MODE_FOV: DrawSensorMFD(); break; + case MFD_MODE_HSD: DrawHSD(); break; + case MFD_MODE_3D: Draw3D(); break; + } +} + +// +--------------------------------------------------------------------+ + +void +MFD::DrawSensorLabels(const char* mfd_mode) +{ + Sensor* sensor = ship->GetSensor(); + char mode_buf[8] = " "; + int scan_r = rect.w; + int scan_x = rect.x; + int scan_y = rect.y; + + switch (sensor->GetMode()) { + case Sensor::PAS: strcpy_s(mode_buf, Game::GetText("MFD.mode.passive").data()); break; + case Sensor::STD: strcpy_s(mode_buf, Game::GetText("MFD.mode.standard").data()); break; + case Sensor::ACM: strcpy_s(mode_buf, Game::GetText("MFD.mode.auto-combat").data()); break; + case Sensor::GM: strcpy_s(mode_buf, Game::GetText("MFD.mode.ground").data()); break; + case Sensor::PST: strcpy_s(mode_buf, Game::GetText("MFD.mode.passive").data()); break; + case Sensor::CST: strcpy_s(mode_buf, Game::GetText("MFD.mode.combined").data()); break; + default: break; + } + + Rect mode_rect(scan_x+2, scan_y+2, 40, 12); + DrawMFDText(0, mode_buf, mode_rect, DT_LEFT); + + char range_txt[12]; + double beam_range = sensor->GetBeamRange() + 1; + if (beam_range >= 1e6) + sprintf_s(range_txt, "-%dM+", (int) (beam_range / 1e6)); + else + sprintf_s(range_txt, "-%3d+", (int) (beam_range / 1e3)); + + Rect range_rect(scan_x+2, scan_y+scan_r-12, 40, 12); + DrawMFDText(1, range_txt, range_rect, DT_LEFT); + + Rect disp_rect(scan_x+scan_r-41, scan_y+2, 40, 12); + DrawMFDText(2, mfd_mode, disp_rect, DT_RIGHT); + + Rect probe_rect(scan_x+scan_r-41, scan_y+scan_r-12, 40, 12); + + if (ship->GetProbeLauncher()) { + char probes[32]; + sprintf_s(probes, "%s %02d", Game::GetText("MFD.probe").data(), ship->GetProbeLauncher()->Ammo()); + DrawMFDText(3, probes, probe_rect, DT_RIGHT); + } + else { + HideMFDText(3); + } + + if (Mouse::LButton() && !mouse_latch) { + mouse_latch = 1; + + if (mode_rect.Contains(Mouse::X(), Mouse::Y())) { + if (sensor->GetMode() < Sensor::PST) { + int sensor_mode = sensor->GetMode() + 1; + if (sensor_mode > Sensor::GM) + sensor_mode = Sensor::PAS; + + sensor->SetMode((Sensor::Mode) sensor_mode); + } + } + + else if (range_rect.Contains(Mouse::X(), Mouse::Y())) { + if (Mouse::X() > range_rect.x+range_rect.w/2) + sensor->IncreaseRange(); + else + sensor->DecreaseRange(); + } + + else if (disp_rect.Contains(Mouse::X(), Mouse::Y())) { + HUDView* hud = HUDView::GetInstance(); + if (hud) + hud->CycleMFDMode(index); + } + + else if (probe_rect.Contains(Mouse::X(), Mouse::Y())) { + ship->LaunchProbe(); + } + } +} + +// +--------------------------------------------------------------------+ + +// AZIMUTH-ELEVATION ANGULAR SCANNER + +void +MFD::DrawSensorMFD() +{ + int scan_r = rect.w; + int scan_x = cockpit_hud_texture ? (index*128) : rect.x; + int scan_y = cockpit_hud_texture ? 256 : rect.y; + int r = scan_r / 2; + + double xctr = (scan_r / 2.0) - 0.5; + double yctr = (scan_r / 2.0) + 0.5; + + Sensor* sensor = ship->GetSensor(); + if (!sensor) { + DrawMFDText(0, Game::GetText("MFD.inactive").data(), rect, DT_CENTER); + return; + } + + int w = sprite->Width(); + int h = sprite->Height(); + + if (w < sprite->Frame()->Width()) + w += 2; + + if (h < sprite->Frame()->Height()) + h += 16; + + sprite->Reshape(w, h); + sprite->Show(); + + if (h < sprite->Frame()->Height()) + return; + + double sweep_scale = r / (PI/2); + + if (sensor->GetBeamLimit() > 90*DEGREES) + sweep_scale = (double) r / (90*DEGREES); + + int az = (int) (sensor->GetBeamLimit() * sweep_scale); + int el = az; + int xc = (int) (scan_x + xctr); + int yc = (int) (scan_y + yctr); + + if (mode == MFD_MODE_FOV) { + if (sensor->GetMode() < Sensor::GM) { + if (cockpit_hud_texture) + cockpit_hud_texture->DrawEllipse(xc-az, yc-el, xc+az, yc+el, hud_color); + else + window->DrawEllipse(xc-az, yc-el, xc+az, yc+el, hud_color); + } + } + else { + char az_txt[8]; + sprintf_s(az_txt, "%d", (int) (sensor->GetBeamLimit() / DEGREES)); + + Rect az_rect(scan_x+2, scan_y+scan_r-12, 32, 12); + DrawMFDText(1, az_txt, az_rect, DT_LEFT); + + az_rect.x = scan_x + (scan_r/2) - (az_rect.w/2); + DrawMFDText(2, "0", az_rect, DT_CENTER); + + az_rect.x = scan_x + scan_r - az_rect.w - 2; + DrawMFDText(3, az_txt, az_rect, DT_RIGHT); + } + + // draw next nav point: + Instruction* navpt = ship->GetNextNavPoint(); + if (navpt && navpt->Region() == ship->GetRegion()) { + const Camera* cam = &ship->Cam(); + + // translate: + Point pt = navpt->Location().OtherHand() - ship->Location(); + + // rotate: + double tx = pt * cam->vrt(); + double ty = pt * cam->vup(); + double tz = pt * cam->vpn(); + + if (tz > 1.0) { + // convert to spherical coords: + double rng = pt.length(); + double az = asin(fabs(tx) / rng); + double el = asin(fabs(ty) / rng); + + if (tx < 0) az = -az; + if (ty < 0) el = -el; + + if (fabs(az) < 90*DEGREES) { + az *= sweep_scale; + el *= sweep_scale; + + int x = (int) (r + az); + int y = (int) (r - el); + + // clip again: + if (x > 0 && x < scan_r && + y > 0 && y < scan_r) { + + // draw: + int xc = scan_x + x; + int yc = scan_y + y; + + if (cockpit_hud_texture) { + cockpit_hud_texture->DrawLine(xc-2, yc-2, xc+2, yc+2, Color::White); + cockpit_hud_texture->DrawLine(xc-2, yc+2, xc+2, yc-2, Color::White); + } + else { + window->DrawLine(xc-2, yc-2, xc+2, yc+2, Color::White); + window->DrawLine(xc-2, yc+2, xc+2, yc-2, Color::White); + } + } + } + } + } + + int num_contacts = ship->NumContacts(); + ListIter iter = ship->ContactList(); + + while (++iter) { + Contact* contact = iter.value(); + Ship* c_ship = contact->GetShip(); + double az, el, rng; + bool aft = false; + + if (c_ship == ship) continue; + + contact->GetBearing(ship, az, el, rng); + + // clip (is in-front): + if (fabs(az) < 90*DEGREES) { + az *= sweep_scale; + el *= sweep_scale; + } + + // rear anulus: + else { + double len = sqrt(az*az + el*el); + + if (len > 1e-6) { + az = r * az/len; + el = r * el/len; + } + else { + az = -r; + el = 0; + } + + aft = true; + } + + int x = (int) (r + az); + int y = (int) (r - el); + + // clip again: + if (x < 0 || x > scan_r) continue; + if (y < 0 || y > scan_r) continue; + + // draw: + Color mark = HUDView::MarkerColor(contact); + + if (aft) + mark = mark * 0.75; + + int xc = scan_x + x; + int yc = scan_y + y; + int size = 1; + + if (c_ship && c_ship == ship->GetTarget()) + size = 2; + + if (cockpit_hud_texture) + cockpit_hud_texture->FillRect(xc-size, yc-size, xc+size, yc+size, mark); + else + window->FillRect(xc-size, yc-size, xc+size, yc+size, mark); + + if (contact->Threat(ship)) { + if (c_ship) { + if (cockpit_hud_texture) + cockpit_hud_texture->DrawEllipse(xc-4, yc-4, xc+3, yc+3, mark); + else + window->DrawEllipse(xc-4, yc-4, xc+3, yc+3, mark); + } + else { + if (cockpit_hud_texture) { + cockpit_hud_texture->DrawLine(xc, yc-5, xc+5, yc, mark); + cockpit_hud_texture->DrawLine(xc+5, yc, xc, yc+5, mark); + cockpit_hud_texture->DrawLine(xc, yc+5, xc-5, yc, mark); + cockpit_hud_texture->DrawLine(xc-5, yc, xc, yc-5, mark); + } + else { + window->DrawLine(xc, yc-5, xc+5, yc, mark); + window->DrawLine(xc+5, yc, xc, yc+5, mark); + window->DrawLine(xc, yc+5, xc-5, yc, mark); + window->DrawLine(xc-5, yc, xc, yc-5, mark); + } + } + } + } + + DrawSensorLabels(Game::GetText("MFD.mode.field-of-view").data()); +} + +// +--------------------------------------------------------------------+ + +// HORIZONTAL SITUATION DISPLAY + +void +MFD::DrawHSD() +{ + int scan_r = rect.w; + int scan_x = cockpit_hud_texture ? (index*128) : rect.x; + int scan_y = cockpit_hud_texture ? 256 : rect.y; + int r = scan_r / 2 - 4; + + double xctr = (scan_r / 2.0) - 0.5; + double yctr = (scan_r / 2.0) + 0.5; + + int xc = (int) xctr + scan_x; + int yc = (int) yctr + scan_y; + + Sensor* sensor = ship->GetSensor(); + if (!sensor) { + DrawMFDText(0, Game::GetText("MFD.inactive").data(), rect, DT_CENTER); + return; + } + + int w = sprite->Width(); + int h = sprite->Height(); + + if (w < sprite->Frame()->Width()) + w += 2; + + if (h < sprite->Frame()->Height()) + h += 16; + + sprite->Reshape(w, h); + sprite->Show(); + + if (h < sprite->Frame()->Height()) + return; + + if (sensor->GetMode() < Sensor::PST) { + double s = sin(sensor->GetBeamLimit()); + double c = cos(sensor->GetBeamLimit()); + + int x0 = (int) (0.1*r*s); + int y0 = (int) (0.1*r*c); + int x1 = (int) (1.0*r*s); + int y1 = (int) (1.0*r*c); + + if (cockpit_hud_texture) { + cockpit_hud_texture->DrawLine(xc-x0, yc-y0, xc-x1, yc-y1, hud_color); + cockpit_hud_texture->DrawLine(xc+x0, yc-y0, xc+x1, yc-y1, hud_color); + } + else { + window->DrawLine(xc-x0, yc-y0, xc-x1, yc-y1, hud_color); + window->DrawLine(xc+x0, yc-y0, xc+x1, yc-y1, hud_color); + } + } + + double rscale = (double) r/(sensor->GetBeamRange()); + + Camera hsd_cam = ship->Cam(); + Point look = ship->Location() + ship->Heading() * 1000; + look.y = ship->Location().y; + + hsd_cam.LookAt(look); + + // draw tick marks on range rings: + for (int dir = 0; dir < 4; dir++) { + Point tick; + + switch (dir) { + case 0: tick = Point( 0, 0, 1000); break; + case 1: tick = Point( 1000, 0, 0); break; + case 2: tick = Point( 0, 0, -1000); break; + case 3: tick = Point(-1000, 0, 0); break; + } + + double tx = tick * hsd_cam.vrt(); + double tz = tick * hsd_cam.vpn(); + double az = asin(fabs(tx) / 1000); + + if (tx < 0) az = -az; + + if (tz < 0) + if (az < 0) az = -PI - az; + else az = PI - az; + + for (double range = 0.3; range < 1; range += 0.3) { + int x0 = (int) (sin(az) * r * range); + int y0 = (int) (cos(az) * r * range); + int x1 = (int) (sin(az) * r * (range + 0.1)); + int y1 = (int) (cos(az) * r * (range + 0.1)); + + if (cockpit_hud_texture) { + cockpit_hud_texture->DrawLine(xc+x0, yc-y0, xc+x1, yc-y1, hud_color); + } + else { + window->DrawLine(xc+x0, yc-y0, xc+x1, yc-y1, hud_color); + } + } + } + + // draw next nav point: + Instruction* navpt = ship->GetNextNavPoint(); + if (navpt && navpt->Region() == ship->GetRegion()) { + const Camera* cam = &hsd_cam; + + // translate: + Point pt = navpt->Location().OtherHand() - ship->Location(); + + // rotate: + double tx = pt * cam->vrt(); + double ty = pt * cam->vup(); + double tz = pt * cam->vpn(); + + // convert to spherical coords: + double rng = pt.length(); + double az = asin(fabs(tx) / rng); + + if (rng > sensor->GetBeamRange()) + rng = sensor->GetBeamRange(); + + if (tx < 0) + az = -az; + + if (tz < 0) + if (az < 0) + az = -PI - az; + else + az = PI - az; + + // draw: + int x = (int) (xc + sin(az) * rng * rscale); + int y = (int) (yc - cos(az) * rng * rscale); + + if (cockpit_hud_texture) { + cockpit_hud_texture->DrawLine(x-2, y-2, x+2, y+2, Color::White); + cockpit_hud_texture->DrawLine(x-2, y+2, x+2, y-2, Color::White); + } + else { + window->DrawLine(x-2, y-2, x+2, y+2, Color::White); + window->DrawLine(x-2, y+2, x+2, y-2, Color::White); + } + } + + // draw contact markers: + double limit = sensor->GetBeamRange(); + ListIter contact = ship->ContactList(); + + while (++contact) { + Ship* c_ship = contact->GetShip(); + if (c_ship == ship) continue; + + // translate: + Point targ_pt = contact->Location() - hsd_cam.Pos(); + + // rotate: + double tx = targ_pt * hsd_cam.vrt(); + double rg = contact->Range(ship, limit); + double true_range = targ_pt.length(); + double az = asin(fabs(tx) / true_range); + + // clip: + if (rg > limit || rg <= 0) + continue; + + if (tx < 0) + az = -az; + + if (!contact->InFront(ship)) + if (az < 0) + az = -PI - az; + else + az = PI - az; + + // draw: + int x = (int) (xc + sin(az) * rg * rscale); + int y = (int) (yc - cos(az) * rg * rscale); + int size = 2; + + // clip again: + if (x < scan_x || y < scan_y) + continue; + + if (c_ship && c_ship == ship->GetTarget()) + size = 3; + + Color mark = HUDView::MarkerColor(contact.value()); + if (cockpit_hud_texture) { + cockpit_hud_texture->FillRect(x-size, y-size, x+size, y+size, mark); + } + else { + window->FillRect(x-size, y-size, x+size, y+size, mark); + } + + if (contact->Threat(ship)) { + if (c_ship) { + if (cockpit_hud_texture) { + cockpit_hud_texture->DrawEllipse(x-4, y-4, x+3, y+3, mark); + } + else { + window->DrawEllipse(x-4, y-4, x+3, y+3, mark); + } + } + else { + if (cockpit_hud_texture) { + cockpit_hud_texture->DrawLine(x, y-5, x+5, y, mark); + cockpit_hud_texture->DrawLine(x+5, y, x, y+5, mark); + cockpit_hud_texture->DrawLine(x, y+5, x-5, y, mark); + cockpit_hud_texture->DrawLine(x-5, y, x, y-5, mark); + } + else { + window->DrawLine(x, y-5, x+5, y, mark); + window->DrawLine(x+5, y, x, y+5, mark); + window->DrawLine(x, y+5, x-5, y, mark); + window->DrawLine(x-5, y, x, y-5, mark); + } + } + } + } + + DrawSensorLabels(Game::GetText("MFD.mode.horizontal").data()); +} + +// +--------------------------------------------------------------------+ + +// ELITE-STYLE 3D RADAR + +void +MFD::Draw3D() +{ + int scan_r = rect.w; + int scan_x = cockpit_hud_texture ? (index*128) : rect.x; + int scan_y = cockpit_hud_texture ? 256 : rect.y; + int r = scan_r / 2 - 4; + + double xctr = (scan_r / 2.0) - 0.5; + double yctr = (scan_r / 2.0) + 0.5; + + int xc = (int) xctr + scan_x; + int yc = (int) yctr + scan_y; + + Sensor* sensor = ship->GetSensor(); + if (!sensor) { + DrawMFDText(0, Game::GetText("MFD.inactive").data(), rect, DT_CENTER); + return; + } + + int w = sprite->Width(); + int h = sprite->Height(); + + if (w < sprite->Frame()->Width()) + w += 2; + + if (h < sprite->Frame()->Height()) + h += 16; + + sprite->Reshape(w, h); + sprite->Show(); + + if (h < sprite->Frame()->Height()) + return; + + double rscale = (double) r/(sensor->GetBeamRange()); + + Camera hsd_cam = ship->Cam(); + + if (ship->IsStarship()) { + Point look = ship->Location() + ship->Heading() * 1000; + look.y = ship->Location().y; + + hsd_cam.LookAt(look); + } + + + // draw next nav point: + Instruction* navpt = ship->GetNextNavPoint(); + if (navpt && navpt->Region() == ship->GetRegion()) { + const Camera* cam = &hsd_cam; + + // translate: + Point pt = navpt->Location().OtherHand() - ship->Location(); + + // rotate: + double tx = pt * cam->vrt(); + double ty = pt * cam->vup(); + double tz = pt * cam->vpn(); + + // convert to cylindrical coords: + double rng = pt.length(); + double az = asin(fabs(tx) / rng); + + if (rng > sensor->GetBeamRange()) + rng = sensor->GetBeamRange(); + + if (tx < 0) + az = -az; + + if (tz < 0) { + if (az < 0) + az = -PI - az; + else + az = PI - az; + } + + // accentuate vertical: + if (ty > 10) + ty = log10(ty-9) * r/8; + + else if (ty < -10) + ty = -log10(9-ty) * r/8; + + else + ty = 0; + + // draw: + int x = (int) (sin(az) * rng * rscale); + int y = (int) (cos(az) * rng * rscale/2); + int z = (int) (ty); + + int x0 = xc+x; + int y0 = yc-y-z; + + if (cockpit_hud_texture) { + cockpit_hud_texture->DrawLine(x0-2, y0-2, x0+2, y0+2, Color::White); + cockpit_hud_texture->DrawLine(x0-2, y0+2, x0+2, y0-2, Color::White); + } + else { + window->DrawLine(x0-2, y0-2, x0+2, y0+2, Color::White); + window->DrawLine(x0-2, y0+2, x0+2, y0-2, Color::White); + } + + if (cockpit_hud_texture) { + if (z > 0) + cockpit_hud_texture->DrawLine(x0, y0+1, x0, y0+z, Color::White); + else if (z < 0) + cockpit_hud_texture->DrawLine(x0, y0+z, x0, y0-1, Color::White); + } + else { + if (z > 0) + window->DrawLine(x0, y0+1, x0, y0+z, Color::White); + else if (z < 0) + window->DrawLine(x0, y0+z, x0, y0-1, Color::White); + } + } + + + // draw contact markers: + double limit = sensor->GetBeamRange(); + ListIter contact = ship->ContactList(); + + while (++contact) { + Ship* c_ship = contact->GetShip(); + if (c_ship == ship) continue; + + // translate: + Point targ_pt = contact->Location() - hsd_cam.Pos(); + + // rotate: + double tx = targ_pt * hsd_cam.vrt(); + double ty = targ_pt * hsd_cam.vup(); + double rg = contact->Range(ship, limit); + double true_range = targ_pt.length(); + double az = asin(fabs(tx) / true_range); + + // clip: + if (rg > limit || rg <= 0) + continue; + + if (tx < 0) + az = -az; + + if (!contact->InFront(ship)) + if (az < 0) + az = -PI - az; + else + az = PI - az; + + // accentuate vertical: + ty *= 4; + + // draw: + int x = (int) (sin(az) * rg * rscale); + int y = (int) (cos(az) * rg * rscale/2); + int z = (int) (ty * rscale/2); + int size = 1; + + int x0 = xc+x; + int y0 = yc-y-z; + + if (c_ship && c_ship == ship->GetTarget()) + size = 2; + + Color mark = HUDView::MarkerColor(contact.value()); + + if (cockpit_hud_texture) { + cockpit_hud_texture->FillRect(x0-size, y0-size, x0+size, y0+size, mark); + + if (contact->Threat(ship)) { + if (c_ship) { + cockpit_hud_texture->DrawEllipse(x0-4, y0-4, x0+3, y0+3, mark); + } + else { + cockpit_hud_texture->DrawLine(x0, y0-5, x0+5, y0, mark); + cockpit_hud_texture->DrawLine(x0+5, y0, x0, y0+5, mark); + cockpit_hud_texture->DrawLine(x0, y0+5, x0-5, y0, mark); + cockpit_hud_texture->DrawLine(x0-5, y0, x0, y0-5, mark); + } + } + + if (z > 0) + cockpit_hud_texture->FillRect(x0-1, y0+size, x0, y0+z, mark); + else if (z < 0) + cockpit_hud_texture->FillRect(x0-1, y0+z, x0, y0-size, mark); + } + else { + window->FillRect(x0-size, y0-size, x0+size, y0+size, mark); + + if (contact->Threat(ship)) { + if (c_ship) { + window->DrawEllipse(x0-4, y0-4, x0+3, y0+3, mark); + } + else { + window->DrawLine(x0, y0-5, x0+5, y0, mark); + window->DrawLine(x0+5, y0, x0, y0+5, mark); + window->DrawLine(x0, y0+5, x0-5, y0, mark); + window->DrawLine(x0-5, y0, x0, y0-5, mark); + } + } + + if (z > 0) + window->FillRect(x0-1, y0+size, x0, y0+z, mark); + else if (z < 0) + window->FillRect(x0-1, y0+z, x0, y0-size, mark); + } + } + + DrawSensorLabels(Game::GetText("MFD.mode.3D").data()); +} + +// +--------------------------------------------------------------------+ + +// GROUND MAP + +void +MFD::DrawMap() +{ + DrawMFDText(0, Game::GetText("MFD.mode.ground").data(), Rect(rect.x, rect.y, rect.w, 12), DT_CENTER); +} + +// +--------------------------------------------------------------------+ + +void +MFD::DrawGauge(int x, int y, int percent) +{ + if (cockpit_hud_texture) { + x += this->index * 128 - this->rect.x; + y += 256 - this->rect.y; + cockpit_hud_texture->DrawRect(x, y, x+53, y+8, Color::DarkGray); + } + else { + window->DrawRect(x, y, x+53, y+8, Color::DarkGray); + } + + if (percent < 3) return; + if (percent > 100) percent = 100; + + percent /= 2; + + if (cockpit_hud_texture) + cockpit_hud_texture->FillRect(x+2, y+2, x+2+percent, y+7, Color::Gray); + else + window->FillRect(x+2, y+2, x+2+percent, y+7, Color::Gray); +} + +void +MFD::DrawGameMFD() +{ + if (lines < 10) lines++; + + char txt[64]; + Rect txt_rect(rect.x, rect.y, rect.w, 12); + + int t = 0; + + if (!HUDView::IsArcade() && HUDView::ShowFPS()) { + sprintf_s(txt, "FPS: %6.2f", Game::FrameRate()); + DrawMFDText(t++, txt, txt_rect, DT_LEFT); + txt_rect.y += 10; + + if (lines <= 1) return; + + Starshatter* game = Starshatter::GetInstance(); + sprintf_s(txt, "Polys: %d", game->GetPolyStats().npolys); + DrawMFDText(t++, txt, txt_rect, DT_LEFT); + txt_rect.y += 10; + } + + if (ship) { + DrawMFDText(t++, ship->Name(), txt_rect, DT_LEFT); + txt_rect.y += 10; + } + + if (lines <= 2) return; + + int hours = (Game::GameTime() / 3600000) ; + int minutes = (Game::GameTime() / 60000) % 60; + int seconds = (Game::GameTime() / 1000) % 60; + + if (ship) { + DWORD clock = ship->MissionClock(); + + hours = (clock / 3600000) ; + minutes = (clock / 60000) % 60; + seconds = (clock / 1000) % 60; + } + + if (Game::TimeCompression() > 1) + sprintf_s(txt, "%02d:%02d:%02d x%d", hours, minutes, seconds, Game::TimeCompression()); //-V576 + else + sprintf_s(txt, "%02d:%02d:%02d", hours, minutes, seconds); + + DrawMFDText(t++, txt, txt_rect, DT_LEFT); + txt_rect.y += 10; + + if (HUDView::IsArcade() || lines <= 3) return; + + DrawMFDText(t++, ship->GetRegion()->Name(), txt_rect, DT_LEFT); + txt_rect.y += 10; + + if (lines <= 4) return; + + if (ship) { + switch (ship->GetFlightPhase()) { + case Ship::DOCKED: DrawMFDText(t++, Game::GetText("MFD.phase.DOCKED").data(), txt_rect, DT_LEFT); break; + case Ship::ALERT: DrawMFDText(t++, Game::GetText("MFD.phase.ALERT").data(), txt_rect, DT_LEFT); break; + case Ship::LOCKED: DrawMFDText(t++, Game::GetText("MFD.phase.LOCKED").data(), txt_rect, DT_LEFT); break; + case Ship::LAUNCH: DrawMFDText(t++, Game::GetText("MFD.phase.LAUNCH").data(), txt_rect, DT_LEFT); break; + case Ship::TAKEOFF: DrawMFDText(t++, Game::GetText("MFD.phase.TAKEOFF").data(), txt_rect, DT_LEFT); break; + case Ship::ACTIVE: DrawMFDText(t++, Game::GetText("MFD.phase.ACTIVE").data(), txt_rect, DT_LEFT); break; + case Ship::APPROACH: DrawMFDText(t++, Game::GetText("MFD.phase.APPROACH").data(), txt_rect, DT_LEFT); break; + case Ship::RECOVERY: DrawMFDText(t++, Game::GetText("MFD.phase.RECOVERY").data(), txt_rect, DT_LEFT); break; + case Ship::DOCKING: DrawMFDText(t++, Game::GetText("MFD.phase.DOCKING").data(), txt_rect, DT_LEFT); break; + } + } +} + +void +MFD::DrawStatusMFD() +{ + if (lines < 10) lines++; + + Rect status_rect(rect.x, rect.y, rect.w, 12); + int row = 0; + char txt[32]; + + if (ship) { + if (status_rect.y > 320 && !ship->IsStarship()) + status_rect.y += 32; + + Drive* drive = ship->GetDrive(); + if (drive) { + DrawMFDText(row++, Game::GetText("MFD.status.THRUST").data(), status_rect, DT_LEFT); + DrawGauge(status_rect.x+70, status_rect.y, (int) ship->Throttle()); + status_rect.y += 10; + } + + if (lines <= 1) return; + + if (ship->Reactors().size() > 0) { + PowerSource* reactor = ship->Reactors()[0]; + if (reactor) { + DrawMFDText(row++, Game::GetText("MFD.status.FUEL").data(), status_rect, DT_LEFT); + DrawGauge(status_rect.x+70, status_rect.y, reactor->Charge()); + status_rect.y += 10; + } + } + + if (lines <= 2) return; + + QuantumDrive* quantum_drive = ship->GetQuantumDrive(); + if (quantum_drive) { + DrawMFDText(row++, Game::GetText("MFD.status.QUANTUM").data(), status_rect, DT_LEFT); + DrawGauge(status_rect.x+70, status_rect.y, (int) quantum_drive->Charge()); + status_rect.y += 10; + } + + if (lines <= 3) return; + + double hull = ship->Integrity() / ship->Design()->integrity * 100; + int hull_status = System::CRITICAL; + + if (hull > 66) + hull_status = System::NOMINAL; + else if (hull > 33) + hull_status = System::DEGRADED; + + DrawMFDText(row++, Game::GetText("MFD.status.HULL").data(), status_rect, DT_LEFT); + DrawGauge(status_rect.x+70, status_rect.y, (int) hull); + status_rect.y += 10; + + if (lines <= 4) return; + + Shield* shield = ship->GetShield(); + if (shield) { + DrawMFDText(row++, Game::GetText("MFD.status.SHIELD").data(), status_rect, DT_LEFT); + DrawGauge(status_rect.x+70, status_rect.y, ship->ShieldStrength()); + status_rect.y += 10; + } + + if (lines <= 5) return; + + Weapon* primary = ship->GetPrimary(); + if (primary) { + DrawMFDText(row++, Game::GetText("MFD.status.GUNS").data(), status_rect, DT_LEFT); + DrawGauge(status_rect.x+70, status_rect.y, primary->Charge()); + status_rect.y += 10; + } + + if (lines <= 6) return; + + if (HUDView::IsArcade()) { + for (int i = 0; i < ship->Weapons().size() && i < 4; i++) { + WeaponGroup* w = ship->Weapons().at(i); + + if (w->IsMissile()) { + char ammo[8]; + + if (ship->GetSecondaryGroup() == w) + sprintf_s(ammo, "%d *", w->Ammo()); + else + sprintf_s(ammo, "%d", w->Ammo()); + + DrawMFDText(row++, (const char*) w->GetDesign()->name, status_rect, DT_LEFT); + status_rect.x += 70; + DrawMFDText(row++, ammo, status_rect, DT_LEFT); + status_rect.x -= 70; + status_rect.y += 10; + } + } + + if (ship->GetDecoy()) { + char ammo[8]; + sprintf_s(ammo, "%d", ship->GetDecoy()->Ammo()); + DrawMFDText(row++, Game::GetText("MFD.status.DECOY").data(), status_rect, DT_LEFT); + status_rect.x += 70; + DrawMFDText(row++, ammo, status_rect, DT_LEFT); + status_rect.x -= 70; + status_rect.y += 10; + } + + if (NetGame::GetInstance()) { + char lives[8]; + sprintf_s(lives, "%d", ship->RespawnCount() + 1); + DrawMFDText(row++, Game::GetText("MFD.status.LIVES").data(), status_rect, DT_LEFT); + status_rect.x += 70; + DrawMFDText(row++, lives, status_rect, DT_LEFT); + status_rect.x -= 70; + status_rect.y += 10; + } + + return; + } + + Sensor* sensor = ship->GetSensor(); + if (sensor) { + if (ship->GetFlightPhase() != Ship::ACTIVE) { + DrawMFDText(row++, Game::GetText("MFD.status.SENSOR").data(), status_rect, DT_LEFT); + status_rect.x += 70; + DrawMFDText(row++, Game::GetText("MFD.status.OFFLINE").data(), status_rect, DT_LEFT); + status_rect.x -= 70; + status_rect.y += 10; + } + + else { + DrawMFDText(row++, Game::GetText("MFD.status.EMCON").data(), status_rect, DT_LEFT); + status_rect.x += 70; + + sprintf_s(txt, "%s %d", Game::GetText("MFD.status.MODE").data(), ship->GetEMCON()); + + if (!sensor->IsPowerOn() || sensor->GetEnergy() == 0) { + if (!Game::Paused() && (Game::RealTime()/1000) & 2) + strcpy_s(txt, Game::GetText("MFD.status.SENSOR-OFF").data()); + } + + DrawMFDText(row++, txt, status_rect, DT_LEFT); + status_rect.x -= 70; + status_rect.y += 10; + } + } + + if (lines <= 7) return; + + DrawMFDText(row++, Game::GetText("MFD.status.SYSTEMS").data(), status_rect, DT_LEFT); + status_rect.x += 70; + DrawMFDText(row++, ship->GetDirectorInfo(), status_rect, DT_LEFT); + + if (NetGame::GetInstance()) { + char lives[8]; + sprintf_s(lives, "%d", ship->RespawnCount() + 1); + status_rect.x -= 70; + status_rect.y += 10; + DrawMFDText(row++, Game::GetText("MFD.status.LIVES").data(), status_rect, DT_LEFT); + status_rect.x += 70; + DrawMFDText(row++, lives, status_rect, DT_LEFT); + } + } +} + +// +--------------------------------------------------------------------+ + +void +MFD::SetStatusColor(int status) +{ + Color status_color; + + switch (status) { + default: + case System::NOMINAL: status_color = txt_color; break; + case System::DEGRADED: status_color = Color(255,255, 0); break; + case System::CRITICAL: status_color = Color(255, 0, 0); break; + case System::DESTROYED: status_color = Color( 0, 0, 0); break; + } +} + +// +--------------------------------------------------------------------+ + +bool MFD::IsMouseLatched() const +{ + return mouse_in; +} + +// +--------------------------------------------------------------------+ + +void MFD::DrawMFDText(int index, const char* txt, Rect& txt_rect, int align, int status) +{ + if (index >= MFD::TXT_LAST) { + Print("MFD DrawMFDText() invalid mfd_text index %d '%s'\n", index, txt); + } + else { + HUDText& mt = mfd_text[index]; + Color mc = mt.color; + + switch (status) { + default: + case System::NOMINAL: mc = txt_color; break; + case System::DEGRADED: mc = Color(255,255, 0); break; + case System::CRITICAL: mc = Color(255, 0, 0); break; + case System::DESTROYED: mc = Color( 0, 0, 0); break; + } + + char txt_buf[256]; + int n = strlen(txt); + + if (n > 250) n = 250; + int i; + + for (i = 0; i < n; i++) { + if (islower(txt[i])) + txt_buf[i] = toupper(txt[i]); + else + txt_buf[i] = txt[i]; + } + + txt_buf[i] = 0; + + + if (cockpit_hud_texture) { + Rect hud_rect(txt_rect); + + hud_rect.x = txt_rect.x + this->index * 128 - this->rect.x; + hud_rect.y = txt_rect.y + 256 - this->rect.y; + + mt.font->SetColor(mc); + mt.font->DrawText(txt_buf, 0, hud_rect, align | DT_SINGLELINE, cockpit_hud_texture); + mt.rect = rect; + mt.hidden = false; + } + else { + if (txt_rect.Contains(Mouse::X(), Mouse::Y())) + mc = Color::White; + + mt.font->SetColor(mc); + mt.font->DrawText(txt_buf, 0, txt_rect, align | DT_SINGLELINE); + mt.rect = rect; + mt.hidden = false; + } + + } +} + +void MFD::HideMFDText(int index) +{ + if (index >= MFD::TXT_LAST) + Print("MFD HideMFDText() invalid mfd_text index %d\n", index); + else + mfd_text[index].hidden = true; +} + + + + -- cgit v1.1