浏览代码

* some changes

mateuszb 14 年之前
父节点
当前提交
94166b83aa

+ 12 - 2
client/Client.cpp

@@ -425,9 +425,12 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 	serv->addStdVecItems(const_cast<CGameInfo*>(CGI)->state);
 	hotSeat = (humanPlayers > 1);
 
-	CERMScriptModule *erm = new CERMScriptModule();
+
+	CScriptingModule *erm = getERMModule();
 	privilagedGameEventReceivers.push_back(erm);
 	privilagedBattleEventReceivers.push_back(erm);
+	icb = this;
+	acb = this;
 	erm->init();
 }
 
@@ -509,7 +512,7 @@ void CClient::handlePack( CPack * pack )
 
 void CClient::updatePaths()
 {	
-	const CGHeroInstance *h = getHero(getSelectedHero());
+	const CGHeroInstance *h = getSelectedHero();
 	if (h)//if we have selected hero...
 		gs->calculatePaths(h, *pathInfo);
 }
@@ -586,6 +589,13 @@ void CClient::loadNeutralBattleAI()
 	battleints[255]->init(new CBattleCallback(gs, 255, this));
 }
 
+void CClient::commitPackage( CPackForClient *pack )
+{
+	CommitPackage cp;
+	cp.packToCommit = pack;
+	*serv << &cp;
+}
+
 template void CClient::serialize( CISer<CLoadFile> &h, const int version );
 template void CClient::serialize( COSer<CSaveFile> &h, const int version );
 

+ 2 - 1
client/Client.h

@@ -109,7 +109,6 @@ public:
 	void setObjProperty(int objid, int prop, si64 val) OVERRIDE {};
 	void changePrimSkill(int ID, int which, si64 val, bool abs=false) OVERRIDE {};
 	void changeSecSkill(int ID, int which, int val, bool abs=false) OVERRIDE {}; 
-	void showInfoDialog(InfoWindow *iw) OVERRIDE {};
 	void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback) OVERRIDE {};
 	ui32 showBlockingDialog(BlockingDialog *iw) OVERRIDE {return 0;}; //synchronous version of above
 	void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb) OVERRIDE {};
@@ -159,6 +158,8 @@ public:
 	void updatePaths();
 	void battleStarted(const BattleInfo * info);
 
+	void commitPackage(CPackForClient *pack) OVERRIDE;
+
 	//////////////////////////////////////////////////////////////////////////
 
 	template <typename Handler> void serialize(Handler &h, const int version);

+ 456 - 118
lib/ERMInterpreter.cpp

@@ -6,6 +6,12 @@
 #include <boost/foreach.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/assign/std/vector.hpp> // for 'operator+=()'
+#include <boost/assign/std/vector.hpp> 
+#include <boost/assign/list_of.hpp>
+
+#include "CObjectHandler.h"
+#include "CHeroHandler.h"
+#include "CCreatureHandler.h"
 
 /*
  * ERMInterpreter.cpp, part of VCMI engine
@@ -17,11 +23,15 @@
  *
  */
 
+#define DBG_PRINT(X) tlog0 << X << std::endl;
+
 namespace spirit = boost::spirit;
 using namespace VERMInterpreter;
 using namespace boost::assign;
-
 typedef int TUnusedType;
+using namespace boost::assign;
+
+ERMInterpreter *erm;
 
 namespace ERMPrinter
 {
@@ -460,6 +470,7 @@ void ERMInterpreter::scanScripts()
 
 ERMInterpreter::ERMInterpreter()
 {
+	erm	 = this;
 	curFunc = NULL;
 	curTrigger = NULL;
 	globalEnv = new Environment();
@@ -564,7 +575,7 @@ bool ERMInterpreter::isCMDATrigger( const ERM::Tcommand & cmd )
 	}
 }
 
-ERM::TLine ERMInterpreter::retrieveLine( LinePointer linePtr ) const
+ERM::TLine &ERMInterpreter::retrieveLine( LinePointer linePtr )
 {
 	return scripts.find(linePtr)->second;
 }
@@ -575,6 +586,7 @@ ERM::TLine ERMInterpreter::retrieveLine( LinePointer linePtr ) const
 template<typename OwnerType>
 struct StandardBodyOptionItemVisitor : boost::static_visitor<>
 {
+	typedef OwnerType TReceiverType;
 	OwnerType & owner;
 	explicit StandardBodyOptionItemVisitor(OwnerType & _owner) : owner(_owner)
 	{}
@@ -633,136 +645,160 @@ struct StandardReceiverVisitor : boost::static_visitor<>
 		throw EScriptExecError("VR arithmetic not allowed in this receiver!");
 	}
 	virtual void operator()(TNormalBodyOption const& trig) const = 0;
+
+	template<typename OptionPerformer>
+	void performOptionTakingOneParamter(const ERM::TNormalBodyOptionList & params) const
+	{
+		if(params.size() == 1)
+		{
+			ERM::TBodyOptionItem boi = params[0];
+			boost::apply_visitor(
+				OptionPerformer(*const_cast<OptionPerformer::TReceiverType*>(static_cast<const OptionPerformer::TReceiverType*>(this))), boi);
+		}
+		else
+			throw EScriptExecError("This receiver option takes exactly 1 parameter!");
+	}
+
+	template<template <int opcode> class OptionPerformer>
+	void performOptionTakingOneParamterWithIntDispatcher(const ERM::TNormalBodyOptionList & params) const
+	{
+		if(params.size() == 2)
+		{
+			int optNum = erm->getIexp(params[0]).getInt();
+
+			ERM::TBodyOptionItem boi = params[1];
+			switch(optNum)
+			{
+			case 0:
+				boost::apply_visitor(
+					OptionPerformer<0>(*const_cast<OptionPerformer<0>::TReceiverType*>(static_cast<const OptionPerformer<0>::TReceiverType*>(this))), boi);
+				break;
+			default:
+				throw EScriptExecError("Wrong number of option code!");
+				break;
+			}
+		}
+		else
+			throw EScriptExecError("This receiver option takes exactly 2 parameters!");
+	}
 };
+////HE
+struct HEPerformer;
 
-struct VRPerformer;
-struct VR_SPerformer : StandardBodyOptionItemVisitor<VRPerformer>
+template<int opcode>
+struct HE_BPerformer : StandardBodyOptionItemVisitor<HEPerformer>
 {
-	explicit VR_SPerformer(VRPerformer & _owner);
-	using StandardBodyOptionItemVisitor<VRPerformer>::operator();
+	explicit HE_BPerformer(HEPerformer & _owner) : StandardBodyOptionItemVisitor(_owner)
+	{}
+	using StandardBodyOptionItemVisitor<HEPerformer>::operator();
 
-	void operator()(TStringConstant const& cmp) const OVERRIDE;
 	void operator()(TIexp const& cmp) const OVERRIDE;
+	void operator()(TVarpExp const& cmp) const OVERRIDE;
 };
 
-struct VRPerformer : StandardReceiverVisitor<IexpValStr>
+template<int opcode>
+void HE_BPerformer<opcode>::operator()( TIexp const& cmp ) const
 {
-	VRPerformer(ERMInterpreter * _interpr, IexpValStr ident) : StandardReceiverVisitor(_interpr, ident)
+	throw EScriptExecError("Setting hero name is not implemented!");
+}
+
+template<int opcode>
+void HE_BPerformer<opcode>::operator()( TVarpExp const& cmp ) const
+{
+	erm->getIexp(cmp).setTo(owner.identifier->name);
+}
+
+template<int opcode>
+struct HE_CPerformer : StandardBodyOptionItemVisitor<HEPerformer>
+{
+	explicit HE_CPerformer(HEPerformer & _owner) : StandardBodyOptionItemVisitor(_owner)
 	{}
+	using StandardBodyOptionItemVisitor<HEPerformer>::operator();
+
+	void operator()(TIexp const& cmp) const OVERRIDE;
+	void operator()(TVarpExp const& cmp) const OVERRIDE;
+};
+
+template<int opcode>
+void HE_CPerformer<opcode>::operator()( TIexp const& cmp ) const
+{
+	throw EScriptExecError("Setting hero army is not implemented!");
+}
+
+template<int opcode>
+void HE_CPerformer<opcode>::operator()( TVarpExp const& cmp ) const
+{
+	erm->getIexp(cmp).setTo(owner.identifier->name);
+}
+
+
+struct HEPerformer : StandardReceiverVisitor<const CGHeroInstance *>
+{
+	HEPerformer(ERMInterpreter * _interpr, const CGHeroInstance * hero) : StandardReceiverVisitor(_interpr, hero)
+	{}
+	using StandardReceiverVisitor<const CGHeroInstance *>::operator();
 
-	void operator()(TVRLogic const& trig) const OVERRIDE
-	{
-		int valr = interp->getIexp(trig.var).getInt();
-		switch (trig.opcode)
-		{
-		case '&':
-			const_cast<VRPerformer*>(this)->identifier.setTo(identifier.getInt() & valr);
-			break;
-		case '|':
-			const_cast<VRPerformer*>(this)->identifier.setTo(identifier.getInt() | valr);
-			break;
-		case 'X':
-			const_cast<VRPerformer*>(this)->identifier.setTo(identifier.getInt() ^ valr);
-			break;
-		default:
-			throw EInterpreterError("Wrong opcode in VR logic expression!");
-			break;
-		}
-	}
-	void operator()(TVRArithmetic const& trig) const OVERRIDE
-	{
-		IexpValStr rhs = interp->getIexp(trig.rhs);
-		switch (trig.opcode)
-		{
-		case '+':
-			const_cast<VRPerformer*>(this)->identifier += rhs;
-			break;
-		case '-':
-			const_cast<VRPerformer*>(this)->identifier -= rhs;
-			break;
-		case '*':
-			const_cast<VRPerformer*>(this)->identifier *= rhs;
-			break;
-		case ':':
-			const_cast<VRPerformer*>(this)->identifier /= rhs;
-			break;
-		case '%':
-			const_cast<VRPerformer*>(this)->identifier %= rhs;
-			break;
-		default:
-			throw EInterpreterError("Wrong opcode in VR arithmetic!");
-			break;
-		}
-	}
 	void operator()(TNormalBodyOption const& trig) const OVERRIDE
 	{
 		switch(trig.optionCode)
 		{
-		case 'C': //setting/checking v vars
-			{
-				//TODO
-			}
-			break;
-		case 'H': //checking if string is empty
-			{
-				//TODO
-			}
-			break;
-		case 'M': //string operations
-			{
-				//TODO
-			}
-			break;
-		case 'R': //random variables
+		case 'B':
 			{
-				//TODO
+				performOptionTakingOneParamterWithIntDispatcher<HE_BPerformer>(trig.params);
 			}
 			break;
-		case 'S': //setting variable
+		case 'C':
 			{
-				if(trig.params.size() == 1)
+				const ERM::TNormalBodyOptionList & params = trig.params;
+				if(params.size() == 4)
 				{
-					ERM::TBodyOptionItem boi = trig.params[0];
-					boost::apply_visitor(VR_SPerformer(*const_cast<VRPerformer*>(this)), boi);
+					if(erm->getIexp(params[0]).getInt() == 0)
+					{
+						int slot = erm->getIexp(params[1]).getInt();
+						if(params[2].which() == 6) //varp
+						{
+							erm->getIexp(boost::get<ERM::TVarpExp>(params[2])).setTo(identifier->getCreature(slot)->idNumber);
+						}
+						else
+							throw EScriptExecError("Setting stack creature type is not implemented!");
+
+						if(params[3].which() == 6) //varp
+						{
+							erm->getIexp(boost::get<ERM::TVarpExp>(params[3])).setTo(identifier->getStackCount(slot));
+						}
+						else
+							throw EScriptExecError("Setting stack count is not implemented!");
+					}
+					else 
+						throw EScriptExecError("Slot number must be an evaluable i-exp");
 				}
+				//todo else if(14 params)
 				else
-					throw EScriptExecError("VR receiver S option takes exactly 1 parameter!");
-			}
-			break;
-		case 'T': //random variables
-			{
-				//TODO
+					throw EScriptExecError("Slot number must be an evaluable i-exp");
 			}
 			break;
-		case 'U': //search for a substring
-			{
-				//TODO
-			}
+		case 'E':
 			break;
-		case 'V': //convert string to value
-			{
-				//TODO
-			}
+		case 'N':
 			break;
 		default:
-			throw EScriptExecError("Wrong VR receiver option!");
 			break;
 		}
 	}
-};
 
+};
 
-VR_SPerformer::VR_SPerformer(VRPerformer & _owner) : StandardBodyOptionItemVisitor(_owner)
-{}
 
-void VR_SPerformer::operator()(ERM::TIexp const& trig) const
-{
-	owner.identifier.setTo(owner.interp->getIexp(trig));
-}
-void VR_SPerformer::operator()(TStringConstant const& cmp) const
+////MA
+struct MAPerformer;
+struct MA_PPerformer : StandardBodyOptionItemVisitor<MAPerformer>
 {
-	owner.identifier.setTo(cmp.str);
-}
+	explicit MA_PPerformer(MAPerformer & _owner);
+	using StandardBodyOptionItemVisitor<MAPerformer>::operator();
+
+	void operator()(TIexp const& cmp) const OVERRIDE;
+	void operator()(TVarpExp const& cmp) const OVERRIDE;
+};
 
 struct MAPerformer : StandardReceiverVisitor<TUnusedType>
 {
@@ -790,8 +826,64 @@ struct MAPerformer : StandardReceiverVisitor<TUnusedType>
 		
 };
 
-struct ConditionDisemboweler;
+void MA_PPerformer::operator()( TIexp const& cmp ) const
+{
+
+}
+
+void MA_PPerformer::operator()( TVarpExp const& cmp ) const
+{
+
+}
+
+////MO
+
+struct MOPerformer;
+struct MO_GPerformer : StandardBodyOptionItemVisitor<MOPerformer>
+{
+	explicit MO_GPerformer(MOPerformer & _owner) : StandardBodyOptionItemVisitor(_owner)
+	{}
+	using StandardBodyOptionItemVisitor<MOPerformer>::operator();
+
+	void operator()(TVarpExp const& cmp) const OVERRIDE;
+	void operator()(TIexp const& cmp) const OVERRIDE;
+};
+
+struct MOPerformer: StandardReceiverVisitor<int3>
+{
+	MOPerformer(ERMInterpreter * _interpr, int3 pos) : StandardReceiverVisitor(_interpr, pos)
+	{}
+	using StandardReceiverVisitor<int3>::operator();
+
+	void operator()(TNormalBodyOption const& trig) const OVERRIDE
+	{
+		switch(trig.optionCode)
+		{
+		case 'G':
+			{
+				performOptionTakingOneParamter<MO_GPerformer>(trig.params);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+};
+
+void MO_GPerformer::operator()( TIexp const& cmp ) const
+{
+	throw EScriptExecError("Setting monster count is not implemented yet!");
+}
+
+void MO_GPerformer::operator()( TVarpExp const& cmp ) const
+{
+	const CGCreature *cre = erm->getObjFromAs<CGCreature>(owner.identifier);
+	erm->getIexp(cmp).setTo(cre->getStackCount(0));
+}
+
 
+struct ConditionDisemboweler;
+//OB
 struct OBPerformer;
 struct OB_UPerformer : StandardBodyOptionItemVisitor<OBPerformer>
 {
@@ -859,10 +951,7 @@ struct OBPerformer : StandardReceiverVisitor<int3>
 			break;
 		case 'U': //sgc of obj subtype
 			{
-				if(trig.params.size() == 1)
-					boost::apply_visitor(OB_UPerformer(const_cast<OBPerformer&>(*this)), trig.params[0]);
-				else
-					throw EScriptExecError("OB:U takes exactly one parameter!");
+				performOptionTakingOneParamter<OB_UPerformer>(trig.params);
 			}
 			break;
 		default:
@@ -875,13 +964,141 @@ struct OBPerformer : StandardReceiverVisitor<int3>
 void OB_UPerformer::operator()( TIexp const& cmp ) const
 {
 	IexpValStr val = owner.interp->getIexp(cmp);
+	throw EScriptExecError("Setting subID is not implemented yet!");
 }
 
 void OB_UPerformer::operator()( TVarpExp const& cmp ) const
 {
 	IexpValStr val = owner.interp->getIexp(cmp);
+	val.setTo(erm->getObjFrom(owner.identifier)->subID);
+}
+
+/////VR
+struct VRPerformer;
+struct VR_SPerformer : StandardBodyOptionItemVisitor<VRPerformer>
+{
+	explicit VR_SPerformer(VRPerformer & _owner);
+	using StandardBodyOptionItemVisitor<VRPerformer>::operator();
+
+	void operator()(TStringConstant const& cmp) const OVERRIDE;
+	void operator()(TIexp const& cmp) const OVERRIDE;
+};
+
+struct VRPerformer : StandardReceiverVisitor<IexpValStr>
+{
+	VRPerformer(ERMInterpreter * _interpr, IexpValStr ident) : StandardReceiverVisitor(_interpr, ident)
+	{}
+
+	void operator()(TVRLogic const& trig) const OVERRIDE
+	{
+		int valr = interp->getIexp(trig.var).getInt();
+		switch (trig.opcode)
+		{
+		case '&':
+			const_cast<VRPerformer*>(this)->identifier.setTo(identifier.getInt() & valr);
+			break;
+		case '|':
+			const_cast<VRPerformer*>(this)->identifier.setTo(identifier.getInt() | valr);
+			break;
+		case 'X':
+			const_cast<VRPerformer*>(this)->identifier.setTo(identifier.getInt() ^ valr);
+			break;
+		default:
+			throw EInterpreterError("Wrong opcode in VR logic expression!");
+			break;
+		}
+	}
+	void operator()(TVRArithmetic const& trig) const OVERRIDE
+	{
+		IexpValStr rhs = interp->getIexp(trig.rhs);
+		switch (trig.opcode)
+		{
+		case '+':
+			const_cast<VRPerformer*>(this)->identifier += rhs;
+			break;
+		case '-':
+			const_cast<VRPerformer*>(this)->identifier -= rhs;
+			break;
+		case '*':
+			const_cast<VRPerformer*>(this)->identifier *= rhs;
+			break;
+		case ':':
+			const_cast<VRPerformer*>(this)->identifier /= rhs;
+			break;
+		case '%':
+			const_cast<VRPerformer*>(this)->identifier %= rhs;
+			break;
+		default:
+			throw EInterpreterError("Wrong opcode in VR arithmetic!");
+			break;
+		}
+	}
+	void operator()(TNormalBodyOption const& trig) const OVERRIDE
+	{
+		switch(trig.optionCode)
+		{
+		case 'C': //setting/checking v vars
+			{
+				//TODO
+			}
+			break;
+		case 'H': //checking if string is empty
+			{
+				//TODO
+			}
+			break;
+		case 'M': //string operations
+			{
+				//TODO
+			}
+			break;
+		case 'R': //random variables
+			{
+				//TODO
+			}
+			break;
+		case 'S': //setting variable
+			{
+				performOptionTakingOneParamter<VR_SPerformer>(trig.params);				
+			}
+			break;
+		case 'T': //random variables
+			{
+				//TODO
+			}
+			break;
+		case 'U': //search for a substring
+			{
+				//TODO
+			}
+			break;
+		case 'V': //convert string to value
+			{
+				//TODO
+			}
+			break;
+		default:
+			throw EScriptExecError("Wrong VR receiver option!");
+			break;
+		}
+	}
+};
+
+
+VR_SPerformer::VR_SPerformer(VRPerformer & _owner) : StandardBodyOptionItemVisitor(_owner)
+{}
+
+void VR_SPerformer::operator()(ERM::TIexp const& trig) const
+{
+	owner.identifier.setTo(owner.interp->getIexp(trig));
+}
+void VR_SPerformer::operator()(TStringConstant const& cmp) const
+{
+	owner.identifier.setTo(cmp.str);
 }
 
+/////
+
 struct ERMExpDispatch : boost::static_visitor<>
 {
 	ERMInterpreter * owner;
@@ -1014,6 +1231,8 @@ struct ERMExpDispatch : boost::static_visitor<>
 			{
 				ERM::Tidentifier tid = trig.identifier.get();
 				objPos = HLP(owner).getPosFromIdentifier(tid, true);
+
+				helper.performBody(trig.body, MOPerformer(owner, objPos));
 			}
 			else
 				throw EScriptExecError("MO receiver must have an identifier!");
@@ -1031,6 +1250,39 @@ struct ERMExpDispatch : boost::static_visitor<>
 			else
 				throw EScriptExecError("OB receiver must have an identifier!");
 		}
+		else if(trig.name == "HE")
+		{
+			const CGHeroInstance * hero = NULL;
+			if(trig.identifier.is_initialized())
+			{
+				ERM::Tidentifier tid = trig.identifier.get();
+				switch(tid.size())
+				{
+				case 1:
+					{
+						int heroNum = erm->getIexp(tid[0]).getInt();
+						if(heroNum == -1)
+							hero = icb->getSelectedHero();
+						else
+							hero = icb->getHeroWithSubid(heroNum);
+
+					}
+					break;
+				case 3:
+					{
+						int3 pos = helper.getPosFromIdentifier(tid, false);
+						hero = erm->getObjFromAs<CGHeroInstance>(pos);
+					}
+					break;
+				default:
+					throw EScriptExecError("HE receiver takes 1 or 3 items in identifier");
+					break;
+				}
+				helper.performBody(trig.body, HEPerformer(owner, hero));
+			}
+			else
+				throw EScriptExecError("HE receiver must have an identifier!");
+		}
 		else
 		{
 			//not supported or invalid trigger
@@ -1083,19 +1335,10 @@ struct LineExec : boost::static_visitor<>
 
 void ERMInterpreter::executeLine( const LinePointer & lp )
 {
-	tlog0 << "Executing line nr " << getRealLine(lp.lineNum) << " (internal " << lp.lineNum << ") from " << lp.file << std::endl;
+	tlog0 << "Executing line nr " << getRealLine(lp.lineNum) << " (internal " << lp.lineNum << ") from " << lp.file->filename << std::endl;
 	boost::apply_visitor(LineExec(this), scripts[lp]);
 }
 
-void ERMInterpreter::init()
-{
-	ermGlobalEnv = new ERMEnvironment();
-	globalEnv = new Environment();
-	//TODO: reset?
-	for(int g = 0; g < ARRAY_COUNT(funcVars); ++g)
-		funcVars[g].reset();
-}
-
 IexpValStr ERMInterpreter::getVar(std::string toFollow, boost::optional<int> initVal) const
 {
 	IexpValStr ret;
@@ -1276,6 +1519,12 @@ IexpValStr ERMInterpreter::getVar(std::string toFollow, boost::optional<int> ini
 		}
 			
 	}
+
+	ret.name = toFollow;
+	if(initVal.is_initialized())
+	{
+		ret.name += boost::lexical_cast<std::string>(initVal.get());
+	}
 	return ret;
 }
 
@@ -1368,6 +1617,29 @@ IexpValStr ERMInterpreter::getIexp( const ERM::TVarpExp & tid ) const
 	return boost::apply_visitor(LVL2IexpDisemboweler(const_cast<ERMInterpreter*>(this), IexpDisemboweler::GET), tid.var);
 }
 
+struct LVL3BodyOptionItemVisitor : StandardBodyOptionItemVisitor<IexpValStr>
+{
+	explicit LVL3BodyOptionItemVisitor(IexpValStr & _owner) : StandardBodyOptionItemVisitor(_owner)
+	{}
+	using StandardBodyOptionItemVisitor<IexpValStr>::operator();
+
+	void operator()(TIexp const& cmp) const OVERRIDE
+	{
+		owner = erm->getIexp(cmp);
+	}
+	void operator()(TVarpExp const& cmp) const OVERRIDE
+	{
+		owner = erm->getIexp(cmp);
+	}
+};
+
+IexpValStr ERMInterpreter::getIexp( const ERM::TBodyOptionItem & opit ) const
+{
+	IexpValStr ret;
+	boost::apply_visitor(LVL3BodyOptionItemVisitor(ret), opit);
+	return ret;
+}
+
 void ERMInterpreter::executeTriggerType( VERMInterpreter::TriggerType tt, bool pre, const TIDPattern & identifier, const std::vector<int> &funParams/*=std::vector<int>()*/ )
 {
 	struct HLP
@@ -1383,7 +1655,7 @@ void ERMInterpreter::executeTriggerType( VERMInterpreter::TriggerType tt, bool p
 	TtriggerListType & triggerList = pre ? triggers : postTriggers;
 
 	TriggerIdentifierMatch tim;
-	tim.allowNoIdetifier = false;
+	tim.allowNoIdetifier = true;
 	tim.ermEnv = this;
 	tim.matchToIt = identifier;
 	std::vector<Trigger> & triggersToTry = triggerList[tt];
@@ -1409,14 +1681,14 @@ void ERMInterpreter::executeTriggerType(const char *trigger)
 	executeTriggerType(VERMInterpreter::TriggerType(trigger), true, TIDPattern());
 }
 
-ERM::TTriggerBase & ERMInterpreter::retrieveTrigger( ERM::TLine line )
+ERM::TTriggerBase & ERMInterpreter::retrieveTrigger( ERM::TLine &line )
 {
 	if(line.which() == 1)
 	{
-		ERM::TERMline tl = boost::get<ERM::TERMline>(line);
+		ERM::TERMline &tl = boost::get<ERM::TERMline>(line);
 		if(tl.which() == 0)
 		{
-			ERM::Tcommand tcm = boost::get<ERM::Tcommand>(tl);
+			ERM::Tcommand &tcm = boost::get<ERM::Tcommand>(tl);
 			if(tcm.cmd.which() == 0)
 			{
 				return boost::get<ERM::Ttrigger>(tcm.cmd);
@@ -1868,6 +2140,7 @@ void VERMInterpreter::FunctionLocalVars::reset()
 
 void IexpValStr::setTo( const IexpValStr & second )
 {
+	DBG_PRINT("setting " << getName() << " to " << second.getName());
 	switch(type)
 	{
 	case IexpValStr::FLOATVAR:
@@ -1889,6 +2162,7 @@ void IexpValStr::setTo( const IexpValStr & second )
 
 void IexpValStr::setTo( int val )
 {
+	DBG_PRINT("setting " << getName() << " to " << val);
 	switch(type)
 	{
 	case INTVAR:
@@ -1902,6 +2176,7 @@ void IexpValStr::setTo( int val )
 
 void IexpValStr::setTo( float val )
 {
+	DBG_PRINT("setting " << getName() << " to " << val);
 	switch(type)
 	{
 	case FLOATVAR:
@@ -1915,6 +2190,7 @@ void IexpValStr::setTo( float val )
 
 void IexpValStr::setTo( const std::string & val )
 {
+	DBG_PRINT("setting " << getName() << " to " << val);
 	switch(type)
 	{
 	case STRINGVAR:
@@ -1967,3 +2243,65 @@ std::string IexpValStr::getString() const
 		break;
 	}
 }
+
+std::string IexpValStr::getName() const
+{
+	if(name.size())
+	{
+		return name;
+	}
+	else if(type == IexpValStr::INT)
+	{
+		return "Literal " + boost::lexical_cast<std::string>(getInt());
+	}
+
+}
+
+void ERMInterpreter::init()
+{
+	ermGlobalEnv = new ERMEnvironment();
+	globalEnv = new Environment();
+	//TODO: reset?
+	for(int g = 0; g < ARRAY_COUNT(funcVars); ++g)
+		funcVars[g].reset();
+
+	scanForScripts();
+	scanScripts();
+	for(std::map<VERMInterpreter::LinePointer, ERM::TLine>::iterator it = scripts.begin();
+		it != scripts.end(); ++it)
+	{
+		tlog0 << it->first.realLineNum << '\t';
+		ERMPrinter::printAST(it->second);
+	}
+
+	executeInstructions();
+	executeTriggerType("PI");
+}
+
+void ERMInterpreter::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start)
+{
+	if(!visitedObj)
+		return;
+	setCurrentlyVisitedObj(visitedObj->pos);
+	TIDPattern tip;
+	tip[1] = list_of(visitedObj->ID);
+	tip[2] = list_of(visitedObj->ID)(visitedObj->subID);
+	tip[3] = list_of(visitedObj->pos.x)(visitedObj->pos.y)(visitedObj->pos.z);
+	executeTriggerType(VERMInterpreter::TriggerType("OB"), start, tip);
+}
+
+void ERMInterpreter::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side)
+{
+	executeTriggerType("BA", 0);
+	executeTriggerType("BR", -1);
+	executeTriggerType("BF", 0);
+	//TODO tactics or not
+}
+
+const CGObjectInstance * ERMInterpreter::getObjFrom( int3 pos )
+{
+	std::vector<const CGObjectInstance * > objs = icb->getVisitableObjs(pos);
+	if(!objs.size())
+		throw EScriptExecError("Attempt to obtain access to nonexistent object!");
+	return objs.back();
+}

+ 26 - 4
lib/ERMInterpreter.h

@@ -1,6 +1,9 @@
 #pragma once
 #include "../global.h"
 #include "ERMParser.h"
+#include "IGameEventsReceiver.h"
+#include "ERMScriptModule.h"
+
 
 /*
  * ERMInterpreter.h, part of VCMI engine
@@ -317,6 +320,9 @@ private:
 		std::string * stringvar;
 	} val;
 public:
+	std::string name;
+	std::string getName() const;
+
 	enum {WRONGVAL, INT, INTVAR, FLOATVAR, STRINGVAR} type;
 	void setTo(const IexpValStr & second);
 	void setTo(int val);
@@ -469,7 +475,7 @@ public:
 	OPERATOR_DEFINITION_INTEGER(%)
 };
 
-class ERMInterpreter
+class ERMInterpreter : public CScriptingModule
 {
 /*not so*/ public:
 // 	friend class ScriptScanner;
@@ -485,8 +491,8 @@ class ERMInterpreter
 	std::vector< VERMInterpreter::FileInfo* > fileInfos;
 	std::map<VERMInterpreter::LinePointer, ERM::TLine> scripts;
 	std::map<VERMInterpreter::LexicalPtr, VERMInterpreter::Environment> lexicalEnvs;
-	ERM::TLine retrieveLine(VERMInterpreter::LinePointer linePtr) const;
-	static ERM::TTriggerBase & retrieveTrigger(ERM::TLine line);
+	ERM::TLine &retrieveLine(VERMInterpreter::LinePointer linePtr);
+	static ERM::TTriggerBase & retrieveTrigger(ERM::TLine &line);
 
 	VERMInterpreter::Environment * globalEnv;
 	VERMInterpreter::ERMEnvironment * ermGlobalEnv;
@@ -502,6 +508,7 @@ class ERMInterpreter
 	IexpValStr getIexp(const ERM::TMacroUsage & macro) const;
 	IexpValStr getIexp(const ERM::TIdentifierInternal & tid) const;
 	IexpValStr getIexp(const ERM::TVarpExp & tid) const;
+	IexpValStr getIexp(const ERM::TBodyOptionItem & opit) const;
 
 	static const std::string triggerSymbol, postTriggerSymbol, defunSymbol;
 
@@ -521,7 +528,6 @@ public:
 	void executeTriggerType(const char *trigger, int id); //convenience version of above, for pre-trigger when there is only one argument
 	void executeTriggerType(const char *trigger); //convenience version of above, for pre-trigger when there are no args
 	void setCurrentlyVisitedObj(int3 pos); //sets v998 - v1000 to given value
-	void init(); //sets up environment etc.
 	void scanForScripts();
 
 	enum EPrintMode{ALL, ERM_ONLY, VERM_ONLY};
@@ -531,4 +537,20 @@ public:
 	ERMInterpreter();
 	bool checkCondition( ERM::Tcondition cond );
 	int getRealLine(int lineNum);
+
+	//overload CScriptingModule
+	virtual void heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start) OVERRIDE;
+	virtual void init() OVERRIDE;//sets up environment etc.
+	virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) OVERRIDE;
+
+	const CGObjectInstance *getObjFrom(int3 pos);
+	template <typename T>
+	const T *getObjFromAs(int3 pos)
+	{
+		const T* obj =  dynamic_cast<const T*>(getObjFrom(pos));
+		if(obj)
+			return obj;
+		else
+			throw EScriptExecError("Wrong cast attempted, object is not of a desired type!");
+	}
 };

+ 2 - 2
lib/ERMParser.h

@@ -165,7 +165,7 @@ namespace ERM
 	{
 		Ttrigger() 
 		{
-			pre = false;
+			pre = true;
 		}
 	};
 
@@ -173,7 +173,7 @@ namespace ERM
 	{
 		TPostTrigger()
 		{
-			pre = true;
+			pre = false;
 		}
 	};
 

+ 6 - 38
lib/ERMScriptModule.cpp

@@ -2,51 +2,19 @@
 
 #include "ERMScriptModule.h"
 #include "ERMInterpreter.h"
-#include <boost/assign/std/vector.hpp> 
-#include <boost/assign/list_of.hpp>
 #include "CObjectHandler.h"
 
-using namespace boost::assign;
+IGameEventRealizer *acb;
+CPrivilagedInfoCallback *icb;
 
-CScriptingModule::~CScriptingModule()
-{
-
-}
-
-CERMScriptModule::CERMScriptModule(void)
-{
-}
 
-CERMScriptModule::~CERMScriptModule(void)
+CScriptingModule * getERMModule()
 {
+	CScriptingModule *ret = new ERMInterpreter();
+	return ret;
 }
 
-void CERMScriptModule::init()
+CScriptingModule::~CScriptingModule()
 {
-	interpreter = new ERMInterpreter();
-	interpreter->init();
-	interpreter->scanForScripts();
-	interpreter->scanScripts();
-	interpreter->executeInstructions();
-	interpreter->executeTriggerType("PI");
-}
 
-void CERMScriptModule::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start)
-{
-	if(!visitedObj)
-		return;
-	interpreter->setCurrentlyVisitedObj(visitedObj->pos);
-	ERMInterpreter::TIDPattern tip;
-	tip[1] = list_of(visitedObj->ID);
-	tip[2] = list_of(visitedObj->ID)(visitedObj->subID);
-	tip[3] = list_of(visitedObj->pos.x)(visitedObj->pos.y)(visitedObj->pos.z);
-	interpreter->executeTriggerType(VERMInterpreter::TriggerType("OB"), start, tip);
 }
-
-void CERMScriptModule::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side)
-{
-	interpreter->executeTriggerType("BA", 0);
-	interpreter->executeTriggerType("BR", -1);
-	interpreter->executeTriggerType("BF", 0);
-	//TODO tactics or not
-}

+ 6 - 11
lib/ERMScriptModule.h

@@ -2,6 +2,9 @@
 
 #include "../global.h"
 #include "IGameEventsReceiver.h"
+#include "IGameCallback.h"
+
+class IGameEventRealizer;
 
 class ERMInterpreter;
 
@@ -13,16 +16,8 @@ public:
 	virtual ~CScriptingModule();
 };
 
-class DLL_EXPORT CERMScriptModule : public CScriptingModule
-{
-public:
-	ERMInterpreter *interpreter;
+extern DLL_EXPORT IGameEventRealizer *acb;
+extern DLL_EXPORT CPrivilagedInfoCallback *icb;
 
-	CERMScriptModule(void);
-	~CERMScriptModule(void);
-
-	virtual void heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start) OVERRIDE;
-	virtual void init() OVERRIDE;
-	virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) OVERRIDE;
-};
 
+DLL_EXPORT CScriptingModule *getERMModule();

+ 14 - 3
lib/IGameCallback.cpp

@@ -362,10 +362,9 @@ const CGHeroInstance* CGameInfoCallback::getSelectedHero( int Player ) const
 	return getHero(p->currentSelection);
 }
 
-int CGameInfoCallback::getSelectedHero() const
+const CGHeroInstance* CGameInfoCallback::getSelectedHero() const
 {
-	const CGHeroInstance *h = getSelectedHero(gs->currentPlayer);
-	return h ? h->id : -1; // TODO synchronous turns?
+	return getSelectedHero(gs->currentPlayer);
 }
 
 const PlayerSettings * CGameInfoCallback::getPlayerSettings(int color) const
@@ -1171,3 +1170,15 @@ const TeamState * CGameInfoCallback::getPlayerTeam( ui8 teamID ) const
 	return NULL;
 }
 
+const CGHeroInstance* CGameInfoCallback::getHeroWithSubid( int subid ) const
+{
+	BOOST_FOREACH(const CGHeroInstance *h, gs->map->heroes)
+		if(h->subID == subid)
+			return h;
+}
+
+
+void IGameEventRealizer::showInfoDialog( InfoWindow *iw )
+{
+	commitPackage(iw);
+}

+ 20 - 6
lib/IGameCallback.h

@@ -150,13 +150,14 @@ public:
 
 	//hero
 	const CGHeroInstance* getHero(int objid) const;
+	const CGHeroInstance* getHeroWithSubid(int subid) const;
 	int getHeroCount(int player, bool includeGarrisoned) const;
 	bool getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) const;
 	int getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //when called during battle, takes into account creatures' spell cost reduction
 	int estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const; //estimates damage of given spell; returns 0 if spell causes no dmg
 	bool verifyPath(CPath * path, bool blockSea)const;
 	const CGHeroInstance* getSelectedHero(int player) const; //NULL if no hero is selected
-	int getSelectedHero() const; //of current (active) player
+	const CGHeroInstance* getSelectedHero() const; //of current (active) player
 
 	//objects
 	const CGObjectInstance* getObj(int objid, bool verbose = true) const;
@@ -239,13 +240,17 @@ public:
 	TerrainTile * getTile(int3 pos);
 };
 
-/// Interface class for handling general game logic and actions
-class DLL_EXPORT IGameCallback : public CPrivilagedInfoCallback
+class DLL_EXPORT IGameEventRealizer
 {
 public:
-	virtual ~IGameCallback(){};
+	virtual void commitPackage(CPackForClient *pack) = 0;
 
-	//do sth
+	virtual void showInfoDialog(InfoWindow *iw);
+};
+
+class DLL_EXPORT IGameEventCallback : public IGameEventRealizer
+{
+public:
 	virtual void changeSpells(int hid, bool give, const std::set<ui32> &spells)=0;
 	virtual bool removeObject(int objid)=0;
 	virtual void setBlockVis(int objid, bool bv)=0;
@@ -254,7 +259,6 @@ public:
 	virtual void setObjProperty(int objid, int prop, si64 val)=0;
 	virtual void changePrimSkill(int ID, int which, si64 val, bool abs=false)=0;
 	virtual void changeSecSkill(int ID, int which, int val, bool abs=false)=0; 
-	virtual void showInfoDialog(InfoWindow *iw)=0;
 	virtual void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback)=0;
 	virtual ui32 showBlockingDialog(BlockingDialog *iw) =0; //synchronous version of above //TODO:
 	virtual void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb) =0; //cb will be called when player closes garrison window
@@ -293,6 +297,16 @@ public:
 	virtual void changeObjPos(int objid, int3 newPos, ui8 flags)=0;
 	virtual void sendAndApply(CPackForClient * info)=0;
 	virtual void heroExchange(si32 hero1, si32 hero2)=0; //when two heroes meet on adventure map
+};
+
+/// Interface class for handling general game logic and actions
+class DLL_EXPORT IGameCallback : public CPrivilagedInfoCallback, public IGameEventCallback
+{
+public:
+	virtual ~IGameCallback(){};
+
+	//do sth
+
 
 	friend struct CPack;
 	friend struct CPackForClient;

+ 18 - 0
lib/NetPacks.h

@@ -162,6 +162,7 @@ public:
 
 /***********************************************************************************************************/
 
+
 struct PackageApplied : public CPackForClient //94
 {
 	PackageApplied() {type = 94;}
@@ -1491,6 +1492,23 @@ struct AdvmapSpellCast : public CPackForClient //108
 
 /***********************************************************************************************************/
 
+struct CommitPackage : public CPackForServer
+{
+	bool applyGh(CGameHandler *gh);
+	CPackForClient *packToCommit;
+
+	~CommitPackage()
+	{
+		delete packToCommit;
+	}
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & packToCommit;
+	}
+};
+
+
 struct CloseServer : public CPackForServer
 {
 	bool applyGh(CGameHandler *gh);

+ 1 - 0
lib/RegisterTypes.cpp

@@ -209,6 +209,7 @@ void registerTypes3(Serializer &s)
 	s.template registerType<CastleTeleportHero>();
 
 	s.template registerType<SaveGame>();
+	s.template registerType<CommitPackage>();
 	s.template registerType<SetSelection>();
 	s.template registerType<PlayerMessage>();
 }

+ 6 - 4
server/CGameHandler.cpp

@@ -1539,10 +1539,7 @@ void CGameHandler::setHoverName(int objid, MetaString* name)
 	SetHoverName shn(objid, *name);
 	sendAndApply(&shn);
 }
-void CGameHandler::showInfoDialog(InfoWindow *iw)
-{
-	sendToAllClients(iw);
-}
+
 void CGameHandler::showBlockingDialog( BlockingDialog *iw, const CFunctionList<void(ui32)> &callback )
 {
 	ask(iw,iw->player,callback);
@@ -5063,6 +5060,11 @@ void CGameHandler::setBattleResult(int resultType, int victoriusSide)
 	battleResult.set(br);
 }
 
+void CGameHandler::commitPackage( CPackForClient *pack )
+{
+	sendAndApply(pack);
+}
+
 CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance *army, BattleInfo *bat)
 {
 	int color = army->tempOwner;

+ 3 - 1
server/CGameHandler.h

@@ -136,7 +136,7 @@ public:
 	void setObjProperty(int objid, int prop, si64 val) OVERRIDE;
 	void changePrimSkill(int ID, int which, si64 val, bool abs=false) OVERRIDE;
 	void changeSecSkill(int ID, int which, int val, bool abs=false) OVERRIDE; 
-	void showInfoDialog(InfoWindow *iw) OVERRIDE;
+	//void showInfoDialog(InfoWindow *iw) OVERRIDE;
 	void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback) OVERRIDE;
 	ui32 showBlockingDialog(BlockingDialog *iw) OVERRIDE; //synchronous version of above
 	void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb) OVERRIDE;
@@ -186,6 +186,8 @@ public:
 	void levelUpHero(int ID);//initial call - check if hero have remaining levelups & handle them
 	//////////////////////////////////////////////////////////////////////////
 
+	void commitPackage(CPackForClient *pack) OVERRIDE;
+
 	void init(StartInfo *si, int Seed);
 	void handleConnection(std::set<int> players, CConnection &c);
 	int getPlayerAt(CConnection *c) const;

+ 6 - 0
server/NetPacksServer.cpp

@@ -40,6 +40,12 @@ bool SaveGame::applyGh( CGameHandler *gh )
 	return true;
 }
 
+bool CommitPackage::applyGh( CGameHandler *gh )
+{
+	gh->sendAndApply(packToCommit);
+	return true;
+}
+
 bool CloseServer::applyGh( CGameHandler *gh )
 {
 	gh->close();