diff --git a/src/include/missile.h b/src/include/missile.h index 8fb46f59d..31589402e 100644 --- a/src/include/missile.h +++ b/src/include/missile.h @@ -342,13 +342,13 @@ typedef int MissileClass; ** FIXME: We need no class or no controller. */ enum _missile_class_ { - /** - ** Missile does nothing - */ + /** + ** Missile does nothing + */ MissileClassNone, - /** - ** Missile flies from x,y to x1,y1 - */ + /** + ** Missile flies from x,y to x1,y1 + */ MissileClassPointToPoint, /** ** Missile flies from x,y to x1,y1 and stays there for a moment @@ -403,6 +403,10 @@ enum _missile_class_ { ** Missile shows the hit points. */ MissileClassHit, + /** + ** Missile flies from x,y to x1,y1 using a parabolic path + */ + MissileClassParabolic, }; /// Base structure of missile-types @@ -474,6 +478,11 @@ struct _missile_ { int Xstep; /// X step int Ystep; /// Y step + long Angle; /// Angle, for parabolic missiles + long Xl; /// internal use. Will be removed later. + int SourceX; /// Missile Source X + int SourceY; /// Missile Source Y + unsigned Local : 1; /// missile is a local missile Missile** MissileSlot; /// pointer to missile slot }; diff --git a/src/stratagus/missile.cpp b/src/stratagus/missile.cpp index 48f04da49..cdcb12964 100644 --- a/src/stratagus/missile.cpp +++ b/src/stratagus/missile.cpp @@ -10,7 +10,7 @@ // /**@name missile.c - The missiles. */ // -// (c) Copyright 1998-2003 by Lutz Sammer +// (c) Copyright 1998-2003 by Lutz Sammer and Jimmy Salmon // // 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 @@ -78,6 +78,7 @@ global const char* MissileClassNames[] = { "missile-class-fire", "missile-class-custom", "missile-class-hit", + "missile-class-parabolic", NULL }; @@ -288,6 +289,8 @@ local Missile* InitMissile(Missile* missile, MissileType* mtype, int sx, missile->Y = sy - mtype->Height / 2; missile->DX = dx - mtype->Width / 2; missile->DY = dy - mtype->Height / 2; + missile->SourceX = sx; + missile->SourceY = sy; missile->Type = mtype; missile->SpriteFrame = 0; missile->State = 0; @@ -904,6 +907,120 @@ local int PointToPointMissile(Missile* missile) return 0; } +/** +** Calculate parabolic trajectories. +** +** @param missile Missile pointer. +** @param amplitude How high can the missile go. This value depends +** on the missile direction and game perspective. +*/ +local int ParabolicCalc(Missile* missile, int amplitude) +{ + int xmid; + long sinu; + int thetha; + + missile->Xl -= missile->Xstep; + missile->X = missile->Xl / 100; + + xmid = (missile->SourceX + missile->DX) / 2; + sinu = (missile->X - xmid) * (missile->X - xmid); + thetha = missile->SourceX - xmid; + missile->Y = ((missile->Angle * (missile->X - missile->SourceX)) - + amplitude * isqrt(-sinu + thetha * thetha) + missile->SourceY * 100) / 100; + + return 0; +} + +/** +** Calculate parabolic trajectories. +** +** @param missile Missile pointer. +*/ +local int ParabolicMissile(Missile* missile) +{ + int i; + int sx; + int sy; + + if (!(missile->State & 1)) { + int dx; + int dy; + int xstep; + int ystep; + + // initialize + dy = missile->DY - missile->Y; + ystep = 1; + if (dy < 0) { + dy = -dy; + ystep = -1; + } + dx = missile->DX - missile->X; + xstep = 1; + if (dx < 0) { + dx = -dx; + xstep = -1; + } + missile->Angle = (100 * (missile->SourceY - missile->DY)) / + (missile->SourceX - missile->DX); + missile->Xl = missile->X * 100; + + MissileNewHeadingFromXY(missile, dx * xstep, dy * ystep); + + if (dx == 0 && dy == 0) { + return 1; + } + + missile->Dx = dx; + missile->Dy = dy; + dx = missile->SourceX - missile->DX; + dy = missile->SourceY - missile->DY; + missile->Xstep = (100 * dx) / isqrt(dx * dx + dy * dy); + missile->Ystep = ystep; + ++missile->State; + DebugLevel3Fn("Init: %d,%d\n" _C_ dx _C_ dy); + return 0; + } + + sx = missile->X; + sy = missile->Y; + + // + // Move missile + // + if (missile->Dy == 0) { // horizontal line + for (i = 0; i<missile->Type->Speed; ++i) { + if (missile->X == missile->DX) { + return 1; + } + ParabolicCalc(missile, 50); + } + MissileNewHeadingFromXY(missile, missile->X - sx, missile->Y - sy); + return 0; + } + + if (missile->Dx == 0) { // vertical line + for (i = 0; i < missile->Type->Speed; ++i) { + if (missile->Y == missile->DY) { + return 1; + } + missile->Y += missile->Ystep; //no parabolic missile there. + } + return 0; + } + + for (i = 0; i < missile->Type->Speed; ++i) { + if (abs(missile->X - missile->DX) <= 1 && + abs(missile->Y - missile->DY) <= 1) { + return 1; + } + ParabolicCalc(missile, 100); + MissileNewHeadingFromXY(missile, missile->X - sx, missile->Y - sy); + } + return 0; +} + /** ** Missile hits the goal. ** @@ -1119,7 +1236,7 @@ local void MissileAction(Missile* missile) neg = 1; missile->SpriteFrame = -missile->SpriteFrame; } - missile->SpriteFrame += 5; // FIXME: frames pro row + missile->SpriteFrame += 5; // FIXME: frames per row if (missile->SpriteFrame >= VideoGraphicFrames(missile->Type->Sprite)) { missile->SpriteFrame-= VideoGraphicFrames(missile->Type->Sprite); @@ -1140,10 +1257,36 @@ local void MissileAction(Missile* missile) FreeMissile(missile); missile = NULL; } else { - // - // Animate missile, depends on the way. - // FIXME: becomes bigger than smaller. - // FIXME: how? + int totalx; + int dx; + int f; + int i; + int j; + + neg = 0; + if (missile->SpriteFrame < 0) { + neg = 1; + missile->SpriteFrame = -missile->SpriteFrame; + } + totalx = abs(missile->DX - missile->SourceX); + dx = abs(missile->X - missile->SourceX); + f = VideoGraphicFrames(missile->Type->Sprite) / 5; // FIXME: frames per row + f = 2 * f - 1; + for (i = 1, j = 1; i <= f; ++i) { + if (dx * f / i < totalx) { + if ((i - 1) * 2 < f) { + j = i - 1; + } else { + j = f - i; + } + missile->SpriteFrame = missile->SpriteFrame % 5 + + j * 5; // FIXME: frames per row + break; + } + } + if (neg) { + missile->SpriteFrame = -missile->SpriteFrame; + } } break; @@ -1178,7 +1321,7 @@ local void MissileAction(Missile* missile) neg = 1; missile->SpriteFrame = -missile->SpriteFrame; } - missile->SpriteFrame += 5; // FIXME: frames pro row + missile->SpriteFrame += 5; // FIXME: frames per row if (missile->SpriteFrame >= VideoGraphicFrames(missile->Type->Sprite)) { missile->SpriteFrame-= VideoGraphicFrames(missile->Type->Sprite); @@ -1392,6 +1535,46 @@ local void MissileAction(Missile* missile) } break; } + + case MissileClassParabolic: + missile->Wait = missile->Type->Sleep; + if (ParabolicMissile(missile)) { + MissileHit(missile); + FreeMissile(missile); + missile = NULL; + } else { + int totalx; + int dx; + int f; + int i; + int j; + + neg = 0; + if (missile->SpriteFrame < 0) { + neg = 1; + missile->SpriteFrame = -missile->SpriteFrame; + } + totalx = abs(missile->DX - missile->SourceX); + dx = abs(missile->X - missile->SourceX); + f = VideoGraphicFrames(missile->Type->Sprite) / 5; // FIXME: frames per row + f = 2 * f - 1; + for (i = 1, j = 1; i <= f; ++i) { + if (dx * f / i < totalx) { + if ((i - 1) * 2 < f) { + j = i - 1; + } else { + j = f - i; + } + missile->SpriteFrame = missile->SpriteFrame % 5 + + j * 5; // FIXME: frames per row + break; + } + } + if (neg) { + missile->SpriteFrame = -missile->SpriteFrame; + } + } + break; } if (missile) { // check after movement