1 /************************************************************************************
2 
3 	AstroMenace
4 	Hardcore 3D space scroll-shooter with spaceship upgrade possibilities.
5 	Copyright (c) 2006-2019 Mikhail Kurinnoi, Viewizard
6 
7 
8 	AstroMenace is free software: you can redistribute it and/or modify
9 	it under the terms of the GNU General Public License as published by
10 	the Free Software Foundation, either version 3 of the License, or
11 	(at your option) any later version.
12 
13 	AstroMenace is distributed in the hope that it will be useful,
14 	but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 	GNU General Public License for more details.
17 
18 	You should have received a copy of the GNU General Public License
19 	along with AstroMenace. If not, see <https://www.gnu.org/licenses/>.
20 
21 
22 	Website: https://viewizard.com/
23 	Project: https://github.com/viewizard/astromenace
24 	E-mail: viewizard@viewizard.com
25 
26 *************************************************************************************/
27 
28 // TODO switch to color preset in SetWeaponFire()
29 
30 // TODO switch to enumeration SetWeaponFire()
31 
32 // TODO codestyle should be fixed
33 
34 #include "weapon.h"
35 #include "functions.h"
36 #include "../projectile/projectile.h"
37 #include "../../assets/audio.h"
38 #include "../../assets/texture.h"
39 
40 // NOTE switch to nested namespace definition (namespace A::B::C { ... }) (since C++17)
41 namespace viewizard {
42 namespace astromenace {
43 
44 namespace {
45 
46 std::list<std::shared_ptr<cWeapon>> WeaponList{};
47 
48 struct sWeaponData {
49 	eGameSFX SFX;
50 	bool NeedRotateOnTargeting;
51 	float Armor;
52 	int WeaponLevel;
53 	float EnergyUse;
54 	int Ammo;
55 	float NextFireTime;
56 	sVECTOR3D FireLocation;
57 	sVECTOR3D DestrFireLocation;
58 	std::string NameVW3D;
59 	std::string TextureName;
60 	std::string TextureIllumName;
61 };
62 
63 // earth 1-99
64 #pragma GCC diagnostic push
65 #pragma GCC diagnostic ignored "-Winline"
66 const std::vector<sWeaponData> PresetEarthWeaponData{
67 	// Kinetic
68 	{eGameSFX::WeaponFire_Kinetic1,		true, 25,	1,	1.5f,	3000,	0.4f, sVECTOR3D{0.0f, -0.613f, 2.0f}, sVECTOR3D{0.0f, -0.65f, 1.0f}, "models/earthfighter/weapon5.vw3d", "models/earthfighter/sf-text00.vw2d", "models/earthfighter/sf-illum01.vw2d"},
69 	{eGameSFX::WeaponFire_Kinetic2,		true, 25,	1,	3,	1500,	0.6f, sVECTOR3D{0.0f, -0.613f, 2.93f}, sVECTOR3D{0.0f, -0.6f, 1.8f}, "models/earthfighter/weapon11.vw3d", "models/earthfighter/sf-text00.vw2d", "models/earthfighter/sf-illum01.vw2d"},
70 	{eGameSFX::WeaponFire_Kinetic3,		true, 30,	2,	3.5,	1000,	0.7f, sVECTOR3D{0.0f, -0.613f, 3.33f}, sVECTOR3D{0.0f, -0.6f, 2.2f}, "models/earthfighter/weapon13.vw3d", "models/earthfighter/sf-text00.vw2d", "models/earthfighter/sf-illum01.vw2d"},
71 	{eGameSFX::WeaponFire_Kinetic4,		true, 30,	2,	5,	7000,	0.3f, sVECTOR3D{0.0f, -0.613f, 2.33f}, sVECTOR3D{0.0f, -0.6f, 1.2f}, "models/earthfighter/weapon8.vw3d", "models/earthfighter/sf-text00.vw2d", "models/earthfighter/sf-illum01.vw2d"},
72 	// Ion
73 	{eGameSFX::WeaponFire_Ion1,		true, 10,	1,	7,	1000,	0.7f, sVECTOR3D{0.0f, -0.43f, 2.13f}, sVECTOR3D{0.0f, -0.45f, 1.5f}, "models/earthfighter/weapon1.vw3d", "models/earthfighter/sf-text04.vw2d", "models/earthfighter/sf-illum02.vw2d"},
74 	{eGameSFX::WeaponFire_Ion2,		true, 10,	1,	10,	2000,	0.9f, sVECTOR3D{0.0f, -0.53f, 1.86f}, sVECTOR3D{0.0f, -0.5f, 1.8f}, "models/earthfighter/weapon4.vw3d", "models/earthfighter/sf-text04.vw2d", "models/earthfighter/sf-illum02.vw2d"},
75 	{eGameSFX::WeaponFire_Ion3,		true, 15,	2,	11.5,	3000,	1.0f, sVECTOR3D{0.0f, -0.63f, 2.26f}, sVECTOR3D{0.0f, -0.65f, 2.3f}, "models/earthfighter/weapon6.vw3d", "models/earthfighter/sf-text04.vw2d", "models/earthfighter/sf-illum02.vw2d"},
76 	// Plasma
77 	{eGameSFX::WeaponFire_Plasma1,		true, 10,	2,	20,	2000,	0.6f, sVECTOR3D{0.0f, -0.613f, 2.0f}, sVECTOR3D{0.0f, -0.65f, 1.8f}, "models/earthfighter/weapon3.vw3d", "models/earthfighter/sf-text06.vw2d", "models/earthfighter/sf-illum03.vw2d"},
78 	{eGameSFX::WeaponFire_Plasma2,		true, 15,	2,	30,	1000,	0.7f, sVECTOR3D{0.0f, -0.8f, 1.86f}, sVECTOR3D{0.0f, -0.8f, 1.8f}, "models/earthfighter/weapon2.vw3d", "models/earthfighter/sf-text06.vw2d", "models/earthfighter/sf-illum03.vw2d"},
79 	{eGameSFX::WeaponFire_Plasma3,		true, 10,	3,	50,	800,	0.9f, sVECTOR3D{0.0f, -0.613f, 1.2f}, sVECTOR3D{0.0f, -0.7f, 1.6f}, "models/earthfighter/weapon7.vw3d", "models/earthfighter/sf-text06.vw2d", "models/earthfighter/sf-illum03.vw2d"},
80 	// Maser
81 	{eGameSFX::WeaponFire_Maser1,		true, 10,	3,	50,	800,	3.0f, sVECTOR3D{0.0f, -0.55f, 2.1f}, sVECTOR3D{0.0f, -0.55f, 1.4f}, "models/earthfighter/weapon10.vw3d", "models/earthfighter/sf-text07.vw2d", "models/earthfighter/sf-illum03.vw2d"},
82 	{eGameSFX::WeaponFire_Maser2,		true, 15,	4,	80,	1000,	2.4f, sVECTOR3D{0.0f, -0.55f, 2.5f}, sVECTOR3D{0.0f, -0.55f, 1.8f}, "models/earthfighter/weapon9.vw3d", "models/earthfighter/sf-text07.vw2d", "models/earthfighter/sf-illum03.vw2d"},
83 	// Antimatter
84 	{eGameSFX::WeaponFire_Antimatter,	true, 20,	4,	50,	5000,	0.8f, sVECTOR3D{0.0f, -0.65f, 2.1f}, sVECTOR3D{0.0f, -0.65f, 1.9f}, "models/earthfighter/weapon12.vw3d", "models/earthfighter/sf-text09.vw2d", "models/earthfighter/sf-illum02.vw2d"},
85 	// Laser
86 	{eGameSFX::WeaponFire_Laser,		true, 15,	5,	150,	800,	1.2f, sVECTOR3D{0.0f, -0.6f, 2.5f}, sVECTOR3D{0.0f, -0.6f, 2.1f}, "models/earthfighter/weapon14.vw3d", "models/earthfighter/sf-text05.vw2d", "models/earthfighter/sf-illum03.vw2d"},
87 	// Gauss
88 	{eGameSFX::WeaponFire_Gauss,		true, 20,	5,	150,	2000,	0.7f, sVECTOR3D{0.0f, -0.65f, 3.6f}, sVECTOR3D{0.0f, -0.55f, 2.2f}, "models/earthfighter/weapon15.vw3d", "models/earthfighter/sf-text08.vw2d", "models/earthfighter/sf-illum03.vw2d"},
89 	// Missiles
90 	{eGameSFX::WeaponFire_SmallMissile,	false, 30,	4,	5,	200,	3.0f, sVECTOR3D{0.0f, -0.8f, 4.7f}, sVECTOR3D{0.0f, -0.9f, 1.5f}, "models/earthfighter/lnch1.vw3d", "models/earthfighter/lnch12.tga", ""},
91 	{eGameSFX::WeaponFire_NormalMissile,	false, 30,	4,	15,	400,	8.0f, sVECTOR3D{0.2f, -0.95f, 2.6f}, sVECTOR3D{0.0f, -0.6f, 1.0f}, "models/earthfighter/lnch2.vw3d", "models/earthfighter/lnch12.tga", ""},
92 	{eGameSFX::WeaponFire_Torpedo,		false, 25,	5,	10,	50,	8.0f, sVECTOR3D{0.0f, -0.95f, 4.0f}, sVECTOR3D{0.0f, -0.9f, 1.5f}, "models/earthfighter/lnch3.vw3d", "models/earthfighter/lnch34.tga", ""},
93 	{eGameSFX::WeaponFire_Bomb,		false, 30,	5,	15,	25,	10.0f, sVECTOR3D{0.0f, -0.95f, 5.0f}, sVECTOR3D{0.0f, -0.9f, 1.8f}, "models/earthfighter/lnch4.vw3d", "models/earthfighter/lnch34.tga", ""}
94 };
95 #pragma GCC diagnostic pop
96 
97 // alien 101-199
98 #pragma GCC diagnostic push
99 #pragma GCC diagnostic ignored "-Winline"
100 const std::vector<sWeaponData> PresetAlienWeaponData{
101 	// like Kinetic1
102 	{eGameSFX::WeaponFire_Ion2, true, 1.0f,		1,	1,	5000,	0.7f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
103 	// homing, like Kinetic2
104 	{eGameSFX::WeaponFire_Plasma1, false, 1.0f,	1,	1,	2500,	3.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
105 	// like Kinetic3
106 	{eGameSFX::WeaponFire_Plasma2, true, 1.0f,	1,	1,	2500,	3.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
107 	// homing, like Kinetic3
108 	{eGameSFX::WeaponFire_Plasma2, false, 1.0f,	1,	1,	2500,	2.5f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
109 	// like Kinetic2
110 	{eGameSFX::WeaponFire_Plasma1, true, 1.0f,	1,	1,	2500,	3.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
111 	// emergy mine 1
112 	{eGameSFX::WeaponFire_Antimatter, false, 1.0f,	1,	1,	50,	5.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
113 	// emergy mine 2, with homing
114 	{eGameSFX::WeaponFire_Antimatter, false, 1.0f,	1,	1,	50,	5.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
115 	// like Plasma3
116 	{eGameSFX::WeaponFire_Plasma3, true, 10,	3,	50,	800,	0.9f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
117 	// like Plasma2
118 	{eGameSFX::WeaponFire_Plasma2, true, 15,	2,	25,	1000,	0.8f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
119 	// like Laser (for matherships)
120 	{eGameSFX::WeaponFire_Laser, true, 15,		5,	150,	800,	1.2f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""}
121 };
122 #pragma GCC diagnostic pop
123 
124 // pirate 201-299
125 #pragma GCC diagnostic push
126 #pragma GCC diagnostic ignored "-Winline"
127 const std::vector<sWeaponData> PresetPirateWeaponData{
128 	// turrent 1
129 	{eGameSFX::WeaponFire_Kinetic1, false, 10,	1,	1,	3000,	0.7f, sVECTOR3D{0.0f, 1.5f, 1.0f}, sVECTOR3D{0.0f, 1.5f, 1.0f}, "models/turret/turret-01.vw3d", "models/turret/turrets.tga", ""},
130 	// turrent 2
131 	{eGameSFX::WeaponFire_Kinetic2, false, 10,	1,	1,	3000,	0.7f, sVECTOR3D{0.0f, 1.0f, 0.0f}, sVECTOR3D{0.0f, 1.0f, 0.0f}, "models/turret/turret-02.vw3d", "models/turret/turrets.tga", ""},
132 
133 	// flares
134 	{eGameSFX::WeaponFire_Kinetic1, false, 1.0f,	1,	1,	2500,	4.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
135 
136 	// like Kinetic1
137 	{eGameSFX::WeaponFire_Kinetic1, true, 10,	1,	1.7f,	3000,	0.7f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
138 	// like Missile1
139 	{eGameSFX::WeaponFire_SmallMissile, false, 80,	4,	5,	200,	5.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
140 	// like Missile2
141 	{eGameSFX::WeaponFire_NormalMissile, false, 30,	4,	5,	800,	8.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
142 	// like Ion2
143 	{eGameSFX::WeaponFire_Ion2, true, 10,	1,	10,		2000,	0.9f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
144 	// like Antimatter
145 	{eGameSFX::WeaponFire_Antimatter, true, 20,	4,	50,	5000,	0.8f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
146 	// like Missile3 (torpedo)
147 	{eGameSFX::WeaponFire_Torpedo, false, 25,	5,	10,	200,	8.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
148 	// like Missile4 (bomb)
149 	{eGameSFX::WeaponFire_Bomb, false, 30,	5,	15,		100,	10.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
150 	// like Kinetic2
151 	{eGameSFX::WeaponFire_Kinetic2, true, 25,	1,	3,	1500,	0.6f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
152 	// like Kinetic3
153 	{eGameSFX::WeaponFire_Kinetic3, true, 30,	2,	3.5,	500,	0.7f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
154 	// like Plasma2
155 	{eGameSFX::WeaponFire_Plasma2, true, 15,	2,	25,	1000,	0.8f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
156 
157 	// mine 1
158 	{eGameSFX::WeaponFire_Torpedo, false, 1.0f,	1,	1,	2500,	4.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
159 	// mine 2
160 	{eGameSFX::WeaponFire_Torpedo, false, 1.0f,	1,	1,	2500,	4.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
161 	// mine 31
162 	{eGameSFX::WeaponFire_Bomb, false, 1.0f,	1,	1,	2500,	4.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""},
163 	// mine 4
164 	{eGameSFX::WeaponFire_Bomb, false, 1.0f,	1,	1,	2500,	4.0f, sVECTOR3D{0.0f, 0.0f, 0.0f}, sVECTOR3D{0.0f, 0.0f, 0.0f}, "", "", ""}
165 };
166 #pragma GCC diagnostic pop
167 
168 } // unnamed namespace
169 
170 
171 /*
172  * Create cWeapon object.
173  */
CreateWeapon(const int WeaponNum)174 std::weak_ptr<cWeapon> CreateWeapon(const int WeaponNum)
175 {
176 	// NOTE emplace_front() return reference to the inserted element (since C++17)
177 	//      this two lines could be combined
178 	WeaponList.emplace_front(new cWeapon{WeaponNum}, [](cWeapon *p) {delete p;});
179 	return WeaponList.front();
180 }
181 
182 /*
183  * Update and remove (erase) dead objects.
184  */
UpdateAllWeapon(float Time)185 void UpdateAllWeapon(float Time)
186 {
187 	// NOTE use std::erase_if here (since C++20)
188 	for (auto iter = WeaponList.begin(); iter != WeaponList.end();) {
189 		if (!iter->get()->Update(Time))
190 			iter = WeaponList.erase(iter);
191 		else
192 			++iter;
193 	}
194 }
195 
196 /*
197  * Draw all objects.
198  */
DrawAllWeapons(bool VertexOnlyPass,unsigned int ShadowMap)199 void DrawAllWeapons(bool VertexOnlyPass, unsigned int ShadowMap)
200 {
201 	for (auto &tmpWeapon : WeaponList) {
202 		tmpWeapon.get()->Draw(VertexOnlyPass, ShadowMap);
203 	}
204 }
205 
206 /*
207  * Release particular weapon object.
208  */
ReleaseWeapon(std::weak_ptr<cWeapon> & Object)209 void ReleaseWeapon(std::weak_ptr<cWeapon> &Object)
210 {
211 	auto sharedObject = Object.lock();
212 	if (!sharedObject)
213 		return;
214 
215 	for (auto iter = WeaponList.begin(); iter != WeaponList.end();) {
216 		if (iter->get() == sharedObject.get()) {
217 			WeaponList.erase(iter);
218 			return;
219 		}
220 		++iter;
221 	}
222 }
223 
224 /*
225  * Release particular weapon object during update cycle.
226  */
ReleaseWeaponLazy(std::weak_ptr<cWeapon> & Object)227 void ReleaseWeaponLazy(std::weak_ptr<cWeapon> &Object)
228 {
229 	auto sharedObject = Object.lock();
230 	if (!sharedObject)
231 		return;
232 
233 	// make sure, that the DeleteAfterLeaveScene is disabled,
234 	// in order to prevent possible Lifetime counter reset
235 	sharedObject->DeleteAfterLeaveScene = eDeleteAfterLeaveScene::disabled;
236 	sharedObject->Lifetime = 0.0f;
237 }
238 
239 /*
240  * Release all objects.
241  */
ReleaseAllWeapons()242 void ReleaseAllWeapons()
243 {
244 	WeaponList.clear();
245 }
246 
247 /*
248  * Setup fire gfx.
249  */
SetWeaponFire(std::shared_ptr<cParticleSystem> & ParticleSystem,const int WeaponNum)250 static void SetWeaponFire(std::shared_ptr<cParticleSystem> &ParticleSystem, const int WeaponNum)
251 {
252 	ParticleSystem->Texture = GetPreloadedTextureAsset("gfx/flare1.tga");
253 	ParticleSystem->ParticlesPerSec = 50;
254 	ParticleSystem->IsSuppressed = true;
255 
256 	switch (WeaponNum) {
257 	case 1:
258 		ParticleSystem->ColorStart.r = 1.00f;
259 		ParticleSystem->ColorStart.g = 0.70f;
260 		ParticleSystem->ColorStart.b = 0.30f;
261 		ParticleSystem->ColorEnd.r = 1.00f;
262 		ParticleSystem->ColorEnd.g = 0.70f;
263 		ParticleSystem->ColorEnd.b = 0.00f;
264 		ParticleSystem->AlphaStart = 0.60f;
265 		ParticleSystem->AlphaEnd = 0.10f;
266 		ParticleSystem->SizeStart = 0.4f;
267 		ParticleSystem->SizeVar = 0.05f;
268 		ParticleSystem->SizeEnd = 0.10f;
269 		ParticleSystem->Speed = 3.00f;
270 		ParticleSystem->SpeedVar = 3.00f;
271 		ParticleSystem->Theta = 30.00f;
272 		ParticleSystem->Life = 0.40f;
273 		ParticleSystem->Light = vw_CreatePointLight(sVECTOR3D{0.0f, 0.0f, 0.0f}, 1.0f, 0.7f, 0.15f, 0.0f, 0.02f);
274 		break;
275 	case 2:
276 		ParticleSystem->ColorStart.r = 1.00f;
277 		ParticleSystem->ColorStart.g = 0.50f;
278 		ParticleSystem->ColorStart.b = 0.10f;
279 		ParticleSystem->ColorEnd.r = 1.00f;
280 		ParticleSystem->ColorEnd.g = 0.50f;
281 		ParticleSystem->ColorEnd.b = 0.00f;
282 		ParticleSystem->AlphaStart = 0.60f;
283 		ParticleSystem->AlphaEnd = 0.10f;
284 		ParticleSystem->SizeStart = 0.50f;
285 		ParticleSystem->SizeVar = 0.05f;
286 		ParticleSystem->SizeEnd = 0.10f;
287 		ParticleSystem->Speed = 2.00f;
288 		ParticleSystem->SpeedVar = 3.00f;
289 		ParticleSystem->Theta = 40.00f;
290 		ParticleSystem->Life = 0.40f;
291 		ParticleSystem->Light = vw_CreatePointLight(sVECTOR3D{0.0f, 0.0f, 0.0f}, 1.0f, 0.5f, 0.05f, 0.0f, 0.02f);
292 		break;
293 	case 3:
294 		ParticleSystem->ColorStart.r = 1.00f;
295 		ParticleSystem->ColorStart.g = 0.50f;
296 		ParticleSystem->ColorStart.b = 0.10f;
297 		ParticleSystem->ColorEnd.r = 1.00f;
298 		ParticleSystem->ColorEnd.g = 0.50f;
299 		ParticleSystem->ColorEnd.b = 0.00f;
300 		ParticleSystem->AlphaStart = 0.60f;
301 		ParticleSystem->AlphaEnd = 0.10f;
302 		ParticleSystem->SizeStart = 0.60f;
303 		ParticleSystem->SizeVar = 0.05f;
304 		ParticleSystem->SizeEnd = 0.10f;
305 		ParticleSystem->Speed = 1.00f;
306 		ParticleSystem->SpeedVar = 3.00f;
307 		ParticleSystem->Theta = 50.00f;
308 		ParticleSystem->Life = 0.50f;
309 		ParticleSystem->Light = vw_CreatePointLight(sVECTOR3D{0.0f, 0.0f, 0.0f}, 1.0f, 0.5f, 0.05f, 0.0f, 0.02f);
310 		break;
311 	case 4:
312 		ParticleSystem->ColorStart.r = 1.00f;
313 		ParticleSystem->ColorStart.g = 0.70f;
314 		ParticleSystem->ColorStart.b = 0.30f;
315 		ParticleSystem->ColorEnd.r = 1.00f;
316 		ParticleSystem->ColorEnd.g = 0.70f;
317 		ParticleSystem->ColorEnd.b = 0.00f;
318 		ParticleSystem->AlphaStart = 0.60f;
319 		ParticleSystem->AlphaEnd = 0.10f;
320 		ParticleSystem->SizeStart = 0.30f;
321 		ParticleSystem->SizeVar = 0.05f;
322 		ParticleSystem->SizeEnd = 0.10f;
323 		ParticleSystem->Speed = 3.00f;
324 		ParticleSystem->SpeedVar = 3.00f;
325 		ParticleSystem->Theta = 30.00f;
326 		ParticleSystem->Life = 0.50f;
327 		ParticleSystem->Light = vw_CreatePointLight(sVECTOR3D{0.0f, 0.0f, 0.0f}, 1.0f, 0.7f, 0.15f, 0.0f, 0.02f);
328 		break;
329 	case 5:
330 		ParticleSystem->ColorStart.r = 0.70f;
331 		ParticleSystem->ColorStart.g = 1.00f;
332 		ParticleSystem->ColorStart.b = 0.70f;
333 		ParticleSystem->ColorEnd.r = 0.00f;
334 		ParticleSystem->ColorEnd.g = 0.00f;
335 		ParticleSystem->ColorEnd.b = 0.00f;
336 		ParticleSystem->AlphaStart = 0.60f;
337 		ParticleSystem->AlphaEnd = 0.00f;
338 		ParticleSystem->SizeStart = 0.30f;
339 		ParticleSystem->SizeEnd = 0.00f;
340 		ParticleSystem->Speed = 4.00f;
341 		ParticleSystem->SpeedVar = 1.00f;
342 		ParticleSystem->Theta = 10.00f;
343 		ParticleSystem->Life = 0.40f;
344 		ParticleSystem->Light = vw_CreatePointLight(sVECTOR3D{0.0f, 0.0f, 0.0f}, 0.35f, 0.5f, 0.35f, 0.0f, 0.02f);
345 		break;
346 	case 6:
347 		ParticleSystem->ColorStart.r = 0.70f;
348 		ParticleSystem->ColorStart.g = 1.00f;
349 		ParticleSystem->ColorStart.b = 0.70f;
350 		ParticleSystem->ColorEnd.r = 0.00f;
351 		ParticleSystem->ColorEnd.g = 0.00f;
352 		ParticleSystem->ColorEnd.b = 0.00f;
353 		ParticleSystem->AlphaStart = 0.60f;
354 		ParticleSystem->AlphaEnd = 0.20f;
355 		ParticleSystem->SizeStart = 0.50f;
356 		ParticleSystem->SizeEnd = 0.20f;
357 		ParticleSystem->Speed = 3.00f;
358 		ParticleSystem->SpeedVar = 1.00f;
359 		ParticleSystem->Theta = 20.00f;
360 		ParticleSystem->Life = 0.40f;
361 		ParticleSystem->Light = vw_CreatePointLight(sVECTOR3D{0.0f, 0.0f, 0.0f}, 0.35f, 0.5f, 0.35f, 0.0f, 0.02f);
362 		break;
363 	case 7:
364 		ParticleSystem->ColorStart.r = 0.70f;
365 		ParticleSystem->ColorStart.g = 1.00f;
366 		ParticleSystem->ColorStart.b = 0.70f;
367 		ParticleSystem->ColorEnd.r = 0.00f;
368 		ParticleSystem->ColorEnd.g = 0.00f;
369 		ParticleSystem->ColorEnd.b = 0.00f;
370 		ParticleSystem->AlphaStart = 0.60f;
371 		ParticleSystem->AlphaEnd = 0.20f;
372 		ParticleSystem->SizeStart = 0.50f;
373 		ParticleSystem->SizeEnd = 0.20f;
374 		ParticleSystem->Speed = 6.00f;
375 		ParticleSystem->SpeedVar = 1.00f;
376 		ParticleSystem->Theta = 10.00f;
377 		ParticleSystem->Life = 0.40f;
378 		ParticleSystem->Light = vw_CreatePointLight(sVECTOR3D{0.0f, 0.0f, 0.0f}, 0.35f, 0.5f, 0.35f, 0.0f, 0.02f);
379 		break;
380 	case 8:
381 		ParticleSystem->ColorStart.r = 0.00f;
382 		ParticleSystem->ColorStart.g = 0.50f;
383 		ParticleSystem->ColorStart.b = 1.00f;
384 		ParticleSystem->ColorEnd.r = 0.70f;
385 		ParticleSystem->ColorEnd.g = 1.00f;
386 		ParticleSystem->ColorEnd.b = 1.00f;
387 		ParticleSystem->AlphaStart = 0.60f;
388 		ParticleSystem->AlphaEnd = 0.10f;
389 		ParticleSystem->SizeStart = 0.2f;
390 		ParticleSystem->SizeVar = 0.05f;
391 		ParticleSystem->SizeEnd = 0.2f;
392 		ParticleSystem->Speed = 4.00f;
393 		ParticleSystem->SpeedVar = 3.00f;
394 		ParticleSystem->Theta = 0.00f;
395 		ParticleSystem->Life = 0.30f;
396 		ParticleSystem->CreationType = eParticleCreationType::Sphere;
397 		ParticleSystem->CreationSize(0.4f, 0.4f, 0.4f);
398 		ParticleSystem->Light = vw_CreatePointLight(sVECTOR3D{0.0f, 0.0f, 0.0f}, 0.35f, 0.75f, 1.0f, 0.0f, 0.02f);
399 		break;
400 	case 9:
401 		ParticleSystem->ColorStart.r = 0.00f;
402 		ParticleSystem->ColorStart.g = 0.50f;
403 		ParticleSystem->ColorStart.b = 1.00f;
404 		ParticleSystem->ColorEnd.r = 0.70f;
405 		ParticleSystem->ColorEnd.g = 1.00f;
406 		ParticleSystem->ColorEnd.b = 1.00f;
407 		ParticleSystem->AlphaStart = 0.60f;
408 		ParticleSystem->AlphaEnd = 0.10f;
409 		ParticleSystem->SizeStart = 0.15f;
410 		ParticleSystem->SizeVar = 0.05f;
411 		ParticleSystem->SizeEnd = 0.15f;
412 		ParticleSystem->Speed = 3.00f;
413 		ParticleSystem->SpeedVar = 3.00f;
414 		ParticleSystem->Theta = 0.00f;
415 		ParticleSystem->Life = 0.40f;
416 		ParticleSystem->CreationType = eParticleCreationType::Sphere;
417 		ParticleSystem->CreationSize(0.3f, 0.3f, 0.3f);
418 		ParticleSystem->Light = vw_CreatePointLight(sVECTOR3D{0.0f, 0.0f, 0.0f}, 0.35f, 0.75f, 1.0f, 0.0f, 0.02f);
419 		break;
420 	case 10:
421 		ParticleSystem->ColorStart.r = 0.00f;
422 		ParticleSystem->ColorStart.g = 0.50f;
423 		ParticleSystem->ColorStart.b = 1.00f;
424 		ParticleSystem->ColorEnd.r = 0.70f;
425 		ParticleSystem->ColorEnd.g = 1.00f;
426 		ParticleSystem->ColorEnd.b = 1.00f;
427 		ParticleSystem->AlphaStart = 0.60f;
428 		ParticleSystem->AlphaEnd = 0.10f;
429 		ParticleSystem->SizeStart = 0.30f;
430 		ParticleSystem->SizeVar = 0.05f;
431 		ParticleSystem->SizeEnd = 0.30f;
432 		ParticleSystem->Speed = 3.00f;
433 		ParticleSystem->SpeedVar = 3.00f;
434 		ParticleSystem->Theta = 0.00f;
435 		ParticleSystem->Life = 0.50f;
436 		ParticleSystem->CreationType = eParticleCreationType::Sphere;
437 		ParticleSystem->CreationSize(0.3f, 0.3f, 0.3f);
438 		ParticleSystem->Light = vw_CreatePointLight(sVECTOR3D{0.0f, 0.0f, 0.0f}, 0.35f, 0.75f, 1.0f, 0.0f, 0.02f);
439 		break;
440 	case 11:
441 		ParticleSystem->ColorStart.r = 0.70f;
442 		ParticleSystem->ColorStart.g = 1.00f;
443 		ParticleSystem->ColorStart.b = 0.30f;
444 		ParticleSystem->ColorEnd.r = 0.00f;
445 		ParticleSystem->ColorEnd.g = 1.00f;
446 		ParticleSystem->ColorEnd.b = 0.00f;
447 		ParticleSystem->AlphaStart = 0.60f;
448 		ParticleSystem->AlphaEnd = 0.60f;
449 		ParticleSystem->SizeStart = 0.1f;
450 		ParticleSystem->SizeVar = 0.05f;
451 		ParticleSystem->SizeEnd = 0.00f;
452 		ParticleSystem->Speed = 3.00f;
453 		ParticleSystem->SpeedVar = 3.00f;
454 		ParticleSystem->Theta = 30.00f;
455 		ParticleSystem->Life = 0.30f;
456 		ParticleSystem->IsMagnet = true;
457 		ParticleSystem->ParticlesPerSec = 20;
458 		ParticleSystem->CreationType = eParticleCreationType::Sphere;
459 		ParticleSystem->CreationSize(0.3f, 0.2f, 0.3f);
460 		break;
461 	case 12:
462 		ParticleSystem->ColorStart.r = 0.70f;
463 		ParticleSystem->ColorStart.g = 1.00f;
464 		ParticleSystem->ColorStart.b = 0.30f;
465 		ParticleSystem->ColorEnd.r = 0.00f;
466 		ParticleSystem->ColorEnd.g = 1.00f;
467 		ParticleSystem->ColorEnd.b = 0.00f;
468 		ParticleSystem->AlphaStart = 0.60f;
469 		ParticleSystem->AlphaEnd = 0.60f;
470 		ParticleSystem->SizeStart = 0.1f;
471 		ParticleSystem->SizeVar = 0.05f;
472 		ParticleSystem->SizeEnd = 0.00f;
473 		ParticleSystem->Speed = 3.00f;
474 		ParticleSystem->SpeedVar = 3.00f;
475 		ParticleSystem->Theta = 30.00f;
476 		ParticleSystem->Life = 0.30f;
477 		ParticleSystem->IsMagnet = true;
478 		ParticleSystem->ParticlesPerSec = 20;
479 		ParticleSystem->CreationType = eParticleCreationType::Sphere;
480 		ParticleSystem->CreationSize(0.3f, 0.2f, 0.3f);
481 		break;
482 	case 13:
483 		ParticleSystem->ColorStart.r = 0.70f;
484 		ParticleSystem->ColorStart.g = 1.00f;
485 		ParticleSystem->ColorStart.b = 0.00f;
486 		ParticleSystem->ColorEnd.r = 0.70f;
487 		ParticleSystem->ColorEnd.g = 1.00f;
488 		ParticleSystem->ColorEnd.b = 0.00f;
489 		ParticleSystem->AlphaStart = 0.60f;
490 		ParticleSystem->AlphaEnd = 0.10f;
491 		ParticleSystem->SizeStart = 0.4f;
492 		ParticleSystem->SizeVar = 0.05f;
493 		ParticleSystem->SizeEnd = 0.10f;
494 		ParticleSystem->Speed = 3.00f;
495 		ParticleSystem->SpeedVar = 3.00f;
496 		ParticleSystem->Theta = 30.00f;
497 		ParticleSystem->Life = 0.40f;
498 		ParticleSystem->Light = vw_CreatePointLight(sVECTOR3D{0.0f, 0.0f, 0.0f}, 0.7f, 1.0f, 0.0f, 0.0f, 0.02f);
499 		break;
500 	case 14:
501 		ParticleSystem->ColorStart.r = 1.00f;
502 		ParticleSystem->ColorStart.g = 1.00f;
503 		ParticleSystem->ColorStart.b = 0.00f;
504 		ParticleSystem->ColorEnd.r = 1.00f;
505 		ParticleSystem->ColorEnd.g = 1.00f;
506 		ParticleSystem->ColorEnd.b = 0.00f;
507 		ParticleSystem->AlphaStart = 1.00f;
508 		ParticleSystem->AlphaEnd   = 1.00f;
509 		ParticleSystem->SizeStart  = 0.10f;
510 		ParticleSystem->SizeVar    = 0.05f;
511 		ParticleSystem->SizeEnd    = 0.00f;
512 		ParticleSystem->Speed      = 1.00f;
513 		ParticleSystem->SpeedVar   = 0.00f;
514 		ParticleSystem->Theta      = 360.00f;
515 		ParticleSystem->Life       = 0.20f;
516 		ParticleSystem->ParticlesPerSec = 200;
517 		ParticleSystem->CreationType       = eParticleCreationType::Sphere;
518 		ParticleSystem->CreationSize       = sVECTOR3D{0.2f, 0.2f, 0.8f};
519 		break;
520 	case 15:
521 		ParticleSystem->ColorStart.r = 1.00f;
522 		ParticleSystem->ColorStart.g = 0.50f;
523 		ParticleSystem->ColorStart.b = 0.00f;
524 		ParticleSystem->ColorEnd.r = 1.00f;
525 		ParticleSystem->ColorEnd.g = 0.50f;
526 		ParticleSystem->ColorEnd.b = 0.00f;
527 		ParticleSystem->AlphaStart = 0.60f;
528 		ParticleSystem->AlphaEnd = 0.10f;
529 		ParticleSystem->SizeStart = 0.4f;
530 		ParticleSystem->SizeVar= 0.05f;
531 		ParticleSystem->SizeEnd = 0.10f;
532 		ParticleSystem->Speed = 3.00f;
533 		ParticleSystem->SpeedVar = 3.00f;
534 		ParticleSystem->Theta = 30.00f;
535 		ParticleSystem->Life = 0.40f;
536 		ParticleSystem->Light = vw_CreatePointLight(sVECTOR3D{0.0f, 0.0f, 0.0f}, 1.0f, 0.5f, 0.0f, 0.0f, 0.02f);
537 		break;
538 	case 16:
539 		ParticleSystem->ColorStart.r = 1.00f;
540 		ParticleSystem->ColorStart.g = 0.70f;
541 		ParticleSystem->ColorStart.b = 0.30f;
542 		ParticleSystem->ColorEnd.r = 1.00f;
543 		ParticleSystem->ColorEnd.g = 0.70f;
544 		ParticleSystem->ColorEnd.b = 0.00f;
545 		ParticleSystem->AlphaStart = 0.60f;
546 		ParticleSystem->AlphaEnd = 0.10f;
547 		ParticleSystem->SizeStart = 0.4f;
548 		ParticleSystem->SizeVar = 0.05f;
549 		ParticleSystem->SizeEnd = 0.10f;
550 		ParticleSystem->Speed = 3.00f;
551 		ParticleSystem->SpeedVar = 3.00f;
552 		ParticleSystem->Theta = 30.00f;
553 		ParticleSystem->Life = 0.40f;
554 		break;
555 	case 17:
556 		ParticleSystem->ColorStart.r = 1.00f;
557 		ParticleSystem->ColorStart.g = 0.70f;
558 		ParticleSystem->ColorStart.b = 0.30f;
559 		ParticleSystem->ColorEnd.r = 1.00f;
560 		ParticleSystem->ColorEnd.g = 0.70f;
561 		ParticleSystem->ColorEnd.b = 0.00f;
562 		ParticleSystem->AlphaStart = 0.60f;
563 		ParticleSystem->AlphaEnd = 0.10f;
564 		ParticleSystem->SizeStart = 0.4f;
565 		ParticleSystem->SizeVar = 0.05f;
566 		ParticleSystem->SizeEnd = 0.10f;
567 		ParticleSystem->Speed = 3.00f;
568 		ParticleSystem->SpeedVar = 3.00f;
569 		ParticleSystem->Theta = 30.00f;
570 		ParticleSystem->Life = 0.40f;
571 		break;
572 	case 18:
573 		ParticleSystem->ColorStart.r = 1.00f;
574 		ParticleSystem->ColorStart.g = 0.70f;
575 		ParticleSystem->ColorStart.b = 0.30f;
576 		ParticleSystem->ColorEnd.r = 1.00f;
577 		ParticleSystem->ColorEnd.g = 0.70f;
578 		ParticleSystem->ColorEnd.b = 0.00f;
579 		ParticleSystem->AlphaStart = 0.60f;
580 		ParticleSystem->AlphaEnd = 0.10f;
581 		ParticleSystem->SizeStart = 0.4f;
582 		ParticleSystem->SizeVar = 0.05f;
583 		ParticleSystem->SizeEnd = 0.10f;
584 		ParticleSystem->Speed = 3.00f;
585 		ParticleSystem->SpeedVar = 3.00f;
586 		ParticleSystem->Theta = 30.00f;
587 		ParticleSystem->Life = 0.40f;
588 		break;
589 	case 19:
590 		ParticleSystem->ColorStart.r = 1.00f;
591 		ParticleSystem->ColorStart.g = 0.70f;
592 		ParticleSystem->ColorStart.b = 0.30f;
593 		ParticleSystem->ColorEnd.r = 1.00f;
594 		ParticleSystem->ColorEnd.g = 0.70f;
595 		ParticleSystem->ColorEnd.b = 0.00f;
596 		ParticleSystem->AlphaStart = 0.60f;
597 		ParticleSystem->AlphaEnd = 0.10f;
598 		ParticleSystem->SizeStart = 0.4f;
599 		ParticleSystem->SizeVar = 0.05f;
600 		ParticleSystem->SizeEnd = 0.10f;
601 		ParticleSystem->Speed = 3.00f;
602 		ParticleSystem->SpeedVar = 3.00f;
603 		ParticleSystem->Theta = 30.00f;
604 		ParticleSystem->Life = 0.40f;
605 		break;
606 
607 	default:
608 		std::cerr << __func__ << "(): " << "wrong WeaponNum.\n";
609 		break;
610 	}
611 }
612 
613 /*
614  * Constructor.
615  */
cWeapon(const int WeaponNum)616 cWeapon::cWeapon(const int WeaponNum)
617 {
618 	ObjectStatus = eObjectStatus::Ally;
619 	ObjectType = eObjectType::ShipWeapon;
620 
621 	ShowStatus = false;
622 
623 	if (WeaponNum <= 0) {
624 		std::cerr << __func__ << "(): " << "Couldn't init cWeapon object with Number " << WeaponNum << "\n";
625 		return;
626 	} else if ((WeaponNum >= 1 && WeaponNum <= 99) && ((unsigned int)WeaponNum > PresetEarthWeaponData.size())) {
627 		std::cerr << __func__ << "(): " << "Couldn't init cWeapon(1) object with Number " << WeaponNum << "\n";
628 		return;
629 	} else if ((WeaponNum >= 101 && WeaponNum <= 199) && ((unsigned int)WeaponNum - 100 > PresetAlienWeaponData.size())) {
630 		std::cerr << __func__ << "(): " << "Couldn't init cWeapon(2) object with Number " << WeaponNum << "\n";
631 		return;
632 	} else if ((WeaponNum >= 201 && WeaponNum <= 299) && ((unsigned int)WeaponNum - 200 > PresetPirateWeaponData.size())) {
633 		std::cerr << __func__ << "(): " << "Couldn't init cWeapon(3) object with Number " << WeaponNum << "\n";
634 		return;
635 	}
636 
637 	InternalType = WeaponNum;
638 
639 	// earth 1-99
640 	if (WeaponNum >= 1 && WeaponNum <= 99) {
641 		ObjectStatus = eObjectStatus::Ally;
642 
643 		ArmorCurrentStatus = ArmorInitialStatus = PresetEarthWeaponData[WeaponNum - 1].Armor;
644 		WeaponLevel = PresetEarthWeaponData[WeaponNum - 1].WeaponLevel;
645 		Ammo = AmmoStart =  PresetEarthWeaponData[WeaponNum - 1].Ammo;
646 		NextFireTime =  PresetEarthWeaponData[WeaponNum - 1].NextFireTime;
647 		SFX = PresetEarthWeaponData[WeaponNum - 1].SFX;
648 		NeedRotateOnTargeting = PresetEarthWeaponData[WeaponNum - 1].NeedRotateOnTargeting;
649 
650 		CurrentEnergyAccumulated = EnergyUse = PresetEarthWeaponData[WeaponNum - 1].EnergyUse;
651 		FireLocation = PresetEarthWeaponData[WeaponNum - 1].FireLocation;
652 
653 		DestroyedFireLocation = PresetEarthWeaponData[WeaponNum - 1].DestrFireLocation;
654 		Fire = vw_CreateParticleSystem();
655 		if (auto sharedFire = Fire.lock()) {
656 			sharedFire->SetStartLocation(FireLocation);
657 			sharedFire->Direction = sVECTOR3D{0.0f, 0.0f, 1.0f};
658 			SetWeaponFire(sharedFire, WeaponNum);
659 		}
660 
661 		LoadObjectData(PresetEarthWeaponData[WeaponNum - 1].NameVW3D, *this);
662 
663 		for (unsigned int i = 0; i < Chunks.size(); i++) {
664 			Texture[i] = GetPreloadedTextureAsset(PresetEarthWeaponData[WeaponNum - 1].TextureName);
665 			if (WeaponNum < 16)
666 				TextureIllum[i] = GetPreloadedTextureAsset(PresetEarthWeaponData[WeaponNum - 1].TextureIllumName);
667 		}
668 
669 	}
670 	// alien 101-199
671 	else if ((WeaponNum >= 101) &&
672 		 (WeaponNum <= 199)) {
673 		int IntWeaponNum = WeaponNum - 100;
674 
675 		ObjectStatus = eObjectStatus::Enemy;
676 
677 		ArmorCurrentStatus = ArmorInitialStatus = PresetAlienWeaponData[IntWeaponNum - 1].Armor;
678 		WeaponLevel = PresetAlienWeaponData[IntWeaponNum - 1].WeaponLevel;
679 		Ammo = AmmoStart =  PresetAlienWeaponData[IntWeaponNum - 1].Ammo;
680 		NextFireTime =  PresetAlienWeaponData[IntWeaponNum - 1].NextFireTime;
681 		SFX = PresetAlienWeaponData[IntWeaponNum - 1].SFX;
682 		NeedRotateOnTargeting = PresetAlienWeaponData[IntWeaponNum - 1].NeedRotateOnTargeting;
683 
684 		CurrentEnergyAccumulated = EnergyUse = PresetAlienWeaponData[IntWeaponNum - 1].EnergyUse;
685 		FireLocation = PresetAlienWeaponData[IntWeaponNum - 1].FireLocation;
686 
687 	}
688 	// pirate 201-299
689 	else if ((WeaponNum >= 201) &&
690 		 (WeaponNum <= 299)) {
691 		int IntWeaponNum = WeaponNum - 200;
692 
693 		ObjectStatus = eObjectStatus::Enemy;
694 
695 		ArmorCurrentStatus = ArmorInitialStatus = PresetPirateWeaponData[IntWeaponNum - 1].Armor;
696 		WeaponLevel = PresetPirateWeaponData[IntWeaponNum - 1].WeaponLevel;
697 		Ammo = AmmoStart =  PresetPirateWeaponData[IntWeaponNum - 1].Ammo;
698 		NextFireTime =  PresetPirateWeaponData[IntWeaponNum - 1].NextFireTime;
699 		SFX = PresetPirateWeaponData[IntWeaponNum - 1].SFX;
700 		NeedRotateOnTargeting = PresetPirateWeaponData[IntWeaponNum - 1].NeedRotateOnTargeting;
701 
702 		CurrentEnergyAccumulated = EnergyUse = PresetPirateWeaponData[IntWeaponNum - 1].EnergyUse;
703 		FireLocation = PresetPirateWeaponData[IntWeaponNum - 1].FireLocation;
704 
705 		// турели пиратов
706 		switch (WeaponNum) {
707 		case 201:
708 			WeaponTurret = true;
709 			TargetHorizChunkNum = 0;
710 			TargetVertChunkNum = 1;
711 			TargetVertChunkMaxAngle = 89.0f;
712 			TargetVertChunkMinAngle = 0.0f;
713 
714 			LoadObjectData(PresetPirateWeaponData[IntWeaponNum - 1].NameVW3D, *this);
715 			for (unsigned int i = 0; i < Chunks.size(); i++) {
716 				Texture[i] = GetPreloadedTextureAsset(PresetPirateWeaponData[IntWeaponNum - 1].TextureName);
717 				TextureIllum[i] = 0;
718 			}
719 			break;
720 
721 		case 202:
722 			WeaponTurret = true;
723 			TargetHorizChunkNum = 0;
724 			TargetVertChunkNum = 1;
725 			TargetVertChunkMaxAngle = 89.0f;
726 			TargetVertChunkMinAngle = 20.0f;
727 
728 			LoadObjectData(PresetPirateWeaponData[IntWeaponNum - 1].NameVW3D, *this);
729 			for (unsigned int i = 0; i < Chunks.size(); i++) {
730 				Texture[i] = GetPreloadedTextureAsset(PresetPirateWeaponData[IntWeaponNum - 1].TextureName);
731 				TextureIllum[i] = 0;
732 			}
733 			break;
734 		}
735 
736 		if ((WeaponNum == 201) ||
737 		    (WeaponNum == 202)) {
738 			if (TargetHorizChunkNum != -1) {
739 				BaseBound = Chunks[TargetHorizChunkNum].Location;
740 			}
741 
742 			if (TargetVertChunkNum != -1) {
743 				if (TargetHorizChunkNum != -1)
744 					MiddleBound = Chunks[TargetVertChunkNum].Location -
745 						      Chunks[TargetHorizChunkNum].Location;
746 				else
747 					MiddleBound = Chunks[TargetVertChunkNum].Location;
748 			}
749 
750 			if (TargetVertChunkNum != -1)
751 				WeaponBound = FireLocation - Chunks[TargetVertChunkNum].Location;
752 			else if (TargetHorizChunkNum != -1)
753 				WeaponBound = FireLocation - Chunks[TargetHorizChunkNum].Location;
754 			else
755 				WeaponBound = FireLocation;
756 		}
757 	}
758 }
759 
760 /*
761  * Destructor.
762  */
~cWeapon()763 cWeapon::~cWeapon()
764 {
765 	if (auto sharedFire = Fire.lock()) {
766 		sharedFire->IsSuppressed = true;
767 		sharedFire->DestroyIfNoParticles = true;
768 	}
769 	if (auto sharedDestroyedFire = DestroyedFire.lock()) {
770 		sharedDestroyedFire->IsSuppressed = true;
771 		sharedDestroyedFire->DestroyIfNoParticles = true;
772 	}
773 	if (auto sharedDestroyedSmoke = DestroyedSmoke.lock()) {
774 		sharedDestroyedSmoke->IsSuppressed = true;
775 		sharedDestroyedSmoke->DestroyIfNoParticles = true;
776 	}
777 	if (!LaserMaser.expired()) {
778 		ReleaseProjectile(LaserMaser);
779 		if (vw_IsSoundAvailable(LaserMaserSoundNum))
780 			vw_StopSound(LaserMaserSoundNum, 150);
781 	}
782 }
783 
784 /*
785  * Update.
786  */
Update(float Time)787 bool cWeapon::Update(float Time)
788 {
789 	if (auto sharedLaserMaser = LaserMaser.lock()) {
790 		if (sharedLaserMaser->Lifetime <= 0.0f)
791 			ReleaseProjectile(LaserMaser);
792 	}
793 
794 	if (!cObject3D::Update(Time))
795 		return false;
796 
797 	if (LastFireTime + TimeDelta <= Time)
798 		if (auto sharedFire = Fire.lock())
799 			sharedFire->IsSuppressed = true;
800 
801 	if ((InternalType >= 1) &&
802 	    (InternalType <= 99) &&
803 	    (ArmorCurrentStatus < ArmorInitialStatus) &&
804 	    DestroyedFire.expired()) {
805 		DestroyedFire = vw_CreateParticleSystem();
806 		if (auto sharedDestroyedFire = DestroyedFire.lock()) {
807 			sharedDestroyedFire->ColorStart.r = 1.00f;
808 			sharedDestroyedFire->ColorStart.g = 0.70f;
809 			sharedDestroyedFire->ColorStart.b = 0.30f;
810 			sharedDestroyedFire->ColorEnd.r = 1.00f;
811 			sharedDestroyedFire->ColorEnd.g = 0.00f;
812 			sharedDestroyedFire->ColorEnd.b = 0.00f;
813 			sharedDestroyedFire->AlphaStart = 1.00f;
814 			sharedDestroyedFire->AlphaEnd = 0.10f;
815 			sharedDestroyedFire->SizeStart = 0.20f;
816 			sharedDestroyedFire->SizeVar= 0.10f;
817 			sharedDestroyedFire->SizeEnd = 0.10f;
818 			sharedDestroyedFire->Speed = 8.00f;
819 			sharedDestroyedFire->SpeedVar = 2.00f;
820 			sharedDestroyedFire->Theta = 5.00f;
821 			sharedDestroyedFire->Life = 0.50f * Length / 3.0f;
822 			sharedDestroyedFire->ParticlesPerSec = 70;
823 			sharedDestroyedFire->Texture = GetPreloadedTextureAsset("gfx/flare1.tga");
824 			sharedDestroyedFire->CreationType = eParticleCreationType::Cube;
825 			sharedDestroyedFire->CreationSize(Width / 2.0f, Width / 2.0f, 0.1f);
826 			sharedDestroyedFire->Direction(0.0f, 0.0f, -1.0f);
827 			sharedDestroyedFire->SetStartLocation(DestroyedFireLocation);
828 		}
829 	}
830 
831 	if ((InternalType >= 1) &&
832 	    (InternalType <= 99) &&
833 	    (ArmorCurrentStatus <= 0.0f) &&
834 	    DestroyedSmoke.expired()) {
835 		DestroyedSmoke = vw_CreateParticleSystem();
836 		if (auto sharedDestroyedSmoke = DestroyedSmoke.lock()) {
837 			sharedDestroyedSmoke->ColorStart.r = 1.00f;
838 			sharedDestroyedSmoke->ColorStart.g = 1.00f;
839 			sharedDestroyedSmoke->ColorStart.b = 1.00f;
840 			sharedDestroyedSmoke->ColorEnd.r = 1.00f;
841 			sharedDestroyedSmoke->ColorEnd.g = 1.00f;
842 			sharedDestroyedSmoke->ColorEnd.b = 1.00f;
843 			sharedDestroyedSmoke->AlphaStart = 0.20f;
844 			sharedDestroyedSmoke->AlphaEnd = 0.00f;
845 			sharedDestroyedSmoke->SizeStart = 0.25f;
846 			sharedDestroyedSmoke->SizeVar = 0.10f;
847 			sharedDestroyedSmoke->SizeEnd = 0.00f;
848 			sharedDestroyedSmoke->Speed = 0.00f;
849 			sharedDestroyedSmoke->SpeedVar = 0.00f;
850 			sharedDestroyedSmoke->Theta = 35.00f;
851 			sharedDestroyedSmoke->Life = 2.00f * Length / 3.0f;
852 			sharedDestroyedSmoke->ParticlesPerSec = 300;
853 			sharedDestroyedSmoke->Texture = GetPreloadedTextureAsset("gfx/flare1.tga");
854 			sharedDestroyedSmoke->CreationType = eParticleCreationType::Point;
855 			sharedDestroyedSmoke->CreationSize(Width / 2.5f, Width / 2.5f, 0.1f);
856 			sharedDestroyedSmoke->Direction(0.0f, 0.0f, -1.0f);
857 			sharedDestroyedSmoke->SetStartLocation(DestroyedFireLocation);
858 		}
859 	}
860 
861 	if (InternalType == 17 && SwarmNum > 0)
862 		if (LastFireTime + 0.15f < Time)
863 			if (Ammo > 0 || !GameUnlimitedAmmo) {
864 				LastFireTime = Time;
865 
866 				if (!GameUnlimitedAmmo)
867 					Ammo -= 1;
868 
869 				float CurrentPenalty{1.0f};
870 				if (ObjectStatus == eObjectStatus::Enemy)
871 					CurrentPenalty = static_cast<float>(GameEnemyWeaponPenalty);
872 
873 				switch (SwarmNum) {
874 				case 9:
875 					FireLocation(-0.5f, -0.5f, 2.6f);
876 					break;
877 				case 8:
878 					FireLocation(0.5f, -0.8f, 2.6f);
879 					break;
880 				case 7:
881 					FireLocation(-0.5f, -0.8f, 2.6f);
882 					break;
883 				case 6:
884 					FireLocation(0.5f, -0.5f, 2.6f);
885 					break;
886 				case 5:
887 					FireLocation(-0.2f, -0.95f, 2.6f);
888 					break;
889 				case 4:
890 					FireLocation(0.2f, -0.65f, 2.6f);
891 					break;
892 				case 3:
893 					FireLocation(-0.2f, -0.3f, 2.6f);
894 					break;
895 				case 2:
896 					FireLocation(0.2f, -0.65f, 2.6f);
897 					break;
898 				case 1:
899 					FireLocation(0.2f, -0.3f, 2.6f);
900 					break;
901 				}
902 				vw_Matrix33CalcPoint(FireLocation, CurrentRotationMat);
903 
904 				std::weak_ptr<cProjectile> tmpProjectile = CreateProjectile(InternalType);
905 				if (auto sharedProjectile = tmpProjectile.lock()) {
906 					sharedProjectile->SetLocation(Location + FireLocation);
907 					sharedProjectile->SetRotation(Rotation);
908 					for (auto &tmpGFX : sharedProjectile->GraphicFX) {
909 						if (auto sharedGFX = tmpGFX.lock()) {
910 							if (auto sharedFire = Fire.lock())
911 								sharedGFX->Direction = sharedFire->Direction ^ -1;
912 
913 							if (CurrentPenalty == 2)
914 								sharedGFX->ParticlesPerSec -= (int)(sharedGFX->ParticlesPerSec * 0.33f);
915 							else if (CurrentPenalty == 3)
916 								sharedGFX->ParticlesPerSec -= (int)(sharedGFX->ParticlesPerSec * 0.5f);
917 							sharedGFX->Speed = sharedGFX->Speed / CurrentPenalty;
918 							sharedGFX->Life = sharedGFX->Life * CurrentPenalty;
919 							sharedGFX->MagnetFactor = sharedGFX->MagnetFactor / (CurrentPenalty * CurrentPenalty);
920 						}
921 					}
922 					sharedProjectile->ObjectStatus = ObjectStatus;
923 					sharedProjectile->SpeedStart = sharedProjectile->SpeedEnd = sharedProjectile->SpeedStart / CurrentPenalty;
924 					sharedProjectile->Age = sharedProjectile->Lifetime = sharedProjectile->Age * CurrentPenalty;
925 					sharedProjectile->Damage /= CurrentPenalty;
926 
927 					if (SFX != eGameSFX::none) {
928 						float fVol = 1.0f;
929 						PlayGameSFX(SFX, fVol, sharedProjectile->Location);
930 					}
931 				}
932 				SwarmNum--;
933 			}
934 
935 	if (InternalType == 203 && SwarmNum > 0)
936 		if (LastFireTime + 0.4f < Time)
937 			if (Ammo > 0 || !GameUnlimitedAmmo) {
938 				LastFireTime = Time;
939 
940 				if (!GameUnlimitedAmmo)
941 					Ammo -= 1;
942 
943 				float CurrentPenalty = 1.0f; // FIXME why we need if-else below if we use 1.0f only?
944 
945 				std::weak_ptr<cProjectile> tmpProjectile = CreateProjectile(InternalType);
946 				if (auto sharedProjectile = tmpProjectile.lock()) {
947 					sharedProjectile->SetLocation(Location + FireLocation);
948 					sharedProjectile->SetRotation(Rotation + sVECTOR3D{vw_fRand0() * 30.0f,
949 											   0.0f,
950 											   vw_fRand0() * 30.0f});
951 
952 					for (auto &tmpGFX : sharedProjectile->GraphicFX) {
953 						if (auto sharedGFX = tmpGFX.lock()) {
954 							sharedGFX->Direction = Orientation ^ -1;
955 
956 							if (CurrentPenalty == 2)
957 								sharedGFX->ParticlesPerSec -= (int)(sharedGFX->ParticlesPerSec * 0.33f);
958 							else if (CurrentPenalty == 3)
959 								sharedGFX->ParticlesPerSec -= (int)(sharedGFX->ParticlesPerSec * 0.5f);
960 							sharedGFX->Speed = sharedGFX->Speed / CurrentPenalty;
961 							sharedGFX->Life = sharedGFX->Life * CurrentPenalty;
962 							sharedGFX->MagnetFactor = sharedGFX->MagnetFactor / (CurrentPenalty * CurrentPenalty);
963 						}
964 					}
965 					sharedProjectile->ObjectStatus = ObjectStatus;
966 					sharedProjectile->SpeedStart = sharedProjectile->SpeedEnd = sharedProjectile->SpeedStart / CurrentPenalty;
967 					sharedProjectile->Age = sharedProjectile->Lifetime = sharedProjectile->Age * CurrentPenalty;
968 					sharedProjectile->Damage /= CurrentPenalty;
969 
970 					if (SFX != eGameSFX::none)
971 						PlayGameSFX(SFX, 1.0f, sharedProjectile->Location);
972 				}
973 				SwarmNum--;
974 			}
975 
976 	if (WeaponTurret) {
977 		sVECTOR3D NeedAngle(TargetVertChunkNeedAngle,TargetHorizChunkNeedAngle,0);
978 		sVECTOR3D tmpTargetLocation{};
979 		if (FindTargetLocationWithPrediction(ObjectStatus, Location + FireLocation, InternalType, tmpTargetLocation))
980 			GetTurretOnTargetOrientation(Location + FireLocation, Rotation, CurrentRotationMat,
981 						     tmpTargetLocation, NeedAngle);
982 		TargetHorizChunkNeedAngle = NeedAngle.y;
983 		TargetVertChunkNeedAngle = NeedAngle.x;
984 
985 		if (TargetHorizChunkNum != -1)
986 			if (TargetHorizChunkNeedAngle != TargetHorizChunkCurrentAngle) {
987 				if (fabsf(TargetHorizChunkNeedAngle - TargetHorizChunkCurrentAngle) > 180.0f) {
988 					if (TargetHorizChunkCurrentAngle - TargetHorizChunkNeedAngle > 180.0f)
989 						TargetHorizChunkCurrentAngle -= 360.0f;
990 					if (TargetHorizChunkNeedAngle - TargetHorizChunkCurrentAngle > 180.0f)
991 						TargetHorizChunkCurrentAngle += 360.0f;
992 				}
993 				float NeedRotate = TargetHorizChunkCurrentAngle;
994 
995 				if (TargetHorizChunkNeedAngle > TargetHorizChunkCurrentAngle) {
996 					NeedRotate += 80.0f * TimeDelta / GameEnemyTargetingSpeedPenalty;
997 					if (NeedRotate > TargetHorizChunkNeedAngle)
998 						NeedRotate = TargetHorizChunkNeedAngle;
999 				} else {
1000 					NeedRotate -= 80.0f * TimeDelta / GameEnemyTargetingSpeedPenalty;
1001 					if (NeedRotate < TargetHorizChunkNeedAngle)
1002 						NeedRotate = TargetHorizChunkNeedAngle;
1003 				}
1004 
1005 				TargetHorizChunkCurrentAngle = NeedRotate;
1006 
1007 				for (auto &tmpChunk : Chunks) {
1008 					sVECTOR3D tmp = tmpChunk.Location - Chunks[TargetHorizChunkNum].Location;
1009 
1010 					vw_RotatePointInv(tmp, tmpChunk.Rotation ^ (-1.0f));
1011 
1012 					tmpChunk.Rotation.y = -NeedRotate;
1013 
1014 					vw_RotatePoint(tmp, tmpChunk.Rotation);
1015 
1016 					tmpChunk.Location = tmp + Chunks[TargetHorizChunkNum].Location;
1017 				}
1018 			}
1019 
1020 		if (TargetVertChunkNum != -1)
1021 			if (TargetVertChunkNeedAngle != TargetVertChunkCurrentAngle) {
1022 				float NeedRotate = TargetVertChunkCurrentAngle;
1023 				if (TargetVertChunkNeedAngle > TargetVertChunkCurrentAngle) {
1024 					NeedRotate += 80.0f * TimeDelta / GameEnemyTargetingSpeedPenalty;
1025 					if (NeedRotate > TargetVertChunkNeedAngle)
1026 						NeedRotate = TargetVertChunkNeedAngle;
1027 					if (NeedRotate > TargetVertChunkMaxAngle)
1028 						NeedRotate = TargetVertChunkMaxAngle;
1029 				} else {
1030 					NeedRotate -= 80.0f * TimeDelta / GameEnemyTargetingSpeedPenalty;
1031 					if (NeedRotate < TargetVertChunkNeedAngle)
1032 						NeedRotate = TargetVertChunkNeedAngle;
1033 					if (NeedRotate < TargetVertChunkMinAngle)
1034 						NeedRotate = TargetVertChunkMinAngle;
1035 				}
1036 
1037 				TargetVertChunkCurrentAngle = NeedRotate;
1038 
1039 				sVECTOR3D tmp = Chunks[TargetVertChunkNum].Location - Chunks[TargetVertChunkNum].Location; // FIXME (0,0,0)???
1040 
1041 				vw_RotatePointInv(tmp, Chunks[TargetVertChunkNum].Rotation ^ (-1.0f));
1042 
1043 				Chunks[TargetVertChunkNum].Rotation.x = -NeedRotate;
1044 
1045 				vw_RotatePoint(tmp, Chunks[TargetVertChunkNum].Rotation);
1046 
1047 				Chunks[TargetVertChunkNum].Location = tmp + Chunks[TargetVertChunkNum].Location;
1048 			}
1049 
1050 		sVECTOR3D RotationBase = Rotation;
1051 		sVECTOR3D BaseBoundTMP = BaseBound;
1052 		vw_RotatePoint(BaseBoundTMP, RotationBase);
1053 
1054 		sVECTOR3D RotationMiddle = Rotation;
1055 		sVECTOR3D MiddleBoundTMP = MiddleBound;
1056 		if (TargetHorizChunkNum != -1)
1057 			RotationMiddle = Chunks[TargetHorizChunkNum].Rotation + Rotation;
1058 		vw_RotatePoint(MiddleBoundTMP, RotationMiddle);
1059 
1060 		sVECTOR3D RotationWeapon = Rotation;
1061 		if (TargetVertChunkNum != -1)
1062 			RotationWeapon = Chunks[TargetVertChunkNum].Rotation + Rotation;
1063 
1064 		sVECTOR3D WeaponBoundTMP = WeaponBound;
1065 		vw_RotatePoint(WeaponBoundTMP, RotationWeapon);
1066 
1067 		FireLocation = BaseBoundTMP + MiddleBoundTMP + WeaponBoundTMP;
1068 
1069 		if ((TargetHorizChunkNum == -1) && (TargetVertChunkNum == -1))
1070 			RotationWeapon = sVECTOR3D{TargetVertChunkNeedAngle,
1071 						   TargetHorizChunkNeedAngle,
1072 						   0.0f} +
1073 					 Rotation;
1074 
1075 		Orientation = sVECTOR3D{0.0f, 0.0f, 1.0f};
1076 		vw_RotatePoint(Orientation, RotationWeapon);
1077 	}
1078 
1079 	return true;
1080 }
1081 
1082 /*
1083  * Set rotation.
1084  */
SetRotation(const sVECTOR3D & NewRotation)1085 void cWeapon::SetRotation(const sVECTOR3D &NewRotation)
1086 {
1087 	cObject3D::SetRotation(NewRotation);
1088 
1089 	if (!WeaponTurret) {
1090 		vw_Matrix33CalcPoint(FireLocation, OldInvRotationMat);
1091 		vw_Matrix33CalcPoint(FireLocation, CurrentRotationMat);
1092 
1093 		if (auto sharedFire = Fire.lock()) {
1094 			sharedFire->MoveSystem(Location + FireLocation);
1095 			sharedFire->SetStartLocation(Location + FireLocation);
1096 			sharedFire->RotateSystemByAngle(Rotation);
1097 		}
1098 	} else {
1099 		sVECTOR3D RotationBase = Rotation;
1100 		sVECTOR3D BaseBoundTMP = BaseBound;
1101 		vw_RotatePoint(BaseBoundTMP, RotationBase);
1102 
1103 		sVECTOR3D RotationMiddle = Rotation;
1104 		sVECTOR3D MiddleBoundTMP = MiddleBound;
1105 		if (TargetHorizChunkNum != -1)
1106 			RotationMiddle = Chunks[TargetHorizChunkNum].Rotation + Rotation;
1107 		vw_RotatePoint(MiddleBoundTMP, RotationMiddle);
1108 
1109 		sVECTOR3D RotationWeapon = Rotation;
1110 		if (TargetVertChunkNum != -1)
1111 			RotationWeapon = Chunks[TargetVertChunkNum].Rotation + Rotation;
1112 
1113 		sVECTOR3D WeaponBoundTMP = WeaponBound;
1114 		vw_RotatePoint(WeaponBoundTMP, RotationWeapon);
1115 
1116 		FireLocation = BaseBoundTMP + MiddleBoundTMP + WeaponBoundTMP;
1117 
1118 		if ((TargetHorizChunkNum == -1) && (TargetVertChunkNum == -1))
1119 			RotationWeapon = sVECTOR3D{TargetVertChunkNeedAngle,
1120 						   TargetHorizChunkNeedAngle,
1121 						   0.0f} +
1122 					 Rotation;
1123 
1124 		Orientation = sVECTOR3D{0.0f, 0.0f, 1.0f};
1125 		vw_RotatePoint(Orientation, RotationWeapon);
1126 	}
1127 
1128 	if (auto sharedDestroyedFire = DestroyedFire.lock()) {
1129 		vw_Matrix33CalcPoint(DestroyedFireLocation, OldInvRotationMat);
1130 		vw_Matrix33CalcPoint(DestroyedFireLocation, CurrentRotationMat);
1131 		sharedDestroyedFire->MoveSystem(Location + DestroyedFireLocation);
1132 		sharedDestroyedFire->SetStartLocation(Location + DestroyedFireLocation);
1133 		sharedDestroyedFire->RotateSystemByAngle(Rotation);
1134 	}
1135 	if (auto sharedDestroyedSmoke = DestroyedSmoke.lock()) {
1136 		sharedDestroyedSmoke->MoveSystemLocation(Location + DestroyedFireLocation);
1137 		sharedDestroyedSmoke->RotateSystemByAngle(Rotation);
1138 	}
1139 	if (auto sharedLaserMaser = LaserMaser.lock()) {
1140 		vw_Matrix33CalcPoint(sharedLaserMaser->ProjectileCenter, OldInvRotationMat);
1141 		vw_Matrix33CalcPoint(sharedLaserMaser->ProjectileCenter, CurrentRotationMat);
1142 		sharedLaserMaser->SetLocation(Location + FireLocation + sharedLaserMaser->ProjectileCenter);
1143 		sharedLaserMaser->SetRotation(NewRotation);
1144 	}
1145 }
1146 
1147 /*
1148  * Set location.
1149  */
SetLocation(const sVECTOR3D & NewLocation)1150 void cWeapon::SetLocation(const sVECTOR3D &NewLocation)
1151 {
1152 	cObject3D::SetLocation(NewLocation);
1153 
1154 	if (auto sharedFire = Fire.lock()) {
1155 		sharedFire->MoveSystem(NewLocation + FireLocation);
1156 		sharedFire->SetStartLocation(NewLocation + FireLocation);
1157 	}
1158 	if (auto sharedDestroyedFire = DestroyedFire.lock()) {
1159 		sharedDestroyedFire->MoveSystem(NewLocation + DestroyedFireLocation);
1160 		sharedDestroyedFire->SetStartLocation(NewLocation + DestroyedFireLocation);
1161 	}
1162 	if (auto sharedDestroyedSmoke = DestroyedSmoke.lock())
1163 		sharedDestroyedSmoke->MoveSystemLocation(NewLocation + DestroyedFireLocation);
1164 
1165 	if (auto sharedLaserMaser = LaserMaser.lock())
1166 		sharedLaserMaser->SetLocation(Location + FireLocation + sharedLaserMaser->ProjectileCenter);
1167 
1168 	if (vw_IsSoundAvailable(LaserMaserSoundNum))
1169 		vw_SetSoundLocation(LaserMaserSoundNum, Location.x, Location.y, Location.z);
1170 }
1171 
1172 /*
1173  * Fire.
1174  */
WeaponFire(float Time)1175 bool cWeapon::WeaponFire(float Time)
1176 {
1177 	if (InternalType == 0)
1178 		return false;
1179 
1180 	float CurrentPenalty{1.0f};
1181 	if (ObjectStatus == eObjectStatus::Enemy)
1182 		CurrentPenalty = static_cast<float>(GameEnemyWeaponPenalty);
1183 
1184 	if (InternalType == 203) // flares
1185 		CurrentPenalty = 1.0f;
1186 
1187 	if (Time < LastFireTime + NextFireTime * CurrentPenalty)
1188 		return false;
1189 	LastFireTime = Time;
1190 
1191 	if ((InternalType >= 1) &&
1192 	    (InternalType <= 99)) {
1193 		bool Misfire{false};
1194 		if ((ArmorCurrentStatus < ArmorInitialStatus) &&
1195 		    (ArmorCurrentStatus / ArmorInitialStatus > vw_fRand()))
1196 			Misfire = true;
1197 
1198 		if ((ArmorCurrentStatus <= 0.0f) ||
1199 		    (Ammo == 0) ||
1200 		    Misfire) {
1201 			float fVol = 1.0f;
1202 
1203 			switch (InternalType) {
1204 			case 1: // Kinetic1
1205 			case 2: // Kinetic2
1206 			case 3: // Kinetic3
1207 			case 4: // Kinetic4
1208 				PlayGameSFX(eGameSFX::WeaponMalfunction_Kinetic, fVol, Location);
1209 				break;
1210 
1211 			case 5: // Ion1
1212 			case 6: // Ion2
1213 			case 7: // Ion3
1214 			case 8: // Plasma1
1215 			case 9: // Plasma2
1216 			case 10: // Plasma3
1217 				PlayGameSFX(eGameSFX::WeaponMalfunction_Particle, fVol, Location);
1218 				break;
1219 
1220 			case 11: // Maser1
1221 			case 12: // Maser2
1222 			case 14: // Laser
1223 				PlayGameSFX(eGameSFX::WeaponMalfunction_Beam, fVol, Location);
1224 				break;
1225 
1226 			case 13: // Antimatter
1227 
1228 			case 15: // Gauss
1229 				PlayGameSFX(eGameSFX::WeaponMalfunction_Energy, fVol, Location);
1230 				break;
1231 
1232 			case 16: // missiles
1233 			case 17: // swarm
1234 			case 18: // torpedo
1235 			case 19: // bomb
1236 				PlayGameSFX(eGameSFX::WeaponMalfunction_Launcher, fVol, Location);
1237 				break;
1238 			}
1239 
1240 			return false;
1241 		}
1242 
1243 		if (ObjectStatus == eObjectStatus::Player) {
1244 			if (CurrentEnergyAccumulated < EnergyUse)
1245 				return false;
1246 			else
1247 				CurrentEnergyAccumulated = 0.0f;
1248 		}
1249 
1250 		if (!GameUnlimitedAmmo)
1251 			Ammo -= 1;
1252 
1253 		if (InternalType < 16) {
1254 			if (auto sharedFire = Fire.lock())
1255 				sharedFire->IsSuppressed = false;
1256 		}
1257 
1258 	}
1259 
1260 	sVECTOR3D RotationWeapon = Rotation;
1261 	if (WeaponTurret) {
1262 		sVECTOR3D RotationBase = Rotation;
1263 		sVECTOR3D BaseBoundTMP = BaseBound;
1264 		vw_RotatePoint(BaseBoundTMP, RotationBase);
1265 
1266 		sVECTOR3D RotationMiddle = Rotation;
1267 		sVECTOR3D MiddleBoundTMP = MiddleBound;
1268 		if (TargetHorizChunkNum != -1)
1269 			RotationMiddle = Chunks[TargetHorizChunkNum].Rotation + Rotation;
1270 		vw_RotatePoint(MiddleBoundTMP, RotationMiddle);
1271 
1272 		if (TargetVertChunkNum != -1)
1273 			RotationWeapon = Chunks[TargetVertChunkNum].Rotation + Rotation;
1274 
1275 		sVECTOR3D WeaponBoundTMP = WeaponBound;
1276 		vw_RotatePoint(WeaponBoundTMP, RotationWeapon);
1277 
1278 		FireLocation = BaseBoundTMP + MiddleBoundTMP + WeaponBoundTMP;
1279 
1280 		if (TargetHorizChunkNum == -1 && TargetVertChunkNum == -1) {
1281 			RotationWeapon = sVECTOR3D{TargetVertChunkNeedAngle,
1282 						   TargetHorizChunkNeedAngle,
1283 						   0.0f} +
1284 					 Rotation;
1285 		}
1286 	}
1287 
1288 	std::weak_ptr<cProjectile> tmpProjectile = CreateProjectile(InternalType);
1289 	if (auto sharedProjectile = tmpProjectile.lock()) {
1290 		if (sharedProjectile->ProjectileType == 2) {
1291 			if (!LaserMaser.expired())
1292 				ReleaseProjectile(LaserMaser);
1293 
1294 			LaserMaser = tmpProjectile;
1295 			vw_Matrix33CalcPoint(sharedProjectile->ProjectileCenter, CurrentRotationMat);
1296 			sharedProjectile->SetLocation(Location + FireLocation + sharedProjectile->ProjectileCenter);
1297 		} else {
1298 			if (sharedProjectile->ProjectileType == 0) {
1299 				sVECTOR3D AddPos(0.0f, 0.0f, 4.0f);
1300 				if (WeaponTurret)
1301 					AddPos = sVECTOR3D{0.0f, 0.0f, 2.0f};
1302 
1303 				vw_RotatePoint(AddPos, RotationWeapon);
1304 				sharedProjectile->SetLocation(Location+FireLocation + AddPos);
1305 			} else
1306 				sharedProjectile->SetLocation(Location+FireLocation);
1307 		}
1308 
1309 		if ((sharedProjectile->ProjectileType == 3) ||
1310 		    (sharedProjectile->ProjectileType == 4)) {
1311 			sharedProjectile->SetRotation(RotationWeapon);
1312 			for (auto &tmpGFX : sharedProjectile->GraphicFX) {
1313 				if (auto sharedGFX = tmpGFX.lock())
1314 					sharedGFX->Direction = Orientation;
1315 			}
1316 			sharedProjectile->ObjectStatus = ObjectStatus;
1317 			sharedProjectile->SpeedStart = sharedProjectile->SpeedEnd = sharedProjectile->SpeedStart / CurrentPenalty;
1318 			sharedProjectile->Age = sharedProjectile->Lifetime = sharedProjectile->Age;
1319 			sharedProjectile->Damage /= CurrentPenalty;
1320 
1321 			// FIXME should be revised, we use -3 in order to 'convert' to proper projectile type
1322 			sharedProjectile->ProjectileType = sharedProjectile->ProjectileType - 3;
1323 		} else {
1324 			sharedProjectile->SetRotation(RotationWeapon);
1325 			for (auto &tmpGFX : sharedProjectile->GraphicFX) {
1326 				if (auto sharedGFX = tmpGFX.lock()) {
1327 					sharedGFX->Direction = Orientation;
1328 					// учитываем пенальти для визуальных эффектов
1329 					sharedGFX->ParticlesPerSec = (int)(sharedGFX->ParticlesPerSec / CurrentPenalty);
1330 
1331 					sharedGFX->Speed = sharedGFX->Speed / CurrentPenalty;
1332 					sharedGFX->Life = sharedGFX->Life * CurrentPenalty;
1333 					sharedGFX->MagnetFactor = sharedGFX->MagnetFactor / (CurrentPenalty * CurrentPenalty);
1334 				}
1335 			}
1336 			sharedProjectile->ObjectStatus = ObjectStatus;
1337 			sharedProjectile->SpeedStart = sharedProjectile->SpeedEnd = sharedProjectile->SpeedStart / CurrentPenalty;
1338 			sharedProjectile->Age = sharedProjectile->Lifetime = sharedProjectile->Age * CurrentPenalty;
1339 			sharedProjectile->Damage /= CurrentPenalty;
1340 		}
1341 	}
1342 
1343 	if (SFX != eGameSFX::none) {
1344 		float fVol = 1.0f;
1345 		LaserMaserSoundNum = PlayGameSFX(SFX, fVol, Location + FireLocation);
1346 		if (LaserMaser.expired())
1347 			LaserMaserSoundNum = 0;
1348 	}
1349 
1350 	if (InternalType == 17) // 9 more swarm missiles
1351 		SwarmNum = 9;
1352 
1353 	if (InternalType == 203) // 4 more flares
1354 		SwarmNum = 4;
1355 
1356 	return true;
1357 }
1358 
1359 } // astromenace namespace
1360 } // viewizard namespace
1361