1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Version bump.

Initial support for IF:M elements and string formatting.
Various minor changes related to ERM interpreter.

The following script should be functional now:
ZVSE
!?PI;
!!DO1/0/6/1&v2777<>1:P0;

!?FU1;
!!IF:M^Hello world number %X16!^;
This commit is contained in:
Michał W. Urbańczyk 2011-06-10 23:50:32 +00:00
parent 78b5e11b93
commit 9775f88045
10 changed files with 184 additions and 16 deletions

View File

@ -45,6 +45,7 @@
#include "../lib/CObjectHandler.h"
#include <boost/program_options.hpp>
#include "../lib/CArtHandler.h"
#include "../lib/ERMScriptModule.h"
#ifdef _WIN32
#include "SDL_syswm.h"
@ -85,6 +86,7 @@ boost::mutex eventsM;
static bool gOnlyAI = false;
static bool setResolution = false; //set by event handling thread after resolution is adjusted
static bool ermInteractiveMode = false; //structurize when time is right
void processCommand(const std::string &message);
static void setScreenRes(int w, int h, int bpp, bool fullscreen);
void dispose();
@ -312,8 +314,30 @@ void processCommand(const std::string &message)
if(LOCPLINT && LOCPLINT->cingconsole)
LOCPLINT->cingconsole->print(message);
if(ermInteractiveMode)
{
if(cn == "exit")
{
ermInteractiveMode = false;
return;
}
else
{
if(client && client->erm)
client->erm->executeUserCommand(message);
tlog0 << "erm>";
}
}
if(message==std::string("die, fool"))
{
exit(EXIT_SUCCESS);
}
else if(cn == "erm")
{
ermInteractiveMode = true;
tlog0 << "erm>";
}
else if(cn==std::string("activate"))
{
int what;

View File

@ -94,6 +94,7 @@ void CClient::init()
serv = NULL;
gs = NULL;
cb = NULL;
erm = NULL;
terminate = false;
}
@ -428,12 +429,12 @@ void CClient::newGame( CConnection *con, StartInfo *si )
hotSeat = (humanPlayers > 1);
// CScriptingModule *erm = getERMModule();
// privilagedGameEventReceivers.push_back(erm);
// privilagedBattleEventReceivers.push_back(erm);
// icb = this;
// acb = this;
// erm->init();
erm = getERMModule();
privilagedGameEventReceivers.push_back(erm);
privilagedBattleEventReceivers.push_back(erm);
icb = this;
acb = this;
erm->init();
}
template <typename Handler>
@ -594,10 +595,18 @@ void CClient::loadNeutralBattleAI()
void CClient::commitPackage( CPackForClient *pack )
{
CommitPackage cp;
cp.freePack = false;
cp.packToCommit = pack;
*serv << &cp;
}
int CClient::getLocalPlayer() const
{
if(LOCPLINT)
return LOCPLINT->playerID;
return getCurrentPlayer();
}
template void CClient::serialize( CISer<CLoadFile> &h, const int version );
template void CClient::serialize( COSer<CSaveFile> &h, const int version );

View File

@ -29,6 +29,7 @@ class CCallback;
struct BattleAction;
struct SharedMem;
class CClient;
class CScriptingModule;
struct CPathsInfo;
namespace boost { class thread; }
@ -72,6 +73,7 @@ public:
CConnection *serv;
BattleAction *curbaction;
CPathsInfo *pathInfo;
CScriptingModule *erm;
CondSh<bool> waitingRequest;
@ -99,6 +101,9 @@ public:
bool terminate; // tell to terminate
boost::thread *connectionHandler; //thread running run() method
//////////////////////////////////////////////////////////////////////////
virtual int getLocalPlayer() const OVERRIDE;
//////////////////////////////////////////////////////////////////////////
//not working yet, will be implement somewhen later with support for local-sim-based gameplay
void changeSpells(int hid, bool give, const std::set<ui32> &spells) OVERRIDE {};

View File

@ -34,7 +34,7 @@ typedef si32 TBonusSubtype;
#define THC
#endif
#define NAME_VER ("VCMI 0.85")
#define NAME_VER ("VCMI 0.85b")
extern std::string NAME; //full name
extern std::string NAME_AFFIX; //client / server
#define CONSOLE_LOGGING_LEVEL 5

View File

@ -412,7 +412,8 @@ void ERMInterpreter::printScripts( EPrintMode mode /*= EPrintMode::ALL*/ )
{
tlog2 << "----------------- script " << it->first.file->filename << " ------------------\n";
}
tlog0 << it->first.realLineNum << '\t';
ERMPrinter::printAST(it->second);
prevIt = it;
}
@ -774,6 +775,107 @@ struct HEPerformer : StandardReceiverVisitor<const CGHeroInstance *>
}
};
struct IFPerformer;
struct IF_MPerformer : StandardBodyOptionItemVisitor<IFPerformer>
{
explicit IF_MPerformer(IFPerformer & _owner) : StandardBodyOptionItemVisitor<IFPerformer>(_owner){}
using StandardBodyOptionItemVisitor<IFPerformer>::operator();
void operator()(TStringConstant const& cmp) const OVERRIDE;
};
struct IFPerformer : StandardReceiverVisitor<TUnusedType>
{
IFPerformer(ERMInterpreter * _interpr) : StandardReceiverVisitor<TUnusedType>(_interpr, 0)
{}
using StandardReceiverVisitor<TUnusedType>::operator();
void operator()(TNormalBodyOption const& trig) const OVERRIDE
{
std::string message; //to be shown
switch(trig.optionCode)
{
case 'M': //Show the message (Text) or contents of z$ variable on the screen immediately.
performOptionTakingOneParamter<IF_MPerformer>(trig.params);
break;
default:
break;
}
}
// startpos is the first digit
// digits will be converted to number and returned
static int getNum(std::string &msg, int numStart, int &digitsUsed)
{
int numEnd = msg.find_first_not_of("1234567890", numStart);
if(numEnd == std::string::npos)
digitsUsed = msg.size() - numStart;
else
digitsUsed = numEnd - numStart;
return boost::lexical_cast<int>(msg.substr(numStart, digitsUsed));
}
static void formatMessage(std::string &msg)
{
int pos = 0; //index of the first not yet processed character in string
//according to the ERM help:
//"%%" -> "%"
//"%V#" -> current value of # flag.
//"%Vf"..."%Vt" -> current value of corresponding variable.
//"%W1"..."%W100" -> current value of corresponding hero variable.
//"%X1"..."%X16" -> current value of corresponding function parameter.
//"%Y1"..."%Y100" -> current value of corresponding local variable.
//"%Z1"..."%Z500" -> current value of corresponding string variable.
//"%$macro$" -> macro name of corresponding variable
//"%Dd" -> current day of week
//"%Dw" -> current week
//"%Dm" -> current month
//"%Da" -> current day from beginning of the game
//"%Gc" -> the color of current gamer in text
while(pos < msg.size())
{
int percentPos = msg.find_first_of('%', pos);
if(percentPos == std::string::npos) //processing done?
break;
if(percentPos + 1 >= msg.size()) //at least one character after % is required
throw EScriptExecError("Formatting error: % at the end of string!");
;
switch(msg[percentPos+1])
{
case '%':
msg.erase(percentPos+1, 1); //just delete superfluous %
break;
case 'X':
{
int digits;
int varNum = getNum(msg, percentPos+2, digits);
msg.replace(percentPos, digits+2, boost::lexical_cast<std::string>(erm->getVar("x", varNum).getInt()));
}
break;
}
pos++;
}
}
void showMessage(const std::string &msg)
{
std::string msgToFormat = msg;
IFPerformer::formatMessage(msgToFormat);
acb->showInfoDialog(msgToFormat, icb->getLocalPlayer());
}
};
void IF_MPerformer::operator()(TStringConstant const& cmp) const
{
owner.showMessage(cmp.str);
}
template<int opcode>
void HE_BPerformer<opcode>::operator()( TVarpExp const& cmp ) const
@ -1281,8 +1383,13 @@ struct ERMExpDispatch : boost::static_visitor<>
else
throw EScriptExecError("HE receiver must have an identifier!");
}
else if(trig.name == "IF")
{
helper.performBody(trig.body, IFPerformer(owner));
}
else
{
tlog3 << trig.name << " receiver is not supported yet, doing nothing...\n";
//not supported or invalid trigger
}
}
@ -2264,12 +2371,6 @@ void ERMInterpreter::init()
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");
@ -2453,6 +2554,11 @@ VOptionList ERMInterpreter::evalEach( VermTreeIterator list, Environment * env /
return ret;
}
void ERMInterpreter::executeUserCommand(const std::string &cmd)
{
tlog0 << "ERM here: received command: " << cmd << std::endl;
}
namespace VERMInterpreter
{
VOption convertToVOption(const ERM::TVOption & tvo)

View File

@ -690,6 +690,8 @@ public:
//overload CScriptingModule
virtual void heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start) OVERRIDE;
virtual void init() OVERRIDE;//sets up environment etc.
virtual void executeUserCommand(const std::string &cmd) OVERRIDE;
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);

View File

@ -11,7 +11,7 @@ class ERMInterpreter;
class DLL_EXPORT CScriptingModule : public IGameEventsReceiver, public IBattleEventsReceiver
{
public:
virtual void executeUserCommand(const std::string &cmd){};
virtual void init(){}; //called upon the start of game (after map randomization, before first turn)
virtual ~CScriptingModule();
};

View File

@ -1180,12 +1180,24 @@ const CGHeroInstance* CGameInfoCallback::getHeroWithSubid( int subid ) const
return NULL;
}
int CGameInfoCallback::getLocalPlayer() const
{
return getCurrentPlayer();
}
void IGameEventRealizer::showInfoDialog( InfoWindow *iw )
{
commitPackage(iw);
}
void IGameEventRealizer::showInfoDialog(const std::string &msg, int player)
{
InfoWindow iw;
iw.player = player;
iw.text << msg;
showInfoDialog(&iw);
}
void IGameEventRealizer::setObjProperty(int objid, int prop, si64 val)
{
SetObjectProperty sob;

View File

@ -144,6 +144,7 @@ public:
void getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj); //get thieves' guild info obtainable while visiting given object
int getPlayerStatus(int player) const; //-1 if no such player
int getCurrentPlayer() const; //player that currently makes move // TODO synchronous turns
virtual int getLocalPlayer() const; //player that is currently owning given client (if not a client, then returns current player)
const PlayerSettings * getPlayerSettings(int color) const;
@ -249,6 +250,9 @@ public:
virtual void showInfoDialog(InfoWindow *iw);
virtual void setObjProperty(int objid, int prop, si64 val);
virtual void showInfoDialog(const std::string &msg, int player);
};
class DLL_EXPORT IGameEventCallback : public IGameEventRealizer

View File

@ -1499,12 +1499,18 @@ struct AdvmapSpellCast : public CPackForClient //108
struct CommitPackage : public CPackForServer
{
bool freePack; //for local usage, DO NOT serialize
bool applyGh(CGameHandler *gh);
CPackForClient *packToCommit;
CommitPackage()
{
freePack = true;
}
~CommitPackage()
{
delete packToCommit;
if(freePack)
delete packToCommit;
}
template <typename Handler> void serialize(Handler &h, const int version)