1
0
Fork 0
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:
fgenesis 2017-11-01 19:25:31 +01:00
parent eb1f38d86c
commit fec1cc7ac2
3 changed files with 96 additions and 57 deletions

View file

@ -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;

View file

@ -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;
} }

View file

@ -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;