void CUnitTable::ReadModConfig() { L(ai, "[CUnitTable::ReadModConfig()]"); std::stringstream msg; std::string cfgFileName = GetModCfgName(); FILE* f = fopen(cfgFileName.c_str(), "r"); if (f != NULL) { msg << "\tparsing existing mod configuration file "; msg << cfgFileName; L(ai, msg.str()); // read the mod's .cfg file char str[1024] = {0}; char unitName[512] = {0}; float unitCostMult = 1.0f; int unitTechLvl = -1; UnitCategory defUnitCat = CAT_LAST; UnitCategory cfgUnitCat = CAT_LAST; while (fgets(str, 1024, f) != NULL) { if (str[0] == '/' && str[1] == '/') { continue; } const int i = sscanf(str, "%s %f %d %d", unitName, &unitCostMult, &unitTechLvl, (int*) &cfgUnitCat); const UnitDef* udef = ai->cb->GetUnitDef(unitName); if ((i == 4) && udef != NULL) { UnitType* utype = &unitTypes[udef->id]; utype->costMultiplier = unitCostMult; utype->techLevel = unitTechLvl; defUnitCat = utype->category; msg.str(""); msg << "\t\tudef->id: " << udef->id << ", udef->name: " << udef->name; msg << ", default cat.: " << defUnitCat << ", .cfg cat.: " << cfgUnitCat; L(ai, msg.str()); // TODO: look for any possible side-effects that might arise // from overriding categories like this, then enable overrides // other than builder --> attacker? // // FIXME: SEGV when unarmed CAT_BUILDER units masquerading as // CAT_G_ATTACK'ers want to or are attacked (NULL weapondefs) // if (cfgUnitCat >= 0 && cfgUnitCat < CAT_LAST) { if (cfgUnitCat == CAT_G_ATTACK && defUnitCat == CAT_BUILDER) { msg.str(""); msg << "\t\t\t.cfg unit category (CAT_G_ATTACK) overrides utype->category (CAT_BUILDER)"; L(ai, msg.str()); std::vector<int>::iterator vit; std::vector<int>& oldDefs = categoryData.GetDefsForUnitCat(defUnitCat); std::vector<int>& newDefs = categoryData.GetDefsForUnitCat(cfgUnitCat); for (vit = oldDefs.begin(); vit != oldDefs.end(); vit++) { const int udefID = *vit; if (udefID == udef->id) { oldDefs.erase(vit); newDefs.push_back(udef->id); vit--; } } utype->category = cfgUnitCat; } } } } msg.str(""); msg << "read mod configuration file "; msg << cfgFileName; L(ai, msg.str()); } else { msg.str(""); msg << "\tcreating new mod configuration file "; msg << cfgFileName; L(ai, msg.str()); // write a new .cfg file with default values f = fopen(cfgFileName.c_str(), "w"); fprintf(f, "// unitName costMultiplier techLevel category\n"); for (int i = 1; i <= numDefs; i++) { UnitType* utype = &unitTypes[i]; // assign and write default values for costMultiplier // and techLevel, category is already set in ::Init() utype->costMultiplier = 1.0f; utype->techLevel = -1; fprintf( f, "%s %.2f %d %d\n", utype->def->name.c_str(), utype->costMultiplier, utype->techLevel, utype->category ); msg.str(""); msg << "\t\tname: " << (utype->def->name); msg << ", .cfg category: " << (utype->category); L(ai, msg.str()); } msg.str(""); msg << "wrote mod configuration file "; msg << cfgFileName; L(ai, msg.str()); } fclose(f); }
void CUnitTable::ReadModConfig() { ai->GetLogger()->Log("[CUnitTable::ReadModConfig()]"); std::string cfgFileName = GetModCfgName(); std::fstream cfgFile; std::stringstream msg; int cfgVersion = 0; if (ai->cb->GetFileSize(cfgFileName.c_str()) != -1) { if (!ai->luaParser->Execute(cfgFileName, "config")) { msg << "\tparse-error in existing mod configuration file \""; msg << cfgFileName << "\": " << ai->luaParser->GetError(); ai->GetLogger()->Log(msg.str()); return; } else { msg << "\tparsed existing mod configuration file \""; msg << cfgFileName << "\""; ai->GetLogger()->Log(msg.str()); } const LuaTable* rootTbl = ai->luaParser->GetRootTbl(); const LuaTable* unitTbl = NULL; const UnitDef* unitDef = NULL; if (rootTbl->GetIntVal("version", cfgVersion) > CFGVERSION) { msg.str(""); msg << "\tconfig-file version (" << cfgVersion << ") is newer than current version (" << CFGVERSION << ")"; return; } UnitType* unitType = NULL; UnitCategory defUnitCat = CAT_LAST; UnitCategory cfgUnitCat = CAT_LAST; std::list<std::string> keys; rootTbl->GetStrTblKeys(&keys); for (std::list<std::string>::const_iterator it = keys.begin(); it != keys.end(); ++it) { unitDef = ai->cb->GetUnitDef((*it).c_str()); if (unitDef == NULL) { msg.str(""); msg << "\t\t.cfg entry \"" << (*it) << "\" does not refer to a valid unit-type"; ai->GetLogger()->Log(msg.str()); continue; } unitTbl = rootTbl->GetTblVal(*it); unitType = &unitTypes[unitDef->id]; unitType->costMultiplier = unitTbl->GetIntVal("costMult", 100) / 100.0f; unitType->techLevel = unitTbl->GetIntVal("techLevel", -1); defUnitCat = unitType->category; cfgUnitCat = UnitCategory(unitTbl->GetIntVal("category", CAT_LAST)); { msg.str(""); msg << "\t\tunitDef->id: " << unitDef->id << ", unitDef->name: " << unitDef->name; msg << ", default cat.: " << defUnitCat << ", .cfg cat.: " << cfgUnitCat; ai->GetLogger()->Log(msg.str()); } /* * TODO: look for any possible "side-effects" that might arise * from overriding categories like this, then enable overrides * other than builder --> attacker (ie. SEGV when an *unarmed* * CAT_BUILDER unit masquerading as a CAT_G_ATTACK'er wants to * or is attacked, due to NULL weapondefs) */ if (defUnitCat != cfgUnitCat) { if (cfgUnitCat < 0 || cfgUnitCat >= CAT_LAST) { // invalid unit-category number continue; } if (cfgUnitCat == CAT_G_ATTACK && defUnitCat == CAT_BUILDER) { { msg.str(""); msg << "\t\t\t.cfg unit category (CAT_G_ATTACK) overrides unitType->category (CAT_BUILDER)"; ai->GetLogger()->Log(msg.str()); } std::vector<int>::iterator vit; std::vector<int>& oldDefs = categoryData.GetDefsForUnitCat(defUnitCat); std::vector<int>& newDefs = categoryData.GetDefsForUnitCat(cfgUnitCat); for (vit = oldDefs.begin(); vit != oldDefs.end(); vit++) { const int unitDefID = *vit; if (unitDefID == unitDef->id) { oldDefs.erase(vit); newDefs.push_back(unitDefID); vit--; } } unitType->category = cfgUnitCat; } } } } else { { msg.str(""); msg << "\twriting new mod configuration file \""; msg << cfgFileName << "\""; ai->GetLogger()->Log(msg.str()); } cfgFile.open(cfgFileName.c_str(), std::ios::out); cfgFile << "config = {\n"; cfgFile << "\tversion = " << CFGVERSION << ",\n\n"; for (int i = 1; i <= numDefs; i++) { UnitType* unitType = &unitTypes[i]; // assign and write default values for costMultiplier // and techLevel, category is already set in ::Init() unitType->costMultiplier = 1.0f; unitType->techLevel = -1; cfgFile << "\t" << unitType->def->name << " = {\n"; cfgFile << "\t\tcostMult = " << unitType->costMultiplier << " * 100" << ",\n"; cfgFile << "\t\ttechLevel = " << unitType->techLevel << ",\n"; cfgFile << "\t\tcategory = " << unitType->category << ",\n"; cfgFile << "\t},\n"; } cfgFile << "}\n"; cfgFile.close(); } }