//========================================================================== //*** // DoActionSpecials // handles action specials as code pointers // //========================================================================== bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) { int i; int min_args, max_args; FString specname = sc.String; int special = P_FindLineSpecial(sc.String, &min_args, &max_args); if (special > 0 && min_args >= 0) { int paramindex=PrepareStateParameters(&state, 6, bag.Info->Class); StateParams.Set(paramindex, new FxConstant(special, sc)); // Make this consistent with all other parameter parsing if (sc.CheckToken('(')) { for (i = 0; i < 5;) { StateParams.Set(paramindex+i+1, ParseExpression (sc, bag.Info->Class)); i++; if (!sc.CheckToken (',')) break; } sc.MustGetToken (')'); } else i=0; if (i < min_args) { sc.ScriptError ("Too few arguments to %s", specname.GetChars()); } if (i > max_args) { sc.ScriptError ("Too many arguments to %s", specname.GetChars()); } state.SetAction(FindGlobalActionFunction("A_CallSpecial"), false); return true; } return false; }
void ParseCompatibility() { TArray<FMD5Holder> md5array; FMD5Holder md5; FCompatValues flags; int i, x; unsigned int j; BCompatMap.Clear(); CompatParams.Clear(); // The contents of this file are not cumulative, as it should not // be present in user-distributed maps. FScanner sc(Wads.GetNumForFullName("compatibility.txt")); while (sc.GetString()) // Get MD5 signature { do { if (strlen(sc.String) != 32) { sc.ScriptError("MD5 signature must be exactly 32 characters long"); } for (i = 0; i < 32; ++i) { if (sc.String[i] >= '0' && sc.String[i] <= '9') { x = sc.String[i] - '0'; } else { sc.String[i] |= 'a' ^ 'A'; if (sc.String[i] >= 'a' && sc.String[i] <= 'f') { x = sc.String[i] - 'a' + 10; } else { x = 0; sc.ScriptError("MD5 signature must be a hexadecimal value"); } } if (!(i & 1)) { md5.Bytes[i / 2] = x << 4; } else { md5.Bytes[i / 2] |= x; } } md5array.Push(md5); sc.MustGetString(); } while (!sc.Compare("{")); memset(flags.CompatFlags, 0, sizeof(flags.CompatFlags)); flags.ExtCommandIndex = ~0u; while (sc.GetString()) { if ((i = sc.MatchString(&Options[0].Name, sizeof(*Options))) >= 0) { flags.CompatFlags[Options[i].WhichSlot] |= Options[i].CompatFlags; } else if (sc.Compare("clearlineflags")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_CLEARFLAGS); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setlineflags")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETFLAGS); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setlinespecial")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETSPECIAL); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetString(); CompatParams.Push(P_FindLineSpecial(sc.String, NULL, NULL)); for (int i = 0; i < 5; i++) { sc.MustGetNumber(); CompatParams.Push(sc.Number); } } else if (sc.Compare("clearlinespecial")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_CLEARSPECIAL); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setactivation")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETACTIVATION); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setsectoroffset")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETSECTOROFFSET); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(SectorPlanes)); sc.MustGetFloat(); CompatParams.Push(int(sc.Float*65536.)); } else if (sc.Compare("setsectorspecial")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETSECTORSPECIAL); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setwallyscale")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETWALLYSCALE); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(LineSides)); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(WallTiers)); sc.MustGetFloat(); CompatParams.Push(int(sc.Float*65536.)); } else if (sc.Compare("setwalltexture")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETWALLTEXTURE); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(LineSides)); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(WallTiers)); sc.MustGetString(); const FString texName = sc.String; const unsigned int texIndex = TexNames.Find(texName); const unsigned int texCount = TexNames.Size(); if (texIndex == texCount) { TexNames.Push(texName); } CompatParams.Push(texIndex); } else if (sc.Compare("setthingz")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETTHINGZ); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetFloat(); CompatParams.Push(int(sc.Float*256)); // do not use full fixed here so that it can eventually handle larger levels } else if (sc.Compare("setsectortag")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETTAG); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setthingflags")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETTHINGFLAGS); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setvertex")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETVERTEX); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetFloat(); CompatParams.Push(int(sc.Float * 256)); // do not use full fixed here so that it can eventually handle larger levels sc.MustGetFloat(); CompatParams.Push(int(sc.Float * 256)); // do not use full fixed here so that it can eventually handle larger levels flags.CompatFlags[SLOT_BCOMPAT] |= BCOMPATF_REBUILDNODES; } else if (sc.Compare("setthingskills")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETTHINGSKILLS); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setsectortexture")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETSECTORTEXTURE); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(SectorPlanes)); sc.MustGetString(); const FString texName = sc.String; const unsigned int texIndex = TexNames.Find(texName); const unsigned int texCount = TexNames.Size(); if (texIndex == texCount) { TexNames.Push(texName); } CompatParams.Push(texIndex); } else if (sc.Compare("setsectorlight")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETSECTORLIGHT); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else { sc.UnGet(); break; } } if (flags.ExtCommandIndex != ~0u) { CompatParams.Push(CP_END); } sc.MustGetStringName("}"); for (j = 0; j < md5array.Size(); ++j) { BCompatMap[md5array[j]] = flags; } md5array.Clear(); } }
void ParseCompatibility() { TArray<FMD5Holder> md5array; FMD5Holder md5; FCompatValues flags; int i, x; unsigned int j; BCompatMap.Clear(); CompatParams.Clear(); // The contents of this file are not cumulative, as it should not // be present in user-distributed maps. FScanner sc(Wads.GetNumForFullName("compatibility.txt")); while (sc.GetString()) // Get MD5 signature { do { if (strlen(sc.String) != 32) { sc.ScriptError("MD5 signature must be exactly 32 characters long"); } for (i = 0; i < 32; ++i) { if (sc.String[i] >= '0' && sc.String[i] <= '9') { x = sc.String[i] - '0'; } else { sc.String[i] |= 'a' ^ 'A'; if (sc.String[i] >= 'a' && sc.String[i] <= 'f') { x = sc.String[i] - 'a' + 10; } else { x = 0; sc.ScriptError("MD5 signature must be a hexadecimal value"); } } if (!(i & 1)) { md5.Bytes[i / 2] = x << 4; } else { md5.Bytes[i / 2] |= x; } } md5array.Push(md5); sc.MustGetString(); } while (!sc.Compare("{")); memset(flags.CompatFlags, 0, sizeof(flags.CompatFlags)); flags.ExtCommandIndex = ~0u; while (sc.GetString()) { if ((i = sc.MatchString(&Options[0].Name, sizeof(*Options))) >= 0) { flags.CompatFlags[Options[i].WhichSlot] |= Options[i].CompatFlags; } else if (sc.Compare("clearlineflags")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_CLEARFLAGS); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setlineflags")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETFLAGS); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setlinespecial")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETSPECIAL); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetString(); CompatParams.Push(P_FindLineSpecial(sc.String, NULL, NULL)); for (int i = 0; i < 5; i++) { sc.MustGetNumber(); CompatParams.Push(sc.Number); } } else if (sc.Compare("clearlinespecial")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_CLEARSPECIAL); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setactivation")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETACTIVATION); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("sectorflooroffset")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SECTORFLOOROFFSET); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetFloat(); CompatParams.Push(FLOAT2FIXED(sc.Float)); } else if (sc.Compare("setwallyscale")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETWALLYSCALE); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(LineSides)); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(WallTiers)); sc.MustGetFloat(); CompatParams.Push(FLOAT2FIXED(sc.Float)); } else if (sc.Compare("setthingz")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETTHINGZ); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetFloat(); CompatParams.Push(FLOAT2FIXED(sc.Float)); } else if (sc.Compare("setsectortag")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETTAG); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setthingflags")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETTHINGFLAGS); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else { sc.UnGet(); break; } } if (flags.ExtCommandIndex != ~0u) { CompatParams.Push(CP_END); } sc.MustGetStringName("}"); for (j = 0; j < md5array.Size(); ++j) { BCompatMap[md5array[j]] = flags; } md5array.Clear(); } }
void MapLoader::parseEDLinedef(FScanner &sc, TMap<int, EDLinedef> &EDLines) { EDLinedef ld; bool argsset = false; memset(&ld, 0, sizeof(ld)); ld.alpha = 1.; sc.MustGetStringName("{"); while (!sc.CheckString("}")) { sc.MustGetString(); if (sc.Compare("recordnum")) { sc.CheckString("="); sc.MustGetNumber(); ld.recordnum = sc.Number; } else if (sc.Compare("tag")) { sc.CheckString("="); sc.MustGetNumber(); ld.tag = sc.Number; } else if (sc.Compare("id")) { sc.CheckString("="); sc.MustGetNumber(); ld.id = sc.Number; } else if (sc.Compare("special")) { sc.CheckString("="); if (sc.CheckNumber()) { // Oh joy, this is going to be fun... // Here we cannot do anything because we need the tag to make this work. // For now just store a negative number and resolve this later. ld.special = -sc.Number; } else { sc.MustGetString(); ld.special = P_FindLineSpecial(sc.String); } } else if (sc.Compare("args")) { sc.CheckString("="); sc.MustGetStringName("{"); int c = 0; while (true) { sc.MustGetNumber(); ld.args[c++] = sc.Number; if (sc.CheckString("}")) break; sc.MustGetStringName(","); } argsset = true; } else if (sc.Compare("alpha")) { sc.CheckString("="); sc.MustGetFloat(); ld.alpha = sc.Float; } else if (sc.Compare("extflags")) { // these are needed to build the proper activation mask out of the possible flags which do not match ZDoom 1:1. uint32_t actmethod = 0; uint32_t acttype = 0; do { sc.CheckString("="); sc.MustGetString(); for (const char *tok = strtok(sc.String, ",+ \t"); tok != nullptr; tok = strtok(nullptr, ",+ \t")) { if (!stricmp(tok, "USE")) actmethod |= SPAC_Use | SPAC_MUse; else if (!stricmp(tok, "CROSS")) actmethod |= SPAC_Cross | SPAC_MCross | SPAC_PCross; else if (!stricmp(tok, "IMPACT")) ld.activation |= SPAC_Impact; else if (!stricmp(tok, "PUSH")) actmethod |= SPAC_Push; else if (!stricmp(tok, "PLAYER")) acttype |= SPAC_Use | SPAC_Cross | SPAC_Push; else if (!stricmp(tok, "MONSTER")) acttype |= SPAC_MUse | SPAC_MCross | SPAC_MPush; else if (!stricmp(tok, "MISSILE")) acttype |= SPAC_PCross; else if (!stricmp(tok, "REPEAT")) ld.flags |= ML_REPEAT_SPECIAL; else if (!stricmp(tok, "1SONLY")) ld.flags |= ML_FIRSTSIDEONLY; else if (!stricmp(tok, "ADDITIVE")) ld.flags |= ML_ADDTRANS; else if (!stricmp(tok, "BLOCKALL")) ld.flags |= ML_BLOCKEVERYTHING; else if (!stricmp(tok, "ZONEBOUNDARY")) ld.flags |= ML_ZONEBOUNDARY; else if (!stricmp(tok, "CLIPMIDTEX")) ld.flags |= ML_CLIP_MIDTEX; else sc.ScriptError("Unknown option '%s'", tok); } } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. // and finally we must mask in the activation method ld.activation |= (actmethod & acttype); } else { sc.ScriptError("Unknown property '%s'", sc.String); } } if (ld.tag == 0) ld.tag = ld.id; // urgh... if (ld.special < 0) // translate numeric specials. { line_t line; maplinedef_t mld; mld.special = -ld.special; mld.tag = ld.tag; Level->TranslateLineDef(&line, &mld); ld.special = line.special; ld.activation = line.activation; ld.flags = (ld.flags & ~(ML_REPEAT_SPECIAL | ML_FIRSTSIDEONLY)) | (line.flags & (ML_REPEAT_SPECIAL | ML_FIRSTSIDEONLY)); if (!argsset) memcpy(ld.args, line.args, sizeof(ld.args)); } EDLines[ld.recordnum] = ld; }
//========================================================================== // // // //========================================================================== int FParseContext::GetToken (char *&sourcep, FParseToken *yylval) { char token[80]; int toksize; int c; loop: while (isspace (c = *sourcep++) && c != 0) { if (c == '\n') SourceLine++; } if (c == 0) { return 0; } if (isdigit (c)) { int buildup = c - '0'; if (c == '0') { c = *sourcep++; if (c == 'x' || c == 'X') { yylval->val = (int)strtol(sourcep, &sourcep, 16); return TokenTrans[NUM]; } else { sourcep--; } } char *endp; sourcep--; yylval->val = (int)strtol(sourcep, &endp, 10); if (*endp == '.') { // It's a float yylval->fval = strtod(sourcep, &sourcep); return TokenTrans[FLOATVAL]; } else { sourcep = endp; return TokenTrans[NUM]; } } if (isalpha (c)) { int buildup = 0; token[0] = c; toksize = 1; while (toksize < 79 && (isalnum (c = *sourcep++) || c == '_')) { token[toksize++] = c; } token[toksize] = 0; if (toksize == 79 && isalnum (c)) { while (isalnum (c = *sourcep++)) ; } sourcep--; if (FindToken (token, &buildup)) { return buildup; } if (FindSym (token, &yylval->symval)) { yylval->val = yylval->symval->Value; return TokenTrans[NUM]; } if ((yylval->val = P_FindLineSpecial(token)) != 0) { return TokenTrans[NUM]; } strcpy (yylval->sym, token); return TokenTrans[SYM]; } if (c == '/') { c = *sourcep++; if (c == '*') { for (;;) { while ((c = *sourcep++) != '*' && c != 0) { if (c == '\n') SourceLine++; } if (c == 0) return 0; if ((c = *sourcep++) == '/') goto loop; if (c == 0) return 0; sourcep--; } } else if (c == '/') { while ((c = *sourcep++) != '\n' && c != 0) ; if (c == '\n') SourceLine++; else if (c == EOF) return 0; goto loop; } else { sourcep--; return TokenTrans[DIVIDE]; } } if (c == '"') { int tokensize = 0; while ((c = *sourcep++) != '"' && c != 0) { yylval->string[tokensize++] = c; } yylval->string[tokensize] = 0; return TokenTrans[STRING]; } if (c == '|') { c = *sourcep++; if (c == '=') return TokenTrans[OR_EQUAL]; sourcep--; return TokenTrans[OR]; } if (c == '<') { c = *sourcep++; if (c == '<') { c = *sourcep++; if (c == '=') { return TokenTrans[LSHASSIGN]; } sourcep--; return 0; } c--; return 0; } if (c == '>') { c = *sourcep++; if (c == '>') { c = *sourcep++; if (c == '=') { return TokenTrans[RSHASSIGN]; } sourcep--; return 0; } c--; return 0; } if (c == '#') { if (!strnicmp(sourcep, "include", 7)) { sourcep+=7; return TokenTrans[INCLUDE]; } if (!strnicmp(sourcep, "define", 6)) { sourcep+=6; return TokenTrans[DEFINE]; } } switch (c) { case '^': return TokenTrans[XOR]; case '&': return TokenTrans[AND]; case '-': return TokenTrans[MINUS]; case '+': return TokenTrans[PLUS]; case '*': return TokenTrans[MULTIPLY]; case '%': return TokenTrans[MODULUS]; case '(': return TokenTrans[LPAREN]; case ')': return TokenTrans[RPAREN]; case ',': return TokenTrans[COMMA]; case '{': return TokenTrans[LBRACE]; case '}': return TokenTrans[RBRACE]; case '=': return TokenTrans[EQUALS]; case ';': return TokenTrans[SEMICOLON]; case ':': return TokenTrans[COLON]; case '[': return TokenTrans[LBRACKET]; case ']': return TokenTrans[RBRACKET]; default: return 0; } }
void FMapInfoParser::ParseDoomEdNums() { TMap<int, bool> defined; int error = 0; MapinfoEdMapItem editem; editem.filename = sc.ScriptName; ParseOpenBrace(); while (true) { if (sc.CheckString("}")) return; else if (sc.CheckNumber()) { int ednum = sc.Number; sc.MustGetStringName("="); sc.MustGetString(); bool *def = defined.CheckKey(ednum); if (def != NULL) { sc.ScriptMessage("Editor Number %d defined more than once", ednum); error++; } defined[ednum] = true; if (sc.String[0] == '$') { // add special stuff like playerstarts and sound sequence overrides here, too. editem.classname = NAME_None; editem.special = sc.MustMatchString(SpecialMapthingNames) + 1; // todo: assign proper constants } else { editem.classname = sc.String; editem.special = -1; } memset(editem.args, 0, sizeof(editem.args)); editem.argsdefined = 0; editem.noskillflags = false; int minargs = 0; int maxargs = 5; FString specialname; if (sc.CheckString(",")) { if (sc.CheckString("noskillflags")) { editem.noskillflags = true; if (!sc.CheckString(",")) goto noargs; } editem.argsdefined = 5; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing. if (editem.special < 0) editem.special = 0; if (!sc.CheckNumber()) { sc.MustGetString(); specialname = sc.String; // save for later error reporting. editem.special = P_FindLineSpecial(sc.String, &minargs, &maxargs); if (editem.special == 0 || minargs == -1) { sc.ScriptMessage("Invalid special %s for Editor Number %d", sc.String, ednum); error++; minargs = 0; maxargs = 5; } if (!sc.CheckString(",")) { // special case: Special without arguments if (minargs != 0) { sc.ScriptMessage("Incorrect number of args for special %s, min = %d, max = %d, found = 0", specialname.GetChars(), minargs, maxargs); error++; } DoomEdFromMapinfo.Insert(ednum, editem); continue; } sc.MustGetNumber(); } int i = 0; while (i < 5) { editem.args[i] = sc.Number; i++; if (!sc.CheckString(",")) break; // special check for the ambient sounds which combine the arg being set here with the ones on the mapthing. if (sc.CheckString("+")) { editem.argsdefined = i; break; } sc.MustGetNumber(); } if (specialname.IsNotEmpty() && (i < minargs || i > maxargs)) { sc.ScriptMessage("Incorrect number of args for special %s, min = %d, max = %d, found = %d", specialname.GetChars(), minargs, maxargs, i); error++; } } noargs: DoomEdFromMapinfo.Insert(ednum, editem); } else { sc.ScriptError("Number expected"); } } if (error > 0) { sc.ScriptError("%d errors encountered in DoomEdNum definition", error); } }