00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <actions/Lightning.h>
00022 #include <common/Defines.h>
00023 #include <common/RandomGenerator.h>
00024 #ifndef S3D_SERVER
00025 #include <sound/SoundUtils.h>
00026 #include <graph/TextureStore.h>
00027 #include <GLEXT/GLState.h>
00028 #include <GLEXT/GLCamera.h>
00029 #include <sprites/ExplosionTextures.h>
00030 #endif
00031 #include <target/TargetContainer.h>
00032 #include <target/TargetDamageCalc.h>
00033 #include <target/TargetLife.h>
00034 #include <target/TargetSpace.h>
00035 #include <engine/ActionController.h>
00036 #include <weapons/AccessoryStore.h>
00037 #include <math.h>
00038
00039 Lightning::Lightning(WeaponLightning *weapon,
00040 WeaponFireContext &weaponContext,
00041 FixedVector &position, FixedVector &velocity) :
00042 ActionReferenced("Lightning"),
00043 totalTime_(0),
00044 weapon_(weapon),
00045 weaponContext_(weaponContext),
00046 position_(position), velocity_(velocity),
00047 texture_(0)
00048 {
00049 }
00050
00051 Lightning::~Lightning()
00052 {
00053 }
00054
00055 void Lightning::init()
00056 {
00057 FixedVector direction = velocity_.Normalize();
00058 std::map<unsigned int, fixed> hurtMap;
00059
00060 generateLightning(0, 1, weapon_->getSize(),
00061 position_, direction, position_, direction,
00062 hurtMap);
00063
00064 std::map<unsigned int, fixed>::iterator hurtItor;
00065 for (hurtItor = hurtMap.begin();
00066 hurtItor != hurtMap.end();
00067 hurtItor++)
00068 {
00069 unsigned int playerId = (*hurtItor).first;
00070 fixed damage = (*hurtItor).second;
00071
00072 Target *target = context_->getTargetContainer().getTargetById(playerId);
00073 if (target)
00074 {
00075 TargetDamageCalc::damageTarget(
00076 *context_, target, weapon_, weaponContext_,
00077 damage, true, false, false);
00078 }
00079 }
00080 }
00081
00082 std::string Lightning::getActionDetails()
00083 {
00084 return S3D::formatStringBuffer("%i,%i,%i %i,%i,%i %s",
00085 position_[0].getInternal(), position_[1].getInternal(), position_[2].getInternal(),
00086 velocity_[0].getInternal(), velocity_[1].getInternal(), velocity_[2].getInternal(),
00087 weapon_->getParent()->getName());
00088 }
00089
00090 void Lightning::simulate(fixed frameTime, bool &remove)
00091 {
00092 #ifndef S3D_SERVER
00093 if (!context_->getServerMode())
00094 {
00095 if (firstTime_)
00096 {
00097 firstTime_ = false;
00098 if (weapon_->getSound() &&
00099 0 != strcmp("none", weapon_->getSound()))
00100 {
00101 SoundBuffer *expSound =
00102 Sound::instance()->fetchOrCreateBuffer(
00103 S3D::getDataFile(weapon_->getSound()));
00104 SoundUtils::playAbsoluteSound(VirtualSoundPriority::eAction,
00105 expSound, position_.asVector());
00106 }
00107 }
00108 }
00109 #endif // #ifndef S3D_SERVER
00110
00111 totalTime_ += frameTime;
00112 remove = (totalTime_ > weapon_->getTotalTime());
00113 Action::simulate(frameTime, remove);
00114 }
00115
00116 void Lightning::draw()
00117 {
00118 #ifndef S3D_SERVER
00119 if (!context_->getServerMode())
00120 {
00121 Vector &cameraPos =
00122 GLCamera::getCurrentCamera()->getCurrentPos();
00123
00124 GLState state(GLState::TEXTURE_ON | GLState::BLEND_ON);
00125 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
00126 glDepthMask(GL_FALSE);
00127 glColor4f(1.0f, 1.0f, 1.0f,
00128 1.0f - totalTime_.asFloat() / weapon_->getTotalTime().asFloat());
00129
00130 if (!texture_)
00131 {
00132 std::string file4 = S3D::getDataFile(weapon_->getTexture());
00133 texture_ = TextureStore::instance()->loadTexture(
00134 file4.c_str(), file4.c_str(), false);
00135 }
00136 texture_->draw();
00137
00138 Vector offset(0.0f, 0.0f, 0.5f);
00139 bool began = false;
00140 float texCoord = 0.0f;
00141 std::list<Segment>::iterator itor;
00142 for (itor = segments_.begin();
00143 itor != segments_.end();
00144 itor++)
00145 {
00146 Segment &segment = (*itor);
00147 Vector cameraDir = (segment.start.asVector() - cameraPos).Normalize();
00148 Vector offset = (segment.direction.asVector() * cameraDir).Normalize();
00149 offset *= 0.4f;
00150
00151 if (!began)
00152 {
00153 began = true;
00154 glBegin(GL_QUAD_STRIP);
00155 }
00156
00157 glTexCoord2f(1.0f, texCoord);
00158 glVertex3fv(segment.start.asVector() + offset * segment.size.asFloat());
00159 glTexCoord2f(0.0f, texCoord);
00160 glVertex3fv(segment.start.asVector() - offset * segment.size.asFloat());
00161 texCoord += 1.0f;
00162
00163 if (segment.endsegment)
00164 {
00165 glTexCoord2f(0.0f, texCoord);
00166 glVertex3fv(segment.end.asVector() - offset * segment.size.asFloat());
00167 glTexCoord2f(1.0f, texCoord);
00168 glVertex3fv(segment.end.asVector() + offset * segment.size.asFloat());
00169 texCoord += 1.0f;
00170
00171 began = false;
00172 glEnd();
00173 }
00174 }
00175
00176 glDepthMask(GL_TRUE);
00177 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00178 }
00179 #endif // #ifndef S3D_SERVER
00180 }
00181
00182 void Lightning::dispaceDirection(FixedVector &direction,
00183 FixedVector &originalDirection, fixed angle)
00184 {
00185 RandomGenerator &generator = context_->getActionController().getRandom();
00186
00187 int breakCount = 0;
00188
00189 FixedVector newdir;
00190 while (breakCount++ < 1000)
00191 {
00192 newdir[0] = (generator.getRandFixed() - fixed(true, 5000)) * 2;
00193 newdir[1] = (generator.getRandFixed() - fixed(true, 5000)) * 2;
00194 newdir[2] = (generator.getRandFixed() - fixed(true, 5000)) * 2;
00195 newdir.StoreNormalize();
00196
00197 fixed a = newdir[0] * direction[0] +
00198 newdir[1] * direction[1] +
00199 newdir[2] * direction[2];
00200 if (a < angle) continue;
00201
00202 fixed b = newdir[0] * originalDirection[0] +
00203 newdir[1] * originalDirection[1] +
00204 newdir[2] * originalDirection[2];
00205 if (b >= weapon_->getDerivAngle())
00206 {
00207 direction = newdir;
00208 return;
00209 }
00210 }
00211 }
00212
00213 void Lightning::generateLightning(int id, int depth, fixed size,
00214 FixedVector &originalPosition, FixedVector &originalDirection,
00215 FixedVector &start, FixedVector &direction,
00216 std::map<unsigned int, fixed> &hurtMap)
00217 {
00218 if (id > 100) return;
00219
00220 RandomGenerator &generator = context_->getActionController().getRandom();
00221 fixed length = weapon_->getSegLength() +
00222 weapon_->getSegVar() * generator.getRandFixed();
00223 FixedVector end = start + direction * length;
00224
00225
00226 segments_.push_back(Segment());
00227 Segment &segment = segments_.back();
00228
00229
00230 segment.start = start;
00231 segment.end = end;
00232 segment.size = size;
00233 segment.direction = direction;
00234 segment.endsegment = false;
00235
00236
00237 damageTargets(segment.end, hurtMap);
00238
00239
00240 if (depth > 1 && generator.getRandFixed() <
00241 weapon_->getDeathProb())
00242 {
00243 segment.endsegment = true;
00244 return;
00245 }
00246
00247
00248 if ((originalPosition - end).Magnitude() >
00249 weapon_->getConeLength())
00250 {
00251 segment.endsegment = true;
00252 return;
00253 }
00254
00255
00256 {
00257 FixedVector newdirection = end - start;
00258 dispaceDirection(newdirection, originalDirection,
00259 weapon_->getAngleVar() * fixed(true, 2500));
00260 generateLightning(id + 1, depth, size,
00261 originalPosition, originalDirection,
00262 end, newdirection,
00263 hurtMap);
00264 }
00265
00266
00267 if (generator.getRandFixed() <=
00268 weapon_->getSplitProb() - fixed(depth - 1) * weapon_->getSplitVar())
00269 {
00270 fixed newsize = size + weapon_->getSizeVar();
00271 if (newsize < weapon_->getMinSize())
00272 newsize = weapon_->getMinSize();
00273
00274 FixedVector newdirection = end - start;
00275 dispaceDirection(newdirection, originalDirection,
00276 weapon_->getAngleVar());
00277 generateLightning(id + 1, depth + 1, newsize,
00278 originalPosition, originalDirection,
00279 end, newdirection,
00280 hurtMap);
00281 }
00282 }
00283
00284 void Lightning::damageTargets(FixedVector &position,
00285 std::map<unsigned int, fixed> &hurtMap)
00286 {
00287 if (weapon_->getSegHurt() <= 0) return;
00288
00289 std::map<unsigned int, Target *> collisionTargets;
00290 context_->getTargetSpace().getCollisionSet(position,
00291 weapon_->getSegHurtRadius() * fixed(true, 15000), collisionTargets);
00292 std::map<unsigned int, Target *>::iterator itor;
00293 for (itor = collisionTargets.begin();
00294 itor != collisionTargets.end();
00295 itor++)
00296 {
00297 Target *target = (*itor).second;
00298 if (target->getAlive() &&
00299 target->getPlayerId() != weaponContext_.getPlayerId())
00300 {
00301 fixed distance = (target->getLife().getTargetPosition() -
00302 position).Magnitude();
00303 if (distance < weapon_->getSegHurtRadius() +
00304 MAX(target->getLife().getSize()[0], target->getLife().getSize()[1]))
00305 {
00306 std::map<unsigned int, fixed>::iterator findItor =
00307 hurtMap.find(target->getPlayerId());
00308 if (findItor == hurtMap.end())
00309 {
00310 hurtMap[target->getPlayerId()] = weapon_->getSegHurt();
00311 }
00312 else
00313 {
00314 hurtMap[target->getPlayerId()] += weapon_->getSegHurt();
00315 }
00316 }
00317 }
00318 }
00319 }