Example #1
0
//
// 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;
}
Example #2
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);
}
Example #3
0
//
// 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);
}
Example #4
0
//
// 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;
}
Example #5
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   
}
Example #6
0
//
// 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;
}
Example #7
0
//
// 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);
   }
}
Example #8
0
//
// 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);
}