1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include "WeaponLoader.h"
4 #include "WeaponDef.h"
5 #include "BeamLaser.h"
6 #include "BombDropper.h"
7 #include "Cannon.h"
8 #include "DGunWeapon.h"
9 #include "EmgCannon.h"
10 #include "FlameThrower.h"
11 #include "LaserCannon.h"
12 #include "LightningCannon.h"
13 #include "MeleeWeapon.h"
14 #include "MissileLauncher.h"
15 #include "NoWeapon.h"
16 #include "PlasmaRepulser.h"
17 #include "Rifle.h"
18 #include "StarburstLauncher.h"
19 #include "TorpedoLauncher.h"
20
21 #include "Game/TraceRay.h"
22 #include "Sim/Misc/GlobalConstants.h"
23 #include "Sim/Units/Unit.h"
24 #include "Sim/Units/UnitDef.h"
25 #include "System/Exceptions.h"
26 #include "System/Log/ILog.h"
27
28 #define DEG2RAD(a) ((a) * (3.141592653f / 180.0f))
29
GetInstance()30 CWeaponLoader* CWeaponLoader::GetInstance()
31 {
32 static CWeaponLoader instance;
33 return &instance;
34 }
35
36
37
LoadWeapons(CUnit * unit)38 void CWeaponLoader::LoadWeapons(CUnit* unit)
39 {
40 const UnitDef* unitDef = unit->unitDef;
41
42 std::vector<CWeapon*>& weapons = unit->weapons;
43 const std::vector<UnitDefWeapon>& defWeapons = unitDef->weapons;
44
45 weapons.reserve(defWeapons.size());
46
47 for (unsigned int i = 0; i < defWeapons.size(); i++) {
48 const UnitDefWeapon* defWeapon = &defWeapons[i];
49 CWeapon* weapon = LoadWeapon(unit, defWeapon);
50
51 weapons.push_back(InitWeapon(unit, weapon, defWeapon));
52 unit->maxRange = std::max(weapon->range, unit->maxRange);
53 }
54 }
55
56
57
LoadWeapon(CUnit * owner,const UnitDefWeapon * defWeapon)58 CWeapon* CWeaponLoader::LoadWeapon(CUnit* owner, const UnitDefWeapon* defWeapon)
59 {
60 CWeapon* weapon = NULL;
61
62 const WeaponDef* weaponDef = defWeapon->def;
63 const std::string& weaponType = weaponDef->type;
64
65 if (weaponType == "Cannon") {
66 weapon = new CCannon(owner, weaponDef);
67 } else if (weaponType == "Rifle") {
68 weapon = new CRifle(owner, weaponDef);
69 } else if (weaponType == "Melee") {
70 weapon = new CMeleeWeapon(owner, weaponDef);
71 } else if (weaponType == "Shield") {
72 weapon = new CPlasmaRepulser(owner, weaponDef);
73 } else if (weaponType == "Flame") {
74 weapon = new CFlameThrower(owner, weaponDef);
75 } else if (weaponType == "MissileLauncher") {
76 weapon = new CMissileLauncher(owner, weaponDef);
77 } else if (weaponType == "AircraftBomb") {
78 weapon = new CBombDropper(owner, weaponDef, false);
79 } else if (weaponType == "TorpedoLauncher") {
80 if (owner->unitDef->canfly && !weaponDef->submissile) {
81 weapon = new CBombDropper(owner, weaponDef, true);
82 } else {
83 weapon = new CTorpedoLauncher(owner, weaponDef);
84 }
85 } else if (weaponType == "LaserCannon") {
86 weapon = new CLaserCannon(owner, weaponDef);
87 } else if (weaponType == "BeamLaser") {
88 weapon = new CBeamLaser(owner, weaponDef);
89 } else if (weaponType == "LightningCannon") {
90 weapon = new CLightningCannon(owner, weaponDef);
91 } else if (weaponType == "EmgCannon") {
92 weapon = new CEmgCannon(owner, weaponDef);
93 } else if (weaponType == "DGun") {
94 // NOTE: no special connection to UnitDef::canManualFire
95 // (any type of weapon may be slaved to the button which
96 // controls manual firing) or the CMD_MANUALFIRE command
97 weapon = new CDGunWeapon(owner, weaponDef);
98 } else if (weaponType == "StarburstLauncher") {
99 weapon = new CStarburstLauncher(owner, weaponDef);
100 } else {
101 weapon = new CNoWeapon(owner, weaponDef);
102 LOG_L(L_ERROR, "weapon-type %s unknown or NOWEAPON", weaponType.c_str());
103 }
104
105 return weapon;
106 }
107
InitWeapon(CUnit * owner,CWeapon * weapon,const UnitDefWeapon * defWeapon)108 CWeapon* CWeaponLoader::InitWeapon(CUnit* owner, CWeapon* weapon, const UnitDefWeapon* defWeapon)
109 {
110 const WeaponDef* weaponDef = defWeapon->def;
111
112 weapon->reloadTime = std::max(1, int(weaponDef->reload * GAME_SPEED));
113 weapon->heightMod = weaponDef->heightmod;
114 weapon->projectileSpeed = weaponDef->projectilespeed;
115
116 weapon->damageAreaOfEffect = weaponDef->damageAreaOfEffect;
117 weapon->craterAreaOfEffect = weaponDef->craterAreaOfEffect;
118 weapon->accuracyError = weaponDef->accuracy;
119 weapon->sprayAngle = weaponDef->sprayAngle;
120
121 weapon->stockpileTime = int(weaponDef->stockpileTime * GAME_SPEED);
122
123 weapon->salvoSize = weaponDef->salvosize;
124 weapon->salvoDelay = int(weaponDef->salvodelay * GAME_SPEED);
125 weapon->projectilesPerShot = weaponDef->projectilespershot;
126
127 weapon->metalFireCost = weaponDef->metalcost;
128 weapon->energyFireCost = weaponDef->energycost;
129
130 weapon->fireSoundId = weaponDef->fireSound.getID(0);
131 weapon->fireSoundVolume = weaponDef->fireSound.getVolume(0);
132
133 weapon->onlyForward = weaponDef->onlyForward;
134 weapon->maxForwardAngleDif = math::cos(DEG2RAD(weaponDef->maxAngle));
135 weapon->maxMainDirAngleDif = defWeapon->maxMainDirAngleDif;
136 weapon->mainDir = defWeapon->mainDir;
137
138 weapon->badTargetCategory = defWeapon->badTargetCat;
139 weapon->onlyTargetCategory = defWeapon->onlyTargetCat;
140
141 // can only slave to an already-loaded weapon
142 if (defWeapon->slavedTo > 0 && defWeapon->slavedTo <= owner->weapons.size()) {
143 weapon->slavedTo = owner->weapons[defWeapon->slavedTo - 1];
144 }
145
146 weapon->fuelUsage = defWeapon->fuelUsage;
147 weapon->targetBorder = weaponDef->targetBorder;
148 weapon->cylinderTargeting = weaponDef->cylinderTargeting;
149 weapon->minIntensity = weaponDef->minIntensity;
150 weapon->heightBoostFactor = weaponDef->heightBoostFactor;
151 weapon->collisionFlags = weaponDef->collisionFlags;
152
153 if (!weaponDef->avoidNeutral) weapon->avoidFlags |= Collision::NONEUTRALS;
154 if (!weaponDef->avoidFriendly) weapon->avoidFlags |= Collision::NOFRIENDLIES;
155 if (!weaponDef->avoidFeature) weapon->avoidFlags |= Collision::NOFEATURES;
156 if (!weaponDef->avoidGround) weapon->avoidFlags |= Collision::NOGROUND;
157
158 weapon->SetWeaponNum(owner->weapons.size());
159 weapon->Init();
160 weapon->UpdateRange(weaponDef->range);
161
162 return weapon;
163 }
164
165