@@ -0,0 +1,61 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BB_MONITOR_H_
#define _BB_MONITOR_H_

#ifndef _BB_DECORATOR_H_
#include "BadBehavior/core/Decorator.h"
#endif

namespace BadBehavior
{
//---------------------------------------------------------------------------
// Monitor decorator
// outputs the return status to the console,
//---------------------------------------------------------------------------
class Monitor : public DecoratorNode
{
typedef DecoratorNode Parent;

public:
virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner);

DECLARE_CONOBJECT(Monitor);
};

//---------------------------------------------------------------------------
// Monitor decorator task
//---------------------------------------------------------------------------
class MonitorTask : public DecoratorTask
{
typedef DecoratorTask Parent;

public:
MonitorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner);

virtual void onChildComplete(Status s);
};

} // namespace BadBehavior

#endif
@@ -0,0 +1,75 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "Root.h"

using namespace BadBehavior;

//------------------------------------------------------------------------------
// Root decorator node
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(Root);

Task *Root::createTask(SimObject &owner, BehaviorTreeRunner &runner)
{
return new RootTask(*this, owner, runner);
}

//------------------------------------------------------------------------------
// Root decorator task
//------------------------------------------------------------------------------
RootTask::RootTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner)
: Parent(node, owner, runner),
mBranch(NULL)
{
}

RootTask::~RootTask()
{
if(mBranch)
delete mBranch;
}

void RootTask::onInitialize()
{
Parent::onInitialize();
if(!mBranch)
mBranch = new BehaviorTreeBranch(mChild);
else
mBranch->reset();
}

Task *RootTask::update()
{
mStatus = mBranch->update();

mIsComplete = mStatus != RUNNING && mStatus != SUSPENDED;
return NULL;
}

Status RootTask::getStatus()
{
if(mStatus == SUSPENDED)
return mBranch->getStatus();

return mStatus;
}
@@ -0,0 +1,73 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BB_ROOT_H_
#define _BB_ROOT_H_

#ifndef _BB_BRANCH_H_
#include "BadBehavior/core/Branch.h"
#endif
#ifndef _BB_DECORATOR_H_
#include "BadBehavior/core/Decorator.h"
#endif

namespace BadBehavior
{
//---------------------------------------------------------------------------
// Root decorator
// A placeholder node to mark the start of a tree.
// Used by the editor, bypassed during tree evaluation.
//---------------------------------------------------------------------------
class Root : public DecoratorNode
{
typedef DecoratorNode Parent;

public:
virtual Task* createTask(SimObject &owner, BehaviorTreeRunner &runner);

DECLARE_CONOBJECT(Root);
};

//---------------------------------------------------------------------------
// Root task
//---------------------------------------------------------------------------
class RootTask : public DecoratorTask
{
typedef DecoratorTask Parent;

protected:
BehaviorTreeBranch *mBranch;

virtual Task* update();
virtual void onInitialize();
//virtual void onTerminate();

public:
RootTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner);
virtual ~RootTask();

virtual Status getStatus();
};

} // namespace BadBehavior

#endif
@@ -0,0 +1,51 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "SucceedAlways.h"

using namespace BadBehavior;

//------------------------------------------------------------------------------
// SucceedAlways decorator node
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(SucceedAlways);

Task *SucceedAlways::createTask(SimObject &owner, BehaviorTreeRunner &runner)
{
return new SucceedAlwaysTask(*this, owner, runner);
}

//------------------------------------------------------------------------------
// SucceedAlways decorator task
//------------------------------------------------------------------------------
SucceedAlwaysTask::SucceedAlwaysTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner)
: Parent(node, owner, runner)
{
}

void SucceedAlwaysTask::onChildComplete(Status s)
{
Parent::onChildComplete(s);
if(mStatus == FAILURE)
mStatus = SUCCESS;
}

@@ -0,0 +1,61 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BB_SUCCEEDALWAYS_H_
#define _BB_SUCCEEDALWAYS_H_

#ifndef _BB_DECORATOR_H_
#include "BadBehavior/core/Decorator.h"
#endif

namespace BadBehavior
{
//---------------------------------------------------------------------------
// SucceedAlways decorator
// Returns SUCCESS if child returns SUCCESS or FAILURE. RUNNING and INVALID are unchanged
//---------------------------------------------------------------------------
class SucceedAlways : public DecoratorNode
{
typedef DecoratorNode Parent;

public:
virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner);

DECLARE_CONOBJECT(SucceedAlways);
};

//---------------------------------------------------------------------------
// SucceedAlways task
//---------------------------------------------------------------------------
class SucceedAlwaysTask : public DecoratorTask
{
typedef DecoratorTask Parent;

public:
SucceedAlwaysTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner);

virtual void onChildComplete(Status s);
};

} // namespace BadBehavior

#endif
@@ -0,0 +1,136 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "Ticker.h"
#include "BadBehavior/core/Runner.h"

#include "console/consoleTypes.h"

using namespace BadBehavior;

//------------------------------------------------------------------------------
// Ticker decorator node
// **** EXPERIMENTAL ****
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(Ticker);

Ticker::Ticker()
: mFrequencyMs(100)
{
}

void Ticker::initPersistFields()
{
addGroup( "Behavior" );

addProtectedField( "frequencyMs", TypeS32, Offset(mFrequencyMs, Ticker), &_setFrequency, &defaultProtectedGetFn,
"The time to wait between evaluations of this nodes child." );

endGroup( "Behavior" );

Parent::initPersistFields();
}

bool Ticker::_setFrequency(void *object, const char *index, const char *data)
{
Ticker *node = static_cast<Ticker *>( object );
node->mFrequencyMs = getMax(0, dAtoi( data ));
return false;
}

Task *Ticker::createTask(SimObject &owner, BehaviorTreeRunner &runner)
{
return new TickerTask(*this, owner, runner);
}

//------------------------------------------------------------------------------
// Ticker decorator task
//------------------------------------------------------------------------------
TickerTask::TickerTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner)
: Parent(node, owner, runner),
mNextTimeMs(0),
mEventId(0),
mBranch(NULL)
{
}

TickerTask::~TickerTask()
{
cancelEvent();

if(mBranch)
delete mBranch;
}

void TickerTask::cancelEvent()
{
if(Sim::isEventPending(mEventId))
{
Sim::cancelEvent(mEventId);
mEventId = 0;
}
}

void TickerTask::onInitialize()
{
Parent::onInitialize();
cancelEvent();
if(!mBranch)
mBranch = new BehaviorTreeBranch(mChild);
else
mBranch->reset();
}

void TickerTask::onTerminate()
{
Parent::onTerminate();
cancelEvent();
}

Task* TickerTask::update()
{
if(Sim::getCurrentTime() < mNextTimeMs)
{
if(!Sim::isEventPending(mEventId))
mEventId = Sim::postEvent(mRunner, new TaskReactivateEvent(*this), mNextTimeMs);

mStatus = SUSPENDED;
}
else if(mStatus != SUSPENDED)
{
mNextTimeMs = Sim::getCurrentTime() + static_cast<Ticker *>(mNodeRep)->getFrequencyMs();
Status s = mBranch->update();
mStatus = s != SUSPENDED ? s : RUNNING;
}

mIsComplete = mStatus != SUSPENDED && mStatus != RUNNING;

return NULL;
}

Status TickerTask::getStatus()
{
if(mStatus != SUSPENDED && mStatus != RESUME)
return mBranch->getStatus();

return mStatus;
}
@@ -0,0 +1,89 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BB_TICKER_H_
#define _BB_TICKER_H_

#ifndef _BB_DECORATOR_H_
#include "BadBehavior/core/Decorator.h"
#endif
#ifndef _BB_BRANCH_H_
#include "BadBehavior/core/Branch.h"
#endif

namespace BadBehavior
{
//---------------------------------------------------------------------------
// Ticker decorator
// Limits the frequency at which it's children are updated.
//---------------------------------------------------------------------------
class Ticker : public DecoratorNode
{
typedef DecoratorNode Parent;

protected:
static bool _setFrequency(void *object, const char *index, const char *data);

// time between ticks (in ms)
S32 mFrequencyMs;

public:
Ticker();

virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner);

static void initPersistFields();

S32 getFrequencyMs() const { return mFrequencyMs; }

DECLARE_CONOBJECT(Ticker);
};

//---------------------------------------------------------------------------
// Ticker decorator task
//---------------------------------------------------------------------------
class TickerTask : public DecoratorTask
{
typedef DecoratorTask Parent;

protected:
U32 mNextTimeMs;
U32 mEventId;

BehaviorTreeBranch *mBranch;

virtual void onInitialize();
virtual void onTerminate();
virtual Task* update();

void cancelEvent();

public:
TickerTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner);
virtual ~TickerTask();

virtual Status getStatus();
};

} // namespace BadBehavior

#endif
@@ -0,0 +1,125 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "RandomWait.h"
#include "BadBehavior/core/Runner.h"

#include "math/mMathFn.h"
#include "console/consoleTypes.h"

using namespace BadBehavior;

//------------------------------------------------------------------------------
// RandomWait leaf node
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(RandomWait);

RandomWait::RandomWait()
: mWaitMinMs(0),
mWaitMaxMs(99999)
{
}

void RandomWait::initPersistFields()
{
addGroup( "Behavior" );

addProtectedField( "waitMinMs", TypeS32, Offset(mWaitMinMs, RandomWait), &_setWaitMin, &defaultProtectedGetFn,
"The minimum time period in ms to wait before completion." );

addProtectedField( "waitMaxMs", TypeS32, Offset(mWaitMaxMs, RandomWait), &_setWaitMax, &defaultProtectedGetFn,
"The maximum time period in ms to wait before completion." );

endGroup( "Behavior" );

Parent::initPersistFields();
}

bool RandomWait::_setWaitMin(void *object, const char *index, const char *data)
{
RandomWait *node = static_cast<RandomWait *>( object );
node->mWaitMinMs = getMin(node->mWaitMaxMs, dAtoi( data ));
return false;
}

bool RandomWait::_setWaitMax(void *object, const char *index, const char *data)
{
RandomWait *node = static_cast<RandomWait *>( object );
node->mWaitMaxMs = getMax(node->mWaitMinMs, dAtoi( data ));
return false;
}

Task *RandomWait::createTask(SimObject &owner, BehaviorTreeRunner &runner)
{
return new RandomWaitTask(*this, owner, runner);
}

//------------------------------------------------------------------------------
// RandomWait task
//------------------------------------------------------------------------------
RandomWaitTask::RandomWaitTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner)
: Parent(node, owner, runner)
{
}

RandomWaitTask::~RandomWaitTask()
{
cancelEvent();
}

void RandomWaitTask::cancelEvent()
{
if(Sim::isEventPending(mEventId))
{
Sim::cancelEvent(mEventId);
mEventId = 0;
}
}

void RandomWaitTask::onInitialize()
{
Parent::onInitialize();
cancelEvent();
}

void RandomWaitTask::onTerminate()
{
Parent::onTerminate();
cancelEvent();
}

Task* RandomWaitTask::update()
{
if(mStatus == RESUME)
{
mStatus = SUCCESS;
mIsComplete = true;
}
else if(mStatus == INVALID)
{
RandomWait *node = static_cast<RandomWait*>(mNodeRep);
mEventId = Sim::postEvent(mRunner, new TaskReactivateEvent(*this), Sim::getCurrentTime() + mRandI(node->getWaitMinMs(), node->getWaitMaxMs()));
mStatus = SUSPENDED;
}

return NULL;
}
@@ -0,0 +1,83 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BB_RANDOMWAIT_H_
#define _BB_RANDOMWAIT_H_

#ifndef _BB_CORE_H_
#include "BadBehavior/core/Core.h"
#endif

namespace BadBehavior
{
//---------------------------------------------------------------------------
// RandomWait leaf
// Pauses for a random period of time between delayMin and delayMax ms before completing.
//---------------------------------------------------------------------------
class RandomWait : public LeafNode
{
typedef LeafNode Parent;

protected:
static bool _setWaitMin(void *object, const char *index, const char *data);
static bool _setWaitMax(void *object, const char *index, const char *data);

S32 mWaitMinMs;
S32 mWaitMaxMs;

public:
RandomWait();

virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner);

static void initPersistFields();

S32 getWaitMinMs() const { return mWaitMinMs; }
S32 getWaitMaxMs() const { return mWaitMaxMs; }

DECLARE_CONOBJECT(RandomWait);
};

//---------------------------------------------------------------------------
// RandomWait leaf task
//---------------------------------------------------------------------------
class RandomWaitTask : public Task
{
typedef Task Parent;

protected:
U32 mEventId;

virtual void onInitialize();
virtual void onTerminate();
virtual Task* update();

void cancelEvent();

public:
RandomWaitTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner);
virtual ~RandomWaitTask();
};

} // namespace BadBehavior

#endif
@@ -0,0 +1,94 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "ScriptEval.h"

#include "console/engineAPI.h"
#include "platform/profiler.h"

using namespace BadBehavior;

//------------------------------------------------------------------------------
// ScriptEval node - warning, slow!
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(ScriptEval);

ScriptEval::ScriptEval()
: mDefaultReturnStatus(SUCCESS)
{
}

void ScriptEval::initPersistFields()
{
addGroup( "Behavior" );

addField( "behaviorScript", TypeCommand, Offset(mBehaviorScript, ScriptEval),
"@brief The command to execute when the leaf is ticked. Max 255 characters." );

addField( "defaultReturnStatus", TYPEID< BadBehavior::Status >(), Offset(mDefaultReturnStatus, ScriptEval),
"@brief The default value for this node to return.");

endGroup( "Behavior" );

Parent::initPersistFields();
}

Task *ScriptEval::createTask(SimObject &owner, BehaviorTreeRunner &runner)
{
return new ScriptEvalTask(*this, owner, runner);
}

Status ScriptEval::evaluateScript( SimObject *owner )
{
PROFILE_SCOPE(ScriptEval_evaluateScript);

if(mBehaviorScript.isEmpty())
return mDefaultReturnStatus;

// get the result
const char *result = Con::evaluatef("%%obj=%s; %s return %s;",
owner->getIdString(),
mBehaviorScript.c_str(),
EngineMarshallData< BehaviorReturnType >(mDefaultReturnStatus));

if(result[0] == '1' || result[0] == '0')
// map true or false to SUCCEED or FAILURE
return static_cast<Status>(dAtoi(result));

// convert the returned value to our internal enum type
return EngineUnmarshallData< BehaviorReturnType >()( result );
}

//------------------------------------------------------------------------------
// RunScript task
//------------------------------------------------------------------------------
ScriptEvalTask::ScriptEvalTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner)
: Parent(node, owner, runner)
{
}

Task* ScriptEvalTask::update()
{
mStatus = static_cast<ScriptEval*>(mNodeRep)->evaluateScript( mOwner );

return NULL; // leaves don't have children
}
@@ -0,0 +1,75 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BB_SCRIPTEVAL_H_
#define _BB_SCRIPTEVAL_H_

#ifndef _BB_CORE_H_
#include "BadBehavior/core/Core.h"
#endif

namespace BadBehavior
{
//---------------------------------------------------------------------------
// ScriptEval - evaluates a set of Torque Script commands when run
// Warning - slow, handle with care!
//---------------------------------------------------------------------------
class ScriptEval : public LeafNode
{
typedef LeafNode Parent;

private:
// status to return if the command does not return a value
Status mDefaultReturnStatus;

// the torque script to evaluate
String mBehaviorScript;

public:
ScriptEval();

virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner);

static void initPersistFields();

// execute the script
Status evaluateScript(SimObject *owner);

DECLARE_CONOBJECT(ScriptEval);
};

//---------------------------------------------------------------------------
// ScriptEval task
//---------------------------------------------------------------------------
class ScriptEvalTask : public Task
{
typedef Task Parent;

protected:
virtual Task* update();

public:
ScriptEvalTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner);
};

} // namespace BadBehavior
#endif
@@ -0,0 +1,121 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "ScriptFunc.h"

#include "console/engineAPI.h"
#include "platform/profiler.h"

using namespace BadBehavior;

//------------------------------------------------------------------------------
// ScriptFunc node
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(ScriptFunc);

ScriptFunc::ScriptFunc()
: mDefaultReturnStatus(SUCCESS),
mScriptFunction(StringTable->insert(""))
{
for(U8 i = 0; i < MAX_COMMAND_ARGS; ++i)
mScriptArgs[i] = StringTable->insert("");
}


void ScriptFunc::initPersistFields()
{
addGroup( "Behavior" );

addField( "func", TypeCaseString, Offset(mScriptFunction, ScriptFunc),
"@brief The function to execute when the leaf is ticked." );

addField( "args", TypeCaseString, Offset(mScriptArgs, ScriptFunc), MAX_COMMAND_ARGS,
"@brief The arguments to be passed to the function to be executed." );

addField( "defaultReturnStatus", TYPEID< BadBehavior::Status >(), Offset(mDefaultReturnStatus, ScriptFunc),
"@brief The default value for this node to return.");

endGroup( "Behavior" );

Parent::initPersistFields();
}

Task *ScriptFunc::createTask(SimObject &owner, BehaviorTreeRunner &runner)
{
return new ScriptFuncTask(*this, owner, runner);
}

Status ScriptFunc::evaluate( SimObject *owner )
{
PROFILE_SCOPE(ScriptFunc_evaluate);

if(!owner)
return INVALID;

if(!mScriptFunction || !mScriptFunction[0])
return mDefaultReturnStatus;

S32 argc = 0;

const char *args[MAX_COMMAND_ARGS + 2];
args[0] = mScriptFunction;

while(argc < MAX_COMMAND_ARGS && (mScriptArgs[argc] && mScriptArgs[argc][0]))
{
args[argc + 2] = mScriptArgs[argc];
++argc;
}

argc += 2;

// get the result
const char *result = Con::execute(owner, argc, args);

// if function didn't return a result, return our default status
if(!result || !result[0])
return mDefaultReturnStatus;

// map true or false to SUCCEED or FAILURE
if(result[0] == '1' || result[0] == '0')
return static_cast<Status>(dAtoi(result));

// convert the returned value to our internal enum type
return EngineUnmarshallData< BehaviorReturnType >()( result );
}

//------------------------------------------------------------------------------
// ScriptFunc task
//------------------------------------------------------------------------------
ScriptFuncTask::ScriptFuncTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner)
: Parent(node, owner, runner)
{
}

Task* ScriptFuncTask::update()
{
mStatus = static_cast<ScriptFunc*>(mNodeRep)->evaluate( mOwner );

if(mStatus != RUNNING && mStatus != SUSPENDED)
mIsComplete = true;

return NULL; // leaves don't have children
}
@@ -0,0 +1,79 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BB_SCRIPTFUNC_H_
#define _BB_SCRIPTFUNC_H_

#ifndef _BB_CORE_H_
#include "BadBehavior/core/Core.h"
#endif

namespace BadBehavior
{
static const U8 MAX_COMMAND_ARGS = 4;

//---------------------------------------------------------------------------
// ScriptFunc - executes a function on the owner object
//---------------------------------------------------------------------------
class ScriptFunc : public LeafNode
{
typedef LeafNode Parent;

protected:
// the function to call
StringTableEntry mScriptFunction;

// the arguments for the function
StringTableEntry mScriptArgs[MAX_COMMAND_ARGS];

// status to return if the command does not return a value
Status mDefaultReturnStatus;

public:
ScriptFunc();

virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner);

static void initPersistFields();

// execute the command
Status evaluate(SimObject *owner);

DECLARE_CONOBJECT(ScriptFunc);
};

//---------------------------------------------------------------------------
// ScriptFunc task
//---------------------------------------------------------------------------
class ScriptFuncTask : public Task
{
typedef Task Parent;

protected:
virtual Task* update();

public:
ScriptFuncTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner);
};

} // namespace BadBehavior
#endif
@@ -0,0 +1,83 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "ScriptedBehavior.h"

#include "console/engineAPI.h"
#include "platform/profiler.h"

using namespace BadBehavior;

//------------------------------------------------------------------------------
// ScriptedBehavior node
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(ScriptedBehavior);

IMPLEMENT_CALLBACK( ScriptedBehavior, onEnter, void, ( SimObject* owner ), ( owner ),
"Called when the behavior is first run.\n"
"@param owner The object that this behavior tree belongs to." );

IMPLEMENT_CALLBACK( ScriptedBehavior, onExit, void, ( SimObject* owner ), ( owner ),
"Called when the behavior is complete.\n"
"@param owner The object that this behavior tree belongs to." );

IMPLEMENT_CALLBACK( ScriptedBehavior, precondition, bool, ( SimObject* owner ), ( owner ),
"Called prior to evaluating the behavior.\n"
"@param owner The object that this behavior tree belongs to.\n"
"A return value of false indicates that evaluation of the behavior should stop.\n"
"A return value of true indicates that evaluation of the behavior should continue.");

IMPLEMENT_CALLBACK( ScriptedBehavior, behavior, Status, ( SimObject* owner ), ( owner ),
"Evaluate the main behavior of this node.\n"
"@param owner The object that this behavior tree belongs to.\n");

ScriptedBehavior::ScriptedBehavior()
{
}

bool ScriptedBehavior::precondition( SimObject *owner )
{
PROFILE_SCOPE( ScriptedBehavior_precondition);

if(isMethod("precondition"))
return precondition_callback(owner);

return true;
}

void ScriptedBehavior::onEnter( SimObject *owner )
{
PROFILE_SCOPE( ScriptedBehavior_onEnter );
onEnter_callback(owner);
}

void ScriptedBehavior::onExit( SimObject *owner )
{
PROFILE_SCOPE( ScriptedBehavior_onExit );
onExit_callback(owner);
}

Status ScriptedBehavior::behavior( SimObject *owner )
{
PROFILE_SCOPE( ScriptedBehavior_behavior );
return behavior_callback( owner );
}
@@ -0,0 +1,56 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BB_SCRIPTEDBEHAVIOR_H_
#define _BB_SCRIPTEDBEHAVIOR_H_

#ifndef _BB_CORE_H_
#include "BadBehavior/core/behavior.h"
#endif

namespace BadBehavior
{
//---------------------------------------------------------------------------
// ScriptedBehavior - A structured behavior leaf node which defines a series
// Of scripted callbacks
//---------------------------------------------------------------------------
class ScriptedBehavior : public Behavior
{
typedef Behavior Parent;

public:
ScriptedBehavior();

virtual bool precondition( SimObject *owner );
virtual void onEnter( SimObject *owner );
virtual void onExit( SimObject *owner );
virtual Status behavior( SimObject *owner );

DECLARE_CONOBJECT(ScriptedBehavior);
DECLARE_CALLBACK(void, onEnter, (SimObject *owner));
DECLARE_CALLBACK(void, onExit, (SimObject *owner));
DECLARE_CALLBACK(bool, precondition, (SimObject *owner));
DECLARE_CALLBACK(Status, behavior, (SimObject *owner));
};
} // namespace BadBehavior

#endif
@@ -0,0 +1,76 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "SubTree.h"

#include "console/consoleTypes.h"

using namespace BadBehavior;


//------------------------------------------------------------------------------
// SubTree node - links to another behavior tree
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(SubTree);

SubTree::SubTree()
: mSubTreeName(0)
{
}

void SubTree::initPersistFields()
{
addGroup( "Behavior" );

addField( "subTreeName", TypeString, Offset(mSubTreeName, SubTree),
"@brief The name of the behavior tree that this node links to. Max 255 characters." );

endGroup( "Behavior" );

Parent::initPersistFields();
}

Task *SubTree::createTask(SimObject &owner, BehaviorTreeRunner &runner)
{
if(!mSubTreeName || mSubTreeName[0] == 0)
{
Con::errorf("SubTree::onInitialize: no sub tree specified");
return NULL;
}

SimObject *subTreeNode;

if(!Sim::findObject(mSubTreeName, subTreeNode))
{
Con::errorf("SubTree:onInitialize: the specified sub tree does not exist");
return NULL;
}

Node *node = dynamic_cast<Node*>(subTreeNode);
if(!node)
{
Con::errorf("SubTree::onInitialize: the specified sub tree is not a behavior tree node");
return NULL;
}

return node->createTask(owner, runner);
}
@@ -0,0 +1,56 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BB_SUBTREE_H_
#define _BB_SUBTREE_H_

#ifndef _BB_CORE_H_
#include "BadBehavior/core/Core.h"
#endif

namespace BadBehavior
{
//---------------------------------------------------------------------------
// SubTree decorator
// Turns a named Behavior into a subtree of this node.
// Does not actually have a child, so is a subclass of leaf
//---------------------------------------------------------------------------
class SubTree : public LeafNode
{
typedef LeafNode Parent;

protected:
const char* mSubTreeName;

public:
SubTree();

virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner);

static void initPersistFields();

DECLARE_CONOBJECT(SubTree);
};

} // namespace BadBehavior

#endif
@@ -0,0 +1,115 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------


#include "Wait.h"
#include "BadBehavior/core/Runner.h"

#include "math/mMathFn.h"
#include "console/consoleTypes.h"

using namespace BadBehavior;

//------------------------------------------------------------------------------
// Wait leaf node
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(Wait);

Wait::Wait()
: mWaitMs(1000)
{
}

void Wait::initPersistFields()
{
addGroup( "Behavior" );

addProtectedField( "waitMs", TypeS32, Offset(mWaitMs, Wait), &_setWait, &defaultProtectedGetFn,
"The time in ms that the node should wait before completion." );

endGroup( "Behavior" );

Parent::initPersistFields();
}

bool Wait::_setWait(void *object, const char *index, const char *data)
{
Wait *node = static_cast<Wait *>( object );
node->mWaitMs = getMax(0, dAtoi( data ));
return false;
}

Task *Wait::createTask(SimObject &owner, BehaviorTreeRunner &runner)
{
return new WaitTask(*this, owner, runner);
}

//------------------------------------------------------------------------------
// Wait task
//------------------------------------------------------------------------------
WaitTask::WaitTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner)
: Parent(node, owner, runner),
mEventId(0)
{
}

WaitTask::~WaitTask()
{
cancelEvent();
}

void WaitTask::cancelEvent()
{
if(Sim::isEventPending(mEventId))
{
Sim::cancelEvent(mEventId);
mEventId = 0;
}
}

void WaitTask::onInitialize()
{
Parent::onInitialize();
cancelEvent();
}

void WaitTask::onTerminate()
{
Parent::onTerminate();
cancelEvent();
}

Task* WaitTask::update()
{
if(mStatus == RESUME)
{
mStatus = SUCCESS;
mIsComplete = true;
}
else if(mStatus == INVALID)
{
mEventId = Sim::postEvent(mRunner, new TaskReactivateEvent(*this), Sim::getCurrentTime() + static_cast<Wait*>(mNodeRep)->getWaitMs());
mStatus = SUSPENDED;
}

return NULL;
}
@@ -0,0 +1,80 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BB_WAIT_H_
#define _BB_WAIT_H_

#ifndef _BB_CORE_H_
#include "BadBehavior/core/Core.h"
#endif

namespace BadBehavior
{
//---------------------------------------------------------------------------
// Wait leaf
// Pauses for a set time period.
//---------------------------------------------------------------------------
class Wait : public LeafNode
{
typedef LeafNode Parent;

protected:
static bool _setWait(void *object, const char *index, const char *data);

S32 mWaitMs;

public:
Wait();

virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner);

static void initPersistFields();

S32 getWaitMs() const { return mWaitMs; }

DECLARE_CONOBJECT(Wait);
};

//---------------------------------------------------------------------------
// Wait leaf task
//---------------------------------------------------------------------------
class WaitTask : public Task
{
typedef Task Parent;

protected:
U32 mEventId;

virtual void onInitialize();
virtual void onTerminate();
virtual Task* update();

void cancelEvent();

public:
WaitTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner);
virtual ~WaitTask();
};

} // namespace BadBehavior

#endif
@@ -0,0 +1,145 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "WaitForSignal.h"
#include "BadBehavior/core/Runner.h"

#include "console/consoleTypes.h"

using namespace BadBehavior;

//------------------------------------------------------------------------------
// WaitForSignal leaf node
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(WaitForSignal);

WaitForSignal::WaitForSignal()
: mTimeoutMs(0)
{
}

void WaitForSignal::initPersistFields()
{
addGroup( "Behavior" );

addField( "signalName", TypeRealString, Offset(mSignalName, WaitForSignal),
"The time in ms that the node should wait before completion." );

addProtectedField( "timeoutMs", TypeS32, Offset(mTimeoutMs, WaitForSignal), &_setTimeout, &defaultProtectedGetFn,
"The maximum time in ms that the node should wait for the signal.\n"
"A value of 0 indicates no limit");

endGroup( "Behavior" );

Parent::initPersistFields();
}

Task *WaitForSignal::createTask(SimObject &owner, BehaviorTreeRunner &runner)
{
return new WaitForSignalTask(*this, owner, runner);
}

bool WaitForSignal::_setTimeout(void *object, const char *index, const char *data)
{
WaitForSignal *node = static_cast<WaitForSignal *>( object );
node->mTimeoutMs = getMax(0, dAtoi( data ));
return false;
}

//------------------------------------------------------------------------------
// Wait task
//------------------------------------------------------------------------------
WaitForSignalTask::WaitForSignalTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner)
: Parent(node, owner, runner),
mEventId(0)
{
}

WaitForSignalTask::~WaitForSignalTask()
{
unsubscribe();
cancelEvent();
}

void WaitForSignalTask::subscribe()
{
mRunner->subscribeToSignal(static_cast<WaitForSignal *>(mNodeRep)->getSignalName().c_str(), this);
}

void WaitForSignalTask::unsubscribe()
{
mRunner->unsubscribeFromSignal(static_cast<WaitForSignal *>(mNodeRep)->getSignalName().c_str(), this);
}

void WaitForSignalTask::onSignal()
{
onResume();
}

void WaitForSignalTask::onTimeout()
{
mStatus = FAILURE;
}

void WaitForSignalTask::cancelEvent()
{
if(mEventId != 0 && Sim::isEventPending(mEventId))
{
Sim::cancelEvent(mEventId);
mEventId = 0;
}
}

void WaitForSignalTask::onInitialize()
{
Parent::onInitialize();
subscribe();
cancelEvent();
}

void WaitForSignalTask::onTerminate()
{
Parent::onTerminate();
unsubscribe();
cancelEvent();
}

Task* WaitForSignalTask::update()
{
if(mStatus == RESUME)
{
mStatus = SUCCESS;
}
else if (mStatus == INVALID)
{
mStatus = SUSPENDED;

S32 timeout = static_cast<WaitForSignal *>(mNodeRep)->getTimeoutMs();
if(timeout > 0)
mEventId = Sim::postEvent(mRunner, new WaitForSignalTimeoutEvent(*this), Sim::getCurrentTime() + timeout);
}

if(mStatus == SUCCESS || mStatus == FAILURE)
mIsComplete = true;

return NULL;
}
@@ -0,0 +1,114 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BB_WAITFORSIGNAL_H_
#define _BB_WAITFORSIGNAL_H_

#ifndef _BB_CORE_H_
#include "BadBehavior/core/Core.h"
#endif
#ifndef _BB_SIGNAL_H_
#include "BadBehavior/core/Signal.h"
#endif
#ifndef _SIMEVENTS_H_
#include "console/simEvents.h"
#endif

namespace BadBehavior
{
//---------------------------------------------------------------------------
// WaitForSignal leaf
// Waits until it receives the requested signal.
//---------------------------------------------------------------------------
class WaitForSignal : public LeafNode
{
typedef LeafNode Parent;

protected:
String mSignalName;
S32 mTimeoutMs;

static bool _setTimeout(void *object, const char *index, const char *data);

public:
WaitForSignal();

virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner);

static void initPersistFields();

const String &getSignalName() const { return mSignalName; }
S32 getTimeoutMs() const { return mTimeoutMs; }

DECLARE_CONOBJECT(WaitForSignal);
};

//---------------------------------------------------------------------------
// WaitForSignal leaf task
//---------------------------------------------------------------------------
class WaitForSignalTask : public Task, public virtual SignalSubscriber
{
typedef Task Parent;

protected:
U32 mEventId;

virtual void onInitialize();
virtual void onTerminate();
virtual Task* update();

void cancelEvent();

// SignalSubscriber
virtual void subscribe();
virtual void unsubscribe();

public:
WaitForSignalTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner);
virtual ~WaitForSignalTask();

// SignalSubscriber
virtual void onSignal();

// timeout
void onTimeout();
};


class WaitForSignalTimeoutEvent : public SimEvent
{
WaitForSignalTask *mTask;
public:
WaitForSignalTimeoutEvent(WaitForSignalTask &task)
{
mTask = &task;
}

void process( SimObject *object )
{
mTask->onTimeout();
}
};

} // namespace BadBehavior

#endif
@@ -0,0 +1,109 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "followBehaviorAction.h"

#include "T3D/aiPlayer.h"

using namespace BadBehavior;

//------------------------------------------------------------------------------
// FollowBehavior node
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(FollowBehaviorAction);

FollowBehaviorAction::FollowBehaviorAction()
{
}

bool FollowBehaviorAction::precondition( SimObject *owner )
{
PROFILE_SCOPE( FollowBehaviorAction_precondition);

// check that our owner is an AIPlayer
AIPlayer *aiPlayer = dynamic_cast<AIPlayer *>(owner);
if(!aiPlayer)
return false;

return true;
}

void FollowBehaviorAction::onEnter( SimObject *owner )
{
//PROFILE_SCOPE( FollowBehaviorAction_onEnter );
}

void FollowBehaviorAction::onExit( SimObject *owner )
{
//PROFILE_SCOPE( FollowBehaviorAction_onExit );
}

Status FollowBehaviorAction::behavior( SimObject *owner )
{
PROFILE_SCOPE( FollowBehaviorAction_behavior );

// get the owning AIPlayer object
AIPlayer *aiPlayer = dynamic_cast<AIPlayer *>(owner);
if(!aiPlayer)
return FAILURE;

// get the script-specified followObject
const char *followFieldName = StringTable->insert("followObject");
const char *followFieldValue = owner->getDataField(followFieldName, NULL);
if(!followFieldValue || !followFieldValue[0])
return FAILURE;

SimObject *followSimObj = Sim::findObject(dAtoi(followFieldValue));
if(!followSimObj)
return FAILURE;

// check that the follow object is a SceneObject
SceneObject *followObject = dynamic_cast<SceneObject *>(followSimObj);
if(!followObject)
return FAILURE;

// get the script-specified followDistance field
const char *distanceFieldName = StringTable->insert("followDistance");
const char *distanceFieldValue = owner->getDataField(distanceFieldName, NULL);
float followDistance = 1.f;
if(distanceFieldValue && distanceFieldValue[0])
followDistance = dAtof(distanceFieldValue);

// try and stay at followDistance from the followObject
Point3F targetPos = followObject->getPosition();
Point3F followVec = aiPlayer->getPosition() - targetPos;

// get current distance (ignore z component)
F32 curDist = Point3F(followVec.x, followVec.y, 0.f).len();

if(mFabs(curDist - followDistance) > aiPlayer->getMoveTolerance())
{
followVec.normalize();
followVec *= followDistance;
Point3F destination = targetPos + followVec;

aiPlayer->setMoveDestination(destination, true);
return RUNNING;
}

return SUCCESS;
}
@@ -0,0 +1,52 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BB_FOLLOWBEHAVIORACTION_H_
#define _BB_FOLLOWBEHAVIORACTION_H_

#ifndef _BB_CORE_H_
#include "BadBehavior/core/behavior.h"
#endif

namespace BadBehavior
{
//---------------------------------------------------------------------------
// FollowBehaviorAction - Make an AIPlayer follow another object
// Demonstrates how to create a compiled behavior by subclassing Behavior
//---------------------------------------------------------------------------
class FollowBehaviorAction : public Behavior
{
typedef Behavior Parent;

public:
FollowBehaviorAction();

virtual bool precondition( SimObject *owner );
virtual void onEnter( SimObject *owner );
virtual void onExit( SimObject *owner );
virtual Status behavior( SimObject *owner );

DECLARE_CONOBJECT(FollowBehaviorAction);
};
} // namespace BadBehavior

#endif
@@ -0,0 +1,135 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "BTUndoActions.h"

#include "console/consoleTypes.h"
#include "console/simSet.h"

S32 getNextObjectInGroup(SimObject *object, SimGroup *group)
{
group->lock();
S32 nextId = -1;

if(object != group->last() && group->find( group->begin(), group->end(), object ) != group->end())
{
for( SimSet::iterator i = group->begin(); i != group->end(); i++)
{
if( *i == object )
{
nextId = (*++i)->getId();
break;
}
}
group->unlock();
}

return nextId;
}

IMPLEMENT_CONOBJECT( BTDeleteUndoAction );

ConsoleDocClass( BTDeleteUndoAction,
"@brief Behavior Tree Editor delete undo instance\n\n"
"Not intended for game development, for editors or internal use only.\n\n "
"@internal");

BTDeleteUndoAction::BTDeleteUndoAction( const UTF8 *actionName )
: UndoAction( actionName )
{
}

BTDeleteUndoAction::~BTDeleteUndoAction()
{
}

void BTDeleteUndoAction::initPersistFields()
{
Parent::initPersistFields();
}

void BTDeleteUndoAction::deleteObject( SimObject *object )
{
AssertFatal( object, "BTDeleteUndoAction::deleteObject() - Got null object!" );
AssertFatal( object->isProperlyAdded(),
"BTDeleteUndoAction::deleteObject() - Object should be registered!" );

// Capture the object id.
mObject.id = object->getId();

// Save the state.
mObject.memento.save( object );

// Store the group.
SimGroup *group = object->getGroup();
if ( group )
{
mObject.groupId = group->getId();

// and the next object in the group
mObject.nextId = getNextObjectInGroup(object, group);
}

// Now delete the object.
object->deleteObject();
}

ConsoleMethod( BTDeleteUndoAction, deleteObject, void, 3, 3, "( SimObject obj )")
{
SimObject *obj = NULL;
if ( Sim::findObject( argv[2], obj ) && obj )
object->deleteObject( obj );
}

void BTDeleteUndoAction::undo()
{
// Create the object.
SimObject::setForcedId(mObject.id); // Restore the object's Id
SimObject *object = mObject.memento.restore();
if ( !object )
return;

// Now restore its group.
SimGroup *group;
if ( Sim::findObject( mObject.groupId, group ) )
{
group->addObject( object );

// restore its position in the group
SimObject *nextObj;
if ( Sim::findObject( mObject.nextId, nextObj ) )
{
group->reOrder(object, nextObj);
}
}

Con::executef( this, "onUndone" );
}

void BTDeleteUndoAction::redo()
{
SimObject *object = Sim::findObject( mObject.id );
if ( object )
object->deleteObject();

Con::executef( this, "onRedone" );
}
@@ -0,0 +1,77 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _BT_UNDO_ACTIONS_H_
#define _BT_UNDO_ACTIONS_H_

#ifndef _UNDO_H_
#include "util/undo.h"
#endif
#ifndef _CONSOLE_SIMOBJECTMEMENTO_H_
#include "console/simObjectMemento.h"
#endif

S32 getNextObjectInSet(SimObject *obj, SimGroup &group);

class BTDeleteUndoAction : public UndoAction
{
typedef UndoAction Parent;

protected:

struct ObjectState
{
/// The object we deleted and will restore in undo.
SimObjectId id;

/// The captured object state.
SimObjectMemento memento;

/// Keep track of the parent group.
SimObjectId groupId;

/// Keep track of the position within the parent group
SimObjectId nextId;
};

/// The object we're deleting.
ObjectState mObject;

public:

DECLARE_CONOBJECT( BTDeleteUndoAction );
static void initPersistFields();

BTDeleteUndoAction( const UTF8* actionName = "Delete Object" );
virtual ~BTDeleteUndoAction();

///
void deleteObject( SimObject *object );

// UndoAction
virtual void undo();
virtual void redo();
};



#endif // _BT_UNDO_ACTIONS_H_
@@ -0,0 +1,301 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "guiBTViewCtrl.h"

#include "gfx/gfxDrawUtil.h"
#include "gui/worldEditor/editorIconRegistry.h"
#include "gui/controls/guiTextEditCtrl.h"

using namespace BadBehavior;

IMPLEMENT_CONOBJECT(GuiBehaviorTreeViewCtrl);

void GuiBehaviorTreeViewCtrl::onRenderCell(Point2I offset, Point2I cell, bool, bool )
{
if( !mVisibleItems.size() )
return;

// Do some sanity checking and data retrieval.
AssertFatal(cell.y < mVisibleItems.size(), "GuiTreeViewCtrl::onRenderCell: invalid cell");
Item * item = mVisibleItems[cell.y];

// If there's no object, deal with it.
if(item->isInspectorData())
if(!item->getObject())
return;

RectI drawRect( offset, mCellSize );
GFXDrawUtil *drawer = GFX->getDrawUtil();
drawer->clearBitmapModulation();

FrameAllocatorMarker txtBuff;

// Ok, we have the item. There are a few possibilities at this point:
// - We need to draw inheritance lines and a treeview-chosen icon
// OR
// - We have to draw an item-dependent icon
// - If we're mouseover, we have to highlight it.
//
// - We have to draw the text for the item
// - Taking into account various mouseover states
// - Taking into account the value (set or not)
// - If it's an inspector data, we have to do some custom rendering
// - ADDED: If it is being renamed, we also have custom rendering.

// Ok, first draw the tab and icon.

// Do we draw the tree lines?
if( mFlags.test(ShowTreeLines) )
{
drawRect.point.x += ( mTabSize * item->mTabLevel );
Item* parent = item->mParent;
for ( S32 i = item->mTabLevel; ( parent && i > 0 ); i-- )
{
drawRect.point.x -= mTabSize;
if ( parent->mNext )
drawer->drawBitmapSR( mProfile->mTextureObject, drawRect.point, mProfile->mBitmapArrayRects[BmpLine] );

parent = parent->mParent;
}
}

// Now, the icon...
drawRect.point.x = offset.x + mTabSize * item->mTabLevel;

// First, draw the rollover glow, if it's an inner node.
if ( item->isParent() && item->mState.test( Item::MouseOverBmp ) )
drawer->drawBitmapSR( mProfile->mTextureObject, drawRect.point, mProfile->mBitmapArrayRects[BmpGlow] );

// Now, do we draw a treeview-selected item or an item dependent one?
S32 newOffset = 0; // This is stored so we can render glow, then update render pos.

S32 bitmap = 0;

// Ok, draw the treeview lines as appropriate.

bool drawBitmap = true;
if ( !item->isParent() )
{
if( mFlags.test( ShowTreeLines ) )
{
if( ( item->mNext && item->mPrevious )
|| ( item->mNext && item->mParent && ( !_isRootLevelItem( item ) || mShowRoot ) ) )
bitmap = BmpChild;
else if( item->mNext && ( !item->mParent || !mShowRoot ) )
bitmap = BmpFirstChild;
else if( item->mPrevious || ( item->mParent && !_isRootLevelItem( item ) ) )
bitmap = BmpLastChild;
else
drawBitmap = false;
}
else
drawBitmap = false;
}
else
{
bitmap = item->isExpanded() ? BmpExp : BmpCon;

if( mFlags.test( ShowTreeLines ) )
{
// Shift indices to show versions with tree lines.

if ( item->mParent || item->mPrevious )
bitmap += ( item->mNext ? 3 : 2 );
else
bitmap += ( item->mNext ? 1 : 0 );
}
}

if( ( bitmap >= 0 ) && ( bitmap < mProfile->mBitmapArrayRects.size() ) )
{
if( drawBitmap )
drawer->drawBitmapSR( mProfile->mTextureObject, drawRect.point, mProfile->mBitmapArrayRects[bitmap] );
newOffset = mProfile->mBitmapArrayRects[bitmap].extent.x;
}

if(item->isInspectorData())
{
// draw lock icon if need be
S32 icon = Lock1;
S32 icon2 = Hidden;

if (item->getObject() && item->getObject()->isLocked())
{
if (mIconTable[icon])
{
//drawRect.point.x = offset.x + mTabSize * item->mTabLevel + mIconTable[icon].getWidth();
drawRect.point.x += mIconTable[icon].getWidth();
drawer->drawBitmap( mIconTable[icon], drawRect.point );
}
}

if (item->getObject() && item->getObject()->isHidden())
{
if (mIconTable[icon2])
{
//drawRect.point.x = offset.x + mTabSize * item->mTabLevel + mIconTable[icon].getWidth();
drawRect.point.x += mIconTable[icon2].getWidth();
drawer->drawBitmap( mIconTable[icon2], drawRect.point );
}
}

/*SimObject * pObject = item->getObject();
SimGroup * pGroup = ( pObject == NULL ) ? NULL : dynamic_cast<SimGroup*>( pObject );
// If this item is a VirtualParent we can use the generic SimGroup123 icons.
// However if there is already an icon in the EditorIconRegistry for this
// exact class (not counting parent class icons) we want to use that instead.
bool hasClassIcon = gEditorIcons.hasIconNoRecurse( pObject );
// draw the icon associated with the item
if ( !hasClassIcon && item->mState.test(Item::VirtualParent))
{
if ( pGroup != NULL)
{
if (item->isExpanded())
item->mIcon = SimGroup1;
else
item->mIcon = SimGroup2;
}
else
item->mIcon = SimGroup2;
}
if ( !hasClassIcon && item->mState.test(Item::Marked))
{
if (item->isInspectorData())
{
if ( pGroup != NULL )
{
if (item->isExpanded())
item->mIcon = SimGroup3;
else
item->mIcon = SimGroup4;
}
}
}*/

GFXTexHandle iconHandle;

if ( ( item->mIcon != -1 ) && mIconTable[item->mIcon] )
iconHandle = mIconTable[item->mIcon];
#ifdef TORQUE_TOOLS
else
iconHandle = gEditorIcons.findIcon( item->getObject() );
#endif

if ( iconHandle.isValid() )
{
S32 iconHeight = (mItemHeight - iconHandle.getHeight()) / 2;
S32 oldHeight = drawRect.point.y;
if(iconHeight > 0)
drawRect.point.y += iconHeight;
drawRect.point.x += iconHandle.getWidth();
drawer->drawBitmap( iconHandle, drawRect.point );
drawRect.point.y = oldHeight;
}
}
else
{
S32 icon = item->isExpanded() ? item->mScriptInfo.mExpandedImage : item->mScriptInfo.mNormalImage;
if ( icon )
{
if (mIconTable[icon])
{
S32 iconHeight = (mItemHeight - mIconTable[icon].getHeight()) / 2;
S32 oldHeight = drawRect.point.y;
if(iconHeight > 0)
drawRect.point.y += iconHeight;
drawRect.point.x += mIconTable[icon].getWidth();
drawer->drawBitmap( mIconTable[icon], drawRect.point );
drawRect.point.y = oldHeight;
}
}
}

// Ok, update offset so we can render some text!
drawRect.point.x += newOffset;

// Ok, now we're off to rendering the actual data for the treeview item.

U32 bufLen = 1024; //item->mDataRenderWidth + 1;
char *displayText = (char *)txtBuff.alloc(bufLen);
displayText[bufLen-1] = 0;
item->getDisplayText(bufLen, displayText);

// Draw the rollover/selected bitmap, if one was specified.
drawRect.extent.x = mProfile->mFont->getStrWidth( displayText ) + ( 2 * mTextOffset );
if ( item->mState.test( Item::Selected ) && mTexSelected )
drawer->drawBitmapStretch( mTexSelected, drawRect );
else if ( item->mState.test( Item::MouseOverText ) && mTexRollover )
drawer->drawBitmapStretch( mTexRollover, drawRect );

// Offset a bit so as to space text properly.
drawRect.point.x += mTextOffset;

// Determine what color the font should be.
ColorI fontColor;

fontColor = item->mState.test( Item::Selected ) ? mProfile->mFontColorSEL :
( item->mState.test( Item::MouseOverText ) ? mProfile->mFontColorHL : mProfile->mFontColor );

if (item->mState.test(Item::Selected))
{
drawer->drawRectFill(drawRect, mProfile->mFillColorSEL);
}
else if (item->mState.test(Item::MouseOverText))
{
drawer->drawRectFill(drawRect, mProfile->mFillColorHL);
}

if( item->mState.test(Item::MouseOverText) )
{
fontColor = mProfile->mFontColorHL;
}

drawer->setBitmapModulation( fontColor );

// Center the text horizontally.
S32 height = (mItemHeight - mProfile->mFont->getHeight()) / 2;

if(height > 0)
drawRect.point.y += height;

// JDD - offset by two pixels or so to keep the text from rendering RIGHT ONTOP of the outline
drawRect.point.x += 2;

drawer->drawText( mProfile->mFont, drawRect.point, displayText, mProfile->mFontColors );

if ( mRenamingItem == item && mRenameCtrl )
{
Point2I ctrPos = globalToLocalCoord( drawRect.point );
ctrPos.y -= height;
ctrPos.x -= 2;

Point2I ctrExtent( getWidth() - ctrPos.x, drawRect.extent.y );

mRenameCtrl->setPosition( ctrPos );
mRenameCtrl->setExtent( ctrExtent );
mRenameCtrl->setVisible( true );
}
}
@@ -0,0 +1,45 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#ifndef _GUI_BTVIEWCTRL_H_
#define _GUI_BTVIEWCTRL_H_

#ifndef _GUI_TREEVIEWCTRL_H
#include "gui/controls/guiTreeViewCtrl.h"
#endif

namespace BadBehavior
{
// subclassing GuiTreeViewCtrl so that we can tweak it for the behavior tree editor
class GuiBehaviorTreeViewCtrl : public GuiTreeViewCtrl
{
typedef GuiTreeViewCtrl Parent;

public:
void onRenderCell(Point2I offset, Point2I cell, bool, bool);

DECLARE_CONOBJECT(GuiBehaviorTreeViewCtrl);
};

} // namespace BadBehavior

#endif
@@ -9,4 +9,5 @@
// In this case all the code in the "custom" folder in your project's source directory would be added
// addSrcDir('../source/custom');

includeModule("BadBehavior");
?>
@@ -9,4 +9,5 @@
// In this case all the code in the "custom" folder in your project's source directory would be added
// addSrcDir('../source/custom');

includeModule("BadBehavior");
?>
@@ -219,6 +219,13 @@ addPath("${srcDir}/platform/input")
addPath("${srcDir}/platform/output")
addPath("${srcDir}/app")
addPath("${srcDir}/app/net")
addPath("${srcDir}/BadBehavior")
addPath("${srcDir}/BadBehavior/composite")
addPath("${srcDir}/BadBehavior/core")
addPath("${srcDir}/BadBehavior/decorator")
addPath("${srcDir}/BadBehavior/leaf")
addPath("${srcDir}/BadBehavior/leaf/compiled")
addPath("${srcDir}/BadBehavior/tools")
addPath("${srcDir}/util/messaging")
addPath("${srcDir}/gfx/Null")
addPath("${srcDir}/gfx/test")