mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-02-03 18:14:01 +00:00
Initial support for scriptable shots
This commit is contained in:
parent
eb1f38d86c
commit
fec1cc7ac2
3 changed files with 96 additions and 57 deletions
|
@ -4817,6 +4817,7 @@ Shot *Game::fireShot(const std::string &bankShot, Entity *firer, Entity *target,
|
||||||
|
|
||||||
|
|
||||||
core->getTopStateData()->addRenderObject(s, LR_PROJECTILES);
|
core->getTopStateData()->addRenderObject(s, LR_PROJECTILES);
|
||||||
|
s->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
|
145
Aquaria/Shot.cpp
145
Aquaria/Shot.cpp
|
@ -251,11 +251,15 @@ void ShotData::bankLoad(const std::string &file, const std::string &path)
|
||||||
// if having weirdness, check for these
|
// if having weirdness, check for these
|
||||||
errorLog(file + " : unidentified token: " + token);
|
errorLog(file + " : unidentified token: " + token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Shot::init()
|
||||||
|
{
|
||||||
|
if(script)
|
||||||
|
script->call("init", this);
|
||||||
|
}
|
||||||
|
|
||||||
void Shot::fire(bool playSfx)
|
void Shot::fire(bool playSfx)
|
||||||
{
|
{
|
||||||
if (shotData)
|
if (shotData)
|
||||||
|
@ -294,6 +298,8 @@ Shot::Shot() : Quad(), Segmented(0,0)
|
||||||
enqueuedForDelete = false;
|
enqueuedForDelete = false;
|
||||||
shotIdx = shots.size();
|
shotIdx = shots.size();
|
||||||
shots.push_back(this);
|
shots.push_back(this);
|
||||||
|
script = 0;
|
||||||
|
updateScript = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadShotCallback(const std::string &filename, void *param)
|
void loadShotCallback(const std::string &filename, void *param)
|
||||||
|
@ -394,16 +400,11 @@ void Shot::applyShotData(ShotData *shotData)
|
||||||
initSegments(position);
|
initSegments(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Shot::suicide()
|
std::string scriptname = "shot_" + shotData->name;
|
||||||
{
|
std::string file = ScriptInterface::MakeScriptFileName(scriptname, "shots");
|
||||||
setLife(1);
|
script = dsq->scriptInterface.openScript(file, true);
|
||||||
setDecayRate(20);
|
updateScript = !!script;
|
||||||
velocity = 0;
|
|
||||||
fadeAlphaWithLife = true;
|
|
||||||
dead = true;
|
|
||||||
onHitWall();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shot::setParticleEffect(const std::string &particleEffect)
|
void Shot::setParticleEffect(const std::string &particleEffect)
|
||||||
|
@ -427,6 +428,12 @@ void Shot::setParticleEffect(const std::string &particleEffect)
|
||||||
|
|
||||||
void Shot::onEndOfLife()
|
void Shot::onEndOfLife()
|
||||||
{
|
{
|
||||||
|
if(script)
|
||||||
|
{
|
||||||
|
script->call("dieNormal", this);
|
||||||
|
dsq->scriptInterface.closeScript(script);
|
||||||
|
script = 0;
|
||||||
|
}
|
||||||
destroySegments(0.2f);
|
destroySegments(0.2f);
|
||||||
dead = true;
|
dead = true;
|
||||||
|
|
||||||
|
@ -455,17 +462,27 @@ void Shot::doHitEffects()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shot::onHitWall()
|
void Shot::suicide()
|
||||||
{
|
{
|
||||||
BBGE_PROF(Shot_onHitWall);
|
setLife(1);
|
||||||
doHitEffects();
|
setDecayRate(20);
|
||||||
updateSegments(position);
|
velocity = 0;
|
||||||
|
fadeAlphaWithLife = true;
|
||||||
|
dead = true;
|
||||||
|
|
||||||
destroySegments(0.2f);
|
destroySegments(0.2f);
|
||||||
if (emitter)
|
if (emitter)
|
||||||
{
|
{
|
||||||
emitter->killParticleEffect();
|
emitter->killParticleEffect();
|
||||||
emitter = 0;
|
emitter = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shot::onHitWall(bool reflect)
|
||||||
|
{
|
||||||
|
BBGE_PROF(Shot_onHitWall);
|
||||||
|
doHitEffects();
|
||||||
|
updateSegments(position);
|
||||||
|
|
||||||
if (shotData)
|
if (shotData)
|
||||||
{
|
{
|
||||||
|
@ -483,6 +500,10 @@ void Shot::onHitWall()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool doDefault = true;
|
||||||
|
return !script
|
||||||
|
|| (script->call("hitSurface", this, reflect, &doDefault) && !doDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shot::killAllShots()
|
void Shot::killAllShots()
|
||||||
|
@ -520,9 +541,6 @@ void Shot::reflectFromEntity(Entity *e)
|
||||||
{
|
{
|
||||||
firer = e;
|
firer = e;
|
||||||
target = oldFirer;
|
target = oldFirer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,20 +549,20 @@ void Shot::targetDied(Entity *target)
|
||||||
int c = 0;
|
int c = 0;
|
||||||
for (Shots::iterator i = shots.begin(); i != shots.end(); i++)
|
for (Shots::iterator i = shots.begin(); i != shots.end(); i++)
|
||||||
{
|
{
|
||||||
if ((*i)->target == target)
|
Shot *s = *i;
|
||||||
|
if (s->target == target)
|
||||||
{
|
{
|
||||||
debugLog("removing target from shot");
|
debugLog("removing target from shot");
|
||||||
(*i)->target = 0;
|
if(s->script)
|
||||||
|
s->script->call("targetDied", (*i), target);
|
||||||
|
s->target = 0;
|
||||||
}
|
}
|
||||||
if ((*i)->firer == target)
|
if (s->firer == target)
|
||||||
{
|
{
|
||||||
(*i)->firer = 0;
|
s->firer = 0;
|
||||||
}
|
}
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Shot::isHitEnts() const
|
bool Shot::isHitEnts() const
|
||||||
|
@ -556,6 +574,17 @@ bool Shot::isHitEnts() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Shot::canHit(Entity *e, Bone *b)
|
||||||
|
{
|
||||||
|
// isHitEnts() is already checked on a much higher level
|
||||||
|
if(!script)
|
||||||
|
return true; // no script? always hit
|
||||||
|
bool hit = true;
|
||||||
|
if(!script->call("canShotHit", e, b, &hit))
|
||||||
|
return true; // script failed / doesn't have the function / returned nil? hit.
|
||||||
|
return hit; // let script decide
|
||||||
|
}
|
||||||
|
|
||||||
void Shot::hitEntity(Entity *e, Bone *b)
|
void Shot::hitEntity(Entity *e, Bone *b)
|
||||||
{
|
{
|
||||||
if (!dead)
|
if (!dead)
|
||||||
|
@ -565,6 +594,9 @@ void Shot::hitEntity(Entity *e, Bone *b)
|
||||||
|
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
|
if(!canHit(e, b))
|
||||||
|
return;
|
||||||
|
|
||||||
DamageData d;
|
DamageData d;
|
||||||
d.attacker = firer;
|
d.attacker = firer;
|
||||||
d.bone = b;
|
d.bone = b;
|
||||||
|
@ -607,21 +639,18 @@ void Shot::hitEntity(Entity *e, Bone *b)
|
||||||
{
|
{
|
||||||
firer->shotHitEntity(e, this, b);
|
firer->shotHitEntity(e, this, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doEffects)
|
if (doEffects)
|
||||||
doHitEffects();
|
doHitEffects();
|
||||||
|
|
||||||
|
bool willDie = (!shotData || shotData->dieOnHit) && die;
|
||||||
|
if(script)
|
||||||
|
script->call("hitEntity", e, b);
|
||||||
|
|
||||||
target = 0;
|
target = 0;
|
||||||
|
|
||||||
if ((!shotData || shotData->dieOnHit) && die)
|
if (willDie)
|
||||||
{
|
{
|
||||||
lifeTime = 0;
|
lifeTime = 0;
|
||||||
fadeAlphaWithLife = true;
|
fadeAlphaWithLife = true;
|
||||||
|
@ -637,8 +666,6 @@ void Shot::hitEntity(Entity *e, Bone *b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shot::noSegs()
|
void Shot::noSegs()
|
||||||
|
@ -782,6 +809,9 @@ void Shot::onUpdate(float dt)
|
||||||
updateSegments(position);
|
updateSegments(position);
|
||||||
if (!dead)
|
if (!dead)
|
||||||
{
|
{
|
||||||
|
if(script && updateScript)
|
||||||
|
updateScript = script->call("update", this, dt);
|
||||||
|
|
||||||
if (lifeTime > 0)
|
if (lifeTime > 0)
|
||||||
{
|
{
|
||||||
lifeTime -= dt;
|
lifeTime -= dt;
|
||||||
|
@ -810,36 +840,39 @@ void Shot::onUpdate(float dt)
|
||||||
{
|
{
|
||||||
case BOUNCE_REAL:
|
case BOUNCE_REAL:
|
||||||
{
|
{
|
||||||
// Should have been checked in last onUpdate()
|
if(onHitWall(true))
|
||||||
// If it is stuck now, it must have been fired from a bad position,
|
|
||||||
// the obstruction map changed, or it was a bouncing beast form shot,
|
|
||||||
// fired from avatar head - which may be inside a wall.
|
|
||||||
// In any of these cases, there is nowhere to bounce, so we let the shot die. -- FG
|
|
||||||
if (!isObstructed(0))
|
|
||||||
{
|
{
|
||||||
if (!shotData->bounceSfx.empty())
|
// Should have been checked in last onUpdate()
|
||||||
|
// If it is stuck now, it must have been fired from a bad position,
|
||||||
|
// the obstruction map changed, or it was a bouncing beast form shot,
|
||||||
|
// fired from avatar head - which may be inside a wall.
|
||||||
|
// In any of these cases, there is nowhere to bounce, so we let the shot die. -- FG
|
||||||
|
if (!isObstructed(0))
|
||||||
{
|
{
|
||||||
dsq->playPositionalSfx(shotData->bounceSfx, position);
|
if (!shotData->bounceSfx.empty())
|
||||||
if(!shotData->bouncePrt.empty())
|
{
|
||||||
dsq->spawnParticleEffect(shotData->bouncePrt, position);
|
dsq->playPositionalSfx(shotData->bounceSfx, position);
|
||||||
}
|
if(!shotData->bouncePrt.empty())
|
||||||
float len = velocity.getLength2D();
|
dsq->spawnParticleEffect(shotData->bouncePrt, position);
|
||||||
Vector I = velocity/len;
|
}
|
||||||
Vector N = dsq->game->getWallNormal(position);
|
float len = velocity.getLength2D();
|
||||||
|
Vector I = velocity/len;
|
||||||
|
Vector N = dsq->game->getWallNormal(position);
|
||||||
|
|
||||||
if (!N.isZero())
|
if (!N.isZero())
|
||||||
{
|
{
|
||||||
|
|
||||||
velocity = 2*(-I.dot(N))*N + I;
|
velocity = 2*(-I.dot(N))*N + I;
|
||||||
velocity *= len;
|
velocity *= len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
suicide();
|
if(onHitWall(false))
|
||||||
|
suicide();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include "Segmented.h"
|
#include "Segmented.h"
|
||||||
|
|
||||||
class ParticleEffect;
|
class ParticleEffect;
|
||||||
|
class Script;
|
||||||
|
|
||||||
struct ShotData
|
struct ShotData
|
||||||
{
|
{
|
||||||
|
@ -93,6 +94,7 @@ public:
|
||||||
int targetPt;
|
int targetPt;
|
||||||
float maxSpeed;
|
float maxSpeed;
|
||||||
|
|
||||||
|
void init();
|
||||||
void fire(bool playSfx = true);
|
void fire(bool playSfx = true);
|
||||||
void hitEntity(Entity *e, Bone *b);
|
void hitEntity(Entity *e, Bone *b);
|
||||||
|
|
||||||
|
@ -116,6 +118,7 @@ public:
|
||||||
ShotData *shotData;
|
ShotData *shotData;
|
||||||
void updatePosition();
|
void updatePosition();
|
||||||
bool isHitEnts() const;
|
bool isHitEnts() const;
|
||||||
|
bool canHit(Entity *e, Bone *b);
|
||||||
bool isObstructed(float dt) const;
|
bool isObstructed(float dt) const;
|
||||||
inline bool isActive() const { return !dead; }
|
inline bool isActive() const { return !dead; }
|
||||||
inline const char *getName() const { return shotData ? shotData->name.c_str() : ""; }
|
inline const char *getName() const { return shotData ? shotData->name.c_str() : ""; }
|
||||||
|
@ -134,13 +137,15 @@ protected:
|
||||||
|
|
||||||
ParticleEffect *emitter;
|
ParticleEffect *emitter;
|
||||||
|
|
||||||
void onHitWall();
|
bool onHitWall(bool reflect);
|
||||||
void onEndOfLife();
|
void onEndOfLife();
|
||||||
|
|
||||||
bool dead;
|
bool dead;
|
||||||
bool fired;
|
bool fired;
|
||||||
bool enqueuedForDelete;
|
bool enqueuedForDelete;
|
||||||
void onUpdate(float dt);
|
void onUpdate(float dt);
|
||||||
|
Script *script;
|
||||||
|
bool updateScript;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int shotIdx;
|
unsigned int shotIdx;
|
||||||
|
|
Loading…
Add table
Reference in a new issue