예제 #1
0
//
// E_VerifyFilter
//
// Because it's exceptionally dangerous to allow the specification of format
// strings by the end user, I'm going to make sure it cannot be abused.
//
static void E_VerifyFilter(const char *str)
{
   const char *rover = str;
   bool inpct = false;
   bool foundpct = false;

   while(*rover != '\0')
   {
      if(inpct)
      {
         // formatting lengths are ok, and are indeed necessary
         if((*rover >= '0' && *rover <= '9') || *rover == '.')
         {
            ++rover;
            continue;
         }

         switch(*rover)
         {
         // allowed characters:
         case 'c': // char
         case 'i': // general int
         case 'd': // int
         case 'x': // hex
         case 'X': // upper-case hex
         case 'o': // octal
         case 'u': // unsigned
            inpct = false;
            break;
         default: // screw you, hacker boy
            E_EDFLoggedErr(2, 
               "E_VerifyFilter: '%s' has bad format specifier '%c'\n",
               str, *rover);
         }
      }
      
      if(*rover == '%')
      {
         if(foundpct) // already found one? dirty hackers.
         {
            E_EDFLoggedErr(2, 
               "E_VerifyFilter: '%s' has too many format specifiers\n",
               str);
         }
         foundpct = true;
         inpct = true;
      }

      ++rover; // let's not forget to do this!
   }
}
예제 #2
0
//
// E_ExtractPrefix
//
// Returns the result of strchr called on the string in value.
// If the return is non-NULL, you can expect to find the extracted
// prefix written into prefixbuf. If the return value is NULL,
// prefixbuf is unmodified.
//
const char *E_ExtractPrefix(const char *value, char *prefixbuf, int buflen)
{
   int i;
   const char *colonloc, *rover, *strval;

   // look for a colon ending a possible prefix
   colonloc = strchr(value, ':');

   if(colonloc)
   {
      strval = colonloc + 1;
      rover = value;
      i = 0;
      
      // 01/10/09: initialize buffer
      memset(prefixbuf, 0, buflen);

      while(rover != colonloc && i < buflen - 1) // leave room for \0
      {
         prefixbuf[i] = *rover;
         ++rover;
         ++i;
      }
      
      // check validity of the string value location (could be end)
      if(!(*strval))
      {
         E_EDFLoggedErr(0,
            "E_ExtractPrefix: invalid prefix:value %s\n", value);
      }
   }

   return colonloc;
}
예제 #3
0
//
// E_ProcessInventoryDeltas
//
// Does processing for inventorydelta sections, which allow cascading editing
// of existing inventory items. The inventorydelta shares most of its fields
// and processing code with the thingtype section.
//
void E_ProcessInventoryDeltas(cfg_t *cfg)
{
   int i, numdeltas;

   E_EDFLogPuts("\t* Processing inventory deltas\n");

   numdeltas = cfg_size(cfg, EDF_SEC_INVDELTA);

   E_EDFLogPrintf("\t\t%d inventorydelta(s) defined\n", numdeltas);

   for(i = 0; i < numdeltas; i++)
   {
      cfg_t       *deltasec = cfg_getnsec(cfg, EDF_SEC_INVDELTA, i);
      inventory_t *inv;

      // get thingtype to edit
      if(!cfg_size(deltasec, ITEM_DELTA_NAME))
         E_EDFLoggedErr(2, "E_ProcessInventoryDeltas: inventorydelta requires name field\n");

      inv = E_GetInventoryForName(cfg_getstr(deltasec, ITEM_DELTA_NAME));

      E_ProcessInventory(inv, deltasec, cfg, false);

      E_EDFLogPrintf("\t\tApplied inventorydelta #%d to %s(#%d)\n",
                     i, inv->name, inv->numkey);
   }
}
예제 #4
0
파일: e_edf.cpp 프로젝트: fragglet/autodoom
//
// E_ProcessSpriteVars
//
// Sets the sprite numbers to be used for the player and blank
// sprites by looking up a provided name in the sprite hash
// table.
//
static void E_ProcessSpriteVars(cfg_t *cfg)
{
   static bool firsttime = true;
   int sprnum;
   const char *str;

   E_EDFLogPuts("\t* Processing sprite variables\n");

   // haleyjd 11/11/09: removed processing of obsolete playersprite variable

   // haleyjd 11/21/11: on subsequent runs, only replace if changed
   if(!firsttime && cfg_size(cfg, ITEM_BLANKSPRITE) == 0)
      return;

   firsttime = false;

   // load blank sprite number

   str = cfg_getstr(cfg, ITEM_BLANKSPRITE);
   sprnum = E_SpriteNumForName(str);
   if(sprnum == -1)
   {
      E_EDFLoggedErr(2, 
         "E_ProcessSpriteVars: invalid blank sprite name: '%s'\n", str);
   }
   E_EDFLogPrintf("\t\tSet sprite %s(#%d) as blank sprite\n", str, sprnum);
   blankSpriteNum = sprnum;
}
예제 #5
0
파일: e_edf.cpp 프로젝트: fragglet/autodoom
//
// E_ParseLumpRecursive
//
// haleyjd 03/21/10: helper routine for E_ParseEDFLump.
// Recursively descends the lump hash chain.
//
static void E_ParseLumpRecursive(cfg_t *cfg, const char *name, int ln)
{
   if(ln >= 0) // terminal case - lumpnum is -1
   {
      lumpinfo_t **lumpinfo = wGlobalDir.getLumpInfo();

      // recurse on next item
      E_ParseLumpRecursive(cfg, name, lumpinfo[ln]->namehash.next);

      // handle this lump
      if(!strncasecmp(lumpinfo[ln]->name, name, 8) &&         // name match
         lumpinfo[ln]->li_namespace == lumpinfo_t::ns_global) // is global
      {
         int err;

         // try to parse it
         if((err = cfg_parselump(cfg, name, ln)))
         {
            E_EDFLoggedErr(1, 
               "E_ParseEDFLump: failed to parse EDF lump %s (#%d, code %d)\n",
               name, ln, err);
         }
      }
   }
}
예제 #6
0
//
// E_CreateString
//
// Creates an EDF string object with the given value which is hashable
// by one or two different keys. The mnemonic key is required and must
// be 128 or fewer characters long. The numeric key is optional. If a
// negative value is passed as the numeric key, the object will not be 
// added to the numeric hash table.
//
edf_string_t *E_CreateString(const char *value, const char *key, int num)
{
   int keyval;
   edf_string_t *newStr;

   if((newStr = E_StringForName(key)))
   {
      // Modify existing object.
      E_ReplaceString(newStr->string, estrdup(value));

      // Modify numeric id and rehash object if necessary
      if(num != newStr->numkey)
      {
         // If old key is >= 0, must remove from hash first
         if(newStr->numkey >= 0)
            E_DelStringFromNumHash(newStr);
         
         // Set new key
         newStr->numkey = num;
         
         // If new key >= 0, add back to hash
         if(newStr->numkey >= 0)
            E_AddStringToNumHash(newStr);
      }
   }
   else
   {
      // Create a new string object
      newStr = estructalloc(edf_string_t, 1);
      
      // copy keys into string object
      if(strlen(key) >= sizeof(newStr->key))
      {
         E_EDFLoggedErr(2, 
            "E_CreateString: invalid string mnemonic '%s'\n", key);
      }
      strncpy(newStr->key, key, sizeof(newStr->key));
      
      newStr->numkey = num;
      
      // duplicate value
      newStr->string = estrdup(value);
      
      // add to hash tables
      
      keyval = D_HashTableKey(newStr->key) % NUM_EDFSTR_CHAINS;
      newStr->next = edf_str_chains[keyval];
      edf_str_chains[keyval] = newStr;
      
      // numeric key is not required
      if(num >= 0)
         E_AddStringToNumHash(newStr);
   }

   return newStr;
}
예제 #7
0
//
// E_AddInventoryToPStack
//
// Adds an inventory definition to the inheritance stack.
//
static void E_AddInventoryToPStack(inventory_t *inv)
{
   // Overflow shouldn't happen since it would require cyclic inheritance as 
   // well, but I'll guard against it anyways.
   
   if(inv_pindex >= numInventoryDefs)
      E_EDFLoggedErr(2, "E_AddInventoryToPStack: max inheritance depth exceeded\n");

   inv_pstack[inv_pindex++] = inv;
}
예제 #8
0
파일: e_edf.cpp 프로젝트: fragglet/autodoom
//
// E_ParseEDFFile
//
// Parses the specified file.
//
static void E_ParseEDFFile(cfg_t *cfg, const char *filename)
{
   int err;

   if((err = cfg_parse(cfg, filename)))
   {
      E_EDFLoggedErr(1, 
         "E_ParseEDFFile: failed to parse %s (code %d)\n",
         filename, err);
   }
}
예제 #9
0
파일: e_edf.cpp 프로젝트: fragglet/autodoom
//
// E_ParseEDFLump
//
// Parses the specified lump. All lumps of the given name will be parsed
// recursively from oldest to newest.
//
static void E_ParseEDFLump(cfg_t *cfg, const char *lumpname)
{
   lumpinfo_t *root;

   // make sure there is at least one lump before starting recursive parsing
   if(W_CheckNumForName(lumpname) < 0)
      E_EDFLoggedErr(1, "E_ParseEDFLump: lump %s not found\n", lumpname);

   // get root of the hash chain for the indicated name
   root = wGlobalDir.getLumpNameChain(lumpname);

   // parse all lumps of this name recursively in last-to-first order
   E_ParseLumpRecursive(cfg, lumpname, root->namehash.index);
}
예제 #10
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   
}
예제 #11
0
파일: e_edf.cpp 프로젝트: fragglet/autodoom
//
// 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);
   }
}
예제 #12
0
파일: e_edf.cpp 프로젝트: fragglet/autodoom
//
// 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);
}