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