summaryrefslogtreecommitdiffhomepage
path: root/Stars45/Weapon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Stars45/Weapon.cpp')
-rw-r--r--Stars45/Weapon.cpp1184
1 files changed, 0 insertions, 1184 deletions
diff --git a/Stars45/Weapon.cpp b/Stars45/Weapon.cpp
deleted file mode 100644
index b5a0fd3..0000000
--- a/Stars45/Weapon.cpp
+++ /dev/null
@@ -1,1184 +0,0 @@
-/* Starshatter: The Open Source Project
- Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors
- Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors
- Copyright (c) 1997-2006, Destroyer Studios LLC.
-
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Weapon class
-*/
-
-#include "Weapon.h"
-#include "Shot.h"
-#include "Drone.h"
-#include "Contact.h"
-#include "Ship.h"
-#include "Sim.h"
-#include "SimEvent.h"
-#include "Random.h"
-
-#include "NetGame.h"
-#include "NetUtil.h"
-
-#include "Game.h"
-#include "Clock.h"
-#include "ContentBundle.h"
-#include "Solid.h"
-
-// +----------------------------------------------------------------------+
-
-Weapon::Weapon(WeaponDesign* d, int nmuz, Vec3* muzzles, double az, double el)
- : System(WEAPON, d->type, d->name, d->value, d->capacity, d->capacity,
- d->recharge_rate),
- design(d), group(d->group), ammo(-1), ripple_count(0),
- aim_azimuth((float) az), aim_elevation((float) el),
- old_azimuth(0.0f), old_elevation(0.0f), aim_time(0),
- enabled(true), refire(0.0f),
- mass(d->carry_mass), resist(d->carry_resist),
- guided(d->guided), shot_speed(d->speed),
- active_barrel(0), locked(false), centered(false), firing(false), blocked(false),
- index(0), target(0), subtarget(0), beams(0), orders(MANUAL),
- control(SINGLE_FIRE), sweep(SWEEP_TIGHT), turret(0), turret_base(0)
-{
- ZeroMemory(visible_stores, sizeof(visible_stores));
-
- if (design->primary)
- abrv = ContentBundle::GetInstance()->GetText("sys.weapon.primary.abrv");
- else
- abrv = ContentBundle::GetInstance()->GetText("sys.weapon.secondary.abrv");
-
- nbarrels = nmuz;
-
- if (nbarrels > MAX_BARRELS)
- nbarrels = MAX_BARRELS;
-
- if (nbarrels == 0 && design->nbarrels > 0) {
- nbarrels = design->nbarrels;
-
- for (int i = 0; i < nbarrels; i++)
- muzzle_pts[i] = rel_pts[i] = design->muzzle_pts[i] * design->scale;
-
- ammo = design->ammo * nbarrels;
- }
- else if (nbarrels == 1 && design->nstores > 0) {
- nbarrels = design->nstores;
-
- for (int i = 0; i < nbarrels; i++)
- muzzle_pts[i] = rel_pts[i] = (muzzles[0] + design->attachments[i]);
-
- ammo = nbarrels;
- }
- else {
- for (int i = 0; i < nbarrels; i++)
- muzzle_pts[i] = rel_pts[i] = muzzles[i];
-
- ammo = design->ammo * nbarrels;
- }
-
- if (design->syncro)
- active_barrel = -1;
-
- emcon_power[0] = 0;
- emcon_power[1] = 0;
- emcon_power[2] = 100;
-
- aim_az_max = design->aim_az_max;
- aim_az_min = design->aim_az_min;
- aim_az_rest = design->aim_az_rest;
-
- aim_el_max = design->aim_el_max;
- aim_el_min = design->aim_el_min;
- aim_el_rest = design->aim_el_rest;
-}
-
-// +----------------------------------------------------------------------+
-
-Weapon::Weapon(const Weapon& w)
- : System(w), design(w.design), ammo(-1), ripple_count(0),
- enabled(true), refire(0.0f),
- mass(w.mass), resist(w.resist),
- aim_azimuth(w.aim_azimuth), aim_elevation(w.aim_elevation),
- old_azimuth(0.0f), old_elevation(0.0f), aim_time(0),
- guided(w.guided), shot_speed(w.shot_speed),
- active_barrel(0), locked(false), centered(false), firing(false), blocked(false),
- target(0), subtarget(0), beams(0), orders(MANUAL),
- control(SINGLE_FIRE), sweep(SWEEP_TIGHT), group(w.group),
- aim_az_max(w.aim_az_max), aim_az_min(w.aim_az_min), aim_az_rest(w.aim_az_rest),
- aim_el_max(w.aim_el_max), aim_el_min(w.aim_el_min), aim_el_rest(w.aim_el_rest),
- turret(0), turret_base(0)
-{
- Mount(w);
- ZeroMemory(visible_stores, sizeof(visible_stores));
-
- nbarrels = w.nbarrels;
-
- for (int i = 0; i < nbarrels; i++) {
- muzzle_pts[i] = rel_pts[i] = w.muzzle_pts[i];
- }
-
- ammo = design->ammo * nbarrels;
-
- if (design->syncro)
- active_barrel = -1;
-
- if (design->beam) {
- beams = new Shot* [nbarrels];
- ZeroMemory(beams, sizeof(Shot*) * nbarrels);
- }
-
- if (aim_az_rest >= 2*PI)
- aim_az_rest = design->aim_az_rest;
-
- if (aim_el_rest >= 2*PI)
- aim_el_rest = design->aim_el_rest;
-}
-
-// +--------------------------------------------------------------------+
-
-Weapon::~Weapon()
-{
- if (beams) {
- for (int i = 0; i < nbarrels; i++) {
- if (beams[i]) {
- Ignore(beams[i]);
- delete beams[i];
- beams[i] = 0;
- }
- }
-
- delete [] beams;
- }
-
- GRAPHIC_DESTROY(turret);
- GRAPHIC_DESTROY(turret_base);
-
- for (int i = 0; i < MAX_BARRELS; i++)
- GRAPHIC_DESTROY(visible_stores[i]);
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-Weapon::IsPrimary() const
-{
- return design->primary;
-}
-
-bool
-Weapon::IsDrone() const
-{
- return design->drone;
-}
-
-bool
-Weapon::IsDecoy() const
-{
- return design->decoy_type != 0;
-}
-
-bool
-Weapon::IsProbe() const
-{
- return design->probe != 0;
-}
-
-bool
-Weapon::IsMissile() const
-{
- return !design->primary;
-}
-
-bool
-Weapon::IsBeam() const
-{
- return design->beam;
-}
-
-// +--------------------------------------------------------------------+
-
-Shot*
-Weapon::GetBeam(int i)
-{
- if (beams && i >= 0 && i < nbarrels)
- return beams[i];
-
- return 0;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Weapon::SetOwner(Ship* s)
-{
- ship = s;
-
- if (design->turret_model) {
- Solid* t = new Solid;
- t->UseModel(design->turret_model);
- turret = t;
- }
-
- if (design->turret_base_model) {
- Solid* t = new Solid;
- t->UseModel(design->turret_base_model);
- turret_base = t;
- }
-
- if (!design->primary &&
- design->visible_stores &&
- ammo == nbarrels &&
- design->shot_model != 0)
- {
- for (int i = 0; i < nbarrels; i++) {
- Solid* s = new Solid;
- s->UseModel(design->shot_model);
-
- visible_stores[i] = s;
- }
- }
-}
-
-Solid*
-Weapon::GetTurret()
-{
- return turret;
-}
-
-Solid*
-Weapon::GetTurretBase()
-{
- return turret_base;
-}
-
-Solid*
-Weapon::GetVisibleStore(int i)
-{
- if (i >= 0 && i < MAX_BARRELS)
- return visible_stores[i];
-
- return 0;
-}
-
-void
-Weapon::SetAmmo(int a)
-{
- if (a >= 0) {
- if (active_barrel >= 0 && design->visible_stores) {
- while (a < ammo) {
- if (active_barrel >= nbarrels)
- active_barrel = 0;
-
- if (visible_stores[active_barrel]) {
- GRAPHIC_DESTROY(visible_stores[active_barrel]);
- active_barrel++;
- ammo--;
- }
- }
- }
-
- ammo = a;
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Weapon::ExecFrame(double seconds)
-{
- System::ExecFrame(seconds);
-
- if (refire > 0)
- refire -= (float) seconds;
-
- locked = false;
- centered = false;
-
- if (!ship)
- return;
-
- if (orders == POINT_DEFENSE && enabled)
- SelectTarget();
-
- if (beams && !target) {
- for (int i = 0; i < nbarrels; i++) {
- if (beams[i]) {
- // aim beam straight:
- Aim();
- SetBeamPoints(false);
- return;
- }
- }
- }
-
- if (design->self_aiming) {
- Track(target, subtarget);
- }
- else if (turret) {
- ZeroAim();
- }
-
- if (ship->CheckFire())
- return;
-
- // aim beam at target:
- bool aim_beams = false;
-
- if (beams) {
- for (int i = 0; i < nbarrels; i++) {
- if (beams[i]) {
- aim_beams = true;
- SetBeamPoints(true);
- break;
- }
- }
- }
-
- if (!aim_beams) {
- if (ripple_count > 0) {
- if (Fire())
- ripple_count--;
- }
-
- else if (locked && !blocked) {
- if (!ship->IsHostileTo(target))
- return;
-
- if (orders == AUTO && centered) {
- if (energy >= design->charge &&
- (ammo < 0 || target && target->Integrity() >= 1) &&
- objective.length() < design->max_range)
- Fire();
- }
-
- else if (orders == POINT_DEFENSE) {
- if (energy >= design->min_charge &&
- (ammo < 0 || target && target->Integrity() >= 1) &&
- objective.length() < design->max_range)
- Fire();
- }
- }
- }
-}
-
-// +----------------------------------------------------------------------+
-
-void
-Weapon::Distribute(double delivered_energy, double seconds)
-{
- if (UsesWatts()) {
- if (seconds < 0.01)
- seconds = 0.01;
-
- // convert Joules to Watts:
- energy = (float) (delivered_energy/seconds);
- }
-
- else if (!Game::GetInstance()->Paused()) {
- energy += (float) (delivered_energy * 1.25);
-
- if (energy > capacity)
- energy = capacity;
-
- else if (energy < 0)
- energy = 0.0f;
- }
-}
-
-
-// +--------------------------------------------------------------------+
-
-bool
-Weapon::Update(SimObject* obj)
-{
- if (obj == target) {
- target = 0;
- }
-
- else if (beams) {
- for (int i = 0; i < nbarrels; i++)
- if (obj == beams[i])
- beams[i] = 0;
- }
-
- return SimObserver::Update(obj);
-}
-
-const char*
-Weapon::GetObserverName() const
-{
- static char name[256];
- sprintf_s(name, "Weapon %s", design->name.data());
- return name;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Weapon::SetFiringOrders(int o)
-{
- if (o >= MANUAL && o <= POINT_DEFENSE)
- orders = o;
-}
-
-void
-Weapon::SetControlMode(int m)
-{
- if (m >= SINGLE_FIRE && m <= SALVO_FIRE)
- control = m;
-}
-
-void
-Weapon::SetSweep(int s)
-{
- if (s >= SWEEP_NONE && s <= SWEEP_WIDE)
- sweep = s;
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-Weapon::CanTarget(DWORD classification) const
-{
- return (design->target_type & classification) ? true : false;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Weapon::SetTarget(SimObject* targ, System* sub)
-{
- // check self targeting:
- if (targ == (SimObject*) ship)
- return;
-
- // check target class filter:
- if (targ) {
- switch (targ->Type()) {
- case SimObject::SIM_SHIP: {
- Ship* tgt_ship = (Ship*) targ;
-
- if ((tgt_ship->Class() & design->target_type) == 0)
- return;
- }
- break;
-
- case SimObject::SIM_SHOT:
- return;
-
- case SimObject::SIM_DRONE: {
- if ((design->target_type & Ship::DRONE) == 0)
- return;
- }
- break;
-
- default:
- return;
- }
- }
-
- // if ok, target this object:
- if (target != targ) {
- target = targ;
-
- if (target)
- Observe(target);
- }
-
- subtarget = sub;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Weapon::SelectTarget()
-{
- bool select_locked = false;
- SimObject* targ = 0;
- double dist = 1e9;
- double az = 0;
- double el = 0;
-
- if (ammo && enabled && (availability > crit_level)) {
- ZeroAim();
-
- ListIter<Contact> contact = ship->ContactList();
-
- // lock onto any threatening shots first (if we can):
- if (design->target_type & Ship::DRONE) {
- while (++contact) {
- Shot* c_shot = contact->GetShot();
-
- if (c_shot && contact->Threat(ship)) {
-
- // distance from self to target:
- double distance = Point(c_shot->Location() - muzzle_pts[0]).length();
-
- if (distance > design->min_range &&
- distance < design->max_range &&
- distance < dist) {
- // check aim basket:
- select_locked = CanLockPoint(c_shot->Location(), az, el);
-
- if (select_locked) {
- targ = c_shot;
- dist = distance;
- }
- }
- }
- }
- }
-
- // lock onto a threatening ship only if it is (much) closer:
- dist *= 0.2;
- contact.reset();
- while (++contact) {
- Ship* c_ship = contact->GetShip();
-
- if (!c_ship) continue;
-
- // can we lock onto this target?
- if ((c_ship->IsRogue() || c_ship->GetIFF() > 0 && c_ship->GetIFF() != ship->GetIFF()) &&
- (c_ship->Class() & design->target_type) &&
- c_ship->Weapons().size() > 0) {
- // distance from self to target:
- double distance = Point(c_ship->Location() - muzzle_pts[0]).length();
-
- if (distance < design->max_range && distance < dist) {
- // check aim basket:
- select_locked = CanLockPoint(c_ship->Location(), az, el);
-
- if (select_locked) {
- targ = c_ship;
- dist = distance;
- }
- }
- }
- }
- }
-
- if (!ammo || !enabled) {
- SetTarget(0,0);
- locked = false;
- }
-
- else {
- SetTarget(targ, 0);
- }
-}
-
-// +--------------------------------------------------------------------+
-
-int
-Weapon::Track(SimObject* targ, System* sub)
-{
- if (ammo && enabled && (availability > crit_level)) {
- firing = 0;
- Aim();
- }
- else if (turret) {
- ZeroAim();
- }
-
- return locked;
-}
-
-// +--------------------------------------------------------------------+
-
-Shot*
-Weapon::Fire()
-{
- if (Game::GetInstance()->Paused())
- return 0;
-
- if (ship && ship->CheckFire())
- return 0;
-
- if (ship->IsStarship() && target && !centered)
- return 0;
-
- if (beams && active_barrel >= 0 && active_barrel < nbarrels && beams[active_barrel])
- return 0;
-
- Shot* shot = 0;
-
- if (ammo && enabled &&
- (refire <= 0) && (energy > design->min_charge) &&
- (availability > crit_level)) {
-
- refire = design->refire_delay;
-
- NetGame* net_game = NetGame::GetInstance();
- bool net_client = net_game ? net_game->IsClient() : false;
-
- // all barrels
- if (active_barrel < 0) {
- if (net_client || IsPrimary())
- NetUtil::SendWepTrigger(this, nbarrels);
-
- if (!net_game || IsPrimary()) {
- for (int i = 0; i < nbarrels; i++)
- shot = FireBarrel(i);
- }
-
- else if (net_game && net_game->IsServer() && IsMissile()) {
- for (int i = 0; i < nbarrels; i++) {
- shot = FireBarrel(i);
- NetUtil::SendWepRelease(this, shot);
- }
- }
- }
-
- // single barrel
- else {
- if (net_client || IsPrimary())
- NetUtil::SendWepTrigger(this, nbarrels);
-
- if (!net_game || IsPrimary()) {
- shot = FireBarrel(active_barrel++);
- }
-
- else if (net_game && net_game->IsServer() && IsMissile()) {
- shot = FireBarrel(active_barrel++);
- NetUtil::SendWepRelease(this, shot);
- }
-
- if (active_barrel >= nbarrels) {
- active_barrel = 0;
- refire += design->salvo_delay;
- }
- }
-
- if (design->ripple_count > 0 && ripple_count <= 0)
- ripple_count = design->ripple_count-1;
-
- if (status != NOMINAL)
- refire *= 2;
- }
-
- return shot;
-}
-
-// +--------------------------------------------------------------------+
-
-Shot*
-Weapon::NetFirePrimary(SimObject* tgt, System* sub, int count)
-{
- Shot* shot = 0;
-
- if (!IsPrimary() || Game::GetInstance()->Paused())
- return shot;
-
- if (active_barrel < 0 || active_barrel >= nbarrels)
- active_barrel = 0;
-
- target = tgt;
- subtarget = sub;
- aim_time = 0;
-
- for (int i = 0; i < count; i++) {
- shot = FireBarrel(active_barrel++);
-
- if (active_barrel >= nbarrels) {
- active_barrel = 0;
- refire += design->salvo_delay;
- }
- }
-
- if (target)
- Observe(target);
-
- return shot;
-}
-
-Shot*
-Weapon::NetFireSecondary(SimObject* tgt, System* sub, DWORD objid)
-{
- Shot* shot = 0;
-
- if (IsPrimary() || Game::GetInstance()->Paused())
- return shot;
-
- if (active_barrel < 0 || active_barrel >= nbarrels)
- active_barrel = 0;
-
- target = tgt;
- subtarget = sub;
- aim_time = 0;
-
- shot = FireBarrel(active_barrel++);
-
- if (active_barrel >= nbarrels) {
- active_barrel = 0;
- refire += design->salvo_delay;
- }
-
- if (shot)
- shot->SetObjID(objid);
-
- if (target)
- Observe(target);
-
- return shot;
-}
-
-// +--------------------------------------------------------------------+
-
-Shot*
-Weapon::FireBarrel(int n)
-{
- const Point& base_vel = ship->Velocity();
- Shot* shot = 0;
- SimRegion* region = ship->GetRegion();
-
- if (!region || n < 0 || n >= nbarrels || Game::GetInstance()->Paused())
- return 0;
-
- firing = 1;
- Aim();
-
- Camera rail_cam;
- rail_cam.Clone(aim_cam);
-
- Point shotpos = muzzle_pts[n];
- if (design->length > 0)
- shotpos = shotpos + aim_cam.vpn() * design->length;
-
- // guns may be slewed towards target:
- if (design->primary) {
- shot = CreateShot(shotpos, aim_cam, design, ship);
-
- if (shot) {
- shot->SetVelocity(shot->Velocity() + base_vel);
- }
- }
-
- // missiles always launch in rail direction:
- else {
- // unless they are on a mobile launcher
- if (turret && design->self_aiming) {
- shot = CreateShot(shotpos, aim_cam, design, ship);
- shot->SetVelocity(base_vel);
- }
- else {
- shot = CreateShot(shotpos, rail_cam, design, ship);
- if (shot /* && !turret */) {
- Matrix orient = ship->Cam().Orientation();
- if (aim_azimuth != 0) orient.Yaw(aim_azimuth);
- if (aim_elevation != 0) orient.Pitch(aim_elevation);
-
- Point eject = design->eject * orient;
- shot->SetVelocity(base_vel + eject);
- }
- }
-
- if (shot && visible_stores[n]) {
- GRAPHIC_DESTROY(visible_stores[n]);
- }
- }
-
- if (shot) {
- if (ammo > 0)
- ammo--;
-
- if (guided && target)
- shot->SeekTarget(target, subtarget);
-
- float shot_load;
- if (energy > design->charge)
- shot_load = design->charge;
- else
- shot_load = energy;
-
- energy -= shot_load;
- shot->SetCharge(shot_load * availability);
-
- if (target && design->flak && !design->guided) {
- double speed = shot->Velocity().length();
- double range = (target->Location() - shot->Location()).length();
-
- if (range > design->min_range && range < design->max_range) {
- shot->SetFuse(range / speed);
- }
- }
-
- region->InsertObject(shot);
-
- if (beams) {
- beams[n] = shot;
- Observe(beams[n]);
-
- // aim beam at target:
- SetBeamPoints(true);
- }
-
- if (ship) {
- ShipStats* stats = ShipStats::Find(ship->Name());
-
- if (design->primary)
- stats->AddGunShot();
- else if (design->decoy_type == 0 && design->damage > 0)
- stats->AddMissileShot();
- }
- }
-
- return shot;
-}
-
-Shot*
-Weapon::CreateShot(const Point& loc, const Camera& cam, WeaponDesign* dsn, const Ship* own)
-{
- if (dsn->drone)
- return new Drone(loc, cam, dsn, own);
-
- else
- return new Shot(loc, cam, dsn, own);
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Weapon::Orient(const Physical* rep)
-{
- System::Orient(rep);
-
- const Matrix& orientation = rep->Cam().Orientation();
- Point loc = rep->Location();
-
- // align graphics with camera:
- if (turret) {
- if (!design->self_aiming)
- ZeroAim();
-
- const Matrix& aim = aim_cam.Orientation();
-
- turret->MoveTo(mount_loc);
- turret->SetOrientation(aim);
-
- if (turret_base) {
- Matrix base = orientation;
-
- if (design->turret_axis == 1) {
- base.Pitch(aim_elevation);
- base.Pitch(old_elevation);
- }
- else {
- base.Yaw(aim_azimuth);
- base.Yaw(old_azimuth);
- }
-
- turret_base->MoveTo(mount_loc);
- turret_base->SetOrientation(base);
- }
-
- for (int i = 0; i < nbarrels; i++) {
- muzzle_pts[i] = (rel_pts[i] * aim) + mount_loc;
-
- if (visible_stores[i]) {
- visible_stores[i]->SetOrientation(aim);
- visible_stores[i]->MoveTo(muzzle_pts[i]);
- }
- }
- }
- else {
- for (int i = 0; i < nbarrels; i++) {
- muzzle_pts[i] = (rel_pts[i] * orientation) + loc;
-
- if (visible_stores[i]) {
- visible_stores[i]->SetOrientation(orientation);
- visible_stores[i]->MoveTo(muzzle_pts[i]);
- }
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Weapon::SetBeamPoints(bool aim)
-{
- for (int i = 0; i < nbarrels; i++) {
- if (beams && beams[i]) {
- Point from = muzzle_pts[i];
- Point to;
- double len = design->length;
-
- if (len < 1 || len > 1e7)
- len = design->max_range;
-
- if (len < 1)
- len = 3e5;
-
- else if (len > 1e7)
- len = 1e7;
-
- // always use the aim cam, to enforce slew_rate
- to = from + aim_cam.vpn() * len;
-
- beams[i]->SetBeamPoints(from, to);
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Weapon::Aim()
-{
- locked = false;
- centered = false;
-
- FindObjective();
-
- if (target) {
- double az = 0;
- double el = 0;
-
- locked = CanLockPoint(obj_w, az, el, &objective);
-
- double spread_az = design->spread_az;
- double spread_el = design->spread_el;
-
- // beam sweep target:
- if (design->beam) {
- double factor = 0;
- double az_phase = 0;
- double el_phase = 0;
-
- if (target->Type() == SimObject::SIM_SHIP) {
- Ship* s = (Ship*) target;
-
- if (s->IsStarship()) {
- switch (sweep) {
- default:
- case SWEEP_NONE: factor = 0; break;
- case SWEEP_TIGHT: factor = 1; break;
- case SWEEP_WIDE: factor = 2; break;
- }
- }
- }
-
- if (factor > 0) {
- factor *= atan2(target->Radius(), (double) objective.z);
-
- for (int i = 0; i < nbarrels; i++) {
- if (beams && beams[i]) {
- az_phase = sin(beams[i]->Life() * 0.4 * PI);
- el_phase = sin(beams[i]->Life() * 1.0 * PI);
- break;
- }
- }
-
- az += factor * spread_az * az_phase;
- el += factor * spread_el * el_phase * 0.25;
- }
- }
-
- else if (!design->beam) {
- if (spread_az > 0)
- az += Random(-spread_az, spread_az);
-
- if (spread_el > 0)
- el += Random(-spread_el, spread_el);
- }
-
- AimTurret(az, -el);
-
- // check range for guided weapons:
- if (locked && guided) {
- double range = objective.length();
-
- if (range > design->max_track)
- locked = false;
-
- else if (range > design->max_range) {
- if (firing) {
- if (RandomChance(1,4)) // 1 in 4 chance of locking anyway
- locked = false;
- }
- else {
- locked = false;
- }
- }
- }
-
- if (locked) {
- Point tloc = target->Location();
- tloc = Transform(tloc);
-
- if (tloc.z > 1) {
- az = atan2(fabs(tloc.x), tloc.z);
- el = atan2(fabs(tloc.y), tloc.z);
-
- double firing_cone = 10*DEGREES;
-
- if (orders == MANUAL)
- firing_cone = 30*DEGREES;
-
- if (az < firing_cone && el < firing_cone)
- centered = true;
- }
- }
- }
- else {
- AimTurret(aim_az_rest, -aim_el_rest);
- }
-}
-
-void
-Weapon::FindObjective()
-{
- ZeroAim();
-
- if (!target || !design->self_aiming) {
- objective = Point();
- return;
- }
-
- obj_w = target->Location();
-
- if (subtarget) {
- obj_w = subtarget->MountLocation();
- }
- else if (target->Type() == SimObject::SIM_SHIP) {
- Ship* tgt_ship = (Ship*) target;
-
- if (tgt_ship->IsGroundUnit())
- obj_w += Point(0,150,0);
- }
-
- if (!design->beam && shot_speed > 0) {
- // distance from self to target:
- double distance = Point(obj_w - muzzle_pts[0]).length();
-
- // TRUE shot speed is relative to ship speed:
- Point eff_shot_vel = ship->Velocity() + aim_cam.vpn() * shot_speed - target->Velocity();
- double eff_shot_speed = eff_shot_vel.length();
-
- // time to reach target:
- double time = distance / eff_shot_speed;
-
- // where the target will be when the shot reaches it:
- obj_w += (target->Velocity() - ship->Velocity()) * time +
- target->Acceleration() * 0.25 * time * time;
- }
-
- // transform into camera coords:
- objective = Transform(obj_w);
-}
-
-Point
-Weapon::Transform(const Point& pt)
-{
- Point result;
-
- Point obj_t = pt - aim_cam.Pos();
- result.x = obj_t * aim_cam.vrt();
- result.y = obj_t * aim_cam.vup();
- result.z = obj_t * aim_cam.vpn();
-
- return result;
-}
-
-bool
-Weapon::CanLockPoint(const Point& test, double& az, double& el, Point* obj)
-{
- Point pt = Transform(test);
- bool locked = true;
-
- // first compute az:
- if (fabs(pt.z) < 0.1) pt.z = 0.1;
- az = atan(pt.x / pt.z);
- if (pt.z < 0) az -= PI;
- if (az < -PI) az += 2*PI;
-
- // then, rotate target into az-coords to compute el:
- Camera tmp;
- tmp.Clone(aim_cam);
- aim_cam.Yaw(az);
- pt = Transform(test);
- aim_cam.Clone(tmp);
-
- if (fabs(pt.z) < 0.1) pt.z = 0.1;
- el = atan(pt.y / pt.z);
-
- if (obj) *obj = pt;
-
- // is the target in the basket?
- // clamp if necessary:
-
- if (az > aim_az_max) {
- az = aim_az_max;
- locked = false;
- }
- else if (az < aim_az_min) {
- az = aim_az_min;
- locked = false;
- }
-
- if (el > aim_el_max) {
- el = aim_el_max;
- locked = false;
- }
- else if (el < aim_el_min) {
- el = aim_el_min;
- locked = false;
- }
-
- if (IsDrone() && guided) {
- double firing_cone = 10*DEGREES;
-
- if (orders == MANUAL)
- firing_cone = 20*DEGREES;
-
- if (az < firing_cone && el < firing_cone)
- locked = true;
- }
-
- return locked;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Weapon::AimTurret(double az, double el)
-{
- double seconds = (Clock::GetInstance()->GameTime() - aim_time) / 1000.0;
-
- // don't let the weapon turn faster than turret slew rate:
- double max_turn = design->slew_rate * seconds;
-
- if (fabs(az-old_azimuth) > max_turn) {
- if (az > old_azimuth)
- az = old_azimuth + max_turn;
- else
- az = old_azimuth - max_turn;
- }
-
- if (fabs(el-old_elevation) > PI/2 * seconds) {
- if (el > old_elevation)
- el = old_elevation + max_turn;
- else
- el = old_elevation - max_turn;
- }
-
- aim_cam.Yaw(az);
- aim_cam.Pitch(el);
-
- old_azimuth = (float) az;
- old_elevation = (float) el;
-
- aim_time = Clock::GetInstance()->GameTime();
-}
-
-void
-Weapon::ZeroAim()
-{
- aim_cam.Clone(ship->Cam());
- if (aim_azimuth != 0) aim_cam.Yaw(aim_azimuth);
- if (aim_elevation != 0) aim_cam.Pitch(aim_elevation);
-
- aim_cam.MoveTo(muzzle_pts[0]);
-}