/* * psquest.cpp * // * Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation (version 2 of the License) * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include "util/log.h" #include "util/strutil.h" #include "util/consoleout.h" #include "../globals.h" #include "../psserver.h" #include "../cachemanager.h" #include "psquest.h" #include "psquestprereqops.h" #include "dictionary.h" psQuest::psQuest() { id = 0; parent_quest = NULL; image = NULL; step_id = 0; player_lockout_time = 0; quest_lockout_time = 0; quest_last_activated = 0; prerequisite = NULL; } psQuest::~psQuest() { if (prerequisite) delete prerequisite; prerequisite = NULL; for(size_t i = 0;i < triggerPairs.Length(); i++) { TriggerResponse triggerResponse = triggerPairs.Get(i); dict->DeleteTriggerResponse(triggerResponse.trigger, triggerResponse.responseID); } // delete subquests for(size_t i = 0;i < subquests.Length(); i++) CacheManager::GetSingleton().UnloadQuest(subquests.Get(i)); } void psQuest::Init(int new_id, const char *new_name) { id = new_id; name = new_name; } bool psQuest::Load(iResultRow& row) { id = row.GetInt("id"); name = row["name"]; task = row["task"]; flags = row.GetInt("flags"); step_id = row.GetInt("minor_step_number"); category = row["category"]; prerequisiteStr = row["prerequisite"]; parent_quest = CacheManager::GetSingleton().GetQuestByID( row.GetUInt32("master_quest_id") ); image = CacheManager::GetSingleton().FindCommonString( row.GetUInt32("cstr_id_icon") ); // the value is expressed in seconds player_lockout_time = row.GetInt("player_lockout_time")*1000; // Convert from sec to ticks quest_lockout_time = row.GetInt("quest_lockout_time")*1000; // Convert from sec to ticks return true; } bool LoadPrerequisiteXML(iDocumentNode * topNode, psQuestPrereqOp*&prerequisite) { // Recursively decode the xml document and generate prerequisite operators. if ( strcmp( topNode->GetValue(), "pre" ) == 0 ) { // This is the top node. Only one node is legal. csRef iter = topNode->GetNodes(); while ( iter->HasNext() ) { csRef node = iter->Next(); if ( node->GetType() != CS_NODE_ELEMENT ) continue; LoadPrerequisiteXML(node,prerequisite); break; } } else if ( strcmp( topNode->GetValue(), "completed" ) == 0 ) { if (topNode->GetAttributeValue("quest")) { psQuest * quest = CacheManager::GetSingleton().GetQuestByName( topNode->GetAttributeValue("quest") ); if (quest) { prerequisite = new psQuestPrereqOpQuestCompleted(quest); } else { Error2("Can't find quest %s while loading prerequisite script", topNode->GetAttributeValue("quest")); } } else if (topNode->GetAttributeValue("category")) { int min = -1,max = -1; csString category = topNode->GetAttributeValue("category"); if (topNode->GetAttributeValue("min")) min = topNode->GetAttributeValueAsInt("min"); if (topNode->GetAttributeValue("max")) max = topNode->GetAttributeValueAsInt("max"); if (min == -1 && max == -1) { Error1("Both min and max is -1, seting min to 1"); min = 1; } prerequisite = new psQuestPrereqOpQuestCompletedCategory(category,min,max); } else { Error1("No attrib of quest or category in the completed node."); return false; } } else if ( strcmp( topNode->GetValue(), "assigned" ) == 0 ) { psQuest * quest = CacheManager::GetSingleton().GetQuestByName( topNode->GetAttributeValue("quest") ); if (quest) { prerequisite = new psQuestPrereqOpQuestAssigned(quest); } else { Error2("Can't find quest %s while loading prerequisite script", topNode->GetAttributeValue("quest")); return false; } } else if ( strcmp( topNode->GetValue(), "and" ) == 0 ) { psQuestPrereqOpList * list = new psQuestPrereqOpAnd(); prerequisite = list; csRef iter = topNode->GetNodes(); while ( iter->HasNext() ) { csRef node = iter->Next(); if (node->GetType() != CS_NODE_ELEMENT) continue; psQuestPrereqOp * op = NULL; LoadPrerequisiteXML(node,op); if (op) { list->Push(op); } else return false; } } else if ( strcmp( topNode->GetValue(), "or" ) == 0 ) { psQuestPrereqOpList * list = new psQuestPrereqOpOr(); prerequisite = list; csRef iter = topNode->GetNodes(); while ( iter->HasNext() ) { csRef node = iter->Next(); if ( node->GetType() != CS_NODE_ELEMENT ) continue; psQuestPrereqOp * op = NULL; LoadPrerequisiteXML(node,op); if (op) { list->Push(op); } else return false; } } else if ( strcmp( topNode->GetValue(), "require" ) == 0 ) { int min = -1,max = -1; if (topNode->GetAttributeValue("min")) min = topNode->GetAttributeValueAsInt("min"); if (topNode->GetAttributeValue("max")) max = topNode->GetAttributeValueAsInt("max"); psQuestPrereqOpList * list = new psQuestPrereqOpRequire(min,max); prerequisite = list; csRef iter = topNode->GetNodes(); while ( iter->HasNext() ) { csRef node = iter->Next(); if ( node->GetType() != CS_NODE_ELEMENT ) continue; psQuestPrereqOp * op = NULL; LoadPrerequisiteXML(node,op); if (op) { list->Push(op); } } } else if ( strcmp( topNode->GetValue(), "not" ) == 0 ) { csRef iter = topNode->GetNodes(); while ( iter->HasNext() ) { csRef node = iter->Next(); if ( node->GetType() != CS_NODE_ELEMENT ) continue; psQuestPrereqOp * op; LoadPrerequisiteXML(node,op); psQuestPrereqOpList* list = new psQuestPrereqOpNot(); list->Push(op); prerequisite = list; break; } } else { Error2("Node \"%s\" isn't supported in prerequisite scripts",topNode->GetValue()); return false; } return true; } bool LoadPrerequisiteXML(psQuestPrereqOp*&prerequisite, csString script) { csRef xml = csPtr(new csTinyDocumentSystem); csRef doc = xml->CreateDocument(); const char* error = doc->Parse( script ); if ( error ) { Error3("%s\n%s",error, script.GetDataSafe() ); return false; } csRef root = doc->GetRoot(); if(!root) { Error1("No XML root in prerequisite script"); return false; } csRef topNode = root->GetNode("pre"); if (topNode) return LoadPrerequisiteXML(topNode,prerequisite); else { Error1("Could not find
 tag in prerequisite script!");
        return false;
    }    

    return true;
}



bool psQuest::PostLoad()
{
    // Parse the prerequisite string
    if (prerequisiteStr != "")
    {
        Debug2(LOG_QUESTS,0, "Loading prereq  : %s", prerequisiteStr.GetDataSafe());

        LoadPrerequisiteXML(prerequisite,prerequisiteStr);
        prerequisiteStr.Empty();
        if (prerequisite)
        {
            Debug2(LOG_QUESTS, 0, "Resulting prereq: %s\n", prerequisite->GetScript().GetDataSafe());
        }
        else
            return false;
    }

    return true;
}

bool psQuest::AddPrerequisite(csString prerequisitescript)
{
    psQuestPrereqOp * op;
    LoadPrerequisiteXML(op,prerequisitescript);
    if (op) AddPrerequisite(op);
    return true;
}


bool psQuest::AddPrerequisite(psQuestPrereqOp * op)
{
    // Make sure that the first op is an AND list if there are an
    // prerequisite from before.
    if (prerequisite)
    {
        // Check if first op is an and list.
        psQuestPrereqOpAnd * list = dynamic_cast(prerequisite);
        if (list == NULL)
        {
            // If not insert an and list.
            list = new psQuestPrereqOpAnd();
            list->Push(prerequisite);
            prerequisite = list;
        }

        list->Push(op);
    }
    else
    {
        // No prerequisite from before so just set this.
        prerequisite = op;
    }

    return true;
}

void psQuest::AddTriggerResponse(NpcTrigger * trigger, int responseID)
{
    TriggerResponse triggerPair;
    triggerPair.responseID = responseID;
    triggerPair.trigger    = trigger;
    triggerPairs.Push(triggerPair);
}

csString psQuest::GetPrerequisiteStr()
{
    if (prerequisite)
        return prerequisite->GetScript();

    return "";
}