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:
parent
78b5e11b93
commit
9775f88045
@ -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;
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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 {};
|
||||
|
2
global.h
2
global.h
@ -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
|
||||
|
@ -413,6 +413,7 @@ 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)
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -1499,11 +1499,17 @@ 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()
|
||||
{
|
||||
if(freePack)
|
||||
delete packToCommit;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user