1 ////////////////////////////////////////////////////////////////////////////////
2 //    Scorched3D (c) 2000-2011
3 //
4 //    This file is part of Scorched3D.
5 //
6 //    Scorched3D is free software; you can redistribute it and/or modify
7 //    it under the terms of the GNU General Public License as published by
8 //    the Free Software Foundation; either version 2 of the License, or
9 //    (at your option) any later version.
10 //
11 //    Scorched3D is distributed in the hope that it will be useful,
12 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //    GNU General Public License for more details.
15 //
16 //    You should have received a copy of the GNU General Public License along
17 //    with this program; if not, write to the Free Software Foundation, Inc.,
18 //    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20 
21 #include <actions/Laser.h>
22 #include <engine/ScorchedContext.h>
23 #include <engine/ActionController.h>
24 #include <weapons/AccessoryStore.h>
25 #include <weapons/Shield.h>
26 #include <actions/ShieldHit.h>
27 #include <target/TargetDamage.h>
28 #include <target/TargetContainer.h>
29 #include <target/TargetShield.h>
30 #include <target/TargetLife.h>
31 #include <target/TargetSpace.h>
32 #include <common/Defines.h>
33 #include <common/Logger.h>
34 #ifndef S3D_SERVER
35 	#include <GLEXT/GLState.h>
36 	#include <sprites/ExplosionTextures.h>
37 #endif
38 #include <math.h>
39 #include <set>
40 
Laser(Weapon * weapon,LaserParams * params,FixedVector & position,FixedVector & direction,WeaponFireContext & weaponContext)41 Laser::Laser(Weapon *weapon, LaserParams *params,
42 		FixedVector &position, FixedVector &direction,
43 		WeaponFireContext &weaponContext) :
44 	Action(weaponContext.getInternalContext().getReferenced()),
45 	params_(params),
46 	totalTime_(0),
47 	drawLength_(0),
48 	firstTime_(true),
49 	weaponContext_(weaponContext),
50 	weapon_(weapon),
51 	position_(position),
52 	direction_(direction)
53 {
54 }
55 
~Laser()56 Laser::~Laser()
57 {
58 	delete params_;
59 }
60 
init()61 void Laser::init()
62 {
63 	directionMagnitude_ = direction_.Magnitude();
64 	fixed per = directionMagnitude_ / 50;
65 	length_ = params_->getMinimumDistance() +
66 		(params_->getMaximumDistance() - params_->getMinimumDistance()) * per;
67 	damage_ = params_->getMinimumHurt() +
68 		(params_->getMaximumHurt() - params_->getMinimumHurt()) * (fixed(1) - per);
69 
70 	FixedVector dir = direction_.Normalize();
71 
72 	angXY_ = 180.0f - atan2f(dir[0].asFloat(), dir[1].asFloat()) / 3.14f * 180.0f;
73 	angYZ_ = acosf(dir[2].asFloat()) / 3.14f * 180.0f;
74 
75 	// preset some values from the numberparser expressions
76 	laserTime_ = params_->getTotalTime();
77 	hurtRadius_ = params_->getHurtRadius();
78 }
79 
getActionDetails()80 std::string Laser::getActionDetails()
81 {
82 	return S3D::formatStringBuffer("%s %s %s",
83 		position_.asQuickString(),
84 		direction_.asQuickString(),
85 		weapon_->getParent()->getName());
86 }
87 
simulate(fixed frameTime,bool & remove)88 void Laser::simulate(fixed frameTime, bool &remove)
89 {
90 	if (firstTime_)
91 	{
92 		firstTime_ = false;
93 
94 		if (damage_ > 0 && directionMagnitude_ > 0)
95 		{
96 			std::set<unsigned int> damagedTargets_;
97 
98 			// Build a set of all tanks in the path of the laser
99 			FixedVector pos = position_;
100 			FixedVector dir = direction_.Normalize() / 4;
101 			bool end = false;
102 			while (!end)
103 			{
104 				std::map<unsigned int, Target *> collisionTargets;
105 				context_->getTargetSpace().getCollisionSet(pos,
106 					fixed(params_->getHurtRadius()), collisionTargets);
107 				std::map<unsigned int, Target *>::iterator itor;
108 				for (itor = collisionTargets.begin();
109 					itor != collisionTargets.end();
110 					++itor)
111 				{
112 					Target *current = (*itor).second;
113 					if (current->getAlive() &&
114 						((current->getPlayerId() != weaponContext_.getPlayerId()) ||
115 						params_->getHurtFirer()))
116 					{
117 						Shield::ShieldLaserProofType laserProof = Shield::ShieldLaserProofNone;
118 						if (current->getShield().getCurrentShield())
119 						{
120 							Shield *shield = (Shield *)
121 								current->getShield().getCurrentShield()->getAction();
122 							if (shield->getLaserProof() != Shield::ShieldLaserProofNone)
123 							{
124 								laserProof = shield->getLaserProof();
125 								FixedVector offset = current->getLife().getTargetPosition() - pos;
126 								if (shield->inShield(offset))
127 								{
128 									context_->getActionController().addAction(
129 										new ShieldHit(current->getPlayerId(), pos, 0));
130 
131 									end = true;
132 									break;
133 								}
134 							}
135 						}
136 
137 						if (laserProof != Shield::ShieldLaserProofTotal)
138 						{
139 							FixedVector offset = current->getLife().getTargetPosition() - pos;
140 							fixed targetDistance = offset.Magnitude();
141 
142 							if (targetDistance < params_->getHurtRadius() +
143 								MAX(current->getLife().getSize()[0], current->getLife().getSize()[1]))
144 							{
145 								damagedTargets_.insert(current->getPlayerId());
146 							}
147 						}
148 					}
149 				}
150 
151 				if (!end)
152 				{
153 					pos += dir;
154 					drawLength_ = (pos - position_).Magnitude();
155 					if (drawLength_ > length_) end = true;
156 				}
157 			}
158 
159 			// Subtract set amount from all tanks
160 			std::set<unsigned int>::iterator itor;
161 			for (itor = damagedTargets_.begin();
162 				itor != damagedTargets_.end();
163 				++itor)
164 			{
165 				unsigned int damagedTarget = (*itor);
166 				TargetDamage::damageTarget(*context_,
167 						weapon_, damagedTarget, weaponContext_,
168 						damage_, false, false, false);
169 			}
170 		}
171 	}
172 
173 	totalTime_ += frameTime;
174 
175 	remove = (totalTime_ > laserTime_);
176 	Action::simulate(frameTime, remove);
177 }
178 
draw()179 void Laser::draw()
180 {
181 #ifndef S3D_SERVER
182 	if (!context_->getServerMode() && (drawLength_ > 0))
183 	{
184 		static GLUquadric *obj = 0;
185 		if (!obj)
186 		{
187 			obj = gluNewQuadric();
188 		}
189 		float timePer = (1.0f - totalTime_.asFloat() / laserTime_.asFloat()) * 0.5f;
190 		float radius1 = 0.05f / 2.0f * hurtRadius_.asFloat();
191 		float radius2 = 0.2f / 2.0f * hurtRadius_.asFloat();
192 
193 		glColor4f(1.0f, 1.0f, 1.0f,	timePer);
194 		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
195 
196 		GLTextureSet *set = ExplosionTextures::instance()->getTextureSetByName(params_->getRingTexture());
197 
198 		float floatLength = drawLength_.asFloat();
199 
200 		GLState glState(GLState::TEXTURE_OFF | GLState::BLEND_ON | GLState::ALPHATEST_OFF);
201 		glDepthMask(GL_FALSE);
202 
203 		glPushMatrix();
204 			glTranslatef(
205 				position_[0].asFloat(),
206 				position_[1].asFloat(),
207 				position_[2].asFloat());
208 			glRotatef(angXY_, 0.0f, 0.0f, 1.0f);
209 			glRotatef(angYZ_, 1.0f, 0.0f, 0.0f);
210 
211 			glColor4f(1.0f, 1.0f, 1.0f,	timePer);
212 			gluCylinder(obj, radius1, radius1, floatLength, 3, 1);
213 
214 			glColor4f(
215 				params_->getColor()[0],
216 				params_->getColor()[1],
217 				params_->getColor()[2],
218 				timePer);
219 			gluCylinder(obj, radius2, radius2, floatLength, 5, 1);
220 
221 			if (params_->getRingRadius() > 0)
222 			{
223 				GLState glState(GLState::TEXTURE_ON);
224 				set->getTexture(0)->draw();
225 				glBegin(GL_QUADS);
226 				float moveAmount = 1.0f;
227 				float size = params_->getRingRadius();
228 				for (float f=0.0f; f<floatLength; f+=moveAmount)
229 				{
230 					glTexCoord2f(0.0f, 0.0f);
231 					glVertex3f(-size, -size, f);
232 					glTexCoord2f(0.0f, 1.0f);
233 					glVertex3f(-size, size, f);
234 					glTexCoord2f(1.0f, 1.0f);
235 					glVertex3f(size, size, f);
236 					glTexCoord2f(1.0f, 0.0f);
237 					glVertex3f(size, -size, f);
238 
239 					glTexCoord2f(1.0f, 1.0f);
240 					glVertex3f(size, size, f);
241 					glTexCoord2f(0.0f, 1.0f);
242 					glVertex3f(-size, size, f);
243 					glTexCoord2f(0.0f, 0.0f);
244 					glVertex3f(-size, -size, f);
245 					glTexCoord2f(1.0f, 0.0f);
246 					glVertex3f(size, -size, f);
247 				}
248 				glEnd();
249 			}
250 		glPopMatrix();
251 		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
252 		glDepthMask(GL_TRUE);
253 	}
254 #endif // #ifndef S3D_SERVER
255 }
256