[ create a new paste ] login | about

Link: http://codepad.org/e1lr40ql    [ raw code | fork ]

C++, pasted on Aug 4:
#include "quest.hpp"

#include "world.hpp"

Quest::Quest(short id, World *world)
{
    char namebuf[4];

    if (id < 0)
    {
        return;
    }
    this->id = id;
    this->exists = true;

    std::string filename = world->config["QuestDir"];
    std::sprintf(namebuf, "%05i", id);
    filename.append(namebuf);
	filename.append(".eqf");
	std::FILE *fh = std::fopen(filename.c_str(), "rt");
	std::string buf;

	if (!fh)
	{
	    Console::Err("Could not load quest file %s", filename.c_str());
	    this->exists = false;
	    return;
	}

	std::fseek(fh, 0, SEEK_END);
	long size = ftell(fh);
	std::rewind(fh);

	buf.resize(size);
	std::fread(&buf[0], 1, size, fh);
	std::fclose(fh);

	Load(buf);
}

void Quest::Load(const std::string source)
{
    bool inmain = false;
    bool instate = false;

    bool inquotes = false;
    bool inparens = false;
    bool incomment = false;
    bool escape = false;
    bool semicolon = false;
    bool version_said = false;
    bool questname_said = false;

    int character = 0;

    int quote_start = 0;
    int quote_end = 0;

    int paren_start = 0;
    int paren_end = 0;

    int comment_start = 0;

    std::vector<int> args;

    State *state;
    Action *action;
    Rule *rule;

    std::string tempstring;

    while (source[character] != '\0')
    {
        if (!incomment && !escape && (source[character] == '\"' || source[character] == '\''))
        {
            if (inquotes)
            {
                quote_end = tempstring.size();
                inquotes = false;
            }
            else
            {
                quote_start = tempstring.size();
                inquotes = true;
            }
        }
        else if (source[character] == '\\')
        {
            if (source[character+1] == '\'' || source[character+1] == '\"')
                escape = true;
        }
        else if (!inquotes && (source[character] == '/' && source[character+1] == '/'))
        {
            incomment = true;
            comment_start = tempstring.size();
        }
        else if ((!incomment && !inquotes && ((source[character] == '\n' && !instate && !inmain) || source[character] == ' ')) || source[character] == '\t')
        {
            character++;
            continue;
        }
        else if (incomment && source[character] == '\n')
        {
            incomment = false;
            tempstring.erase(comment_start);
        }
        else if (!incomment && !inquotes && source[character] == '{')
        {
            if (tempstring.compare(0, 4, "main") == 0)
            {
                inmain = true;
            }
            else if (tempstring.compare(0, 5, "state") == 0)
            {
                instate = true;
                state = new State();
                if (tempstring.size() <= 6)
                    SyntaxError("No state name available");

                state->name = tempstring.substr(5);
            }

            tempstring.clear();
        }
        else if (!incomment && !inquotes && source[character] == '}')
        {
            if (!inmain && !instate)
                SyntaxError("Invalid brace: No starting brace");

            if (inmain) inmain = false;
            else if (instate)
            {
                this->states.push_back(state);
                state->Release();
                instate = false;
            }

            tempstring.clear();
        }
        else if (!incomment && !inquotes && source[character] == '(')
        {
            if (inparens)
                SyntaxError("Nested parentheses not allowed");

            inparens = true;
            paren_start = tempstring.size();
        }
        else if (!incomment && !inquotes && source[character] == ')')
        {
            if (!inparens)
                SyntaxError("Not in parentheses");

            inparens = false;
            paren_end = tempstring.size();
        }
        else if (!incomment && !inquotes && source[character] == ';')
        {
            semicolon = true;
        }
        else if (!incomment && !inquotes && source[character] == ',')
        {
            if (!inparens)
                SyntaxError("Invalid comma outside of parentheses");

            args.push_back(tempstring.size());
        }
        else
        {
            escape = false;

            if ((source[character] >= 'A' && source[character] <= 'Z') && !inquotes)
                tempstring += source[character] - 'A' + 'a';
            else
                tempstring += source[character];
        }

        if (inmain)
        {
            if (source[character] == '\n')
            {
                if (tempstring.compare(0, 9, "questname") == 0)
                {
                    if (quote_start == 0 || quote_end == 0)
                        SyntaxError("No quotation marks around the questname");

                    this->name = tempstring.substr(quote_start, quote_end);
                    questname_said = true;
                    quote_start = quote_end = 0;
                }
                else if (tempstring.compare(0, 7, "version") == 0)
                {
                    std::vector<std::string> parts = util::explode('.', tempstring);
                    if (parts.size() != 2)
                        SyntaxError("Invalid version format (try major.minor)");

                    this->version_major = util::to_int(parts[0]);
                    this->version_minor = util::to_int(parts[1]);
                    version_said = true;
                }
                tempstring.clear();
            }
        }
        else if (instate)
        {
            if (source[character] == '\n')
            {
                if (tempstring.compare(0, 4, "desc") == 0)
                {
                    if (quote_start == 0 || quote_end == 0)
                        SyntaxError("No quotation marks around the description");

                    state->description = tempstring.substr(quote_start, quote_end);
                    quote_start = quote_end = 0;

                    tempstring.clear();
                }
                else if (tempstring.compare(0, 6, "action") == 0)
                {
                    if (semicolon)
                    {
                        if (paren_start == 0 || paren_end == 0)
                            SyntaxError("No parentheses in action");

                        action = new Action();
                        action->name = tempstring.substr(6, paren_start - 6);
                        if (args.size() > 0)
                        {
                            size_t start, end;
                            for (size_t i = 0; i <= args.size(); ++i)
                            {
                                start = (i == 0 ? paren_start : args[i - 1]);
                                end = (i == args.size() ? paren_end : args[i]) - start;
                                action->args.push_back(new util::variant(tempstring.substr(start, end)));
                            }
                        }
                        else
                        {
                            action->args.push_back(new util::variant(tempstring.substr(paren_start, paren_end-paren_start)));
                        }

                        if (action->name.compare("giveitem") == 0 && action->args.size() != 2)
                            SyntaxError("GiveItem requires two parameters");
                        else if (action->name.compare("removeitem") == 0 && action->args.size() != 2)
                            SyntaxError("RemoveItem requires two parameters");
                        else if (action->name.compare("giveexp") == 0 && action->args.size() != 1)
                            SyntaxError("GiveExp requires one parameter");
                        else if (action->name.compare("givekarma") == 0 && action->args.size() != 1)
                            SyntaxError("GiveKarma requires one parameter");
                        else if (action->name.compare("removekarma") == 0 && action->args.size() != 1)
                            SyntaxError("RemoveKarma requires one parameter");
                        else if (action->name.compare("showhint") == 0 && action->args.size() != 1)
                            SyntaxError("ShowHint requires one parameter");
                        else if (action->name.compare("playsound") == 0 && action->args.size() != 1)
                            SyntaxError("PlaySound requires one parameter");
                        else if (action->name.compare("setcoord") == 0 && action->args.size() != 3)
                            SyntaxError("SetCoord requires three parameterw");
                        else if (action->name.compare("setrace") == 0 && action->args.size() != 1)
                            SyntaxError("SetRace requires one parameter");
                        else if (action->name.compare("setclass") == 0 && action->args.size() != 1)
                            SyntaxError("SetClass requires one parameter");
                        else if (action->name.compare("setstate") == 0 && action->args.size() != 1)
                            SyntaxError("SetState requires one parameter");
                        else if (action->name.compare("quake") == 0 && (action->args.size() != 1 && action->args.size() != 2))
                            SyntaxError("Quake requires at least one parameter");
                        else if (action->name.compare("addnpctext") == 0 && action->args.size() != 2)
                            SyntaxError("AddNpcText requires two parameters");
                        else if (action->name.compare("addnpcchat") == 0 && action->args.size() != 2)
                            SyntaxError("AddNpcChat requires two parameters");
                        else if (action->name.compare("addnpcinput") == 0 && action->args.size() != 3)
                            SyntaxError("AddNpcInput requires three parameters");

                        state->actions.push_back(action);
                        action->Release();
                        paren_start = paren_end = 0;
                        tempstring.clear();
                        args.clear();
                        semicolon = false;
                    }
                    else if (paren_end != 0)
                    {
                        SyntaxError("Expected \';\'");
                        paren_start = paren_end = 0;
                        tempstring.clear();
                        args.clear();
                    }
                }
                else if (tempstring.compare(0, 4, "rule") == 0)
                {
                    if (paren_start == 0 || paren_end == 0)
                        SyntaxError("No parentheses in rule");

                    rule = new Rule();
                    rule->name = tempstring.substr(4, paren_start - 4);

                    if (args.size() > 0)
                    {
                        size_t start, end;
                        for (size_t i = 0; i <= args.size(); ++i)
                        {
                            start = (i == 0 ? paren_start : args[i - 1]);
                            end = (i == args.size() ? paren_end : args[i]) - start;
                            rule->args.push_back(new util::variant(tempstring.substr(start, end)));
                        }
                    }
                    else
                    {
                        rule->args.push_back(new util::variant(tempstring.substr(paren_start, paren_end-paren_start)));
                    }

                    if (tempstring.compare(paren_end, 4, "goto") == 0)
                    {
                        rule->goto_state = util::trim(tempstring.substr(paren_end+4));
                    }
                    else
                        SyntaxError("Every rule is required to have a goto");

                    if (rule->name.compare("inputnpc") == 0 && rule->args.size() != 1)
                        SyntaxError("InputNpc requires one parameter");
                    else if (rule->name.compare("talkedtonpc") == 0 && rule->args.size() != 1)
                        SyntaxError("TalkedToNpc requires one parameter");
                    else if (rule->name.compare("gotitems") == 0 && rule->args.size() != 2)
                        SyntaxError("GotItems requires two parameters");
                    else if (rule->name.compare("lostitems") == 0 && rule->args.size() != 2)
                        SyntaxError("LostItems requires two parameters");
                    else if (rule->name.compare("killednpcs") == 0 && rule->args.size() != 2)
                        SyntaxError("KilledNpcs requires two parameters");
                    else if (rule->name.compare("killedplayers") == 0 && rule->args.size() != 1)
                        SyntaxError("KilledPlayers requires one parameter");
                    else if (rule->name.compare("entercoord") == 0 && rule->args.size() != 3)
                        SyntaxError("EnterCoord requires three parameters");
                    else if (rule->name.compare("leavecoord") == 0 && rule->args.size() != 3)
                        SyntaxError("LeaveCoord requires three parameters");
                    else if (rule->name.compare("entermap") == 0 && rule->args.size() != 1)
                        SyntaxError("EnterMap requires one parameter");
                    else if (rule->name.compare("leavemap") == 0 && rule->args.size() != 1)
                        SyntaxError("LeaveMap requires one parameter");

                    state->rules.push_back(rule);
                    rule->Release();
                    paren_start = paren_end = 0;
                    tempstring.clear();
                    args.clear();
                }
                else
                    tempstring.clear();
            }
        }

        character++;
    }

    if (!questname_said)
        SyntaxError("No questname variable");

    if (!version_said)
        SyntaxError("No version variable");
}

void Quest::Reload(World *world)
{
    this->states.clear();

    char namebuf[4];
    this->exists = true;

    std::string filename = world->config["QuestDir"];
    std::sprintf(namebuf, "%05i", id);
    filename.append(namebuf);
	filename.append(".eqf");
	std::FILE *fh = std::fopen(filename.c_str(), "rt");
	std::string buf;

	if (!fh)
	{
	    Console::Err("Could not load quest file %s", filename.c_str());
	    this->exists = false;
	    return;
	}

	std::fseek(fh, 0, SEEK_END);
	long size = ftell(fh);
	std::rewind(fh);

	buf.resize(size);
	std::fread(&buf[0], 1, size, fh);
	std::fclose(fh);

	Load(buf);
}

State *Quest::GetState(std::string name)
{
    UTIL_PTR_VECTOR_FOREACH(this->states, State, state)
    {
        if (state->name.compare(name) == 0)
        {
            return *state;
        }
    }
    return 0;
}


Create a new paste based on this one


Comments: