From 4e62d647f759b252371879416cdf4c844d746bd6 Mon Sep 17 00:00:00 2001
From: Joris <Joris.dauphin@gmail.com>
Date: Sat, 5 Feb 2011 22:50:44 +0100
Subject: [PATCH] Fix casting range. Fix missile by introducing PixelPos
 (instead of Vec2i).

---
 src/action/action_spellcast.cpp  |  5 +--
 src/action/command.cpp           |  1 -
 src/include/actions.h            |  6 +++-
 src/include/editor.h             |  6 ++--
 src/include/missile.h            | 32 +++++++++----------
 src/include/unit.h               | 17 ++++++++++
 src/include/vec2i.h              | 55 ++++++++++++++++++++------------
 src/stratagus/missile.cpp        | 45 +++++++++++++-------------
 src/stratagus/script_missile.cpp |  6 ++--
 src/unit/unit.cpp                | 14 ++++++++
 10 files changed, 117 insertions(+), 70 deletions(-)

diff --git a/src/action/action_spellcast.cpp b/src/action/action_spellcast.cpp
index 92e8c4eb7..ed43de9c6 100644
--- a/src/action/action_spellcast.cpp
+++ b/src/action/action_spellcast.cpp
@@ -110,7 +110,6 @@ static void SpellMoveToTarget(CUnit &unit)
 	goal = order->GetGoal();
 
 	if (goal && unit.MapDistanceTo(*goal) <= order->Range) {
-
 		// there is goal and it is in range
 		unit.State = 0;
 		UnitHeadingFromDeltaXY(unit, goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos);
@@ -118,9 +117,7 @@ static void SpellMoveToTarget(CUnit &unit)
 		return;
 	} else if (!goal && unit.MapDistanceTo(order->goalPos.x, order->goalPos.y) <= order->Range) {
 		// there is no goal and target spot is in range
-		const Vec2i diag = {order->Arg1.Spell->Range, order->Arg1.Spell->Range};
-
-		UnitHeadingFromDeltaXY(unit, order->goalPos + diag - unit.tilePos);
+		UnitHeadingFromDeltaXY(unit, order->goalPos - unit.tilePos);
 		unit.SubAction++; // cast the spell
 		return;
 	} else if (err == PF_UNREACHABLE) {
diff --git a/src/action/command.cpp b/src/action/command.cpp
index ef70c97d5..a7f88f119 100644
--- a/src/action/command.cpp
+++ b/src/action/command.cpp
@@ -1078,7 +1078,6 @@ void CommandSpellCast(CUnit &unit, const Vec2i &pos, CUnit *dest, SpellType *spe
 				order->SetGoal(dest);
 			}
 		} else {
-			order->Range = 1;
 			order->goalPos = pos;
 		}
 		order->Arg1.Spell = spell;
diff --git a/src/include/actions.h b/src/include/actions.h
index b1332f442..100e63215 100644
--- a/src/include/actions.h
+++ b/src/include/actions.h
@@ -36,6 +36,10 @@
 #include "unit_cache.h"
 #endif
 
+#ifndef __VEC2I_H__
+#include "vec2i.h"
+#endif
+
 //#include "vec2i.h"
 
 /*----------------------------------------------------------------------------
@@ -54,7 +58,7 @@ class CUnitType;
 class CUpgrade;
 class SpellType;
 class CAnimation;
-class Vec2i;
+
 
 /*----------------------------------------------------------------------------
 --  Variables
diff --git a/src/include/editor.h b/src/include/editor.h
index d859381cc..4db142339 100644
--- a/src/include/editor.h
+++ b/src/include/editor.h
@@ -37,13 +37,15 @@
 #include <string>
 #include "player.h"
 #include "icons.h"
-
+#ifndef __VEC2I_H__
+#include "vec2i.h"
+#endif
 /*----------------------------------------------------------------------------
 --  Declarations
 ----------------------------------------------------------------------------*/
 
 class CUnitType;
-class Vec2i;
+
 
 enum EditorRunningType {
 	EditorNotRunning = 0,    /// Not Running
diff --git a/src/include/missile.h b/src/include/missile.h
index d089225fe..13d4a938f 100644
--- a/src/include/missile.h
+++ b/src/include/missile.h
@@ -383,10 +383,10 @@ public:
 
 	/// load the graphics for a missile type
 	void LoadMissileSprite();
-	void Init(void);
-	void DrawMissileType(int frame, const Vec2i &pos) const;
+	void Init();
+	void DrawMissileType(int frame, const PixelPos &pos) const;
 	void DrawMissileType(int frame, int x, int y) const {
-		Vec2i pos = {x, y};
+		PixelPos pos = {x, y};
 
 		DrawMissileType(frame, pos);
 	}
@@ -396,7 +396,7 @@ public:
 
 	std::string Ident;         /// missile name
 	int Transparency;          /// missile transparency
-	Vec2i size;                /// missile size in pixels
+	PixelSize size;            /// missile size in pixels
 	int DrawLevel;             /// Level to draw missile at
 	int SpriteFrames;          /// number of sprite frames in graphic
 	int NumDirections;         /// number of directions missile can face
@@ -439,10 +439,10 @@ protected:
 public:
 	virtual ~Missile() {};
 
-	static Missile *Init(MissileType *mtype, const Vec2i &startPos, const Vec2i &destPos);
+	static Missile *Init(MissileType *mtype, const PixelPos &startPos, const PixelPos &destPos);
 	static Missile *Init(MissileType *mtype, int sx, int sy, int dx, int dy) {
-		Vec2i startPos = {sx, sy};
-		Vec2i destPos = {dx, dy};
+		PixelPos startPos = {sx, sy};
+		PixelPos destPos = {dx, dy};
 
 		return Init(mtype, startPos, destPos);
 	}
@@ -452,9 +452,9 @@ public:
 	void DrawMissile(const CViewport *vp) const;
 	void SaveMissile(CFile *file) const;
 
-	Vec2i source; /// Missile source position
-	Vec2i position;   /// missile pixel position
-	Vec2i destination;  /// missile pixel destination
+	PixelPos source; /// Missile source position
+	PixelPos position;   /// missile pixel position
+	PixelPos destination;  /// missile pixel destination
 	MissileType *Type;  /// missile-type pointer
 	int SpriteFrame;  /// sprite frame counter
 	int State;        /// state
@@ -585,18 +585,18 @@ 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 Vec2i &startPos, const Vec2i &destPos);
+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 Vec2i startPos = {sx, sy};
-	const Vec2i destPos = {dx, dy};
+	const PixelPos startPos = {sx, sy};
+	const PixelPos destPos = {dx, dy};
 
 	return MakeMissile(mtype, startPos, destPos);
 }
 	/// create a local missile
-extern Missile *MakeLocalMissile(MissileType *mtype, const Vec2i &startPos, const Vec2i &destPos);
+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 Vec2i startPos = {sx, sy};
-	const Vec2i destPos = {dx, dy};
+	const PixelPos startPos = {sx, sy};
+	const PixelPos destPos = {dx, dy};
 
 	return MakeLocalMissile(mtype, startPos, destPos);
 }
diff --git a/src/include/unit.h b/src/include/unit.h
index 3108b6335..cdb3fe182 100644
--- a/src/include/unit.h
+++ b/src/include/unit.h
@@ -409,6 +409,21 @@ static inline int MapDistance(const Vec2i& pos1, const Vec2i &pos2)
 	return isqrt(diff.x * diff.x + diff.y * diff.y);
 }
 
+/**
+**  Returns the map distance between two points.
+**
+**  @param pos1  map pixel position.
+**  @param pos2  map pixel position.
+**
+**  @return    The distance between in pixels.
+*/
+static inline int MapDistance(const PixelPos& pos1, const PixelPos &pos2)
+{
+	const PixelDiff diff = pos2 - pos1;
+
+	return isqrt(diff.x * diff.x + diff.y * diff.y);
+}
+
 	/// Returns the map distance between two points with unit-type
 extern int MapDistanceToType(const Vec2i &pos1, const CUnitType &type, const Vec2i &pos2);
 
@@ -1279,6 +1294,8 @@ extern void RescueUnits();
 
 	/// Convert direction (dx,dy) to heading (0-255)
 extern int DirectionToHeading(const Vec2i &dir);
+	/// Convert direction (dx,dy) to heading (0-255)
+extern int DirectionToHeading(const PixelDiff &dir);
 
 	/// Update frame from heading
 extern void UnitUpdateHeading(CUnit &unit);
diff --git a/src/include/vec2i.h b/src/include/vec2i.h
index 9eee5e451..4376e1ba8 100644
--- a/src/include/vec2i.h
+++ b/src/include/vec2i.h
@@ -33,93 +33,108 @@
 
 //@{
 
-class Vec2i
+template <typename T>
+class Vec2T
 {
 public:
-	short int x;
-	short int y;
+	T x;
+	T y;
 };
 
 
-inline bool operator == (const Vec2i &lhs, const Vec2i & rhs)
+template <typename T>
+inline bool operator == (const Vec2T<T> &lhs, const Vec2T<T> &rhs)
 {
 	return lhs.x == rhs.x && lhs.y == rhs.y;
 }
 
-inline bool operator != (const Vec2i &lhs, const Vec2i & rhs)
+template <typename T>
+inline bool operator != (const Vec2T<T> &lhs, const Vec2T<T> &rhs)
 {
 	return !(lhs == rhs);
 }
 
-inline const Vec2i& operator += (Vec2i &lhs, const Vec2i& rhs)
+template <typename T>
+inline const Vec2T<T>& operator += (Vec2T<T> &lhs, const Vec2T<T>& rhs)
 {
 	lhs.x += rhs.x;
 	lhs.y += rhs.y;
 	return lhs;
 }
 
-inline const Vec2i& operator -= (Vec2i &lhs, const Vec2i& rhs)
+template <typename T>
+inline const Vec2T<T>& operator -= (Vec2T<T> &lhs, const Vec2T<T> &rhs)
 {
 	lhs.x -= rhs.x;
 	lhs.y -= rhs.y;
 	return lhs;
 }
 
-inline const Vec2i& operator *= (Vec2i &lhs, int rhs)
+template <typename T>
+inline const Vec2T<T>& operator *= (Vec2T<T> &lhs, int rhs)
 {
 	lhs.x *= rhs;
 	lhs.y *= rhs;
 	return lhs;
 }
 
-inline const Vec2i& operator /= (Vec2i &lhs, int rhs)
+template <typename T>
+inline const Vec2T<T>& operator /= (Vec2T<T> &lhs, int rhs)
 {
 	lhs.x /= rhs;
 	lhs.y /= rhs;
 	return lhs;
 }
 
-inline Vec2i operator + (const Vec2i &lhs, const Vec2i& rhs)
+template <typename T>
+inline Vec2T<T> operator + (const Vec2T<T> &lhs, const Vec2T<T>& rhs)
 {
-	Vec2i res(lhs);
+	Vec2T<T> res(lhs);
 
 	res += rhs;
 	return res;
 }
 
-inline Vec2i operator - (const Vec2i &lhs, const Vec2i& rhs)
+template <typename T>
+inline Vec2T<T> operator - (const Vec2T<T> &lhs, const Vec2T<T>& rhs)
 {
-	Vec2i res(lhs);
+	Vec2T<T> res(lhs);
 
 	res -= rhs;
 	return res;
 }
 
-inline Vec2i operator * (const Vec2i &lhs, int rhs)
+template <typename T>
+inline Vec2T<T> operator * (const Vec2T<T> &lhs, int rhs)
 {
-	Vec2i res(lhs);
+	Vec2T<T> res(lhs);
 
 	res *= rhs;
 	return res;
 }
 
-inline Vec2i operator * (int lhs, const Vec2i &rhs)
+template <typename T>
+inline Vec2T<T> operator * (int lhs, const Vec2T<T> &rhs)
 {
-	Vec2i res(rhs);
+	Vec2T<T> res(rhs);
 
 	res *= lhs;
 	return res;
 }
 
-
-inline Vec2i operator / (const Vec2i &lhs, int rhs)
+template <typename T>
+inline Vec2T<T> operator / (const Vec2T<T> &lhs, int rhs)
 {
-	Vec2i res(lhs);
+	Vec2T<T> res(lhs);
 
 	res /= rhs;
 	return res;
 }
 
+typedef Vec2T<short int> Vec2i;
+typedef Vec2T<int> PixelPos;
+typedef Vec2T<int> PixelDiff;
+typedef Vec2T<int> PixelSize;
 
 //@}
 
diff --git a/src/stratagus/missile.cpp b/src/stratagus/missile.cpp
index 3c8e695e5..085d00dd1 100644
--- a/src/stratagus/missile.cpp
+++ b/src/stratagus/missile.cpp
@@ -170,7 +170,7 @@ Missile::Missile() :
 **
 **  @return       created missile.
 */
-Missile *Missile::Init(MissileType *mtype, const Vec2i &startPos, const Vec2i &destPos)
+Missile *Missile::Init(MissileType *mtype, const PixelPos &startPos, const PixelPos &destPos)
 {
 	Missile *missile = NULL;
 
@@ -218,7 +218,7 @@ Missile *Missile::Init(MissileType *mtype, const Vec2i &startPos, const Vec2i &d
 			missile = new MissileDeathCoil;
 			break;
 	}
-	const Vec2i halfSize = mtype->size / 2;
+	const PixelPos halfSize = mtype->size / 2;
 	missile->position = startPos - halfSize;
 	missile->destination = destPos - halfSize;
 	missile->source = missile->position;
@@ -238,7 +238,7 @@ Missile *Missile::Init(MissileType *mtype, const Vec2i &startPos, const Vec2i &d
 **
 **  @return       created missile.
 */
-Missile *MakeMissile(MissileType *mtype, const Vec2i &startPos, const Vec2i &destPos)
+Missile *MakeMissile(MissileType *mtype, const PixelPos &startPos, const PixelPos &destPos)
 {
 	Missile *missile = Missile::Init(mtype, startPos, destPos);
 
@@ -255,7 +255,7 @@ Missile *MakeMissile(MissileType *mtype, const Vec2i &startPos, const Vec2i &des
 **
 **  @return       created missile.
 */
-Missile *MakeLocalMissile(MissileType *mtype, const Vec2i &startPos, const Vec2i &destPos)
+Missile *MakeLocalMissile(MissileType *mtype, const PixelPos &startPos, const PixelPos &destPos)
 {
 	Missile *missile = Missile::Init(mtype, startPos, destPos);
 
@@ -513,7 +513,7 @@ static int MissileVisibleInViewport(const CViewport *vp, const Missile *missile)
 **  @param frame  Animation frame
 **  @param pos    Screen pixel position
 */
-void MissileType::DrawMissileType(int frame, const Vec2i &pos) const
+void MissileType::DrawMissileType(int frame, const PixelPos &pos) const
 {
 #ifdef DYNAMIC_LOAD
 	if (!this->G->IsLoaded()) {
@@ -683,7 +683,7 @@ int FindAndSortMissiles(const CViewport *vp,
 **
 **  @internal We have : SpriteFrame / (2 * (Numdirection - 1)) == DirectionToHeading / 256.
 */
-static void MissileNewHeadingFromXY(Missile &missile, const Vec2i &delta)
+static void MissileNewHeadingFromXY(Missile &missile, const PixelPos &delta)
 {
 	int neg;
 
@@ -720,7 +720,7 @@ static void MissileNewHeadingFromXY(Missile &missile, const Vec2i &delta)
 */
 static int MissileInitMove(Missile &missile)
 {
-	const Vec2i heading = missile.destination - missile.position;
+	const PixelPos heading = missile.destination - missile.position;
 
 	MissileNewHeadingFromXY(missile, heading);
 	if (!(missile.State & 1)) {
@@ -759,11 +759,11 @@ static int PointToPointMissile(Missile &missile)
 	Assert(missile.Type != NULL);
 	Assert(missile.TotalStep != 0);
 
-	const Vec2i diff = (missile.destination - missile.source);
+	const PixelPos diff = (missile.destination - missile.source);
 	missile.position = missile.source + diff * missile.CurrentStep / missile.TotalStep;
 
 	if (missile.Type->SmokeMissile && missile.CurrentStep) {
-		const Vec2i position =  missile.position + missile.Type->size / 2;
+		const PixelPos position =  missile.position + missile.Type->size / 2;
 		MakeMissile(missile.Type->SmokeMissile, position, position);
 	}
 	return 0;
@@ -792,10 +792,10 @@ static int ParabolicMissile(Missile &missile)
 		return 1;
 	}
 	Assert(missile.Type != NULL);
-	const Vec2i orig_pos = missile.position;
+	const PixelPos orig_pos = missile.position;
 	Assert(missile.TotalStep != 0);
-	const Vec2i step = (missile.destination - missile.source) * 1000 / missile.TotalStep;
-	missile.position = missile.source + step * missile.CurrentStep / 1000;
+	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;
@@ -804,7 +804,7 @@ static int ParabolicMissile(Missile &missile)
 	missile.position.y += z * zprojToY / 64;
 	MissileNewHeadingFromXY(missile, missile.position - orig_pos);
 	if (missile.Type->SmokeMissile && missile.CurrentStep) {
-		const Vec2i position = missile.position + missile.Type->size / 2;
+		const PixelPos position = missile.position + missile.Type->size / 2;
 		MakeMissile(missile.Type->SmokeMissile, position, position);
 	}
 	return 0;
@@ -875,18 +875,18 @@ void MissileHit(Missile *missile)
 	if (missile->Type->ImpactSound.Sound) {
 		PlayMissileSound(missile, missile->Type->ImpactSound.Sound);
 	}
-	Vec2i pos = missile->position + missile->Type->size / 2;
+	const PixelPos pixelPos = missile->position + missile->Type->size / 2;
 
 	//
 	// The impact generates a new missile.
 	//
 	if (missile->Type->ImpactMissile) {
-		MakeMissile(missile->Type->ImpactMissile, pos.x, pos.y, pos.x, pos.y);
+		MakeMissile(missile->Type->ImpactMissile, pixelPos, pixelPos);
 	}
 	if (missile->Type->ImpactParticle) {
 		missile->Type->ImpactParticle->pushPreamble();
-		missile->Type->ImpactParticle->pushInteger(pos.x);
-		missile->Type->ImpactParticle->pushInteger(pos.y);
+		missile->Type->ImpactParticle->pushInteger(pixelPos.x);
+		missile->Type->ImpactParticle->pushInteger(pixelPos.y);
 		missile->Type->ImpactParticle->run();
 	}
 
@@ -894,8 +894,7 @@ void MissileHit(Missile *missile)
 		return;
 	}
 
-	pos.x /= TileSizeX;
-	pos.y /= TileSizeY;
+	const Vec2i pos = {pixelPos.x / TileSizeX, pixelPos.y / TileSizeY};
 
 	if (!Map.Info.IsPointOnMap(pos)) {
 		// FIXME: this should handled by caller?
@@ -1126,7 +1125,7 @@ void MissileActions()
 */
 int ViewPointDistanceToMissile(const Missile *missile)
 {
-	const Vec2i pixelPos = missile->position + missile->Type->size / 2;
+	const PixelPos pixelPos = missile->position + missile->Type->size / 2;
 	const Vec2i tilePos = { pixelPos.x / TileSizeX, pixelPos.y / TileSizeY };
 
 	return ViewPointDistance(tilePos);
@@ -1400,9 +1399,9 @@ void MissilePointToPointBounce::Action()
 	this->Wait = this->Type->Sleep;
 	if (PointToPointMissile(*this)) {
 		if (this->State < 2 * this->Type->NumBounces - 1 && this->TotalStep) {
-			const Vec2i step = (this->destination - this->source) * 1024 / this->TotalStep;
+			const PixelPos step = (this->destination - this->source);
 
-			this->destination += step * ((TileSizeX + TileSizeY) * 3) / 4 / 1024;
+			this->destination += step * ((TileSizeX + TileSizeY) * 3) / 4 / this->TotalStep;
 			this->State++; // !(State & 1) to initialise
 			this->source = this->position;
 			PointToPointMissile(*this);
@@ -1625,7 +1624,7 @@ void MissileWhirlwind::Action()
 	//
 	// Center of the tornado
 	//
-	Vec2i center = this->position + this->Type->size / 2;
+	PixelPos center = this->position + this->Type->size / 2;
 	center.x = (center.x + TileSizeX / 2) / TileSizeX;
 	center.y = (center.y + TileSizeY) / TileSizeY;
 
diff --git a/src/stratagus/script_missile.cpp b/src/stratagus/script_missile.cpp
index 823a881ba..1d82c4316 100644
--- a/src/stratagus/script_missile.cpp
+++ b/src/stratagus/script_missile.cpp
@@ -197,9 +197,9 @@ static int CclDefineMissileType(lua_State *l)
 static int CclMissile(lua_State *l)
 {
 	MissileType *type = NULL;
-	Vec2i position = {-1, -1};
-	Vec2i destination = {-1, -1};
-	Vec2i source = {-1, -1};
+	PixelPos position = {-1, -1};
+	PixelPos destination = {-1, -1};
+	PixelPos source = {-1, -1};
 	Missile *missile = NULL;
 
 	DebugPrint("FIXME: not finished\n");
diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp
index 28d94a49e..c90ad7edf 100644
--- a/src/unit/unit.cpp
+++ b/src/unit/unit.cpp
@@ -1744,6 +1744,20 @@ int DirectionToHeading(const Vec2i& delta)
 	return 0;
 }
 
+/**
+**  Convert direction to heading.
+**
+**  @param delta  Delta.
+**
+**  @return         Angle (0..255)
+*/
+int DirectionToHeading(const PixelDiff& delta)
+{
+	// code is identic for Vec2i and PixelDiff
+	Vec2i delta2 = {delta.x, delta.y};
+	return DirectionToHeading(delta2);
+}
+
 /**
 **  Update sprite frame for new heading.
 */