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