diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 20d831e1c0..f15827e5d6 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -889,6 +889,7 @@ SET(LIBCMD_SOURCES src/cmd/intelligent.cpp src/cmd/energetic.cpp + src/cmd/cloak.cpp src/cmd/planetary_orbit.cpp diff --git a/engine/src/cmd/ai/fire.cpp b/engine/src/cmd/ai/fire.cpp index 095ce08610..3c6d1b8769 100644 --- a/engine/src/cmd/ai/fire.cpp +++ b/engine/src/cmd/ai/fire.cpp @@ -430,7 +430,7 @@ class ChooseTargetClass { } bool ShouldTargetUnit(Unit *un, float distance) { - if (un->CloakVisible() > .8) { + if (un->cloak.Visible()) { float rangetotarget = distance; float rel0 = parent->getRelation(un); float rel[] = { @@ -841,7 +841,7 @@ void FireAt::Execute() { bool istargetjumpableplanet = false; if ((targ = parent->Target())) { istargetjumpableplanet = isJumpablePlanet(targ); - if (targ->CloakVisible() > .8 && !targ->Destroyed()) { + if (targ->cloak.Visible() && !targ->Destroyed()) { had_target = true; if (parent->getNumMounts() > 0) { if (!istargetjumpableplanet) { diff --git a/engine/src/cmd/ai/firekeyboard.cpp b/engine/src/cmd/ai/firekeyboard.cpp index 0ee2234d42..f792b8a85d 100644 --- a/engine/src/cmd/ai/firekeyboard.cpp +++ b/engine/src/cmd/ai/firekeyboard.cpp @@ -64,7 +64,6 @@ extern bool toggle_pause(); FireKeyboard::FireKeyboard(unsigned int whichplayer, unsigned int whichjoystick) : Order(WEAPON, 0) { memset(savedTargets, 0, sizeof(void *) * NUMSAVEDTARGETS); this->autotrackingtoggle = 1; - this->cloaktoggle = true; this->whichjoystick = whichjoystick; this->whichplayer = whichplayer; gunspeed = gunrange = .0001; @@ -1780,8 +1779,7 @@ void FireKeyboard::Execute() { } if (f().cloakkey == PRESS) { f().cloakkey = DOWN; - parent->Cloak(cloaktoggle); - cloaktoggle = !cloaktoggle; + parent->cloak.Toggle(); } if (f().lockkey == PRESS) { f().lockkey = DOWN; diff --git a/engine/src/cmd/ai/firekeyboard.h b/engine/src/cmd/ai/firekeyboard.h index 94c1431cbc..3cc6ca2cff 100644 --- a/engine/src/cmd/ai/firekeyboard.h +++ b/engine/src/cmd/ai/firekeyboard.h @@ -34,7 +34,6 @@ #define NUMSAVEDTARGETS 10 class FireKeyboard : public Order { bool itts; - bool cloaktoggle; bool refresh_target; float gunspeed; float gunrange; diff --git a/engine/src/cmd/ai/tactics.cpp b/engine/src/cmd/ai/tactics.cpp index adcbcaa9cd..86884d90be 100644 --- a/engine/src/cmd/ai/tactics.cpp +++ b/engine/src/cmd/ai/tactics.cpp @@ -31,13 +31,13 @@ void CloakFor::Execute() { if (time == 0) { - parent->Cloak(enable); + parent->cloak.Activate(); } time += SIMULATION_ATOM; if (time > maxtime) { done = true; if (maxtime != 0) { - parent->Cloak(!enable); + parent->cloak.Deactivate(); } return; } @@ -48,7 +48,7 @@ CloakFor::~CloakFor() { VS_LOG_AND_FLUSH(trace, (boost::format("clk%1$x") % this)); #endif if (parent && time <= maxtime) { - parent->Cloak(!enable); + parent->cloak.Deactivate(); } } diff --git a/engine/src/cmd/armed.cpp b/engine/src/cmd/armed.cpp index 25fa01bbc3..40f99bb2b6 100644 --- a/engine/src/cmd/armed.cpp +++ b/engine/src/cmd/armed.cpp @@ -199,7 +199,7 @@ void Armed::ActivateGuns(const WeaponInfo *sz, bool ms) { void Armed::Fire(unsigned int weapon_type_bitmask, bool listen_to_owner) { Unit *unit = static_cast(this); - if ((unit->cloaking >= 0 && !configuration()->weapons.can_fire_in_cloak) || + if ((unit->cloak.Active() && !configuration()->weapons.can_fire_in_cloak) || (unit->graphicOptions.InWarp && !configuration()->weapons.can_fire_in_spec)) { UnFire(); return; diff --git a/engine/src/cmd/basecomputer.cpp b/engine/src/cmd/basecomputer.cpp index e97d524dc8..63f243cf58 100644 --- a/engine/src/cmd/basecomputer.cpp +++ b/engine/src/cmd/basecomputer.cpp @@ -5565,17 +5565,17 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C } } //cloaking device? If we don't have one, no need to mention it ever exists, right? - if (playerUnit->cloaking != -1) { + if (playerUnit->cloak.Capable()) { if (!mode) { PRETTY_ADDU(statcolor + "Cloaking device available, energy usage: #-c", - playerUnit->cloakenergy * RSconverter * Wconv, + playerUnit->cloak.Energy() * RSconverter * Wconv, 0, "MJ/s"); } else { switch (replacement_mode) { case 0: //Replacement or new Module PRETTY_ADDU(statcolor + "Installs a cloaking device.#n# Activated energy usage: #-c", - playerUnit->cloakenergy * RSconverter * Wconv, + playerUnit->cloak.Energy() * RSconverter * Wconv, 0, "MJ/s"); break; diff --git a/engine/src/cmd/briefing.cpp b/engine/src/cmd/briefing.cpp index 436c5d733e..537368fead 100644 --- a/engine/src/cmd/briefing.cpp +++ b/engine/src/cmd/briefing.cpp @@ -116,11 +116,7 @@ void Briefing::Ship::Render(const Matrix &cam, double interpol) { Matrix camfinal; MultMatrix(camfinal, cam, final); for (unsigned int i = 0; i < meshdata.size(); i++) { - int scloak = int(cloak * ((-1) > 1)); //FIXME short fix? - if ((scloak & 0x1) == 0) { - scloak += 1; - } - meshdata[i]->Draw(1, camfinal, 1, cloak > .99 ? -1 : scloak); + meshdata[i]->Draw(1, camfinal, 1); } } diff --git a/engine/src/cmd/cloak.cpp b/engine/src/cmd/cloak.cpp new file mode 100644 index 0000000000..7f20ef5c86 --- /dev/null +++ b/engine/src/cmd/cloak.cpp @@ -0,0 +1,144 @@ +/* + * cloak.cpp + * + * Copyright (C) 2001-2023 Daniel Horn, Benjaman Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#include "cloak.h" +#include "unit_csv_factory.h" +#include "vegastrike.h" +#include "configuration/configuration.h" + +Cloak::Cloak() +{ + status = CloakingStatus::disabled; + + energy = 0; + rate = 100; + glass = false; + current = 0; + minimum = 0; +} + +Cloak::Cloak(std::string unit_key) +{ + if(UnitCSVFactory::GetVariable(unit_key, "Can_Cloak", false)) { + status = CloakingStatus::ready; + } else { + status = CloakingStatus::disabled; + } + + glass = UnitCSVFactory::GetVariable(unit_key, "Cloak_Glass", false); + rate = UnitCSVFactory::GetVariable(unit_key, "Cloak_Rate", 0.0); + energy = UnitCSVFactory::GetVariable(unit_key, "Cloak_Energy", 0.0); + minimum = UnitCSVFactory::GetVariable(unit_key, "Cloak_Min", 0.0); + minimum = std::min(1.0, std::max(0.0, minimum)); + current = 0; +} + +void Cloak::Save(std::map& unit) +{ + unit["Cloak_Min"] = std::to_string(minimum); + unit["Can_Cloak"] = std::to_string(Capable()); + unit["Cloak_Rate"] = std::to_string(rate); + unit["Cloak_Energy"] = std::to_string(energy); + unit["Cloak_Glass"] = std::to_string(glass); +} + +void Cloak::Update(Energetic *energetic) +{ + // Unit is not capable of cloaking or damaged or just not cloaking + if(status == CloakingStatus::disabled || + status == CloakingStatus::damaged || + status == CloakingStatus::ready) { + return; + } + + // Use warp power for cloaking (SPEC capacitor) + const static bool warp_energy_for_cloak = configuration()->warp_config.use_warp_energy_for_cloak; + double available_energy = warp_energy_for_cloak ? energetic->warpenergy : energetic->energy.Value(); + + + // Insufficient energy to cloak ship + if(available_energy < this->energy) { + status = CloakingStatus::decloaking; + } else { + // Subtract the energy used + if (warp_energy_for_cloak) { + energetic->warpenergy -= (simulation_atom_var * energy); + } else { + energetic->energy -= (simulation_atom_var * energy); + } + } + + if(status == CloakingStatus::decloaking) { + current = std::max(0.0, current - rate * simulation_atom_var); + + if(current == 0) { + status = CloakingStatus::ready; + } + } + + if(status == CloakingStatus::cloaking) { + current = std::min(1.0, current + rate * simulation_atom_var); + + if(current > minimum) { + status = CloakingStatus::cloaked; + } + } + + +} + +void Cloak::Toggle() { + // Unit is not capable of cloaking or damaged + if(status == CloakingStatus::disabled || + status == CloakingStatus::damaged) { + return; + } + + // If we're ready start cloaking + if(status == CloakingStatus::ready) { + status = CloakingStatus::cloaking; + return; + } + + // In any other case, start decloaking + status = CloakingStatus::decloaking; +} + +void Cloak::Activate() { + if(status == CloakingStatus::ready) { + status = CloakingStatus::cloaking; + } +} + +void Cloak::Deactivate() { + // Unit is not capable of cloaking or damaged or just not cloaking + if(status == CloakingStatus::disabled || + status == CloakingStatus::damaged || + status == CloakingStatus::ready) { + return; + } + + // Start decloaking + status = CloakingStatus::decloaking; +} diff --git a/engine/src/cmd/cloak.h b/engine/src/cmd/cloak.h new file mode 100644 index 0000000000..967145d279 --- /dev/null +++ b/engine/src/cmd/cloak.h @@ -0,0 +1,150 @@ +/* + * cloak.h + * + * Copyright (C) 2001-2023 Daniel Horn, Benjaman Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#ifndef CLOAK_H +#define CLOAK_H + +#include +#include + +#include "energetic.h" +#include "damageable_layer.h" + +enum class CloakingStatus { + disabled, + damaged, + ready, + cloaking, + cloaked, + decloaking +}; + +class Cloak +{ + friend class Unit; + + CloakingStatus status; + + // How much energy cloaking takes per frame + double energy; + + // How fast does this starship cloak/decloak + double rate; + + // If this unit cloaks like glass or like fading. + // Glass is alpha only. Non glass affects rgb as well. + bool glass; + + // Current cloak value. 0 is uncloaked. 1 is fully cloaked. + double current; + + // The minimum cloaking value... + double minimum; + +public: + Cloak(); + Cloak(std::string unit_key); + void Save(std::map& unit); + + void Update(Energetic *energetic); + void Toggle(); // Toggle cloak on/off + + bool Capable() const { + return (status != CloakingStatus::disabled); + } + + bool Cloaking() { + return (status == CloakingStatus::cloaking); + } + + bool Cloaked() const { + return (status == CloakingStatus::cloaked); + } + + // Active is cloaking, cloaked or decloaking + bool Active() { + return (status == CloakingStatus::cloaking || + status == CloakingStatus::cloaked || + status == CloakingStatus::decloaking); + } + + bool Damaged() { + return (status == CloakingStatus::damaged); + } + + bool Ready() { + return (status == CloakingStatus::ready); + } + + bool Glass() { + return glass; + } + + double Energy() { + return energy; + } + + // Is the ship visible + bool Visible() { + return !Cloaked(); + } + + double Current() const { + return current; + } + + //how visible the ship is from 0 to 1 + double Visibility() const { + return 1-current; + } + + // TODO: more granular damage + // TODO: damageable component + void Damage() { + status = CloakingStatus::damaged; + current = 0; + } + + void Repair() { + if(status == CloakingStatus::damaged) { + status = CloakingStatus::ready; + current = 0; + } + } + + void Disable() { + status = CloakingStatus::disabled; + current = 0; + } + + void Enable() { + status = CloakingStatus::ready; + current = 0; + } + + void Activate(); + void Deactivate(); +}; + +#endif // CLOAK_H diff --git a/engine/src/cmd/cont_terrain.cpp b/engine/src/cmd/cont_terrain.cpp index d7a15c9393..fcac14c502 100644 --- a/engine/src/cmd/cont_terrain.cpp +++ b/engine/src/cmd/cont_terrain.cpp @@ -287,7 +287,8 @@ void ContinuousTerrain::Draw() { md[i].mesh->rSize() ); if (d) { - md[i].mesh->Draw(1000, md[i].mat, d, -1, (_Universe->AccessCamera()->GetNebula() != NULL) ? -1 : 0); + static Cloak dummy_cloak; + md[i].mesh->Draw(1000, md[i].mat, d, dummy_cloak, (_Universe->AccessCamera()->GetNebula() != NULL) ? -1 : 0); } } } diff --git a/engine/src/cmd/damageable.cpp b/engine/src/cmd/damageable.cpp index 8ab291bf7a..7847c00040 100644 --- a/engine/src/cmd/damageable.cpp +++ b/engine/src/cmd/damageable.cpp @@ -565,8 +565,9 @@ void Damageable::RegenerateShields(const float difficulty, const bool player_shi } - // Discharge shields due to energy or SPEC - if ((in_warp && !shields_in_spec) || !unit->sufficient_energy_to_recharge_shields) { + // Discharge shields due to energy or SPEC or cloak + if ((in_warp && !shields_in_spec) || !unit->sufficient_energy_to_recharge_shields || + unit->cloak.Active()) { shield->Discharge(discharge_rate, min_shield_discharge); } else { // Shield regeneration diff --git a/engine/src/cmd/drawable.cpp b/engine/src/cmd/drawable.cpp index a4095163a5..04e20c2678 100644 --- a/engine/src/cmd/drawable.cpp +++ b/engine/src/cmd/drawable.cpp @@ -204,15 +204,10 @@ void Drawable::Draw(const Transformation &parent, const Matrix &parentMatrix) { bool On_Screen = false; bool Unit_On_Screen = false; float Apparent_Size = 0.0f; - int cloak = unit->cloaking; Matrix wmat; if (!cam_setup_phase) { // Following stuff is only needed in actual drawing phase - if (unit->cloaking > unit->cloakmin) { - cloak = (int) (unit->cloaking - interpolation_blend_factor * unit->cloakrate * simulation_atom_var); - cloak = cloakVal(cloak, unit->cloakmin, unit->cloakrate, unit->cloakglass); - } if ((*unit->current_hull) < (*unit->max_hull)) { damagelevel = (*unit->current_hull) / (*unit->max_hull); chardamage = (255 - (unsigned char) (damagelevel * 255)); @@ -272,10 +267,9 @@ void Drawable::Draw(const Transformation &parent, const Matrix &parentMatrix) { if (frustd) { //if the radius is at least half a pixel at detail 1 (equivalent to pixradius >= 0.5 / detail) float currentFrame = meshdata[i]->getCurrentFrame(); - this->meshdata[i]->Draw(lod, wmat, d, - i == this->meshdata.size() - 1 ? -1 : cloak, + this->meshdata[i]->Draw(lod, wmat, d, unit->cloak, (camera->GetNebula() == unit->nebula && unit->nebula != NULL) ? -1 : 0, - chardamage); //cloakign and nebula + chardamage); //cloaking and nebula On_Screen = true; unsigned int numAnimFrames = 0; static const string default_animation; @@ -349,8 +343,8 @@ void Drawable::Draw(const Transformation &parent, const Matrix &parentMatrix) { return; } - DrawSubunits(On_Screen, wmat, cloak, avgscale, chardamage); - DrawHalo(On_Screen, Apparent_Size, wmat, cloak); + DrawSubunits(On_Screen, wmat, unit->cloak, avgscale, chardamage); + DrawHalo(On_Screen, Apparent_Size, wmat, unit->cloak); Sparkle(On_Screen, ctm); } @@ -412,10 +406,7 @@ void Drawable::DrawNow(const Matrix &mato, float lod) { pos = mato.p; VectorAndPositionToMatrix(mat, p, q, r, pos); } - int cloak = unit->cloaking; - if (unit->cloaking > unit->cloakmin) { - cloak = cloakVal(cloak, unit->cloakmin, unit->cloakrate, unit->cloakglass); - } + for (i = 0; i <= this->nummesh(); i++) { //NOTE LESS THAN OR EQUALS...to cover shield mesh if (this->meshdata[i] == NULL) { @@ -426,7 +417,7 @@ void Drawable::DrawNow(const Matrix &mato, float lod) { float d = GFXSphereInFrustum(TransformedPosition, this->meshdata[i]->clipRadialSize() * vlpqrScaleFactor); if (d) { //d can be used for level of detail //this->meshdata[i]->DrawNow(lod,false,mat,cloak);//cloakign and nebula - this->meshdata[i]->Draw(lod, mat, d, cloak); + this->meshdata[i]->Draw(lod, mat, d, unit->cloak); } } Unit *un; @@ -468,22 +459,20 @@ void Drawable::DrawNow(const Matrix &mato, float lod) { (d - gun->rSize() < g_game.znear) ? g_game.znear : d - gun->rSize()); ScaleMatrix(mmat, Vector(mahnt->xyscale, mahnt->xyscale, mahnt->zscale)); gun->setCurrentFrame(unit->mounts[i].ComputeAnimatedFrame(gun)); - gun->Draw(lod, mmat, d, cloak, - (_Universe->AccessCamera()->GetNebula() == unit->nebula && unit->nebula != NULL) ? -1 + gun->Draw(lod, mmat, d, unit->cloak, (_Universe->AccessCamera()->GetNebula() == unit->nebula && unit->nebula != NULL) ? -1 : 0, chardamage, true); //cloakign and nebula if (mahnt->type->gun1) { gun = mahnt->type->gun1; gun->setCurrentFrame(unit->mounts[i].ComputeAnimatedFrame(gun)); - gun->Draw(lod, - mmat, - d, - cloak, - (_Universe->AccessCamera()->GetNebula() == unit->nebula && unit->nebula + gun->Draw(lod, mmat, + d, + unit->cloak, + (_Universe->AccessCamera()->GetNebula() == unit->nebula && unit->nebula != NULL) ? -1 : 0, - chardamage, - true); //cloakign and nebula + chardamage, + true); //cloakign and nebula } } } @@ -497,7 +486,7 @@ void Drawable::DrawNow(const Matrix &mato, float lod) { if (!(unit->docked & (unit->DOCKED | unit->DOCKED_INSIDE))) { halos->Draw(mat, Scale, - cloak, + unit->cloak.Visibility(), 0, unit->GetHullPercent(), velocity, @@ -707,7 +696,7 @@ void Drawable::Sparkle(bool on_screen, Matrix *ctm) { } } -void Drawable::DrawHalo(bool on_screen, float apparent_size, Matrix wmat, int cloak) { +void Drawable::DrawHalo(bool on_screen, float apparent_size, Matrix wmat, Cloak cloak) { Unit *unit = vega_dynamic_cast_ptr(this); // Units not shown don't emit a halo @@ -746,12 +735,12 @@ void Drawable::DrawHalo(bool on_screen, float apparent_size, Matrix wmat, int cl //nor is maxaccel. Instead, each halo should have its own limits specified in units.csv float nebd = (_Universe->AccessCamera()->GetNebula() == unit->nebula && unit->nebula != nullptr) ? -1 : 0; float hulld = unit->GetHull() > 0 ? damage_level : 1.0; - halos->Draw(wmat, Scale, cloak, nebd, hulld, velocity, + halos->Draw(wmat, Scale, unit->cloak.Visibility(), nebd, hulld, velocity, linaccel, angaccel, maxaccel, cmas, unit->faction); } -void Drawable::DrawSubunits(bool on_screen, Matrix wmat, int cloak, float average_scale, unsigned char char_damage) { +void Drawable::DrawSubunits(bool on_screen, Matrix wmat, Cloak cloak, float average_scale, unsigned char char_damage) { Unit *unit = vega_dynamic_cast_ptr(this); Transformation *ct = &unit->cumulative_transformation; @@ -811,8 +800,7 @@ void Drawable::DrawSubunits(bool on_screen, Matrix wmat, int cloak, float averag if (lod > 0.5 && pixradius > 2.5) { ScaleMatrix(mat, Vector(mount->xyscale, mount->xyscale, mount->zscale)); gun->setCurrentFrame(unit->mounts[i].ComputeAnimatedFrame(gun)); - gun->Draw(lod, mat, d, cloak, - (_Universe->AccessCamera()->GetNebula() == unit->nebula && unit->nebula != NULL) ? -1 : 0, + gun->Draw(lod, mat, d, cloak, (_Universe->AccessCamera()->GetNebula() == unit->nebula && unit->nebula != NULL) ? -1 : 0, char_damage, true); //cloakign and nebula } diff --git a/engine/src/cmd/drawable.h b/engine/src/cmd/drawable.h index 119305b1a8..dc0db5d7ee 100644 --- a/engine/src/cmd/drawable.h +++ b/engine/src/cmd/drawable.h @@ -32,6 +32,8 @@ #include #include +#include "cloak.h" + class Mesh; class Flightgroup; class Unit; @@ -134,8 +136,8 @@ class Drawable { virtual std::string drawableGetName() = 0; void Sparkle(bool on_screen, Matrix *ctm); - void DrawHalo(bool on_screen, float apparent_size, Matrix wmat, int cloak); - void DrawSubunits(bool on_screen, Matrix wmat, int cloak, float average_scale, unsigned char char_damage); + void DrawHalo(bool on_screen, float apparent_size, Matrix wmat, Cloak cloak); + void DrawSubunits(bool on_screen, Matrix wmat, Cloak cloak, float average_scale, unsigned char char_damage); //Split this mesh with into 2^level submeshes at arbitrary planes void Split(int level); diff --git a/engine/src/cmd/jump_capable.cpp b/engine/src/cmd/jump_capable.cpp index d8930247d6..571b470fb7 100644 --- a/engine/src/cmd/jump_capable.cpp +++ b/engine/src/cmd/jump_capable.cpp @@ -212,7 +212,7 @@ bool JumpCapable::AutoPilotToErrorMessage(const Unit *target, XMLSupport::parse_bool(vs_config->getVariable("physics", "teleport_autopilot", "true")); bool unsafe = false; if ((!teleport_autopilot) && (!nanspace)) { - if (Guaranteed == Mission::AUTO_NORMAL && unit->CloakVisible() > .5) { + if (Guaranteed == Mission::AUTO_NORMAL && unit->cloak.Cloaked()) { bool ignore_friendlies = true; for (un_iter i = ss->getUnitList().createIterator(); (un = *i) != NULL; ++i) { static bool canflythruplanets = diff --git a/engine/src/cmd/unit_csv.cpp b/engine/src/cmd/unit_csv.cpp index ad6496e888..cfad4830b1 100644 --- a/engine/src/cmd/unit_csv.cpp +++ b/engine/src/cmd/unit_csv.cpp @@ -922,28 +922,8 @@ void Unit::LoadRow(std::string unit_identifier, string modification, bool saved_ computer.radar.trackingcone = cos(UnitCSVFactory::GetVariable(unit_key, "Tracking_Cone", 180.0f) * VS_PI / 180); computer.radar.lockcone = cos(UnitCSVFactory::GetVariable(unit_key, "Lock_Cone", 180.0f) * VS_PI / 180); - cloakmin = static_cast(UnitCSVFactory::GetVariable(unit_key, "Cloak_Min", 0.0f) * 2147483136); - if (cloakmin < 0) { - cloakmin = 0; - } - - cloakglass = UnitCSVFactory::GetVariable(unit_key, "Cloak_Glass", false); - if ((cloakmin & 0x1) && !cloakglass) { - cloakmin -= 1; - } - - if ((cloakmin & 0x1) == 0 && cloakglass) { - cloakmin += 1; - } + cloak = Cloak(unit_key); - if (!UnitCSVFactory::GetVariable(unit_key, "Can_Cloak", false)) { - cloaking = -1; - } else { - cloaking = (int) (-2147483647) - 1; - } - - cloakrate = (int) (2147483136.0 * UnitCSVFactory::GetVariable(unit_key, "Cloak_Rate", 0.0f)); //short fix - cloakenergy = UnitCSVFactory::GetVariable(unit_key, "Cloak_Energy", 0.0f); repair_droid = UnitCSVFactory::GetVariable(unit_key, "Repair_Droid", 0); ecm = UnitCSVFactory::GetVariable(unit_key, "ECM_Rating", 0); @@ -1384,11 +1364,8 @@ string Unit::WriteUnitString() { unit["Tracking_Cone"] = tos(acos(computer.radar.trackingcone) * 180. / VS_PI); unit["Max_Cone"] = tos(acos(computer.radar.maxcone) * 180. / VS_PI); unit["Lock_Cone"] = tos(acos(computer.radar.lockcone) * 180. / VS_PI); - unit["Cloak_Min"] = tos(cloakmin / 2147483136.); - unit["Can_Cloak"] = tos(cloaking != -1); - unit["Cloak_Rate"] = tos(fabs(cloakrate / 2147483136.)); - unit["Cloak_Energy"] = tos(cloakenergy); - unit["Cloak_Glass"] = tos(cloakglass); + + cloak.Save(unit); unit["Repair_Droid"] = tos(repair_droid); unit["ECM_Rating"] = tos(ecm > 0 ? ecm : -ecm); unit["Hud_Functionality"] = WriteHudDamage(this); diff --git a/engine/src/cmd/unit_generic.cpp b/engine/src/cmd/unit_generic.cpp index 14dfa67c83..ce51e2e6a0 100644 --- a/engine/src/cmd/unit_generic.cpp +++ b/engine/src/cmd/unit_generic.cpp @@ -138,7 +138,7 @@ void Unit::SetNebula(Nebula *neb) { bool Unit::InRange(const Unit *target, double &mm, bool cone, bool cap, bool lock) const { const float capship_size = configuration()->physics_config.capship_size; - if (this == target || target->CloakVisible() < .8) { + if (this == target || target->cloak.Cloaked()) { return false; } if (cone && computer.radar.maxcone > -.98) { @@ -961,8 +961,11 @@ void Unit::UpdateSubunitPhysics(Unit *subunit, lastframe, uc, superunit); - //short fix - subunit->cloaking = (unsigned int) cloaking; + + // TODO: make the subunit->cloak a pointer to parent->cloak + // Also, no reason why subunits should handle their own physics but that's + // much harder to refactor + subunit->cloak.status = cloak.status; if (Destroyed()) { subunit->Target(NULL); UnFire(); //don't want to go off shooting while your body's splitting everywhere @@ -1298,14 +1301,8 @@ void Unit::DamageRandSys(float dam, const Vector &vec, float randnum, float degr if (degrees >= 90 && degrees < 120) { //DAMAGE Shield //DAMAGE cloak - if (randnum >= .95) { - this->cloaking = -1; - damages |= Damages::CLOAK_DAMAGED; - } else if (randnum >= .78) { - cloakenergy += ((1 - dam) * recharge); - damages |= Damages::CLOAK_DAMAGED; - } else if (randnum >= .7) { - cloakmin += (rand() % (32000 - cloakmin)); + if (randnum >= .7) { + this->cloak.Damage(); damages |= Damages::CLOAK_DAMAGED; } @@ -1666,25 +1663,12 @@ void Unit::SetOwner(Unit *target) { owner = target; } -void Unit::Cloak(bool loak) { - damages |= Damages::CLOAK_DAMAGED; - if (loak) { - static bool warp_energy_for_cloak = - XMLSupport::parse_bool(vs_config->getVariable("physics", "warp_energy_for_cloak", "true")); - if (cloakenergy < (warp_energy_for_cloak ? warpenergy : energy.Value())) { - cloakrate = (cloakrate >= 0) ? cloakrate : -cloakrate; - //short fix - if (cloaking < -1 && cloakrate != 0) { - //short fix - cloaking = 2147483647; - } else { - } - } +// Need this for python API. Do not delete. +void Unit::ActivateCloak(bool enable) { + if(enable) { + cloak.Activate(); } else { - cloakrate = (cloakrate >= 0) ? -cloakrate : cloakrate; - if (cloaking == cloakmin) { - ++cloaking; - } + cloak.Deactivate(); } } @@ -3348,14 +3332,17 @@ bool Unit::UpAndDownGrade(const Unit *up, tempdownmap); } } - if (cloaking != -1 && up->cloaking != -1) { + if (cloak.Capable() && up->cloak.Capable()) { if (touchme) { - cloaking = -1; + cloak.Disable(); } ++numave; ++percentage; if (gen_downgrade_list) { - AddToDowngradeMap(up->name, up->cloaking, ((char *) &this->cloaking) - ((char *) this), tempdownmap); + AddToDowngradeMap(up->name, + up->cloak.current, + ((char *) &this->cloak.current) - ((char *) this), + tempdownmap); } } //NOTE: Afterburner type 2 (jmp) @@ -3384,16 +3371,17 @@ bool Unit::UpAndDownGrade(const Unit *up, } } } - if ((cloaking == -1 && up->cloaking != -1) || force_change_on_nothing) { + if ((!cloak.Capable() && up->cloak.Capable()) || force_change_on_nothing) { if (touchme) { - cloaking = up->cloaking; - cloakmin = up->cloakmin; - cloakrate = up->cloakrate; - cloakglass = up->cloakglass; - cloakenergy = up->cloakenergy; + cloak.Enable(); + + cloak.minimum = up->cloak.minimum; + cloak.rate = up->cloak.rate; + cloak.glass = up->cloak.glass; + cloak.energy = up->cloak.energy; } ++numave; - } else if (cloaking != -1 && up->cloaking != -1) { + } else if (cloak.Capable() && up->cloak.Capable()) { cancompletefully = false; } //NOTE: Afterburner type 2 (jmp) @@ -4263,95 +4251,7 @@ void Unit::applyTechniqueOverrides(const std::map &ove std::map Drawable::Units; -//helper func for Init -string toLowerCase(string in) { - string out; - for (unsigned int i = 0; i < in.length(); i++) { - switch (in[i]) { - case 'A': - out += 'a'; - break; - case 'B': - out += 'b'; - break; - case 'C': - out += 'c'; - break; - case 'D': - out += 'd'; - break; - case 'E': - out += 'e'; - break; - case 'F': - out += 'f'; - break; - case 'G': - out += 'g'; - break; - case 'H': - out += 'h'; - break; - case 'I': - out += 'i'; - break; - case 'J': - out += 'j'; - break; - case 'K': - out += 'k'; - break; - case 'L': - out += 'l'; - break; - case 'M': - out += 'm'; - break; - case 'N': - out += 'n'; - break; - case 'O': - out += 'o'; - break; - case 'P': - out += 'p'; - break; - case 'Q': - out += 'q'; - break; - case 'R': - out += 'r'; - break; - case 'S': - out += 's'; - break; - case 'T': - out += 't'; - break; - case 'U': - out += 'u'; - break; - case 'V': - out += 'v'; - break; - case 'W': - out += 'w'; - break; - case 'X': - out += 'x'; - break; - case 'Y': - out += 'y'; - break; - case 'Z': - out += 'z'; - break; - default: - out += in[i]; - } - } - return out; -} + unsigned int Drawable::unitCount = 0; @@ -4438,7 +4338,18 @@ void Unit::UpdatePhysics3(const Transformation &trans, if (fuel < 0) { fuel = 0; } - UpdateCloak(); + + static CloakingStatus previous_status = cloak.status; + cloak.Update(this); + + // Play once per cloaking + if(cloak.Cloaking() && previous_status != CloakingStatus::cloaking) { + previous_status = cloak.status; + playSound(SoundType::cloaking); + } else if(cloak.Cloaked() && previous_status != CloakingStatus::cloaked) { + previous_status = cloak.status; + adjustSound(SoundType::cloaking, cumulative_transformation.position, cumulative_velocity); + } // Recharge energy and shields const bool apply_difficulty_shields = configuration()->physics_config.difficulty_based_shield_recharge; @@ -4491,7 +4402,7 @@ void Unit::UpdatePhysics3(const Transformation &trans, float dist_sqr_to_target = FLT_MAX; Unit *target = Unit::Target(); bool increase_locking = false; - if (target && cloaking < 0 /*-1 or -32768*/) { + if (target && !cloak.Cloaked()) { if (target->isUnit() != Vega_UnitType::planet) { Vector TargetPos(InvTransform(cumulative_transformation_matrix, (target->Position())).Cast()); dist_sqr_to_target = TargetPos.MagnitudeSquared(); @@ -4534,7 +4445,7 @@ void Unit::UpdatePhysics3(const Transformation &trans, // TODO: simplify this if if (((false && mounts[i].status - == Mount::INACTIVE) || mounts[i].status == Mount::ACTIVE) && cloaking < 0 + == Mount::INACTIVE) || mounts[i].status == Mount::ACTIVE) && !cloak.Cloaked() && mounts[i].ammo != 0) { if (player_cockpit) { touched = true; @@ -4733,55 +4644,6 @@ void Unit::UpdatePhysics3(const Transformation &trans, } } -void Unit::UpdateCloak() { - // Use warp power for cloaking (SPEC capacitor) - const bool warp_energy_for_cloak = configuration()->warp_config.use_warp_energy_for_cloak; - - // We are not cloaked - exiting function - if (cloaking < cloakmin) { - return; - } - - // Insufficient energy to cloak ship - if (cloakenergy * simulation_atom_var > (warp_energy_for_cloak ? warpenergy : energy.Value())) { - Cloak(false); - return; - } - - // Cloaked ships don't have shields on - shield->Disable(); - - // We're cloaked - if (cloaking > cloakmin) { - adjustSound(SoundType::cloaking, cumulative_transformation.position, cumulative_velocity); - - //short fix - // TODO: figure out what they have fixed - if ((cloaking == (2147483647) - && cloakrate > 0) || (cloaking == cloakmin + 1 && cloakrate < 0)) { - playSound(SoundType::cloaking); - } - - //short fix - // TODO: figure out what they have fixed - cloaking -= (int) (cloakrate * simulation_atom_var); - if (cloaking <= cloakmin && cloakrate > 0) { - cloaking = cloakmin; - } - if (cloaking < 0 && cloakrate < 0) { - cloaking = -2147483647 - 1; - } - } - - // Calculate energy drain - if (cloakrate > 0 || cloaking == cloakmin) { - if (warp_energy_for_cloak) { - warpenergy -= (simulation_atom_var * cloakenergy); - } else { - energy -= (simulation_atom_var * cloakenergy); - } - } -} bool Unit::isPlayerShip() { return _Universe->isPlayerStarship(this) ? true : false; diff --git a/engine/src/cmd/unit_generic.h b/engine/src/cmd/unit_generic.h index 00cb85b922..568f03dec1 100644 --- a/engine/src/cmd/unit_generic.h +++ b/engine/src/cmd/unit_generic.h @@ -76,6 +76,7 @@ void UncheckUnit( class Unit*un ); #include "SharedPool.h" #include "role_bitmask.h" #include "upgradeable_unit.h" +#include "cloak.h" #include "configuration/configuration.h" #include "configuration/game_config.h" @@ -138,11 +139,14 @@ struct PlanetaryOrbitData; // TODO: move Armed to subclasses class Unit : public Armed, public Audible, public Drawable, public Damageable, public Energetic, public Intelligent, public Movable, public JumpCapable, public Carrier, public UpgradeableUnit { + protected: //How many lists are referencing us int ucref = 0; StringPool::Reference csvRow; + public: + Cloak cloak; /// Radar and related systems // TODO: take a deeper look at this much later... @@ -586,20 +590,6 @@ class Unit : public Armed, public Audible, public Drawable, public Damageable, p float shieldtight = configuration()->physics_config.default_shield_tightness; public: - // TODO: move cloak to Cloakable? - ///How much energy cloaking takes per frame - float cloakenergy = 0; - ///how fast this starship decloaks/close...if negative, decloaking - int cloakrate = 100; //short fix - ///If this unit cloaks like glass or like fading - bool cloakglass = false; - - //-1 is not available... ranges between 0 32767 for "how invisible" unit currently is (32768... -32768) being visible) - // Despite the above comment, Init() would set it to -1 - int cloaking = -1; //short fix -//the minimum cloaking value... - int cloakmin = cloakglass ? 1 : 0; //short fix - // TODO: move to jump_capable? ///if the unit is a wormhole bool forcejump = false; @@ -615,16 +605,14 @@ class Unit : public Armed, public Audible, public Drawable, public Damageable, p return ToLocalCoordinates((un->Position() - Position()).Cast()); } -//how visible the ship is from 0 to 1 - float CloakVisible() const { - if (cloaking < 0) { - return 1; - } - return ((float) cloaking) / 2147483647; +// how visible the ship is from 0 to 1 +// Need this function to expose it to python + float CloakVisible() { + return cloak.Visibility(); } //cloaks or decloaks the starship depending on the bool - virtual void Cloak(bool cloak); + virtual void ActivateCloak(bool cloak); //deletes void Kill(bool eraseFromSave = true, bool quitting = false); diff --git a/engine/src/gfx/cockpit.cpp b/engine/src/gfx/cockpit.cpp index 634cb91a8d..6bec2be868 100644 --- a/engine/src/gfx/cockpit.cpp +++ b/engine/src/gfx/cockpit.cpp @@ -682,11 +682,11 @@ float GameCockpit::LookupUnitStat(int stat, Unit *target) { return (float) UnitImages::NOTAPPLICABLE; } case UnitImages::CLOAK_MODAL: - if (-1 == target->cloaking) { + if (!target->cloak.Capable() || target->cloak.Damaged()) { return (float) UnitImages::NOTAPPLICABLE; - } else if (((int) (-2147483647) - 1) == target->cloaking) { + } else if (target->cloak.Ready()) { return (float) UnitImages::READY; - } else if (target->cloaking == target->cloakmin) { + } else if (target->cloak.Cloaked()) { return (float) UnitImages::ACTIVE; } else { return (float) UnitImages::SWITCHING; diff --git a/engine/src/gfx/halo_system.cpp b/engine/src/gfx/halo_system.cpp index 7e723175bb..272d31813e 100644 --- a/engine/src/gfx/halo_system.cpp +++ b/engine/src/gfx/halo_system.cpp @@ -243,7 +243,9 @@ void HaloSystem::Draw(const Matrix &trans, GFXColor(1, 1, 1, 1), GFXColor(1, 1, 1, 1), blend); - i->mesh->Draw(50000000000000.0, m, 1, alpha, nebdist, 0, false, &xtraFX); + + static Cloak dummy_cloak; + i->mesh->Draw(50000000000000.0, m, alpha, dummy_cloak, nebdist, 0, false, &xtraFX); // If damaged, and halo is back-facing if (hullpercent < .99 && ((i->trans.getR().z / i->trans.getR().Magnitude()) > 0.707)) { diff --git a/engine/src/gfx/mesh.cpp b/engine/src/gfx/mesh.cpp index 9db212e539..0ba65b852a 100644 --- a/engine/src/gfx/mesh.cpp +++ b/engine/src/gfx/mesh.cpp @@ -50,7 +50,7 @@ #include "lin_time.h" #include "mesh_xml.h" #include "gfx/technique.h" -#include +#include #include #define LOD_HYSTHERESIS_DIVIDER (20) diff --git a/engine/src/gfx/mesh.h b/engine/src/gfx/mesh.h index aec5e45876..7998181530 100644 --- a/engine/src/gfx/mesh.h +++ b/engine/src/gfx/mesh.h @@ -343,13 +343,13 @@ class Mesh { ///Draws lod pixel wide mesh at Transformation LATER void Draw(float lod, - const Matrix &m = identity_matrix, - float toofar = 1, - int cloak = -1, - float nebdist = 0, - unsigned char damage = 0, - bool renormalize_normals = false, - const MeshFX *mfx = NULL); //short fix + const Matrix &m = identity_matrix, + float toofar = 1, + Cloak cloak = Cloak(), + float nebdist = 0, + unsigned char damage = 0, + bool renormalize_normals = false, + const MeshFX *mfx = NULL); //short fix ///Draws lod pixels wide, mesh at Transformation NOW. If centered, then will center on camera and disable cull void DrawNow(float lod, bool centered, diff --git a/engine/src/gfx/mesh_gfx.cpp b/engine/src/gfx/mesh_gfx.cpp index 23edb8db44..91f2d7c4b1 100644 --- a/engine/src/gfx/mesh_gfx.cpp +++ b/engine/src/gfx/mesh_gfx.cpp @@ -491,13 +491,13 @@ Mesh::~Mesh() { } void Mesh::Draw(float lod, - const Matrix &m, - float toofar, - int cloak, - float nebdist, - unsigned char hulldamage, - bool renormalize, - const MeshFX *mfx) //short fix + const Matrix &m, + float toofar, + Cloak cloak, + float nebdist, + unsigned char hulldamage, + bool renormalize, + const MeshFX *mfx) //short fix { Mesh *origmesh = getLOD(lod); if (origmesh->rSize() > 0) { @@ -512,6 +512,8 @@ void Mesh::Draw(float lod, c.damage = hulldamage; c.mesh_seq = ((toofar + rSize()) > g_game.zfar) ? NUM_ZBUF_SEQ : draw_sequence; + + // Cloaking and Nebula c.cloaked = MeshDrawContext::NONE; if (nebdist < 0) { c.cloaked |= MeshDrawContext::FOG; @@ -519,30 +521,30 @@ void Mesh::Draw(float lod, if (renormalize) { c.cloaked |= MeshDrawContext::RENORMALIZE; } - if (cloak >= 0) { + + // This should have gradually made the ship cloak go transparent + // for cloak.Glass but it does the same thing as the ordinary cloak. + // TODO: revisit this. + if(cloak.Active()) { c.cloaked |= MeshDrawContext::CLOAK; - if ((cloak & 0x1)) { - c.cloaked |= MeshDrawContext::GLASSCLOAK; - c.mesh_seq = MESH_SPECIAL_FX_ONLY; //draw near the end with lights + c.cloaked |= MeshDrawContext::GLASSCLOAK; + + if (cloak.Glass()) { + c.CloakFX.a = cloak.Current(); + c.mesh_seq = 2; //MESH_SPECIAL_FX_ONLY; } else { c.mesh_seq = 2; + c.CloakFX.r = cloak.Visibility(); + c.CloakFX.g = cloak.Visibility(); + c.CloakFX.b = cloak.Visibility(); + c.CloakFX.a = cloak.Current(); } - if (cloak <= CLKSCALE / 2) { - c.cloaked |= MeshDrawContext::NEARINVIS; - } - float tmp = ((float) cloak) / CLKSCALE; - c.CloakFX.r = (c.cloaked & MeshDrawContext::GLASSCLOAK) ? tmp : 1; - c.CloakFX.g = (c.cloaked & MeshDrawContext::GLASSCLOAK) ? tmp : 1; - c.CloakFX.b = (c.cloaked & MeshDrawContext::GLASSCLOAK) ? tmp : 1; - c.CloakFX.a = tmp; - /* - * c.CloakNebFX.ambient[0]=((float)cloak)/CLKSCALE; - * c.CloakNebFX.ag=((float)cloak)/CLKSCALE; - * c.CloakNebFX.ab=((float)cloak)/CLKSCALE; - * c.CloakNebFX.aa=((float)cloak)/CLKSCALE; - */ - ///all else == defaults, only ambient } + + if (cloak.Cloaking()) { + c.cloaked |= MeshDrawContext::NEARINVIS; + } + //c.mat[12]=pos.i; //c.mat[13]=pos.j; //c.mat[14]=pos.k;//to translate to local_pos which is now obsolete! diff --git a/engine/src/gfx/nav/navscreen.cpp b/engine/src/gfx/nav/navscreen.cpp index 4432e329ea..5720caeb00 100644 --- a/engine/src/gfx/nav/navscreen.cpp +++ b/engine/src/gfx/nav/navscreen.cpp @@ -429,9 +429,7 @@ void NavigationSystem::Draw() { Matrix mat(p, q, r, pos); if (mesh[i]) { - mesh[i]->Draw( - FLT_MAX, // lod - mat); + mesh[i]->Draw(FLT_MAX, mat); } } Mesh::ProcessZFarMeshes(true); diff --git a/engine/src/python/python_unit_wrap.h b/engine/src/python/python_unit_wrap.h index 677b664b91..f5b60bca31 100644 --- a/engine/src/python/python_unit_wrap.h +++ b/engine/src/python/python_unit_wrap.h @@ -80,7 +80,7 @@ WRAPPED3(bool, InRange, UnitWrapper, target, bool, cone, bool, cap, false ) WRAPPED0(float, CloakVisible, false ) -voidWRAPPED1( Cloak, +voidWRAPPED1( ActivateCloak, bool, cloak ) voidWRAPPED0( RemoveFromSystem ) WRAPPED4(QVector, diff --git a/engine/src/resource/resource.h b/engine/src/resource/resource.h index 4ef41759d1..a43c4e75e3 100644 --- a/engine/src/resource/resource.h +++ b/engine/src/resource/resource.h @@ -37,7 +37,7 @@ class Resource { T adjusted_max_value_; bool no_max_; public: - Resource(const T &value, const T &min_value = 0, const T &max_value = -1); + Resource(const T &value = 0, const T &min_value = 0, const T &max_value = -1); Resource operator+=(const T &value); Resource operator-=(const T &value);