// load a list of triggers static bool eventLoadTriggerList(WzConfig &ini, QString tname) { UDWORD event, offset, time; int numTriggers, context, type, trigger; SCRIPT_CONTEXT *psContext; numTriggers = ini.value("general/num" + tname).toInt(); for (int i = 0; i < numTriggers; i++) { ini.beginGroup(tname + "_" + QString::number(i)); time = ini.value("time").toInt(); context = ini.value("context").toInt(); if (!eventFindContext(context, &psContext)) { debug(LOG_FATAL, "could not find context"); return false; } type = ini.value("type").toInt(); trigger = ini.value("trigger").toInt(); event = ini.value("event").toInt(); offset = ini.value("offset").toInt(); if (!eventLoadTrigger(time, psContext, type, trigger, event, offset)) { debug(LOG_FATAL, "Failed to create trigger"); return false; } ini.endGroup(); } return true; }
// save a list of triggers static bool eventSaveTriggerList(ACTIVE_TRIGGER *psList, QString tname, WzConfig &ini) { int numTriggers = 0, context = 0; for (ACTIVE_TRIGGER *psCurr = psList; psCurr != NULL; psCurr = psCurr->psNext) { if (!eventGetContextIndex(psCurr->psContext, &context)) { debug(LOG_FATAL, "Could not find context"); return false; } ini.beginGroup(tname + "_" + QString::number(numTriggers)); ini.setValue("time", QVariant(psCurr->testTime)); ini.setValue("context", QVariant(context)); ini.setValue("type", QVariant(psCurr->type)); ini.setValue("trigger", QVariant(psCurr->trigger)); ini.setValue("event", QVariant(psCurr->event)); ini.setValue("offset", QVariant(psCurr->offset)); ini.endGroup(); numTriggers++; } ini.setValue("general/num" + tname, QVariant(numTriggers)); return true; }
/** Load the research stats */ bool loadResearch(WzConfig &ini) { ASSERT(ini.isAtDocumentRoot(), "WzConfig instance is in the middle of traversal"); std::vector<WzString> list = ini.childGroups(); PLAYER_RESEARCH dummy; memset(&dummy, 0, sizeof(dummy)); std::vector< std::vector<WzString> > preResearch; preResearch.resize(list.size()); for (size_t inc = 0; inc < list.size(); ++inc) { // HACK FIXME: the code assumes we have empty PLAYER_RESEARCH entries to throw around for (auto &j : asPlayerResList) { j.push_back(dummy); } ini.beginGroup(list[inc]); RESEARCH research; research.index = inc; research.name = ini.string("name"); research.id = list[inc]; //check the name hasn't been used already ASSERT_OR_RETURN(false, checkResearchName(&research, inc), "Research name '%s' used already", getName(&research)); research.ref = REF_RESEARCH_START + inc; research.results = ini.json("results", nlohmann::json::array()); //set subGroup icon WzString subGroup = ini.value("subgroupIconID", "").toWzString(); if (subGroup.compare("") != 0) { research.subGroup = setIconID(subGroup.toUtf8().c_str(), getName(&research)); } else { research.subGroup = NO_RESEARCH_ICON; } //set key topic unsigned int keyTopic = ini.value("keyTopic", 0).toUInt(); ASSERT(keyTopic <= 1, "Invalid keyTopic for research topic - '%s' ", getName(&research)); if (keyTopic <= 1) { research.keyTopic = ini.value("keyTopic", 0).toUInt(); } else { research.keyTopic = 0; } //set tech code UBYTE techCode = ini.value("techCode", 0).toUInt(); ASSERT(techCode <= 1, "Invalid tech code for research topic - '%s' ", getName(&research)); if (techCode == 0) { research.techCode = TC_MAJOR; } else { research.techCode = TC_MINOR; } //set the iconID WzString iconID = ini.value("iconID", "").toWzString(); if (iconID.compare("") != 0) { research.iconID = setIconID(iconID.toUtf8().c_str(), getName(&research)); } else { research.iconID = NO_RESEARCH_ICON; } //get the IMDs used in the interface WzString statID = ini.value("statID", "").toWzString(); research.psStat = nullptr; if (statID.compare("") != 0) { //try find the structure stat with given name research.psStat = getCompStatsFromName(statID); ASSERT_OR_RETURN(false, research.psStat, "Could not find stats for %s research %s", statID.toUtf8().c_str(), getName(&research)); } WzString imdName = ini.value("imdName", "").toWzString(); if (imdName.compare("") != 0) { research.pIMD = modelGet(imdName); ASSERT(research.pIMD != nullptr, "Cannot find the research PIE '%s' for record '%s'", imdName.toUtf8().data(), getName(&research)); } WzString imdName2 = ini.value("imdName2", "").toWzString(); if (imdName2.compare("") != 0) { research.pIMD2 = modelGet(imdName2); ASSERT(research.pIMD2 != nullptr, "Cannot find the 2nd research '%s' PIE for record '%s'", imdName2.toUtf8().data(), getName(&research)); } WzString msgName = ini.value("msgName", "").toWzString(); if (msgName.compare("") != 0) { //check its a major tech code ASSERT(research.techCode == TC_MAJOR, "This research should not have a message associated with it, '%s' the message will be ignored!", getName(&research)); if (research.techCode == TC_MAJOR) { research.pViewData = getViewData(msgName); } } //set the researchPoints unsigned int resPoints = ini.value("researchPoints", 0).toUInt(); ASSERT_OR_RETURN(false, resPoints <= UWORD_MAX, "Research Points too high for research topic - '%s' ", getName(&research)); research.researchPoints = resPoints; //set the research power unsigned int resPower = ini.value("researchPower", 0).toUInt(); ASSERT_OR_RETURN(false, resPower <= UWORD_MAX, "Research Power too high for research topic - '%s' ", getName(&research)); research.researchPower = resPower; //remember research pre-requisites for futher checking preResearch[inc] = ini.value("requiredResearch").toWzStringList(); //set components results std::vector<WzString> compResults = ini.value("resultComponents").toWzStringList(); for (size_t j = 0; j < compResults.size(); j++) { WzString compID = compResults[j].trimmed(); COMPONENT_STATS *pComp = getCompStatsFromName(compID); if (pComp != nullptr) { research.componentResults.push_back(pComp); } else { ASSERT(false, "Invalid item '%s' in list of result components of research '%s' ", compID.toUtf8().c_str(), getName(&research)); } } //set replaced components std::vector<WzString> replacedComp = ini.value("replacedComponents").toWzStringList(); for (size_t j = 0; j < replacedComp.size(); j++) { //read pair of components oldComponent:newComponent std::vector<WzString> pair = replacedComp[j].split(":"); ASSERT(pair.size() == 2, "Invalid item '%s' in list of replaced components of research '%s'. Required format: 'oldItem:newItem, item1:item2'", replacedComp[j].toUtf8().c_str(), getName(&research)); if (pair.size() != 2) { continue; //skip invalid entries } WzString oldCompID = pair[0].trimmed(); WzString newCompID = pair[1].trimmed(); COMPONENT_STATS *oldComp = getCompStatsFromName(oldCompID); if (oldComp == nullptr) { ASSERT(false, "Invalid item '%s' in list of replaced components of research '%s'. Wrong component code.", oldCompID.toUtf8().c_str(), getName(&research)); continue; } COMPONENT_STATS *newComp = getCompStatsFromName(newCompID); if (newComp == nullptr) { ASSERT(false, "Invalid item '%s' in list of replaced components of research '%s'. Wrong component code.", newCompID.toUtf8().c_str(), getName(&research)); continue; } RES_COMP_REPLACEMENT replItem; replItem.pOldComponent = oldComp; replItem.pNewComponent = newComp; research.componentReplacement.push_back(replItem); } //set redundant components std::vector<WzString> redComp = ini.value("redComponents").toWzStringList(); for (size_t j = 0; j < redComp.size(); j++) { WzString compID = redComp[j].trimmed(); COMPONENT_STATS *pComp = getCompStatsFromName(compID); if (pComp == nullptr) { ASSERT(false, "Invalid item '%s' in list of redundant components of research '%s' ", compID.toUtf8().c_str(), getName(&research)); } else { research.pRedArtefacts.push_back(pComp); } } //set result structures std::vector<WzString> resStruct = ini.value("resultStructures").toWzStringList(); for (size_t j = 0; j < resStruct.size(); j++) { WzString strucID = resStruct[j].trimmed(); int structIndex = getStructStatFromName(strucID); ASSERT(structIndex >= 0, "Invalid item '%s' in list of result structures of research '%s' ", strucID.toUtf8().c_str(), getName(&research)); if (structIndex >= 0) { research.pStructureResults.push_back(structIndex); } } //set required structures std::vector<WzString> reqStruct = ini.value("requiredStructures").toWzStringList(); for (size_t j = 0; j < reqStruct.size(); j++) { WzString strucID = reqStruct[j].trimmed(); int structIndex = getStructStatFromName(strucID.toUtf8().c_str()); ASSERT(structIndex >= 0, "Invalid item '%s' in list of required structures of research '%s' ", strucID.toUtf8().c_str(), getName(&research)); if (structIndex >= 0) { research.pStructList.push_back(structIndex); } } //set redundant structures std::vector<WzString> redStruct = ini.value("redStructures").toWzStringList(); for (size_t j = 0; j < redStruct.size(); j++) { WzString strucID = redStruct[j].trimmed(); int structIndex = getStructStatFromName(strucID.toUtf8().c_str()); ASSERT(structIndex >= 0, "Invalid item '%s' in list of redundant structures of research '%s' ", strucID.toUtf8().c_str(), getName(&research)); if (structIndex >= 0) { research.pRedStructs.push_back(structIndex); } } asResearch.push_back(research); ini.endGroup(); } //Load and check research pre-requisites (need do it AFTER loading research items) for (size_t inc = 0; inc < asResearch.size(); inc++) { std::vector<WzString> &preRes = preResearch[inc]; for (size_t j = 0; j < preRes.size(); j++) { WzString resID = preRes[j].trimmed(); RESEARCH *preResItem = getResearch(resID.toUtf8().c_str()); ASSERT(preResItem != nullptr, "Invalid item '%s' in list of pre-requisites of research '%s' ", resID.toUtf8().c_str(), getName(&asResearch[inc])); if (preResItem != nullptr) { asResearch[inc].pPRList.push_back(preResItem->index); } } } return true; }
// save the context information for the script system static bool eventSaveContext(WzConfig &ini) { int numVars, numContext = 0; UDWORD hashedName; // go through the context list for (SCRIPT_CONTEXT *psCCont = psContList; psCCont != NULL; psCCont = psCCont->psNext) { // save the context info if (!resGetHashfromData("SCRIPT", psCCont->psCode, &hashedName)) { debug(LOG_FATAL, "Could not find script resource id"); return false; } numVars = psCCont->psCode->numGlobals + psCCont->psCode->arraySize; ini.beginGroup("context_" + QString::number(numContext)); ini.setValue("context", hashedName); ini.setValue("numVars", numVars); ini.setValue("release", psCCont->release); ini.beginGroup("var"); // save the context variables int countVar = 0; for (VAL_CHUNK *psCVals = psCCont->psGlobals; psCVals != NULL; psCVals = psCVals->psNext) { for (int i = 0; i < CONTEXT_VALS; i++) { INTERP_VAL *psVal = psCVals->asVals + i; ASSERT(psVal->type < SWORD_MAX, "Variable type number %d too big", (int)psVal->type); ini.beginGroup(QString::number(countVar)); ini.setValue("type", QVariant(psVal->type)); ini.setValue("typename", QString(scriptTypeToString(psVal->type))); // for debugging // store the variable value if (psVal->type == VAL_STRING) { ini.setValue("data", QString(psVal->v.sval)); } else if (psVal->type == VAL_BOOL) { ini.setValue("data", QVariant((bool)psVal->v.bval)); } else if (psVal->type == VAL_FLOAT) { ini.setValue("data", QVariant((float)psVal->v.fval)); } else if (psVal->type == VAL_OBJ_GETSET || psVal->type == VAL_FUNC_EXTERN) { ini.setValue("data", QString("n/a")); } else if (psVal->type < VAL_USERTYPESTART) { ini.setValue("data", QVariant(psVal->v.ival)); } else { // user defined type SCR_VAL_SAVE saveFunc = asScrTypeTab[psVal->type - VAL_USERTYPESTART].saveFunc; ASSERT(saveFunc != NULL, "No save function for type %d", psVal->type); if (!saveFunc(psVal, ini)) { debug(LOG_FATAL, "Could not get user defined variable value"); return false; } } numVars -=1; countVar++; ini.endGroup(); if (numVars <= 0) { // done all the variables ASSERT(psCVals->psNext == NULL, "Number of context variables does not match the script code"); break; } } } ASSERT(numVars == 0, "Number of context variables does not match the script code (%d)", numVars); ini.endGroup(); ini.endGroup(); numContext++; } // actually store how many contexts have been saved ini.setValue("general/contexts", QVariant(numContext)); return true; }
// load the context information for the script system static bool eventLoadContext(WzConfig &ini) { SDWORD numVars, numContext; SCRIPT_CONTEXT *psCCont; SCR_VAL_LOAD loadFunc; UDWORD hashedName; SCRIPT_CODE *psCode; CONTEXT_RELEASE release; INTERP_VAL *psVal, data; // get the number of contexts in the save file numContext = ini.value("general/contexts", 0).toInt(); if (numContext == 0) { debug(LOG_FATAL, "No script contexts found -- failed to load script data"); return false; } // go through the contexts for (int context = 0; context < numContext; context++) { ini.beginGroup("context_" + QString::number(context)); hashedName = ini.value("context").toUInt(); numVars = ini.value("numVars").toInt(); release = (CONTEXT_RELEASE)ini.value("release").toInt(); psCode = (SCRIPT_CODE*)resGetDataFromHash("SCRIPT", hashedName); // create the context if (!eventNewContext(psCode, release, &psCCont)) { debug(LOG_FATAL, "Failed to create new context"); return false; } if (numVars != psCode->numGlobals + psCode->arraySize) { ASSERT(false, "Context %d of %d: Number of context variables (%d) does not match the script code (%d)", context, numContext, numVars, psCode->numGlobals + psCode->arraySize); return false; } // bit of a hack this - note the id of the context to link it to the triggers psContList->id = context; ini.beginGroup("var"); // set the context variables for (int i = 0; i < numVars; i++) { ini.beginGroup(QString::number(i)); // get the variable type INTERP_TYPE type = (INTERP_TYPE)ini.value("type").toInt(); // get the variable value if (type < VAL_USERTYPESTART) { data.type = type; switch (type) { case VAL_BOOL: data.v.bval = ini.value("data").toBool(); break; case VAL_FLOAT: data.v.fval = ini.value("data").toFloat(); break; case VAL_INT: case VAL_TRIGGER: case VAL_EVENT: case VAL_VOID: case VAL_OPCODE: case VAL_PKOPCODE: data.v.ival = ini.value("data").toInt(); break; case VAL_STRING: data.v.sval = (char*)malloc(MAXSTRLEN); strcpy(data.v.sval, ini.value("var/" + QString::number(i) + "/data").toString().toAscii().constData()); break; case VAL_OBJ_GETSET: case VAL_FUNC_EXTERN: // do nothing break; default: ASSERT(false, "Invalid internal type"); } // set the value in the context if (!eventSetContextVar(psCCont, i, &data)) { debug(LOG_FATAL, "Could not set variable value"); return false; } } else { // user defined type loadFunc = asScrTypeTab[type - VAL_USERTYPESTART].loadFunc; ASSERT(loadFunc, "No load function for type %d", type); // get the value pointer so that the loadFunc can write directly // into the variables data space. if (!eventGetContextVal(psCCont, i, &psVal)) { debug(LOG_FATAL, "Could not find variable %d in context %d", i, context); return false; } if (!loadFunc(psVal, ini)) { debug(LOG_FATAL, "Could not get variable value context %d, variable %d", context, i); return false; } } ini.endGroup(); } ini.endGroup(); ini.endGroup(); } return true; }