Some clean up with Missile :

- use ref
- use PixelPos instead of x, y
This commit is contained in:
joris 2012-02-19 16:46:07 +01:00
parent 006cba3793
commit 1d66191f8d
12 changed files with 265 additions and 324 deletions

View file

@ -1086,7 +1086,8 @@ int UnitShowAnimationScaled(CUnit &unit, const CAnimation *anim, int scale)
const int desty = ParseAnimInt(&unit, unit.Anim.Anim->D.SpawnMissile.DestY);
const int flags = ParseAnimFlags(unit, unit.Anim.Anim->D.SpawnMissile.Flags);
CUnit *goal;
int x, y, dx, dy;
PixelPos start;
PixelPos dest;
if ((flags & ANIM_SM_RELTARGET) && unit.CurrentOrder()->HasGoal()) {
goal = unit.CurrentOrder()->GetGoal();
@ -1094,37 +1095,37 @@ int UnitShowAnimationScaled(CUnit &unit, const CAnimation *anim, int scale)
goal = &unit;
}
if ((flags & ANIM_SM_PIXEL)) {
x = goal->tilePos.x * PixelTileSize.x + goal->IX + startx;
y = goal->tilePos.y * PixelTileSize.y + goal->IY + starty;
start.x = goal->tilePos.x * PixelTileSize.x + goal->IX + startx;
start.y = goal->tilePos.y * PixelTileSize.y + goal->IY + starty;
} else {
x = (goal->tilePos.x + startx) * PixelTileSize.x + PixelTileSize.x / 2;
y = (goal->tilePos.y + starty) * PixelTileSize.y + PixelTileSize.y / 2;
start.x = (goal->tilePos.x + startx) * PixelTileSize.x + PixelTileSize.x / 2;
start.y = (goal->tilePos.y + starty) * PixelTileSize.y + PixelTileSize.y / 2;
}
if ((flags & ANIM_SM_TOTARGET) && goal->CurrentOrder()->HasGoal()) {
CUnit &target = *goal->CurrentOrder()->GetGoal();
if (flags & ANIM_SM_PIXEL) {
dx = target.tilePos.x * PixelTileSize.x + target.IX;
dy = target.tilePos.y * PixelTileSize.y + target.IY;
dest.x = target.tilePos.x * PixelTileSize.x + target.IX;
dest.y = target.tilePos.y * PixelTileSize.y + target.IY;
} else {
dx = target.tilePos.x * PixelTileSize.x + PixelTileSize.x / 2;
dy = target.tilePos.y * PixelTileSize.y + PixelTileSize.y / 2;
dest.x = target.tilePos.x * PixelTileSize.x + PixelTileSize.x / 2;
dest.y = target.tilePos.y * PixelTileSize.y + PixelTileSize.y / 2;
}
} else {
if ((flags & ANIM_SM_PIXEL)) {
dx = goal->tilePos.x * PixelTileSize.x + goal->IX + destx;
dy = goal->tilePos.y * PixelTileSize.y + goal->IY + desty;
dest.x = goal->tilePos.x * PixelTileSize.x + goal->IX + destx;
dest.y = goal->tilePos.y * PixelTileSize.y + goal->IY + desty;
} else {
dx = (unit.tilePos.x + destx) * PixelTileSize.x + PixelTileSize.x / 2;
dy = (unit.tilePos.y + desty) * PixelTileSize.y + PixelTileSize.y / 2;
dest.x = (unit.tilePos.x + destx) * PixelTileSize.x + PixelTileSize.x / 2;
dest.y = (unit.tilePos.y + desty) * PixelTileSize.y + PixelTileSize.y / 2;
}
}
const int dist = goal->MapDistanceTo(dx, dy);
const int dist = goal->MapDistanceTo(dest.x, dest.y);
if ((flags & ANIM_SM_RANGED) && !(flags & ANIM_SM_PIXEL)
&& dist > goal->Stats->Variables[ATTACKRANGE_INDEX].Max
&& dist < goal->Type->MinAttackRange) {
} else {
Missile *missile = MakeMissile(MissileTypeByIdent(unit.Anim.Anim->D.SpawnMissile.Missile), x, y, dx, dy);
Missile *missile = MakeMissile(*MissileTypeByIdent(unit.Anim.Anim->D.SpawnMissile.Missile), start, dest);
if (flags & ANIM_SM_DAMAGE) {
missile->SourceUnit = &unit;
}

View file

@ -150,7 +150,7 @@ int SaveGame(const std::string &filename)
SaveAi(&file);
SaveSelections(&file);
SaveGroups(&file);
SaveMissiles(&file);
SaveMissiles(file);
SaveReplayList(&file);
// FIXME: find all state information which must be saved.
s = SaveGlobal(Lua, true);

View file

@ -102,7 +102,7 @@
**
** Class of the missile-type, defines the basic effects of the
** missile. Look at the different class identifiers for more
** informations (::_missile_class_, ::MissileClassNone, ...).
** informations (::MissileClassNone, ...).
**
** MissileType::NumBounces
**
@ -334,48 +334,27 @@ class LuaCallback;
#define MAX_MISSILES 2048 /// maximum number of missiles
#define MAX_LOCAL_MISSILES 4096 /// maximum number of local missiles
/**
** Missile-type-class typedef
*/
typedef int MissileClass;
/**
** Missile-class this defines how a missile-type reacts.
**
*/
enum _missile_class_ {
/// Missile does nothing
MissileClassNone,
/// Missile flies from x,y to x1,y1
MissileClassPointToPoint,
/// Missile flies from x,y to x1,y1 than shows hit animation.
MissileClassPointToPointWithHit,
/// Missile flies from x,y to x1,y1 and animates ONCE from start to finish and back
MissileClassPointToPointCycleOnce,
/// Missile flies from x,y to x1,y1 than bounces three times.
MissileClassPointToPointBounce,
/// Missile appears at x,y, does it's anim and vanishes.
MissileClassStay,
/// Missile appears at x,y, then cycle through the frames once.
MissileClassCycleOnce,
/// Missile doesn't move, than checks the source unit for HP.
MissileClassFire,
/// Missile shows the hit points.
MissileClassHit,
/// Missile flies from x,y to x1,y1 using a parabolic path
MissileClassParabolic,
/// Missile wait on x,y until a non-air unit comes by, the explodes.
MissileClassLandMine,
/// Missile appears at x,y, is whirlwind
MissileClassWhirlwind,
/// Missile surround x,y
MissileClassFlameShield,
/// Missile is death coil.
MissileClassDeathCoil,
/// Missile seeks towards to target unit
MissileClassTracer,
/// Missile remains clipped to target's current goal and plays his animation once
MissileClassClipToTarget
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
};
/// Base structure of missile-types
@ -388,15 +367,11 @@ public:
void LoadMissileSprite();
void Init();
void DrawMissileType(int frame, const PixelPos &pos) const;
void DrawMissileType(int frame, int x, int y) const {
PixelPos pos = {x, y};
DrawMissileType(frame, pos);
}
int Width() const { return size.x; }
int Height() const { return size.y; }
//private:
std::string Ident; /// missile name
int Transparency; /// missile transparency
PixelSize size; /// missile size in pixels
@ -413,7 +388,7 @@ public:
bool CanHitOwner; /// missile can hit the owner
bool FriendlyFire; /// missile can't hit own units
MissileClass Class; /// missile class
int Class; /// missile class
int NumBounces; /// number of bounces
int StartDelay; /// missile start delay
int Sleep; /// missile sleep
@ -436,30 +411,25 @@ public:
----------------------------------------------------------------------------*/
/// Missile on the map
class Missile {
class Missile
{
protected:
Missile();
public:
virtual ~Missile() {};
static Missile *Init(MissileType *mtype, const PixelPos &startPos, const PixelPos &destPos);
static Missile *Init(MissileType *mtype, int sx, int sy, int dx, int dy) {
PixelPos startPos = {sx, sy};
PixelPos destPos = {dx, dy};
return Init(mtype, startPos, destPos);
}
static Missile *Init(const MissileType &mtype, const PixelPos &startPos, const PixelPos &destPos);
virtual void Action() = 0;
void DrawMissile(const CViewport *vp) const;
void SaveMissile(CFile *file) const;
void DrawMissile(const CViewport &vp) const;
void SaveMissile(CFile &file) const;
PixelPos source; /// Missile source position
PixelPos position; /// missile pixel position
PixelPos destination; /// missile pixel destination
MissileType *Type; /// missile-type pointer
const MissileType *Type; /// missile-type pointer
int SpriteFrame; /// sprite frame counter
int State; /// state
int AnimWait; /// Animation wait.
@ -484,20 +454,19 @@ public:
static unsigned int Count; /// slot number generator.
};
struct MissileDrawProxy
class MissileDrawProxy
{
MissileType *Type; /// missile-type pointer
public:
void DrawMissile(const CViewport &vp) const;
void operator=(const Missile* missile);
public:
const MissileType *Type; /// missile-type pointer
union {
int Damage; /// direct damage that missile applies
int SpriteFrame; /// sprite frame counter
} data;
short X;
short Y;
void DrawMissile(const CViewport *vp) const;
void operator=(const Missile* missile);
PixelPos pixelPos;
};
class MissileNone : public Missile {
@ -599,40 +568,26 @@ extern MissileType *NewMissileTypeSlot(const std::string& ident);
/// Get missile-type by ident
extern MissileType *MissileTypeByIdent(const std::string& ident);
/// create a missile
extern Missile *MakeMissile(MissileType *mtype, const PixelPos &startPos, const PixelPos &destPos);
inline Missile *MakeMissile(MissileType *mtype, int sx, int sy, int dx, int dy) {
const PixelPos startPos = {sx, sy};
const PixelPos destPos = {dx, dy};
return MakeMissile(mtype, startPos, destPos);
}
extern Missile *MakeMissile(const MissileType &mtype, const PixelPos &startPos, const PixelPos &destPos);
/// create a local missile
extern Missile *MakeLocalMissile(MissileType *mtype, const PixelPos &startPos, const PixelPos &destPos);
inline Missile *MakeLocalMissile(MissileType *mtype, int sx, int sy, int dx, int dy) {
const PixelPos startPos = {sx, sy};
const PixelPos destPos = {dx, dy};
return MakeLocalMissile(mtype, startPos, destPos);
}
extern Missile *MakeLocalMissile(const MissileType &mtype, const PixelPos &startPos, const PixelPos &destPos);
/// fire a missile
extern void FireMissile(CUnit &unit);
extern int FindAndSortMissiles(const CViewport *vp,
Missile *table[], const int tablesize);
extern int FindAndSortMissiles(const CViewport *vp,
MissileDrawProxy table[], const int tablesize);
extern int FindAndSortMissiles(const CViewport &vp, Missile *table[], const int tablesize);
extern int FindAndSortMissiles(const CViewport &vp, MissileDrawProxy table[], const int tablesize);
/// handle all missiles
extern void MissileActions();
/// distance from view point to missile
extern int ViewPointDistanceToMissile(const Missile *missile);
extern int ViewPointDistanceToMissile(const Missile &missile);
/// Get the burning building missile based on hp percent
extern MissileType *MissileBurningBuilding(int percent);
/// Save missiles
extern void SaveMissiles(CFile *file);
extern void SaveMissiles(CFile &file);
/// Initialize missile-types
extern void InitMissileTypes();

View file

@ -182,6 +182,11 @@ public:
/// Convert map pixel coordinates into viewport coordinates
void MapPixel2Viewport(int &x, int &y) const;
// Convert screen coordinates into map pixel coordinates
PixelPos ScreenToMapPixelPos(const PixelPos& screenPixelPos) const;
// Convert map pixel coordinates into screen coordinates
PixelPos MapToScreenPixelPos(const PixelPos& mapPixelPos) const;
/// Set the current map view to x,y(upper,left corner)
void Set(int x, int y, int offsetx, int offsety);
/// Center map on point in viewport

View file

@ -768,6 +768,8 @@ public:
bool CanMove() const { return Type->CanMove(); }
int GetDrawLevel() const;
PixelPos GetMapPixelPosCenter() const;
};
typedef COrder* COrderPtr;
@ -1011,6 +1013,8 @@ extern void UpdateForNewUnit(const CUnit &unit, int upgrade);
/// @todo more docu
extern void NearestOfUnit(const CUnit &unit, const Vec2i& pos, Vec2i *dpos);
extern CUnit *GetFirstContainer(const CUnit &unit);
/// Call when an Unit goes under fog.
extern void UnitGoesUnderFog(CUnit &unit, const CPlayer &player);
/// Call when an Unit goes out of fog.

View file

@ -163,6 +163,27 @@ void CViewport::MapPixel2Viewport(int &x, int &y) const
y = y + this->Y - (this->MapY * PixelTileSize.y + this->OffsetY);
}
// Convert viewport coordinates into map pixel coordinates
PixelPos CViewport::ScreenToMapPixelPos(const PixelPos &screenPixelPos) const
{
const int x = (screenPixelPos.x - this->X + this->MapX * PixelTileSize.x + this->OffsetX);
const int y = (screenPixelPos.y - this->Y + this->MapY * PixelTileSize.y + this->OffsetY);
const PixelPos mapPixelPos = {x, y};
return mapPixelPos;
}
// Convert map pixel coordinates into viewport coordinates
PixelPos CViewport::MapToScreenPixelPos(const PixelPos &mapPixelPos) const
{
PixelPos screenPixelPos = {
mapPixelPos.x + this->X - (this->MapX * PixelTileSize.x + this->OffsetX),
mapPixelPos.y + this->Y - (this->MapY * PixelTileSize.y + this->OffsetY)
};
return screenPixelPos;
}
/**
** Change viewpoint of map viewport v to x,y.
**
@ -341,7 +362,7 @@ public:
//
if (lock.TryLock()) {
nunits = FindAndSortUnits(vp, unittable);
nmissiles = FindAndSortMissiles(vp, missiletable, MAX_MISSILES * 9);
nmissiles = FindAndSortMissiles(*vp, missiletable, MAX_MISSILES * 9);
lock.UnLock();
}
}
@ -355,7 +376,7 @@ public:
unittable[i].Draw(vp);
++i;
} else {
missiletable[j].DrawMissile(vp);
missiletable[j].DrawMissile(*vp);
++j;
}
}
@ -363,7 +384,7 @@ public:
unittable[i].Draw(vp);
}
for (; j < nmissiles; ++j) {
missiletable[j].DrawMissile(vp);
missiletable[j].DrawMissile(*vp);
}
lock.UnLock();
}
@ -406,7 +427,7 @@ void CViewport::Draw() const
// We find and sort units after draw level.
//
int nunits = FindAndSortUnits(this, unittable);
int nmissiles = FindAndSortMissiles(this, missiletable, MAX_MISSILES * 9);
int nmissiles = FindAndSortMissiles(*this, missiletable, MAX_MISSILES * 9);
int i = 0;
int j = 0;
@ -415,7 +436,7 @@ void CViewport::Draw() const
unittable[i]->Draw(this);
++i;
} else {
missiletable[j]->DrawMissile(this);
missiletable[j]->DrawMissile(*this);
++j;
}
}
@ -423,7 +444,7 @@ void CViewport::Draw() const
unittable[i]->Draw(this);
}
for (; j < nmissiles; ++j) {
missiletable[j]->DrawMissile(this);
missiletable[j]->DrawMissile(*this);
}
}

View file

@ -334,7 +334,7 @@ void PlayMissileSound(const Missile *missile, CSound *sound)
if (channel == -1) {
return;
}
SetChannelVolume(channel, CalculateVolume(false, ViewPointDistanceToMissile(missile), sound->Range));
SetChannelVolume(channel, CalculateVolume(false, ViewPointDistanceToMissile(*missile), sound->Range));
SetChannelStereo(channel, stereo);
}

View file

@ -169,11 +169,11 @@ Missile::Missile() :
**
** @return created missile.
*/
Missile *Missile::Init(MissileType *mtype, const PixelPos &startPos, const PixelPos &destPos)
/* static */ Missile *Missile::Init(const MissileType &mtype, const PixelPos &startPos, const PixelPos &destPos)
{
Missile *missile = NULL;
switch (mtype->Class) {
switch (mtype.Class) {
case MissileClassNone :
missile = new MissileNone;
break;
@ -223,13 +223,13 @@ Missile *Missile::Init(MissileType *mtype, const PixelPos &startPos, const Pixel
missile = new MissileClipToTarget;
break;
}
const PixelPos halfSize = mtype->size / 2;
const PixelPos halfSize = mtype.size / 2;
missile->position = startPos - halfSize;
missile->destination = destPos - halfSize;
missile->source = missile->position;
missile->Type = mtype;
missile->Wait = mtype->Sleep;
missile->Delay = mtype->StartDelay;
missile->Type = &mtype;
missile->Wait = mtype.Sleep;
missile->Delay = mtype.StartDelay;
return missile;
}
@ -243,7 +243,7 @@ Missile *Missile::Init(MissileType *mtype, const PixelPos &startPos, const Pixel
**
** @return created missile.
*/
Missile *MakeMissile(MissileType *mtype, const PixelPos &startPos, const PixelPos &destPos)
Missile *MakeMissile(const MissileType &mtype, const PixelPos &startPos, const PixelPos &destPos)
{
Missile *missile = Missile::Init(mtype, startPos, destPos);
@ -260,7 +260,7 @@ Missile *MakeMissile(MissileType *mtype, const PixelPos &startPos, const PixelPo
**
** @return created missile.
*/
Missile *MakeLocalMissile(MissileType *mtype, const PixelPos &startPos, const PixelPos &destPos)
Missile *MakeLocalMissile(const MissileType &mtype, const PixelPos &startPos, const PixelPos &destPos)
{
Missile *missile = Missile::Init(mtype, startPos, destPos);
@ -356,6 +356,19 @@ static int CalculateDamage(const CUnit &attacker, const CUnit &goal)
return res;
}
/**
** Get pixel position of the center of the specified tilePos.
*/
static PixelPos GetPixelPosFromCenterTile(const Vec2i& tilePos)
{
PixelPos pixelPos = {tilePos.x * PixelTileSize.x + PixelTileSize.x / 2,
tilePos.y * PixelTileSize.y + PixelTileSize.y / 2};
return pixelPos;
}
/**
** Fire missile.
**
@ -363,17 +376,11 @@ static int CalculateDamage(const CUnit &attacker, const CUnit &goal)
*/
void FireMissile(CUnit &unit)
{
int x;
int y;
CUnit *goal = unit.CurrentOrder()->GetGoal();
//
// Goal dead?
//
if (goal) {
// Better let the caller/action handle this.
if (goal->Destroyed) {
DebugPrint("destroyed unit\n");
return;
@ -381,14 +388,11 @@ void FireMissile(CUnit &unit)
if (goal->Removed || goal->CurrentAction() == UnitActionDie) {
return;
}
// FIXME: Some missile hit the field of the target and all units on it.
// FIXME: goal is already dead, but missile could hit others?
}
//
// No missile hits immediately!
//
if (unit.Type->Missile.Missile->Class == MissileClassNone) {
// No goal, take target coordinates
if (!goal) {
@ -414,20 +418,14 @@ void FireMissile(CUnit &unit)
}
// If Firing from inside a Bunker
if (unit.Container) {
x = unit.Container->tilePos.x * PixelTileSize.x + PixelTileSize.x / 2; // missile starts in tile middle
y = unit.Container->tilePos.y * PixelTileSize.y + PixelTileSize.y / 2;
} else {
x = unit.tilePos.x * PixelTileSize.x + PixelTileSize.x / 2; // missile starts in tile middle
y = unit.tilePos.y * PixelTileSize.y + PixelTileSize.y / 2;
}
CUnit* from = GetFirstContainer(unit);
const PixelPos startPixelPos = GetPixelPosFromCenterTile(from->tilePos);
Vec2i dpos;
if (goal) {
Assert(goal->Type); // Target invalid?
//
// Moved out of attack range?
//
if (unit.MapDistanceTo(*goal) < unit.Type->MinAttackRange) {
DebugPrint("Missile target too near %d,%d\n" _C_
unit.MapDistanceTo(*goal) _C_ unit.Type->MinAttackRange);
@ -436,20 +434,14 @@ void FireMissile(CUnit &unit)
}
// Fire to nearest point of the unit!
// If Firing from inside a Bunker
if (unit.Container) {
NearestOfUnit(*goal, unit.Container->tilePos, &dpos);
} else {
NearestOfUnit(*goal, unit.tilePos, &dpos);
}
NearestOfUnit(*goal, GetFirstContainer(unit)->tilePos, &dpos);
} else {
dpos = unit.CurrentOrder()->goalPos;
// FIXME: Can this be too near??
}
// Fire to the tile center of the destination.
dpos.x = dpos.x * PixelTileSize.x + PixelTileSize.x / 2;
dpos.y = dpos.y * PixelTileSize.y + PixelTileSize.y / 2;
Missile *missile = MakeMissile(unit.Type->Missile.Missile, x, y, dpos.x, dpos.y);
const PixelPos destPixelPos = GetPixelPosFromCenterTile(dpos);
Missile *missile = MakeMissile(*unit.Type->Missile.Missile, startPixelPos, destPixelPos);
//
// Damage of missile
//
@ -556,25 +548,23 @@ void MissileType::DrawMissileType(int frame, const PixelPos &pos) const
}
}
void MissileDrawProxy::DrawMissile(const CViewport *vp) const
void MissileDrawProxy::DrawMissile(const CViewport &vp) const
{
const int x = this->X - vp->MapX * PixelTileSize.x + vp->X - vp->OffsetX;
const int y = this->Y - vp->MapY * PixelTileSize.y + vp->Y - vp->OffsetY;
const PixelPos sceenPixelPos = vp.MapToScreenPixelPos(this->pixelPos);
switch (this->Type->Class) {
case MissileClassHit:
CLabel(GetGameFont()).DrawClip(x,y, this->data.Damage);
//VideoDrawNumberClip(x, y, GetGameFont(), this->data.Damage);
CLabel(GetGameFont()).DrawClip(sceenPixelPos.x, sceenPixelPos.y, this->data.Damage);
break;
default:
this->Type->DrawMissileType(this->data.SpriteFrame, x, y);
this->Type->DrawMissileType(this->data.SpriteFrame, sceenPixelPos);
break;
}
}
void MissileDrawProxy::operator=(const Missile* missile) {
this->Type = missile->Type;
this->X = missile->position.x;
this->Y = missile->position.y;
this->pixelPos = missile->position;
if (missile->Type->Class == MissileClassHit) {
this->data.Damage = missile->Damage;
} else {
@ -585,7 +575,7 @@ void MissileDrawProxy::operator=(const Missile* missile) {
/**
** Draw missile.
*/
void Missile::DrawMissile(const CViewport *vp) const
void Missile::DrawMissile(const CViewport &vp) const
{
Assert(this->Type);
@ -597,20 +587,19 @@ void Missile::DrawMissile(const CViewport *vp) const
}
#endif
}
const int x = this->position.x - vp->MapX * PixelTileSize.x + vp->X - vp->OffsetX;
const int y = this->position.y - vp->MapY * PixelTileSize.y + vp->Y - vp->OffsetY;
const PixelPos screenPixelPos = vp.MapToScreenPixelPos(this->position);
switch (this->Type->Class) {
case MissileClassHit:
CLabel(GetGameFont()).DrawClip(x, y, this->Damage);
CLabel(GetGameFont()).DrawClip(screenPixelPos.x, screenPixelPos.y, this->Damage);
break;
default:
this->Type->DrawMissileType(this->SpriteFrame, x, y);
this->Type->DrawMissileType(this->SpriteFrame, screenPixelPos);
break;
}
}
static bool MissileDrawLevelCompare(const Missile*const l,
const Missile*const r)
static bool MissileDrawLevelCompare(const Missile*const l, const Missile*const r)
{
if (l->Type->DrawLevel == r->Type->DrawLevel) {
return l->Slot < r->Slot;
@ -628,22 +617,19 @@ static bool MissileDrawLevelCompare(const Missile*const l,
**
** @return number of missiles returned in table
*/
int FindAndSortMissiles(const CViewport *vp,
Missile *table[], const int tablesize)
int FindAndSortMissiles(const CViewport &vp, Missile *table[], const int tablesize)
{
int nmissiles = 0;
std::vector<Missile *>::const_iterator i;
//
// Loop through global missiles, then through locals.
//
for (i = GlobalMissiles.begin(); i != GlobalMissiles.end() && nmissiles < tablesize; ++i) {
Missile &missile = *(*i);
if (missile.Delay || missile.Hidden) {
continue; // delayed or hidden -> aren't shown
}
// Draw only visible missiles
if (MissileVisibleInViewport(*vp, missile)) {
if (MissileVisibleInViewport(vp, missile)) {
table[nmissiles++] = &missile;
}
}
@ -662,19 +648,15 @@ int FindAndSortMissiles(const CViewport *vp,
return nmissiles;
}
int FindAndSortMissiles(const CViewport *vp,
MissileDrawProxy table[], const int tablesize)
int FindAndSortMissiles(const CViewport &vp, MissileDrawProxy table[], const int tablesize)
{
Assert(tablesize <= MAX_MISSILES * 9);
Missile *buffer[MAX_MISSILES * 9];
int n = FindAndSortMissiles(vp, buffer, MAX_MISSILES * 9);
const int n = FindAndSortMissiles(vp, buffer, MAX_MISSILES * 9);
if (n > 0) {
table[0] = buffer[0];
for (int i = 1; i < n; ++i) {
table[i] = buffer[i];
}
for (int i = 0; i < n; ++i) {
table[i] = buffer[i];
}
return n;
}
@ -764,7 +746,7 @@ static int PointToPointMissile(Missile &missile)
if (missile.Type->SmokeMissile && missile.CurrentStep) {
const PixelPos position = missile.position + missile.Type->size / 2;
MakeMissile(missile.Type->SmokeMissile, position, position);
MakeMissile(*missile.Type->SmokeMissile, position, position);
}
return 0;
}
@ -794,7 +776,7 @@ static int TracerMissile(Missile &missile)
if (missile.Type->SmokeMissile && missile.CurrentStep) {
const PixelPos position = missile.position + missile.Type->size / 2;
MakeMissile(missile.Type->SmokeMissile, position, position);
MakeMissile(*missile.Type->SmokeMissile, position, position);
}
return 0;
}
@ -835,7 +817,7 @@ static int ParabolicMissile(Missile &missile)
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);
MakeMissile(*missile.Type->SmokeMissile, position, position);
}
return 0;
}
@ -913,7 +895,7 @@ static void MissileHit(Missile &missile)
// The impact generates a new missile.
//
if (mtype.ImpactMissile) {
MakeMissile(mtype.ImpactMissile, pixelPos, pixelPos);
MakeMissile(*mtype.ImpactMissile, pixelPos, pixelPos);
}
if (mtype.ImpactParticle) {
mtype.ImpactParticle->pushPreamble();
@ -1162,9 +1144,9 @@ void MissileActions()
**
** @return the computed value.
*/
int ViewPointDistanceToMissile(const Missile *missile)
int ViewPointDistanceToMissile(const Missile &missile)
{
const PixelPos pixelPos = missile->position + missile->Type->size / 2;
const PixelPos pixelPos = missile.position + missile.Type->size / 2;
const Vec2i tilePos = { pixelPos.x / PixelTileSize.x, pixelPos.y / PixelTileSize.y };
return ViewPointDistance(tilePos);
@ -1188,39 +1170,47 @@ MissileType *MissileBurningBuilding(int percent)
return NULL;
}
/**
** Save a specific pos.
*/
static void SavePixelPos(CFile &file, const PixelPos &pos)
{
file.printf("{%d, %d}", pos.x, pos.y);
}
/**
** Save the state of a missile to file.
**
** @param file Output file.
*/
void Missile::SaveMissile(CFile *file) const
void Missile::SaveMissile(CFile &file) const
{
file->printf("Missile(\"type\", \"%s\",", this->Type->Ident.c_str());
file->printf(" \"%s\",", this->Local ? "local" : "global");
file->printf(" \"pos\", {%d, %d}, \"origin-pos\", {%d, %d}, \"goal\", {%d, %d},",
this->position.x, this->position.y, this->source.x, this->source.y, this->destination.x, this->destination.y);
file->printf("\n \"frame\", %d, \"state\", %d, \"anim-wait\", %d, \"wait\", %d, \"delay\", %d,\n ",
file.printf("Missile(\"type\", \"%s\",", this->Type->Ident.c_str());
file.printf(" \"%s\",", this->Local ? "local" : "global");
file.printf(" \"pos\", ");
SavePixelPos(file, this->position);
file.printf(", \"origin-pos\", ");
SavePixelPos(file, this->source);
file.printf(", \"goal\", ");
SavePixelPos(file, this->destination);
file.printf(",\n \"frame\", %d, \"state\", %d, \"anim-wait\", %d, \"wait\", %d, \"delay\", %d,\n ",
this->SpriteFrame, this->State, this->AnimWait, this->Wait, this->Delay);
if (this->SourceUnit) {
file->printf(" \"source\", \"%s\",", UnitReference(*this->SourceUnit).c_str());
file.printf(" \"source\", \"%s\",", UnitReference(*this->SourceUnit).c_str());
}
if (this->TargetUnit) {
file->printf(" \"target\", \"%s\",", UnitReference(*this->TargetUnit).c_str());
file.printf(" \"target\", \"%s\",", UnitReference(*this->TargetUnit).c_str());
}
file->printf(" \"damage\", %d,", this->Damage);
file->printf(" \"ttl\", %d,", this->TTL);
file.printf(" \"damage\", %d,", this->Damage);
file.printf(" \"ttl\", %d,", this->TTL);
if (this->Hidden) {
file->printf(" \"hidden\", ");
file.printf(" \"hidden\", ");
}
file->printf(" \"step\", {%d, %d}", this->CurrentStep, this->TotalStep);
file.printf(" \"step\", {%d, %d}", this->CurrentStep, this->TotalStep);
// Slot filled in during init
file->printf(")\n");
file.printf(")\n");
}
/**
@ -1228,12 +1218,12 @@ void Missile::SaveMissile(CFile *file) const
**
** @param file Output file.
*/
void SaveMissiles(CFile *file)
void SaveMissiles(CFile &file)
{
std::vector<Missile *>::const_iterator i;
file->printf("\n--- -----------------------------------------\n");
file->printf("--- MODULE: missiles\n\n");
file.printf("\n--- -----------------------------------------\n");
file.printf("--- MODULE: missiles\n\n");
for (i = GlobalMissiles.begin(); i != GlobalMissiles.end(); ++i) {
(*i)->SaveMissile(file);
@ -1248,9 +1238,7 @@ void SaveMissiles(CFile *file)
*/
void MissileType::Init()
{
//
// Resolve impact missiles and sounds.
//
if (!this->FiredSound.Name.empty()) {
this->FiredSound.Sound = SoundForName(this->FiredSound.Name);
}
@ -1274,7 +1262,6 @@ void InitMissileTypes()
#endif
for (std::vector<MissileType*>::iterator i = MissileTypes.begin(); i != MissileTypes.end(); ++i) {
(*i)->Init();
}
}

View file

@ -87,21 +87,14 @@ static const char *MissileClassNames[] = {
*/
static int CclDefineMissileType(lua_State *l)
{
const char *value;
const char *str;
MissileType *mtype;
unsigned i;
std::string file;
LuaCheckArgs(l, 2);
if (!lua_istable(l, 2)) {
LuaError(l, "incorrect argument");
}
// Slot identifier
str = LuaToString(l, 1);
mtype = MissileTypeByIdent(str);
const char *str = LuaToString(l, 1);
MissileType *mtype = MissileTypeByIdent(str);
if (mtype) {
DebugPrint("Redefining missile-type `%s'\n" _C_ str);
@ -114,11 +107,11 @@ static int CclDefineMissileType(lua_State *l)
// Ensure we don't divide by zero.
mtype->SplashFactor = 100;
//
// Parse the arguments
//
std::string file;
for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
value = LuaToString(l, -2);
const char *value = LuaToString(l, -2);
if (!strcmp(value, "File")) {
file = LuaToString(l, -1);
} else if (!strcmp(value, "Size")) {
@ -144,9 +137,10 @@ static int CclDefineMissileType(lua_State *l)
} else if (!strcmp(value, "ImpactSound")) {
mtype->ImpactSound.Name = LuaToString(l, -1);
} else if (!strcmp(value, "Class")) {
value = LuaToString(l, -1);
for (i = 0; MissileClassNames[i]; ++i) {
if (!strcmp(value, MissileClassNames[i])) {
const char* className = LuaToString(l, -1);
unsigned int i = 0;
for (; MissileClassNames[i]; ++i) {
if (!strcmp(className, MissileClassNames[i])) {
mtype->Class = i;
break;
}
@ -246,12 +240,12 @@ static int CclMissile(lua_State *l)
lua_pop(l, 1);
} else if (!strcmp(value, "local")) {
Assert(type);
missile = MakeLocalMissile(type, position, destination);
missile = MakeLocalMissile(*type, position, destination);
missile->Local = 1;
--j;
} else if (!strcmp(value, "global")) {
Assert(type);
missile = MakeMissile(type, position, destination);
missile = MakeMissile(*type, position, destination);
missile->position = position;
missile->source = source;
missile->destination = destination;
@ -325,30 +319,23 @@ static int CclMissile(lua_State *l)
*/
static int CclDefineBurningBuilding(lua_State *l)
{
const char *value;
BurningBuildingFrame *ptr;
int args;
int j;
int subargs;
int k;
for (std::vector<BurningBuildingFrame *>::iterator i = BurningBuildingFrames.begin();
i != BurningBuildingFrames.end(); ++i) {
delete *i;
}
BurningBuildingFrames.clear();
args = lua_gettop(l);
for (j = 0; j < args; ++j) {
const int args = lua_gettop(l);
for (int j = 0; j < args; ++j) {
if (!lua_istable(l, j + 1)) {
LuaError(l, "incorrect argument");
}
BurningBuildingFrame *ptr = new BurningBuildingFrame;
const int subargs = lua_objlen(l, j + 1);
ptr = new BurningBuildingFrame;
subargs = lua_objlen(l, j + 1);
for (k = 0; k < subargs; ++k) {
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, j + 1, k + 1);
value = LuaToString(l, -1);
const char *value = LuaToString(l, -1);
lua_pop(l, 1);
++k;

View file

@ -236,38 +236,28 @@ int AreaAdjustVitals::Cast(CUnit &caster, const SpellType *spell, CUnit *target,
*/
int AreaBombardment::Cast(CUnit &caster, const SpellType *, CUnit *, int x, int y)
{
int fields;
int shards;
int damage;
::Missile *mis;
int offsetx;
int offsety;
int dx;
int dy;
int i;
MissileType *missile;
int fields = this->Fields;
const int shards = this->Shards;
const int damage = this->Damage;
const PixelDiff offset = { this->StartOffsetX, this->StartOffsetY};
const MissileType *missile = this->Missile;
mis = NULL;
fields = this->Fields;
shards = this->Shards;
damage = this->Damage;
offsetx = this->StartOffsetX;
offsety = this->StartOffsetY;
missile = this->Missile;
while (fields--) {
// FIXME: radius configurable...
int dx;
int dy;
// FIXME: radius configurable...
do {
// find new destination in the map
dx = x + SyncRand() % 5 - 2;
dy = y + SyncRand() % 5 - 2;
} while (!Map.Info.IsPointOnMap(dx, dy));
for (i = 0; i < shards; ++i) {
mis = MakeMissile(missile,
dx * PixelTileSize.x + PixelTileSize.x / 2 + offsetx,
dy * PixelTileSize.y + PixelTileSize.y / 2 + offsety,
dx * PixelTileSize.x + PixelTileSize.x / 2,
dy * PixelTileSize.y + PixelTileSize.y / 2);
const PixelPos dest = { dx * PixelTileSize.x + PixelTileSize.x / 2,
dy * PixelTileSize.y + PixelTileSize.y / 2};
const PixelPos start = dest + offset;
for (int i = 0; i < shards; ++i) {
::Missile *mis = MakeMissile(*missile, start, dest);
// FIXME: This is just patched up, it works, but I have no idea why.
// FIXME: What is the reasoning behind all this?
if (mis->Type->Speed) {
@ -334,18 +324,15 @@ static void EvaluateMissileLocation(const SpellActionMissileLocation *location,
*/
int SpawnMissile::Cast(CUnit &caster, const SpellType *, CUnit *target, int x, int y)
{
::Missile *missile;
int sx;
int sy;
int dx;
int dy;
PixelPos startPos;
PixelPos endPos;
EvaluateMissileLocation(&this->StartPoint,
caster, target, x, y, &sx, &sy);
caster, target, x, y, &startPos.x, &startPos.y);
EvaluateMissileLocation(&this->EndPoint,
caster, target, x, y, &dx, &dy);
caster, target, x, y, &endPos.x, &endPos.y);
missile = MakeMissile(this->Missile, sx, sy, dx, dy);
::Missile *missile = MakeMissile(*this->Missile, startPos, endPos);
missile->TTL = this->TTL;
missile->Delay = this->Delay;
missile->Damage = this->Damage;

View file

@ -1418,16 +1418,14 @@ static void UISelectStateButtonDown(unsigned)
UI.ButtonPanel.Update();
if (MouseButtons & LeftButton) {
const CViewport *vp = UI.MouseViewport;
const CViewport &vp = *UI.MouseViewport;
const PixelPos screenPixelPos = {CursorX, CursorY};
const PixelPos mapPixelPos = vp.ScreenToMapPixelPos(screenPixelPos);
if (!ClickMissile.empty()) {
int mx = vp->MapX * PixelTileSize.x + CursorX - vp->X + vp->OffsetX;
int my = vp->MapY * PixelTileSize.y + CursorY - vp->Y + vp->OffsetY;
MakeLocalMissile(MissileTypeByIdent(ClickMissile),
mx, my, mx, my);
MakeLocalMissile(*MissileTypeByIdent(ClickMissile), mapPixelPos, mapPixelPos);
}
int sx = CursorX - vp->X + PixelTileSize.x * vp->MapX + vp->OffsetX;
int sy = CursorY - vp->Y + PixelTileSize.y * vp->MapY + vp->OffsetY;
SendCommand(sx, sy);
SendCommand(mapPixelPos.x, mapPixelPos.y);
}
return;
}
@ -1438,10 +1436,13 @@ static void UISelectStateButtonDown(unsigned)
if (CursorOn == CursorOnMinimap) {
int mx = UI.Minimap.Screen2MapX(CursorX);
int my = UI.Minimap.Screen2MapY(CursorY);
const Vec2i cursorTilePos = {mx, my};
if (MouseButtons & LeftButton) {
int sx = mx * PixelTileSize.x;
int sy = my * PixelTileSize.y;
const int sx = cursorTilePos.x * PixelTileSize.x + PixelTileSize.x / 2;
const int sy = cursorTilePos.y * PixelTileSize.y + PixelTileSize.y / 2;
const PixelPos mapPixelPos = {sx, sy};
UI.StatusLine.Clear();
ClearCosts();
CursorState = CursorStatePoint;
@ -1450,14 +1451,11 @@ static void UISelectStateButtonDown(unsigned)
CurrentButtonLevel = 0;
UI.ButtonPanel.Update();
if (!ClickMissile.empty()) {
MakeLocalMissile(MissileTypeByIdent(ClickMissile),
sx + PixelTileSize.x / 2, sy + PixelTileSize.y / 2, 0, 0);
MakeLocalMissile(*MissileTypeByIdent(ClickMissile), mapPixelPos, mapPixelPos);
}
SendCommand(sx, sy);
SendCommand(mapPixelPos.x, mapPixelPos.y);
} else {
const Vec2i cursorPos = {mx, my};
UI.SelectedViewport->Center(cursorPos, PixelTileSize / 2);
UI.SelectedViewport->Center(cursorTilePos, PixelTileSize / 2);
}
return;
}
@ -1643,11 +1641,10 @@ void UIHandleButtonDown(unsigned button)
unit->Blink = 4; // if right click on building -- blink
} else { // if not not click on building -- green cross
if (!ClickMissile.empty()) {
MakeLocalMissile(MissileTypeByIdent(ClickMissile),
UI.MouseViewport->MapX * PixelTileSize.x +
CursorX - UI.MouseViewport->X + UI.MouseViewport->OffsetX,
UI.MouseViewport->MapY * PixelTileSize.y +
CursorY - UI.MouseViewport->Y + UI.MouseViewport->OffsetY, 0, 0);
const PixelPos screenPos = {CursorX, CursorY};
const PixelPos mapPixelPos = UI.MouseViewport->ScreenToMapPixelPos(screenPos);
MakeLocalMissile(*MissileTypeByIdent(ClickMissile), mapPixelPos, mapPixelPos);
}
}
DoRightButton(tilePos.x * PixelTileSize.x, tilePos.y * PixelTileSize.y);
@ -1670,20 +1667,18 @@ void UIHandleButtonDown(unsigned button)
// Cursor is on the minimap area
//
} else if (CursorOn == CursorOnMinimap) {
if (MouseButtons & LeftButton) { // enter move mini-mode
const Vec2i cursorPos = {UI.Minimap.Screen2MapX(CursorX), UI.Minimap.Screen2MapY(CursorY)};
const Vec2i cursorTilePos = {UI.Minimap.Screen2MapX(CursorX), UI.Minimap.Screen2MapY(CursorY)};
UI.SelectedViewport->Center(cursorPos, PixelTileSize / 2);
if (MouseButtons & LeftButton) { // enter move mini-mode
UI.SelectedViewport->Center(cursorTilePos, PixelTileSize / 2);
} else if (MouseButtons & RightButton) {
if (!GameObserve && !GamePaused) {
PixelPos mapPixelPos = { cursorTilePos.x * PixelTileSize.x + PixelTileSize.x / 2,
cursorTilePos.y * PixelTileSize.y + PixelTileSize.y / 2};
if (!ClickMissile.empty()) {
MakeLocalMissile(MissileTypeByIdent(ClickMissile),
UI.Minimap.Screen2MapX(CursorX) * PixelTileSize.x + PixelTileSize.x / 2,
UI.Minimap.Screen2MapY(CursorY) * PixelTileSize.y + PixelTileSize.y / 2, 0, 0);
MakeLocalMissile(*MissileTypeByIdent(ClickMissile), mapPixelPos, mapPixelPos);
}
// DoRightButton() takes screen map coordinates
DoRightButton(UI.Minimap.Screen2MapX(CursorX) * PixelTileSize.x,
UI.Minimap.Screen2MapY(CursorY) * PixelTileSize.y);
DoRightButton(mapPixelPos.x, mapPixelPos.y);
}
}
//

View file

@ -541,7 +541,7 @@ static void MapMarkUnitSightRec(const CUnit &unit, const Vec2i &pos, int width,
**
** @return Container of container of ... of unit. It is not null.
*/
static CUnit *GetFirstContainer(const CUnit &unit)
CUnit *GetFirstContainer(const CUnit &unit)
{
const CUnit *container = &unit;
@ -2763,6 +2763,13 @@ CUnit *UnitOnScreen(CUnit *ounit, int x, int y)
return nunit;
}
PixelPos CUnit::GetMapPixelPosCenter() const
{
const PixelPos center = { tilePos.x * PixelTileSize.x + Type->TileWidth * PixelTileSize.x / 2,
tilePos.y * PixelTileSize.y + Type->TileHeight * PixelTileSize.y / 2};
return center;
}
/**
** Let an unit die.
**
@ -2795,17 +2802,16 @@ void LetUnitDie(CUnit &unit)
// Catapults,... explodes.
//
if (type->ExplodeWhenKilled) {
MakeMissile(type->Explosion.Missile,
unit.tilePos.x * PixelTileSize.x + type->TileWidth * PixelTileSize.x / 2,
unit.tilePos.y * PixelTileSize.y + type->TileHeight * PixelTileSize.y / 2,
0, 0);
const PixelPos pixelPos = unit.GetMapPixelPosCenter();
MakeMissile(*type->Explosion.Missile, pixelPos, pixelPos);
}
if (type->DeathExplosion) {
const PixelPos pixelPos = unit.GetMapPixelPosCenter();
type->DeathExplosion->pushPreamble();
type->DeathExplosion->pushInteger(unit.tilePos.x * PixelTileSize.x +
type->TileWidth * PixelTileSize.x / 2);
type->DeathExplosion->pushInteger(unit.tilePos.y * PixelTileSize.y +
type->TileHeight * PixelTileSize.y / 2);
type->DeathExplosion->pushInteger(pixelPos.x);
type->DeathExplosion->pushInteger(pixelPos.y);
type->DeathExplosion->run();
}
// Handle Teleporter Destination Removal
@ -3031,29 +3037,23 @@ void HitUnit(CUnit *attacker, CUnit &target, int damage)
CommandStopUnit(*attacker); // Attacker shouldn't continue attack!
}
const PixelPos targetPixelCenter = target.GetMapPixelPosCenter();
if ((target.IsVisibleOnMap(*ThisPlayer) || ReplayRevealMap) && !DamageMissile.empty()) {
MakeLocalMissile(MissileTypeByIdent(DamageMissile),
target.tilePos.x * PixelTileSize.x + target.Type->TileWidth * PixelTileSize.x / 2,
target.tilePos.y * PixelTileSize.y + target.Type->TileHeight * PixelTileSize.y / 2,
target.tilePos.x * PixelTileSize.x + target.Type->TileWidth * PixelTileSize.x / 2 + 3,
target.tilePos.y * PixelTileSize.y + target.Type->TileHeight * PixelTileSize.y / 2 -
MissileTypeByIdent(DamageMissile)->Range)->Damage = -damage;
MissileType *mtype = MissileTypeByIdent(DamageMissile);
const PixelDiff offset = {3, -mtype->Range};
MakeLocalMissile(*mtype, targetPixelCenter, targetPixelCenter + offset)->Damage = -damage;
}
// Show impact missiles
if (target.Variable[SHIELD_INDEX].Value > 0
&& !target.Type->Impact[ANIMATIONS_DEATHTYPES+1].Name.empty()) { // shield impact
MakeMissile(target.Type->Impact[ANIMATIONS_DEATHTYPES+1].Missile,
target.tilePos.x * PixelTileSize.x + PixelTileSize.x / 2,
target.tilePos.y * PixelTileSize.y + PixelTileSize.y / 2, 0, 0);
&& !target.Type->Impact[ANIMATIONS_DEATHTYPES + 1].Name.empty()) { // shield impact
MakeMissile(*target.Type->Impact[ANIMATIONS_DEATHTYPES + 1].Missile, targetPixelCenter, targetPixelCenter);
} else if (target.DamagedType && !target.Type->Impact[target.DamagedType].Name.empty()) { // specific to damage type impact
MakeMissile(target.Type->Impact[target.DamagedType].Missile,
target.tilePos.x * PixelTileSize.x + PixelTileSize.x / 2,
target.tilePos.y * PixelTileSize.y + PixelTileSize.y / 2, 0, 0);
MakeMissile(*target.Type->Impact[target.DamagedType].Missile, targetPixelCenter, targetPixelCenter);
} else if (!target.Type->Impact[ANIMATIONS_DEATHTYPES].Name.empty()) { // generic impact
MakeMissile(target.Type->Impact[ANIMATIONS_DEATHTYPES].Missile,
target.tilePos.x * PixelTileSize.x + PixelTileSize.x / 2,
target.tilePos.y * PixelTileSize.y + PixelTileSize.y / 2, 0, 0);
MakeMissile(*target.Type->Impact[ANIMATIONS_DEATHTYPES].Missile, targetPixelCenter, targetPixelCenter);
}
if (type->Building && !target.Burning) {
@ -3061,13 +3061,12 @@ void HitUnit(CUnit *attacker, CUnit &target, int damage)
MissileType *fire = MissileBurningBuilding(f);
if (fire) {
Missile *missile = MakeMissile(fire,
target.tilePos.x * PixelTileSize.x + (type->TileWidth * PixelTileSize.x) / 2,
target.tilePos.y * PixelTileSize.y + (type->TileHeight * PixelTileSize.y) / 2 - PixelTileSize.y,
0, 0);
const PixelDiff offset = {0, -PixelTileSize.y};
Missile *missile = MakeMissile(*fire, targetPixelCenter - offset, targetPixelCenter - offset);
target.RefsIncrease();
missile->SourceUnit = &target;
target.Burning = 1;
target.RefsIncrease();
}
}