diff --git a/Aquaria/Avatar.cpp b/Aquaria/Avatar.cpp index 82c3101..0c9aa0a 100644 --- a/Aquaria/Avatar.cpp +++ b/Aquaria/Avatar.cpp @@ -2921,7 +2921,7 @@ void Avatar::formAbility(int ability) for (i = Shot::shots.begin(); i != Shot::shots.end(); i++) { Shot *s = (*i); - if (s->shotData && !s->shotData->invisible) + if (s->isActive() && s->shotData && !s->shotData->invisible) { if (!s->firer || s->firer->getEntityType()==ET_ENEMY) { @@ -4935,23 +4935,23 @@ void Avatar::updateAura(float dt) */ for (Shot::Shots::iterator i = Shot::shots.begin(); i != Shot::shots.end(); ++i) { - //&& (*i)->life > 0.2f - if ((*i) && dsq->game->isDamageTypeEnemy((*i)->getDamageType()) && (*i)->firer != this - && (!(*i)->shotData || !(*i)->shotData->ignoreShield)) + Shot *s = *i; + if (s->isActive() && dsq->game->isDamageTypeEnemy(s->getDamageType()) && s->firer != this + && (!s->shotData || !s->shotData->ignoreShield)) { - Vector diff = (*i)->position - shieldPosition; + Vector diff = s->position - shieldPosition; if (diff.getSquaredLength2D() < sqr(AURA_SHIELD_RADIUS)) { - shieldPoints -= (*i)->getDamage(); + shieldPoints -= s->getDamage(); auraHitEmitter.start(); - dsq->spawnParticleEffect("ReflectShot", (*i)->position); + dsq->spawnParticleEffect("ReflectShot", s->position); core->sound->playSfx("Shield-Hit"); - (*i)->position += diff; - //(*i)->target = 0; - diff.setLength2D((*i)->maxSpeed); - (*i)->velocity = diff; - (*i)->reflectFromEntity(this); + s->position += diff; + //s->target = 0; + diff.setLength2D(s->maxSpeed); + s->velocity = diff; + s->reflectFromEntity(this); } } } diff --git a/Aquaria/DSQ.cpp b/Aquaria/DSQ.cpp index f67f612..538549b 100644 --- a/Aquaria/DSQ.cpp +++ b/Aquaria/DSQ.cpp @@ -4665,6 +4665,8 @@ void DSQ::onUpdate(float dt) lockMouse(); Network::update(); + + Shot::clearShotGarbage(); } void DSQ::lockMouse() diff --git a/Aquaria/Entity.cpp b/Aquaria/Entity.cpp index 35c1b57..8e7f027 100644 --- a/Aquaria/Entity.cpp +++ b/Aquaria/Entity.cpp @@ -2912,7 +2912,7 @@ void Entity::doSpellAvoidance(float dt, int range, float mod) { Shot *s = (Shot*)(*i); - if ((s->position - this->position).getSquaredLength2D() < sqr(range)) + if (s->isActive() && (s->position - this->position).getSquaredLength2D() < sqr(range)) { for (int j = 0; j < ignoreShotDamageTypes.size(); j++) { diff --git a/Aquaria/Game.cpp b/Aquaria/Game.cpp index 4b838e1..0c20846 100644 --- a/Aquaria/Game.cpp +++ b/Aquaria/Game.cpp @@ -6253,6 +6253,7 @@ void Game::applyState() //core->afterEffectManager->addEffect(new RippleEffect()); } Shot::shots.clear(); + Shot::deleteShots.clear(); backdropQuad = 0; clearObsRows(); inGameMenu = false; @@ -8491,7 +8492,7 @@ void Game::handleShotCollisions(Entity *e, bool hasShield) for (Shot::Shots::iterator i = Shot::shots.begin(); i != Shot::shots.end(); i++) { Shot *shot = *i; - if (isEntityCollideWithShot(e, shot) && (!hasShield || (!shot->shotData || !shot->shotData->ignoreShield))) + if (shot->isActive() && isEntityCollideWithShot(e, shot) && (!hasShield || (!shot->shotData || !shot->shotData->ignoreShield))) { Vector collidePoint = e->position+e->offset; if (e->getNumTargetPoints()>0) @@ -8523,7 +8524,7 @@ void Game::handleShotCollisionsSkeletal(Entity *e) for (Shot::Shots::iterator i = Shot::shots.begin(); i != Shot::shots.end(); i++) { Shot *shot = *i; - if (isEntityCollideWithShot(e, shot)) + if (shot->isActive() && isEntityCollideWithShot(e, shot)) { Bone *b = collideSkeletalVsCircle(e, shot->position, shot->collideRadius); if (b) @@ -8540,7 +8541,7 @@ void Game::handleShotCollisionsHair(Entity *e, int num) for (Shot::Shots::iterator i = Shot::shots.begin(); i != Shot::shots.end(); i++) { Shot *shot = *i; - if (isEntityCollideWithShot(e, shot)) + if (shot->isActive() && isEntityCollideWithShot(e, shot)) { bool b = collideHairVsCircle(e, num, shot->position, 8); if (b) @@ -10886,6 +10887,7 @@ void Game::removeState() debugLog("killAllShots"); Shot::killAllShots(); + Shot::clearShotGarbage(); debugLog("killAllBeams"); Beam::killAllBeams(); debugLog("killAllWebs"); diff --git a/Aquaria/ScriptInterface.cpp b/Aquaria/ScriptInterface.cpp index c7cfa1f..cbaf63b 100644 --- a/Aquaria/ScriptInterface.cpp +++ b/Aquaria/ScriptInterface.cpp @@ -1811,6 +1811,22 @@ luaFunc(web_getNumPoints) luaReturnInt(num); } +luaFunc(getFirstShot) +{ + luaReturnPtr(Shot::getFirstShot()); +} + +luaFunc(getNextShot) +{ + luaReturnPtr(Shot::getNextShot()); +} + +luaFunc(shot_getName) +{ + Shot *s = getShot(L); + luaReturnStr(s ? s->getName() : ""); +} + luaFunc(shot_setOut) { Shot *shot = getShot(L); @@ -1859,11 +1875,26 @@ luaFunc(shot_getFirer) luaReturnPtr(shot ? shot->firer : NULL); } +luaFunc(shot_setFirer) +{ + Shot *shot = getShot(L); + if(shot) + { + Entity *e = lua_isuserdata(L, 2) ? entity(L, 2) : NULL; + shot->firer = e; + } + + luaReturnNil(); +} + luaFunc(shot_setTarget) { Shot *shot = getShot(L); if(shot) - shot->setTarget(entity(L, 2)); + { + Entity *e = lua_isuserdata(L, 2) ? entity(L, 2) : NULL; + shot->setTarget(e); + } luaReturnNil(); } @@ -1873,6 +1904,32 @@ luaFunc(shot_getTarget) luaReturnPtr(shot ? shot->target : NULL); } +luaFunc(shot_setExtraDamage) +{ + Shot *shot = getShot(L); + if(shot) + shot->extraDamage = lua_tonumber(L, 2); + luaReturnNil(); +} + +luaFunc(shot_getExtraDamage) +{ + Shot *shot = getShot(L); + luaReturnNum(shot ? shot->extraDamage : 0.0f); +} + +luaFunc(shot_getDamage) +{ + Shot *shot = getShot(L); + luaReturnNum(shot ? shot->getDamage() : 0.0f); +} + +luaFunc(shot_getDamageType) +{ + Shot *shot = getShot(L); + luaReturnNum(shot ? shot->getDamageType() : DT_NONE); +} + luaFunc(entity_setVel) { Entity *e = entity(L); @@ -5275,7 +5332,10 @@ luaFunc(entity_getRandomTargetPoint) luaFunc(playVisualEffect) { - dsq->playVisualEffect(lua_tonumber(L, 1), Vector(lua_tonumber(L, 2), lua_tonumber(L, 3))); + Entity *target = NULL; + if(lua_isuserdata(L, 4)) + target = entity(L, 4); + dsq->playVisualEffect(lua_tonumber(L, 1), Vector(lua_tonumber(L, 2), lua_tonumber(L, 3)), target); luaReturnNil(); } @@ -7959,13 +8019,21 @@ static const struct { luaRegister(createSpore), + luaRegister(getFirstShot), + luaRegister(getNextShot), luaRegister(shot_setAimVector), luaRegister(shot_setOut), luaRegister(shot_getEffectTime), luaRegister(shot_isIgnoreShield), + luaRegister(shot_setFirer), luaRegister(shot_getFirer), luaRegister(shot_setTarget), luaRegister(shot_getTarget), + luaRegister(shot_setExtraDamage), + luaRegister(shot_getExtraDamage), + luaRegister(shot_getDamage), + luaRegister(shot_getDamageType), + luaRegister(shot_getName), luaRegister(entity_pathBurst), luaRegister(entity_handleShotCollisions), luaRegister(entity_handleShotCollisionsSkeletal), diff --git a/Aquaria/Shot.cpp b/Aquaria/Shot.cpp index af07a4e..12a33cc 100644 --- a/Aquaria/Shot.cpp +++ b/Aquaria/Shot.cpp @@ -26,7 +26,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../BBGE/MathFunctions.h" Shot::Shots Shot::shots; +Shot::Shots Shot::deleteShots; Shot::ShotBank Shot::shotBank; +unsigned int Shot::shotsIter = 0; std::string Shot::shotBankPath = ""; @@ -92,6 +94,9 @@ void ShotData::bankLoad(const std::string &file, const std::string &path) checkDamageTarget = true; } + this->name = file; + stringToLower(this->name); + debugLog(usef); char *data = readFile(core->adjustFilenameCase(usef).c_str()); if (!data) @@ -335,6 +340,7 @@ Shot::Shot() : Quad(), Segmented(0,0) fired = false; target = 0; dead = false; + shotIdx = shots.size(); shots.push_back(this); } @@ -479,7 +485,9 @@ void Shot::setLifeTime(float l) void Shot::onEndOfLife() { destroySegments(0.2); - shots.remove(this); + deleteShots.push_back(this); + dead = true; + if (emitter) { emitter->killParticleEffect(); @@ -531,24 +539,31 @@ void Shot::onHitWall() void Shot::killAllShots() { - std::queueshotDeleteQueue; - for (Shots::iterator i = shots.begin(); i != shots.end(); i++) - { - shotDeleteQueue.push(*i); - } - Shot *s = 0; - while (!shotDeleteQueue.empty()) - { - s = shotDeleteQueue.front(); - if (s) - { - s->safeKill(); - } - shotDeleteQueue.pop(); - } - shots.clear(); + for (Shots::iterator i = shots.begin(); i != shots.end(); ++i) + (*i)->safeKill(); } +void Shot::clearShotGarbage() +{ + for(size_t i = 0; i < deleteShots.size(); ++i) + { + Shot *s = deleteShots[i]; + const unsigned int idx = s->shotIdx; + // move last shot to deleted one and shorten vector + if(idx < shots.size() && shots[idx] == s) + { + Shot *lastshot = shots.back(); + shots[idx] = lastshot; + lastshot->shotIdx = idx; + shots.pop_back(); + } + else + errorLog("Shot::clearShotGarbage(): wrong index in shot vector"); + } + deleteShots.clear(); +} + + void Shot::reflectFromEntity(Entity *e) { Entity *oldFirer = firer; diff --git a/Aquaria/Shot.h b/Aquaria/Shot.h index c94d911..657a55c 100644 --- a/Aquaria/Shot.h +++ b/Aquaria/Shot.h @@ -29,7 +29,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. struct ShotData { ShotData(); - std::string texture; + std::string texture, name; std::string hitSfx, bounceSfx, fireSfx; std::string hitPrt, trailPrt, firePrt, bouncePrt; std::string spawnEntity; @@ -79,11 +79,15 @@ public: //void destroy(); void reflectFromEntity(Entity *e); void setParticleEffect(const std::string &particleEffect); - typedef std::list Shots; - static Shots shots; + typedef std::vector Shots; + static Shots shots, deleteShots; + static unsigned int shotsIter; // for script + static Shot *getFirstShot() { shotsIter = 0; return getNextShot(); } + static Shot *getNextShot() { return shotsIter < shots.size() ? shots[shotsIter++] : NULL; } static std::string shotBankPath; static void targetDied(Entity *t); static void killAllShots(); + static void clearShotGarbage(); Entity *target, *firer; int maxSpeed, targetPt; @@ -117,6 +121,8 @@ public: void updatePosition(); bool isHitEnts() const; bool isObstructed(float dt) const; + inline bool isActive() const { return !dead; } + inline const char *getName() const { return shotData ? shotData->name.c_str() : ""; } float extraDamage; protected: @@ -136,6 +142,9 @@ protected: bool dead; void onUpdate(float dt); + +private: + unsigned int shotIdx; }; class Beam : public Quad