split missile file.

This commit is contained in:
Joris 2012-04-17 12:18:53 +02:00
parent c3bff8491d
commit 323b91c6b7
19 changed files with 1256 additions and 598 deletions

View file

@ -179,9 +179,25 @@ source_group(map FILES ${map_SRCS})
set(missile_SRCS
src/missile/missile.cpp
src/missile/missile_cliptotarget.cpp
src/missile/missile_cycleonce.cpp
src/missile/missile_deathcoil.cpp
src/missile/missile_fire.cpp
src/missile/missile_flameshield.cpp
src/missile/missile_hit.cpp
src/missile/missile_landmine.cpp
src/missile/missile_none.cpp
src/missile/missile_parabolic.cpp
src/missile/missile_pointotpointwithhit.cpp
src/missile/missile_pointtopoint.cpp
src/missile/missile_pointtopointbounce.cpp
src/missile/missile_pointtopointcycleonce.cpp
src/missile/missile_stay.cpp
src/missile/missile_tracer.cpp
src/missile/missile_whirlwind.cpp
src/missile/script_missile.cpp
)
source_group(map FILES ${missile_SRCS})
source_group(missile FILES ${missile_SRCS})
set(network_SRCS
src/network/commands.cpp
@ -227,10 +243,8 @@ set(stratagusmain_SRCS
src/stratagus/iolib.cpp
src/stratagus/luacallback.cpp
src/stratagus/mainloop.cpp
src/stratagus/missile.cpp
src/stratagus/player.cpp
src/stratagus/script.cpp
src/stratagus/script_missile.cpp
src/stratagus/script_player.cpp
src/stratagus/script_spell.cpp
src/stratagus/selection.cpp

View file

@ -427,6 +427,10 @@ public:
void DrawMissile(const CViewport &vp) const;
void SaveMissile(CFile &file) const;
void MissileHit();
bool NextMissileFrame(char sign, char longAnimation);
void NextMissileFrameCycle();
void MissileNewHeadingFromXY(const PixelPos &delta);
PixelPos source; /// Missile source position
PixelPos position; /// missile pixel position
@ -456,6 +460,9 @@ public:
static unsigned int Count; /// slot number generator.
};
extern bool MissileInitMove(Missile &missile);
extern int PointToPointMissile(Missile &missile);
class MissileDrawProxy
{
public:

View file

@ -192,7 +192,7 @@ Missile::Missile() :
missile = new MissileFire;
break;
case MissileClassHit :
missile = new MissileHit;
missile = new ::MissileHit;
break;
case MissileClassParabolic :
missile = new MissileParabolic;
@ -655,31 +655,30 @@ int FindAndSortMissiles(const CViewport &vp, MissileDrawProxy table[], const int
/**
** Change missile heading from x,y.
**
** @param missile Missile.
** @param delta Delta movement
**
** @internal We have : SpriteFrame / (2 * (Numdirection - 1)) == DirectionToHeading / 256.
*/
static void MissileNewHeadingFromXY(Missile &missile, const PixelPos &delta)
void Missile::MissileNewHeadingFromXY(const PixelPos &delta)
{
if (missile.Type->NumDirections == 1 || (delta.x == 0 && delta.y == 0)) {
if (this->Type->NumDirections == 1 || (delta.x == 0 && delta.y == 0)) {
return;
}
if (missile.SpriteFrame < 0) {
missile.SpriteFrame = -missile.SpriteFrame - 1;
if (this->SpriteFrame < 0) {
this->SpriteFrame = -this->SpriteFrame - 1;
}
missile.SpriteFrame /= missile.Type->NumDirections / 2 + 1;
missile.SpriteFrame *= missile.Type->NumDirections / 2 + 1;
this->SpriteFrame /= this->Type->NumDirections / 2 + 1;
this->SpriteFrame *= this->Type->NumDirections / 2 + 1;
const int nextdir = 256 / missile.Type->NumDirections;
const int nextdir = 256 / this->Type->NumDirections;
Assert(nextdir != 0);
const int dir = ((DirectionToHeading(delta) + nextdir / 2) & 0xFF) / nextdir;
if (dir <= LookingS / nextdir) { // north->east->south
missile.SpriteFrame += dir;
this->SpriteFrame += dir;
} else {
missile.SpriteFrame += 256 / nextdir - dir;
missile.SpriteFrame = -missile.SpriteFrame - 1;
this->SpriteFrame += 256 / nextdir - dir;
this->SpriteFrame = -this->SpriteFrame - 1;
}
}
@ -690,29 +689,29 @@ static void MissileNewHeadingFromXY(Missile &missile, const PixelPos &delta)
**
** @return 1 if goal is reached, 0 else.
*/
static int MissileInitMove(Missile &missile)
bool MissileInitMove(Missile &missile)
{
const PixelPos heading = missile.destination - missile.position;
MissileNewHeadingFromXY(missile, heading);
missile.MissileNewHeadingFromXY(heading);
if (!(missile.State & 1)) {
missile.CurrentStep = 0;
missile.TotalStep = 0;
if (heading.x == 0 && heading.y == 0) {
return 1;
return true;
}
// initialize
missile.TotalStep = MapDistance(missile.source, missile.destination);
missile.State++;
return 0;
return false;
}
Assert(missile.TotalStep != 0);
missile.CurrentStep += missile.Type->Speed;
if (missile.CurrentStep >= missile.TotalStep) {
missile.position = missile.destination;
return 1;
return true;
}
return 0;
return false;
}
/**
@ -722,7 +721,7 @@ static int MissileInitMove(Missile &missile)
**
** @return 1 if goal is reached, 0 else.
*/
static int PointToPointMissile(Missile &missile)
int PointToPointMissile(Missile &missile)
{
if (MissileInitMove(missile) == 1) {
return 1;
@ -741,77 +740,6 @@ static int PointToPointMissile(Missile &missile)
return 0;
}
/**
** Handle tracer missile.
**
** @param missile Missile pointer.
**
** @return 1 if goal is reached, 0 else.
*/
static int TracerMissile(Missile &missile)
{
if (MissileInitMove(missile) == 1) {
return 1;
}
Assert(missile.Type != NULL);
Assert(missile.TotalStep != 0);
if (missile.TargetUnit) {
missile.destination.x = missile.TargetUnit->tilePos.x * PixelTileSize.x + missile.TargetUnit->IX;
missile.destination.y = missile.TargetUnit->tilePos.y * PixelTileSize.y + missile.TargetUnit->IY;
}
const PixelPos diff = (missile.destination - missile.source);
missile.position = missile.source + diff * missile.CurrentStep / missile.TotalStep;
if (missile.Type->SmokeMissile && missile.CurrentStep) {
const PixelPos position = missile.position + missile.Type->size / 2;
MakeMissile(*missile.Type->SmokeMissile, position, position);
}
return 0;
}
/**
** Calculate parabolic trajectories.
**
** @param missile Missile pointer.
**
** @return 1 if target is reached, 0 otherwise
**
** @todo Find good values for ZprojToX and Y
*/
static int ParabolicMissile(Missile &missile)
{
int k; // Coefficient of the parabol.
int zprojToX; // Projection of Z axis on axis X.
int zprojToY; // Projection of Z axis on axis Y.
int z; // should be missile.Z later.
k = -2048; //-1024; // Should be initialised by an other method (computed with distance...)
zprojToX = 4;
zprojToY = 1024;
if (MissileInitMove(missile) == 1) {
return 1;
}
Assert(missile.Type != NULL);
const PixelPos orig_pos = missile.position;
Assert(missile.TotalStep != 0);
const PixelPos diff = (missile.destination - missile.source);
missile.position = missile.source + diff * missile.CurrentStep / missile.TotalStep;
Assert(k != 0);
z = missile.CurrentStep * (missile.TotalStep - missile.CurrentStep) / k;
// Until Z is used for drawing, modify X and Y.
missile.position.x += z * zprojToX / 64;
missile.position.y += z * zprojToY / 64;
MissileNewHeadingFromXY(missile, missile.position - orig_pos);
if (missile.Type->SmokeMissile && missile.CurrentStep) {
const PixelPos position = missile.position + missile.Type->size / 2;
MakeMissile(*missile.Type->SmokeMissile, position, position);
}
return 0;
}
/**
** Missile hits the goal.
**
@ -869,17 +797,15 @@ static void MissileHitsWall(const Missile &missile, const Vec2i &tilePos, int sp
/**
** Work for missile hit.
**
** @param missile Missile reaching end-point.
*/
static void MissileHit(Missile &missile)
void Missile::MissileHit()
{
const MissileType &mtype = *missile.Type;
const MissileType &mtype = *this->Type;
if (mtype.ImpactSound.Sound) {
PlayMissileSound(&missile, mtype.ImpactSound.Sound);
PlayMissileSound(this, mtype.ImpactSound.Sound);
}
const PixelPos pixelPos = missile.position + missile.Type->size / 2;
const PixelPos pixelPos = this->position + this->Type->size / 2;
//
// The impact generates a new missile.
@ -894,7 +820,7 @@ static void MissileHit(Missile &missile)
mtype.ImpactParticle->run();
}
if (!missile.SourceUnit) { // no owner - green-cross ...
if (!this->SourceUnit) { // no owner - green-cross ...
return;
}
@ -910,20 +836,20 @@ static void MissileHit(Missile &missile)
// Choose correct goal.
//
if (!mtype.Range) {
if (missile.TargetUnit && (mtype.FriendlyFire == false
|| missile.TargetUnit->Player->Index != missile.SourceUnit->Player->Index)) {
if (this->TargetUnit && (mtype.FriendlyFire == false
|| this->TargetUnit->Player->Index != this->SourceUnit->Player->Index)) {
//
// Missiles without range only hits the goal always.
//
CUnit &goal = *missile.TargetUnit;
if (goal.Destroyed) { // Destroyed
missile.TargetUnit = NoUnitP;
CUnit &goal = *this->TargetUnit;
if (goal.Destroyed) {
this->TargetUnit = NoUnitP;
return;
}
MissileHitsGoal(missile, goal, 1);
MissileHitsGoal(*this, goal, 1);
return;
}
MissileHitsWall(missile, pos, 1);
MissileHitsWall(*this, pos, 1);
return;
}
@ -934,7 +860,7 @@ static void MissileHit(Missile &missile)
const Vec2i range = {mtype.Range - 1, mtype.Range - 1};
std::vector<CUnit *> table;
Map.Select(pos - range, pos + range, table);
Assert(missile.SourceUnit != NULL);
Assert(this->SourceUnit != NULL);
for (size_t i = 0; i != table.size(); ++i) {
CUnit &goal = *table[i];
//
@ -942,17 +868,17 @@ static void MissileHit(Missile &missile)
// NOTE: perhaps this should be come a property of the missile.
// Also check CorrectSphashDamage so land explosions can't hit the air units
//
if (CanTarget(missile.SourceUnit->Type, goal.Type)
&& (mtype.FriendlyFire == false || goal.Player->Index != missile.SourceUnit->Player->Index)) {
if (CanTarget(this->SourceUnit->Type, goal.Type)
&& (mtype.FriendlyFire == false || goal.Player->Index != this->SourceUnit->Player->Index)) {
bool shouldHit = true;
if (mtype.CorrectSphashDamage == true) {
if (missile.SourceUnit->CurrentAction() == UnitActionAttackGround) {
if (goal.Type->UnitType != missile.SourceUnit->Type->UnitType) {
if (this->SourceUnit->CurrentAction() == UnitActionAttackGround) {
if (goal.Type->UnitType != this->SourceUnit->Type->UnitType) {
shouldHit = false;
}
} else {
if (missile.TargetUnit == NULL || goal.Type->UnitType != missile.TargetUnit->Type->UnitType) {
if (this->TargetUnit == NULL || goal.Type->UnitType != this->TargetUnit->Type->UnitType) {
shouldHit = false;
}
}
@ -965,7 +891,7 @@ static void MissileHit(Missile &missile)
} else {
splash = 1;
}
MissileHitsGoal(missile, goal, splash);
MissileHitsGoal(*this, goal, splash);
}
}
}
@ -984,7 +910,7 @@ static void MissileHit(Missile &missile)
if (d == 0) {
d = 1;
}
MissileHitsWall(missile, posIt, d);
MissileHitsWall(*this, posIt, d);
}
}
}
@ -993,13 +919,12 @@ static void MissileHit(Missile &missile)
/**
** Pass to the next frame for animation.
**
** @param missile missile to animate.
** @param sign 1 for next frame, -1 for previous frame.
** @param longAnimation 1 if Frame is conditionned by covered distance, 0 else.
**
** @return 1 if animation is finished, 0 else.
** @return true if animation is finished, false else.
*/
static int NextMissileFrame(Missile &missile, char sign, char longAnimation)
bool Missile::NextMissileFrame(char sign, char longAnimation)
{
int neg; // True for mirroring sprite.
int animationIsFinished; // returned value.
@ -1010,10 +935,10 @@ static int NextMissileFrame(Missile &missile, char sign, char longAnimation)
//
neg = 0;
animationIsFinished = 0;
numDirections = missile.Type->NumDirections / 2 + 1;
if (missile.SpriteFrame < 0) {
numDirections = this->Type->NumDirections / 2 + 1;
if (this->SpriteFrame < 0) {
neg = 1;
missile.SpriteFrame = -missile.SpriteFrame - 1;
this->SpriteFrame = -this->SpriteFrame - 1;
}
if (longAnimation) {
int totalf; // Total number of frame (for one direction).
@ -1021,29 +946,29 @@ static int NextMissileFrame(Missile &missile, char sign, char longAnimation)
int totalx; // Total distance to cover.
int dx; // Covered distance.
totalx = MapDistance(missile.destination, missile.source);
dx = MapDistance(missile.position, missile.source);
totalf = missile.Type->SpriteFrames / numDirections;
df = missile.SpriteFrame / numDirections;
totalx = MapDistance(this->destination, this->source);
dx = MapDistance(this->position, this->source);
totalf = this->Type->SpriteFrames / numDirections;
df = this->SpriteFrame / numDirections;
if ((sign == 1 && dx * totalf <= df * totalx)
|| (sign == -1 && dx * totalf > df * totalx)) {
return animationIsFinished;
}
}
missile.SpriteFrame += sign * numDirections;
this->SpriteFrame += sign * numDirections;
if (sign > 0) {
if (missile.SpriteFrame >= missile.Type->SpriteFrames) {
missile.SpriteFrame -= missile.Type->SpriteFrames;
if (this->SpriteFrame >= this->Type->SpriteFrames) {
this->SpriteFrame -= this->Type->SpriteFrames;
animationIsFinished = 1;
}
} else {
if (missile.SpriteFrame < 0) {
missile.SpriteFrame += missile.Type->SpriteFrames;
if (this->SpriteFrame < 0) {
this->SpriteFrame += this->Type->SpriteFrames;
animationIsFinished = 1;
}
}
if (neg) {
missile.SpriteFrame = -missile.SpriteFrame - 1;
this->SpriteFrame = -this->SpriteFrame - 1;
}
return animationIsFinished;
@ -1052,20 +977,18 @@ static int NextMissileFrame(Missile &missile, char sign, char longAnimation)
/**
** Pass the next frame of the animation.
** This animation goes from start to finish ONCE on the way
**
** @param missile Missile pointer.
*/
static void NextMissileFrameCycle(Missile &missile)
void Missile::NextMissileFrameCycle()
{
int neg = 0;
if (missile.SpriteFrame < 0) {
if (this->SpriteFrame < 0) {
neg = 1;
missile.SpriteFrame = -missile.SpriteFrame - 1;
this->SpriteFrame = -this->SpriteFrame - 1;
}
const int totalx = abs(missile.destination.x - missile.source.x);
const int dx = abs(missile.position.x - missile.source.x);
int f = missile.Type->SpriteFrames / (missile.Type->NumDirections / 2 + 1);
const int totalx = abs(this->destination.x - this->source.x);
const int dx = abs(this->position.x - this->source.x);
int f = this->Type->SpriteFrames / (this->Type->NumDirections / 2 + 1);
f = 2 * f - 1;
for (int i = 1, j = 1; i <= f; ++i) {
if (dx * f / i < totalx) {
@ -1074,13 +997,13 @@ static void NextMissileFrameCycle(Missile &missile)
} else {
j = f - i;
}
missile.SpriteFrame = missile.SpriteFrame % (missile.Type->NumDirections / 2 + 1) +
j * (missile.Type->NumDirections / 2 + 1);
this->SpriteFrame = this->SpriteFrame % (this->Type->NumDirections / 2 + 1) +
j * (this->Type->NumDirections / 2 + 1);
break;
}
}
if (neg) {
missile.SpriteFrame = -missile.SpriteFrame - 1;
this->SpriteFrame = -this->SpriteFrame - 1;
}
}
@ -1334,460 +1257,4 @@ void FreeBurningBuildingFrames()
}
#endif
/*----------------------------------------------------------------------------
-- Functions (Spells Controllers/Callbacks) TODO: move to another file?
----------------------------------------------------------------------------*/
// ****************************************************************************
// Actions for the missiles
// ****************************************************************************
/*
** Missile controllers
**
** To cancel a missile set it's TTL to 0, it will be handled right after
** the controller call and missile will be down.
*/
/**
** Missile does nothing
*/
void MissileNone::Action()
{
this->Wait = this->Type->Sleep;
// Busy doing nothing.
}
/**
** Missile flies from x,y to x1,y1 animation on the way
*/
void MissilePointToPoint::Action()
{
this->Wait = this->Type->Sleep;
if (PointToPointMissile(*this)) {
MissileHit(*this);
this->TTL = 0;
} else {
NextMissileFrame(*this, 1, 0);
}
}
/**
** Missile flies from x,y to x1,y1 showing the first frame
** and then shows a hit animation.
*/
void MissilePointToPointWithHit::Action()
{
this->Wait = this->Type->Sleep;
if (PointToPointMissile(*this)) {
if (NextMissileFrame(*this, 1, 0)) {
MissileHit(*this);
this->TTL = 0;
}
}
}
/**
** Missile flies from x,y to x1,y1 and stays there for a moment
*/
void MissilePointToPointCycleOnce::Action()
{
this->Wait = this->Type->Sleep;
if (PointToPointMissile(*this)) {
MissileHit(*this);
this->TTL = 0;
} else {
NextMissileFrameCycle(*this);
}
}
/**
** Missile don't move, than disappears
*/
void MissileStay::Action()
{
this->Wait = this->Type->Sleep;
if (NextMissileFrame(*this, 1, 0)) {
MissileHit(*this);
this->TTL = 0;
}
}
/**
** Missile flies from x,y to x1,y1 than bounces NumBounces times
*/
void MissilePointToPointBounce::Action()
{
this->Wait = this->Type->Sleep;
if (PointToPointMissile(*this)) {
if (this->State < 2 * this->Type->NumBounces - 1 && this->TotalStep) {
const PixelPos step = (this->destination - this->source);
this->destination += step * ((PixelTileSize.x + PixelTileSize.y) * 3) / 4 / this->TotalStep;
this->State++; // !(State & 1) to initialise
this->source = this->position;
PointToPointMissile(*this);
//this->State++;
MissileHit(*this);
// FIXME: hits to left and right
// FIXME: reduce damage effects on later impacts
} else {
MissileHit(*this);
this->TTL = 0;
}
} else {
NextMissileFrame(*this, 1, 0);
}
}
/**
** Missile doesn't move, it will just cycle once and vanish.
** Used for ui missiles (cross shown when you give and order)
*/
void MissileCycleOnce::Action()
{
this->Wait = this->Type->Sleep;
switch (this->State) {
case 0:
case 2:
++this->State;
break;
case 1:
if (NextMissileFrame(*this, 1, 0)) {
++this->State;
}
break;
case 3:
if (NextMissileFrame(*this, -1, 0)) {
MissileHit(*this);
this->TTL = 0;
}
break;
}
}
/**
** Missile don't move, than checks the source unit for HP.
*/
void MissileFire::Action()
{
CUnit &unit = *this->SourceUnit;
this->Wait = this->Type->Sleep;
if (unit.Destroyed || unit.CurrentAction() == UnitActionDie) {
this->TTL = 0;
return;
}
if (NextMissileFrame(*this, 1, 0)) {
this->SpriteFrame = 0;
const int f = (100 * unit.Variable[HP_INDEX].Value) / unit.Variable[HP_INDEX].Max;
MissileType *fire = MissileBurningBuilding(f);
if (!fire) {
this->TTL = 0;
unit.Burning = 0;
} else {
if (this->Type != fire) {
this->position += this->Type->size / 2;
this->Type = fire;
this->position -= this->Type->size / 2;
}
}
}
}
/**
** Missile shows hit points?
*/
void MissileHit::Action()
{
this->Wait = this->Type->Sleep;
if (PointToPointMissile(*this)) {
::MissileHit(*this);
this->TTL = 0;
}
}
/**
** Missile flies from x,y to x1,y1 using a parabolic path
*/
void MissileParabolic::Action()
{
this->Wait = this->Type->Sleep;
if (ParabolicMissile(*this)) {
MissileHit(*this);
this->TTL = 0;
} else {
NextMissileFrameCycle(*this);
}
}
/**
** FlameShield controller
*/
void MissileFlameShield::Action()
{
static int fs_dc[] = {
0, 32, 5, 31, 10, 30, 16, 27, 20, 24, 24, 20, 27, 15, 30, 10, 31,
5, 32, 0, 31, -5, 30, -10, 27, -16, 24, -20, 20, -24, 15, -27, 10,
-30, 5, -31, 0, -32, -5, -31, -10, -30, -16, -27, -20, -24, -24, -20,
-27, -15, -30, -10, -31, -5, -32, 0, -31, 5, -30, 10, -27, 16, -24,
20, -20, 24, -15, 27, -10, 30, -5, 31, 0, 32
};
this->Wait = this->Type->Sleep;
const int index = this->TTL % 36; // 36 positions on the circle
const int dx = fs_dc[index * 2];
const int dy = fs_dc[index * 2 + 1];
CUnit *unit = this->TargetUnit;
//
// Show around the top most unit.
// FIXME: conf, do we hide if the unit is contained or not?
//
while (unit->Container) {
unit = unit->Container;
}
const Vec2i upos = unit->tilePos;
const int ix = unit->IX;
const int iy = unit->IY;
const int uw = unit->Type->TileWidth;
const int uh = unit->Type->TileHeight;
this->position.x = upos.x * PixelTileSize.x + ix + uw * PixelTileSize.x / 2 + dx - 16;
this->position.y = upos.y * PixelTileSize.y + iy + uh * PixelTileSize.y / 2 + dy - 32;
if (unit->CurrentAction() == UnitActionDie) {
this->TTL = index;
}
if (unit->Container) {
this->Hidden = 1;
return; // Hidden missile don't do damage.
} else {
this->Hidden = 0;
}
// Only hit 1 out of 8 frames
if (this->TTL & 7) {
return;
}
std::vector<CUnit *> table;
Map.SelectAroundUnit(*unit, 1, table);
for (size_t i = 0; i != table.size(); ++i) {
if (table[i]->CurrentAction() != UnitActionDie) {
HitUnit(this->SourceUnit, *table[i], this->Damage);
}
}
}
struct LandMineTargetFinder {
const CUnit *const source;
int CanHitOwner;
LandMineTargetFinder(const CUnit *unit, int hit):
source(unit), CanHitOwner(hit) {}
inline bool operator()(const CUnit *const unit) const {
return (!(unit == source && !CanHitOwner)
&& unit->Type->UnitType != UnitTypeFly
&& unit->CurrentAction() != UnitActionDie);
}
inline CUnit *FindOnTile(const CMapField *const mf) const {
return mf->UnitCache.find(*this);
}
};
/**
** Land mine controller.
** @todo start-finish-start cyclic animation.(anim scripts!)
** @todo missile should dissapear for a while.
*/
void MissileLandMine::Action()
{
const Vec2i pos = {this->position.x / PixelTileSize.x, this->position.y / PixelTileSize.y};
if (LandMineTargetFinder(this->SourceUnit, this->Type->CanHitOwner).FindOnTile(Map.Field(pos)) != NULL) {
DebugPrint("Landmine explosion at %d,%d.\n" _C_ pos.x _C_ pos.y);
MissileHit(*this);
this->TTL = 0;
return;
}
if (!this->AnimWait--) {
NextMissileFrame(*this, 1, 0);
this->AnimWait = this->Type->Sleep;
}
this->Wait = 1;
}
/**
** Whirlwind controller
**
** @todo do it more configurable.
*/
void MissileWhirlwind::Action()
{
//
// Animate, move.
//
if (!this->AnimWait--) {
if (NextMissileFrame(*this, 1, 0)) {
this->SpriteFrame = 0;
PointToPointMissile(*this);
}
this->AnimWait = this->Type->Sleep;
}
this->Wait = 1;
//
// Center of the tornado
//
PixelPos center = this->position + this->Type->size / 2;
center.x = (center.x + PixelTileSize.x / 2) / PixelTileSize.x;
center.y = (center.y + PixelTileSize.y) / PixelTileSize.y;
#if 0
CUnit *table[UnitMax];
int i;
int n;
//
// Every 4 cycles 4 points damage in tornado center
//
if (!(this->TTL % 4)) {
n = SelectUnitsOnTile(x, y, table);
for (i = 0; i < n; ++i) {
if (table[i]->CurrentAction() != UnitActionDie) {
// should be missile damage ?
HitUnit(this->SourceUnit, table[i], WHIRLWIND_DAMAGE1);
}
}
}
//
// Every 1/10s 1 points damage on tornado periphery
//
if (!(this->TTL % (CYCLES_PER_SECOND / 10))) {
// we should parameter this
n = SelectUnits(center.x - 1, center.y - 1, center.x + 1, center.y + 1, table);
for (i = 0; i < n; ++i) {
if ((table[i]->X != center.x || table[i]->Y != center.y) && table[i]->CurrentAction() != UnitActionDie) {
// should be in missile
HitUnit(this->SourceUnit, table[i], WHIRLWIND_DAMAGE2);
}
}
}
DebugPrint("Whirlwind: %d, %d, TTL: %d state: %d\n" _C_
missile->X _C_ missile->Y _C_ missile->TTL _C_ missile->State);
#else
if (!(this->TTL % CYCLES_PER_SECOND / 10)) {
MissileHit(*this);
}
#endif
//
// Changes direction every 3 seconds (approx.)
//
if (!(this->TTL % 100)) { // missile has reached target unit/spot
int nx;
int ny;
do {
// find new destination in the map
nx = center.x + SyncRand() % 5 - 2;
ny = center.y + SyncRand() % 5 - 2;
} while (!Map.Info.IsPointOnMap(nx, ny));
this->destination.x = nx * PixelTileSize.x + PixelTileSize.x / 2;
this->destination.y = ny * PixelTileSize.y + PixelTileSize.y / 2;
this->source = this->position;
this->State = 0;
DebugPrint("Whirlwind new direction: %d, %d, TTL: %d\n" _C_
this->destination.x _C_ this->destination.y _C_ this->TTL);
}
}
/**
** Death-Coil class. Damages organic units and gives to the caster.
**
** @todo do it configurable.
*/
void MissileDeathCoil::Action()
{
this->Wait = this->Type->Sleep;
if (PointToPointMissile(*this)) {
Assert(this->SourceUnit != NULL);
CUnit &source = *this->SourceUnit;
if (source.Destroyed) {
return;
}
// source unit still exists
//
// Target unit still exists and casted on a special target
//
if (this->TargetUnit && !this->TargetUnit->Destroyed
&& this->TargetUnit->CurrentAction() == UnitActionDie) {
HitUnit(&source, *this->TargetUnit, this->Damage);
if (source.CurrentAction() != UnitActionDie) {
source.Variable[HP_INDEX].Value += this->Damage;
if (source.Variable[HP_INDEX].Value > source.Variable[HP_INDEX].Max) {
source.Variable[HP_INDEX].Value = source.Variable[HP_INDEX].Max;
}
}
} else {
//
// No target unit -- try enemies in range 5x5 // Must be parametrable
//
std::vector<CUnit *> table;
const Vec2i destPos = {this->destination.x / PixelTileSize.x, this->destination.y / PixelTileSize.y};
const Vec2i range = {2, 2};
Map.Select(destPos - range, destPos + range, table, IsEnemyWith(*source.Player));
if (table.empty()) {
return;
}
const size_t n = table.size(); // enemy count
const int damage = std::min<int>(1, this->Damage / n);
// disperse damage between them
for (size_t i = 0; i != n; ++i) {
HitUnit(&source, *table[i], damage);
}
if (source.CurrentAction() != UnitActionDie) {
source.Variable[HP_INDEX].Value += this->Damage;
if (source.Variable[HP_INDEX].Value > source.Variable[HP_INDEX].Max) {
source.Variable[HP_INDEX].Value = source.Variable[HP_INDEX].Max;
}
}
}
this->TTL = 0;
}
}
/**
** Missile flies from x,y to the target position, changing direction on the way
*/
void MissileTracer::Action()
{
this->Wait = this->Type->Sleep;
if (TracerMissile(*this)) {
MissileHit(*this);
this->TTL = 0;
} else {
NextMissileFrame(*this, 1, 0);
}
}
/**
** Missile remains clipped to target's current goal and plays his animation once
*/
void MissileClipToTarget::Action()
{
this->Wait = this->Type->Sleep;
if (this->TargetUnit != NULL) {
this->position.x = this->TargetUnit->tilePos.x * PixelTileSize.x + this->TargetUnit->IX;
this->position.y = this->TargetUnit->tilePos.y * PixelTileSize.y + this->TargetUnit->IY;
}
if (NextMissileFrame(*this, 1, 0)) {
MissileHit(*this);
this->TTL = 0;
}
}
//@}

View file

@ -0,0 +1,61 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_cliptotarget.cpp - The missile ClipToTarget. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
#include "map.h"
#include "unit.h"
/**
** Missile remains clipped to target's current goal and plays his animation once
*/
void MissileClipToTarget::Action()
{
this->Wait = this->Type->Sleep;
if (this->TargetUnit != NULL) {
this->position.x = this->TargetUnit->tilePos.x * PixelTileSize.x + this->TargetUnit->IX;
this->position.y = this->TargetUnit->tilePos.y * PixelTileSize.y + this->TargetUnit->IY;
}
if (this->NextMissileFrame(1, 0)) {
this->MissileHit();
this->TTL = 0;
}
}
//@}

View file

@ -0,0 +1,66 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_.cpp - The missile . */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
/**
** Missile doesn't move, it will just cycle once and vanish.
** Used for ui missiles (cross shown when you give and order)
*/
void MissileCycleOnce::Action()
{
this->Wait = this->Type->Sleep;
switch (this->State) {
case 0:
case 2:
++this->State;
break;
case 1:
if (this->NextMissileFrame(1, 0)) {
++this->State;
}
break;
case 3:
if (this->NextMissileFrame(-1, 0)) {
this->MissileHit();
this->TTL = 0;
}
break;
}
}
//@}

View file

@ -0,0 +1,102 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_deathcoil.cpp - The missile DeathCoil. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
#include "actions.h"
#include "map.h"
#include "unit.h"
/**
** Death-Coil class. Damages organic units and gives to the caster.
**
** @todo do it configurable.
*/
void MissileDeathCoil::Action()
{
this->Wait = this->Type->Sleep;
if (PointToPointMissile(*this)) {
Assert(this->SourceUnit != NULL);
CUnit &source = *this->SourceUnit;
if (source.Destroyed) {
return;
}
// source unit still exists
//
// Target unit still exists and casted on a special target
//
if (this->TargetUnit && !this->TargetUnit->Destroyed
&& this->TargetUnit->CurrentAction() == UnitActionDie) {
HitUnit(&source, *this->TargetUnit, this->Damage);
if (source.CurrentAction() != UnitActionDie) {
source.Variable[HP_INDEX].Value += this->Damage;
if (source.Variable[HP_INDEX].Value > source.Variable[HP_INDEX].Max) {
source.Variable[HP_INDEX].Value = source.Variable[HP_INDEX].Max;
}
}
} else {
//
// No target unit -- try enemies in range 5x5 // Must be parametrable
//
std::vector<CUnit *> table;
const Vec2i destPos = {this->destination.x / PixelTileSize.x, this->destination.y / PixelTileSize.y};
const Vec2i range = {2, 2};
Map.Select(destPos - range, destPos + range, table, IsEnemyWith(*source.Player));
if (table.empty()) {
return;
}
const size_t n = table.size(); // enemy count
const int damage = std::min<int>(1, this->Damage / n);
// disperse damage between them
for (size_t i = 0; i != n; ++i) {
HitUnit(&source, *table[i], damage);
}
if (source.CurrentAction() != UnitActionDie) {
source.Variable[HP_INDEX].Value += this->Damage;
if (source.Variable[HP_INDEX].Value > source.Variable[HP_INDEX].Max) {
source.Variable[HP_INDEX].Value = source.Variable[HP_INDEX].Max;
}
}
}
this->TTL = 0;
}
}
//@}

View file

@ -0,0 +1,73 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_fire.cpp - The missile Fire. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
#include "actions.h"
#include "unit.h"
/**
** Missile don't move, than checks the source unit for HP.
*/
void MissileFire::Action()
{
CUnit &unit = *this->SourceUnit;
this->Wait = this->Type->Sleep;
if (unit.Destroyed || unit.CurrentAction() == UnitActionDie) {
this->TTL = 0;
return;
}
if (this->NextMissileFrame(1, 0)) {
this->SpriteFrame = 0;
const int f = (100 * unit.Variable[HP_INDEX].Value) / unit.Variable[HP_INDEX].Max;
MissileType *fire = MissileBurningBuilding(f);
if (!fire) {
this->TTL = 0;
unit.Burning = 0;
} else {
if (this->Type != fire) {
this->position += this->Type->size / 2;
this->Type = fire;
this->position -= this->Type->size / 2;
}
}
}
}
//@}

View file

@ -0,0 +1,101 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_flameshield.cpp - The missile FlameShield. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
#include "actions.h"
#include "map.h"
#include "unit.h"
/**
** FlameShield controller
*/
void MissileFlameShield::Action()
{
static int fs_dc[] = {
0, 32, 5, 31, 10, 30, 16, 27, 20, 24, 24, 20, 27, 15, 30, 10, 31,
5, 32, 0, 31, -5, 30, -10, 27, -16, 24, -20, 20, -24, 15, -27, 10,
-30, 5, -31, 0, -32, -5, -31, -10, -30, -16, -27, -20, -24, -24, -20,
-27, -15, -30, -10, -31, -5, -32, 0, -31, 5, -30, 10, -27, 16, -24,
20, -20, 24, -15, 27, -10, 30, -5, 31, 0, 32
};
this->Wait = this->Type->Sleep;
const int index = this->TTL % 36; // 36 positions on the circle
const int dx = fs_dc[index * 2];
const int dy = fs_dc[index * 2 + 1];
CUnit *unit = this->TargetUnit;
//
// Show around the top most unit.
// FIXME: conf, do we hide if the unit is contained or not?
//
while (unit->Container) {
unit = unit->Container;
}
const Vec2i upos = unit->tilePos;
const int ix = unit->IX;
const int iy = unit->IY;
const int uw = unit->Type->TileWidth;
const int uh = unit->Type->TileHeight;
this->position.x = upos.x * PixelTileSize.x + ix + uw * PixelTileSize.x / 2 + dx - 16;
this->position.y = upos.y * PixelTileSize.y + iy + uh * PixelTileSize.y / 2 + dy - 32;
if (unit->CurrentAction() == UnitActionDie) {
this->TTL = index;
}
if (unit->Container) {
this->Hidden = 1;
return; // Hidden missile don't do damage.
} else {
this->Hidden = 0;
}
// Only hit 1 out of 8 frames
if (this->TTL & 7) {
return;
}
std::vector<CUnit *> table;
Map.SelectAroundUnit(*unit, 1, table);
for (size_t i = 0; i != table.size(); ++i) {
if (table[i]->CurrentAction() != UnitActionDie) {
HitUnit(this->SourceUnit, *table[i], this->Damage);
}
}
}
//@}

View file

@ -0,0 +1,52 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_hit.cpp - The missile Hit. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
/**
** Missile shows hit points?
*/
void MissileHit::Action()
{
this->Wait = this->Type->Sleep;
if (PointToPointMissile(*this)) {
::MissileHit(*this);
this->TTL = 0;
}
}
//@}

View file

@ -0,0 +1,81 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_landmine.cpp - The missile LandMine. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
#include "actions.h"
#include "map.h"
#include "unit.h"
struct LandMineTargetFinder {
const CUnit *const source;
int CanHitOwner;
LandMineTargetFinder(const CUnit *unit, int hit):
source(unit), CanHitOwner(hit) {}
inline bool operator()(const CUnit *const unit) const {
return (!(unit == source && !CanHitOwner)
&& unit->Type->UnitType != UnitTypeFly
&& unit->CurrentAction() != UnitActionDie);
}
inline CUnit *FindOnTile(const CMapField *const mf) const {
return mf->UnitCache.find(*this);
}
};
/**
** Land mine controller.
** @todo start-finish-start cyclic animation.(anim scripts!)
** @todo missile should dissapear for a while.
*/
void MissileLandMine::Action()
{
const Vec2i pos = {this->position.x / PixelTileSize.x, this->position.y / PixelTileSize.y};
if (LandMineTargetFinder(this->SourceUnit, this->Type->CanHitOwner).FindOnTile(Map.Field(pos)) != NULL) {
DebugPrint("Landmine explosion at %d,%d.\n" _C_ pos.x _C_ pos.y);
this->MissileHit();
this->TTL = 0;
return;
}
if (!this->AnimWait--) {
this->NextMissileFrame(1, 0);
this->AnimWait = this->Type->Sleep;
}
this->Wait = 1;
}
//@}

View file

@ -0,0 +1,49 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_none.cpp - The missile None. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
/**
** Missile does nothing
*/
void MissileNone::Action()
{
this->Wait = this->Type->Sleep;
// Busy doing nothing.
}
//@}

View file

@ -0,0 +1,97 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_parabolic.cpp - The missile Parabolic. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include <stdio.h>
#include "stratagus.h"
#include "missile.h"
/**
** Calculate parabolic trajectories.
**
** @param missile Missile pointer.
**
** @return 1 if target is reached, 0 otherwise
**
** @todo Find good values for ZprojToX and Y
*/
static int ParabolicMissile(Missile &missile)
{
int k; // Coefficient of the parabol.
int zprojToX; // Projection of Z axis on axis X.
int zprojToY; // Projection of Z axis on axis Y.
int z; // should be missile.Z later.
k = -2048; //-1024; // Should be initialised by an other method (computed with distance...)
zprojToX = 4;
zprojToY = 1024;
if (MissileInitMove(missile) == 1) {
return 1;
}
Assert(missile.Type != NULL);
const PixelPos orig_pos = missile.position;
Assert(missile.TotalStep != 0);
const PixelPos diff = (missile.destination - missile.source);
missile.position = missile.source + diff * missile.CurrentStep / missile.TotalStep;
Assert(k != 0);
z = missile.CurrentStep * (missile.TotalStep - missile.CurrentStep) / k;
// Until Z is used for drawing, modify X and Y.
missile.position.x += z * zprojToX / 64;
missile.position.y += z * zprojToY / 64;
missile.MissileNewHeadingFromXY(missile.position - orig_pos);
if (missile.Type->SmokeMissile && missile.CurrentStep) {
const PixelPos position = missile.position + missile.Type->size / 2;
MakeMissile(*missile.Type->SmokeMissile, position, position);
}
return 0;
}
/**
** Missile flies from x,y to x1,y1 using a parabolic path
*/
void MissileParabolic::Action()
{
this->Wait = this->Type->Sleep;
if (ParabolicMissile(*this)) {
this->MissileHit();
this->TTL = 0;
} else {
this->NextMissileFrameCycle();
}
}
//@}

View file

@ -0,0 +1,55 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_pointtopointwithhit.cpp - The missile PointToPointWithHit. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
/**
** Missile flies from x,y to x1,y1 showing the first frame
** and then shows a hit animation.
*/
void MissilePointToPointWithHit::Action()
{
this->Wait = this->Type->Sleep;
if (PointToPointMissile(*this)) {
if (this->NextMissileFrame(1, 0)) {
this->MissileHit();
this->TTL = 0;
}
}
}
//@}

View file

@ -0,0 +1,54 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_pointtopoint.cpp - The missile PointToPoint. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
/**
** Missile flies from x,y to x1,y1 animation on the way
*/
void MissilePointToPoint::Action()
{
this->Wait = this->Type->Sleep;
if (PointToPointMissile(*this)) {
this->MissileHit();
this->TTL = 0;
} else {
this->NextMissileFrame(1, 0);
}
}
//@}

View file

@ -0,0 +1,69 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_pointtopointbounce.cpp - The missile PointToPointBounce. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
#include "map.h"
/**
** Missile flies from x,y to x1,y1 than bounces NumBounces times
*/
void MissilePointToPointBounce::Action()
{
this->Wait = this->Type->Sleep;
if (PointToPointMissile(*this)) {
if (this->State < 2 * this->Type->NumBounces - 1 && this->TotalStep) {
const PixelPos step = (this->destination - this->source);
this->destination += step * ((PixelTileSize.x + PixelTileSize.y) * 3) / 4 / this->TotalStep;
this->State++; // !(State & 1) to initialise
this->source = this->position;
PointToPointMissile(*this);
//this->State++;
this->MissileHit();
// FIXME: hits to left and right
// FIXME: reduce damage effects on later impacts
} else {
this->MissileHit();
this->TTL = 0;
}
} else {
this->NextMissileFrame(1, 0);
}
}
//@}

View file

@ -0,0 +1,54 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_pointtopointcycleoncecpp - The missile PointToPointCycleOnce. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
/**
** Missile flies from x,y to x1,y1 and stays there for a moment
*/
void MissilePointToPointCycleOnce::Action()
{
this->Wait = this->Type->Sleep;
if (PointToPointMissile(*this)) {
this->MissileHit();
this->TTL = 0;
} else {
this->NextMissileFrameCycle();
}
}
//@}

View file

@ -0,0 +1,52 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_stay.cpp - The missile Stay. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
/**
** Missile don't move, than disappears
*/
void MissileStay::Action()
{
this->Wait = this->Type->Sleep;
if (this->NextMissileFrame(1, 0)) {
this->MissileHit();
this->TTL = 0;
}
}
//@}

View file

@ -0,0 +1,89 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_tracer.cpp - The missile Tracer. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include <stdio.h>
#include "stratagus.h"
#include "missile.h"
#include "map.h"
#include "unit.h"
/**
** Handle tracer missile.
**
** @param missile Missile pointer.
**
** @return 1 if goal is reached, 0 else.
*/
static int TracerMissile(Missile &missile)
{
if (MissileInitMove(missile) == 1) {
return 1;
}
Assert(missile.Type != NULL);
Assert(missile.TotalStep != 0);
if (missile.TargetUnit) {
missile.destination.x = missile.TargetUnit->tilePos.x * PixelTileSize.x + missile.TargetUnit->IX;
missile.destination.y = missile.TargetUnit->tilePos.y * PixelTileSize.y + missile.TargetUnit->IY;
}
const PixelPos diff = (missile.destination - missile.source);
missile.position = missile.source + diff * missile.CurrentStep / missile.TotalStep;
if (missile.Type->SmokeMissile && missile.CurrentStep) {
const PixelPos position = missile.position + missile.Type->size / 2;
MakeMissile(*missile.Type->SmokeMissile, position, position);
}
return 0;
}
/**
** Missile flies from x,y to the target position, changing direction on the way
*/
void MissileTracer::Action()
{
this->Wait = this->Type->Sleep;
if (TracerMissile(*this)) {
this->MissileHit();
this->TTL = 0;
} else {
this->NextMissileFrame(1, 0);
}
}
//@}

View file

@ -0,0 +1,115 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name missile_whirlwind.cpp - The missile Whirlwind. */
//
// (c) Copyright 2012 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "missile.h"
#include "map.h"
/**
** Whirlwind controller
**
** @todo do it more configurable.
*/
void MissileWhirlwind::Action()
{
//
// Animate, move.
//
if (!this->AnimWait--) {
if (this->NextMissileFrame(1, 0)) {
this->SpriteFrame = 0;
PointToPointMissile(*this);
}
this->AnimWait = this->Type->Sleep;
}
this->Wait = 1;
//
// Center of the tornado
//
PixelPos center = this->position + this->Type->size / 2;
center.x = (center.x + PixelTileSize.x / 2) / PixelTileSize.x;
center.y = (center.y + PixelTileSize.y) / PixelTileSize.y;
#if 0
CUnit *table[UnitMax];
if (!(this->TTL % 4)) { // Every 4 cycles 4 points damage in tornado center
int n = SelectUnitsOnTile(x, y, table);
for (int i = 0; i < n; ++i) {
if (table[i]->CurrentAction() != UnitActionDie) {
// should be missile damage ?
HitUnit(this->SourceUnit, table[i], WHIRLWIND_DAMAGE1);
}
}
}
if (!(this->TTL % (CYCLES_PER_SECOND / 10))) { // Every 1/10s 1 points damage on tornado periphery
// we should parameter this
int n = SelectUnits(center.x - 1, center.y - 1, center.x + 1, center.y + 1, table);
for (int i = 0; i < n; ++i) {
if ((table[i]->X != center.x || table[i]->Y != center.y) && table[i]->CurrentAction() != UnitActionDie) {
// should be in missile
HitUnit(this->SourceUnit, table[i], WHIRLWIND_DAMAGE2);
}
}
}
DebugPrint("Whirlwind: %d, %d, TTL: %d state: %d\n" _C_
missile->X _C_ missile->Y _C_ missile->TTL _C_ missile->State);
#else
if (!(this->TTL % CYCLES_PER_SECOND / 10)) {
this->MissileHit();
}
#endif
// Changes direction every 3 seconds (approx.)
if (!(this->TTL % 100)) { // missile has reached target unit/spot
int nx;
int ny;
do {
// find new destination in the map
nx = center.x + SyncRand() % 5 - 2;
ny = center.y + SyncRand() % 5 - 2;
} while (!Map.Info.IsPointOnMap(nx, ny));
this->destination.x = nx * PixelTileSize.x + PixelTileSize.x / 2;
this->destination.y = ny * PixelTileSize.y + PixelTileSize.y / 2;
this->source = this->position;
this->State = 0;
DebugPrint("Whirlwind new direction: %d, %d, TTL: %d\n" _C_
this->destination.x _C_ this->destination.y _C_ this->TTL);
}
}
//@}