// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/> // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. #include "mission_compiler.h" using namespace std; using namespace NLMISC; using namespace NLLIGO; class IVarFactory { public: virtual IVar *createVar(CMissionData &md, IPrimitive *prim) = 0; }; template <class VarClass> class CVarFactory : public IVarFactory { IVar *createVar(CMissionData &md, IPrimitive *prim) { return new VarClass(md, prim); } }; #define REGISTER_VAR_INDIRECT(varClass, key) typedef CVarFactory<varClass> TVarFactory##varClass; \ NLMISC_REGISTER_OBJECT_INDIRECT(IVarFactory, TVarFactory##varClass, string, string(key)); //#define REGISTER_VARIABLE(className, varName) NLMISC_REGISTER_OBJECT(IVar, className, std::string, string(varName)); /* Class for npc variable */ class CVarNpc : public IVar { public: CVarNpc(CMissionData &md, IPrimitive *prim) : IVar(vt_npc, prim) { _NpcLabel = getPrimProperty(prim, "npc_name"); _NpcFunction = getPrimProperty(prim, "npc_function"); if (!_NpcFunction.empty()) { _NpcFunction = "$"+_NpcFunction+"$"; } IVar *nameVar = CFactoryIndirect<IVarFactory, string>::instance().getFactory("var_npc_name")->createVar(md, prim); md.addVariable(prim, nameVar); } const std::string getNpcLabel() { return _NpcLabel; } const std::string getNpcFunction() { return _NpcFunction; } const std::string getNpcFullName() { return _NpcLabel+_NpcFunction; } string evalVar(const string &subPart) { if (subPart == "fullname") return getNpcFullName(); else if (subPart == "function") return _NpcFunction; else if (subPart == "") return _NpcLabel; throw EParseException(NULL, toString("var_npc don't have a subpart '%s'", subPart.c_str()).c_str()); } STRING_MANAGER::TParamType getStringManagerType() { return STRING_MANAGER::bot; } string genDecl(CMissionData &md) { return "decl : bot : "+evalVar("")+NL; } private: string _NpcLabel; string _NpcFunction; }; REGISTER_VAR_INDIRECT(CVarNpc, "var_npc"); /** Var for npc name (aka bot_name) * This class is implicitly instancied by * CVarNpc. */ class CVarNpcName : public IVar { public: CVarNpcName(CMissionData &md, IPrimitive *prim) : IVar(vt_npc, prim) { // Change the var name _VarName += "_name"; _NpcLabel = getPrimProperty(prim, "npc_name"); _NpcFunction = getPrimProperty(prim, "npc_function"); if (!_NpcFunction.empty()) { _NpcFunction = "$"+_NpcFunction+"$"; } } const std::string getNpcLabel() { return _NpcLabel; } const std::string getNpcFunction() { return _NpcFunction; } const std::string getNpcFullName() { return _NpcLabel+_NpcFunction; } string evalVar(const string &subPart) { if (subPart == "") return string("\"")+_NpcLabel+"\""; throw EParseException(NULL, toString("var_npc_name don't have a subpart '%s'", subPart.c_str()).c_str()); } STRING_MANAGER::TParamType getStringManagerType() { return STRING_MANAGER::bot_name; } string genDecl(CMissionData &md) { return string(); } private: string _NpcLabel; string _NpcFunction; }; REGISTER_VAR_INDIRECT(CVarNpcName, "var_npc_name"); /* Class for npc variable */ class CVarGroup : public IVar { public: CVarGroup(CMissionData &md, IPrimitive *prim) : IVar(vt_npc, prim) { _GroupName = getPrimProperty(prim, "group_name"); } string evalVar(const string &subPart) { if (subPart.empty()) return _GroupName; else if (subPart == "quoted") return string("\"")+_GroupName+"\""; else nlassert(false); return ""; } STRING_MANAGER::TParamType getStringManagerType() { return STRING_MANAGER::bot_name; } string genDecl(CMissionData &md) { // return "decl : bot : "+evalVar("no_quote")+NL; return "decl : bot : "+evalVar("")+NL; } private: string _GroupName; }; REGISTER_VAR_INDIRECT(CVarGroup, "var_group"); //NLMISC_REGISTER_OBJECT(IVar, CVarGroup, std::string, string("var_group")); /* Class for item */ class CVarItem : public IVar { public: CVarItem(CMissionData &md, IPrimitive *prim) : IVar(vt_item, prim) { _ItemSheet = getPrimProperty(prim, "item_sheet"); } const std::string getItemSheet() { return _ItemSheet; } string evalVar(const string &subPart) { nlassert(subPart.empty()); return _ItemSheet; } STRING_MANAGER::TParamType getStringManagerType() { return STRING_MANAGER::item; } string genDecl(CMissionData &md) { return "decl : item : "+evalVar("")+NL; } private: string _ItemSheet; }; REGISTER_VAR_INDIRECT(CVarItem, "var_item"); //NLMISC_REGISTER_OBJECT(IVar, CVarItem, std::string, string("var_item")); /* Class for race */ class CVarRace : public IVar { public: CVarRace(CMissionData &md, IPrimitive *prim) : IVar(vt_item, prim) { _Race = getPrimProperty(prim, "race"); } string evalVar(const string &subPart) { nlassert(subPart.empty()); return _Race; } STRING_MANAGER::TParamType getStringManagerType() { return STRING_MANAGER::race; } string genDecl(CMissionData &md) { return "decl : race : "+evalVar("")+NL; } private: string _Race; }; REGISTER_VAR_INDIRECT(CVarRace, "var_race"); /* Class for sphrase */ class CVarSPhrase : public IVar { public: CVarSPhrase(CMissionData &md, IPrimitive *prim) : IVar(vt_item, prim) { _SPhrase = getPrimProperty(prim, "sphrase_sheet"); } string evalVar(const string &subPart) { nlassert(subPart.empty()); return _SPhrase; } STRING_MANAGER::TParamType getStringManagerType() { return STRING_MANAGER::sphrase; } string genDecl(CMissionData &md) { return "decl : sphrase : "+evalVar("")+NL; } private: string _SPhrase; }; REGISTER_VAR_INDIRECT(CVarSPhrase, "var_sphrase"); /* Class for sbrick */ class CVarSBrick : public IVar { public: CVarSBrick(CMissionData &md, IPrimitive *prim) : IVar(vt_item, prim) { _SBrick = getPrimProperty(prim, "sbrick_sheet"); } string evalVar(const string &subPart) { nlassert(subPart.empty()); return _SBrick; } STRING_MANAGER::TParamType getStringManagerType() { return STRING_MANAGER::sbrick; } string genDecl(CMissionData &md) { return "decl : sbrick : "+evalVar("")+NL; } private: string _SBrick; }; REGISTER_VAR_INDIRECT(CVarSBrick, "var_sbrick"); /* for special item */ char *SpecialItemProp[] = { "Durability", "Weight", "SapLoad", "Dmg", "Speed", "Range", "DodgeModifier", "ParryModifier", "AdversaryDodgeModifier", "AdversaryParryModifier", "ProtectionFactor", "MaxSlashingProtection", "MaxBluntProtection", "MaxPiercingProtection", "HpBuff", "SapBuff", "StaBuff", "FocusBuff" }; struct TItemProperty { string PropName; string PropValue; }; /* Class for special item */ class CVarSpecialItem : public IVar { public: CVarSpecialItem(CMissionData &md, IPrimitive *prim) : IVar(vt_item, prim) { static bool init = false; static set<string> propertyNames; if (!init) { for (uint i=0; i<sizeof(SpecialItemProp)/sizeof(char*); ++i) propertyNames.insert(SpecialItemProp[i]); init = true; } _ItemSheet = getPrimProperty(prim, "item_sheet"); _ReqSkill = getPrimProperty(prim, "req_skill_level"); vector<string> vs; vs = getPrimPropertyArray(prim, "properties/values"); // parse the strings vector for (uint i=0; i<vs.size(); ++i) { vector<string> parts; explode(vs[i], string(" "), parts, true); if (!parts.empty() && parts.size() != 2) { string s = toString("Invalid special item property at line %u", i+1); throw EParseException(prim, s.c_str()); } if (parts.size() == 2) { TItemProperty ip; ip.PropName = parts[0]; ip.PropValue = parts[1]; if (propertyNames.find(ip.PropName) == propertyNames.end()) { string s = toString("Invalid property name '%s'", ip.PropName.c_str()); throw EParseException(prim, s.c_str()); } _Properties.push_back(ip); } } _Action = getPrimProperty(prim, "item_action"); vs.clear(); vs = getPrimPropertyArray(prim, "phrase_item_name"); _ItemPhrase.initPhrase(md, prim, vs); string s; s = getPrimProperty(prim, "no_drop"); _NoDrop = (s == "true"); } // const std::string getItemSheet() // { // return _ItemSheet; // } string evalVar(const string &subPart) { nlassert(subPart.empty()); return _VarName; } STRING_MANAGER::TParamType getStringManagerType() { return STRING_MANAGER::item; } string genDecl(CMissionData &md) { string ret = string("decl_item : ")+_VarName+" : "+_ItemSheet+" : "+_ReqSkill; if (!_Properties.empty() ||!_Action.empty()) ret += " : "; for (uint i=0; i<_Properties.size(); ++i) { TItemProperty &ip = _Properties[i]; ret += ip.PropName+" "+ip.PropValue; if (i < _Properties.size()-1 || !_Action.empty()) ret += "; "; } if (!_Action.empty()) ret += _Action; ret += " : "+_ItemPhrase.genScript(md); if (_NoDrop) ret += " : no_drop"; ret += NL; return ret; } std::string genPhrase() { return _ItemPhrase.genPhrase(); } private: /// the item sheet used as base for this special item string _ItemSheet; /// The skill required to use the item string _ReqSkill; /// The list of properties vector<TItemProperty> _Properties; // Optional action (enchantement) string _Action; // Name of the item CPhrase _ItemPhrase; // No drop flag bool _NoDrop; string _Color; }; REGISTER_VAR_INDIRECT(CVarSpecialItem, "var_special_item"); //NLMISC_REGISTER_OBJECT(IVar, CVarSpecialItem, std::string, string("var_special_item")); /* Class for place variable */ class CVarPlace : public IVar { public: CVarPlace(CMissionData &md, IPrimitive *prim) : IVar(vt_npc, prim) { _PlaceLabel = getPrimProperty(prim, "place_name"); } /* const std::string getPlaceLabel() { return _PlaceLabel; } */ string evalVar(const string &subPart) { nlassert(subPart.empty()); return _PlaceLabel; } STRING_MANAGER::TParamType getStringManagerType() { return STRING_MANAGER::place; } string genDecl(CMissionData &md) { return "decl : place : "+evalVar("")+NL; } private: string _PlaceLabel; }; REGISTER_VAR_INDIRECT(CVarPlace, "var_place"); //NLMISC_REGISTER_OBJECT(IVar, CVarPlace, std::string, string("var_place")); /* Class for integer variable */ class CVarInteger : public IVar { public: CVarInteger(CMissionData &md, IPrimitive *prim) : IVar(vt_integer, prim) { if (prim->checkProperty("value")) _Value = getPrimProperty(prim, "value"); else if (prim->checkProperty("quantity")) _Value = getPrimProperty(prim, "quantity"); else if (prim->checkProperty("quality")) _Value = getPrimProperty(prim, "quality"); else { string err = toString("Can't find a valid property for integer variable"); throw EParseException(prim, err.c_str()); } } const std::string getIntegerValue() { return _Value; } string evalVar(const string &subPart) { nlassert(subPart.empty()); return _Value;; } STRING_MANAGER::TParamType getStringManagerType() { return STRING_MANAGER::integer; } string genDecl(CMissionData &md) { // nothing to declare for this pseudo var return string(); } private: string _Value; }; REGISTER_VAR_INDIRECT(CVarInteger, "var_integer"); //NLMISC_REGISTER_OBJECT(IVar, CVarInteger, std::string, string("var_integer")); typedef CVarInteger CVarQuantity; REGISTER_VAR_INDIRECT(CVarQuantity, "var_quantity"); //NLMISC_REGISTER_OBJECT(IVar, CVarQuantity, std::string, string("var_quantity")); typedef CVarInteger CVarQuality; REGISTER_VAR_INDIRECT(CVarQuality, "var_quality"); //NLMISC_REGISTER_OBJECT(IVar, CVarQuality, std::string, string("var_quality")); /* Class for text var */ class CVarText : public IVar { public: CVarText(CMissionData &md, IPrimitive *prim) : IVar(vt_item, prim) { _TextValue = getPrimPropertyArray(prim, "text"); } const vector<std::string> &getText() { return _TextValue;; } string evalVar(const string &subPart) { nlassert(subPart.empty()); string t; return std::accumulate(_TextValue.begin(), _TextValue.end(), string("")); return t; } STRING_MANAGER::TParamType getStringManagerType() { nlassert(false); return STRING_MANAGER::NB_PARAM_TYPES; } string genDecl(CMissionData &md) { // nothing to declare for this one return string(); } private: vector<string> _TextValue; }; REGISTER_VAR_INDIRECT(CVarText, "var_text"); //NLMISC_REGISTER_OBJECT(IVar, CVarText, std::string, string("var_text")); /* Class for creature var */ class CVarCreature : public IVar { public: CVarCreature(CMissionData &md, IPrimitive *prim) : IVar(vt_item, prim) { _CreatureSheet = getPrimProperty(prim, "creature_sheet"); } string evalVar(const string &subPart) { nlassert(subPart.empty()); return _CreatureSheet; } STRING_MANAGER::TParamType getStringManagerType() { // return STRING_MANAGER::creature; return STRING_MANAGER::creature_model; } string genDecl(CMissionData &md) { // declare a creature sheet // return "decl : creature : "+_CreatureSheet+NL; return "decl : creature_model : "+_CreatureSheet+NL; } private: string _CreatureSheet; }; REGISTER_VAR_INDIRECT(CVarCreature, "var_creature"); //NLMISC_REGISTER_OBJECT(IVar, CVarCreature, std::string, string("var_creature")); /* Class for faction var */ class CVarFaction : public IVar { public: CVarFaction(CMissionData &md, IPrimitive *prim) : IVar(vt_item, prim) { _FactionName = getPrimProperty(prim, "faction_name"); } string evalVar(const string &subPart) { nlassert(subPart.empty()); return _FactionName; } STRING_MANAGER::TParamType getStringManagerType() { return STRING_MANAGER::faction; } string genDecl(CMissionData &md) { // declare a creature sheet return "decl : faction : "+_FactionName+NL; } private: string _FactionName; }; REGISTER_VAR_INDIRECT(CVarFaction, "var_faction"); //NLMISC_REGISTER_OBJECT(IVar, CVarFaction, std::string, string("var_faction")); // Variable factory. IVar *IVar::createVar(CMissionData &md, IPrimitive *prim) { string *c; if (!prim->getPropertyByName("class", c)) throw EParseException(prim, "Can't find property 'class' on primitive"); return CFactoryIndirect<IVarFactory, string>::instance().getFactory(*c)->createVar(md, prim); return NULL; }; //IVar *IVar::createVar(CMissionData &md, IPrimitive *prim) //{ // string *className; // if (!prim->getPropertyByName("class", className)) // throw EParseException(prim, "Can't find property 'class' in primitive"); // // IVar *ret = NLMISC_GET_FACTORY_INDIRECT(IVar, std::string).createObject(md, *className, prim); // // return ret; //} //