174 lines
4.7 KiB
C++
174 lines
4.7 KiB
C++
/* -----------------------------------------------------------------------------
|
|
GSFramework
|
|
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
#include "core/ace.h"
|
|
#include "ascii/parser.h"
|
|
#include "log/log.h"
|
|
|
|
using namespace GS::ACE;
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Manager::UpdateACEUnit(Unit *u, float dt)
|
|
{
|
|
if (!u->pc)
|
|
u->is_done = true;
|
|
if (u->is_done)
|
|
return;
|
|
|
|
// Execute sequence until next exec opcode.
|
|
bool has_exec_left = false, looped = false;
|
|
|
|
List <Command> ::Item *cpc;
|
|
for (cpc = u->pc; cpc; cpc = cpc->Next())
|
|
{
|
|
Command *cmd = &cpc->Object();
|
|
if (cmd->code == AceCommandExec)
|
|
{
|
|
cpc = cpc->Next();
|
|
break;
|
|
}
|
|
|
|
if (cmd->duration_left > 0.00001)
|
|
{
|
|
float exec_dt = cmd->duration_left;
|
|
if (dt < cmd->duration_left)
|
|
{
|
|
exec_dt = dt;
|
|
has_exec_left = true;
|
|
}
|
|
|
|
u->ExecCommand(cmd, exec_dt);
|
|
cmd->duration_left -= exec_dt;
|
|
|
|
if (cmd->code == AceCommandNext)
|
|
looped = true;
|
|
}
|
|
}
|
|
|
|
// Sequence done.
|
|
if (looped)
|
|
{
|
|
// We need to reset the looping block commands duration.
|
|
for (List <Command> ::Item *lpc = u->loop_pc; lpc != cpc; lpc = lpc->Next())
|
|
lpc->Object().duration_left = lpc->Object().duration;
|
|
}
|
|
else
|
|
if (!has_exec_left)
|
|
u->pc = cpc;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
static bool DefineNameCompare(const Define *o, const GS::String &name) { return o->id == name; }
|
|
|
|
//------------------------------------------------------------------------------
|
|
int Manager::LoadACECommandList(const char *s, Unit *u) const
|
|
{
|
|
if (!s)
|
|
__ERR__(__LOG_E__ << "Cannot load a null command list.\n", -1);
|
|
|
|
u->ResetCommandList();
|
|
|
|
using namespace AsciiParser;
|
|
|
|
// Parse command list.
|
|
const char *e = s + String::strlen(s);
|
|
s = SkipSpace(s, e);
|
|
|
|
while (s < e)
|
|
{
|
|
Command &cc = u->list.Add(Command())->Object();
|
|
|
|
// Read in code.
|
|
String command(s, SkipEntry(s, e));
|
|
|
|
Define *d = ArrayListFindEx(define_list, DefineNameCompare, command);
|
|
if (!d)
|
|
__ERR__(__LOG_E__ << "Undefined ACE command '" << command << "'.\n", -1);
|
|
cc.code = d->code;
|
|
|
|
// Read in duration.
|
|
s = NextEntry(s, e);
|
|
if (s == e)
|
|
__ERR__(__LOG_E__ << "No duration for ACE command '" << command << "'.\n", -1);
|
|
|
|
cc.duration = String(s, SkipEntry(s, e)).Float();
|
|
if (cc.duration < 0.001f)
|
|
cc.duration = 0.001f; // Force minimum duration to 1ms.
|
|
cc.duration_left = cc.duration;
|
|
|
|
// Read up to 3 parameters.
|
|
s = NextEntry(s, e);
|
|
uint nparm = 0;
|
|
|
|
while (s < e)
|
|
{
|
|
if ((s[0] == '+') || (s[0] == ';'))
|
|
break;
|
|
|
|
if (nparm == 3)
|
|
__ERR__(__LOG_E__ << "ACE compiled with " << max_command_param << " command parameter(s) maximum.\n", -1);
|
|
if (s[0] != ',')
|
|
__ERR__(__LOG_E__ << "Expected ',' in ACE list declaration.\n", -1);
|
|
s = SkipSpace(s + 1, e);
|
|
if (s == e)
|
|
__ERR__(__LOG_E__ << "Expected ACE command parameter following ','.\n", -1);
|
|
|
|
String parm(s, SkipEntry(s, e, true));
|
|
cc.parm[nparm++] = parm.Float();
|
|
s = SkipSpace(SkipEntry(s, e, true), e);
|
|
}
|
|
if (s == e)
|
|
__ERR__(__LOG_E__ << "Mangled ACE command list.\n", -1);
|
|
if ((uint)d->nparm != nparm)
|
|
__ERR__(__LOG_E__ << "ACE command '" << command << "' takes " << d->nparm << " parameter(s), found " << nparm << ".\n", -1);
|
|
|
|
// Output exec command.
|
|
if (s[0] == ';')
|
|
u->list.Add(Command())->Object().code = AceCommandExec;
|
|
|
|
s = SkipSpace(s + 1, e); // Skip comma.
|
|
}
|
|
|
|
// Set PC to list root command.
|
|
u->is_done = false;
|
|
u->pc = u->list.GetRoot();
|
|
return u->list.GetCount();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool Manager::DefineACECommand(const char *command, int code, int nparm, bool user_code)
|
|
{
|
|
if (user_code && (code < 0))
|
|
__ERR__(__LOG_E__ << "Negative command codes are reserved.\n", false)
|
|
|
|
Define *d = new Define;
|
|
if (!d)
|
|
__ERR__(__LOG_E__ << "Failed to allocate new container to define ACE command '" << command << "'.\n", false)
|
|
|
|
d->id = command;
|
|
d->code = code;
|
|
d->nparm = nparm;
|
|
|
|
define_list.Add(d);
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
Manager::Manager()
|
|
{
|
|
DefineACECommand("nop", AceCommandNop, 0, false);
|
|
DefineACECommand("loop", AceCommandLoop, 0, false);
|
|
DefineACECommand("next", AceCommandNext, 0, false);
|
|
}
|
|
Manager::~Manager()
|
|
{
|
|
ArrayListDeleteAllPtr(Define *, define_list)
|
|
}
|
|
//------------------------------------------------------------------------------
|