// // E_IncludePrev // // Includes the next WAD lump on the lumpinfo hash chain of the same // name as the current lump being processed (to the user, this is // the "previous" lump of that name). Enables recursive inclusion // of like-named lumps to enable cascading behavior. // int E_IncludePrev(cfg_t *cfg, cfg_opt_t *opt, int argc, const char **argv) { int i; lumpinfo_t **lumpinfo = wGlobalDir.getLumpInfo(); // haleyjd 03/18/10: deprecation warning E_EDFLoggedWarning(0, "Warning: include_prev is deprecated\n"); if(argc != 0) { cfg_error(cfg, "wrong number of args to include_prev()\n"); return 1; } if(!cfg->filename) { cfg_error(cfg, "include_prev: cfg_t filename is undefined\n"); return 1; } if((i = cfg_lexer_source_type(cfg)) < 0) { cfg_error(cfg, "include_prev: cannot call from file\n"); return 1; } // Go down the hash chain and look for the next lump of the same // name within the global namespace. while((i = lumpinfo[i]->namehash.next) >= 0) { if(lumpinfo[i]->li_namespace == lumpinfo_t::ns_global && !strncasecmp(lumpinfo[i]->name, cfg->filename, 8)) { return E_OpenAndCheckInclude(cfg, cfg->filename, i); } } // it is not an error if no such lump is found return 0; }
// // E_StdInclude // // An include function that looks for files in the EXE's directory, as // opposed to the current directory. // int E_StdInclude(cfg_t *cfg, cfg_opt_t *opt, int argc, const char **argv) { const char *filename; if(argc != 1) { cfg_error(cfg, "wrong number of args to stdinclude()\n"); return 1; } // haleyjd 03/15/2010: Using stdinclude on anything other than root.edf is // now considered deprecated because of problems it creates with forward // compatibility of EDF mods when new EDF modules are added. if(!strstr(argv[0], "root.edf")) { E_EDFLoggedWarning(0, "Warning: stdinclude() is deprecated except for " "the inclusion of file 'root.edf'.\n"); } filename = E_BuildDefaultFn(argv[0]); return E_OpenAndCheckInclude(cfg, filename, -1); }
// // Processes the DECORATE state list in a weapon // static void E_processDecorateWepStateList(weaponinfo_t *wi, const char *str, const char *firststate, bool recursive) { edecstateout_t *dso; if(!(dso = E_ParseDecorateStates(str, firststate))) { E_EDFLoggedWarning(2, "Warning: couldn't attach DECORATE states to weapon '%s'.\n", wi->name); return; } // first deal with any gotos that still need resolution if(dso->numgotos) E_processDecorateWepGotos(wi, dso); // add all labeled states from the block to the weaponinfo if(dso->numstates && !recursive) E_processDecorateWepStates(wi, dso); // free the DSO object E_FreeDSO(dso); }
// // bex_include // // 12/12/03: New include function that allows EDF to queue // DeHackEd/BEX files for later processing. This helps to // integrate BEX features such as string editing into the // EDF/BEX superlanguage. // // This function interprets paths relative to the current // file. // static int bex_include(cfg_t *cfg, cfg_opt_t *opt, int argc, const char **argv) { char *currentpath; char *filename = NULL; // haleyjd 03/18/10: deprecation warning E_EDFLoggedWarning(0, "Warning: bexinclude is deprecated. " "Please use a GFS or DEHACKED lump instead.\n"); if(argc != 1) { cfg_error(cfg, "wrong number of args to bexinclude()\n"); return 1; } if(!cfg->filename) { cfg_error(cfg, "bexinclude: cfg_t filename is undefined\n"); return 1; } if(cfg_lexer_source_type(cfg) >= 0) { cfg_error(cfg, "bexinclude: cannot call from a wad lump\n"); return 1; } currentpath = (char *)(Z_Alloca(strlen(cfg->filename) + 1)); M_GetFilePath(cfg->filename, currentpath, strlen(cfg->filename) + 1); filename = M_SafeFilePath(currentpath, argv[0]); // queue the file for later processing D_QueueDEH(filename, 0); return 0; }
// // E_ProcessInventory // // Generalized code to process the data for a single inventory definition // structure. Doubles as code for inventory and inventorydelta. // static void E_ProcessInventory(inventory_t *inv, cfg_t *invsec, cfg_t *pcfg, bool def) { //int tempint; const char *tempstr; bool inherits = false; // possible when inheriting from an inventory def of a previous EDF generation if(!invsec) return; // Process inheritance (not in deltas) if(def) { // if this inventory is already processed via recursion due to // inheritance, don't process it again if(inv->processed) return; if(cfg_size(invsec, ITEM_INVENTORY_INHERITS) > 0) { cfg_t *parent_invsec; // resolve parent inventory def inventory_t *parent = E_GetInventoryForName(cfg_getstr(invsec, ITEM_INVENTORY_INHERITS)); // check against cyclic inheritance if(!E_CheckInventoryInherit(parent)) { E_EDFLoggedErr(2, "E_ProcessInventory: cyclic inheritance detected in inventory '%s'\n", inv->name); } // add to inheritance stack E_AddInventoryToPStack(parent); // process parent recursively parent_invsec = cfg_gettsec(pcfg, EDF_SEC_INVENTORY, parent->name); E_ProcessInventory(parent, parent_invsec, pcfg, true); // copy parent to this thing E_CopyInventory(inv, parent); // keep track of parent explicitly inv->parent = parent; // we inherit, so treat defaults as no value inherits = true; } else inv->parent = NULL; // no parent. // mark this inventory def as processed inv->processed = true; } // field processing if(IS_SET(ITEM_INVENTORY_CLASS)) { const char *classname = cfg_getstr(invsec, ITEM_INVENTORY_CLASS); int classtype = E_StrToNumLinear(inventoryClassNames, INV_CLASS_NUMCLASSES, classname); if(classtype == INV_CLASS_NUMCLASSES) { E_EDFLoggedWarning(2, "Warning: unknown inventory class %s\n", classname); classtype = INV_CLASS_NONE; } inv->classtype = classtype; } #ifdef RANGECHECK if(inv->classtype < 0 || inv->classtype >= INV_CLASS_NUMCLASSES) E_EDFLoggedErr(2, "E_ProcessInventory: internal error - bad classtype %d\n", inv->classtype); #endif // process subclass fields inventorySubClasses[inv->classtype](inv, invsec, def, inherits); if(IS_SET(ITEM_INVENTORY_AMOUNT)) inv->amount = cfg_getint(invsec, ITEM_INVENTORY_AMOUNT); if(IS_SET(ITEM_INVENTORY_MAXAMOUNT)) inv->maxAmount = cfg_getint(invsec, ITEM_INVENTORY_MAXAMOUNT); if(IS_SET(ITEM_INVENTORY_INTERHUBAMOUNT)) inv->interHubAmount = cfg_getint(invsec, ITEM_INVENTORY_INTERHUBAMOUNT); if(IS_SET(ITEM_INVENTORY_ICON)) E_ReplaceString(inv->icon, cfg_getstrdup(invsec, ITEM_INVENTORY_ICON)); if(IS_SET(ITEM_INVENTORY_PICKUPMESSAGE)) E_ReplaceString(inv->pickUpMessage, cfg_getstrdup(invsec, ITEM_INVENTORY_PICKUPMESSAGE)); if(IS_SET(ITEM_INVENTORY_PICKUPSOUND)) E_ReplaceString(inv->pickUpSound, cfg_getstrdup(invsec, ITEM_INVENTORY_PICKUPSOUND)); if(IS_SET(ITEM_INVENTORY_PICKUPFLASH)) E_ReplaceString(inv->pickUpFlash, cfg_getstrdup(invsec, ITEM_INVENTORY_PICKUPFLASH)); if(IS_SET(ITEM_INVENTORY_USESOUND)) E_ReplaceString(inv->useSound, cfg_getstrdup(invsec, ITEM_INVENTORY_USESOUND)); if(IS_SET(ITEM_INVENTORY_RESPAWNTICS)) inv->respawnTics = cfg_getint(invsec, ITEM_INVENTORY_RESPAWNTICS); if(IS_SET(ITEM_INVENTORY_GIVEQUEST)) inv->giveQuest = cfg_getint(invsec, ITEM_INVENTORY_GIVEQUEST); if(IS_SET(ITEM_INVENTORY_FLAGS)) { tempstr = cfg_getstr(invsec, ITEM_INVENTORY_FLAGS); if(*tempstr == '\0') inv->flags = 0; else inv->flags = E_ParseFlags(tempstr, &inventory_flagset); } // TODO: addflags/remflags }
// // E_LoadLinearFont // // Populates a pre-allocated vfont_t with information on a linear font // graphic. // static void E_LoadLinearFont(vfont_t *font, const char *name, int fmt, bool requantize) { int w = 0, h = 0, size = 0, i, lumpnum; bool foundsize = false; // in case this font was changed from patch to block: E_DisposePatches(font); // handle disposal of previous font graphics if(font->data && !E_IsLinearLumpUsed(font, font->data)) { efree(font->data); font->data = NULL; } lumpnum = W_GetNumForName(name); size = W_LumpLength(lumpnum); if(fmt == FONT_FMT_PNG) { // convert PNG to linear VPNGImage fontpng; if(fontpng.readFromLump(wGlobalDir, lumpnum)) { AutoPalette pal(wGlobalDir); bool is8Bit256 = (fontpng.getBitDepth() == 8 && fontpng.getNumColors() == 256); bool doRequantize = (!is8Bit256 || requantize); font->data = fontpng.getAs8Bit(doRequantize ? pal.get() : NULL); w = static_cast<int>(fontpng.getWidth()); h = static_cast<int>(fontpng.getHeight()); size = w * h; } } else if(fmt == FONT_FMT_PATCH) { // convert patch to linear patch_t *p = PatchLoader::CacheNum(wGlobalDir, lumpnum, PU_STATIC); font->data = V_PatchToLinear(p, false, 0, &w, &h); // done with lump Z_ChangeTag(p, PU_CACHE); size = w * h; } else font->data = (byte *)(wGlobalDir.cacheLumpNum(lumpnum, PU_STATIC)); // check for proper dimensions for(i = 5; i <= 32; i++) { if(i * i * 128 == size) { font->lsize = i; foundsize = true; break; } } if(!foundsize) { E_EDFLoggedWarning(2, "Invalid lump dimensions for linear font %s\n", name); if(!E_IsLinearLumpUsed(font, font->data)) efree(font->data); font->data = nullptr; // This font won't be able to draw, too bad. } font->start = 0; font->end = 127; font->size = 128; // full ASCII range is supported // set metrics - linear fonts are monospace font->cw = font->lsize; font->cy = font->lsize; font->dw = 0; font->absh = font->lsize; font->space = font->lsize; // set flags font->centered = false; // not block-centered font->color = true; // supports color translations font->linear = true; // is linear, obviously ;) font->upper = false; // not all-caps // patch array is unused font->fontgfx = nullptr; }
// // E_ProcessBossTypes // // Gets the thing type entries in the boss_spawner_types list, // for use by the SpawnFly codepointer. // // modified by schepe to remove 11-type limit // static void E_ProcessBossTypes(cfg_t *cfg) { int i, a = 0; int numTypes = cfg_size(cfg, SEC_BOSSTYPES); int numProbs = cfg_size(cfg, SEC_BOSSPROBS); bool useProbs = true; E_EDFLogPuts("\t* Processing boss spawn types\n"); if(!numTypes) { // haleyjd 05/31/06: allow zero boss types E_EDFLogPuts("\t\tNo boss types defined\n"); return; } // haleyjd 11/19/03: allow defaults for boss spawn probs if(!numProbs) useProbs = false; if(useProbs ? numTypes != numProbs : numTypes != 11) { E_EDFLoggedErr(2, "E_ProcessBossTypes: %d boss types, %d boss probs\n", numTypes, useProbs ? numProbs : 11); } // haleyjd 11/21/11: allow multiple runs if(BossSpawnTypes) { efree(BossSpawnTypes); BossSpawnTypes = NULL; } if(BossSpawnProbs) { efree(BossSpawnProbs); BossSpawnProbs = NULL; } NumBossTypes = numTypes; BossSpawnTypes = ecalloc(int *, numTypes, sizeof(int)); BossSpawnProbs = ecalloc(int *, numTypes, sizeof(int)); // load boss spawn probabilities for(i = 0; i < numTypes; ++i) { if(useProbs) { a += cfg_getnint(cfg, SEC_BOSSPROBS, i); BossSpawnProbs[i] = a; } else BossSpawnProbs[i] = BossDefaults[i]; } // check that the probabilities total 256 if(useProbs && a != 256) { E_EDFLoggedErr(2, "E_ProcessBossTypes: boss spawn probs do not total 256\n"); } for(i = 0; i < numTypes; ++i) { const char *typeName = cfg_getnstr(cfg, SEC_BOSSTYPES, i); int typeNum = E_ThingNumForName(typeName); if(typeNum == -1) { E_EDFLoggedWarning(2, "Warning: invalid boss type '%s'\n", typeName); typeNum = UnknownThingType; } BossSpawnTypes[i] = typeNum; E_EDFLogPrintf("\t\tAssigned type %s(#%d) to boss type %d\n", mobjinfo[typeNum]->name, typeNum, i); } }
// // E_ProcessCast // // Creates the DOOM II cast call information // static void E_ProcessCast(cfg_t *cfg) { static bool firsttime = true; int i, numcastorder = 0, numcastsections = 0; cfg_t **ci_order; E_EDFLogPuts("\t* Processing cast call\n"); // get number of cast sections numcastsections = cfg_size(cfg, SEC_CAST); if(firsttime && !numcastsections) // on main parse, at least one is required. E_EDFLoggedErr(2, "E_ProcessCast: no cast members defined.\n"); firsttime = false; E_EDFLogPrintf("\t\t%d cast member(s) defined\n", numcastsections); // haleyjd 11/21/11: allow multiple runs if(castorder) { int i; // free names for(i = 0; i < max_castorder; i++) { if(castorder[i].name) efree(castorder[i].name); } // free castorder efree(castorder); castorder = NULL; max_castorder = 0; } // check if the "castorder" array is defined for imposing an // order on the castinfo sections numcastorder = cfg_size(cfg, SEC_CASTORDER); E_EDFLogPrintf("\t\t%d cast member(s) in castorder\n", numcastorder); // determine size of castorder max_castorder = (numcastorder > 0) ? numcastorder : numcastsections; // allocate with size+1 for an end marker castorder = estructalloc(castinfo_t, max_castorder + 1); ci_order = ecalloc(cfg_t **, sizeof(cfg_t *), max_castorder); if(numcastorder > 0) { for(i = 0; i < numcastorder; ++i) { const char *title = cfg_getnstr(cfg, SEC_CASTORDER, i); cfg_t *section = cfg_gettsec(cfg, SEC_CAST, title); if(!section) { E_EDFLoggedErr(2, "E_ProcessCast: unknown cast member '%s' in castorder\n", title); } ci_order[i] = section; } } else { // no castorder array is defined, so use the cast members // in the order they are encountered (for backward compatibility) for(i = 0; i < numcastsections; ++i) ci_order[i] = cfg_getnsec(cfg, SEC_CAST, i); } for(i = 0; i < max_castorder; ++i) { int j; const char *tempstr; int tempint = 0; cfg_t *castsec = ci_order[i]; // resolve thing type tempstr = cfg_getstr(castsec, ITEM_CAST_TYPE); if(!tempstr || (tempint = E_ThingNumForName(tempstr)) == -1) { E_EDFLoggedWarning(2, "Warning: cast %d: unknown thing type %s\n", i, tempstr); tempint = UnknownThingType; } castorder[i].type = tempint; // get cast name, if any -- the first seventeen entries can // default to using the internal string editable via BEX strings tempstr = cfg_getstr(castsec, ITEM_CAST_NAME); if(cfg_size(castsec, ITEM_CAST_NAME) == 0 && i < 17) castorder[i].name = NULL; // set from DeHackEd else castorder[i].name = estrdup(tempstr); // store provided value // get stopattack flag (used by player) castorder[i].stopattack = cfg_getbool(castsec, ITEM_CAST_SA); // process sound blocks (up to four will be processed) tempint = cfg_size(castsec, ITEM_CAST_SOUND); for(j = 0; j < 4; ++j) { castorder[i].sounds[j].frame = 0; castorder[i].sounds[j].sound = 0; } for(j = 0; j < tempint && j < 4; ++j) { int num; sfxinfo_t *sfx; const char *name; cfg_t *soundsec = cfg_getnsec(castsec, ITEM_CAST_SOUND, j); // if these are invalid, just fill them with zero rather // than causing an error, as they're very unimportant // name of sound to play name = cfg_getstr(soundsec, ITEM_CAST_SOUNDNAME); // haleyjd 03/22/06: modified to support dehnum auto-allocation if((sfx = E_EDFSoundForName(name)) == NULL) { E_EDFLoggedWarning(2, "Warning: cast member references invalid sound %s\n", name); castorder[i].sounds[j].sound = 0; } else { if(sfx->dehackednum != -1 || E_AutoAllocSoundDEHNum(sfx)) castorder[i].sounds[j].sound = sfx->dehackednum; else { E_EDFLoggedWarning(2, "Warning: could not auto-allocate a DeHackEd number " "for sound %s\n", name); castorder[i].sounds[j].sound = 0; } } // name of frame that triggers sound event name = cfg_getstr(soundsec, ITEM_CAST_SOUNDFRAME); if((num = E_StateNumForName(name)) < 0) num = 0; castorder[i].sounds[j].frame = num; } } // initialize the end marker to all zeroes memset(&castorder[max_castorder], 0, sizeof(castinfo_t)); // free the ci_order table efree(ci_order); }