[+] Added new MissileStraightFly, which flies straightly, until it reaches terrain tile field flags mask specified in MissileType::MissileStopFlags. You can use KillFirstUnit property, so missile will explode on first unit.
[*] More correct missile handling in MissileHandleBlocking [*] Missile with KillFirstUnit can't kill dead or non-solid units
This commit is contained in:
parent
c64a14b05c
commit
210369b752
5 changed files with 73 additions and 36 deletions
|
@ -216,6 +216,7 @@ set(missile_SRCS
|
|||
src/missile/missile_pointtopointbounce.cpp
|
||||
src/missile/missile_pointtopointcycleonce.cpp
|
||||
src/missile/missile_stay.cpp
|
||||
src/missile/missile_straightfly.cpp
|
||||
src/missile/missile_tracer.cpp
|
||||
src/missile/missile_whirlwind.cpp
|
||||
src/missile/missileconfig.cpp
|
||||
|
|
|
@ -318,23 +318,24 @@ class LuaCallback;
|
|||
** Missile-class this defines how a missile-type reacts.
|
||||
*/
|
||||
enum {
|
||||
MissileClassNone, /// Missile does nothing
|
||||
MissileClassPointToPoint, /// Missile flies from x,y to x1,y1
|
||||
MissileClassPointToPointWithHit, /// Missile flies from x,y to x1,y1 than shows hit animation.
|
||||
MissileClassPointToPointCycleOnce, /// Missile flies from x,y to x1,y1 and animates ONCE from start to finish and back
|
||||
MissileClassPointToPointBounce, /// Missile flies from x,y to x1,y1 than bounces three times.
|
||||
MissileClassStay, /// Missile appears at x,y, does it's anim and vanishes.
|
||||
MissileClassCycleOnce, /// Missile appears at x,y, then cycle through the frames once.
|
||||
MissileClassFire, /// Missile doesn't move, than checks the source unit for HP.
|
||||
MissileClassHit, /// Missile shows the hit points.
|
||||
MissileClassParabolic, /// Missile flies from x,y to x1,y1 using a parabolic path
|
||||
MissileClassLandMine, /// Missile wait on x,y until a non-air unit comes by, the explodes.
|
||||
MissileClassWhirlwind, /// Missile appears at x,y, is whirlwind
|
||||
MissileClassFlameShield, /// Missile surround x,y
|
||||
MissileClassDeathCoil, /// Missile is death coil.
|
||||
MissileClassTracer, /// Missile seeks towards to target unit
|
||||
MissileClassClipToTarget, /// Missile remains clipped to target's current goal and plays his animation once
|
||||
MissileClassContinious /// Missile stays and plays it's animation several times
|
||||
MissileClassNone, /// Missile does nothing
|
||||
MissileClassPointToPoint, /// Missile flies from x,y to x1,y1
|
||||
MissileClassPointToPointWithHit, /// Missile flies from x,y to x1,y1 than shows hit animation.
|
||||
MissileClassPointToPointCycleOnce, /// Missile flies from x,y to x1,y1 and animates ONCE from start to finish and back
|
||||
MissileClassPointToPointBounce, /// Missile flies from x,y to x1,y1 than bounces three times.
|
||||
MissileClassStay, /// Missile appears at x,y, does it's anim and vanishes.
|
||||
MissileClassCycleOnce, /// Missile appears at x,y, then cycle through the frames once.
|
||||
MissileClassFire, /// Missile doesn't move, than checks the source unit for HP.
|
||||
MissileClassHit, /// Missile shows the hit points.
|
||||
MissileClassParabolic, /// Missile flies from x,y to x1,y1 using a parabolic path
|
||||
MissileClassLandMine, /// Missile wait on x,y until a non-air unit comes by, the explodes.
|
||||
MissileClassWhirlwind, /// Missile appears at x,y, is whirlwind
|
||||
MissileClassFlameShield, /// Missile surround x,y
|
||||
MissileClassDeathCoil, /// Missile is death coil.
|
||||
MissileClassTracer, /// Missile seeks towards to target unit
|
||||
MissileClassClipToTarget, /// Missile remains clipped to target's current goal and plays his animation once
|
||||
MissileClassContinious, /// Missile stays and plays it's animation several times
|
||||
MissileClassStraightFly /// Missile flies from x,y to x1,y1 then continues to fly, until incompatible terrain is detected
|
||||
};
|
||||
|
||||
/// Base structure of missile-types
|
||||
|
@ -389,6 +390,7 @@ public:
|
|||
int Damage; /// missile damage (used for non-direct missiles, e.g. impacts)
|
||||
int ReduceFactor; /// Multiplier for reduce or increase damage dealt to the next unit
|
||||
int SmokePrecision; /// How frequently the smoke missile will generate itself
|
||||
int MissileStopFlags; /// On which terrain types missile won't fly
|
||||
|
||||
int Range; /// missile damage range
|
||||
int SplashFactor; /// missile splash divisor
|
||||
|
@ -445,8 +447,9 @@ public:
|
|||
|
||||
int Damage; /// direct damage that missile applies
|
||||
|
||||
int TTL; /// time to live (ticks) used for spells
|
||||
int Hidden; /// If this is 1 then the missile is invisible
|
||||
int TTL; /// time to live (ticks) used for spells
|
||||
int Hidden; /// If this is 1 then the missile is invisible
|
||||
int DestroyMissile; /// this tells missile-class-straight-fly, that it's time to die
|
||||
|
||||
// Internal use:
|
||||
int CurrentStep; /// Current step (0 <= x < TotalStep).
|
||||
|
@ -552,6 +555,13 @@ public:
|
|||
virtual void Action();
|
||||
};
|
||||
|
||||
class MissileStraightFly : public Missile
|
||||
{
|
||||
public:
|
||||
virtual void Action();
|
||||
};
|
||||
|
||||
|
||||
class BurningBuildingFrame
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -146,7 +146,7 @@ MissileType *NewMissileTypeSlot(const std::string &ident)
|
|||
Missile::Missile() :
|
||||
Type(NULL), SpriteFrame(0), State(0), AnimWait(0), Wait(0),
|
||||
Delay(0), SourceUnit(), TargetUnit(), Damage(0),
|
||||
TTL(-1), Hidden(0),
|
||||
TTL(-1), Hidden(0), DestroyMissile(0),
|
||||
CurrentStep(0), TotalStep(0),
|
||||
Local(0)
|
||||
{
|
||||
|
@ -224,6 +224,9 @@ Missile::Missile() :
|
|||
case MissileClassContinious :
|
||||
missile = new MissileContinious;
|
||||
break;
|
||||
case MissileClassStraightFly :
|
||||
missile = new MissileStraightFly;
|
||||
break;
|
||||
}
|
||||
const PixelPos halfSize = mtype.size / 2;
|
||||
missile->position = startPos - halfSize;
|
||||
|
@ -666,8 +669,16 @@ void MissileHandlePierce(Missile &missile, const Vec2i &pos)
|
|||
|
||||
bool MissileHandleBlocking(Missile &missile, const PixelPos &position)
|
||||
{
|
||||
if (missile.SourceUnit && (missile.SourceUnit->CurrentAction() == UnitActionAttackGround
|
||||
|| (missile.TargetUnit && missile.SourceUnit->Type->UnitType == missile.TargetUnit->Type->UnitType))) {
|
||||
const MissileType &mtype = *missile.Type;
|
||||
if (missile.SourceUnit) {
|
||||
bool shouldHit = false;
|
||||
if (missile.TargetUnit && missile.SourceUnit->Type->UnitType == missile.TargetUnit->Type->UnitType) {
|
||||
shouldHit = true;
|
||||
}
|
||||
if (mtype.Range && mtype.CorrectSphashDamage) {
|
||||
shouldHit = true;
|
||||
}
|
||||
if (shouldHit) {
|
||||
// search for blocking units
|
||||
std::vector<CUnit *> blockingUnits;
|
||||
const Vec2i missilePos = Map.MapPixelPosToTilePos(position);
|
||||
|
@ -686,20 +697,27 @@ bool MissileHandleBlocking(Missile &missile, const PixelPos &position)
|
|||
} else {
|
||||
missile.position = position;
|
||||
}
|
||||
missile.DestroyMissile = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// missile can kill any unit on it's way
|
||||
if (missile.Type->KillFirstUnit && &unit != missile.SourceUnit) {
|
||||
// can't kill non-solid or dead units
|
||||
if (unit.IsAliveOnMap() == false || unit.Type->BoolFlag[NONSOLID_INDEX].value) {
|
||||
continue;
|
||||
}
|
||||
if (missile.Type->FriendlyFire == false || unit.IsEnemy(*missile.SourceUnit->Player)) {
|
||||
missile.TargetUnit = &unit;
|
||||
if (unit.Type->TileWidth == 1 || unit.Type->TileHeight == 1) {
|
||||
missile.position = Map.TilePosToMapPixelPos_TopLeft(unit.tilePos);
|
||||
}
|
||||
missile.DestroyMissile = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -725,7 +743,6 @@ bool PointToPointMissile(Missile &missile)
|
|||
const PixelPrecise oldPos((double)missile.position.x, (double)missile.position.y); // Remember old position
|
||||
PixelPrecise pos(oldPos);
|
||||
missile.position = missile.source + diff * missile.CurrentStep / missile.TotalStep;
|
||||
Vec2i mapPos = Map.MapPixelPosToTilePos(missile.position);
|
||||
|
||||
for (; pos.x * sign.x <= missile.position.x * sign.x
|
||||
&& pos.y * sign.y <= missile.position.y * sign.y;
|
||||
|
@ -755,18 +772,29 @@ bool PointToPointMissile(Missile &missile)
|
|||
}
|
||||
|
||||
// Handle wall blocking and kill first enemy
|
||||
mapPos = Map.MapPixelPosToTilePos(missile.position);
|
||||
for (pos = oldPos; pos.x * sign.x <= missile.position.x * sign.x
|
||||
&& pos.y * sign.y <= missile.position.y * sign.y;
|
||||
pos.x += (double)diff.x / missile.TotalStep,
|
||||
pos.y += (double)diff.y / missile.TotalStep) {
|
||||
const PixelPos position((int)pos.x + missile.Type->size.x / 2,
|
||||
(int)pos.y + missile.Type->size.y / 2);
|
||||
if (Map.MapPixelPosToTilePos(position) != mapPos) {
|
||||
if (MissileHandleBlocking(missile, position)) {
|
||||
return true;
|
||||
const Vec2i tilePos(Map.MapPixelPosToTilePos(position));
|
||||
|
||||
if (MissileHandleBlocking(missile, position)) {
|
||||
return true;
|
||||
}
|
||||
if (missile.Type->MissileStopFlags) {
|
||||
if (!Map.Info.IsPointOnMap(tilePos)) { // gone outside
|
||||
missile.TTL = 0;
|
||||
return false;
|
||||
}
|
||||
const CMapField &mf = *Map.Field(tilePos);
|
||||
if (missile.Type->MissileStopFlags & mf.Flags) { // incompatible terrain
|
||||
missile.position = position;
|
||||
missile.MissileHit();
|
||||
missile.TTL = 0;
|
||||
return false;
|
||||
}
|
||||
mapPos = Map.MapPixelPosToTilePos(position);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1290,7 +1318,7 @@ MissileType::MissileType(const std::string &ident) :
|
|||
AlwaysFire(false), Pierce(false), PierceOnce(false), IgnoreWalls(true), KillFirstUnit(false),
|
||||
Class(), NumBounces(0), ParabolCoefficient(2048), StartDelay(0),
|
||||
Sleep(0), Speed(0), TTL(-1), Damage(0), ReduceFactor(100), SmokePrecision(0),
|
||||
Range(0), SplashFactor(0),
|
||||
MissileStopFlags(0), Range(0), SplashFactor(0),
|
||||
ImpactParticle(NULL), SmokeParticle(NULL), OnImpact(NULL),
|
||||
G(NULL)
|
||||
{
|
||||
|
|
|
@ -69,7 +69,6 @@ static bool TracerMissile(Missile &missile)
|
|||
const PixelPrecise oldPos((double)missile.position.x, (double)missile.position.y); // Remember old position
|
||||
PixelPrecise pos(oldPos);
|
||||
missile.position = missile.source + diff * missile.CurrentStep / missile.TotalStep;
|
||||
Vec2i mapPos = Map.MapPixelPosToTilePos(missile.position);
|
||||
|
||||
for (; pos.x * sign.x <= missile.position.x * sign.x
|
||||
&& pos.y * sign.y <= missile.position.y * sign.y;
|
||||
|
@ -98,18 +97,14 @@ static bool TracerMissile(Missile &missile)
|
|||
}
|
||||
|
||||
// Handle wall blocking
|
||||
mapPos = Map.MapPixelPosToTilePos(missile.position);
|
||||
for (pos = oldPos; pos.x * sign.x <= missile.position.x * sign.x
|
||||
&& pos.y * sign.y <= missile.position.y * sign.y;
|
||||
pos.x += (double)diff.x / missile.TotalStep,
|
||||
pos.y += (double)diff.y / missile.TotalStep) {
|
||||
const PixelPos position((int)pos.x + missile.Type->size.x / 2,
|
||||
(int)pos.y + missile.Type->size.y / 2);
|
||||
if (Map.MapPixelPosToTilePos(position) != mapPos) {
|
||||
if (MissileHandleBlocking(missile, position)) {
|
||||
return true;
|
||||
}
|
||||
mapPos = Map.MapPixelPosToTilePos(position);
|
||||
if (MissileHandleBlocking(missile, position)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ static const char *MissileClassNames[] = {
|
|||
"missile-class-tracer",
|
||||
"missile-class-clip-to-target",
|
||||
"missile-class-continious",
|
||||
"missile-class-straight-fly",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -146,6 +147,8 @@ void MissileType::Load(lua_State *l)
|
|||
this->ReduceFactor = LuaToNumber(l, -1);
|
||||
} else if (!strcmp(value, "SmokePrecision")) {
|
||||
this->SmokePrecision = LuaToNumber(l, -1);
|
||||
} else if (!strcmp(value, "MissileStopFlags")) {
|
||||
this->MissileStopFlags = LuaToNumber(l, -1);
|
||||
} else if (!strcmp(value, "DrawLevel")) {
|
||||
this->DrawLevel = LuaToNumber(l, -1);
|
||||
} else if (!strcmp(value, "Range")) {
|
||||
|
|
Loading…
Reference in a new issue