1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-15 00:05:02 +02:00

Entities redesign and a few ERM features

* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
This commit is contained in:
AlexVinS
2018-03-17 17:58:30 +03:00
committed by AlexVinS
parent 11bb46780a
commit ecaa9f5d0b
475 changed files with 22491 additions and 7123 deletions

View File

@ -1,14 +1,16 @@
include_directories(${CMAKE_HOME_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/include ${CMAKE_CURRENT_SOURCE_DIRECTORY})
include_directories(${Boost_INCLUDE_DIRS} ${CMAKE_HOME_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/include ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib)
set(lib_SRCS
StdInc.cpp
ERMParser.cpp
ERMInterpreter.cpp
ERMScriptModule.cpp
ERMParser.cpp
ERMInterpreter.cpp
ERMScriptModule.cpp
)
add_library(vcmiERM SHARED ${lib_SRCS})
target_link_libraries(vcmiERM ${Boost_LIBRARIES})
target_link_libraries(vcmiERM ${Boost_LIBRARIES} vcmi)
vcmi_set_output_dir(vcmiERM "scripting")
set_target_properties(vcmiERM PROPERTIES ${PCH_PROPERTIES})
cotire(vcmiERM)

View File

@ -8,7 +8,7 @@
<Build>
<Target title="Debug-win32">
<Option platforms="Windows;" />
<Option output="../ERM" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option output="../vcmiERM" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/x86/" />
<Option type="3" />
<Option compiler="gcc" />
@ -29,7 +29,7 @@
</Target>
<Target title="Release-win32">
<Option platforms="Windows;" />
<Option output="../ERM" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option output="../vcmiERM" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/x86/" />
<Option type="3" />
<Option compiler="gcc" />
@ -50,7 +50,7 @@
</Target>
<Target title="Debug-win64">
<Option platforms="Windows;" />
<Option output="../ERM" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option output="../vcmiERM" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/x64/" />
<Option type="3" />
<Option compiler="gnu_gcc_compiler_x64" />
@ -73,6 +73,7 @@
<Compiler>
<Add option="-Wextra" />
<Add option="-Wall" />
<Add option="-std=gnu++11" />
<Add option="-fexceptions" />
<Add option="-Wpointer-arith" />
<Add option="-Wno-switch" />
@ -81,7 +82,7 @@
<Add option="-Wno-overloaded-virtual" />
<Add option="-DBOOST_ALL_DYN_LINK" />
<Add option="-DBOOST_SYSTEM_NO_DEPRECATED" />
<Add option="-D_WIN32_WINNT=0x0501" />
<Add option="-D_WIN32_WINNT=0x0600" />
<Add option="-D_WIN32" />
<Add directory="$(#boost.include)" />
<Add directory="../../include" />
@ -89,6 +90,7 @@
<Linker>
<Add directory="../.." />
</Linker>
<Unit filename="CMakeLists.txt" />
<Unit filename="ERMInterpreter.cpp" />
<Unit filename="ERMInterpreter.h" />
<Unit filename="ERMParser.cpp" />
@ -100,10 +102,6 @@
<Option weight="0" />
</Unit>
<Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" />
<DoxyBlocks>
<comment_style block="0" line="0" />
<doxyfile_project />
@ -113,6 +111,7 @@
<doxyfile_dot />
<general />
</DoxyBlocks>
<lib_finder disable_auto="1" />
</Extensions>
</Project>
</CodeBlocks_project_file>

File diff suppressed because it is too large Load Diff

View File

@ -9,10 +9,11 @@
*/
#pragma once
#include "ERMParser.h"
#include "ERMScriptModule.h"
class ERMInterpreter;
namespace VERMInterpreter
{
using namespace ERM;
@ -98,7 +99,6 @@ namespace VERMInterpreter
{}
};
// All numeric variables are integer variables and have a range of -2147483647...+2147483647
// c stores game active day number //indirect variable
// d current value //not an actual variable but a modifier
@ -114,73 +114,25 @@ namespace VERMInterpreter
// z1..z1000 String variables //global
// z-1..z-10 Function local string variables //local
struct TriggerLocalVars
{
static const int EVAR_NUM = 100; //number of evar locals
static const int YVAR_NUM = 100; //number of yvar locals
TriggerLocalVars();
double & getEvar(int num);
int & getYvar(int num);
private:
double evar[EVAR_NUM]; //negative indices
int yvar[YVAR_NUM];
};
struct FunctionLocalVars
{
static const int NUM_PARAMETERS = 16; //number of function parameters
static const int NUM_LOCALS = 100;
static const int NUM_STRINGS = 10;
static const int NUM_FLOATINGS = 100;
int & getParam(int num);
int & getLocal(int num);
std::string & getString(int num);
double & getFloat(int num);
void reset();
private:
int params[NUM_PARAMETERS]; //x-vars
int locals[NUM_LOCALS]; //y-vars
std::string strings[NUM_STRINGS]; //z-vars (negative indices)
double floats[NUM_FLOATINGS]; //e-vars (positive indices)
};
struct ERMEnvironment
{
ERMEnvironment();
static const int NUM_QUICKS = 't' - 'f' + 1; //it should be 15
int & getQuickVar(const char letter); //'f' - 't' variables
int & getStandardVar(int num); //get v-variable
std::string & getZVar(int num);
bool & getFlag(int num);
static const int NUM_STANDARDS = 10000;
static const int NUM_STRINGS = 1000;
std::map<std::string, ERM::TVarExpNotMacro> macroBindings;
static const int NUM_FLAGS = 1000;
private:
int quickVars[NUM_QUICKS]; //referenced by letter ('f' to 't' inclusive)
int standardVars[NUM_STANDARDS]; //v-vars
std::string strings[NUM_STRINGS]; //z-vars (positive indices)
bool flags[NUM_FLAGS];
};
struct TriggerType
{
//the same order of trigger types in this enum and in validTriggers array is obligatory!
enum ETrigType{AE, BA, BF, BG, BR, CM, CO, FU, GE, GM, HE, HL, HM, IP, LE, MF, MG, MM, MR,
MW, OB, PI, SN, TH, TM} type;
enum ETrigType
{
AE, BA, BF, BG, BR, CM, CO, FU, GE, GM, HE, HL, HM, IP, LE, MF, MG, MM, MR, MW, OB, PI, SN, TH, TM
};
ETrigType type;
static ETrigType convertTrigger(const std::string & trig)
{
static const std::string validTriggers[] = {"AE", "BA", "BF", "BG", "BR", "CM", "CO", "FU",
static const std::string validTriggers[] =
{
"AE", "BA", "BF", "BG", "BR", "CM", "CO", "FU",
"GE", "GM", "HE", "HL", "HM", "IP", "LE", "MF", "MG", "MM", "MR", "MW", "OB", "PI", "SN",
"TH", "TM"};
"TH", "TM"
};
for(int i=0; i<ARRAY_COUNT(validTriggers); ++i)
{
@ -202,38 +154,30 @@ namespace VERMInterpreter
};
struct FileInfo
{
std::string filename;
int length;
};
struct LinePointer
{
const FileInfo * file; //non-owning
int lineNum;
int realLineNum;
int fileLength;
LinePointer() : file(nullptr)
LinePointer()
: fileLength(-1)
{}
LinePointer(const FileInfo * finfo, int line, int _realLineNum) : file(finfo), lineNum(line),
LinePointer(int _fileLength, int line, int _realLineNum)
: fileLength(_fileLength),
lineNum(line),
realLineNum(_realLineNum)
{}
//lexicographical order
bool operator<(const LinePointer & rhs) const
{
if(file->filename != rhs.file->filename)
return file->filename < rhs.file->filename;
return lineNum < rhs.lineNum;
}
bool operator!=(const LinePointer & rhs) const
{
return file->filename != rhs.file->filename || lineNum != rhs.lineNum;
return lineNum != rhs.lineNum;
}
LinePointer & operator++()
{
@ -242,45 +186,14 @@ namespace VERMInterpreter
}
bool isValid() const
{
return file && lineNum < file->length;
return fileLength > 0 && lineNum < fileLength;
}
};
struct LexicalPtr
{
LinePointer line; //where to start
std::vector<int> entryPoints; //defines how to pass to current location
bool operator<(const LexicalPtr & sec) const
{
if(line != sec.line)
return line < sec.line;
if(entryPoints.size() != sec.entryPoints.size())
return entryPoints.size() < sec.entryPoints.size();
for(int g=0; g<entryPoints.size(); ++g)
{
if(entryPoints[g] < sec.entryPoints[g])
return true;
}
return false;
}
};
//call stack, represents dynamic range
struct Stack
{
std::vector<LexicalPtr> stack;
};
struct Trigger
{
LinePointer line;
TriggerLocalVars ermLocalVars;
Stack * stack; //where we are stuck at execution
Trigger() : stack(nullptr)
Trigger()
{}
};
@ -302,99 +215,7 @@ namespace VERMInterpreter
typedef boost::variant<char, double, int, std::string> TLiteral;
//for operator <, but this one seems to be implemented in boost alerady
struct _opLTvis : boost::static_visitor<bool>
{
const TLiteral & lhs;
_opLTvis(const TLiteral & _lhs) : lhs(_lhs)
{}
template<typename OP>
bool operator()(OP const & rhs) const
{
return boost::get<OP>(lhs) < rhs;
}
};
// bool operator<(const TLiteral & t1, const TLiteral & t2)
// {
// if(t1.type() == t2.type())
// {
// return boost::apply_visitor(_opLTvis(t1), t2);
// }
// throw EVermScriptExecError("These types are incomparable!");
// }
//for operator <=
struct _opLEvis : boost::static_visitor<bool>
{
const TLiteral & lhs;
_opLEvis(const TLiteral & _lhs) : lhs(_lhs)
{}
template<typename OP>
bool operator()(OP const & rhs) const
{
return boost::get<OP>(lhs) <= rhs;
}
};
bool operator<=(const TLiteral & t1, const TLiteral & t2);
//operator >
struct _opGTvis : boost::static_visitor<bool>
{
const TLiteral & lhs;
_opGTvis(const TLiteral & _lhs) : lhs(_lhs)
{}
template<typename OP>
bool operator()(OP const & rhs) const
{
return boost::get<OP>(lhs) > rhs;
}
};
bool operator>(const TLiteral & t1, const TLiteral & t2);
//operator >=
struct _opGEvis : boost::static_visitor<bool>
{
const TLiteral & lhs;
_opGEvis(const TLiteral & _lhs) : lhs(_lhs)
{}
template<typename OP>
bool operator()(OP const & rhs) const
{
return boost::get<OP>(lhs) >= rhs;
}
};
bool operator>=(const TLiteral & t1, const TLiteral & t2);
//operator =
struct _opEQvis : boost::static_visitor<bool>
{
const TLiteral & lhs;
_opEQvis(const TLiteral & _lhs) : lhs(_lhs)
{}
template<typename OP>
bool operator()(OP const & rhs) const
{
return boost::get<OP>(lhs) == rhs;
}
};
//VFunc
struct VFunc;
//VOption & stuff
typedef boost::variant<VNIL, boost::recursive_wrapper<VNode>, VSymbol, TLiteral, ERM::Tcommand, boost::recursive_wrapper<VFunc> > VOption; //options in v-expression, VNIl should be the default
typedef boost::variant<VNIL, boost::recursive_wrapper<VNode>, VSymbol, TLiteral, ERM::Tcommand> VOption; //options in v-expression, VNIl should be the default
template<typename T, typename SecType>
T& getAs(SecType & opt)
@ -414,84 +235,6 @@ namespace VERMInterpreter
return false;
}
//why it doesn't work?
// template<typename TBasicVariant>
// struct IntVarinant : public TBasicVariant
// {
// template<typename T>
// bool isA() const
// {
// return type() == typeid(T);
// }
// template<typename T>
// T getAs()
// {
// if(isA<T>())
// return boost::get<T>(*this);
// else
// throw EVermScriptExecError("Getting improved variant with wrongly specified type");
// }
//
// IntVarinant(const VNode & val) : TBasicVariant(val)
// {}
// IntVarinant(const VNIL & val) : TBasicVariant(val)
// {}
// IntVarinant(const TLiteral & val) : TBasicVariant(val)
// {}
// IntVarinant(const VSymbol & val) : TBasicVariant(val)
// {}
// IntVarinant(const int & val) : TBasicVariant(val)
// {}
// IntVarinant(const char & val) : TBasicVariant(val)
// {}
// IntVarinant(const double & val) : TBasicVariant(val)
// {}
// IntVarinant(const ERM::Tcommand & val) : TBasicVariant(val)
// {}
// TBasicVariant & getAsPlaintVariant()
// {
// return *this;
// }
//
// IntVarinant()
// {}
// };
///main environment class, manages symbols
class Environment
{
private:
std::map<std::string, VOption> symbols;
Environment * parent;
public:
Environment() : parent(nullptr)
{}
void setPatent(Environment * _parent);
Environment * getPatent() const;
enum EIsBoundMode {GLOBAL_ONLY, LOCAL_ONLY, ANYWHERE};
bool isBound(const std::string & name, EIsBoundMode mode) const;
VOption & retrieveValue(const std::string & name);
enum EUnbindMode{LOCAL, RECURSIVE_UNTIL_HIT, FULLY_RECURSIVE};
///returns true if symbol was really unbound
bool unbind(const std::string & name, EUnbindMode mode);
void localBind(std::string name, const VOption & sym);
void bindAtFirstHit(std::string name, const VOption & sym); //if symbol is locally defines, it gets overwritten; otherwise it is bind globally
};
//this class just introduces a new dynamic range when instantiated, nothing more
class IntroduceDynamicEnv
{
public:
IntroduceDynamicEnv();
~IntroduceDynamicEnv();
};
struct VermTreeIterator
{
private:
@ -509,9 +252,7 @@ namespace VERMInterpreter
VermTreeIterator & operator=(const std::vector<VOption> & opt);
VermTreeIterator & operator=(const VOptionList & opt);
VOption & getAsItem();
VermTreeIterator getAsCDR();
VOptionList getAsList();
VOption & getIth(int i);
size_t size() const;
VermTreeIterator& operator=(const VermTreeIterator & rhs)
@ -535,32 +276,6 @@ namespace VERMInterpreter
public:
VermTreeIterator car();
VermTreeIterator cdr();
bool isNil() const;
};
struct VFunc
{
enum Eopt {DEFAULT, LT, GT, LE, GE, EQ, ADD, SUB, MULT, DIV, MOD} option;
std::vector<VSymbol> args;
VOptionList body;
bool macro; //true - act as macro, false - act as function
VFunc(const VOptionList & _body, bool asMacro = false) : option(DEFAULT), body(_body), macro(asMacro)
{}
VFunc(Eopt func) : option(func), macro(false)
{}
VFunc& operator=(const VFunc & rhs)
{
if(this == &rhs)
{
return *this;
}
args = rhs.args;
body = rhs.body;
return *this;
}
VOption operator()(VermTreeIterator params);
};
struct OptionConverterVisitor : boost::static_visitor<VOption>
@ -586,275 +301,29 @@ namespace VERMInterpreter
VNode( const VOption & first, const VOptionList & rest); //merges given arguments into [a, rest];
void setVnode( const VOption & first, const VOptionList & rest);
};
//v printer
void printVOption(const VOption & opt);
}
class ERMInterpreter;
struct TriggerIdentifierMatch
{
bool allowNoIdetifier;
std::map< int, std::vector<int> > matchToIt; //match subidentifiers to these numbers
static const int MAX_SUBIDENTIFIERS = 16;
ERMInterpreter * ermEnv;
bool tryMatch(VERMInterpreter::Trigger * interptrig) const;
};
struct IexpValStr
{
private:
union
{
int val;
int * integervar;
double * flvar;
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);
void setTo(double val);
void setTo(const std::string & val);
int getInt() const;
double getFloat() const;
std::string getString() const;
IexpValStr() : type(WRONGVAL)
{}
IexpValStr(int _val) : type(INT)
{
val.val = _val;
}
IexpValStr(int* _val) : type(INTVAR)
{
val.integervar = _val;
}
IexpValStr(double * _val) : type(FLOATVAR)
{
val.flvar = _val;
}
IexpValStr(std::string * _val) : type(STRINGVAR)
{
val.stringvar = _val;
}
#define OPERATOR_DEFINITION_FULL(OPSIGN) \
template<typename T> \
IexpValStr operator OPSIGN(const T & sec) const \
{ \
IexpValStr ret = *this; \
switch (type) \
{ \
case INT: \
case INTVAR: \
ret.setTo(ret.getInt() OPSIGN sec); \
break; \
case FLOATVAR: \
ret.setTo(ret.getFloat() OPSIGN sec); \
break; \
case STRINGVAR: \
ret.setTo(ret.getString() OPSIGN sec); \
break; \
} \
return ret; \
} \
IexpValStr operator OPSIGN(const IexpValStr & sec) const \
{ \
IexpValStr ret = *this; \
switch (type) \
{ \
case INT: \
case INTVAR: \
ret.setTo(ret.getInt() OPSIGN sec.getInt()); \
break; \
case FLOATVAR: \
ret.setTo(ret.getFloat() OPSIGN sec.getFloat()); \
break; \
case STRINGVAR: \
ret.setTo(ret.getString() OPSIGN sec.getString()); \
break; \
} \
return ret; \
} \
template<typename T> \
IexpValStr & operator OPSIGN ## = (const T & sec) \
{ \
*this = *this OPSIGN sec; \
return *this; \
}
#define OPERATOR_DEFINITION(OPSIGN) \
template<typename T> \
IexpValStr operator OPSIGN(const T & sec) const \
{ \
IexpValStr ret = *this; \
switch (type) \
{ \
case INT: \
case INTVAR: \
ret.setTo(ret.getInt() OPSIGN sec); \
break; \
case FLOATVAR: \
ret.setTo(ret.getFloat() OPSIGN sec); \
break; \
} \
return ret; \
} \
IexpValStr operator OPSIGN(const IexpValStr & sec) const \
{ \
IexpValStr ret = *this; \
switch (type) \
{ \
case INT: \
case INTVAR: \
ret.setTo(ret.getInt() OPSIGN sec.getInt()); \
break; \
case FLOATVAR: \
ret.setTo(ret.getFloat() OPSIGN sec.getFloat()); \
break; \
} \
return ret; \
} \
template<typename T> \
IexpValStr & operator OPSIGN ## = (const T & sec) \
{ \
*this = *this OPSIGN sec; \
return *this; \
}
#define OPERATOR_DEFINITION_INTEGER(OPSIGN) \
template<typename T> \
IexpValStr operator OPSIGN(const T & sec) const \
{ \
IexpValStr ret = *this; \
switch (type) \
{ \
case INT: \
case INTVAR: \
ret.setTo(ret.getInt() OPSIGN sec); \
break; \
} \
return ret; \
} \
IexpValStr operator OPSIGN(const IexpValStr & sec) const \
{ \
IexpValStr ret = *this; \
switch (type) \
{ \
case INT: \
case INTVAR: \
ret.setTo(ret.getInt() OPSIGN sec.getInt()); \
break; \
} \
return ret; \
} \
template<typename T> \
IexpValStr & operator OPSIGN ## = (const T & sec) \
{ \
*this = *this OPSIGN sec; \
return *this; \
}
OPERATOR_DEFINITION_FULL(+)
OPERATOR_DEFINITION(-)
OPERATOR_DEFINITION(*)
OPERATOR_DEFINITION(/)
OPERATOR_DEFINITION_INTEGER(%)
};
class ERMInterpreter : public CScriptingModule
class ERMInterpreter
{
/*not so*/ public:
// friend class ScriptScanner;
// friend class TriggerIdMatchHelper;
// friend class TriggerIdentifierMatch;
// friend class ConditionDisemboweler;
// friend struct LVL2IexpDisemboweler;
// friend struct VR_SPerformer;
// friend struct ERMExpDispatch;
// friend struct VRPerformer;
std::vector<VERMInterpreter::FileInfo*> files;
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);
static ERM::TTriggerBase & retrieveTrigger(ERM::TLine &line);
VERMInterpreter::Environment * globalEnv;
VERMInterpreter::ERMEnvironment * ermGlobalEnv;
typedef std::map<VERMInterpreter::TriggerType, std::vector<VERMInterpreter::Trigger> > TtriggerListType;
TtriggerListType triggers, postTriggers;
VERMInterpreter::Trigger * curTrigger;
VERMInterpreter::FunctionLocalVars * curFunc;
static const int TRIG_FUNC_NUM = 30000;
VERMInterpreter::FunctionLocalVars funcVars[TRIG_FUNC_NUM + 1]; //+1 because we use [0] as a global set of y-vars
VERMInterpreter::FunctionLocalVars * getFuncVars(int funNum); //0 is a global func-like set
TtriggerListType triggers;
TtriggerListType postTriggers;
std::vector<VERMInterpreter::LinePointer> instructions;
IexpValStr getIexp(const ERM::TIexp & iexp) const;
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;
void executeLine(const VERMInterpreter::LinePointer & lp);
void executeLine(const ERM::TLine &line);
void executeTrigger(VERMInterpreter::Trigger & trig, int funNum = -1, std::vector<int> funParams=std::vector<int>());
static bool isCMDATrigger(const ERM::Tcommand & cmd);
static bool isATrigger(const ERM::TLine & line);
static ERM::EVOtions getExpType(const ERM::TVOption & opt);
IexpValStr getVar(std::string toFollow, boost::optional<int> initVal) const;
std::string processERMString(std::string ermstring);
VERMInterpreter::VOption eval( VERMInterpreter::VOption line, VERMInterpreter::Environment * env = nullptr );
VERMInterpreter::VOptionList evalEach( VERMInterpreter::VermTreeIterator list, VERMInterpreter::Environment * env = nullptr );
ERM::TLine & retrieveLine(const VERMInterpreter::LinePointer & linePtr);
static ERM::TTriggerBase & retrieveTrigger(ERM::TLine & line);
public:
typedef std::map< int, std::vector<int> > TIDPattern;
void executeInstructions(); //called when starting a new game, before most of the map settings are done
void executeTriggerType(VERMInterpreter::TriggerType tt, bool pre, const TIDPattern & identifier, const std::vector<int> &funParams=std::vector<int>()); //use this to run triggers
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 scanForScripts();
vstd::CLoggerBase * logger;
enum EPrintMode{ALL, ERM_ONLY, VERM_ONLY};
void printScripts(EPrintMode mode = ALL);
void scanScripts(); //scans for functions, triggers etc.
ERMInterpreter();
bool checkCondition( ERM::Tcondition cond );
int getRealLine(const VERMInterpreter::LinePointer &lp);
//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 giveInfoCB(CPrivilegedInfoCallback *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;
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 VERMInterpreter::EScriptExecError("Wrong cast attempted, object is not of a desired type!");
}
ERMInterpreter(vstd::CLoggerBase * logger_);
virtual ~ERMInterpreter();
std::string loadScript(const std::string & name, const std::string & source);
};

View File

@ -31,27 +31,21 @@ namespace phoenix = boost::phoenix;
//actually these macros help in dealing with boost::variant
CERMPreprocessor::CERMPreprocessor(const std::string &Fname) : fname(Fname), file(Fname.c_str()), lineNo(0), version(INVALID)
CERMPreprocessor::CERMPreprocessor(const std::string & source)
: sourceStream(source),
lineNo(0),
version(Version::INVALID)
{
if(!file.is_open())
{
logGlobal->error("File %s not found or unable to open", Fname);
return;
}
//check header
std::string header;
getline(header);
if(header == "ZVSE")
version = ERM;
version = Version::ERM;
else if(header == "VERM")
version = VERM;
version = Version::VERM;
else
{
logGlobal->error("File %s has wrong header", fname);
return;
}
}
class ParseErrorException : public std::exception
@ -68,14 +62,11 @@ std::string CERMPreprocessor::retrieveCommandLine()
bool openedString = false;
int openedBraces = 0;
while(file.good())
while(sourceStream.good())
{
std::string line ;
getline(line); //reading line
size_t dash = line.find_first_of('^');
bool inTheMiddle = openedBraces || openedString;
@ -122,11 +113,16 @@ std::string CERMPreprocessor::retrieveCommandLine()
}
else if(c == '^')
openedString = true;
else if(c == ';') // a ';' that is in command line (and not in string) ends the command -> throw away rest
else if(c == ';' && !verm) //do not allow comments inside VExp for now
{
line.erase(i+!verm, line.length() - i - !verm); //leave ';' at the end only at ERM commands
break;
}
// else if(c == ';') // a ';' that is in command line (and not in string) ends the command -> throw away rest
// {
// line.erase(i+!verm, line.length() - i - !verm); //leave ';' at the end only at ERM commands
// break;
// }
}
else if(c == '^')
openedString = false;
@ -148,24 +144,30 @@ std::string CERMPreprocessor::retrieveCommandLine()
}
if(openedBraces || openedString)
{
logGlobal->error("Ill-formed file: %s", fname);
throw ParseErrorException();
}
return "";
}
void CERMPreprocessor::getline(std::string &ret)
{
lineNo++;
std::getline(file, ret);
std::getline(sourceStream, ret);
boost::trim(ret); //get rid of wspace
}
ERMParser::ERMParser(std::string file)
:srcFile(file)
{}
std::vector<LineInfo> ERMParser::parseFile()
ERMParser::ERMParser()
{
ERMgrammar = std::make_shared<ERM::ERM_grammar<std::string::const_iterator>>();
}
ERMParser::~ERMParser() = default;
std::vector<LineInfo> ERMParser::parseFile(CERMPreprocessor & preproc)
{
CERMPreprocessor preproc(srcFile);
std::vector<LineInfo> ret;
try
{
@ -185,6 +187,7 @@ std::vector<LineInfo> ERMParser::parseFile()
catch (ParseErrorException & e)
{
logGlobal->error("Stopped parsing file.");
throw;
}
return ret;
}
@ -243,7 +246,7 @@ BOOST_FUSION_ADAPT_STRUCT(
BOOST_FUSION_ADAPT_STRUCT(
ERM::TNormalBodyOption,
(char, optionCode)
(ERM::TNormalBodyOptionList, params)
(boost::optional<ERM::TNormalBodyOptionList>, params)
)
BOOST_FUSION_ADAPT_STRUCT(
@ -308,10 +311,15 @@ BOOST_FUSION_ADAPT_STRUCT(
(boost::optional<ERM::Tcondition>, condition)
)
//BOOST_FUSION_ADAPT_STRUCT(
// ERM::Tcommand,
// (ERM::Tcommand::Tcmd, cmd)
// (std::string, comment)
// )
BOOST_FUSION_ADAPT_STRUCT(
ERM::Tcommand,
(ERM::Tcommand::Tcmd, cmd)
(std::string, comment)
)
BOOST_FUSION_ADAPT_STRUCT(
@ -346,27 +354,32 @@ namespace ERM
commentLine %= (~qi::char_("!") >> comment | (qi::char_('!') >> (~qi::char_("?!$#[")) >> comment ));
cmdName %= qi::lexeme[qi::repeat(2)[qi::char_]];
arithmeticOp %= iexp >> qi::char_ >> iexp;
//???
//identifier is usually a vector of i-expressions but VR receiver performs arithmetic operations on it
identifier %= (iexp | arithmeticOp) % qi::lit('/');
//identifier %= (iexp | arithmeticOp) % qi::lit('/');
identifier %= iexp % qi::lit('/');
comparison %= iexp >> (*qi::char_("<=>")) >> iexp;
condition %= qi::char_("&|X/") >> (comparison | qi::int_) >> -condition;
condition %= qi::char_("&|/") >> (comparison | qi::int_) >> -condition;
trigger %= cmdName >> -identifier >> -condition > qi::lit(";"); /////
string %= qi::lexeme['^' >> *(qi::char_ - '^') >> '^'];
VRLogic %= qi::char_("&|X") >> iexp;
// VRLogic %= qi::char_("&|X") >> iexp;
VRLogic %= qi::char_("&") >> iexp;
VRarithmetic %= qi::char_("+*:/%-") >> iexp;
semiCompare %= +qi::char_("<=>") >> iexp;
curStr %= iexp >> string;
varConcatString %= varExp >> qi::lit("+") >> string;
bodyOptionItem %= varConcatString | curStr | string | semiCompare | ERMmacroDef | varp | iexp | qi::eps;
bodyOptionItem %= varConcatString | curStr | string | semiCompare | ERMmacroDef | varp | iexp ;
exactBodyOptionList %= (bodyOptionItem % qi::lit("/"));
normalBodyOption = qi::char_("A-Z+") > exactBodyOptionList;
normalBodyOption = qi::char_("A-Z") > -(exactBodyOptionList);
bodyOption %= VRLogic | VRarithmetic | normalBodyOption;
body %= qi::lit(":") >> +(bodyOption) > qi::lit(";");
body %= qi::lit(":") >> *(bodyOption) > qi::lit(";");
instruction %= cmdName >> -identifier >> -condition >> body;
receiver %= cmdName >> -identifier >> -condition >> -body; //receiver without body exists... change needed
receiver %= cmdName >> -identifier >> -condition >> body;
postTrigger %= cmdName >> -identifier >> -condition > qi::lit(";");
command %= (qi::lit("!") >>
@ -375,7 +388,7 @@ namespace ERM
(qi::lit("!") >> receiver) |
(qi::lit("#") >> instruction) |
(qi::lit("$") >> postTrigger)
) >> comment
) //>> comment
);
rline %=
@ -471,7 +484,7 @@ namespace ERM
};
}
ERM::TLine ERMParser::parseLine( const std::string & line, int realLineNo )
ERM::TLine ERMParser::parseLine(const std::string & line, int realLineNo)
{
try
{
@ -479,20 +492,19 @@ ERM::TLine ERMParser::parseLine( const std::string & line, int realLineNo )
}
catch(...)
{
logGlobal->error("Parse error occurred in file %s (line %d): %s", srcFile, realLineNo, line);
//logGlobal->error("Parse error occurred in file %s (line %d): %s", fname, realLineNo, line);
throw;
}
}
ERM::TLine ERMParser::parseLine(const std::string & line)
{
std::string::const_iterator beg = line.begin(),
end = line.end();
auto beg = line.begin();
auto end = line.end();
ERM::ERM_grammar<std::string::const_iterator> ERMgrammar;
ERM::TLine AST;
bool r = qi::phrase_parse(beg, end, ERMgrammar, ascii::space, AST);
bool r = qi::phrase_parse(beg, end, *ERMgrammar.get(), ascii::space, AST);
if(!r || beg != end)
{
logGlobal->error("Parse error: cannot parse: %s", std::string(beg, end));
@ -501,29 +513,14 @@ ERM::TLine ERMParser::parseLine(const std::string & line)
return AST;
}
int ERMParser::countHatsBeforeSemicolon( const std::string & line ) const
{
//CHECK: omit macros? or anything else?
int numOfHats = 0; //num of '^' before ';'
//check for unmatched ^
for (char c : line)
{
if(c == ';')
break;
if(c == '^')
++numOfHats;
}
return numOfHats;
}
void ERMParser::repairEncoding( std::string & str ) const
void ERMParser::repairEncoding(std::string & str) const
{
for(int g=0; g<str.size(); ++g)
if(str[g] & 0x80)
str[g] = '|';
}
void ERMParser::repairEncoding( char * str, int len ) const
void ERMParser::repairEncoding(char * str, int len) const
{
for(int g=0; g<len; ++g)
if(str[g] & 0x80)

View File

@ -8,7 +8,7 @@
*
*/
#pragma once
#include <boost/spirit/home/support/unused.hpp>
namespace spirit = boost::spirit;
@ -16,14 +16,22 @@ namespace spirit = boost::spirit;
class CERMPreprocessor
{
std::string fname;
std::ifstream file;
std::stringstream sourceStream;
int lineNo;
enum {INVALID, ERM, VERM} version;
void getline(std::string &ret);
public:
CERMPreprocessor(const std::string &Fname);
enum class Version : ui8
{
INVALID,
ERM,
VERM
};
Version version;
CERMPreprocessor(const std::string & source);
std::string retrieveCommandLine();
int getCurLineNo() const
{
@ -34,6 +42,9 @@ public:
//various classes that represent ERM/VERM AST
namespace ERM
{
using ValType = int; //todo: set to int64_t
using IType = int; //todo: set to int32_t
struct TStringConstant
{
std::string str;
@ -105,25 +116,25 @@ namespace ERM
TStringConstant string;
};
struct TVarConcatString
struct TVarConcatString
{
TVarExp var;
TStringConstant string;
};
typedef boost::variant<TVarConcatString, TStringConstant, TCurriedString, TSemiCompare, TMacroDef, TIexp, TVarpExp, boost::spirit::unused_type> TBodyOptionItem;
typedef boost::variant<TVarConcatString, TStringConstant, TCurriedString, TSemiCompare, TMacroDef, TIexp, TVarpExp> TBodyOptionItem;
typedef std::vector<TBodyOptionItem> TNormalBodyOptionList;
struct TNormalBodyOption
{
char optionCode;
TNormalBodyOptionList params;
boost::optional<TNormalBodyOptionList> params;
};
typedef boost::variant<TVRLogic, TVRArithmetic, TNormalBodyOption> TBodyOption;
typedef boost::variant<TIexp, TArithmeticOp > TIdentifierInternal;
typedef std::vector< TIdentifierInternal > Tidentifier;
// typedef boost::variant<TIexp, TArithmeticOp > TIdentifierInternal;
typedef std::vector< TIexp > Tidentifier;
struct TComparison
{
@ -160,7 +171,7 @@ namespace ERM
struct Ttrigger : TTriggerBase
{
Ttrigger()
Ttrigger()
{
pre = true;
}
@ -209,7 +220,7 @@ namespace ERM
>
Tcmd;
Tcmd cmd;
std::string comment;
//std::string comment;
};
//vector expression
@ -239,6 +250,8 @@ namespace ERM
//script line
typedef boost::variant<TVExp, TERMline> TLine;
template <typename T> class ERM_grammar;
}
struct LineInfo
@ -249,17 +262,16 @@ struct LineInfo
class ERMParser
{
public:
std::shared_ptr<ERM::ERM_grammar<std::string::const_iterator>> ERMgrammar;
ERMParser();
virtual ~ERMParser();
std::vector<LineInfo> parseFile(CERMPreprocessor & preproc);
private:
std::string srcFile;
void repairEncoding(char * str, int len) const; //removes nonstandard ascii characters from string
void repairEncoding(std::string & str) const; //removes nonstandard ascii characters from string
enum ELineType{COMMAND_FULL, COMMENT, UNFINISHED, END_OF};
int countHatsBeforeSemicolon(const std::string & line) const;
ERM::TLine parseLine(const std::string & line, int realLineNo);
public:
ERMParser(std::string file);
std::vector<LineInfo> parseFile();
static ERM::TLine parseLine(const std::string & line);
ERM::TLine parseLine(const std::string & line);
};

View File

@ -12,10 +12,6 @@
#include "ERMInterpreter.h"
IGameEventRealizer *acb;
CPrivilegedInfoCallback *icb;
#ifdef __GNUC__
#define strcpy_s(a, b, c) strncpy(a, c, b)
#endif
@ -27,7 +23,46 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
}
extern "C" DLL_EXPORT void GetNewModule(std::shared_ptr<CScriptingModule> &out)
extern "C" DLL_EXPORT void GetNewModule(std::shared_ptr<scripting::Module> &out)
{
out = std::make_shared<ERMInterpreter>();
out = std::make_shared<ERMScriptModule>();
}
ERMScriptModule::ERMScriptModule()
{
}
std::string ERMScriptModule::compile(const std::string & name, const std::string & source, vstd::CLoggerBase * logger) const
{
std::shared_ptr<ERMInterpreter> interp = std::make_shared<ERMInterpreter>(logger);
try
{
return interp->loadScript(name, source);
}
catch(const std::exception & ex)
{
logger->error(ex.what());
}
catch(const std::string & ex)
{
logger->error(ex);
}
catch(...)
{
logger->error("Sorry, caught unknown exception type. No more info available.");
}
return "";
}
std::shared_ptr<scripting::ContextBase> ERMScriptModule::createContextFor(const scripting::Script * source, const Environment * env) const
{
throw std::runtime_error("ERM context creation is not possible");
}
void ERMScriptModule::registerSpellEffect(spells::effects::Registry * registry, const scripting::Script * source) const
{
throw std::runtime_error("ERM spell effect registration is not possible");
}

View File

@ -11,5 +11,15 @@
#include "../../lib/CScriptingModule.h"
extern IGameEventRealizer *acb;
extern CPrivilegedInfoCallback *icb;
class ERMScriptModule : public scripting::Module
{
public:
ERMScriptModule();
std::string compile(const std::string & name, const std::string & source, vstd::CLoggerBase * logger) const override;
std::shared_ptr<scripting::ContextBase> createContextFor(const scripting::Script * source, const Environment * env) const override;
void registerSpellEffect(spells::effects::Registry * registry, const scripting::Script * source) const override;
};

View File

@ -0,0 +1,57 @@
include_directories(${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} ${CMAKE_HOME_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/include ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib)
set(lib_SRCS
StdInc.cpp
LuaReference.cpp
LuaScriptModule.cpp
LuaScriptingContext.cpp
LuaSpellEffect.cpp
LuaStack.cpp
api/battle/UnitProxy.cpp
api/events/BattleEvents.cpp
api/events/EventBusProxy.cpp
api/events/GenericEvents.cpp
api/events/SubscriptionRegistryProxy.cpp
api/netpacks/BattleLogMessage.cpp
api/netpacks/BattleStackMoved.cpp
api/netpacks/BattleUnitsChanged.cpp
api/netpacks/EntitiesChanged.cpp
api/netpacks/InfoWindow.cpp
api/netpacks/SetResources.cpp
api/Artifact.cpp
api/BattleCb.cpp
api/BonusSystem.cpp
api/Creature.cpp
api/Faction.cpp
api/GameCb.cpp
api/HeroClass.cpp
api/HeroInstance.cpp
api/HeroType.cpp
api/Registry.cpp
api/ServerCb.cpp
api/Services.cpp
api/Skill.cpp
api/Spell.cpp
api/StackInstance.cpp
)
add_library(vcmiLua SHARED ${lib_SRCS})
target_link_libraries(vcmiLua ${Boost_LIBRARIES} ${LUA_LIBRARY} vcmi)
vcmi_set_output_dir(vcmiLua "scripting")
set_target_properties(vcmiLua PROPERTIES ${PCH_PROPERTIES})
cotire(vcmiLua)
install(TARGETS vcmiLua DESTINATION ${SCRIPTING_LIB_DIR})
#manually copy lua dll from vcpkg folder to build directory on windows since vcpkg deps copy feature has flaws, using hardcoded paths based on vcmi windows deps package 1.1 from github
if(MSVC)
if(EXISTS ${LUA_INCLUDE_DIR}/../../bin/lua51.dll)
file(COPY ${LUA_INCLUDE_DIR}/../../bin/lua51.dll DESTINATION ${CMAKE_BINARY_DIR}/bin)
endif()
endif()

171
scripting/lua/Lua.cbp Normal file
View File

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="Lua" />
<Option compiler="gcc" />
<Build>
<Target title="Debug-win32">
<Option output="../vcmiLua" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/x32/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-Og" />
<Add option="-Wall" />
<Add option="-g" />
<Add option="-DBUILD_DLL" />
</Compiler>
<Linker>
<Add option="-lboost_program_options$(#boost.libsuffix32)" />
<Add option="-lboost_filesystem$(#boost.libsuffix32)" />
<Add option="-lboost_system$(#boost.libsuffix32)" />
<Add option="-lboost_thread$(#boost.libsuffix32)" />
<Add option="-lboost_chrono$(#boost.libsuffix32)" />
<Add option="-lVCMI_lib" />
<Add directory="$(#boost.lib32)" />
</Linker>
</Target>
<Target title="Release-win32">
<Option output="../vcmiLua" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/x32/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
<Add option="-Wall" />
<Add option="-DBUILD_DLL" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-lboost_program_options$(#boost.libsuffix32)" />
<Add option="-lboost_filesystem$(#boost.libsuffix32)" />
<Add option="-lboost_system$(#boost.libsuffix32)" />
<Add option="-lboost_thread$(#boost.libsuffix32)" />
<Add option="-lboost_chrono$(#boost.libsuffix32)" />
<Add option="-lVCMI_lib" />
<Add directory="$(#boost.lib32)" />
</Linker>
</Target>
<Target title="Debug-win64">
<Option output="../vcmiLua" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/x64/" />
<Option type="3" />
<Option compiler="gnu_gcc_compiler_x64" />
<Compiler>
<Add option="-Og" />
<Add option="-g" />
<Add option="-DBUILD_DLL" />
</Compiler>
<Linker>
<Add option="-lboost_program_options$(#boost.libsuffix64)" />
<Add option="-lboost_filesystem$(#boost.libsuffix64)" />
<Add option="-lboost_system$(#boost.libsuffix64)" />
<Add option="-lboost_thread$(#boost.libsuffix64)" />
<Add option="-lboost_chrono$(#boost.libsuffix64)" />
<Add option="-lVCMI_lib" />
<Add directory="$(#boost.lib64)" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-std=gnu++11" />
<Add option="-fexceptions" />
<Add option="-Wpointer-arith" />
<Add option="-Wno-switch" />
<Add option="-Wno-sign-compare" />
<Add option="-Wno-unused-parameter" />
<Add option="-Wno-overloaded-virtual" />
<Add option="-DBOOST_ALL_DYN_LINK" />
<Add option="-DBOOST_SYSTEM_NO_DEPRECATED" />
<Add option="-DBOOST_UUID_RANDOM_PROVIDER_FORCE_WINCRYPT" />
<Add option="-D_WIN32_WINNT=0x0600" />
<Add option="-D_WIN32" />
<Add directory="$(#boost.include)" />
<Add directory="$(#lua.include)" />
<Add directory="../../include" />
</Compiler>
<Linker>
<Add library="../../lua51.dll" />
<Add directory=".." />
<Add directory="../.." />
</Linker>
<Unit filename="CMakeLists.txt" />
<Unit filename="LuaCallWrapper.h" />
<Unit filename="LuaFunctor.h" />
<Unit filename="LuaReference.cpp" />
<Unit filename="LuaReference.h" />
<Unit filename="LuaScriptModule.cpp" />
<Unit filename="LuaScriptModule.h" />
<Unit filename="LuaScriptingContext.cpp" />
<Unit filename="LuaScriptingContext.h" />
<Unit filename="LuaSpellEffect.cpp" />
<Unit filename="LuaSpellEffect.h" />
<Unit filename="LuaStack.cpp" />
<Unit filename="LuaStack.h" />
<Unit filename="LuaWrapper.h" />
<Unit filename="StdInc.h">
<Option weight="0" />
</Unit>
<Unit filename="api/Artifact.cpp" />
<Unit filename="api/Artifact.h" />
<Unit filename="api/BattleCb.cpp" />
<Unit filename="api/BattleCb.h" />
<Unit filename="api/BonusSystem.cpp" />
<Unit filename="api/BonusSystem.h" />
<Unit filename="api/Creature.cpp" />
<Unit filename="api/Creature.h" />
<Unit filename="api/Faction.cpp" />
<Unit filename="api/Faction.h" />
<Unit filename="api/GameCb.cpp" />
<Unit filename="api/GameCb.h" />
<Unit filename="api/HeroClass.cpp" />
<Unit filename="api/HeroClass.h" />
<Unit filename="api/HeroInstance.cpp" />
<Unit filename="api/HeroInstance.h" />
<Unit filename="api/HeroType.cpp" />
<Unit filename="api/HeroType.h" />
<Unit filename="api/ObjectInstance.cpp" />
<Unit filename="api/ObjectInstance.h" />
<Unit filename="api/Player.cpp" />
<Unit filename="api/Player.h" />
<Unit filename="api/Registry.cpp" />
<Unit filename="api/Registry.h" />
<Unit filename="api/ServerCb.cpp" />
<Unit filename="api/ServerCb.h" />
<Unit filename="api/Services.cpp" />
<Unit filename="api/Services.h" />
<Unit filename="api/Skill.cpp" />
<Unit filename="api/Skill.h" />
<Unit filename="api/Spell.cpp" />
<Unit filename="api/Spell.h" />
<Unit filename="api/StackInstance.cpp" />
<Unit filename="api/StackInstance.h" />
<Unit filename="api/battle/UnitProxy.cpp" />
<Unit filename="api/battle/UnitProxy.h" />
<Unit filename="api/events/AdventureEvents.cpp" />
<Unit filename="api/events/AdventureEvents.h" />
<Unit filename="api/events/BattleEvents.cpp" />
<Unit filename="api/events/BattleEvents.h" />
<Unit filename="api/events/EventBusProxy.cpp" />
<Unit filename="api/events/EventBusProxy.h" />
<Unit filename="api/events/GenericEvents.cpp" />
<Unit filename="api/events/GenericEvents.h" />
<Unit filename="api/events/SubscriptionRegistryProxy.cpp" />
<Unit filename="api/events/SubscriptionRegistryProxy.h" />
<Unit filename="api/netpacks/BattleLogMessage.cpp" />
<Unit filename="api/netpacks/BattleLogMessage.h" />
<Unit filename="api/netpacks/BattleStackMoved.cpp" />
<Unit filename="api/netpacks/BattleStackMoved.h" />
<Unit filename="api/netpacks/BattleUnitsChanged.cpp" />
<Unit filename="api/netpacks/BattleUnitsChanged.h" />
<Unit filename="api/netpacks/EntitiesChanged.cpp" />
<Unit filename="api/netpacks/EntitiesChanged.h" />
<Unit filename="api/netpacks/InfoWindow.cpp" />
<Unit filename="api/netpacks/InfoWindow.h" />
<Unit filename="api/netpacks/PackForClient.h" />
<Unit filename="api/netpacks/SetResources.cpp" />
<Unit filename="api/netpacks/SetResources.h" />
<Extensions />
</Project>
</CodeBlocks_project_file>

View File

@ -0,0 +1,319 @@
/*
* LuaCallWrapper.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "api/Registry.h"
#include "LuaStack.h"
#include "LuaFunctor.h"
namespace scripting
{
namespace detail
{
}
//TODO: this should be the only one wrapper type
//
template <typename U, typename M, M m>
class LuaMethodWrapper
{
};
template <typename U, typename T, typename R, R(T:: * method)()const>
class LuaMethodWrapper <U, R(T:: *)()const, method>
{
public:
static int invoke(lua_State * L)
{
LuaStack S(L);
const U * obj = nullptr;
if(!S.tryGet(1,obj))
return S.retVoid();
static auto functor = std::mem_fn(method);
S.clear();
S.push(functor(obj));
return S.retPushed();
}
};
template <typename U, typename T, void(T:: * method)()const>
class LuaMethodWrapper <U, void(T:: *)()const, method>
{
public:
static int invoke(lua_State * L)
{
LuaStack S(L);
const U * obj = nullptr;
if(!S.tryGet(1,obj))
return S.retVoid();
static auto functor = std::mem_fn(method);
S.clear();
functor(obj);
return 0;
}
};
template <typename U, typename T, typename R, typename P1, R(T:: * method)(P1)const>
class LuaMethodWrapper <U, R(T:: *)(P1)const, method>
{
public:
static int invoke(lua_State * L)
{
LuaStack S(L);
const U * obj = nullptr;
if(!S.tryGet(1,obj))
return S.retVoid();
P1 p1;
if(!S.tryGet(2, p1))
return S.retVoid();
static auto functor = std::mem_fn(method);
S.clear();
S.push(functor(obj, p1));
return S.retPushed();
}
};
template <typename U, typename T, typename P1, void(T:: * method)(P1)const>
class LuaMethodWrapper <U, void(T:: *)(P1)const, method>
{
public:
static int invoke(lua_State * L)
{
LuaStack S(L);
const U * obj = nullptr;
if(!S.tryGet(1,obj))
return S.retVoid();
P1 p1;
if(!S.tryGet(2, p1))
return S.retVoid();
static auto functor = std::mem_fn(method);
S.clear();
functor(obj, p1);
return 0;
}
};
template <typename U, typename T, typename R, typename P1, typename P2, R(T:: * method)(P1, P2)const>
class LuaMethodWrapper <U, R(T:: *)(P1, P2)const, method>
{
public:
static int invoke(lua_State * L)
{
LuaStack S(L);
const U * obj = nullptr;
if(!S.tryGet(1, obj))
return S.retVoid();
P1 p1;
if(!S.tryGet(2, p1))
return S.retVoid();
P2 p2;
if(!S.tryGet(3, p2))
return S.retVoid();
static auto functor = std::mem_fn(method);
S.clear();
S.push(functor(obj, p1, p2));
return S.retPushed();
}
};
template <typename U, typename T, typename P1, typename P2, void(T:: * method)(P1, P2)const>
class LuaMethodWrapper <U, void(T:: *)(P1, P2)const, method>
{
public:
static int invoke(lua_State * L)
{
LuaStack S(L);
const U * obj = nullptr;
if(!S.tryGet(1, obj))
return S.retVoid();
P1 p1;
if(!S.tryGet(2, p1))
return S.retVoid();
P2 p2;
if(!S.tryGet(3, p2))
return S.retVoid();
static auto functor = std::mem_fn(method);
S.clear();
functor(obj, p1, p2);
return 0;
}
};
//deprecated, should use LuaMethodWrapper instead, once implemented
template <typename T>
class LuaCallWrapper
{
public:
using Wrapped = typename std::remove_const<T>::type;
static std::function<int(lua_State *, T *)> createFunctor(void (Wrapped::* method)())
{
auto functor = std::mem_fn(method);
auto ret = [=](lua_State * L, T * object)->int
{
LuaStack S(L);
functor(object);
return S.retVoid();
};
return ret;
}
static std::function<int(lua_State *, T *)> createFunctor(void (Wrapped::* method)() const)
{
auto functor = std::mem_fn(method);
auto ret = [=](lua_State * L, T * object)->int
{
LuaStack S(L);
functor(object);
return S.retVoid();
};
return ret;
}
template <typename R>
static std::function<int(lua_State *, T *)> createFunctor(R (Wrapped::* method)())
{
auto functor = std::mem_fn(method);
auto ret = [=](lua_State * L, T * object)->int
{
LuaStack S(L);
S.clear();
S.push(functor(object));
return S.retPushed();
};
return ret;
}
template <typename R>
static std::function<int(lua_State *, T *)> createFunctor(R (Wrapped::* method)() const)
{
auto functor = std::mem_fn(method);
auto ret = [=](lua_State * L, T * object)->int
{
LuaStack S(L);
S.clear();
S.push(functor(object));
return S.retPushed();
};
return ret;
}
template <typename P1>
static std::function<int(lua_State *, T *)> createFunctor(void (Wrapped::* method)(P1))
{
auto functor = std::mem_fn(method);
auto ret = [=](lua_State * L, T * object)->int
{
LuaStack S(L);
P1 p1;
if(S.tryGet(1, p1))
{
functor(object, p1);
}
return S.retVoid();
};
return ret;
}
template <typename P1>
static std::function<int(lua_State *, T *)> createFunctor(void (Wrapped::* method)(P1) const)
{
auto functor = std::mem_fn(method);
auto ret = [=](lua_State * L, T * object)->int
{
LuaStack S(L);
P1 p1;
if(S.tryGet(1, p1))
{
functor(object, p1);
}
return S.retVoid();
};
return ret;
}
template <typename R, typename P1>
static std::function<int(lua_State *, T *)> createFunctor(R (Wrapped::* method)(P1))
{
auto functor = std::mem_fn(method);
auto ret = [=](lua_State * L, T * object)->int
{
LuaStack S(L);
P1 p1;
if(S.tryGet(1, p1))
{
S.push(functor(object, p1));
return 1;
}
return S.retVoid();
};
return ret;
}
template <typename R, typename P1>
static std::function<int(lua_State *, T *)> createFunctor(R (Wrapped::* method)(P1) const)
{
auto functor = std::mem_fn(method);
auto ret = [=](lua_State * L, T * object)->int
{
LuaStack S(L);
P1 p1;
if(S.tryGet(1, p1))
{
S.push(functor(object, p1));
return 1;
}
return S.retVoid();
};
return ret;
}
};
}

View File

@ -0,0 +1,23 @@
/*
* LuaFunctor.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
namespace scripting
{
template <typename T>
class LuaFunctor
{
public:
virtual int operator() (lua_State *, T *) = 0;
};
}

View File

@ -0,0 +1,44 @@
/*
* LuaReference.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "LuaReference.h"
namespace scripting
{
LuaReference::LuaReference(lua_State * L)
: l(L),
doCleanup(true)
{
key = luaL_ref(l, LUA_REGISTRYINDEX);
}
LuaReference::LuaReference(LuaReference && other)
: l(other.l),
key(other.key),
doCleanup(false)
{
std::swap(doCleanup, other.doCleanup);
}
LuaReference::~LuaReference()
{
if(doCleanup)
luaL_unref(l, LUA_REGISTRYINDEX, key);
}
void LuaReference::push()
{
lua_rawgeti(l, LUA_REGISTRYINDEX, key);
}
}

View File

@ -0,0 +1,33 @@
/*
* LuaReference.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
namespace scripting
{
class LuaReference : public boost::noncopyable
{
public:
//pop from the top of stack
LuaReference(lua_State * L);
LuaReference(LuaReference && other);
~LuaReference();
void push();
private:
bool doCleanup;
int key;
lua_State * l;
};
}

View File

@ -0,0 +1,56 @@
/*
* LuaScriptModule.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "LuaScriptModule.h"
#include "LuaScriptingContext.h"
#include "LuaSpellEffect.h"
#ifdef __GNUC__
#define strcpy_s(a, b, c) strncpy(a, c, b)
#endif
const char *g_cszAiName = "Lua interpreter";
extern "C" DLL_EXPORT void GetAiName(char * name)
{
strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
}
extern "C" DLL_EXPORT void GetNewModule(std::shared_ptr<scripting::Module> & out)
{
out = std::make_shared<scripting::LuaScriptModule>();
}
namespace scripting
{
LuaScriptModule::LuaScriptModule() = default;
LuaScriptModule::~LuaScriptModule() = default;
std::string LuaScriptModule::compile(const std::string & name, const std::string & source, vstd::CLoggerBase * logger) const
{
//TODO: pre-compile to byte code
//LuaJit bytecode in architecture agnostic, but is not backward compatible and completely incompatible with Lua
return source;
}
std::shared_ptr<ContextBase> LuaScriptModule::createContextFor(const Script * source, const Environment * env) const
{
return std::make_shared<LuaContext>(source, env);
}
void LuaScriptModule::registerSpellEffect(spells::effects::Registry * registry, const Script * source) const
{
registry->add(source->getName(), std::make_shared<spells::effects::LuaSpellEffectFactory>(source));
}
}

View File

@ -0,0 +1,33 @@
/*
* LuaScriptModule.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "../../lib/CScriptingModule.h"
namespace scripting
{
class LuaScriptModule : public Module
{
public:
LuaScriptModule();
virtual ~LuaScriptModule();
std::string compile(const std::string & name, const std::string & source, vstd::CLoggerBase * logger) const override;
std::shared_ptr<ContextBase> createContextFor(const Script * source, const Environment * env) const override;
void registerSpellEffect(spells::effects::Registry * registry, const Script * source) const override;
private:
};
}

View File

@ -0,0 +1,607 @@
/*
* LuaScriptingContext.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "LuaScriptingContext.h"
#include <vstd/StringUtils.h>
#include <vcmi/events/EventBus.h>
#include <vcmi/ServerCallback.h>
#include "LuaStack.h"
#include "api/Registry.h"
#include "../../lib/JsonNode.h"
#include "../../lib/NetPacks.h"
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/battle/IBattleInfoCallback.h"
#include "../../lib/CGameInfoCallback.h"
namespace scripting
{
const std::string LuaContext::STATE_FIELD = "DATA";
LuaContext::LuaContext(const Script * source, const Environment * env_)
: ContextBase(env_->logger()),
script(source),
env(env_)
{
L = luaL_newstate();
static const std::vector<luaL_Reg> STD_LIBS =
{
{"", luaopen_base},
{LUA_TABLIBNAME, luaopen_table},
{LUA_STRLIBNAME, luaopen_string},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_BITLIBNAME, luaopen_bit}
};
for(const luaL_Reg & lib : STD_LIBS)
{
lua_pushcfunction(L, lib.func);
lua_pushstring(L, lib.name);
lua_call(L, 1, 0);
}
popAll();
cleanupGlobals();
popAll();
lua_newtable(L);
modules = std::make_shared<LuaReference>(L);
popAll();
registerCore();
popAll();
LuaStack S(L);
S.push(env->game());
lua_setglobal(L, "GAME");
S.push(env->battle());
lua_setglobal(L, "BATTLE");
S.push(env->eventBus());
lua_setglobal(L, "EVENT_BUS");
S.push(env->services());
lua_setglobal(L, "SERVICES");
popAll();
}
LuaContext::~LuaContext()
{
modules.reset();
scriptClosure.reset();
lua_close(L);
}
void LuaContext::cleanupGlobals()
{
LuaStack S(L);
S.clear();
S.pushNil();
lua_setglobal(L, "collectgarbage");
S.pushNil();
lua_setglobal(L, "dofile");
S.pushNil();
lua_setglobal(L, "load");
S.pushNil();
lua_setglobal(L, "loadfile");
S.pushNil();
lua_setglobal(L, "loadstring");
S.pushNil();
lua_setglobal(L, "print");
S.clear();
lua_getglobal(L, LUA_STRLIBNAME);
S.push("dump");
S.pushNil();
lua_rawset(L, -3);
S.clear();
lua_getglobal(L, LUA_MATHLIBNAME);
S.push("random");
S.pushNil();
lua_rawset(L, -3);
S.push("randomseed");
S.pushNil();
lua_rawset(L, -3);
S.clear();
}
void LuaContext::run(ServerCallback * server, const JsonNode & initialState)
{
{
LuaStack S(L);
S.push(server);
lua_setglobal(L, "SERVER");
S.clear();
}
run(initialState);
// {
// LuaStack S(L);
// S.pushNil();
// lua_setglobal(L, "SERVER");
// S.clear();
// }
}
void LuaContext::run(const JsonNode & initialState)
{
setGlobal(STATE_FIELD, initialState);
int ret = luaL_loadbuffer(L, script->getSource().c_str(), script->getSource().size(), script->getName().c_str());
if(ret)
{
logger->error("Script '%s' failed to load, error: %s", script->getName(), toStringRaw(-1));
popAll();
return;
}
scriptClosure = std::make_shared<LuaReference>(L);
popAll();
scriptClosure->push();
ret = lua_pcall(L, 0, 0, 0);
if(ret)
{
logger->error("Script '%s' failed to run, error: '%s'", script->getName(), toStringRaw(-1));
popAll();
}
}
int LuaContext::errorRetVoid(const std::string & message)
{
logger->error(message);
popAll();
return 0;
}
JsonNode LuaContext::callGlobal(const std::string & name, const JsonNode & parameters)
{
LuaStack S(L);
lua_getglobal(L, name.c_str());
if(!S.isFunction(-1))
{
boost::format fmt("%s is not a function");
fmt % name;
logger->error(fmt.str());
S.clear();
return JsonNode();
}
int argc = parameters.Vector().size();
for(int idx = 0; idx < argc; idx++)
S.push(parameters.Vector()[idx]);
if(lua_pcall(L, argc, 1, 0))
{
std::string error = lua_tostring(L, -1);
boost::format fmt("Lua function %s failed with message: %s");
fmt % name % error;
logger->error(fmt.str());
S.clear();
return JsonNode();
}
JsonNode ret;
pop(ret);
S.balance();
return ret;
}
JsonNode LuaContext::callGlobal(ServerCallback * cb, const std::string & name, const JsonNode & parameters)
{
LuaStack S(L);
S.push(cb);
lua_setglobal(L, "SERVER");
auto ret = callGlobal(name, parameters);
S.pushNil();
lua_setglobal(L, "SERVER");
return ret;
}
void LuaContext::getGlobal(const std::string & name, int & value)
{
LuaStack S(L);
lua_getglobal(L, name.c_str());
lua_Integer temp;
if(S.tryGetInteger(-1, temp))
value = static_cast<int>(temp);
else
value = 0;
S.balance();
}
void LuaContext::getGlobal(const std::string & name, std::string & value)
{
LuaStack S(L);
lua_getglobal(L, name.c_str());
if(!S.tryGet(-1, value))
value.clear();
S.balance();
}
void LuaContext::getGlobal(const std::string & name, double & value)
{
LuaStack S(L);
lua_getglobal(L, name.c_str());
if(!S.tryGet(-1, value))
value = 0.0;
S.balance();
}
void LuaContext::getGlobal(const std::string & name, JsonNode & value)
{
LuaStack S(L);
lua_getglobal(L, name.c_str());
pop(value);
S.balance();
}
void LuaContext::setGlobal(const std::string & name, int value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
lua_setglobal(L, name.c_str());
}
void LuaContext::setGlobal(const std::string & name, const std::string & value)
{
lua_pushlstring(L, value.c_str(), value.size());
lua_setglobal(L, name.c_str());
}
void LuaContext::setGlobal(const std::string & name, double value)
{
lua_pushnumber(L, value);
lua_setglobal(L, name.c_str());
}
void LuaContext::setGlobal(const std::string & name, const JsonNode & value)
{
LuaStack S(L);
S.push(value);
lua_setglobal(L, name.c_str());
S.balance();
}
JsonNode LuaContext::saveState()
{
JsonNode data;
getGlobal(STATE_FIELD, data);
return std::move(data);
}
void LuaContext::pop(JsonNode & value)
{
auto type = lua_type(L, -1);
switch(type)
{
case LUA_TNUMBER:
value.Float() = lua_tonumber(L, -1);
break;
case LUA_TBOOLEAN:
value.Bool() = (lua_toboolean(L, -1) != 0);
break;
case LUA_TSTRING:
value.String() = toStringRaw(-1);
break;
case LUA_TTABLE:
{
JsonNode asVector(JsonNode::JsonType::DATA_VECTOR);
JsonNode asStruct(JsonNode::JsonType::DATA_STRUCT);
lua_pushnil(L); /* first key */
while(lua_next(L, -2) != 0)
{
/* 'key' (at index -2) and 'value' (at index -1) */
JsonNode fieldValue;
pop(fieldValue);
if(lua_type(L, -1) == LUA_TNUMBER)
{
auto key = lua_tointeger(L, -1);
if(key > 0)
{
if(asVector.Vector().size() < key)
asVector.Vector().resize(key);
--key;
asVector.Vector().at(key) = fieldValue;
}
}
else if(lua_isstring(L, -1))
{
auto key = toStringRaw(-1);
asStruct[key] = fieldValue;
}
}
if(!asVector.Vector().empty())
{
std::swap(value, asVector);
}
else
{
std::swap(value, asStruct);
}
}
break;
default:
value.clear();
break;
}
lua_pop(L, 1);
}
void LuaContext::push(const std::string & value)
{
lua_pushlstring(L, value.c_str(), value.size());
}
void LuaContext::push(lua_CFunction f, void * opaque)
{
lua_pushlightuserdata(L, opaque);
lua_pushcclosure(L, f, 1);
}
void LuaContext::popAll()
{
lua_settop(L, 0);
}
std::string LuaContext::toStringRaw(int index)
{
size_t len = 0;
auto raw = lua_tolstring(L, index, &len);
return std::string(raw, len);
}
void LuaContext::registerCore()
{
push(&LuaContext::require, this);
lua_setglobal(L, "require");
push(&LuaContext::logError, this);
lua_setglobal(L, "logError");
popAll();//just in case
for(auto & registar : api::Registry::get()->getCoreData())
{
registar.second->pushMetatable(L); //table
modules->push(); //table modules
push(registar.first); //table modules name
lua_pushvalue(L, -3); //table modules name table
lua_rawset(L, -3);
popAll();
}
}
int LuaContext::require(lua_State * L)
{
LuaContext * self = static_cast<LuaContext *>(lua_touserdata(L, lua_upvalueindex(1)));
if(!self)
{
lua_pushstring(L, "internal error");
lua_error(L);
return 0;
}
return self->loadModule();
}
int LuaContext::loadModule()
{
int argc = lua_gettop(L);
if(argc < 1)
return errorRetVoid("Module name required");
//if module is loaded already, assume that module name is valid
modules->push();
lua_pushvalue(L, -2);
lua_rawget(L, -2);
if(lua_istable(L, -1))
{
lua_replace(L, 1);
lua_settop(L, 1);
return 1;
}
//continue with more checks
if(!lua_isstring(L, 1))
return errorRetVoid("Module name must be string");
std::string resourceName = toStringRaw(1);
if(resourceName.empty())
return errorRetVoid("Module name is empty");
auto temp = vstd::split(resourceName, ":");
std::string scope;
std::string modulePath;
if(temp.size() <= 1)
{
modulePath = temp.at(0);
}
else
{
scope = temp.at(0);
modulePath = temp.at(1);
}
if(scope.empty())
{
auto registar = api::Registry::get()->find(modulePath);
if(!registar)
{
return errorRetVoid("Module not found: "+modulePath);
}
registar->pushMetatable(L);
}
else if(scope == "core")
{
// boost::algorithm::replace_all(modulePath, boost::is_any_of("\\/ "), "");
boost::algorithm::replace_all(modulePath, ".", "/");
auto loader = CResourceHandler::get("core");
modulePath = "scripts/lib/" + modulePath;
ResourceID id(modulePath, EResType::LUA);
if(!loader->existsResource(id))
return errorRetVoid("Module not found: "+modulePath);
auto rawData = loader->load(id)->readAll();
auto sourceText = std::string((char *)rawData.first.get(), rawData.second);
int ret = luaL_loadbuffer(L, sourceText.c_str(), sourceText.size(), modulePath.c_str());
if(ret)
return errorRetVoid(toStringRaw(-1));
ret = lua_pcall(L, 0, 1, 0);
if(ret)
{
logger->error("Module '%s' failed to run, error: %s", modulePath, toStringRaw(-1));
popAll();
return 0;
}
}
else
{
//todo: also allow loading scripts from same scope
return errorRetVoid("No access to scope "+scope);
}
modules->push(); //name table modules
lua_pushvalue(L, 1);//name table modules name
if(!lua_isstring(L, -1))
return errorRetVoid("Module name corrupted");
lua_pushvalue(L, -3);//name table modules name table
lua_rawset(L, -3);//name table modules
lua_pop(L, 1);//name table
lua_replace(L, 1);//table table
lua_settop(L, 1);//table
return 1;
}
int LuaContext::print(lua_State * L)
{
//TODO:
lua_settop(L, 0);
return 0;
}
int LuaContext::printImpl()
{
//TODO:
return 0;
}
int LuaContext::logError(lua_State * L)
{
LuaContext * self = static_cast<LuaContext *>(lua_touserdata(L, lua_upvalueindex(1)));
if(!self)
{
lua_pushstring(L, "internal error");
lua_error(L);
return 0;
}
return self->logErrorImpl();
}
int LuaContext::logErrorImpl()
{
LuaStack S(L);
std::string message;
if(S.tryGet(1, message))
logger->error(message);
return S.retVoid();
}
}

View File

@ -0,0 +1,90 @@
/*
* LuaScriptingContext.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "LuaWrapper.h"
#include "LuaReference.h"
#include "../../lib/ScriptHandler.h"
#include "../../lib/CScriptingModule.h"
namespace scripting
{
class LuaContext : public ContextBase
{
public:
static const std::string STATE_FIELD;
LuaContext(const Script * source, const Environment * env_);
virtual ~LuaContext();
void run(const JsonNode & initialState) override;
void run(ServerCallback * server, const JsonNode & initialState) override;
//log error and return nil from LuaCFunction
int errorRetVoid(const std::string & message);
JsonNode callGlobal(const std::string & name, const JsonNode & parameters) override;
JsonNode callGlobal(ServerCallback * cb, const std::string & name, const JsonNode & parameters) override;
void getGlobal(const std::string & name, int & value) override;
void getGlobal(const std::string & name, std::string & value) override;
void getGlobal(const std::string & name, double & value) override;
void getGlobal(const std::string & name, JsonNode & value) override;
void setGlobal(const std::string & name, int value) override;
void setGlobal(const std::string & name, const std::string & value) override;
void setGlobal(const std::string & name, double value) override;
void setGlobal(const std::string & name, const JsonNode & value) override;
JsonNode saveState() override;
void pop(JsonNode & value);
void popAll();
void push(const std::string & value);
void push(lua_CFunction f, void * opaque);
std::string toStringRaw(int index);
private:
lua_State * L;
const Script * script;
const Environment * env;
std::shared_ptr<LuaReference> modules;
std::shared_ptr<LuaReference> scriptClosure;
void cleanupGlobals();
void registerCore();
//require global function
static int require(lua_State * L);
//print global function
static int print(lua_State * L);
static int logError(lua_State * L);
//require function implementation
int loadModule();
int printImpl();
int logErrorImpl();
};
}

View File

@ -0,0 +1,186 @@
/*
* LuaSpellEffect.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "LuaSpellEffect.h"
#include <vcmi/scripting/Service.h>
#include "../../lib/spells/effects/Registry.h"
#include "../../lib/spells/ISpellMechanics.h"
#include "../../lib/battle/Unit.h"
#include "../../lib/battle/CBattleInfoCallback.h"
#include "../../lib/serializer/JsonSerializeFormat.h"
static const std::string APPLICABLE_GENERAL = "applicable";
static const std::string APPLICABLE_TARGET = "applicableTarget";
static const std::string APPLY = "apply";
namespace spells
{
namespace effects
{
LuaSpellEffectFactory::LuaSpellEffectFactory(const Script * script_)
: script(script_)
{
}
LuaSpellEffectFactory::~LuaSpellEffectFactory() = default;
Effect * LuaSpellEffectFactory::create() const
{
return new LuaSpellEffect(script);
}
LuaSpellEffect::LuaSpellEffect(const Script * script_)
: script(script_)
{
}
LuaSpellEffect::~LuaSpellEffect() = default;
void LuaSpellEffect::adjustTargetTypes(std::vector<TargetType> & types) const
{
}
void LuaSpellEffect::adjustAffectedHexes(std::set<BattleHex> & hexes, const Mechanics * m, const Target & spellTarget) const
{
}
bool LuaSpellEffect::applicable(Problem & problem, const Mechanics * m) const
{
std::shared_ptr<scripting::Context> context = resolveScript(m);
if(!context)
return false;
setContextVariables(m, context);
JsonNode response = context->callGlobal(APPLICABLE_GENERAL, JsonNode());
if(response.getType() != JsonNode::JsonType::DATA_BOOL)
{
logMod->error("Invalid API response from script %s.", script->getName());
logMod->debug(response.toJson(true));
return false;
}
return response.Bool();
}
bool LuaSpellEffect::applicable(Problem & problem, const Mechanics * m, const EffectTarget & target) const
{
std::shared_ptr<scripting::Context> context = resolveScript(m);
if(!context)
return false;
setContextVariables(m, context);
JsonNode requestP;
if(target.empty())
return false;
for(auto & dest : target)
{
JsonNode targetData;
targetData.Vector().push_back(JsonUtils::intNode(dest.hexValue.hex));
if(dest.unitValue)
targetData.Vector().push_back(JsonUtils::intNode(dest.unitValue->unitId()));
else
targetData.Vector().push_back(JsonUtils::intNode(-1));
requestP.Vector().push_back(targetData);
}
JsonNode request;
request.Vector().push_back(requestP);
JsonNode response = context->callGlobal(APPLICABLE_TARGET, request);
if(response.getType() != JsonNode::JsonType::DATA_BOOL)
{
logMod->error("Invalid API response from script %s.", script->getName());
logMod->debug(response.toJson(true));
return false;
}
return response.Bool();
}
void LuaSpellEffect::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
{
if(target.empty())
return;
std::shared_ptr<scripting::Context> context = resolveScript(m);
if(!context)
{
server->complain("Unable to create scripting context");
return;
}
setContextVariables(m, context);
JsonNode requestP;
for(auto & dest : target)
{
JsonNode targetData;
targetData.Vector().push_back(JsonUtils::intNode(dest.hexValue.hex));
if(dest.unitValue)
targetData.Vector().push_back(JsonUtils::intNode(dest.unitValue->unitId()));
else
targetData.Vector().push_back(JsonUtils::intNode(-1));
requestP.Vector().push_back(targetData);
}
JsonNode request;
request.Vector().push_back(requestP);
context->callGlobal(server, APPLY, request);
}
EffectTarget LuaSpellEffect::filterTarget(const Mechanics * m, const EffectTarget & target) const
{
return EffectTarget(target);
}
EffectTarget LuaSpellEffect::transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const
{
return EffectTarget(spellTarget);
}
void LuaSpellEffect::serializeJsonEffect(JsonSerializeFormat & handler)
{
//TODO: load everything and provide to script
}
std::shared_ptr<Context> LuaSpellEffect::resolveScript(const Mechanics * m) const
{
return m->battle()->getContextPool()->getContext(script);
}
void LuaSpellEffect::setContextVariables(const Mechanics * m, std::shared_ptr<Context> context) const
{
context->setGlobal("effectLevel", m->getEffectLevel());
context->setGlobal("effectRangeLevel", m->getRangeLevel());
context->setGlobal("effectPower", m->getEffectPower());
context->setGlobal("effectDuration", m->getEffectDuration());
context->setGlobal("effectValue", static_cast<int>(m->getEffectValue()));
}
}
}

View File

@ -0,0 +1,73 @@
/*
* LuaSpellEffect.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "../../lib/spells/effects/Effect.h"
#include "../../lib/spells/effects/Registry.h"
namespace scripting
{
class Script;
class Context;
}
namespace spells
{
namespace effects
{
using ::scripting::Script;
using ::scripting::Context;
class LuaSpellEffectFactory : public IEffectFactory
{
public:
LuaSpellEffectFactory(const Script * script_);
virtual ~LuaSpellEffectFactory();
virtual Effect * create() const override;
private:
const Script * script;
};
class LuaSpellEffect : public Effect
{
public:
LuaSpellEffect(const Script * script_);
virtual ~LuaSpellEffect();
void adjustTargetTypes(std::vector<TargetType> & types) const override;
void adjustAffectedHexes(std::set<BattleHex> & hexes, const Mechanics * m, const Target & spellTarget) const override;
bool applicable(Problem & problem, const Mechanics * m) const override;
bool applicable(Problem & problem, const Mechanics * m, const EffectTarget & target) const override;
void apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const override;
EffectTarget filterTarget(const Mechanics * m, const EffectTarget & target) const override;
EffectTarget transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const override;
protected:
void serializeJsonEffect(JsonSerializeFormat & handler) override;
private:
const Script * script;
std::shared_ptr<Context> resolveScript(const Mechanics * m) const;
void setContextVariables(const Mechanics * m, std::shared_ptr<Context> context) const;
};
}
}

253
scripting/lua/LuaStack.cpp Normal file
View File

@ -0,0 +1,253 @@
/*
* LuaStack.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "LuaStack.h"
#include "../../lib/JsonNode.h"
#include "../../lib/int3.h"
namespace scripting
{
LuaStack::LuaStack(lua_State * L_)
: L(L_)
{
initialTop = lua_gettop(L);
}
void LuaStack::balance()
{
lua_settop(L, initialTop);
}
void LuaStack::clear()
{
lua_settop(L, 0);
}
void LuaStack::pushByIndex(lua_Integer index)
{
lua_pushvalue(L, index);
}
void LuaStack::pushNil()
{
lua_pushnil(L);
}
void LuaStack::pushInteger(lua_Integer value)
{
lua_pushinteger(L, value);
}
void LuaStack::push(bool value)
{
lua_pushboolean(L, value);
}
void LuaStack::push(const char * value)
{
lua_pushstring(L, value);
}
void LuaStack::push(const std::string & value)
{
lua_pushlstring(L, value.c_str(), value.size());
}
void LuaStack::push(const int3 & value)
{
push(value.x);
push(value.y);
push(value.z);
}
void LuaStack::push(const JsonNode & value)
{
switch(value.getType())
{
case JsonNode::JsonType::DATA_BOOL:
{
push(value.Bool());
}
break;
case JsonNode::JsonType::DATA_FLOAT:
{
lua_pushnumber(L, value.Float());
}
break;
case JsonNode::JsonType::DATA_INTEGER:
{
pushInteger(value.Integer());
}
break;
case JsonNode::JsonType::DATA_STRUCT:
{
lua_newtable(L);
for(auto & keyValue : value.Struct())
{
push(keyValue.first);
push(keyValue.second);
lua_rawset(L, -3);
}
}
break;
case JsonNode::JsonType::DATA_STRING:
push(value.String());
break;
case JsonNode::JsonType::DATA_VECTOR:
{
lua_newtable(L);
for(int idx = 0; idx < value.Vector().size(); idx++)
{
pushInteger(idx + 1);
push(value.Vector()[idx]);
lua_rawset(L, -3);
}
}
break;
default:
pushNil();
break;
}
}
bool LuaStack::tryGet(int position, bool & value)
{
if(!lua_isboolean(L, position))
return false;
value = (lua_toboolean(L, position) != 0);
return true;
}
bool LuaStack::tryGet(int position, double & value)
{
if(!lua_isnumber(L, position))
return false;
value = lua_tonumber(L, position);
return true;
}
bool LuaStack::tryGetInteger(int position, lua_Integer & value)
{
if(!lua_isnumber(L, position))
return false;
value = lua_tointeger(L, position);
return true;
}
bool LuaStack::tryGet(int position, std::string & value)
{
if(!lua_isstring(L, position))
return false;
size_t len = 0;
auto raw = lua_tolstring(L, position, &len);
value = std::string(raw, len);
return true;
}
bool LuaStack::tryGet(int position, int3 & value)
{
return tryGet(position, value.x) && tryGet(position+1, value.y) && tryGet(position+2, value.z);
}
bool LuaStack::tryGet(int position, JsonNode & value)
{
auto type = lua_type(L, position);
switch(type)
{
case LUA_TNIL:
value.clear();
return true;
case LUA_TNUMBER:
return tryGet(position, value.Float());
case LUA_TBOOLEAN:
value.Bool() = (lua_toboolean(L, position) != 0);
return true;
case LUA_TSTRING:
return tryGet(position, value.String());
case LUA_TTABLE:
{
JsonNode asVector(JsonNode::JsonType::DATA_VECTOR);
JsonNode asStruct(JsonNode::JsonType::DATA_STRUCT);
lua_pushnil(L); /* first key */
while(lua_next(L, position) != 0)
{
/* 'key' (at index -2) and 'value' (at index -1) */
JsonNode fieldValue;
if(!tryGet(lua_gettop(L), fieldValue))
{
lua_pop(L, 2);
value.clear();
return false;
}
lua_pop(L, 1); //pop value
if(lua_type(L, -1) == LUA_TNUMBER)
{
auto key = lua_tointeger(L, -1);
if(key > 0)
{
if(asVector.Vector().size() < key)
asVector.Vector().resize(key);
--key;
asVector.Vector().at(key) = fieldValue;
}
}
else if(lua_isstring(L, -1))
{
std::string key;
tryGet(-1, key);
asStruct[key] = fieldValue;
}
}
if(!asVector.Vector().empty())
{
std::swap(value, asVector);
}
else
{
std::swap(value, asStruct);
}
}
return true;
default:
value.clear();
return false;
}
}
int LuaStack::retNil()
{
clear();
pushNil();
return 1;
}
int LuaStack::retVoid()
{
clear();
return 0;
}
}

288
scripting/lua/LuaStack.h Normal file
View File

@ -0,0 +1,288 @@
/*
* LuaStack.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "api/Registry.h"
#include "../../lib/GameConstants.h"
class JsonNode;
class int3;
namespace scripting
{
namespace detail
{
template<typename T>
struct IsRegularClass
{
static constexpr auto value = std::is_class<T>::value && !std::is_base_of<IdTag, T>::value;
};
template<typename T>
struct IsIdClass
{
static constexpr auto value = std::is_class<T>::value && std::is_base_of<IdTag, T>::value;
};
}
class LuaStack
{
public:
LuaStack(lua_State * L_);
void balance();
void clear();
void pushByIndex(lua_Integer index);
void pushNil();
void pushInteger(lua_Integer value);
void push(bool value);
void push(const char * value);
void push(const std::string & value);
void push(const JsonNode & value);
template<typename T>
void push(const boost::optional<T> & value)
{
if(value.is_initialized())
push(value.get());
else
pushNil();
}
template<typename T, typename std::enable_if< std::is_integral<T>::value && !std::is_same<T, bool>::value, int>::type = 0>
void push(const T value)
{
pushInteger(static_cast<lua_Integer>(value));
}
template<typename T, typename std::enable_if< std::is_enum<T>::value, int>::type = 0>
void push(const T value)
{
pushInteger(static_cast<lua_Integer>(value));
}
void push(const int3 & value);
template<typename T, typename std::enable_if< detail::IsIdClass<T>::value, int>::type = 0>
void push(const T & value)
{
pushInteger(static_cast<lua_Integer>(value.toEnum()));
}
template<typename T, typename std::enable_if<detail::IsRegularClass<T>::value, int>::type = 0>
void push(T * value)
{
using UData = T *;
static auto KEY = api::TypeRegistry::get()->getKey<UData>();
if(!value)
{
pushNil();
return;
}
void * raw = lua_newuserdata(L, sizeof(UData));
if(!raw)
{
pushNil();
return;
}
UData * ptr = static_cast<UData *>(raw);
*ptr = value;
luaL_getmetatable(L, KEY);
lua_setmetatable(L, -2);
}
template<typename T, typename std::enable_if<detail::IsRegularClass<T>::value, int>::type = 0>
void push(std::shared_ptr<T> value)
{
using UData = std::shared_ptr<T>;
static auto KEY = api::TypeRegistry::get()->getKey<UData>();
if(!value)
{
pushNil();
return;
}
void * raw = lua_newuserdata(L, sizeof(UData));
if(!raw)
{
pushNil();
return;
}
new(raw) UData(value);
luaL_getmetatable(L, KEY);
lua_setmetatable(L, -2);
}
template<typename T, typename std::enable_if<detail::IsRegularClass<T>::value, int>::type = 0>
void push(std::unique_ptr<T> && value)
{
using UData = std::unique_ptr<T>;
static auto KEY = api::TypeRegistry::get()->getKey<UData>();
if(!value)
{
pushNil();
return;
}
void * raw = lua_newuserdata(L, sizeof(UData));
if(!raw)
{
pushNil();
return;
}
new(raw) UData(std::move(value));
luaL_getmetatable(L, KEY);
lua_setmetatable(L, -2);
}
bool tryGetInteger(int position, lua_Integer & value);
bool tryGet(int position, bool & value);
template<typename T, typename std::enable_if< std::is_integral<T>::value && !std::is_same<T, bool>::value, int>::type = 0>
bool tryGet(int position, T & value)
{
lua_Integer temp;
if(tryGetInteger(position, temp))
{
value = static_cast<T>(temp);
return true;
}
else
{
return false;
}
}
template<typename T, typename std::enable_if<detail::IsIdClass<T>::value, int>::type = 0>
bool tryGet(int position, T & value)
{
lua_Integer temp;
if(tryGetInteger(position, temp))
{
value = T(temp);
return true;
}
else
{
return false;
}
}
template<typename T, typename std::enable_if< std::is_enum<T>::value, int>::type = 0>
bool tryGet(int position, T & value)
{
lua_Integer temp;
if(tryGetInteger(position, temp))
{
value = static_cast<T>(temp);
return true;
}
else
{
return false;
}
}
bool tryGet(int position, int3 & value);
bool tryGet(int position, double & value);
bool tryGet(int position, std::string & value);
template<typename T, typename std::enable_if<detail::IsRegularClass<T>::value, int>::type = 0>
bool tryGet(int position, T * & value)
{
return tryGetUData(position, value);
}
template<typename T, typename std::enable_if<detail::IsRegularClass<T>::value, int>::type = 0>
bool tryGet(int position, std::shared_ptr<T> & value)
{
return tryGetUData(position, value);
}
template<typename U>
bool tryGetUData(int position, U & value)
{
static auto KEY = api::TypeRegistry::get()->getKey<U>();
void * raw = luaL_checkudata(L, position, KEY);
if(!raw)
return false;
value = *(static_cast<U *>(raw));
return true;
}
bool tryGet(int position, JsonNode & value);
int retNil();
int retVoid();
STRONG_INLINE
int retPushed()
{
return lua_gettop(L);
}
inline bool isFunction(int position)
{
return lua_isfunction(L, position);
}
inline bool isNumber(int position)
{
return lua_isnumber(L, position);
}
static int quickRetBool(lua_State * L, bool value)
{
lua_settop(L, 0);
lua_pushboolean(L, value);
return 1;
}
template<typename T>
static int quickRetInt(lua_State * L, const T & value)
{
lua_settop(L, 0);
lua_pushinteger(L, static_cast<int32_t>(value));
return 1;
}
static int quickRetStr(lua_State * L, const std::string & value)
{
lua_settop(L, 0);
lua_pushlstring(L, value.c_str(), value.size());
return 1;
}
private:
lua_State * L;
int initialTop;
};
}

266
scripting/lua/LuaWrapper.h Normal file
View File

@ -0,0 +1,266 @@
/*
* LuaWrapper.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "api/Registry.h"
#include "LuaFunctor.h"
#include "LuaStack.h"
/*
* Original code is LunaWrapper by nornagon.
* https://lua-users.org/wiki/LunaWrapper
* Published under the BSD 2-clause license
* https://opensource.org/licenses/BSD-2-Clause
*
*/
namespace scripting
{
namespace detail
{
template<typename T>
struct RegType
{
const char * name;
std::function<int(lua_State *, T)> functor;
};
struct CustomRegType
{
const char * name;
lua_CFunction functor;
bool isStatic;
};
template <typename P, typename U>
struct Dispatcher
{
using ProxyType = P;
using UDataType = U;
static int invoke(lua_State * L)
{
static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();
int i = (int)lua_tonumber(L, lua_upvalueindex(1));
void * raw = luaL_checkudata(L, 1, KEY);
if(!raw)
{
lua_settop(L, 0);
return 0;
}
lua_remove(L, 1);
auto obj = *(static_cast<UDataType *>(raw));
return (ProxyType::REGISTER[i].functor)(L, obj);
}
static void setIndexTable(lua_State * L)
{
lua_pushstring(L, "__index");
lua_newtable(L);
lua_Integer index = 0;
for(auto & reg : ProxyType::REGISTER)
{
lua_pushstring(L, reg.name);
lua_pushnumber(L, index);
lua_pushcclosure(L, &invoke, 1);
lua_rawset(L, -3);
index++;
}
for(auto & reg : ProxyType::REGISTER_CUSTOM)
{
if(!reg.isStatic)
{
lua_pushstring(L, reg.name);
lua_pushcclosure(L, reg.functor, 0);
lua_rawset(L, -3);
}
}
lua_rawset(L, -3);
}
static void pushStaticTable(lua_State * L)
{
lua_newtable(L);
lua_newtable(L);
lua_pushstring(L, "__index");
{
lua_newtable(L);
for(auto & reg : ProxyType::REGISTER_CUSTOM)
{
if(reg.isStatic)
{
lua_pushstring(L, reg.name);
lua_pushcclosure(L, reg.functor, 0);
lua_rawset(L, -3);
}
}
}
lua_rawset(L, -3);
lua_pushstring(L, "__newindex");
lua_pushnil(L);
lua_rawset(L, -3);
lua_setmetatable(L, -2);
}
static int destructor(lua_State * L)
{
static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();
void * objPtr = luaL_checkudata(L, 1, KEY);
if(objPtr)
{
auto obj = static_cast<UDataType *>(objPtr);
obj->reset();
}
lua_settop(L, 0);
return 0;
}
};
}
class RegistarBase : public api::Registar
{
public:
protected:
virtual void adjustMetatable(lua_State * L) const
{
}
virtual void adjustStaticTable(lua_State * L) const
{
}
};
template<class T, class Proxy = T>
class OpaqueWrapper : public RegistarBase
{
public:
using ObjectType = typename std::remove_cv<T>::type;
using UDataType = T *;
using RegType = detail::RegType<UDataType>;
using CustomRegType = detail::CustomRegType;
void pushMetatable(lua_State * L) const override final
{
static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();
LuaStack S(L);
if(luaL_newmetatable(L, KEY) != 0)
adjustMetatable(L);
S.balance();
detail::Dispatcher<Proxy, UDataType>::pushStaticTable(L);
adjustStaticTable(L);
}
protected:
void adjustMetatable(lua_State * L) const override
{
detail::Dispatcher<Proxy, UDataType>::setIndexTable(L);
}
};
template<class T, class Proxy = T>
class SharedWrapper : public RegistarBase
{
public:
using ObjectType = typename std::remove_cv<T>::type;
using UDataType = std::shared_ptr<T>;
using RegType = detail::RegType<UDataType>;
using CustomRegType = detail::CustomRegType;
static int constructor(lua_State * L)
{
LuaStack S(L);
S.clear();//we do not accept any parameters in constructor
auto obj = std::make_shared<T>();
S.push(obj);
return 1;
}
void pushMetatable(lua_State * L) const override final
{
static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();
LuaStack S(L);
if(luaL_newmetatable(L, KEY) != 0)
{
adjustMetatable(L);
S.push("__gc");
lua_pushcfunction(L, &(detail::Dispatcher<Proxy, UDataType>::destructor));
lua_rawset(L, -3);
}
S.balance();
detail::Dispatcher<Proxy, UDataType>::pushStaticTable(L);
adjustStaticTable(L);
}
protected:
void adjustMetatable(lua_State * L) const override
{
detail::Dispatcher<Proxy, UDataType>::setIndexTable(L);
}
};
template<class T, class Proxy = T>
class UniqueOpaqueWrapper : public api::Registar
{
public:
using ObjectType = typename std::remove_cv<T>::type;
using UDataType = std::unique_ptr<T>;
using RegType = detail::RegType<UDataType>;
using CustomRegType = detail::CustomRegType;
void pushMetatable(lua_State * L) const override final
{
static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();
LuaStack S(L);
if(luaL_newmetatable(L, KEY) != 0)
{
// detail::Dispatcher<Proxy, UDataType>::setIndexTable(L);
S.push("__gc");
lua_pushcfunction(L, &(detail::Dispatcher<Proxy, UDataType>::destructor));
lua_rawset(L, -3);
}
S.balance();
detail::Dispatcher<Proxy, UDataType>::pushStaticTable(L);
}
};
}

2
scripting/lua/StdInc.cpp Normal file
View File

@ -0,0 +1,2 @@
// Creates the precompiled header
#include "StdInc.h"

10
scripting/lua/StdInc.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include "../../Global.h"
#include <lua.hpp>
// This header should be treated as a pre compiled header file(PCH) in the compiler building settings.
// Here you can add specific libraries and macros which are specific to this project.

View File

@ -0,0 +1,48 @@
/*
* api/Artifact.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Artifact.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
#include "../../../lib/HeroBonus.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(ArtifactProxy, "Artifact");
const std::vector<ArtifactProxy::RegType> ArtifactProxy::REGISTER = {};
const std::vector<ArtifactProxy::CustomRegType> ArtifactProxy::REGISTER_CUSTOM =
{
{"getIconIndex", LuaMethodWrapper<Artifact, int32_t(Entity:: *)()const, &Entity::getIconIndex>::invoke, false},
{"getIndex", LuaMethodWrapper<Artifact, int32_t(Entity:: *)()const, &Entity::getIndex>::invoke, false},
{"getJsonKey", LuaMethodWrapper<Artifact, const std::string &(Entity:: *)()const, &Entity::getJsonKey>::invoke, false},
{"getName", LuaMethodWrapper<Artifact, const std::string &(Entity:: *)()const, &Entity::getName>::invoke, false},
{"getId", LuaMethodWrapper<Artifact, ArtifactID(EntityT<ArtifactID>::*)()const, &EntityT<ArtifactID>::getId>::invoke, false},
{"accessBonuses", LuaMethodWrapper<Artifact, const IBonusBearer *(EntityWithBonuses<ArtifactID>:: *)()const, &EntityWithBonuses<ArtifactID>::accessBonuses>::invoke, false},
{"getDescription", LuaMethodWrapper<Artifact, const std::string &(Artifact:: *)()const, &Artifact::getDescription>::invoke, false},
{"getEventText", LuaMethodWrapper<Artifact, const std::string &(Artifact:: *)()const, &Artifact::getEventText>::invoke, false},
{"isBig", LuaMethodWrapper<Artifact, bool(Artifact:: *)()const, &Artifact::isBig>::invoke, false},
{"isTradable", LuaMethodWrapper<Artifact, bool(Artifact:: *)()const, &Artifact::isTradable>::invoke, false},
{"getPrice", LuaMethodWrapper<Artifact, uint32_t(Artifact:: *)()const, &Artifact::getPrice>::invoke, false},
};
}
}

View File

@ -0,0 +1,32 @@
/*
* api/Artifact.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/Artifact.h>
#include "../LuaWrapper.h"
namespace scripting
{
namespace api
{
class ArtifactProxy : public OpaqueWrapper<const Artifact, ArtifactProxy>
{
public:
using Wrapper = OpaqueWrapper<const Artifact, ArtifactProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,101 @@
/*
* BattleCb.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "BattleCb.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
#include "../../../lib/GameConstants.h"
#include "../../../lib/battle/Unit.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(BattleCbProxy, "Battle");
const std::vector<BattleCbProxy::RegType> BattleCbProxy::REGISTER =
{
{
"getBattlefieldType",
&BattleCbProxy::getBattlefieldType
},
{
"getNextUnitId",
LuaCallWrapper<const BattleCb>::createFunctor(&BattleCb::battleNextUnitId)
},
{
"getTacticDistance",
LuaCallWrapper<const BattleCb>::createFunctor(&BattleCb::battleTacticDist)
},
{
"getTerrainType",
&BattleCbProxy::getTerrainType
},
{
"getUnitById",
LuaCallWrapper<const BattleCb>::createFunctor(&BattleCb::battleGetUnitByID)
},
{
"getUnitByPos",
&BattleCbProxy::getUnitByPos
},
{
"isFinished",
LuaCallWrapper<const BattleCb>::createFunctor(&BattleCb::battleIsFinished)
}
};
const std::vector<BattleCbProxy::CustomRegType> BattleCbProxy::REGISTER_CUSTOM =
{
};
int BattleCbProxy::getBattlefieldType(lua_State * L, const BattleCb * object)
{
LuaStack S(L);
auto ret = object->battleGetBattlefieldType();
S.push(static_cast<si32>(ret.num));
return 1;
}
int BattleCbProxy::getTerrainType(lua_State * L, const BattleCb * object)
{
LuaStack S(L);
auto ret = object->battleTerrainType();
S.push(static_cast<si32>(ret.num));
return 1;
}
int BattleCbProxy::getUnitByPos(lua_State * L, const BattleCb * object)
{
LuaStack S(L);
BattleHex hex;
if(!S.tryGet(1, hex.hex))
return S.retNil();
bool onlyAlive;
if(!S.tryGet(2, onlyAlive))
onlyAlive = true;//same as default value in battleGetUnitByPos
S.push(object->battleGetUnitByPos(hex, onlyAlive));
return 1;
}
}
}

View File

@ -0,0 +1,37 @@
/*
* BattleCb.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/scripting/Service.h>
#include "../../../lib/battle/IBattleInfoCallback.h"
#include "../LuaWrapper.h"
namespace scripting
{
namespace api
{
class BattleCbProxy : public OpaqueWrapper<const BattleCb, BattleCbProxy>
{
public:
using Wrapper = OpaqueWrapper<const BattleCb, BattleCbProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
static int getBattlefieldType(lua_State * L, const BattleCb * object);
static int getTerrainType(lua_State * L, const BattleCb * object);
static int getUnitByPos(lua_State * L, const BattleCb * object);
};
}
}

View File

@ -0,0 +1,232 @@
/*
* BonusSystem.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "BonusSystem.h"
#include "../../../lib/HeroBonus.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_SCRIPT_API(BonusProxy, "Bonus");
const std::vector<BonusProxy::RegType> BonusProxy::REGISTER =
{
{"getType", &BonusProxy::getType},
{"getSubtype", &BonusProxy::getSubtype},
{"getDuration", &BonusProxy::getDuration},
{"getTurns", &BonusProxy::getTurns},
{"getValueType", &BonusProxy::getValueType},
{"getVal", &BonusProxy::getVal},
{"getSource", &BonusProxy::getSource},
{"getSourceID", &BonusProxy::getSourceID},
{"getEffectRange", &BonusProxy::getEffectRange},
{"getStacking", &BonusProxy::getStacking},
{"getDescription", &BonusProxy::getDescription},
{"toJsonNode", &BonusProxy::toJsonNode}
};
const std::vector<BonusProxy::CustomRegType> BonusProxy::REGISTER_CUSTOM =
{
};
int BonusProxy::getType(lua_State * L, std::shared_ptr<const Bonus> object)
{
return LuaStack::quickRetInt(L, object->type);
}
int BonusProxy::getSubtype(lua_State * L, std::shared_ptr<const Bonus> object)
{
return LuaStack::quickRetInt(L, object->subtype);
}
int BonusProxy::getDuration(lua_State * L, std::shared_ptr<const Bonus> object)
{
return LuaStack::quickRetInt(L, object->duration);
}
int BonusProxy::getTurns(lua_State * L, std::shared_ptr<const Bonus> object)
{
return LuaStack::quickRetInt(L, object->turnsRemain);
}
int BonusProxy::getValueType(lua_State * L, std::shared_ptr<const Bonus> object)
{
return LuaStack::quickRetInt(L, object->valType);
}
int BonusProxy::getVal(lua_State * L, std::shared_ptr<const Bonus> object)
{
return LuaStack::quickRetInt(L, object->val);
}
int BonusProxy::getSource(lua_State * L, std::shared_ptr<const Bonus> object)
{
return LuaStack::quickRetInt(L, object->source);
}
int BonusProxy::getSourceID(lua_State * L, std::shared_ptr<const Bonus> object)
{
return LuaStack::quickRetInt(L, object->sid);
}
int BonusProxy::getEffectRange(lua_State * L, std::shared_ptr<const Bonus> object)
{
return LuaStack::quickRetInt(L, object->effectRange);
}
int BonusProxy::getStacking(lua_State * L, std::shared_ptr<const Bonus> object)
{
return LuaStack::quickRetStr(L, object->stacking);
}
int BonusProxy::getDescription(lua_State * L, std::shared_ptr<const Bonus> object)
{
return LuaStack::quickRetStr(L, object->description);
}
int BonusProxy::toJsonNode(lua_State * L, std::shared_ptr<const Bonus> object)
{
LuaStack S(L);
S.clear();
S.push(object->toJsonNode());
return 1;
}
template <typename T>
static void publishMap(lua_State * L, const T & map)
{
for(auto & p : map)
{
const std::string & name = p.first;
int32_t id = static_cast<int32_t>(p.second);
lua_pushstring(L, name.c_str());
lua_pushinteger(L, id);
lua_rawset(L, -3);
}
}
void BonusProxy::adjustStaticTable(lua_State * L) const
{
publishMap(L, bonusNameMap);
publishMap(L, bonusValueMap);
publishMap(L, bonusSourceMap);
publishMap(L, bonusDurationMap);
}
VCMI_REGISTER_SCRIPT_API(BonusListProxy, "BonusList");
const std::vector<BonusListProxy::RegType> BonusListProxy::REGISTER =
{
};
const std::vector<BonusListProxy::CustomRegType> BonusListProxy::REGISTER_CUSTOM =
{
};
int BonusListProxy::index(lua_State * L)
{
//field = __index(self, key)
LuaStack S(L);
std::shared_ptr<const BonusList> self;
lua_Integer key = -1;
if(S.tryGet(1, self) && S.tryGetInteger(2, key))
{
if((key >= 1) && (key <= self->size()))
{
std::shared_ptr<const Bonus> ret = (*self)[key-1];
S.clear();
S.push(ret);
return 1;
}
}
return S.retNil();
}
void BonusListProxy::adjustMetatable(lua_State * L) const
{
lua_pushstring(L, "__index");
lua_pushcfunction(L, &BonusListProxy::index);
lua_rawset(L, -3);
}
VCMI_REGISTER_SCRIPT_API(BonusBearerProxy, "BonusBearer");
const std::vector<BonusBearerProxy::RegType> BonusBearerProxy::REGISTER =
{
{"getBonuses", &BonusBearerProxy::getBonuses},
};
const std::vector<BonusBearerProxy::CustomRegType> BonusBearerProxy::REGISTER_CUSTOM =
{
};
int BonusBearerProxy::getBonuses(lua_State * L, const IBonusBearer * object)
{
LuaStack S(L);
TConstBonusListPtr ret;
const bool hasSelector = S.isFunction(1);
const bool hasRangeSelector = S.isFunction(2);
if(hasSelector)
{
auto selector = [](const Bonus * b)
{
return false; //TODO: BonusBearerProxy::getBonuses selector
};
if(hasRangeSelector)
{
auto rangeSelector = [](const Bonus * b)
{
return false;//TODO: BonusBearerProxy::getBonuses rangeSelector
};
ret = object->getBonuses(selector, rangeSelector);
}
else
{
ret = object->getBonuses(selector, Selector::all);
}
}
else
{
ret = object->getBonuses(Selector::all, Selector::all);
}
S.clear();
S.push(ret);
return S.retPushed();
}
}
}

View File

@ -0,0 +1,75 @@
/*
* BonusSystem.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "../LuaWrapper.h"
class Bonus;
class BonusList;
class IBonusBearer;
namespace scripting
{
namespace api
{
class BonusProxy : public SharedWrapper<const Bonus, BonusProxy>
{
public:
using Wrapper = SharedWrapper<const Bonus, BonusProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
static int getType(lua_State * L, std::shared_ptr<const Bonus> object);
static int getSubtype(lua_State * L, std::shared_ptr<const Bonus> object);
static int getDuration(lua_State * L, std::shared_ptr<const Bonus> object);
static int getTurns(lua_State * L, std::shared_ptr<const Bonus> object);
static int getValueType(lua_State * L, std::shared_ptr<const Bonus> object);
static int getVal(lua_State * L, std::shared_ptr<const Bonus> object);
static int getSource(lua_State * L, std::shared_ptr<const Bonus> object);
static int getSourceID(lua_State * L, std::shared_ptr<const Bonus> object);
static int getDescription(lua_State * L, std::shared_ptr<const Bonus> object);
static int getEffectRange(lua_State * L, std::shared_ptr<const Bonus> object);
static int getStacking(lua_State * L, std::shared_ptr<const Bonus> object);
static int toJsonNode(lua_State * L, std::shared_ptr<const Bonus> object);
protected:
virtual void adjustStaticTable(lua_State * L) const override;
};
class BonusListProxy : public SharedWrapper<const BonusList, BonusListProxy>
{
public:
using Wrapper = SharedWrapper<const BonusList, BonusListProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
static int index(lua_State * L);
protected:
virtual void adjustMetatable(lua_State * L) const override;
};
class BonusBearerProxy : public OpaqueWrapper<const IBonusBearer, BonusBearerProxy>
{
public:
using Wrapper = OpaqueWrapper<const IBonusBearer, BonusBearerProxy>;
static int getBonuses(lua_State * L, const IBonusBearer * object);
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,68 @@
/*
* api/Creature.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Creature.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
#include "../../../lib/HeroBonus.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(CreatureProxy, "Creature");
const std::vector<CreatureProxy::RegType> CreatureProxy::REGISTER =
{
{"accessBonuses", LuaCallWrapper<const EntityWithBonuses<CreatureID>>::createFunctor(&EntityWithBonuses<CreatureID>::accessBonuses)},
{"getCost", LuaCallWrapper<const Creature>::createFunctor(&Creature::getCost)},
{"isDoubleWide", LuaCallWrapper<const Creature>::createFunctor(&Creature::isDoubleWide)},
};
const std::vector<CreatureProxy::CustomRegType> CreatureProxy::REGISTER_CUSTOM =
{
{"getIconIndex", LuaMethodWrapper<Creature, int32_t(Entity:: *)()const, &Entity::getIconIndex>::invoke, false},
{"getIndex", LuaMethodWrapper<Creature, int32_t(Entity:: *)()const, &Entity::getIndex>::invoke, false},
{"getJsonKey", LuaMethodWrapper<Creature, const std::string &(Entity:: *)()const, &Entity::getJsonKey>::invoke, false},
{"getName", LuaMethodWrapper<Creature, const std::string &(Entity:: *)()const, &Entity::getName>::invoke, false},
{"accessBonuses", LuaMethodWrapper<Creature, const IBonusBearer *(EntityWithBonuses<CreatureID>:: *)()const, &EntityWithBonuses<CreatureID>::accessBonuses>::invoke, false},
{"getMaxHealth", LuaMethodWrapper<Creature, uint32_t(Creature:: *)()const, &Creature::getMaxHealth>::invoke, false},
{"getPluralName", LuaMethodWrapper<Creature, const std::string &(Creature:: *)()const, &Creature::getPluralName>::invoke, false},
{"getSingularName", LuaMethodWrapper<Creature, const std::string &(Creature:: *)()const, &Creature::getSingularName>::invoke, false},
{"getAdvMapAmountMin", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getAdvMapAmountMin>::invoke, false},
{"getAdvMapAmountMax", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getAdvMapAmountMax>::invoke, false},
{"getAIValue", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getAIValue>::invoke, false},
{"getFightValue", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getFightValue>::invoke, false},
{"getLevel", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getLevel>::invoke, false},
{"getGrowth", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getGrowth>::invoke, false},
{"getHorde", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getHorde>::invoke, false},
{"getFactionIndex", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getFactionIndex>::invoke, false},
{"getBaseAttack", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getBaseAttack>::invoke, false},
{"getBaseDefense", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getBaseDefense>::invoke, false},
{"getBaseDamageMin", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getBaseDamageMin>::invoke, false},
{"getBaseDamageMax", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getBaseDamageMax>::invoke, false},
{"getBaseHitPoints", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getBaseHitPoints>::invoke, false},
{"getBaseSpellPoints", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getBaseSpellPoints>::invoke, false},
{"getBaseSpeed", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getBaseSpeed>::invoke, false},
{"getBaseShots", LuaMethodWrapper<Creature, int32_t(Creature:: *)()const, &Creature::getBaseShots>::invoke, false},
};
}
}

View File

@ -0,0 +1,33 @@
/*
* api/Creature.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/Creature.h>
#include "../LuaWrapper.h"
namespace scripting
{
namespace api
{
class CreatureProxy : public OpaqueWrapper<const Creature, CreatureProxy>
{
public:
using Wrapper = OpaqueWrapper<const Creature, CreatureProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,38 @@
/*
* api/Faction.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Faction.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(FactionProxy, "Faction");
const std::vector<FactionProxy::RegType> FactionProxy::REGISTER = {};
const std::vector<FactionProxy::CustomRegType> FactionProxy::REGISTER_CUSTOM =
{
{"getIconIndex", LuaMethodWrapper<Faction, int32_t(Entity:: *)()const, &Entity::getIconIndex>::invoke, false},
{"getIndex", LuaMethodWrapper<Faction, int32_t(Entity:: *)()const, &Entity::getIndex>::invoke, false},
{"getJsonKey", LuaMethodWrapper<Faction, const std::string &(Entity:: *)()const, &Entity::getJsonKey>::invoke, false},
{"getName", LuaMethodWrapper<Faction, const std::string &(Entity:: *)()const, &Entity::getName>::invoke, false},
{"hasTown", LuaMethodWrapper<Faction, bool(Faction:: *)()const, &Faction::hasTown>::invoke, false},
};
}
}

View File

@ -0,0 +1,31 @@
/*
* api/Faction.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/Faction.h>
#include "../LuaWrapper.h"
namespace scripting
{
namespace api
{
class FactionProxy : public OpaqueWrapper<const Faction, FactionProxy>
{
public:
using Wrapper = OpaqueWrapper<const Faction, FactionProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,43 @@
/*
* GameCb.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "GameCb.h"
#include <vcmi/Player.h>
#include "../LuaCallWrapper.h"
#include "../../../lib/mapObjects/CGHeroInstance.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(GameCbProxy, "Game");
const std::vector<GameCbProxy::RegType> GameCbProxy::REGISTER = {};
const std::vector<GameCbProxy::CustomRegType> GameCbProxy::REGISTER_CUSTOM =
{
{"getDate", LuaMethodWrapper<GameCb, int32_t(GameCb:: *)(Date::EDateType)const, &GameCb::getDate>::invoke, false},
{"isAllowed", LuaMethodWrapper<GameCb, bool(GameCb:: *)(int32_t, int32_t)const, &GameCb::isAllowed>::invoke, false},
{"getCurrentPlayer", LuaMethodWrapper<GameCb, PlayerColor(GameCb:: *)()const, &GameCb::getLocalPlayer>::invoke, false},
{"getPlayer", LuaMethodWrapper<GameCb, const Player * (GameCb:: *)(PlayerColor)const, &GameCb::getPlayer>::invoke, false},
{"getHero", LuaMethodWrapper<GameCb, const CGHeroInstance *(GameCb:: *)(ObjectInstanceID)const, &GameCb::getHero>::invoke, false},
{"getHeroWithSubid", LuaMethodWrapper<GameCb, const CGHeroInstance *(GameCb:: *)(int)const, &GameCb::getHeroWithSubid>::invoke, false},
{"getObj", LuaMethodWrapper<GameCb, const CGObjectInstance *(GameCb:: *)(ObjectInstanceID, bool)const, &GameCb::getObj>::invoke, false},
};
}
}

View File

@ -0,0 +1,34 @@
/*
* GameCb.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/scripting/Service.h>
#include "../../../lib/CGameInfoCallback.h"
#include "../LuaWrapper.h"
namespace scripting
{
namespace api
{
class GameCbProxy : public OpaqueWrapper<const GameCb, GameCbProxy>
{
public:
using Wrapper = OpaqueWrapper<const GameCb, GameCbProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,36 @@
/*
* api/HeroClass.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "HeroClass.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(HeroClassProxy, "HeroClass");
const std::vector<HeroClassProxy::RegType> HeroClassProxy::REGISTER = {};
const std::vector<HeroClassProxy::CustomRegType> HeroClassProxy::REGISTER_CUSTOM =
{
{"getIconIndex", LuaMethodWrapper<HeroClass, int32_t(Entity:: *)()const, &Entity::getIconIndex>::invoke, false},
{"getIndex", LuaMethodWrapper<HeroClass, int32_t(Entity:: *)()const, &Entity::getIndex>::invoke, false},
{"getJsonKey", LuaMethodWrapper<HeroClass, const std::string &(Entity:: *)()const, &Entity::getJsonKey>::invoke, false},
{"getName", LuaMethodWrapper<HeroClass, const std::string &(Entity:: *)()const, &Entity::getName>::invoke, false},
};
}
}

View File

@ -0,0 +1,32 @@
/*
* api/HeroClass.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/HeroClass.h>
#include "../LuaWrapper.h"
namespace scripting
{
namespace api
{
class HeroClassProxy : public OpaqueWrapper<const HeroClass, HeroClassProxy>
{
public:
using Wrapper = OpaqueWrapper<const HeroClass, HeroClassProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,35 @@
/*
* HeroInstance.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "HeroInstance.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(HeroInstanceProxy, "HeroInstance");
const std::vector<HeroInstanceProxy::RegType> HeroInstanceProxy::REGISTER = {};
const std::vector<HeroInstanceProxy::CustomRegType> HeroInstanceProxy::REGISTER_CUSTOM =
{
{"getStack", LuaMethodWrapper<CGHeroInstance, const CStackInstance *(CCreatureSet:: *)(SlotID)const, &CCreatureSet::getStackPtr>::invoke, false},
{"getOwner", LuaMethodWrapper<CGHeroInstance, PlayerColor(CGObjectInstance:: *)()const, &CGObjectInstance::getOwner>::invoke, false},
};
}
}

View File

@ -0,0 +1,35 @@
/*
* HeroInstance.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/HeroClass.h>
#include "../LuaWrapper.h"
#include "../../../lib/mapObjects/CGHeroInstance.h"
namespace scripting
{
namespace api
{
class HeroInstanceProxy : public OpaqueWrapper<const CGHeroInstance, HeroInstanceProxy>
{
public:
using Wrapper = OpaqueWrapper<const CGHeroInstance, HeroInstanceProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,38 @@
/*
* api/HeroType.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "HeroType.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(HeroTypeProxy, "HeroType");
const std::vector<HeroTypeProxy::RegType> HeroTypeProxy::REGISTER = {};
const std::vector<HeroTypeProxy::CustomRegType> HeroTypeProxy::REGISTER_CUSTOM =
{
{"getIconIndex", LuaMethodWrapper<HeroType, int32_t(Entity:: *)()const, &Entity::getIconIndex>::invoke, false},
{"getIndex", LuaMethodWrapper<HeroType, int32_t(Entity:: *)()const, &Entity::getIndex>::invoke, false},
{"getJsonKey", LuaMethodWrapper<HeroType, const std::string &(Entity:: *)()const, &Entity::getJsonKey>::invoke, false},
{"getName", LuaMethodWrapper<HeroType, const std::string &(Entity:: *)()const, &Entity::getName>::invoke, false},
};
}
}

View File

@ -0,0 +1,32 @@
/*
* api/HeroType.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/HeroType.h>
#include "../LuaWrapper.h"
namespace scripting
{
namespace api
{
class HeroTypeProxy : public OpaqueWrapper<const HeroType, HeroTypeProxy>
{
public:
using Wrapper = OpaqueWrapper<const HeroType, HeroTypeProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,38 @@
/*
* ObjectInstance.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "ObjectInstance.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(ObjectInstanceProxy, "ObjectInstance");
const std::vector<ObjectInstanceProxy::RegType> ObjectInstanceProxy::REGISTER = {};
const std::vector<ObjectInstanceProxy::CustomRegType> ObjectInstanceProxy::REGISTER_CUSTOM =
{
{"getOwner", LuaMethodWrapper<CGObjectInstance, PlayerColor(IObjectInterface:: *)()const, &IObjectInterface::getOwner>::invoke, false},
{"getObjGroupIndex", LuaMethodWrapper<CGObjectInstance, int32_t(IObjectInterface:: *)()const, &IObjectInterface::getObjGroupIndex>::invoke, false},
{"getObjTypeIndex", LuaMethodWrapper<CGObjectInstance, int32_t(IObjectInterface:: *)()const, &IObjectInterface::getObjTypeIndex>::invoke, false},
{"getVisitablePosition", LuaMethodWrapper<CGObjectInstance, int3(IObjectInterface:: *)()const, &IObjectInterface::visitablePos>::invoke, false},
{"getPosition", LuaMethodWrapper<CGObjectInstance, int3(IObjectInterface:: *)()const, &IObjectInterface::getPosition>::invoke, false},
};
}
}

View File

@ -0,0 +1,35 @@
/*
* ObjectInstance.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/HeroClass.h>
#include "../LuaWrapper.h"
#include "../../../lib/mapObjects/CObjectHandler.h"
namespace scripting
{
namespace api
{
class ObjectInstanceProxy : public OpaqueWrapper<const IObjectInterface, ObjectInstanceProxy>
{
public:
using Wrapper = OpaqueWrapper<const IObjectInterface, ObjectInstanceProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,42 @@
/*
* api/Player.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Player.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(PlayerProxy, "Player");
const std::vector<PlayerProxy::RegType> PlayerProxy::REGISTER =
{
};
const std::vector<PlayerProxy::CustomRegType> PlayerProxy::REGISTER_CUSTOM =
{
// virtual PlayerColor getColor() const = 0;
// virtual TeamID getTeam() const = 0;
// virtual bool isHuman() const = 0;
// virtual const IBonusBearer * accessBonuses() const = 0;
// virtual int getResourceAmount(int type) const = 0;
};
}
}

View File

@ -0,0 +1,33 @@
/*
* api/Player.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/Player.h>
#include "../LuaWrapper.h"
namespace scripting
{
namespace api
{
class PlayerProxy : public OpaqueWrapper<const Player, PlayerProxy>
{
public:
using Wrapper = OpaqueWrapper<const Player, PlayerProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,88 @@
/*
* Registry.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "api/Registry.h"
namespace scripting
{
namespace api
{
Registry::Registry() = default;
Registry * Registry::get()
{
static std::unique_ptr<Registry> Instance = std::unique_ptr<Registry>(new Registry());
return Instance.get();
}
void Registry::add(const std::string & name, std::shared_ptr<Registar> item)
{
data[name] = item;
}
void Registry::addCore(const std::string & name, std::shared_ptr<Registar> item)
{
coreData[name] = item;
}
const Registar * Registry::find(const std::string & name) const
{
auto iter = data.find(name);
if(iter == data.end())
return nullptr;
else
return iter->second.get();
}
TypeRegistry::TypeRegistry()
: nextIndex(0)
{
}
TypeRegistry * TypeRegistry::get()
{
static std::unique_ptr<TypeRegistry> Instance = std::unique_ptr<TypeRegistry>(new TypeRegistry());
return Instance.get();
}
const char * TypeRegistry::getKeyForType(const std::type_info & type)
{
//std::type_index is unique and stable (because all bindings are in vcmiLua shared lib), but there is no way to convert it to Lua value
//there is no guarantee that name is unique, but it is at least somewhat human readable, so we append unique number to name
//TODO: name demangle
std::type_index typeIndex(type);
boost::unique_lock<boost::mutex> lock(mutex);
auto iter = keys.find(typeIndex);
if(iter == std::end(keys))
{
std::string newKey = type.name();
newKey += "_";
newKey += std::to_string(nextIndex++);
keys[typeIndex] = std::move(newKey);
return keys[typeIndex].c_str();
}
else
{
return iter->second.c_str();
}
}
}
}

View File

@ -0,0 +1,110 @@
/*
* Registry.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <typeinfo>
#include <typeindex>
#define VCMI_REGISTER_SCRIPT_API(Type, Name) \
namespace\
{\
RegisterAPI<Type> _register ## Type (Name);\
}\
\
#define VCMI_REGISTER_CORE_SCRIPT_API(Type, Name) \
namespace\
{\
RegisterCoreAPI<Type> _register ## Type (Name);\
}\
\
namespace scripting
{
namespace api
{
class TypeRegistry;
class Registar
{
public:
virtual ~Registar() = default;
virtual void pushMetatable(lua_State * L) const = 0;
};
class Registry : public boost::noncopyable
{
public:
using RegistryData = std::map<std::string, std::shared_ptr<Registar>>;
static Registry * get();
const Registar * find(const std::string & name) const;
void add(const std::string & name, std::shared_ptr<Registar> item);
void addCore(const std::string & name, std::shared_ptr<Registar> item);
const RegistryData & getCoreData() const
{
return coreData;
}
private:
RegistryData data;
RegistryData coreData;
Registry();
};
template<typename T>
class RegisterAPI
{
public:
RegisterAPI(const std::string & name)
{
auto r = std::make_shared<T>();
Registry::get()->add(name, r);
}
};
template<typename T>
class RegisterCoreAPI
{
public:
RegisterCoreAPI(const std::string & name)
{
auto r = std::make_shared<T>();
Registry::get()->addCore(name, r);
}
};
class TypeRegistry : public boost::noncopyable
{
public:
template<typename T>
const char * getKey()
{
return getKeyForType(typeid(T));
}
static TypeRegistry * get();
private:
size_t nextIndex;
boost::mutex mutex;
std::map<std::type_index, std::string> keys;
TypeRegistry();
const char * getKeyForType(const std::type_info & type);
};
}
}

View File

@ -0,0 +1,93 @@
/*
* ServerCb.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "ServerCb.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../../../lib/NetPacks.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(ServerCbProxy, "Server");
const std::vector<ServerCbProxy::RegType> ServerCbProxy::REGISTER =
{
{
"addToBattleLog",
&ServerCbProxy::apply<BattleLogMessage>
},
{
"moveUnit",
&ServerCbProxy::apply<BattleStackMoved>
},
{
"changeUnits",
&ServerCbProxy::apply<BattleUnitsChanged>
},
{
"commitPackage",
&ServerCbProxy::commitPackage
}
};
const std::vector<ServerCbProxy::CustomRegType> ServerCbProxy::REGISTER_CUSTOM =
{
};
int ServerCbProxy::commitPackage(lua_State * L, ServerCallback * object)
{
if(lua_isuserdata(L, 1) != 1)
{
lua_settop(L, 0);
return 0;
}
lua_getfield(L, 1, "toNetpackLight");
lua_insert(L, 1);
int ret = lua_pcall(L, 1, 1, 0);
if(ret != 0 || !lua_islightuserdata(L, 1))
{
lua_settop(L, 0);
return 0;
}
CPackForClient * pack = static_cast<CPackForClient *>(lua_touserdata(L, 1));
object->apply(pack);
lua_settop(L, 0);
return 0;
}
template<typename NetPack>
int ServerCbProxy::apply(lua_State * L, ServerCallback * object)
{
LuaStack S(L);
std::shared_ptr<NetPack> pack;
if(!S.tryGet(1, pack))
return S.retVoid();
object->apply(pack.get());
return S.retVoid();
}
}
}

View File

@ -0,0 +1,37 @@
/*
* ServerCb.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/ServerCallback.h>
#include "../LuaWrapper.h"
namespace scripting
{
namespace api
{
class ServerCbProxy : public OpaqueWrapper<ServerCallback, ServerCbProxy>
{
public:
using Wrapper = OpaqueWrapper<ServerCallback, ServerCbProxy>;
static int commitPackage(lua_State * L, ServerCallback * object);
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
template<typename NetPack>
static int apply(lua_State * L, ServerCallback * object);
};
}
}

View File

@ -0,0 +1,137 @@
/*
* api/Services.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Services.h"
#include <vcmi/Artifact.h>
#include <vcmi/Creature.h>
#include <vcmi/Faction.h>
#include <vcmi/HeroClass.h>
#include <vcmi/HeroType.h>
#include <vcmi/Skill.h>
#include <vcmi/spells/Spell.h>
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(ServicesProxy, "Services");
const std::vector<ServicesProxy::RegType> ServicesProxy::REGISTER =
{
{"artifacts", LuaCallWrapper<const Services>::createFunctor(&Services::artifacts)},
{"creatures", LuaCallWrapper<const Services>::createFunctor(&Services::creatures)},
{"factions", LuaCallWrapper<const Services>::createFunctor(&Services::factions)},
{"heroClasses", LuaCallWrapper<const Services>::createFunctor(&Services::heroClasses)},
{"heroTypes", LuaCallWrapper<const Services>::createFunctor(&Services::heroTypes)},
{"spells", LuaCallWrapper<const Services>::createFunctor(&Services::spells)},
{"skills", LuaCallWrapper<const Services>::createFunctor(&Services::skills)},
};
const std::vector<ServicesProxy::CustomRegType> ServicesProxy::REGISTER_CUSTOM =
{
};
VCMI_REGISTER_CORE_SCRIPT_API(ArtifactServiceProxy, "Artifacts");
const std::vector<ArtifactServiceProxy::RegType> ArtifactServiceProxy::REGISTER =
{
{"getByIndex", LuaCallWrapper<const EntityServiceT<ArtifactID, Artifact>>::createFunctor(&ArtifactService::getByIndex)}
};
const std::vector<ArtifactServiceProxy::CustomRegType> ArtifactServiceProxy::REGISTER_CUSTOM =
{
};
VCMI_REGISTER_CORE_SCRIPT_API(CreatureServiceProxy, "Creatures");
const std::vector<CreatureServiceProxy::RegType> CreatureServiceProxy::REGISTER =
{
{"getByIndex", LuaCallWrapper<const EntityServiceT<CreatureID, Creature>>::createFunctor(&CreatureService::getByIndex)}
};
const std::vector<CreatureServiceProxy::CustomRegType> CreatureServiceProxy::REGISTER_CUSTOM =
{
};
VCMI_REGISTER_CORE_SCRIPT_API(FactionServiceProxy, "Factions");
const std::vector<FactionServiceProxy::RegType> FactionServiceProxy::REGISTER =
{
{"getByIndex", LuaCallWrapper<const EntityServiceT<FactionID, Faction>>::createFunctor(&FactionService::getByIndex)}
};
const std::vector<FactionServiceProxy::CustomRegType> FactionServiceProxy::REGISTER_CUSTOM =
{
};
VCMI_REGISTER_CORE_SCRIPT_API(HeroClassServiceProxy, "HeroClasses");
const std::vector<HeroClassServiceProxy::RegType> HeroClassServiceProxy::REGISTER =
{
{"getByIndex", LuaCallWrapper<const EntityServiceT<HeroClassID, HeroClass>>::createFunctor(&HeroClassService::getByIndex)}
};
const std::vector<HeroClassServiceProxy::CustomRegType> HeroClassServiceProxy::REGISTER_CUSTOM =
{
};
VCMI_REGISTER_CORE_SCRIPT_API(HeroTypeServiceProxy, "HeroTypes");
const std::vector<HeroTypeServiceProxy::RegType> HeroTypeServiceProxy::REGISTER =
{
{"getByIndex", LuaCallWrapper<const EntityServiceT<HeroTypeID, HeroType>>::createFunctor(&HeroTypeService::getByIndex)}
};
const std::vector<HeroTypeServiceProxy::CustomRegType> HeroTypeServiceProxy::REGISTER_CUSTOM =
{
};
VCMI_REGISTER_CORE_SCRIPT_API(SkillServiceProxy, "Skills");
const std::vector<SkillServiceProxy::RegType> SkillServiceProxy::REGISTER =
{
{"getByIndex", LuaCallWrapper<const EntityServiceT<SecondarySkill, Skill>>::createFunctor(&SkillService::getByIndex)}
};
const std::vector<SkillServiceProxy::CustomRegType> SkillServiceProxy::REGISTER_CUSTOM =
{
};
VCMI_REGISTER_CORE_SCRIPT_API(SpellServiceProxy, "Spells");
const std::vector<SpellServiceProxy::RegType> SpellServiceProxy::REGISTER =
{
{"getByIndex", LuaCallWrapper<const EntityServiceT<SpellID, spells::Spell>>::createFunctor(&spells::Service::getByIndex)}
};
const std::vector<SpellServiceProxy::CustomRegType> SpellServiceProxy::REGISTER_CUSTOM =
{
};
}
}

View File

@ -0,0 +1,97 @@
/*
* api/Services.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/Services.h>
#include <vcmi/ArtifactService.h>
#include <vcmi/CreatureService.h>
#include <vcmi/FactionService.h>
#include <vcmi/HeroClassService.h>
#include <vcmi/HeroTypeService.h>
#include <vcmi/SkillService.h>
#include <vcmi/spells/Service.h>
#include "../LuaWrapper.h"
namespace scripting
{
namespace api
{
class ServicesProxy : public OpaqueWrapper<const Services, ServicesProxy>
{
public:
using Wrapper = OpaqueWrapper<const Services, ServicesProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
class ArtifactServiceProxy : public OpaqueWrapper<const ArtifactService, ArtifactServiceProxy>
{
public:
using Wrapper = OpaqueWrapper<const ArtifactService, ArtifactServiceProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
class CreatureServiceProxy : public OpaqueWrapper<const CreatureService, CreatureServiceProxy>
{
public:
using Wrapper = OpaqueWrapper<const CreatureService, CreatureServiceProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
class FactionServiceProxy : public OpaqueWrapper<const FactionService, FactionServiceProxy>
{
public:
using Wrapper = OpaqueWrapper<const FactionService, FactionServiceProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
class HeroClassServiceProxy : public OpaqueWrapper<const HeroClassService, HeroClassServiceProxy>
{
public:
using Wrapper = OpaqueWrapper<const HeroClassService, HeroClassServiceProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
class HeroTypeServiceProxy : public OpaqueWrapper<const HeroTypeService, HeroTypeServiceProxy>
{
public:
using Wrapper = OpaqueWrapper<const HeroTypeService, HeroTypeServiceProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
class SkillServiceProxy : public OpaqueWrapper<const SkillService, SkillServiceProxy>
{
public:
using Wrapper = OpaqueWrapper<const SkillService, SkillServiceProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
class SpellServiceProxy : public OpaqueWrapper<const spells::Service, SpellServiceProxy>
{
public:
using Wrapper = OpaqueWrapper<const spells::Service, SpellServiceProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,36 @@
/*
* api/Skill.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Skill.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(SkillProxy, "Skill");
const std::vector<SkillProxy::RegType> SkillProxy::REGISTER = {};
const std::vector<SkillProxy::CustomRegType> SkillProxy::REGISTER_CUSTOM =
{
{"getIconIndex", LuaMethodWrapper<Skill, int32_t(Entity:: *)()const, &Entity::getIconIndex>::invoke, false},
{"getIndex", LuaMethodWrapper<Skill, int32_t(Entity:: *)()const, &Entity::getIndex>::invoke, false},
{"getJsonKey", LuaMethodWrapper<Skill, const std::string &(Entity:: *)()const, &Entity::getJsonKey>::invoke, false},
{"getName", LuaMethodWrapper<Skill, const std::string &(Entity:: *)()const, &Entity::getName>::invoke, false},
};
}
}

32
scripting/lua/api/Skill.h Normal file
View File

@ -0,0 +1,32 @@
/*
* api/Skill.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/Skill.h>
#include "../LuaWrapper.h"
namespace scripting
{
namespace api
{
class SkillProxy : public OpaqueWrapper<const Skill, SkillProxy>
{
public:
using Wrapper = OpaqueWrapper<const Skill, SkillProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,57 @@
/*
* api/Spell.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Spell.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
namespace scripting
{
namespace api
{
using ::spells::Spell;
VCMI_REGISTER_CORE_SCRIPT_API(SpellProxy, "Spell");
//TODO:calculateDamage,forEachSchool
const std::vector<SpellProxy::RegType> SpellProxy::REGISTER =
{
{"getCost", LuaCallWrapper<const Spell>::createFunctor(&Spell::getCost)},
{"getBasePower", LuaCallWrapper<const Spell>::createFunctor(&Spell::getBasePower)},
{"getLevelPower", LuaCallWrapper<const Spell>::createFunctor(&Spell::getLevelPower)},
{"getLevelDescription", LuaCallWrapper<const Spell>::createFunctor(&Spell::getLevelDescription)},
};
const std::vector<SpellProxy::CustomRegType> SpellProxy::REGISTER_CUSTOM =
{
{"getIconIndex", LuaMethodWrapper<Spell, int32_t(Entity:: *)()const, &Entity::getIconIndex>::invoke, false},
{"getIndex", LuaMethodWrapper<Spell, int32_t(Entity:: *)()const, &Entity::getIndex>::invoke, false},
{"getJsonKey", LuaMethodWrapper<Spell, const std::string &(Entity:: *)()const, &Entity::getJsonKey>::invoke, false},
{"getName", LuaMethodWrapper<Spell, const std::string &(Entity:: *)()const, &Entity::getName>::invoke, false},
{"isAdventure", LuaMethodWrapper<Spell, bool(Spell:: *)()const, &Spell::isAdventure>::invoke, false},
{"isCombat", LuaMethodWrapper<Spell, bool(Spell:: *)()const, &Spell::isCombat>::invoke, false},
{"isCreatureAbility", LuaMethodWrapper<Spell, bool(Spell:: *)()const, &Spell::isCreatureAbility>::invoke, false},
{"isPositive", LuaMethodWrapper<Spell, bool(Spell:: *)()const, &Spell::isPositive>::invoke, false},
{"isNegative", LuaMethodWrapper<Spell, bool(Spell:: *)()const, &Spell::isNegative>::invoke, false},
{"isNeutral", LuaMethodWrapper<Spell, bool(Spell:: *)()const, &Spell::isNeutral>::invoke, false},
{"isDamage", LuaMethodWrapper<Spell, bool(Spell:: *)()const, &Spell::isDamage>::invoke, false},
{"isOffensive", LuaMethodWrapper<Spell, bool(Spell:: *)()const, &Spell::isOffensive>::invoke, false},
{"isSpecial", LuaMethodWrapper<Spell, bool(Spell:: *)()const, &Spell::isSpecial>::invoke, false},
};
}
}

31
scripting/lua/api/Spell.h Normal file
View File

@ -0,0 +1,31 @@
/*
* api/Spell.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/spells/Spell.h>
#include "../LuaWrapper.h"
namespace scripting
{
namespace api
{
class SpellProxy : public OpaqueWrapper<const ::spells::Spell, SpellProxy>
{
public:
using Wrapper = OpaqueWrapper<const ::spells::Spell, SpellProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,40 @@
/*
* StackInstance.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "StackInstance.h"
#include "Registry.h"
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
#include <vcmi/Creature.h>
namespace scripting
{
namespace api
{
VCMI_REGISTER_CORE_SCRIPT_API(StackInstanceProxy, "StackInstance");
const std::vector<StackInstanceProxy::RegType> StackInstanceProxy::REGISTER =
{
};
const std::vector<StackInstanceProxy::CustomRegType> StackInstanceProxy::REGISTER_CUSTOM =
{
{"getType", LuaMethodWrapper<CStackInstance, const Creature *(CStackBasicDescriptor:: *)()const, &CStackBasicDescriptor::getType>::invoke, false},
{"getCount", LuaMethodWrapper<CStackInstance, TQuantity(CStackBasicDescriptor:: *)()const, &CStackBasicDescriptor::getCount>::invoke, false},
};
}
}

View File

@ -0,0 +1,35 @@
/*
* StackInstance.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/HeroClass.h>
#include "../LuaWrapper.h"
#include "../../../lib/CCreatureSet.h"
namespace scripting
{
namespace api
{
class StackInstanceProxy : public OpaqueWrapper<const CStackInstance, StackInstanceProxy>
{
public:
using Wrapper = OpaqueWrapper<const CStackInstance, StackInstanceProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}

View File

@ -0,0 +1,63 @@
/*
* UnitProxy.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "UnitProxy.h"
#include "../../LuaStack.h"
#include "../../LuaCallWrapper.h"
#include "../Registry.h"
namespace scripting
{
namespace api
{
namespace battle
{
VCMI_REGISTER_SCRIPT_API(UnitProxy, "battle.Unit")
const std::vector<UnitProxy::RegType> UnitProxy::REGISTER =
{
{
"getMinDamage",
LuaCallWrapper<const IBonusBearer>::createFunctor(&IBonusBearer::getMinDamage)
},
{
"getMaxDamage",
LuaCallWrapper<const IBonusBearer>::createFunctor(&IBonusBearer::getMaxDamage)
},
{
"getAttack",
LuaCallWrapper<const IBonusBearer>::createFunctor(&IBonusBearer::getAttack)
},
{
"getDefense",
LuaCallWrapper<const IBonusBearer>::createFunctor(&IBonusBearer::getDefense)
},
{
"isAlive",
LuaCallWrapper<const Unit>::createFunctor(&Unit::alive)
},
{
"unitId",
LuaCallWrapper<const IUnitInfo>::createFunctor(&IUnitInfo::unitId)
}
};
const std::vector<UnitProxy::CustomRegType> UnitProxy::REGISTER_CUSTOM =
{
};
}
}
}

View File

@ -0,0 +1,38 @@
/*
* UnitProxy.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/scripting/Service.h>
#include "../../../../lib/battle/Unit.h"
#include "../../LuaWrapper.h"
namespace scripting
{
namespace api
{
namespace battle
{
using ::battle::IUnitInfo;
using ::battle::Unit;
class UnitProxy : public OpaqueWrapper<const Unit, UnitProxy>
{
public:
using Wrapper = OpaqueWrapper<const Unit, UnitProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}
}

View File

@ -0,0 +1,47 @@
/*
* AdventureEvents.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "AdventureEvents.h"
#include "../../LuaStack.h"
#include "../../LuaCallWrapper.h"
#include "../Registry.h"
#include "SubscriptionRegistryProxy.h"
namespace scripting
{
namespace api
{
namespace events
{
VCMI_REGISTER_SCRIPT_API(ObjectVisitStartedProxy, "events.ObjectVisitStarted");
const std::vector<ObjectVisitStartedProxy::RegType> ObjectVisitStartedProxy::REGISTER = {};
const std::vector<ObjectVisitStartedProxy::CustomRegType> ObjectVisitStartedProxy::REGISTER_CUSTOM =
{
{
"subscribeBefore",
&SubscriptionRegistryProxy<ObjectVisitStartedProxy>::subscribeBefore,
true
},
{
"subscribeAfter",
&SubscriptionRegistryProxy<ObjectVisitStartedProxy>::subscribeAfter,
true
},
};
}
}
}

View File

@ -0,0 +1,41 @@
/*
* AdventureEvents.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/events/AdventureEvents.h>
#include "../../LuaWrapper.h"
#include "EventBusProxy.h"
namespace scripting
{
namespace api
{
namespace events
{
using ::events::ObjectVisitStarted;
class ObjectVisitStartedProxy : public OpaqueWrapper<ObjectVisitStarted, ObjectVisitStartedProxy>
{
public:
using Wrapper = OpaqueWrapper<ObjectVisitStarted, ObjectVisitStartedProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}
}

View File

@ -0,0 +1,67 @@
/*
* BattleEvents.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "BattleEvents.h"
#include "../../LuaStack.h"
#include "../../LuaCallWrapper.h"
#include "../Registry.h"
#include "../../../../lib/battle/Unit.h"
#include "SubscriptionRegistryProxy.h"
namespace scripting
{
namespace api
{
namespace events
{
using ::events::ApplyDamage;
VCMI_REGISTER_SCRIPT_API(ApplyDamageProxy, "events.ApplyDamage");
const std::vector<ApplyDamageProxy::RegType> ApplyDamageProxy::REGISTER =
{
{
"getInitalDamage",
LuaCallWrapper<ApplyDamage>::createFunctor(&ApplyDamage::getInitalDamage)
},
{
"getDamage",
LuaCallWrapper<ApplyDamage>::createFunctor(&ApplyDamage::getDamage)
},
{
"setDamage",
LuaCallWrapper<ApplyDamage>::createFunctor(&ApplyDamage::setDamage)
},
{
"getTarget",
LuaCallWrapper<ApplyDamage>::createFunctor(&ApplyDamage::getTarget)
}
};
const std::vector<ApplyDamageProxy::CustomRegType> ApplyDamageProxy::REGISTER_CUSTOM =
{
{
"subscribeBefore",
&SubscriptionRegistryProxy<ApplyDamageProxy>::subscribeBefore,
true
},
{
"subscribeAfter",
&SubscriptionRegistryProxy<ApplyDamageProxy>::subscribeAfter,
true
}
};
}
}
}

View File

@ -0,0 +1,38 @@
/*
* BattleEvents.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/events/BattleEvents.h>
#include "../../LuaWrapper.h"
#include "EventBusProxy.h"
namespace scripting
{
namespace api
{
namespace events
{
class ApplyDamageProxy : public OpaqueWrapper<::events::ApplyDamage, ApplyDamageProxy>
{
public:
using Wrapper = OpaqueWrapper<::events::ApplyDamage, ApplyDamageProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}
}

View File

@ -0,0 +1,33 @@
/*
* EventBusProxy.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "EventBusProxy.h"
#include "../../LuaStack.h"
#include "../../LuaCallWrapper.h"
#include "../Registry.h"
namespace scripting
{
namespace api
{
namespace events
{
//No methods here, just an empty metatable for type safety.
VCMI_REGISTER_CORE_SCRIPT_API(EventBusProxy, "EventBus");
const std::vector<EventBusProxy::RegType> EventBusProxy::REGISTER = {};
const std::vector<EventBusProxy::CustomRegType> EventBusProxy::REGISTER_CUSTOM = {};
}
}
}

View File

@ -0,0 +1,34 @@
/*
* EventBusProxy.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/events/EventBus.h>
#include "../../LuaWrapper.h"
namespace scripting
{
namespace api
{
namespace events
{
class EventBusProxy : public OpaqueWrapper<::events::EventBus, EventBusProxy>
{
public:
using Wrapper = OpaqueWrapper<::events::EventBus, EventBusProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}
}

View File

@ -0,0 +1,94 @@
/*
* GenericEvents.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "GenericEvents.h"
#include "../../LuaStack.h"
#include "../../LuaCallWrapper.h"
#include "../Registry.h"
#include "SubscriptionRegistryProxy.h"
namespace scripting
{
namespace api
{
namespace events
{
using ::events::GameResumed;
using ::events::PlayerGotTurn;
using ::events::TurnStarted;
VCMI_REGISTER_SCRIPT_API(GameResumedProxy, "events.GameResumed");
VCMI_REGISTER_SCRIPT_API(PlayerGotTurnProxy, "events.PlayerGotTurn");
VCMI_REGISTER_SCRIPT_API(TurnStartedProxy, "events.TurnStarted");
const std::vector<GameResumedProxy::RegType> GameResumedProxy::REGISTER = {};
const std::vector<GameResumedProxy::CustomRegType> GameResumedProxy::REGISTER_CUSTOM =
{
{
"subscribeBefore",
&SubscriptionRegistryProxy<GameResumedProxy>::subscribeBefore,
true
},
{
"subscribeAfter",
&SubscriptionRegistryProxy<GameResumedProxy>::subscribeAfter,
true
}
};
const std::vector<PlayerGotTurnProxy::RegType> PlayerGotTurnProxy::REGISTER =
{
{
"getPlayer",
LuaCallWrapper<PlayerGotTurn>::createFunctor(&PlayerGotTurn::getPlayerIndex)
},
{
"setPlayer",
LuaCallWrapper<PlayerGotTurn>::createFunctor(&PlayerGotTurn::setPlayerIndex)
},
};
const std::vector<PlayerGotTurnProxy::CustomRegType> PlayerGotTurnProxy::REGISTER_CUSTOM =
{
{
"subscribeBefore",
&SubscriptionRegistryProxy<PlayerGotTurnProxy>::subscribeBefore,
true
},
{
"subscribeAfter",
&SubscriptionRegistryProxy<PlayerGotTurnProxy>::subscribeAfter,
true
}
};
const std::vector<TurnStartedProxy::RegType> TurnStartedProxy::REGISTER = {};
const std::vector<TurnStartedProxy::CustomRegType> TurnStartedProxy::REGISTER_CUSTOM =
{
{
"subscribeBefore",
&SubscriptionRegistryProxy<TurnStartedProxy>::subscribeBefore,
true
},
{
"subscribeAfter",
&SubscriptionRegistryProxy<TurnStartedProxy>::subscribeAfter,
true
}
};
}
}
}

View File

@ -0,0 +1,54 @@
/*
* GenericEvents.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/events/GenericEvents.h>
#include "../../LuaWrapper.h"
#include "EventBusProxy.h"
namespace scripting
{
namespace api
{
namespace events
{
class GameResumedProxy : public OpaqueWrapper<::events::GameResumed, GameResumedProxy>
{
public:
using Wrapper = OpaqueWrapper<::events::GameResumed, GameResumedProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
class PlayerGotTurnProxy : public OpaqueWrapper<::events::PlayerGotTurn, PlayerGotTurnProxy>
{
public:
using Wrapper = OpaqueWrapper<::events::PlayerGotTurn, PlayerGotTurnProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
class TurnStartedProxy : public OpaqueWrapper<::events::TurnStarted, TurnStartedProxy>
{
public:
using Wrapper = OpaqueWrapper<::events::TurnStarted, TurnStartedProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
}
}
}

View File

@ -0,0 +1,28 @@
/*
* SubscriptionRegistryProxy.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "SubscriptionRegistryProxy.h"
#include "../Registry.h"
namespace scripting
{
namespace api
{
namespace events
{
//No methods here, just an empty metatable for type safety.
VCMI_REGISTER_CORE_SCRIPT_API(EventSubscriptionProxy, "EventSubscription");
const std::vector<EventSubscriptionProxy::RegType> EventSubscriptionProxy::REGISTER = {};
const std::vector<EventSubscriptionProxy::CustomRegType> EventSubscriptionProxy::REGISTER_CUSTOM = {};
}
}
}

View File

@ -0,0 +1,131 @@
/*
* SubscriptionRegistryProxy.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <vcmi/events/Event.h>
#include <vcmi/events/EventBus.h>
#include <vcmi/events/SubscriptionRegistry.h>
#include "../../LuaWrapper.h"
#include "../../LuaStack.h"
#include "../../LuaReference.h"
namespace scripting
{
namespace api
{
namespace events
{
class EventSubscriptionProxy : public UniqueOpaqueWrapper<::events::EventSubscription, EventSubscriptionProxy>
{
public:
using Wrapper = UniqueOpaqueWrapper<::events::EventSubscription, EventSubscriptionProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
};
template <typename EventProxy>
class SubscriptionRegistryProxy
{
public:
using EventType = typename EventProxy::ObjectType;
using RegistryType = ::events::SubscriptionRegistry<EventType>;
static_assert(std::is_base_of<::events::Event, EventType>::value, "Invalid template parameter");
static int subscribeBefore(lua_State * L)
{
LuaStack S(L);
// subscription = subscribeBefore(eventBus, callback)
//TODO: use capture by move from c++14
auto callbackRef = std::make_shared<LuaReference>(L);
::events::EventBus * eventBus = nullptr;
if(!S.tryGet(1, eventBus))
{
S.push("No event bus");
return 1;
}
S.clear();
RegistryType * registry = EventType::getRegistry();
typename EventType::PreHandler callback = [=](EventType & event)
{
LuaStack S(L);
callbackRef->push();
S.push(&event);
if(lua_pcall(L, 1, 0, 0) != 0)
{
std::string msg;
S.tryGet(1, msg);
logMod->error("Script callback error: %s", msg);
}
S.clear();
};
std::unique_ptr<::events::EventSubscription> subscription = registry->subscribeBefore(eventBus, std::move(callback));
S.push(std::move(subscription));
return 1;
}
static int subscribeAfter(lua_State * L)
{
LuaStack S(L);
//TODO: use capture by move from c++14
auto callbackRef = std::make_shared<LuaReference>(L);
::events::EventBus * eventBus = nullptr;
if(!S.tryGet(1, eventBus))
{
S.push("No event bus");
return 1;
}
S.clear();
RegistryType * registry = EventType::getRegistry();
typename EventType::PostHandler callback = [=](const EventType & event)
{
LuaStack S(L);
callbackRef->push();
S.push(const_cast<EventType *>(&event)); //FIXME:
if(lua_pcall(L, 1, 0, 0) != 0)
{
std::string msg;
S.tryGet(1, msg);
logMod->error("Script callback error: %s", msg);
}
S.clear();
};
std::unique_ptr<::events::EventSubscription> subscription = registry->subscribeAfter(eventBus, std::move(callback));
S.push(std::move(subscription));
return 1;
}
};
}
}
}

View File

@ -0,0 +1,63 @@
/*
* api/netpacks/BattleLogMessage.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "BattleLogMessage.h"
#include "../../LuaStack.h"
#include "../Registry.h"
namespace scripting
{
namespace api
{
namespace netpacks
{
VCMI_REGISTER_SCRIPT_API(BattleLogMessageProxy, "netpacks.BattleLogMessage");
const std::vector<BattleLogMessageProxy::RegType> BattleLogMessageProxy::REGISTER =
{
{
"addText",
&BattleLogMessageProxy::addText
},
{
"toNetpackLight",
&PackForClientProxy<BattleLogMessageProxy>::toNetpackLight
},
};
const std::vector<BattleLogMessageProxy::CustomRegType> BattleLogMessageProxy::REGISTER_CUSTOM =
{
{"new", &Wrapper::constructor, true}
};
int BattleLogMessageProxy::addText(lua_State * L, std::shared_ptr<BattleLogMessage> object)
{
LuaStack S(L);
std::string text;
if(S.tryGet(1, text))
{
if(object->lines.empty())
object->lines.emplace_back();
object->lines.back() << text;
}
return S.retVoid();
}
}
}
}

View File

@ -0,0 +1,35 @@
/*
* api/netpacks/BattleLogMessage.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "PackForClient.h"
namespace scripting
{
namespace api
{
namespace netpacks
{
class BattleLogMessageProxy : public SharedWrapper<BattleLogMessage, BattleLogMessageProxy>
{
public:
using Wrapper = SharedWrapper<BattleLogMessage, BattleLogMessageProxy>;
static const std::vector<Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
static int addText(lua_State * L, std::shared_ptr<BattleLogMessage> object);
};
}
}
}

View File

@ -0,0 +1,89 @@
/*
* api/netpacks/BattleStackMoved.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "BattleStackMoved.h"
#include "../../LuaStack.h"
#include "../Registry.h"
namespace scripting
{
namespace api
{
namespace netpacks
{
VCMI_REGISTER_SCRIPT_API(BattleStackMovedProxy, "netpacks.BattleStackMoved");
const std::vector<BattleStackMovedProxy::RegType> BattleStackMovedProxy::REGISTER =
{
{
"addTileToMove",
&BattleStackMovedProxy::addTileToMove
},
{
"setUnitId",
&BattleStackMovedProxy::setUnitId
},
{
"setDistance",
&BattleStackMovedProxy::setDistance
},
{
"setTeleporting",
&BattleStackMovedProxy::setTeleporting
},
{
"toNetpackLight",
&PackForClientProxy<BattleStackMovedProxy>::toNetpackLight
}
};
const std::vector<BattleStackMovedProxy::CustomRegType> BattleStackMovedProxy::REGISTER_CUSTOM =
{
{"new", &Wrapper::constructor, true}
};
int BattleStackMovedProxy::addTileToMove(lua_State * L, std::shared_ptr<BattleStackMoved> object)
{
LuaStack S(L);
lua_Integer hex = 0;
if(!S.tryGetInteger(1, hex))
return S.retVoid();
object->tilesToMove.emplace_back(hex);
return S.retVoid();
}
int BattleStackMovedProxy::setUnitId(lua_State * L, std::shared_ptr<BattleStackMoved> object)
{
LuaStack S(L);
S.tryGet(1, object->stack);
return S.retVoid();
}
int BattleStackMovedProxy::setDistance(lua_State * L, std::shared_ptr<BattleStackMoved> object)
{
LuaStack S(L);
S.tryGet(1, object->distance);
return S.retVoid();
}
int BattleStackMovedProxy::setTeleporting(lua_State * L, std::shared_ptr<BattleStackMoved> object)
{
LuaStack S(L);
S.tryGet(1, object->teleporting);
return S.retVoid();
}
}
}
}

View File

@ -0,0 +1,39 @@
/*
* api/netpacks/BattleStackMoved.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "PackForClient.h"
namespace scripting
{
namespace api
{
namespace netpacks
{
class BattleStackMovedProxy : public SharedWrapper<BattleStackMoved, BattleStackMovedProxy>
{
public:
using Wrapper = SharedWrapper<BattleStackMoved, BattleStackMovedProxy>;
static const std::vector<Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
static int addTileToMove(lua_State * L, std::shared_ptr<BattleStackMoved> object);
static int setUnitId(lua_State * L, std::shared_ptr<BattleStackMoved> object);
static int setDistance(lua_State * L, std::shared_ptr<BattleStackMoved> object);
static int setTeleporting(lua_State * L, std::shared_ptr<BattleStackMoved> object);
};
}
}
}

View File

@ -0,0 +1,114 @@
/*
* api/netpacks/BattleUnitsChanged.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "BattleUnitsChanged.h"
#include "../../LuaStack.h"
#include "../Registry.h"
namespace scripting
{
namespace api
{
namespace netpacks
{
VCMI_REGISTER_SCRIPT_API(BattleUnitsChangedProxy, "netpacks.BattleUnitsChanged");
const std::vector<BattleUnitsChangedProxy::RegType> BattleUnitsChangedProxy::REGISTER =
{
{
"toNetpackLight",
&PackForClientProxy<BattleUnitsChangedProxy>::toNetpackLight
},
{
"add",
&BattleUnitsChangedProxy::add
},
{
"update",
&BattleUnitsChangedProxy::update
},
{
"resetState",
&BattleUnitsChangedProxy::resetState
},
{
"remove",
&BattleUnitsChangedProxy::remove
}
};
const std::vector<BattleUnitsChangedProxy::CustomRegType> BattleUnitsChangedProxy::REGISTER_CUSTOM =
{
{"new", &Wrapper::constructor, true}
};
int BattleUnitsChangedProxy::add(lua_State * L, std::shared_ptr<BattleUnitsChanged> object)
{
LuaStack S(L);
uint32_t id;
if(!S.tryGet(1, id))
return S.retVoid();
UnitChanges changes(id, BattleChanges::EOperation::ADD);
if(!S.tryGet(2, changes.data))
return S.retVoid();
if(!S.tryGet(3, changes.healthDelta))
changes.healthDelta = 0;
object->changedStacks.push_back(changes);
return S.retVoid();
}
int BattleUnitsChangedProxy::update(lua_State * L, std::shared_ptr<BattleUnitsChanged> object)
{
LuaStack S(L);
uint32_t id;
if(!S.tryGet(1, id))
return S.retVoid();
UnitChanges changes(id, BattleChanges::EOperation::UPDATE);
if(!S.tryGet(2, changes.data))
return S.retVoid();
if(!S.tryGet(3, changes.healthDelta))
changes.healthDelta = 0;
object->changedStacks.push_back(changes);
return S.retVoid();
}
int BattleUnitsChangedProxy::resetState(lua_State * L, std::shared_ptr<BattleUnitsChanged> object)
{
LuaStack S(L);
return S.retVoid();
}
int BattleUnitsChangedProxy::remove(lua_State * L, std::shared_ptr<BattleUnitsChanged> object)
{
LuaStack S(L);
return S.retVoid();
}
}
}
}

View File

@ -0,0 +1,38 @@
/*
* api/netpacks/BattleUnitsChanged.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "PackForClient.h"
namespace scripting
{
namespace api
{
namespace netpacks
{
class BattleUnitsChangedProxy : public SharedWrapper<BattleUnitsChanged, BattleUnitsChangedProxy>
{
public:
using Wrapper = SharedWrapper<BattleUnitsChanged, BattleUnitsChangedProxy>;
static const std::vector<Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
static int add(lua_State * L, std::shared_ptr<BattleUnitsChanged> object);
static int update(lua_State * L, std::shared_ptr<BattleUnitsChanged> object);
static int resetState(lua_State * L, std::shared_ptr<BattleUnitsChanged> object);
static int remove(lua_State * L, std::shared_ptr<BattleUnitsChanged> object);
};
}
}
}

View File

@ -0,0 +1,69 @@
/*
* api/netpacks/EntitiesChanged.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "EntitiesChanged.h"
#include "../../LuaStack.h"
#include "../Registry.h"
namespace scripting
{
namespace api
{
namespace netpacks
{
VCMI_REGISTER_SCRIPT_API(EntitiesChangedProxy, "netpacks.EntitiesChanged");
const std::vector<EntitiesChangedProxy::RegType> EntitiesChangedProxy::REGISTER =
{
{
"update",
&EntitiesChangedProxy::update
},
{
"toNetpackLight",
&PackForClientProxy<EntitiesChangedProxy>::toNetpackLight
},
};
const std::vector<EntitiesChangedProxy::CustomRegType> EntitiesChangedProxy::REGISTER_CUSTOM =
{
{"new", &Wrapper::constructor, true}
};
int EntitiesChangedProxy::update(lua_State * L, std::shared_ptr<EntitiesChanged> object)
{
LuaStack S(L);
EntityChanges changes;
int32_t metaIndex = 0;
if(!S.tryGet(1, metaIndex))
return S.retVoid();
changes.metatype = static_cast<Metatype>(metaIndex);
if(!S.tryGet(2, changes.entityIndex))
return S.retVoid();
if(!S.tryGet(3, changes.data))
return S.retVoid();
object->changes.push_back(changes);
return S.retVoid();
}
}
}
}

View File

@ -0,0 +1,36 @@
/*
* api/netpacks/EntitiesChanged.h part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "PackForClient.h"
namespace scripting
{
namespace api
{
namespace netpacks
{
class EntitiesChangedProxy : public SharedWrapper<EntitiesChanged, EntitiesChangedProxy>
{
public:
using Wrapper = SharedWrapper<EntitiesChanged, EntitiesChangedProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
static int update(lua_State * L, std::shared_ptr<EntitiesChanged> object);
};
}
}
}

View File

@ -0,0 +1,128 @@
/*
* api/netpacks/InfoWindow.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "InfoWindow.h"
#include "../../LuaStack.h"
#include "../Registry.h"
using scripting::api::netpacks::InfoWindowProxy;
using scripting::api::RegisterAPI;
VCMI_REGISTER_SCRIPT_API(InfoWindowProxy, "netpacks.InfoWindow")
namespace scripting
{
namespace api
{
namespace netpacks
{
const std::vector<InfoWindowProxy::RegType> InfoWindowProxy::REGISTER =
{
{
"addReplacement",
&InfoWindowProxy::addReplacement
},
{
"addText",
&InfoWindowProxy::addText
},
{
"setPlayer",
&InfoWindowProxy::setPlayer
},
{
"toNetpackLight",
&PackForClientProxy<InfoWindowProxy>::toNetpackLight
},
};
const std::vector<InfoWindowProxy::CustomRegType> InfoWindowProxy::REGISTER_CUSTOM =
{
{"new", &Wrapper::constructor, true}
};
int InfoWindowProxy::addReplacement(lua_State * L, std::shared_ptr<InfoWindow> object)
{
int top = lua_gettop(L);
if(top == 1)
{
if(lua_isstring(L, 1))
{
size_t len = 0;
auto raw = lua_tolstring(L, 1, &len);
std::string text(raw, len);
object->text.addReplacement(text);
}
else if(lua_isnumber(L, 1))
{
object->text.addReplacement(lua_tointeger(L, 1));
}
}
else if(top >= 2)
{
if(lua_isnumber(L, 1) && lua_isnumber(L, 2))
object->text.addReplacement(lua_tointeger(L, 1), lua_tointeger(L, 2));
}
lua_settop(L, 0);
return 0;
}
int InfoWindowProxy::addText(lua_State * L, std::shared_ptr<InfoWindow> object)
{
int top = lua_gettop(L);
if(top == 1)
{
if(lua_isstring(L, 1))
{
size_t len = 0;
auto raw = lua_tolstring(L, 1, &len);
std::string text(raw, len);
object->text << text;
}
else if(lua_isnumber(L, 1))
{
object->text << (lua_tointeger(L, 1));
}
}
if(top >= 2)
{
if(lua_isnumber(L, 1) && lua_isnumber(L, 2))
object->text.addTxt(lua_tointeger(L, 1), lua_tointeger(L, 2));
}
lua_settop(L, 0);
return 0;
}
int InfoWindowProxy::setPlayer(lua_State * L, std::shared_ptr<InfoWindow> object)
{
LuaStack S(L);
PlayerColor value;
if(S.tryGet(1, value))
object->player = value;
return S.retVoid();
}
}
}
}

View File

@ -0,0 +1,36 @@
/*
* api/netpacks/InfoWindow.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "PackForClient.h"
namespace scripting
{
namespace api
{
namespace netpacks
{
class InfoWindowProxy : public SharedWrapper<InfoWindow, InfoWindowProxy>
{
public:
using Wrapper = SharedWrapper<InfoWindow, InfoWindowProxy>;
static const std::vector<typename Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
static int addReplacement(lua_State * L, std::shared_ptr<InfoWindow> object);
static int addText(lua_State * L, std::shared_ptr<InfoWindow> object);
static int setPlayer(lua_State * L, std::shared_ptr<InfoWindow> object);
};
}
}
}

View File

@ -0,0 +1,39 @@
/*
* api/netpacks/PackForClient.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "../../LuaWrapper.h"
#include "../../../../lib/NetPacks.h"
namespace scripting
{
namespace api
{
namespace netpacks
{
template <typename Derived>
class PackForClientProxy
{
public:
static int toNetpackLight(lua_State * L, typename Derived::UDataType object)
{
lua_settop(L, 0);
lua_pushlightuserdata(L, static_cast<CPackForClient *>(object.get()));
return 1;
}
};
}
}
}

View File

@ -0,0 +1,133 @@
/*
* api/netpacks/SetResources.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "SetResources.h"
#include "../../LuaStack.h"
#include "../Registry.h"
namespace scripting
{
namespace api
{
namespace netpacks
{
VCMI_REGISTER_SCRIPT_API(SetResourcesProxy, "netpacks.SetResources");
const std::vector<SetResourcesProxy::RegType> SetResourcesProxy::REGISTER =
{
{"getAbs",&SetResourcesProxy::getAbs},
{"setAbs",&SetResourcesProxy::setAbs},
{"getPlayer",&SetResourcesProxy::getPlayer},
{"setPlayer",&SetResourcesProxy::setPlayer},
{"setAmount",&SetResourcesProxy::setAmount},
{"getAmount",&SetResourcesProxy::getAmount},
{"clear",&SetResourcesProxy::clear},
{
"toNetpackLight",
&PackForClientProxy<SetResourcesProxy>::toNetpackLight
},
};
const std::vector<SetResourcesProxy::CustomRegType> SetResourcesProxy::REGISTER_CUSTOM =
{
{"new", &Wrapper::constructor, true}
};
int SetResourcesProxy::getAbs(lua_State * L, std::shared_ptr<SetResources> object)
{
return LuaStack::quickRetBool(L, object->abs);
}
int SetResourcesProxy::setAbs(lua_State * L, std::shared_ptr<SetResources> object)
{
LuaStack S(L);
bool value = false;
if(S.tryGet(1, value))
object->abs = value;
return S.retVoid();
}
int SetResourcesProxy::getPlayer(lua_State * L, std::shared_ptr<SetResources> object)
{
LuaStack S(L);
S.clear();
S.push(object->player);
return 1;
}
int SetResourcesProxy::setPlayer(lua_State * L, std::shared_ptr<SetResources> object)
{
LuaStack S(L);
PlayerColor value;
if(S.tryGet(1, value))
object->player = value;
return S.retVoid();
}
int SetResourcesProxy::getAmount(lua_State * L, std::shared_ptr<SetResources> object)
{
LuaStack S(L);
Res::ERes type = Res::ERes::INVALID;
if(!S.tryGet(1, type))
return S.retVoid();
S.clear();
const TQuantity amount = vstd::atOrDefault(object->res, static_cast<size_t>(type), 0);
S.push(amount);
return 1;
}
int SetResourcesProxy::setAmount(lua_State * L, std::shared_ptr<SetResources> object)
{
LuaStack S(L);
Res::ERes type = Res::ERes::INVALID;
if(!S.tryGet(1, type))
return S.retVoid();
int typeIdx = static_cast<int>(type);
if(typeIdx < 0 || typeIdx >= object->res.size())
return S.retVoid();
TQuantity amount = 0;
if(!S.tryGet(2, amount))
return S.retVoid();
object->res.at(typeIdx) = amount;
return S.retVoid();
}
int SetResourcesProxy::clear(lua_State * L, std::shared_ptr<SetResources> object)
{
LuaStack S(L);
object->res.amin(0);
object->res.positive();
return S.retVoid();
}
}
}
}

View File

@ -0,0 +1,41 @@
/*
* api/netpacks/SetResources.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "PackForClient.h"
namespace scripting
{
namespace api
{
namespace netpacks
{
class SetResourcesProxy : public SharedWrapper<SetResources, SetResourcesProxy>
{
public:
using Wrapper = SharedWrapper<SetResources, SetResourcesProxy>;
static const std::vector<Wrapper::RegType> REGISTER;
static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
static int getAbs(lua_State * L, std::shared_ptr<SetResources> object);
static int setAbs(lua_State * L, std::shared_ptr<SetResources> object);
static int getPlayer(lua_State * L, std::shared_ptr<SetResources> object);
static int setPlayer(lua_State * L, std::shared_ptr<SetResources> object);
static int getAmount(lua_State * L, std::shared_ptr<SetResources> object);
static int setAmount(lua_State * L, std::shared_ptr<SetResources> object);
static int clear(lua_State * L, std::shared_ptr<SetResources> object);
};
}
}
}