SGBindingList _bindings;
std::set<State*> _sourceStates; ///< weak refs to source states
State* _target;
+ bool _excludeTarget;
SGSharedPtr<SGCondition> _condition;
};
assert(aTarget);
d->_name = aName;
d->_target = aTarget;
+ d->_excludeTarget = true;
}
StateMachine::Transition::~Transition()
bool StateMachine::Transition::applicableForState(State* aCurrent) const
{
+ if (d->_excludeTarget && (aCurrent == d->_target)) {
+ return false;
+ }
+
+ if (d->_sourceStates.empty()) {
+ return true;
+ }
return d->_sourceStates.count(aCurrent);
}
d->_bindings.push_back(aBinding);
}
+void StateMachine::Transition::setExcludeTarget(bool aExclude)
+{
+ d->_excludeTarget = aExclude;
+}
+
///////////////////////////////////////////////////////////////////////////
StateMachine::StateMachine() :
return t;
}
-StateMachine* StateMachine::createFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
+void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
{
- StateMachine* sm = new StateMachine;
-
+ std::string path = desc->getStringValue("branch");
+ if (!path.empty()) {
+ d->_root = root->getNode(path, 0, true);
+ assert(d->_root);
+ }
BOOST_FOREACH(SGPropertyNode* stateDesc, desc->getChildren("state")) {
std::string nm = stateDesc->getStringValue("name");
readBindingList(stateDesc, "exit", root, st->d->_entryBindings);
readBindingList(stateDesc, "update", root, st->d->_exitBindings);
- sm->addState(st);
+ addState(st);
} // of states iteration
BOOST_FOREACH(SGPropertyNode* tDesc, desc->getChildren("transition")) {
std::string nm = tDesc->getStringValue("name");
- State_ptr target = sm->findStateByName(tDesc->getStringValue("target"));
+ State_ptr target = findStateByName(tDesc->getStringValue("target"));
SGCondition* cond = sgReadCondition(root, tDesc->getChild("condition"));
Transition_ptr t(new Transition(nm, target));
t->setTriggerCondition(cond);
+ t->setExcludeTarget(tDesc->getBoolValue("exclude-target", true));
BOOST_FOREACH(SGPropertyNode* src, desc->getChildren("source")) {
- State_ptr srcState = sm->findStateByName(src->getStringValue());
+ State_ptr srcState = findStateByName(src->getStringValue());
t->addSourceState(srcState);
}
readBindingList(tDesc, "binding", root, t->d->_bindings);
- sm->addTransition(t);
+ addTransition(t);
} // of states iteration
+ init();
+}
+
+StateMachine* StateMachine::createFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
+{
+ StateMachine* sm = new StateMachine;
+ sm->initFromPlist(desc, root);
return sm;
}
std::string name() const;
+ /**
+ * Set if the target state should automatically be excluded
+ * from the source state. Defaults to true, can be cleared
+ * to allow a state to re-enter itself
+ */
+ void setExcludeTarget(bool aExclude);
+
+
/**
* The state we end in, after this transition fires
*/
typedef SGSharedPtr<State> State_ptr;
typedef SGSharedPtr<Transition> Transition_ptr;
+ void initFromPlist(SGPropertyNode* desc, SGPropertyNode* root);
+
/**
* create a state machine from a property list description
*/
}
}
+void testNoSourcesTransition()
+{
+ BUILD_MACHINE_1();
+
+ DummyCondition* trigger4 = new DummyCondition;
+ StateMachine::Transition_ptr t4 = sm->createTransition("alwaysToA", stateA); \
+ t4->setTriggerCondition(trigger4); \
+ sm->init();
+
+ COMPARE(sm->state()->name(), "a");
+ trigger1->_state = true;
+ sm->update(1.0);
+ trigger1->_state = false;
+ COMPARE(sm->state()->name(), "b");
+
+ trigger4->_state = true;
+ sm->update(1.0);
+ trigger4->_state = false;
+ COMPARE(sm->state()->name(), "a");
+}
+
void testBindings()
{
SGCommandMgr* cmdMgr = SGCommandMgr::instance();
testBasic();
testBindings();
testParse();
+ testNoSourcesTransition();
+
cout << __FILE__ << ": All tests passed" << endl;
return EXIT_SUCCESS;
}