/* ----------------------------------------------------------------------------- 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 ::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 ::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) } //------------------------------------------------------------------------------