From 27c650023e0fb9e5549caeff0989faccd564b9cb Mon Sep 17 00:00:00 2001
From: Daniel Karbach <daniel.karbach@localhorst.tv>
Date: Fri, 31 Aug 2012 23:35:27 +0200
Subject: [PATCH] added Spell and TargetingMode interpretation

---
 src/loader/Interpreter.cpp | 120 +++++++++++++++++++++++++++++++++++++
 src/loader/Interpreter.h   |  17 ++++++
 src/main.cpp               |  59 ++++++------------
 test-data/test.l2s         |   2 +
 4 files changed, 156 insertions(+), 42 deletions(-)

diff --git a/src/loader/Interpreter.cpp b/src/loader/Interpreter.cpp
index f616c1a..4416f9b 100644
--- a/src/loader/Interpreter.cpp
+++ b/src/loader/Interpreter.cpp
@@ -11,6 +11,8 @@
 #include "../battle/Hero.h"
 #include "../battle/Monster.h"
 #include "../battle/PartyLayout.h"
+#include "../common/Spell.h"
+#include "../common/TargetingMode.h"
 #include "../graphics/ComplexAnimation.h"
 #include "../graphics/Font.h"
 #include "../graphics/Frame.h"
@@ -26,6 +28,8 @@ using battle::Hero;
 using battle::Monster;
 using battle::PartyLayout;
 using battle::Stats;
+using common::Spell;
+using common::TargetingMode;
 using graphics::Animation;
 using graphics::Font;
 using graphics::Frame;
@@ -70,12 +74,18 @@ Interpreter::~Interpreter() {
 	for (vector<SimpleAnimation *>::const_iterator i(simpleAnimations.begin()), end(simpleAnimations.end()); i != end; ++i) {
 		delete *i;
 	}
+	for (vector<Spell *>::const_iterator i(spells.begin()), end(spells.end()); i != end; ++i) {
+		delete *i;
+	}
 	for (vector<Sprite *>::const_iterator i(sprites.begin()), end(sprites.end()); i != end; ++i) {
 		delete *i;
 	}
 	for (vector<const char *>::const_iterator i(strings.begin()), end(strings.end()); i != end; ++i) {
 		delete *i;
 	}
+	for (vector<TargetingMode *>::const_iterator i(targetingModes.begin()), end(targetingModes.end()); i != end; ++i) {
+		delete *i;
+	}
 }
 
 
@@ -198,6 +208,19 @@ PartyLayout *Interpreter::GetPartyLayout(const std::string &name) {
 	}
 }
 
+Spell *Interpreter::GetSpell(const std::string &name) {
+	map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(name));
+	if (i != parsedDefinitions.end()) {
+		if (i->second.type == SPELL) {
+			return spells[i->second.index];
+		} else {
+			throw Error("cannot cast " + i->second.dfn->TypeName() + " to Spell");
+		}
+	} else {
+		throw Error("access to undefined Spell " + name);
+	}
+}
+
 Sprite *Interpreter::GetSprite(const std::string &name) {
 	map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(name));
 	if (i != parsedDefinitions.end()) {
@@ -224,6 +247,19 @@ const char *Interpreter::GetString(const std::string &name) const {
 	}
 }
 
+TargetingMode *Interpreter::GetTargetingMode(const std::string &name) {
+	map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(name));
+	if (i != parsedDefinitions.end()) {
+		if (i->second.type == TARGETING_MODE) {
+			return targetingModes[i->second.index];
+		} else {
+			throw Error("cannot cast " + i->second.dfn->TypeName() + " to TargetingMode");
+		}
+	} else {
+		throw Error("access to undefined TargetingMode " + name);
+	}
+}
+
 Vector<int> Interpreter::GetVector(const std::string &name) const {
 	map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(name));
 	if (i != parsedDefinitions.end()) {
@@ -399,6 +435,17 @@ const vector<PropertyList *> &Interpreter::GetPropertyListArray(const Value &v)
 	}
 }
 
+Spell *Interpreter::GetSpell(const Value &v) {
+	if (v.IsLiteral()) {
+		Spell *s(new Spell);
+		ReadSpell(*s, *v.GetLiteral().GetProperties());
+		return s;
+	} else {
+		ReadDefinition(source.GetDefinition(v.GetIdentifier()));
+		return GetSpell(v.GetIdentifier());
+	}
+}
+
 Sprite *Interpreter::GetSprite(const Value &v) {
 	if (v.IsLiteral()) {
 		Sprite *s(new Sprite);
@@ -419,6 +466,17 @@ const char *Interpreter::GetString(const Value &v) {
 	}
 }
 
+TargetingMode *Interpreter::GetTargetingMode(const Value &v) {
+	if (v.IsLiteral()) {
+		TargetingMode *t(new TargetingMode);
+		ReadTargetingMode(*t, *v.GetLiteral().GetProperties());
+		return t;
+	} else {
+		ReadDefinition(source.GetDefinition(v.GetIdentifier()));
+		return GetTargetingMode(v.GetIdentifier());
+	}
+}
+
 Vector<int> Interpreter::GetVector(const Value &v) {
 	if (v.IsLiteral()) {
 		return Vector<int>(v.GetLiteral().GetX(), v.GetLiteral().GetY());
@@ -486,12 +544,24 @@ void Interpreter::ReadObject(const Definition &dfn) {
 		simpleAnimations.push_back(animation);
 		ReadSimpleAnimation(*animation, *dfn.GetProperties());
 		parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, SIMPLE_ANIMATION, index)));
+	} else if (dfn.TypeName() == "Spell") {
+		Spell *spell(new Spell);
+		int index(spells.size());
+		spells.push_back(spell);
+		ReadSpell(*spell, *dfn.GetProperties());
+		parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, SPELL, index)));
 	} else if (dfn.TypeName() == "Sprite") {
 		Sprite *sprite(new Sprite);
 		int index(sprites.size());
 		sprites.push_back(sprite);
 		ReadSprite(*sprite, *dfn.GetProperties());
 		parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, SPRITE, index)));
+	} else if (dfn.TypeName() == "TargetingMode") {
+		TargetingMode *mode(new TargetingMode);
+		int index(targetingModes.size());
+		targetingModes.push_back(mode);
+		ReadTargetingMode(*mode, *dfn.GetProperties());
+		parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, TARGETING_MODE, index)));
 	} else {
 		throw Error("unhandled object type: " + dfn.TypeName());
 	}
@@ -682,6 +752,24 @@ void Interpreter::ReadSimpleAnimation(SimpleAnimation &a, const PropertyList &pr
 	}
 }
 
+void Interpreter::ReadSpell(Spell &s, const PropertyList &props) {
+	for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) {
+		if (i->first == "name") {
+			s.SetName(GetString(*i->second));
+		} else if (i->first == "cost") {
+			s.SetCost(GetNumber(*i->second));
+		} else if (i->first == "battle") {
+			if (GetBoolean(*i->second)) {
+				s.SetUsableInBattle();
+			}
+		} else if (i->first == "targets") {
+			s.GetTargetingMode() = *GetTargetingMode(*i->second);
+		} else {
+			throw Error("unknown Spell property: " + i->first);
+		}
+	}
+}
+
 void Interpreter::ReadSprite(Sprite &s, const PropertyList &props) {
 	for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) {
 		if (i->first == "image") {
@@ -718,4 +806,36 @@ void Interpreter::ReadStats(Stats &s, const PropertyList &props) {
 	}
 }
 
+void Interpreter::ReadTargetingMode(TargetingMode &t, const PropertyList &props) {
+	for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) {
+		if (i->first == "ally") {
+			if (GetBoolean(*i->second)) {
+				t.TargetAlly();
+			} else {
+				t.TargetEnemy();
+			}
+		} else if (i->first == "enemy") {
+			if (GetBoolean(*i->second)) {
+				t.TargetEnemy();
+			} else {
+				t.TargetAlly();
+			}
+		} else if (i->first == "all") {
+			if (GetBoolean(*i->second)) {
+				t.TargetAll();
+			}
+		} else if (i->first == "multiple") {
+			if (GetBoolean(*i->second)) {
+				t.TargetMultiple();
+			}
+		} else if (i->first == "single") {
+			if (GetBoolean(*i->second)) {
+				t.TargetSingle();
+			}
+		} else {
+			throw Error("unknown TargetingMode property: " + i->first);
+		}
+	}
+}
+
 }
diff --git a/src/loader/Interpreter.h b/src/loader/Interpreter.h
index cf08009..93a6e36 100644
--- a/src/loader/Interpreter.h
+++ b/src/loader/Interpreter.h
@@ -24,6 +24,11 @@ namespace battle {
 	class Stats;
 }
 
+namespace common {
+	class Spell;
+	class TargetingMode;
+}
+
 namespace graphics {
 	class Animation;
 	class Font;
@@ -68,8 +73,10 @@ public:
 	battle::Monster *GetMonster(const std::string &name);
 	int GetNumber(const std::string &name) const;
 	battle::PartyLayout *GetPartyLayout(const std::string &name);
+	common::Spell *GetSpell(const std::string &name);
 	graphics::Sprite *GetSprite(const std::string &name);
 	const char *GetString(const std::string &name) const;
+	common::TargetingMode *GetTargetingMode(const std::string &name);
 	geometry::Vector<int> GetVector(const std::string &name) const;
 
 public:
@@ -84,8 +91,10 @@ public:
 	const std::vector<int> &Numbers() const { return numbers; }
 	const std::vector<battle::PartyLayout *> &PartyLayouts() const { return partyLayouts; }
 	const std::vector<graphics::SimpleAnimation *> &SimpleAnimations() const { return simpleAnimations; }
+	const std::vector<common::Spell *> &Spells() const { return spells; }
 	const std::vector<graphics::Sprite *> &Sprites() const { return sprites; }
 	const std::vector<const char *> &Strings() const { return strings; }
+	const std::vector<common::TargetingMode *> &TargetingModes() const { return targetingModes; }
 	const std::vector<geometry::Vector<int> > &Vectors() const { return vectors; }
 
 private:
@@ -103,8 +112,10 @@ private:
 	battle::PartyLayout *GetPartyLayout(const Value &);
 	const PropertyList *GetPropertyList(const Value &);
 	const std::vector<PropertyList *> &GetPropertyListArray(const Value &);
+	common::Spell *GetSpell(const Value &);
 	graphics::Sprite *GetSprite(const Value &);
 	const char *GetString(const Value &);
+	common::TargetingMode *GetTargetingMode(const Value &);
 	const std::vector<Value *> &GetValueArray(const Value &);
 	geometry::Vector<int> GetVector(const Value &);
 
@@ -117,8 +128,10 @@ private:
 	void ReadMonster(battle::Monster &, const PropertyList &);
 	void ReadPartyLayout(battle::PartyLayout &, const PropertyList &);
 	void ReadSimpleAnimation(graphics::SimpleAnimation &, const PropertyList &);
+	void ReadSpell(common::Spell &, const PropertyList &);
 	void ReadSprite(graphics::Sprite &, const PropertyList &);
 	void ReadStats(battle::Stats &, const PropertyList &);
+	void ReadTargetingMode(common::TargetingMode &, const PropertyList &);
 
 private:
 	const ParsedSource &source;
@@ -135,8 +148,10 @@ private:
 		PARTY_LAYOUT,
 		PROPERTY_LIST_ARRAY,
 		SIMPLE_ANIMATION,
+		SPELL,
 		SPRITE,
 		STRING,
+		TARGETING_MODE,
 		VECTOR,
 		VALUE_ARRAY,
 	};
@@ -162,8 +177,10 @@ private:
 	std::vector<PropertyList *> propertyLists;
 	std::vector<std::vector<PropertyList *> > propertyListArrays;
 	std::vector<graphics::SimpleAnimation *> simpleAnimations;
+	std::vector<common::Spell *> spells;
 	std::vector<graphics::Sprite *> sprites;
 	std::vector<const char *> strings;
+	std::vector<common::TargetingMode *> targetingModes;
 	std::vector<std::vector<Value *> > valueArrays;
 	std::vector<geometry::Vector<int> > vectors;
 
diff --git a/src/main.cpp b/src/main.cpp
index e657f57..2f1c12a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -145,48 +145,23 @@ int main(int argc, char **argv) {
 		battleRes.magicTargetCursor = intp.GetSprite("magicTargetCursor");
 		battleRes.itemTargetCursor = intp.GetSprite("itemTargetCursor");
 
-		Spell resetSpell;
-		resetSpell.SetName("Reset");
-		maxim.AddSpell(&resetSpell);
-		Spell strongSpell;
-		strongSpell.SetName("Strong");
-		strongSpell.SetCost(3);
-		strongSpell.SetUsableInBattle();
-		strongSpell.GetTargetingMode().TargetMultipleAllies();
-		maxim.AddSpell(&strongSpell);
-		selan.AddSpell(&strongSpell);
-		Spell strongerSpell;
-		strongerSpell.SetName("Stronger");
-		strongerSpell.SetCost(8);
-		strongerSpell.SetUsableInBattle();
-		strongerSpell.GetTargetingMode().TargetMultipleAllies();
-		maxim.AddSpell(&strongerSpell);
-		selan.AddSpell(&strongerSpell);
-		Spell championSpell;
-		championSpell.SetName("Champion");
-		championSpell.SetCost(16);
-		championSpell.SetUsableInBattle();
-		championSpell.GetTargetingMode().TargetMultipleAllies();
-		maxim.AddSpell(&championSpell);
-		selan.AddSpell(&championSpell);
-		Spell rallySpell;
-		rallySpell.SetName("Rally");
-		rallySpell.SetCost(10);
-		rallySpell.SetUsableInBattle();
-		rallySpell.GetTargetingMode().TargetMultipleAllies();
-		maxim.AddSpell(&rallySpell);
-		selan.AddSpell(&rallySpell);
-		Spell escapeSpell;
-		escapeSpell.SetName("Escape");
-		escapeSpell.SetCost(8);
-		selan.AddSpell(&escapeSpell);
-		Spell valorSpell;
-		valorSpell.SetName("Valor");
-		valorSpell.SetCost(30);
-		valorSpell.SetUsableInBattle();
-		valorSpell.GetTargetingMode().TargetMultipleAllies();
-		maxim.AddSpell(&valorSpell);
-		selan.AddSpell(&valorSpell);
+		maxim.AddSpell(intp.GetSpell("resetSpell"));
+		Spell *strongSpell(intp.GetSpell("strongSpell"));
+		maxim.AddSpell(strongSpell);
+		selan.AddSpell(strongSpell);
+		Spell *strongerSpell(intp.GetSpell("strongerSpell"));
+		maxim.AddSpell(strongerSpell);
+		selan.AddSpell(strongerSpell);
+		Spell *championSpell(intp.GetSpell("championSpell"));
+		maxim.AddSpell(championSpell);
+		selan.AddSpell(championSpell);
+		Spell *rallySpell(intp.GetSpell("rallySpell"));
+		maxim.AddSpell(rallySpell);
+		selan.AddSpell(rallySpell);
+		selan.AddSpell(intp.GetSpell("escapeSpell"));
+		Spell *valorSpell(intp.GetSpell("valorSpell"));
+		maxim.AddSpell(valorSpell);
+		selan.AddSpell(valorSpell);
 
 		battleRes.spellMenuHeadline = "Please choose a spell.";
 		battleRes.spellMenuPrototype = Menu<const Spell *>(intp.GetFont("normalFont"), intp.GetFont("disabledFont"), intp.GetSprite("handCursor"), 9, 6, 8, 0, 2, 32, 2, ':');
diff --git a/test-data/test.l2s b/test-data/test.l2s
index ad2b301..f947f91 100644
--- a/test-data/test.l2s
+++ b/test-data/test.l2s
@@ -509,3 +509,5 @@ export Sprite itemTargetCursor {
 	size: <32,32>,
 	offset: <0,64>
 }
+
+include "test-data/spells.l2s"
-- 
2.39.5