1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
#ifndef WEAPON_H
#define WEAPON_H
#include <functional>
#include <vector>
#include "System/Object.h"
#include "Sim/Misc/DamageArray.h"
#include "Sim/Projectiles/ProjectileParams.h"
#include "Sim/Weapons/WeaponTarget.h"
#include "System/float3.h"
class CUnit;
class CWeaponProjectile;
struct WeaponDef;
class CWeapon : public CObject
{
CR_DECLARE_DERIVED(CWeapon)
public:
CWeapon(CUnit* owner = nullptr, const WeaponDef* def = nullptr);
virtual ~CWeapon();
virtual void Init();
void SetWeaponNum(int num) { weaponNum = num; }
void DependentDied(CObject* o) override;
virtual void SlowUpdate();
virtual void Update();
public:
bool Attack(const SWeaponTarget& newTarget);
void SetAttackTarget(const SWeaponTarget& newTarget); //< does no validity checks!
void DropCurrentTarget();
void AimScriptFinished(bool retCode) { angleGood = retCode; }
bool HaveTarget() const { return (currentTarget.type != Target_None); }
bool HaveUnitTarget() const { return (currentTarget.type == Target_Unit); }
bool HavePosTarget() const { return (currentTarget.type == Target_Pos); }
const SWeaponTarget& GetCurrentTarget() const { return currentTarget; }
const float3& GetCurrentTargetPos() const { return currentTargetPos; }
virtual const float3& GetAimFromPos(bool useMuzzle = false) const { return (useMuzzle? weaponMuzzlePos: aimFromPos); }
bool HasIncomingProjectile(int projID) const { return (std::find(incomingProjectileIDs.begin(), incomingProjectileIDs.end(), projID) != incomingProjectileIDs.end()); }
void AddIncomingProjectile(int projID) { incomingProjectileIDs.push_back(projID); }
public:
/// test if the weapon is able to attack an enemy/mapspot just by its properties (no range check, no FreeLineOfFire check, ...)
virtual bool TestTarget(const float3 tgtPos, const SWeaponTarget& trg) const;
/// test if the enemy/mapspot is in range/angle
virtual bool TestRange(const float3 tgtPos, const SWeaponTarget& trg) const;
/// test if something is blocking our LineOfFire
virtual bool HaveFreeLineOfFire(const float3 srcPos, const float3 tgtPos, const SWeaponTarget& trg) const;
virtual bool CanFire(bool ignoreAngleGood, bool ignoreTargetType, bool ignoreRequestedDir) const;
bool TryTarget(const SWeaponTarget& trg) const;
bool TryTargetRotate(const CUnit* unit, bool userTarget, bool manualFire);
bool TryTargetRotate(float3 tgtPos, bool userTarget, bool manualFire);
bool TryTargetHeading(short heading, const SWeaponTarget& trg);
public:
bool CheckTargetAngleConstraint(const float3 worldTargetDir, const float3 worldWeaponDir) const;
float3 GetTargetBorderPos(const CUnit* targetUnit, const float3 rawTargetPos, const float3 rawTargetDir) const;
void AdjustTargetPosToWater(float3& tgtPos, bool attackGround) const;
float3 GetUnitPositionWithError(const CUnit* unit) const;
float3 GetUnitLeadTargetPos(const CUnit* unit) const;
float3 GetLeadTargetPos(const SWeaponTarget& target) const;
float TargetWeight(const CUnit* unit) const;
static float GetStaticRange2D(const CWeapon* w, const WeaponDef* wd, float modHeightDiff, float modProjGravity);
static float GetLiveRange2D(const CWeapon* w, const WeaponDef* wd, float modHeightDiff, float modProjGravity) { return (w->GetRange2D(0.0f, modHeightDiff)); }
virtual float GetRange2D(float boost, float ydiff) const;
virtual void UpdateProjectileSpeed(const float val) { projectileSpeed = val; }
virtual void UpdateRange(const float val) { range = val; }
bool AutoTarget();
void AimReady(const int value);
void Fire(const bool scriptCall);
float ExperienceErrorScale() const;
float MoveErrorExperience() const;
float AccuracyExperience() const { return (accuracyError * ExperienceErrorScale()); }
float SprayAngleExperience() const { return (sprayAngle * ExperienceErrorScale()); }
float3 SalvoErrorExperience() const { return (salvoError * ExperienceErrorScale()); }
bool StopAttackingTargetIf(const std::function<bool(const SWeaponTarget&)>& pred);
bool StopAttackingAllyTeam(const int ally);
protected:
virtual void FireImpl(const bool scriptCall) {}
virtual void UpdateWantedDir();
virtual float GetPredictedImpactTime(float3 p) const; //< how long time we predict it take for a projectile to reach target
ProjectileParams GetProjectileParams();
static bool TargetUnderWater(const float3 tgtPos, const SWeaponTarget&);
static bool TargetInWater(const float3 tgtPos, const SWeaponTarget&);
void UpdateWeaponPieces(const bool updateAimFrom = true);
void UpdateWeaponVectors();
float3 GetLeadVec(const CUnit* unit) const;
private:
void UpdateAim();
void UpdateFire();
bool UpdateStockpile();
void UpdateSalvo();
void UpdateInterceptTarget();
bool AllowWeaponAutoTarget() const;
bool CobBlockShot() const;
bool CheckAimingAngle() const;
bool CanCallAimingScript(bool validAngle) const;
bool CallAimingScript(bool waitForAim);
void HoldIfTargetInvalid();
bool TryTarget(const float3 tgtPos, const SWeaponTarget& trg, bool preFire = false) const;
public:
CUnit* owner;
CWeapon* slavedTo; // use this weapon to choose target
const WeaponDef* weaponDef;
const DynDamageArray* damages;
int weaponNum; // ordering among owner's weapons
int aimFromPiece;
int muzzlePiece;
int reaimTime; // time between successive reaims in ticks
int reloadTime; // time between successive fires in ticks
int reloadStatus; // next tick the weapon can fire again
int salvoDelay; // delay between shots in a salvo
int salvoSize; // number of shots in a salvo
int projectilesPerShot; // number of projectiles per shot
int nextSalvo; // when the next shot in the current salvo will fire
int salvoLeft; // number of shots left in current salvo
float range;
float projectileSpeed;
float accuracyError; // inaccuracy of whole salvo
float sprayAngle; // inaccuracy of individual shots inside salvo
float predictSpeedMod; // how the weapon predicts the speed of the units goes -> 1 when experience increases
bool hasBlockShot; // set when the script has a BlockShot() function for this weapon
bool hasTargetWeight; // set when there's a TargetWeight() function for this weapon
bool angleGood; // set when script indicated ready to fire
bool avoidTarget; // set when the script wants the weapon to pick a new target, reset once one has been chosen
bool onlyForward; // can only fire in the forward direction of the unit (for aircrafts mostly?)
bool doTargetGroundPos; // (used for bombers) target the ground pos under the unit instead of the center aimPos
bool noAutoTarget;
bool alreadyWarnedAboutMissingPieces;
unsigned int badTargetCategory; // targets in this category get a lot lower targetting priority
unsigned int onlyTargetCategory; // only targets in this category can be targeted (default 0xffffffff)
float buildPercent; // how far we have come on building current missile if stockpiling
int numStockpiled; // how many missiles we have stockpiled
int numStockpileQued; // how many weapons the user have added to our que
int lastAimedFrame; // when the last AimWeapon script callin was performed
int lastTargetRetry; // when we last recalculated target selection
float maxForwardAngleDif; // for onlyForward/!turret weapons, max. angle between owner->frontdir and (targetPos - owner->pos) (derived from UnitDefWeapon::maxAngleDif)
float maxMainDirAngleDif; // for !onlyForward/turret weapons, max. angle from <mainDir> the weapon can aim (derived from WeaponDef::tolerance)
float heightBoostFactor; // controls cannon range height boost. default: -1 -- automatically calculate a more or less sane value
float autoTargetRangeBoost;
unsigned int avoidFlags;
unsigned int collisionFlags;
float3 relAimFromPos; // aimFromPos relative to the unit
float3 aimFromPos; // absolute weapon pos
float3 relWeaponMuzzlePos; // position of the firepoint
float3 weaponMuzzlePos;
float3 weaponDir;
float3 mainDir; // main aiming-direction of weapon
float3 wantedDir; // norm(currentTargetPos - weaponMuzzlePos)
float3 lastRequestedDir; // last angle we called the script with
float3 salvoError; // error vector for the whole salvo
float3 errorVector;
float3 errorVectorAdd;
float muzzleFlareSize; // size of muzzle flare if drawn
protected:
SWeaponTarget currentTarget;
float3 currentTargetPos;
// projectiles that are on the way to our interception zone
// (eg. nuke toward a repulsor, or missile toward a shield)
std::vector<int> incomingProjectileIDs;
};
#endif /* WEAPON_H */
|