Linux multi-monitor fullscreen support
[ryzomcore.git] / ryzom / tools / leveldesign / mission_compiler_lib / steps.cpp
blob5e627bfa08288ed4c22b9bbc172944a71e1711a9
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2011 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "mission_compiler.h"
22 #include "step.h"
23 #include "nel/misc/factory.h"
24 #include <memory>
26 using namespace std;
27 using namespace NLMISC;
28 using namespace NLLIGO;
31 // *****
32 // IStep
33 // *****
35 IStep *IStep::createStep(CMissionData &md, IPrimitive *prim)
37 string *c;
38 if (!prim->getPropertyByName("class", c))
39 throw EParseException(prim, "Can't find property 'class' on primitive");
41 IStep *ret = CFactoryIndirect<IStepFactory, string>::instance().getFactory(*c)->createStep(md, prim);
42 ret->init(md, prim);
44 return ret;
47 IStep::IStep(CMissionData &md, NLLIGO::IPrimitive *prim)
48 : _Primitive(prim),
49 EndOfBranch(false),
50 JumpPoint(false)
52 if (prim == NULL)
53 return;
55 prim->getPropertyByName("class", _StepType);
56 prim->getPropertyByName("name", _StepName);
58 // parse the sub prim to create action & objectives;
59 IPrimitive *child;
60 // parse the preactions
62 TPrimitiveClassAndNamePredicate pred("actions", "pre_actions");
63 child = getPrimitiveChild(prim, pred);
66 if (child)
68 for (uint i=0; i<child->getNumChildren(); ++i)
70 IPrimitive *subChild;
71 child->getChild(subChild, i);
72 if (subChild)
74 // ok, we got one
75 IStepContent *sc = IStepContent::createStepContent(md, subChild);
76 if (sc)
77 _PreActions.push_back(sc);
81 // parse the objectives
83 TPrimitiveClassAndNamePredicate pred("mission_objectives", "objectives");
84 child = getPrimitiveChild(prim, pred);
86 if (child)
88 for (uint i=0; i<child->getNumChildren(); ++i)
90 IPrimitive *subChild;
91 child->getChild(subChild, i);
92 if (subChild)
94 // ok, we got one
95 IStepContent *sc = IStepContent::createStepContent(md, subChild);
96 if (sc)
97 _Objectives.push_back(sc);
101 // parse the post actions
103 TPrimitiveClassAndNamePredicate pred("actions", "post_actions");
104 child = getPrimitiveChild(prim, pred);
106 if (child)
108 for (uint i=0; i<child->getNumChildren(); ++i)
110 IPrimitive *subChild;
111 child->getChild(subChild, i);
112 if (subChild)
114 // ok, we got one
115 IStepContent *sc = IStepContent::createStepContent(md, subChild);
116 if (sc)
117 _PostActions.push_back(sc);
123 void IStep::fillStepJump(CMissionData &md, std::set<TJumpInfo> &jumpPoints)
125 uint i;
126 // extract step content jump points
127 for (i=0; i<_PreActions.size(); ++i)
129 _PreActions[i]->fillJump(md, jumpPoints);
131 for (i=0; i<_Objectives.size(); ++i)
133 _Objectives[i]->fillJump(md, jumpPoints);
135 for (i=0; i<_PostActions.size(); ++i)
137 _PostActions[i]->fillJump(md, jumpPoints);
140 fillJump(md, jumpPoints);
142 for (i = 0; i < _SubSteps.size(); ++i)
143 if (_SubSteps[i] != NULL)
144 _SubSteps[i]->fillStepJump(md, jumpPoints);
148 void IStep::fillJump(CMissionData &md, std::set<TJumpInfo> &jumpPoints)
150 // jump to the next step
151 IStep *next = md.getNextStep(this);
153 if (!EndOfBranch && next)
155 TJumpInfo ji(next->getStepName());
156 jumpPoints.insert(ji);
158 else
160 TJumpInfo ji("__end__");
161 jumpPoints.insert(ji);
165 std::string IStep::genCode(CMissionData &md)
167 string ret;
169 ret += genCodePreActions(md);
170 ret += genCodeObjectives(md);
171 ret += genCodePostActions(md);
173 return ret;
176 std::string IStep::genCodePreActions(CMissionData &md)
178 string ret;
179 // generate code for pre actions
180 for (uint i=0; i<_PreActions.size(); ++i)
182 ret += _PreActions[i]->genStepContentCode(md);
184 return ret;
187 std::string IStep::genCodeObjectives(CMissionData &md)
189 string ret;
190 // generate code for objectives
191 for (uint i=0; i<_Objectives.size(); ++i)
193 ret += _Objectives[i]->genStepContentCode(md);
195 return ret;
198 std::string IStep::genCodePostActions(CMissionData &md)
200 string ret;
201 //generate code for post actions
202 for (uint i=0; i<_PostActions.size(); ++i)
204 ret += _PostActions[i]->genStepContentCode(md);
206 return ret;
210 std::string IStep::genPhrase()
212 string ret;
213 // generate code for pre actions
214 for (uint i=0; i<_PreActions.size(); ++i)
216 ret += _PreActions[i]->genStepContentPhrase();
218 // generate code for objectives
219 for (uint i=0; i<_Objectives.size(); ++i)
221 ret += _Objectives[i]->genStepContentPhrase();
223 //generate code for post actions
224 for (uint i=0; i<_PostActions.size(); ++i)
226 ret += _PostActions[i]->genStepContentPhrase();
228 //generate code for sub steps
229 for (uint i=0; i<_SubSteps.size(); ++i)
231 ret += _SubSteps[i]->genPhrase();
234 return ret;
238 class CStep : public IStep
240 public:
241 CStep(CMissionData &md, IPrimitive *prim)
242 : IStep(md, prim)
244 // nothing special to do
248 REGISTER_STEP_INDIRECT(CStep, "step");
250 class CStepObjective : public CStep
252 public:
253 virtual void getPredefParam(uint32 &numEntry, CPhrase::TPredefParams &predef)
255 numEntry = 0;
256 predef.clear();
259 CStepObjective(CMissionData &md, IPrimitive *prim, const std::string &prefix = "")
260 : CStep(md, prim),
261 _Prefix(prefix),
262 _HideObj(false)
266 void init(CMissionData &md, IPrimitive *prim)
268 _HideObj = md.getProperty(prim, _Prefix + "hide_obj", true, false) == "true";
269 _OverloadObj = md.getPropertyArray(prim, _Prefix + "overload_objective", false, false);
270 _RoleplayObj = md.getPropertyArray(prim, _Prefix + "roleplay_objective", false, false);
271 uint32 numEntry;
272 CPhrase::TPredefParams params;
273 // ask derived class for predefined params
274 getPredefParam(numEntry, params);
275 _OverloadPhrase.initPhrase(md, prim, _OverloadObj, numEntry, params);
276 _RoleplayPhrase.initPhrase(md, prim, _RoleplayObj, numEntry, params);
279 virtual bool isAction() { return true; }
281 string genCode(CMissionData &md)
283 string ret;
284 if (_HideObj)
285 ret = "hide_obj" + NL;
286 if (!_OverloadObj.empty())
288 ret += "set_obj : " + _OverloadPhrase.genScript(md) + NL;
290 if (!_RoleplayObj.empty())
292 ret += "set_obj_rp : " + _RoleplayPhrase.genScript(md) + NL;
295 return ret;
298 string genPhrase()
300 string ret;
301 ret += _OverloadPhrase.genPhrase();
302 ret += _RoleplayPhrase.genPhrase();
304 ret += IStep::genPhrase();
306 return ret;
309 protected:
310 string _Prefix;
311 bool _HideObj;
312 vector<string> _OverloadObj;
313 CPhrase _OverloadPhrase;
314 vector<string> _RoleplayObj;
315 CPhrase _RoleplayPhrase;
318 class CStepDynChatTalkTo : public CStepObjective
320 // string _BotNameVar;
321 // string _BotName;
322 TCompilerVarName _BotName;
323 CPhrase _Phrase;
325 void getPredefParam(uint32 &numEntry, CPhrase::TPredefParams &predef)
327 numEntry = 0;
328 predef.resize(1);
329 predef[0].resize(1);
330 predef[0][0] = _BotName.getParamInfo();
331 // if (_BotNameVar.empty())
332 // predef[0][0] = CPhrase::TParamInfo("npc", STRING_MANAGER::bot);
333 // else
334 // predef[0][0] = CPhrase::TParamInfo(_BotNameVar, STRING_MANAGER::bot);
336 public:
337 CStepDynChatTalkTo(CMissionData &md, IPrimitive *prim, const std::string &prefix = "")
338 : CStepObjective(md, prim, prefix)
342 void init(CMissionData &md, IPrimitive *prim)
344 _BotName.init("npc", STRING_MANAGER::bot, md, prim, "npc_name");
345 // _BotNameVar = md.getProperty(prim, "npc_name", false, false);
346 // remove the variable tag if any
347 // untagVar(_BotNameVar);
349 // _BotName = md.getProperty(prim, "npc_name", true, false);
350 vector<string> vs;
351 vs = md.getPropertyArray(prim, "talk_to_menu", false, false);
352 CPhrase::TPredefParams pp(1);
353 pp[0].push_back(_BotName.getParamInfo());
354 // if (_BotNameVar.empty())
355 // pp[0].push_back(CPhrase::TParamInfo("npc", STRING_MANAGER::bot));
356 // else
357 // pp[0].push_back(CPhrase::TParamInfo(_BotNameVar, STRING_MANAGER::bot));
358 _Phrase.initPhrase(md, prim, vs, 0, pp);
360 // _Phrase.initPhrase(md, prim, vs);
362 // if (_Phrase.asAdditionnalParams())
363 // {
364 // // we need to remove the default 'npc' parameter if add params are found
365 // CPhrase temp;
366 // temp.initPhrase(md, prim, vs);
368 // _Phrase = temp;
369 // }
370 CStepObjective::init(md, prim);
373 string genCode(CMissionData &md)
375 string ret;
376 ret = CStepObjective::genCode(md);
378 ret += "talk_to : "+_BotName._VarValue;
380 if (!_Phrase.isEmpty())
381 ret += " : "+_Phrase.genScript(md);
382 ret += NL;
384 return ret;
387 string genPhrase()
389 string ret;
390 ret = CStepObjective::genPhrase();
391 ret += _Phrase.genPhrase();
393 return ret;
397 class CStepJump : public IStep
399 public:
400 CStepJump(CMissionData &md, IPrimitive *prim)
401 : IStep(md, prim)
403 _StepName = md.getProperty(prim, "target", true, false);
406 void fillJump(CMissionData &md, set<TJumpInfo> &jumpPoints)
408 jumpPoints.insert(TJumpInfo(_StepName, "", false));
411 string genCode(CMissionData &md)
413 string ret;
415 ret += "jump : " + _StepName + NL;
417 return ret;
420 bool isAJump()
422 return true;
425 string _StepName;
427 REGISTER_STEP_INDIRECT(CStepJump, "jump_to");
429 /// pseudo step used in step parsing
430 class CStepEnd : public IStep
432 public:
433 CStepEnd(CMissionData &md, IPrimitive *prim)
434 : IStep(md, prim)
438 string genCode(CMissionData &md)
440 string ret;
442 ret = "end"+NL;
444 return ret;
447 bool isEnd() { return true; }
450 REGISTER_STEP_INDIRECT(CStepEnd, "end");
452 class CStepFailure : public IStep
454 // Optional jump at end of failure
455 string _JumpTo;
456 public:
457 CStepFailure(CMissionData &md, IPrimitive *prim)
458 : IStep(md, prim)
460 // parse the sub prim to create action & objectives;
461 IPrimitive *child;
462 // parse the pre-actions
464 TPrimitiveClassAndNamePredicate pred("actions", "actions");
465 child = getPrimitiveChild(prim, pred);
467 if (child)
469 for (uint i=0; i<child->getNumChildren(); ++i)
471 IPrimitive *subChild;
472 child->getChild(subChild, i);
473 if (subChild)
475 // ok, we got one
476 IStepContent *sc = IStepContent::createStepContent(md, subChild);
477 if (sc)
478 _PreActions.push_back(sc);
482 // look for an optional jump
484 TPrimitiveClassPredicate pred("jump_to");
485 child = getPrimitiveChild(prim, pred);
487 if (child)
489 // ok, we have a jump at end of fail step
490 _JumpTo = md.getProperty(child, "target", true, false);
494 string genCode(CMissionData &md)
496 string ret;
498 ret = "failure" + NL;
500 string tmp = IStep::genCode(md);
501 tabulateLine(tmp, 1);
502 ret += tmp;
505 if (!_JumpTo.empty())
507 ret += "\tjump : "+_JumpTo + NL;
510 ret += "/failure"+NL;
512 return ret;
515 void fillJump(CMissionData &md, set<TJumpInfo> &jumpPoints)
517 IStep::fillJump(md, jumpPoints);
518 if (!_JumpTo.empty())
519 jumpPoints.insert(TJumpInfo(_JumpTo));
523 REGISTER_STEP_INDIRECT(CStepFailure, "step_failure");
525 class CStepCrash : public IStep
527 // Optional jump at end of failure
528 string _JumpTo;
529 vector<string> _AiInstances;
530 public:
531 CStepCrash(CMissionData &md, IPrimitive *prim)
532 : IStep(md, prim)
534 // parse the sub prim to create action & objectives;
535 IPrimitive *child;
536 // parse the pre-actions
538 TPrimitiveClassAndNamePredicate pred("actions", "actions");
539 child = getPrimitiveChild(prim, pred);
541 if (child)
543 for (uint i=0; i<child->getNumChildren(); ++i)
545 IPrimitive *subChild;
546 child->getChild(subChild, i);
547 if (subChild)
549 // ok, we got one
550 IStepContent *sc = IStepContent::createStepContent(md, subChild);
551 if (sc)
552 _PreActions.push_back(sc);
557 // parse ai instance list
558 vector<string> vs = md.getPropertyArray(prim, "ai_instances", true, false);
559 /* if (vs.empty())
561 string err = toString("crash block need at least one ai instance !");
562 throw EParseException(prim, err.c_str());
565 for (uint i=0; i<vs.size(); ++i)
567 _AiInstances.push_back(vs[i]);
570 // look for an optional jump
572 TPrimitiveClassPredicate pred("jump_to");
573 child = getPrimitiveChild(prim, pred);
575 if (child)
577 // ok, we have a jump at end of fail step
578 _JumpTo = md.getProperty(child, "target", true, false);
582 string genCode(CMissionData &md)
584 string ret;
586 ret = "crash";
588 if (!_AiInstances.empty())
590 ret += " :";
591 for (uint i=0; i<_AiInstances.size(); ++i)
593 ret += string(" ")+_AiInstances[i];
597 ret += NL;
599 string tmp = IStep::genCode(md);
600 tabulateLine(tmp, 1);
601 ret += tmp;
604 if (!_JumpTo.empty())
606 ret += "\tjump : "+_JumpTo + NL;
609 ret += "/crash"+NL;
611 return ret;
614 void fillJump(CMissionData &md, set<TJumpInfo> &jumpPoints)
616 IStep::fillJump(md, jumpPoints);
617 if (!_JumpTo.empty())
618 jumpPoints.insert(TJumpInfo(_JumpTo));
622 REGISTER_STEP_INDIRECT(CStepCrash, "step_crash");
624 // ///////////////////// //
625 // STEP PLAYER RECONNECT //
626 // ///////////////////// //
628 // ***************************************************************************
629 CStepPlayerReconnect::CStepPlayerReconnect(CMissionData &md, IPrimitive *prim) : IStep(md, prim)
631 // parse the sub prim to create action & objectives;
632 IPrimitive *child;
634 TPrimitiveSet resp;
636 TPrimitivePropertyPredicate pred("step_tag", "true");
637 filterPrimitiveChilds(prim, pred, resp);
639 for (uint i=0; i<resp.size(); ++i)
641 _SubBranchs.push_back(resp[i]);
644 // look for an optional jump
646 TPrimitiveClassPredicate pred("jump_to");
647 child = getPrimitiveChild(prim, pred);
649 if (child)
651 // ok, we have a jump at end of fail step
652 _JumpTo = md.getProperty(child, "target", true, false);
656 // ***************************************************************************
657 TPrimitiveSet CStepPlayerReconnect::getSubBranchs()
659 return _SubBranchs;
662 // ***************************************************************************
663 string CStepPlayerReconnect::genCode(CMissionData &md)
665 string ret;
667 ret = "player_reconnect"+NL;
669 string tmp = IStep::genCode(md);
670 tabulateLine(tmp, 1);
671 ret += tmp;
673 for (uint i = 0; i < _SubSteps.size(); ++i)
675 if ( md.isThereAJumpTo(_SubSteps[i]->getStepName()) )
677 // insert a jump point
678 ret += "jump_point : " + _SubSteps[i]->getStepName() + NL;
681 ret += _SubSteps[i]->genCode(md);
684 if (!_JumpTo.empty())
686 ret += "\tjump : "+_JumpTo + NL;
689 ret += "/player_reconnect"+NL;
691 return ret;
694 // ***************************************************************************
695 void CStepPlayerReconnect::fillJump(CMissionData &md, set<TJumpInfo> &jumpPoints)
697 IStep::fillJump(md, jumpPoints);
698 if (!_JumpTo.empty())
699 jumpPoints.insert(TJumpInfo(_JumpTo));
702 REGISTER_STEP_INDIRECT(CStepPlayerReconnect, "step_player_reconnect");
704 // //////////////////////////// //
705 // END OF STEP PLAYER RECONNECT //
706 // //////////////////////////// //
708 // ***************************************************************************
709 // get the jump point of a node. NB: if the node is itself a jump, then directly jump to its target
710 static std::string *getJumpTarget(IPrimitive *child)
712 if(!child)
713 return NULL;
715 // default: jump to the node
716 string *s= NULL;
717 child->getPropertyByName("name", s);
719 // if the node is a jump itself
720 string *className= NULL;
721 child->getPropertyByName("class", className);
722 if (className && *className == "jump_to")
724 // generate jump to the step jump target
725 child->getPropertyByName("target", s);
728 return s;
732 // ***************************************************************************
733 class CStepDynChat : public IStep
735 public:
736 CStepDynChat(CMissionData &md, IPrimitive *prim)
737 : IStep(md, prim)
739 _BotName = md.getProperty(prim, "npc_name", true, false);
740 vector<string> temp = md.getPropertyArray(prim, "phrase", false, false);
741 _Phrase.initPhrase(md, prim, temp);
742 // talk_to menu
743 temp = md.getPropertyArray(prim, "talk_to_menu", false, false);
744 // _TalkToMenu.initPhrase(md, prim, temp);
746 _TalkToObjective = NULL;
747 CUniquePtr<CStepDynChatTalkTo> talkToObjective; // next calls could throw exceptions, so take care...
748 if (!temp.empty())
750 talkToObjective.reset(new CStepDynChatTalkTo(md, prim, "talk_to_"));
751 talkToObjective->init(md, prim);
754 // build the sub branch list
755 IPrimitive *noResp;
757 TPrimitiveClassPredicate pred("no_answer");
758 noResp = getPrimitiveChild(prim, pred);
760 nlassert(noResp);
761 _SubBranchs.push_back(noResp);
763 TPrimitiveSet resp;
765 TPrimitiveClassPredicate pred("dyn_answer");
766 filterPrimitiveChilds(prim, pred, resp);
768 _Responses.resize(resp.size());
769 for (uint i=0; i<resp.size(); ++i)
771 _SubBranchs.push_back(resp[i]);
772 if (resp[i]->getNumChildren() == 0)
773 throw EParseException(prim, "missing step under 'dyn_answer' node for response");
775 vector<string> temp = md.getPropertyArray(resp[i], "phrase_answer", false, false);
776 _Responses[i].initPhrase(md, resp[i], temp);
778 _TalkToObjective = talkToObjective.release(); // commit result
780 ~CStepDynChat()
782 delete _TalkToObjective;
785 TPrimitiveSet getSubBranchs()
787 TPrimitiveSet vStepsToReturn;
788 for (uint i = 0; i < _SubBranchs.size(); ++i)
790 TPrimitiveSet childs;
792 TPrimitivePropertyPredicate pred("step_tag", "true");
793 filterPrimitiveChilds(_SubBranchs[i], pred, childs);
795 for (uint j = 0; j < childs.size(); ++j)
796 vStepsToReturn.push_back(childs[j]);
798 return vStepsToReturn;
801 void fillJump(CMissionData &md, set<TJumpInfo> &jumpPoints)
803 for (uint i=0; i<_SubBranchs.size(); ++i)
805 string *s;
806 IPrimitive *firstStep;
807 if (!_SubBranchs[i]->getChild(firstStep, 0))
808 throw EParseException(_Primitive, toString("Can't find child in %uth sub branch", i+1).c_str());
810 bool ret = firstStep->getPropertyByName("name", s);
811 if (!ret)
812 throw EParseException(_Primitive, toString("Can't find property 'name' in %uth sub branch", i+1).c_str());
814 string label;
815 _SubBranchs[i]->getPropertyByName("name", label);
816 jumpPoints.insert(TJumpInfo(*s, label));
820 string genCode(CMissionData &md)
822 string ret;
824 // if there's a talk_to menu, add it
825 // if (!_TalkToMenu.isEmpty())
826 if (_TalkToObjective != NULL)
828 ret += _TalkToObjective->genCode(md);
829 // ret += "talk_to : "+_BotName;
830 // ret += " : " + _TalkToMenu.genScript(md);
831 // ret += NL;
835 ret += "dyn_chat : " + _BotName + " : " + _Phrase.genScript(md);
837 for (uint i=1; i<_SubBranchs.size(); ++i)
839 IPrimitive *child;
840 _SubBranchs[i]->getChild(child, 0);
842 // get the jump target
843 string *s= getJumpTarget(child);
845 ret += " : " + *s + " " + _Responses[i-1].genScript(md);
848 ret += NL;
850 return ret;
853 string genPhrase()
855 string ret; /* = CStepObjective::genPhrase();*/
857 // if (!_TalkToMenu.isEmpty())
858 if (_TalkToObjective != NULL)
860 ret += _TalkToObjective->genPhrase();
861 // ret += _TalkToMenu.genPhrase();
864 ret += _Phrase.genPhrase();
866 for (uint i=0; i<_Responses.size(); ++i)
868 ret += _Responses[i].genPhrase();
870 return ret;
873 /// the list of sub branch for the dyn chat.
874 TPrimitiveSet _SubBranchs;
875 // phrase for the main text
876 CPhrase _Phrase;
877 // list of phrase for each response
878 vector<CPhrase> _Responses;
880 string _BotName;
882 // 'talk_to' part
883 // CPhrase _TalkToMenu;
884 CStepDynChatTalkTo *_TalkToObjective;
887 REGISTER_STEP_INDIRECT(CStepDynChat, "step_dyn_chat");
889 class CLinearDynChat : public IStep
891 enum TLinearMode
893 mode_fail,
894 mode_retry,
895 mode_continue,
896 // mode_skipable
899 TLinearMode _Mode;
900 string _BotName;
901 CPhrase _Phrase;
902 CPhrase _PhraseYes;
905 public:
908 CLinearDynChat(CMissionData &md, IPrimitive *prim)
909 : IStep(md, prim)
911 _BotName = md.getProperty(prim, "npc_name", true, false);
912 vector<string> temp = md.getPropertyArray(prim, "phrase", false, false);
913 _Phrase.initPhrase(md, prim, temp);
915 // set the linear mode
916 string className;
917 prim->getPropertyByName("class", className);
919 if (className == "linear_dyn_chat_fail")
920 _Mode = mode_fail;
921 else if (className == "linear_dyn_chat_retry")
922 _Mode = mode_retry;
923 else if (className == "linear_dyn_chat_continue")
924 _Mode = mode_continue;
925 else
927 string err = toString("Unknow class '%s' for dyn chat !", className.c_str());
928 throw EParseException(prim, err.c_str());
931 // read the response phrase
932 vector<string> phraseYes;
933 phraseYes = md.getPropertyArray(prim, "phrase_yes", false, false);
934 _PhraseYes.initPhrase(md, prim, phraseYes);
937 string genCode(CMissionData &md)
939 string ret;
941 switch (_Mode)
943 case mode_fail:
944 ret = "dyn_chat : "+_BotName+" : "+_Phrase.genScript(md)+" : "+_StepName+"_resp "+_PhraseYes.genScript(md)+NL;
945 ret += "fail"+NL;
946 ret += "jump_point : " +_StepName+"_resp"+NL;
947 break;
948 case mode_retry:
949 ret += "jump_point : " +_StepName+"_retry"+NL;
950 ret += "dyn_chat : "+_BotName+" : "+_Phrase.genScript(md)+" : "+_StepName+"_resp "+_PhraseYes.genScript(md)+NL;
951 ret += "jump : "+_StepName+"_retry"+NL;
952 ret += "jump_point : " +_StepName+"_resp"+NL;
953 break;
954 case mode_continue:
955 ret = "dyn_chat : "+_BotName+" : "+_Phrase.genScript(md)+" : "+_StepName+"_resp "+_PhraseYes.genScript(md)+NL;
956 ret += "jump_point : " +_StepName+"_resp"+NL;
957 break;
960 return ret;
963 string genPhrase()
965 string ret;
966 // ret = CStepObjective::genPhrase();
967 ret += _Phrase.genPhrase();
968 ret += _PhraseYes.genPhrase();
970 return ret;
974 typedef CLinearDynChat TLinearDynChatFail;
975 REGISTER_STEP_INDIRECT(TLinearDynChatFail, "linear_dyn_chat_fail");
976 typedef CLinearDynChat TLinearDynChatRetry;
977 REGISTER_STEP_INDIRECT(TLinearDynChatRetry, "linear_dyn_chat_retry");
978 typedef CLinearDynChat TLinearDynChatContinue;
979 REGISTER_STEP_INDIRECT(TLinearDynChatContinue, "linear_dyn_chat_continue");
981 // /////// //
982 // STEP IF //
983 // /////// //
985 CStepIf::CStepIf(CMissionData &md, IPrimitive *prim) : IStep(md, prim)
987 if (prim->getNumChildren() != 2)
988 throw EParseException(prim, toString("step_if need two child primitive for 'not_ok' and 'ok' clause, found %u child", prim->getNumChildren()).c_str());
990 IPrimitive *notOk = const_cast<IPrimitive *>(prim->getPrimitive("result_no"));
991 //prim->getChild(notOk, 0);
992 IPrimitive *ok = const_cast<IPrimitive *>(prim->getPrimitive("result_yes"));
993 //prim->getChild(ok, 1);
995 if (notOk == NULL)
996 throw EParseException(prim, "Can't find 'not ok' step branch");
997 if (ok == NULL)
998 throw EParseException(prim, "Can't find 'ok' step branch");
1000 string name;
1001 notOk->getPropertyByName("class", name);
1002 if (name != "result_no")
1003 throw EParseException(prim, toString("first child must be of class 'result_no', found '%s' instead", name.c_str()).c_str());
1004 ok->getPropertyByName("class", name);
1005 if (name != "result_yes")
1006 throw EParseException(prim, toString("second child must be of class 'result_yes', found '%s' instead", name.c_str()).c_str());
1008 // push in order : not ok, then ok
1009 _SubBranchs.push_back(notOk);
1010 _SubBranchs.push_back(ok);
1013 string s = md.getProperty(prim, "condition_type", true, false);
1014 if (s == "test_missions_done")
1015 _IfType = it_mission_done;
1016 else if (s == "test_skills_level")
1017 _IfType = it_skills;
1018 else if (s == "test_bricks_known")
1019 _IfType = it_bricks;
1020 else if (s == "test_sdb")
1021 _IfType = it_sdb;
1022 else if (s == "test_race")
1023 _IfType = it_race;
1024 else if (s == "test_cult")
1025 _IfType = it_cult;
1026 else if (s == "test_civ")
1027 _IfType = it_civ;
1028 else if (s == "test_faction_point")
1029 _IfType = it_faction_point;
1030 else if (s == "test_guild_civ")
1031 _IfType = it_guild_civ;
1032 else if (s == "test_guild_cult")
1033 _IfType = it_guild_cult;
1034 else if (s == "test_guild_fame")
1035 _IfType = it_guild_fame;
1036 else if (s == "test_no_trial")
1037 _IfType = it_no_trial;
1038 else if (s == "test_item_in_inv")
1039 _IfType = it_item_in_inv;
1040 else
1041 throw EParseException(prim, "Unknow test type !");
1043 _IfParams = md.getPropertyArray(prim, "test_parameters", true, false);
1046 TPrimitiveSet CStepIf::getSubBranchs()
1048 TPrimitiveSet vStepsToReturn;
1049 for (uint i = 0; i < _SubBranchs.size(); ++i)
1051 TPrimitiveSet childs;
1053 TPrimitivePropertyPredicate pred("step_tag", "true");
1054 filterPrimitiveChilds(_SubBranchs[i], pred, childs);
1056 for (uint j = 0; j < childs.size(); ++j)
1057 vStepsToReturn.push_back(childs[j]);
1059 return vStepsToReturn;
1062 void CStepIf::fillJump(CMissionData &md, set<TJumpInfo> &jumpPoints)
1064 /*string *s;
1065 TPrimitiveSet childs;
1066 bool ret;
1068 filterPrimitiveChilds(_SubBranchs[1], TPrimitivePropertyPredicate("step_tag", "true"), childs);
1069 if (!childs.empty())
1071 ret = childs[0]->getPropertyByName("name", s);
1072 if (!ret)
1073 throw EParseException(childs[0], "Can't find property 'name' in first step of 'ok' sub branch");
1075 jumpPoints.insert(TJumpInfo(*s, "yes"));
1078 // insert link to 'no' step
1079 childs.clear();
1080 filterPrimitiveChilds(_SubBranchs[0], TPrimitivePropertyPredicate("step_tag", "true"), childs);
1081 if (!childs.empty())
1083 ret = childs[0]->getPropertyByName("name", s);
1084 if (!ret)
1085 throw EParseException(childs[0], "Can't find property 'name' in first step of 'not ok' sub branch");
1087 jumpPoints.insert(TJumpInfo(*s, "no"));
1091 string CStepIf::genCode(CMissionData &md)
1093 string ret;
1095 uint32 i;
1097 TPrimitiveSet childs;
1098 vector<IStep*> yesSteps;
1099 vector<IStep*> noSteps;
1101 // Get the 'yes branch' jump point
1103 TPrimitivePropertyPredicate pred("step_tag", "true");
1104 filterPrimitiveChilds(_SubBranchs[1], pred, childs);
1106 if (!childs.empty())
1108 for (i = 0; i < _SubSteps.size(); ++i)
1109 if (std::find(childs.begin(), childs.end(), _SubSteps[i]->getPrimitive()) != childs.end())
1110 yesSteps.push_back(_SubSteps[i]);
1112 if (yesSteps.empty())
1114 string err = toString("In step '%s', can't find sub step in 'yes' sub branch", getStepName().c_str());
1115 throw EParseException(_SubBranchs[1]->getParent(), err.c_str());
1119 // Get the 'no branch' jump point
1120 childs.clear();
1122 TPrimitivePropertyPredicate pred("step_tag", "true");
1123 filterPrimitiveChilds(_SubBranchs[0], pred, childs);
1125 if (!childs.empty())
1127 for (i = 0; i < _SubSteps.size(); ++i)
1128 if (std::find(childs.begin(), childs.end(), _SubSteps[i]->getPrimitive()) != childs.end())
1129 noSteps.push_back(_SubSteps[i]);
1131 if (noSteps.empty())
1133 string err = toString("In step '%s', can't find sub step in 'no' sub branch", getStepName().c_str());
1134 throw EParseException(_SubBranchs[0]->getParent(), err.c_str());
1138 if ((yesSteps.empty()) && (noSteps.empty()))
1140 string err = toString("In step '%s', no yes-branch and no no-branch", getStepName().c_str());
1141 throw EParseException(_SubBranchs[0]->getParent(), err.c_str());
1144 string jumpToYes;
1145 if (!yesSteps.empty())
1146 jumpToYes = yesSteps[0]->getStepName();
1147 else
1148 jumpToYes = getStepName() + "_endif";
1151 // type of IF:
1152 switch(_IfType)
1154 case it_mission_done:
1155 if (_IfParams.empty())
1156 throw EParseException(_Primitive, "if_mission_done need at least one mission to test");
1157 for (uint i=0; i<_IfParams.size(); ++i)
1158 ret += "if_mission_done : " + _IfParams[i] + " : " + jumpToYes + NL;
1159 break;
1160 case it_skills:
1161 if (_IfParams.empty())
1162 throw EParseException(_Primitive, "if_skills need at least one <skill level> to test");
1163 ret = "if_skills : ";
1164 for (uint i=0; i<_IfParams.size(); ++i)
1166 ret += _IfParams[i];
1167 if (i < _IfParams.size()-1)
1168 ret += "; ";
1170 ret += " : " + jumpToYes + NL;
1171 break;
1172 case it_bricks:
1173 if (_IfParams.empty())
1174 throw EParseException(_Primitive, "if_bricks need at least one sbrick to test");
1175 ret = "if_bricks : ";
1176 for (uint i=0; i<_IfParams.size(); ++i)
1178 ret += _IfParams[i];
1179 if (i < _IfParams.size()-1)
1180 ret += "; ";
1182 ret += " : " + jumpToYes + NL;
1183 break;
1184 case it_sdb:
1185 if (_IfParams.empty())
1186 throw EParseException(_Primitive, "if_sdb need an expression to test");
1187 ret = "if_sdb : ";
1188 for (uint i=0; i<_IfParams.size(); ++i)
1190 ret += _IfParams[i];
1191 if (i < _IfParams.size()-1)
1192 ret += " ";
1194 ret += " : " + jumpToYes + NL;
1195 break;
1196 case it_race:
1197 if (_IfParams.empty())
1198 throw EParseException(_Primitive, "if_race need an expression to test");
1199 ret = "if_race : ";
1200 for (uint i=0; i<_IfParams.size(); ++i)
1202 ret += _IfParams[i];
1203 if (i < _IfParams.size()-1)
1204 ret += " ";
1206 ret += " : " + jumpToYes + NL;
1207 break;
1208 case it_cult:
1209 if (_IfParams.empty())
1210 throw EParseException(_Primitive, "if_cult need an expression to test");
1211 ret = "if_cult : ";
1212 for (uint i=0; i<_IfParams.size(); ++i)
1214 ret += _IfParams[i];
1215 if (i < _IfParams.size()-1)
1216 ret += " ";
1218 ret += " : " + jumpToYes + NL;
1219 break;
1220 case it_civ:
1221 if (_IfParams.empty())
1222 throw EParseException(_Primitive, "if_civ need an expression to test");
1223 ret = "if_civ : ";
1224 for (uint i=0; i<_IfParams.size(); ++i)
1226 ret += _IfParams[i];
1227 if (i < _IfParams.size()-1)
1228 ret += " ";
1230 ret += " : " + jumpToYes + NL;
1231 break;
1232 case it_faction_point:
1233 if (_IfParams.empty())
1234 throw EParseException(_Primitive, "if_faction_point need an expression to test");
1235 ret = "if_faction_point : ";
1236 for (uint i=0; i<_IfParams.size(); ++i)
1238 ret += _IfParams[i];
1239 if (i < _IfParams.size()-1)
1240 ret += " ";
1242 ret += " : " + jumpToYes + NL;
1243 break;
1244 case it_guild_civ:
1245 if (_IfParams.empty())
1246 throw EParseException(_Primitive, "it_guild_civ need an expression to test");
1247 ret = "if_guild_civ : ";
1248 for (uint i=0; i<_IfParams.size(); ++i)
1250 ret += _IfParams[i];
1251 if (i < _IfParams.size()-1)
1252 ret += " ";
1254 ret += " : " + jumpToYes + NL;
1255 break;
1256 case it_guild_cult:
1257 if (_IfParams.empty())
1258 throw EParseException(_Primitive, "it_guild_cult need an expression to test");
1259 ret = "if_guild_cult : ";
1260 for (uint i=0; i<_IfParams.size(); ++i)
1262 ret += _IfParams[i];
1263 if (i < _IfParams.size()-1)
1264 ret += " ";
1266 ret += " : " + jumpToYes + NL;
1267 break;
1268 case it_guild_fame:
1269 if (_IfParams.empty())
1270 throw EParseException(_Primitive, "it_guild_fame need an expression to test");
1271 ret = "if_guild_fame : ";
1272 for (uint i=0; i<_IfParams.size(); ++i)
1274 ret += _IfParams[i];
1275 if (i < _IfParams.size()-1)
1276 ret += " ";
1278 ret += " : " + jumpToYes + NL;
1279 break;
1280 case it_no_trial:
1281 ret = "if_no_trial : " + jumpToYes + NL;
1282 break;
1283 case it_item_in_inv:
1284 if (_IfParams.empty())
1285 throw EParseException(_Primitive, "if_item_in_inv need at least one mission to test");
1286 for (uint i=0; i<_IfParams.size(); ++i)
1287 ret += "if_item_in_inv : " + _IfParams[i] + " : " + jumpToYes + NL;
1288 break;
1291 // Generate the 'no branch'
1293 if (!noSteps.empty())
1295 ret += "# no: " + noSteps[0]->getStepName() + NL;
1296 for (uint i = 0; i < noSteps.size(); ++i)
1298 if ( md.isThereAJumpTo(noSteps[i]->getStepName()) )
1300 // insert a jump point
1301 ret += "jump_point : " + noSteps[i]->getStepName() + NL;
1304 ret += noSteps[i]->genCode(md);
1308 // Generate the 'yes branch'
1310 if (!yesSteps.empty())
1312 ret += "jump : " + getStepName() + "_endif" + NL;
1313 ret += "# yes: " + yesSteps[0]->getStepName() + NL;
1315 for (uint i = 0; i < yesSteps.size(); ++i)
1317 if ((i == 0) || md.isThereAJumpTo(yesSteps[i]->getStepName()) )
1319 // insert a jump point
1320 ret += "jump_point : " + yesSteps[i]->getStepName() + NL;
1323 ret += yesSteps[i]->genCode(md);
1327 // Generate ending jump point
1329 ret += "jump_point : " + getStepName() + "_endif" + NL;
1331 return ret;
1334 REGISTER_STEP_INDIRECT(CStepIf, "step_if");
1336 // ////////////// //
1337 // END OF STEP IF //
1338 // ////////////// //
1340 class CStepOOO : public CStepObjective
1342 public:
1343 CStepOOO(CMissionData &md, IPrimitive *prim)
1344 : CStepObjective(md, prim)
1349 string genCode(CMissionData &md)
1351 string ret;
1353 ret += CStepObjective::genCode(md);
1355 ret += IStep::genCodePreActions(md);
1357 ret += "ooo" + NL;
1359 string tmp = IStep::genCodeObjectives(md);
1360 tabulateLine(tmp, 1);
1361 ret += tmp;
1363 ret += "/ooo"+NL;
1365 ret += genCodePostActions(md);
1367 return ret;
1371 REGISTER_STEP_INDIRECT(CStepOOO, "step_ooo");
1373 class CStepAny : public CStepObjective
1375 public:
1376 CStepAny(CMissionData &md, IPrimitive *prim)
1377 : CStepObjective(md, prim)
1381 string genCode(CMissionData &md)
1383 string ret;
1385 ret += CStepObjective::genCode(md);
1387 ret += IStep::genCodePreActions(md);
1389 ret += "any" + NL;
1391 string tmp = IStep::genCodeObjectives(md);
1392 tabulateLine(tmp, 1);
1394 ret += tmp;
1396 ret += "/any"+NL;
1398 ret += genCodePostActions(md);
1400 return ret;
1404 REGISTER_STEP_INDIRECT(CStepAny, "step_any");