1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-10-31 00:07:39 +02:00

ERM is now a separate project, linking to ./Scripting/ERM.dll and consisting all ERM* files from ./lib.

Little changes around handling ERM. New class in lib: CFileUtility, so the code for scanning files with given extension is not duplicated.
This commit is contained in:
Michał W. Urbańczyk
2011-06-20 11:41:04 +00:00
parent e7bbfb615c
commit 580c4e4c9b
24 changed files with 445 additions and 244 deletions

View File

@@ -20,7 +20,7 @@
*/
template<typename rett>
rett * createAnyAI(std::string dllname, std::string methodName)
rett * createAny(std::string dllname, std::string methodName)
{
char temp[50];
rett * ret=NULL;
@@ -29,24 +29,25 @@ rett * createAnyAI(std::string dllname, std::string methodName)
std::string dllPath;
//TODO unify at least partially (code duplication)
#ifdef _WIN32
dllPath = LIB_DIR "/" +dllname+".dll";
dllPath = dllname;
HINSTANCE dll = LoadLibraryA(dllPath.c_str());
if (!dll)
{
tlog1 << "Cannot open AI library ("<<dllPath<<"). Throwing..."<<std::endl;
throw new std::string("Cannot open AI library");
tlog1 << "Cannot open dynamic library ("<<dllPath<<"). Throwing..."<<std::endl;
throw new std::string("Cannot open dynamic library");
}
//int len = dllname.size()+1;
getName = (void(*)(char*))GetProcAddress(dll,"GetAiName");
getAI = (rett*(*)())GetProcAddress(dll,methodName.c_str());
#else
dllPath = LIB_DIR "/" + dllname + ".so";
dllPath = dllname;
void *dll = dlopen(dllPath.c_str(), RTLD_LOCAL | RTLD_LAZY);
if (!dll)
{
tlog1 << "Cannot open AI library ("<<dllPath<<"). Throwing..."<<std::endl;
throw new std::string("Cannot open AI library");
tlog1 << "Cannot open dynamic library ("<<dllPath<<"). Throwing..."<<std::endl;
throw new std::string("Cannot open dynamic library");
}
getName = (void(*)(char*))dlsym(dll,"GetAiName");
getAI = (rett*(*)())dlsym(dll,methodName.c_str());
@@ -58,20 +59,33 @@ rett * createAnyAI(std::string dllname, std::string methodName)
if(!ret)
tlog1 << "Cannot get AI!\n";
ret->dllName = dllname;
return ret;
}
CGlobalAI * CAIHandler::getNewAI(std::string dllname)
template<typename rett>
rett * createAnyAI(std::string dllname, std::string methodName)
{
rett* ret = createAny<rett>(LIB_DIR "/" + dllname + '.' + LIB_EXT, methodName);
ret->dllName = dllname;
return ret;
}
CGlobalAI * CDynLibHandler::getNewAI(std::string dllname)
{
return createAnyAI<CGlobalAI>(dllname, "GetNewAI");
}
CBattleGameInterface * CAIHandler::getNewBattleAI(std::string dllname )
CBattleGameInterface * CDynLibHandler::getNewBattleAI(std::string dllname )
{
return createAnyAI<CBattleGameInterface>(dllname, "GetNewBattleAI");
}
CScriptingModule * CDynLibHandler::getNewScriptingModule(std::string dllname)
{
return createAny<CScriptingModule>(dllname, "GetNewModule");
}
BattleAction CGlobalAI::activeStack( const CStack * stack )
{
BattleAction ba; ba.actionType = BattleAction::DEFEND;

View File

@@ -54,6 +54,7 @@ typedef si32 TQuantity;
template <typename Serializer> class CISer;
template <typename Serializer> class COSer;
struct ArtifactLocation;
class CScriptingModule;
class CBattleGameInterface : public IBattleEventsReceiver
{
@@ -82,12 +83,14 @@ public:
virtual void serialize(CISer<CLoadFile> &h, const int version){}; //loading
};
class CAIHandler
class CDynLibHandler
{
public:
static CGlobalAI * getNewAI(std::string dllname);
static CBattleGameInterface * getNewBattleAI(std::string dllname);
static CScriptingModule * getNewScriptingModule(std::string dllname);
};
class CGlobalAI : public CGameInterface // AI class (to derivate)
{
public:

115
Scripting/ERM/ERM.vcxproj Normal file
View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="RD|Win32">
<Configuration>RD</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{8F202F43-106D-4F63-AD9D-B1D43E803E8C}</ProjectGuid>
<RootNamespace>ERM</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">
<OutDir>$(SolutionDir)$(Configuration)\bin\Scripting\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)\Scripting\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../../../include;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>../../../libs; ../../;</AdditionalLibraryDirectories>
<AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>../../../include;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>../../../libs; ../../;</AdditionalLibraryDirectories>
<AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>../../../include;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>../../../libs; ../../;</AdditionalLibraryDirectories>
<AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="ERMInterpreter.h" />
<ClInclude Include="ERMParser.h" />
<ClInclude Include="ERMScriptModule.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ERMInterpreter.cpp" />
<ClCompile Include="ERMParser.cpp" />
<ClCompile Include="ERMScriptModule.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,6 +1,5 @@
#define VCMI_DLL
#include "ERMInterpreter.h"
#include <cctype>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
@@ -9,9 +8,9 @@
#include <boost/assign/std/vector.hpp>
#include <boost/assign/list_of.hpp>
#include "CObjectHandler.h"
#include "CHeroHandler.h"
#include "CCreatureHandler.h"
#include "../../lib/CObjectHandler.h"
#include "../../lib/CHeroHandler.h"
#include "../../lib/CCreatureHandler.h"
/*
* ERMInterpreter.cpp, part of VCMI engine
@@ -745,9 +744,14 @@ struct HEPerformer : StandardReceiverVisitor<const CGHeroInstance *>
if(erm->getIexp(params[0]).getInt() == 0)
{
int slot = erm->getIexp(params[1]).getInt();
const CStackInstance *stack = identifier->getStackPtr(slot);
if(params[2].which() == 6) //varp
{
erm->getIexp(boost::get<ERM::TVarpExp>(params[2])).setTo(identifier->getCreature(slot)->idNumber);
IexpValStr lhs = erm->getIexp(boost::get<ERM::TVarpExp>(params[2]));
if(stack)
lhs.setTo(stack->getCreatureID());
else
lhs.setTo(-1);
}
else
throw EScriptExecError("Setting stack creature type is not implemented!");
@@ -787,6 +791,102 @@ struct IF_MPerformer : StandardBodyOptionItemVisitor<IFPerformer>
void operator()(TStringConstant const& cmp) const OVERRIDE;
};
//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
struct StringFormatter
{
int pos;
int tokenLength;
int percentPos;
int charsToReplace;
std::string &msg;
StringFormatter(std::string &MSG) : msg(MSG), pos(0) {}
static void format(std::string &msg)
{
StringFormatter sf(msg);
sf.format();
}
// startpos is the first digit
// digits will be converted to number and returned
// ADDITIVE on digitsUsed
int getNum()
{
int toAdd = 0;
int numStart = percentPos + 2;
int numEnd = msg.find_first_not_of("1234567890", numStart);
if(numEnd == std::string::npos)
toAdd = msg.size() - numStart;
else
toAdd = numEnd - numStart;
charsToReplace += toAdd;
return boost::lexical_cast<int>(msg.substr(numStart, toAdd));
}
void format()
{
while(pos < msg.size())
{
percentPos = msg.find_first_of('%', pos);
charsToReplace = 1; //at least the same '%' needs to be replaced
std::ostringstream replaceWithWhat;
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!");
charsToReplace++; //the sign after % is consumed
switch(msg[percentPos+1])
{
case '%':
replaceWithWhat << '%';
break;
case 'F':
replaceWithWhat << erm->ermGlobalEnv->getFlag(getNum());
break;
case 'V':
if(std::isdigit(msg[percentPos + 2]))
replaceWithWhat << erm->ermGlobalEnv->getStandardVar(getNum());
else
{
charsToReplace++;
replaceWithWhat << erm->ermGlobalEnv->getQuickVar(msg[percentPos+2]);
}
case 'X':
replaceWithWhat << erm->getVar("x", getNum()).getInt();
break;
case 'Z':
replaceWithWhat << erm->ermGlobalEnv->getZVar(getNum());
break;
default:
throw EScriptExecError("Formatting error: unrecognized token indicator after %!");
}
msg.replace(percentPos, charsToReplace, replaceWithWhat.str());
pos = percentPos + 1;
}
}
};
struct IFPerformer : StandardReceiverVisitor<TUnusedType>
{
IFPerformer(ERMInterpreter * _interpr) : StandardReceiverVisitor<TUnusedType>(_interpr, 0)
@@ -807,69 +907,10 @@ struct IFPerformer : StandardReceiverVisitor<TUnusedType>
}
}
// 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);
StringFormatter::format(msgToFormat);
acb->showInfoDialog(msgToFormat, icb->getLocalPlayer());
}
};
@@ -1937,54 +1978,6 @@ void ERMInterpreter::setCurrentlyVisitedObj( int3 pos )
ermGlobalEnv->getStandardVar(1000) = pos.z;
}
struct StringProcessHLP
{
int extractNumber(const std::string & token)
{
return atoi(token.substr(1).c_str());
}
template <typename T>
void replaceToken(std::string ret, int tokenBegin, int tokenEnd, T val)
{
ret.replace(tokenBegin, tokenEnd, boost::lexical_cast<std::string>(val));
}
};
std::string ERMInterpreter::processERMString( std::string ermstring )
{
StringProcessHLP hlp;
std::string ret = ermstring;
int curPos = 0;
while((curPos = ret.find('%', curPos)) != std::string::npos)
{
curPos++;
int tokenEnd = ret.find(' ', curPos);
std::string token = ret.substr(curPos, tokenEnd - curPos);
if(token.size() == 0)
{
throw EScriptExecError("Empty token not allowed!");
}
switch(token[0])
{
case '%':
ret.erase(curPos);
break;
case 'F':
hlp.replaceToken(ret, curPos, tokenEnd, ermGlobalEnv->getFlag(hlp.extractNumber(token)));
break;
case 'V':
hlp.replaceToken(ret, curPos, tokenEnd, ermGlobalEnv->getStandardVar(hlp.extractNumber(token)));
break;
default:
throw EScriptExecError("Unrecognized token in string");
break;
}
}
return ret;
}
const std::string ERMInterpreter::triggerSymbol = "trigger";
const std::string ERMInterpreter::postTriggerSymbol = "postTrigger";
const std::string ERMInterpreter::defunSymbol = "defun";
@@ -2747,6 +2740,16 @@ void ERMInterpreter::executeUserCommand(const std::string &cmd)
tlog0 << "ERM here: received command: " << cmd << std::endl;
}
void ERMInterpreter::giveInfoCB(CPrivilagedInfoCallback *cb)
{
icb = cb;
}
void ERMInterpreter::giveActionCB(IGameEventRealizer *cb)
{
acb = cb;
}
namespace VERMInterpreter
{
VOption convertToVOption(const ERM::TVOption & tvo)

View File

@@ -1,7 +1,6 @@
#pragma once
#include "../global.h"
#include "../../global.h"
#include "ERMParser.h"
#include "IGameEventsReceiver.h"
#include "ERMScriptModule.h"
/*
@@ -841,6 +840,8 @@ public:
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 giveInfoCB(CPrivilagedInfoCallback *cb) OVERRIDE;
virtual void giveActionCB(IGameEventRealizer *cb) OVERRIDE;
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) OVERRIDE;
@@ -854,4 +855,5 @@ public:
else
throw VERMInterpreter::EScriptExecError("Wrong cast attempted, object is not of a desired type!");
}
};

View File

@@ -1,4 +1,3 @@
#define VCMI_DLL
#include "ERMParser.h"
#include <boost/version.hpp>
//To make compilation with older boost versions possible

View File

@@ -1,5 +1,5 @@
#pragma once
#include "../global.h"
#include "../../global.h"
#include <fstream>
#include <boost/variant.hpp>
#include <boost/optional.hpp>

View File

@@ -0,0 +1,22 @@
#include "ERMScriptModule.h"
#include "ERMInterpreter.h"
IGameEventRealizer *acb;
CPrivilagedInfoCallback *icb;
#ifdef __GNUC__
#define strcpy_s(a, b, c) strncpy(a, c, b)
#endif
const char *g_cszAiName = "(V)ERM interpreter";
extern "C" DLL_F_EXPORT void GetAiName(char* name)
{
strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
}
extern "C" DLL_F_EXPORT CScriptingModule* GetNewModule()
{
return new ERMInterpreter();
}

View File

@@ -0,0 +1,5 @@
#pragma once
#include "../../lib/CScriptingModule.h"
extern IGameEventRealizer *acb;
extern CPrivilagedInfoCallback *icb;

View File

@@ -14,6 +14,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StupidAI", "AI\StupidAI\Stu
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F} = {B952FFC5-3039-4DE1-9F08-90ACDA483D8F}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ERM", "Scripting\ERM\ERM.vcxproj", "{8F202F43-106D-4F63-AD9D-B1D43E803E8C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -51,6 +53,12 @@ Global
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.RD|Win32.Build.0 = RD|Win32
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.Release|Win32.ActiveCfg = Release|Win32
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.Release|Win32.Build.0 = Release|Win32
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.Debug|Win32.ActiveCfg = Debug|Win32
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.Debug|Win32.Build.0 = Debug|Win32
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.RD|Win32.ActiveCfg = RD|Win32
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.RD|Win32.Build.0 = RD|Win32
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.Release|Win32.ActiveCfg = Release|Win32
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -45,7 +45,7 @@
#include "../lib/CObjectHandler.h"
#include <boost/program_options.hpp>
#include "../lib/CArtHandler.h"
#include "../lib/ERMScriptModule.h"
#include "../lib/CScriptingModule.h"
#ifdef _WIN32
#include "SDL_syswm.h"

View File

@@ -48,6 +48,7 @@
#include <boost/thread/recursive_mutex.hpp>
#include "../CThreadHelper.h"
#include "CConfigHandler.h"
#include "../lib/CFileUtility.h"
/*
* CPreGame.cpp, part of VCMI engine
@@ -846,34 +847,7 @@ void SelectionTab::filter( int size, bool selectFirst )
void SelectionTab::getFiles(std::vector<FileInfo> &out, const std::string &dirname, const std::string &ext)
{
if(!boost::filesystem::exists(dirname))
{
tlog1 << "Cannot find " << dirname << " directory!\n";
}
fs::path tie(dirname);
fs::directory_iterator end_iter;
for ( fs::directory_iterator file (tie); file!=end_iter; ++file )
{
if(fs::is_regular_file(file->status())
&& boost::ends_with(file->path().filename(), ext))
{
std::time_t date = 0;
try
{
date = fs::last_write_time(file->path());
out.resize(out.size()+1);
out.back().date = date;
out.back().name = file->path().string();
}
catch(...)
{
tlog2 << "\t\tWarning: very corrupted map file: " << file->path().string() << std::endl;
}
}
}
CFileUtility::getFilesWithExt(out, dirname, ext);
allItems.resize(out.size());
}

View File

@@ -30,6 +30,7 @@ class CCampaignState;
class CConnection;
struct CPackForSelectionScreen;
struct PlayerInfo;
struct FileInfo;
namespace boost{ class thread; class recursive_mutex;}
@@ -66,13 +67,6 @@ public:
void moveTo(CMenuScreen *next);
};
/// Struct which stores name, date and a value which says if the file is located in LOD
struct FileInfo
{
std::string name; // file name with full path and extension
std::time_t date;
bool inLod; //tells if this file is located in Lod
};
/// Implementation of the chat box
class CChatBox : public CIntObject

View File

@@ -33,7 +33,8 @@
#include "CPreGame.h"
#include "CBattleInterface.h"
#include "../CThreadHelper.h"
#include "../lib/ERMScriptModule.h"
#include "../lib/CScriptingModule.h"
#include "../lib/CFileUtility.h"
#define NOT_LIB
#include "../lib/RegisterTypes.cpp"
@@ -394,7 +395,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
CCallback *cb = new CCallback(gs,color,this);
if(!it->second.human)
{
playerint[color] = static_cast<CGameInterface*>(CAIHandler::getNewAI(conf.cc.defaultPlayerAI));
playerint[color] = static_cast<CGameInterface*>(CDynLibHandler::getNewAI(conf.cc.defaultPlayerAI));
}
else
{
@@ -408,7 +409,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
else
{
CBattleCallback * cbc = new CBattleCallback(gs, color, this);
battleints[color] = CAIHandler::getNewBattleAI("StupidAI");
battleints[color] = CDynLibHandler::getNewBattleAI("StupidAI");
battleints[color]->init(cbc);
}
}
@@ -430,13 +431,19 @@ void CClient::newGame( CConnection *con, StartInfo *si )
serv->addStdVecItems(const_cast<CGameInfo*>(CGI)->state);
hotSeat = (humanPlayers > 1);
std::vector<FileInfo> scriptModules;
CFileUtility::getFilesWithExt(scriptModules, "./Scripting", ".dll");
BOOST_FOREACH(FileInfo &m, scriptModules)
{
CScriptingModule * nm = CDynLibHandler::getNewScriptingModule(m.name);
privilagedGameEventReceivers.push_back(nm);
privilagedBattleEventReceivers.push_back(nm);
nm->giveActionCB(this);
nm->giveInfoCB(this);
nm->init();
erm = getERMModule();
privilagedGameEventReceivers.push_back(erm);
privilagedBattleEventReceivers.push_back(erm);
icb = this;
acb = this;
erm->init();
erm = nm; //something tells me that there'll at most one module and it'll be ERM
}
}
template <typename Handler>
@@ -472,14 +479,14 @@ void CClient::serialize( Handler &h, const int version )
if(pid == 255)
{
CBattleCallback * cbc = new CBattleCallback(gs, pid, this);
CBattleGameInterface *cbgi = CAIHandler::getNewBattleAI(dllname);
CBattleGameInterface *cbgi = CDynLibHandler::getNewBattleAI(dllname);
battleints[pid] = cbgi;
cbgi->init(cb);
//TODO? consider serialization
continue;
}
else
nInt = CAIHandler::getNewAI(dllname);
nInt = CDynLibHandler::getNewAI(dllname);
}
else
nInt = new CPlayerInterface(pid);
@@ -591,7 +598,7 @@ void CClient::battleStarted(const BattleInfo * info)
void CClient::loadNeutralBattleAI()
{
battleints[255] = CAIHandler::getNewBattleAI(conf.cc.defaultBattleAI);
battleints[255] = CDynLibHandler::getNewBattleAI(conf.cc.defaultBattleAI);
battleints[255]->init(new CBattleCallback(gs, 255, this));
}

View File

@@ -51,22 +51,24 @@ extern std::string NAME_AFFIX; //client / server
* LIB_DIR is where the AI libraries reside (linux only)
*/
#ifdef _WIN32
#define DATA_DIR "."
#define USER_DIR "."
#define BIN_DIR "."
#define LIB_DIR "AI"
#define SERVER_NAME "VCMI_server.exe"
#define DATA_DIR "."
#define USER_DIR "."
#define BIN_DIR "."
#define LIB_DIR "AI"
#define SERVER_NAME "VCMI_server.exe"
#define LIB_EXT "dll"
#else
#ifndef DATA_DIR
#error DATA_DIR undefined.
#endif
#ifndef BIN_DIR
#error BIN_DIR undefined.
#endif
#ifndef LIB_DIR
#error LIB_DIR undefined.
#endif
#define SERVER_NAME "vcmiserver"
#ifndef DATA_DIR
#error DATA_DIR undefined.
#endif
#ifndef BIN_DIR
#error BIN_DIR undefined.
#endif
#ifndef LIB_DIR
#error LIB_DIR undefined.
#endif
#define SERVER_NAME "vcmiserver"
#define LIB_EXT "so"
#endif
#ifdef _WIN32

View File

@@ -268,7 +268,14 @@ void CCreatureSet::clear()
const CStackInstance& CCreatureSet::getStack(TSlot slot) const
{
assert(hasStackAtSlot(slot));
return *stacks.find(slot)->second;
return *getStackPtr(slot);
}
const CStackInstance* CCreatureSet::getStackPtr(TSlot slot) const
{
if(hasStackAtSlot(slot))
return stacks.find(slot)->second;
else return NULL;
}
void CCreatureSet::eraseStack(TSlot slot)
@@ -914,6 +921,14 @@ void CStackInstance::deserializationFix()
setArmyObj(armyBackup);
}
int CStackInstance::getCreatureID() const
{
if(type)
return type->idNumber;
else
return -1;
}
CStackBasicDescriptor::CStackBasicDescriptor()
{
type = NULL;

View File

@@ -53,6 +53,7 @@ public:
std::string getQuantityTXT(bool capitalized = true) const;
int getExpRank() const;
si32 magicResistance() const;
int getCreatureID() const; //-1 if not available
void init();
CStackInstance();
CStackInstance(TCreature id, TQuantity count);
@@ -132,7 +133,8 @@ public:
bool setCreature (TSlot slot, TCreature type, TQuantity quantity) OVERRIDE; //replaces creature in stack; slots 0 to 6, if quantity=0 erases stack
void setToArmy(CSimpleArmy &src); //erases all our army and moves stacks from src to us; src MUST NOT be an armed object! WARNING: use it wisely. Or better do not use at all.
const CStackInstance& getStack(TSlot slot) const;
const CStackInstance& getStack(TSlot slot) const; //stack must exist
const CStackInstance* getStackPtr(TSlot slot) const; //if stack doesn't exist, returns NULL
const CCreature* getCreature(TSlot slot) const; //workaround of map issue;
int getStackCount (TSlot slot) const;
expType getStackExperience(TSlot slot) const;

46
lib/CFileUtility.cpp Normal file
View File

@@ -0,0 +1,46 @@
#define VCMI_DLL
#include "CFileUtility.h"
#include <boost/filesystem.hpp> // includes all needed Boost.Filesystem declarations
#include <boost/algorithm/string/predicate.hpp>
namespace fs = boost::filesystem;
CFileUtility::CFileUtility(void)
{
}
CFileUtility::~CFileUtility(void)
{
}
void CFileUtility::getFilesWithExt(std::vector<FileInfo> &out, const std::string &dirname, const std::string &ext)
{
if(!fs::exists(dirname))
{
tlog1 << "Cannot find " << dirname << " directory!\n";
}
fs::path tie(dirname);
fs::directory_iterator end_iter;
for ( fs::directory_iterator file (tie); file!=end_iter; ++file )
{
if(fs::is_regular_file(file->status())
&& boost::ends_with(file->path().filename(), ext))
{
std::time_t date = 0;
try
{
date = fs::last_write_time(file->path());
out.resize(out.size()+1);
out.back().date = date;
out.back().name = file->path().string();
}
catch(...)
{
tlog2 << "\t\tWarning: very corrupted file: " << file->path().string() << std::endl;
}
}
}
}

20
lib/CFileUtility.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include "../global.h"
/// Struct which stores name, date and a value which says if the file is located in LOD
struct FileInfo
{
std::string name; // file name with full path and extension
std::time_t date;
bool inLod; //tells if this file is located in Lod
};
class DLL_EXPORT CFileUtility
{
public:
CFileUtility(void);
~CFileUtility(void);
static void getFilesWithExt(std::vector<FileInfo> &out, const std::string &dirname, const std::string &ext);
};

16
lib/CScriptingModule.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include "../global.h"
#include "IGameEventsReceiver.h"
#include "IGameCallback.h"
class 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 void giveActionCB(IGameEventRealizer *cb){};
virtual void giveInfoCB(CPrivilagedInfoCallback *cb){};
CScriptingModule(){}
virtual ~CScriptingModule(){}
};

View File

@@ -1,20 +0,0 @@
#define VCMI_DLL
#include "ERMScriptModule.h"
#include "ERMInterpreter.h"
#include "CObjectHandler.h"
IGameEventRealizer *acb;
CPrivilagedInfoCallback *icb;
CScriptingModule * getERMModule()
{
CScriptingModule *ret = new ERMInterpreter();
return ret;
}
CScriptingModule::~CScriptingModule()
{
}

View File

@@ -1,23 +0,0 @@
#pragma once
#include "../global.h"
#include "IGameEventsReceiver.h"
#include "IGameCallback.h"
class IGameEventRealizer;
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();
};
extern DLL_EXPORT IGameEventRealizer *acb;
extern DLL_EXPORT CPrivilagedInfoCallback *icb;
DLL_EXPORT CScriptingModule *getERMModule();

View File

@@ -11,7 +11,7 @@
#include "CBuildingHandler.h"
#include "CSpellHandler.h"
#include "CGeneralTextHandler.h"
#include "ERMInterpreter.h"
#include "IGameEventsReceiver.h"
/*
* VCMI_Lib.cpp, part of VCMI engine

View File

@@ -172,6 +172,7 @@
<ClCompile Include="CCreatureHandler.cpp" />
<ClCompile Include="CCreatureSet.cpp" />
<ClCompile Include="CDefObjInfoHandler.cpp" />
<ClCompile Include="CFileUtility.cpp" />
<ClCompile Include="CGameState.cpp" />
<ClCompile Include="CGeneralTextHandler.cpp" />
<ClCompile Include="CHeroHandler.cpp" />
@@ -181,9 +182,6 @@
<ClCompile Include="Connection.cpp" />
<ClCompile Include="CSpellHandler.cpp" />
<ClCompile Include="CTownHandler.cpp" />
<ClCompile Include="ERMInterpreter.cpp" />
<ClCompile Include="ERMParser.cpp" />
<ClCompile Include="ERMScriptModule.cpp" />
<ClCompile Include="HeroBonus.cpp" />
<ClCompile Include="IGameCallback.cpp" />
<ClCompile Include="map.cpp" />
@@ -204,6 +202,7 @@
<ClInclude Include="CCreatureHandler.h" />
<ClInclude Include="CCreatureSet.h" />
<ClInclude Include="CDefObjInfoHandler.h" />
<ClInclude Include="CFileUtility.h" />
<ClInclude Include="CGameState.h" />
<ClInclude Include="CGeneralTextHandler.h" />
<ClInclude Include="CHeroHandler.h" />
@@ -214,11 +213,9 @@
<ClInclude Include="CondSh.h" />
<ClInclude Include="Connection.h" />
<ClInclude Include="ConstTransitivePtr.h" />
<ClInclude Include="CScriptingModule.h" />
<ClInclude Include="CSpellHandler.h" />
<ClInclude Include="CTownHandler.h" />
<ClInclude Include="ERMInterpreter.h" />
<ClInclude Include="ERMParser.h" />
<ClInclude Include="ERMScriptModule.h" />
<ClInclude Include="HeroBonus.h" />
<ClInclude Include="IGameCallback.h" />
<ClInclude Include="IGameEventsReceiver.h" />