static void ParseOptionSettings(FScanner &sc) { sc.MustGetStringName("{"); while (!sc.CheckString("}")) { sc.MustGetString(); if (sc.Compare("ifgame")) { if (!CheckSkipGameBlock(sc)) { // recursively parse sub-block ParseOptionSettings(sc); } } else if (sc.Compare("Linespacing")) { sc.MustGetNumber(); OptionSettings.mLinespacing = sc.Number; } else if (sc.Compare("LabelOffset")) { sc.MustGetNumber(); // ignored } else { sc.ScriptError("Unknown keyword '%s'", sc.String); } } }
void FTextureManager::ParseCameraTexture(FScanner &sc) { const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny | TEXMAN_ShortNameOnly; int width, height; int fitwidth, fitheight; FString picname; sc.MustGetString (); picname = sc.String; sc.MustGetNumber (); width = sc.Number; sc.MustGetNumber (); height = sc.Number; FTextureID picnum = CheckForTexture (picname, FTexture::TEX_Flat, texflags); FTexture *viewer = new FCanvasTexture (picname, width, height); if (picnum.Exists()) { FTexture *oldtex = Texture(picnum); fitwidth = oldtex->GetScaledWidth (); fitheight = oldtex->GetScaledHeight (); viewer->UseType = oldtex->UseType; ReplaceTexture (picnum, viewer, true); } else { fitwidth = width; fitheight = height; // [GRB] No need for oldtex viewer->UseType = FTexture::TEX_Wall; AddTexture (viewer); } if (sc.GetString()) { if (sc.Compare ("fit")) { sc.MustGetNumber (); fitwidth = sc.Number; sc.MustGetNumber (); fitheight = sc.Number; } else { sc.UnGet (); } } if (sc.GetString()) { if (sc.Compare("WorldPanning")) { viewer->bWorldPanning = true; } else { sc.UnGet(); } } viewer->SetScaledSize(fitwidth, fitheight); }
static void ParseStatistics(const char *fn, TArray<FStatistics> &statlist) { statlist.Clear(); try { FScanner sc; sc.OpenFile(fn); while (sc.GetString()) { FStatistics &ep_entry = statlist[statlist.Reserve(1)]; ep_entry.epi_header = sc.String; sc.MustGetString(); ep_entry.epi_name = sc.String; sc.MustGetStringName("{"); while (!sc.CheckString("}")) { FSessionStatistics &session = ep_entry.stats[ep_entry.stats.Reserve(1)]; sc.MustGetString(); sc.MustGetString(); strncpy(session.name, sc.String, 12); sc.MustGetString(); strncpy(session.info, sc.String, 30); int h,m,s; sc.MustGetString(); sscanf(sc.String, "%d:%d:%d", &h, &m, &s); session.timeneeded= ((((h*60)+m)*60)+s)*TICRATE; sc.MustGetNumber(); session.skill=sc.Number; if (sc.CheckString("{")) { while (!sc.CheckString("}")) { FLevelStatistics &lstats = session.levelstats[session.levelstats.Reserve(1)]; sc.MustGetString(); strncpy(lstats.name, sc.String, 12); sc.MustGetString(); strncpy(lstats.info, sc.String, 30); int h,m,s; sc.MustGetString(); sscanf(sc.String, "%d:%d:%d", &h, &m, &s); lstats.timeneeded= ((((h*60)+m)*60)+s)*TICRATE; lstats.skill = 0; } } } } } catch(CRecoverableError &) { } }
int ParseFlagExpressionString(FScanner &sc, const FParseValue *vals) { // May be given flags by number... if (sc.CheckNumber()) { sc.MustGetNumber(); return sc.Number; } // ... else should be flags by name. // NOTE: Later this should be removed and a normal expression used. // The current DECORATE parser can't handle this though. bool gotparen = sc.CheckString("("); int style = 0; do { sc.MustGetString(); style |= vals[sc.MustMatchString(&vals->Name, sizeof (*vals))].Flag; } while (sc.CheckString("|")); if (gotparen) { sc.MustGetStringName(")"); } return style; }
static void parseSector(FScanner &sc, TMap<int, EDSector> &EDSectors) { EDSector sec; memset(&sec, 0, sizeof(sec)); sec.Overlayalpha[sector_t::floor] = sec.Overlayalpha[sector_t::ceiling] = 1.; sec.floorterrain = sec.ceilingterrain = -1; sc.MustGetStringName("{"); while (!sc.CheckString("}")) { sc.MustGetString(); if (sc.Compare("recordnum")) { sc.CheckString("="); sc.MustGetNumber(); sec.recordnum = sc.Number; } else if (sc.Compare("flags")) { uint32_t *flagvar = nullptr; if (sc.CheckString(".")) { sc.MustGetString(); if (sc.Compare("add")) { flagvar = &sec.flagsAdd; } else if (sc.Compare("remove")) { flagvar = &sec.flagsRemove; } else { sc.ScriptError("Invalid property 'flags.%s'", sc.String); } } else { sec.flagsSet = true; flagvar = &sec.flags; } sc.CheckString("="); do { sc.MustGetString(); for (const char *tok = strtok(sc.String, ",+ \t"); tok != nullptr; tok = strtok(nullptr, ",+ \t")) { if (!stricmp(tok, "SECRET")) *flagvar |= SECF_SECRET | SECF_WASSECRET; else if (!stricmp(tok, "FRICTION")) *flagvar |= SECF_FRICTION; else if (!stricmp(tok, "PUSH")) *flagvar |= SECF_PUSH; else if (!stricmp(tok, "KILLSOUND")) *flagvar |= SECF_SILENT; else if (!stricmp(tok, "KILLMOVESOUND")) *flagvar |= SECF_SILENTMOVE; else sc.ScriptError("Unknown option '%s'", tok); } } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. } else if (sc.Compare("damage")) { sc.CheckString("="); sc.MustGetNumber(); sec.damageamount = sc.Number; } else if (sc.Compare("damagemod")) { sc.CheckString("="); sc.MustGetString(); sec.damagetype = sc.String; } else if (sc.Compare("damagemask")) { sc.CheckString("="); sc.MustGetNumber(); sec.damageinterval = sc.Number; } else if (sc.Compare("damageflags")) { uint32_t *flagvar = nullptr; uint8_t *leakvar = nullptr; if (sc.CheckString(".")) { sc.MustGetString(); if (sc.Compare("add")) { flagvar = &sec.damageflagsAdd; leakvar = &sec.leakyadd; } else if (sc.Compare("remove")) { flagvar = &sec.damageflagsRemove; leakvar = &sec.leakyremove; } else { sc.ScriptError("Invalid property 'flags.%s'", sc.String); } } else { sec.damageflagsSet = true; flagvar = &sec.damageflags; leakvar = &sec.leaky; } sc.CheckString("="); do { sc.MustGetString(); for (const char *tok = strtok(sc.String, ",+ \t"); tok != nullptr; tok = strtok(nullptr, ",+ \t")) { if (!stricmp(tok, "LEAKYSUIT")) *leakvar |= 1; else if (!stricmp(tok, "IGNORESUIT")) *leakvar |= 2; // these 2 bits will be used to set 'leakychance', but this can only be done when the sector gets initialized else if (!stricmp(tok, "ENDGODMODE")) *flagvar |= SECF_ENDGODMODE; else if (!stricmp(tok, "ENDLEVEL")) *flagvar |= SECF_ENDLEVEL; else if (!stricmp(tok, "TERRAINHIT")) *flagvar |= SECF_DMGTERRAINFX; else sc.ScriptError("Unknown option '%s'", tok); } } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. } else if (sc.Compare("floorterrain")) { sc.CheckString("="); sc.MustGetString(); sec.floorterrain = P_FindTerrain(sc.String); } else if (sc.Compare("floorangle")) { sc.CheckString("="); sc.MustGetFloat(); sec.angle[sector_t::floor] = sc.Float; } else if (sc.Compare("flooroffsetx")) { sc.CheckString("="); sc.MustGetFloat(); sec.xoffs[sector_t::floor] = sc.Float; } else if (sc.Compare("flooroffsety")) { sc.CheckString("="); sc.MustGetFloat(); sec.yoffs[sector_t::floor] = sc.Float; } else if (sc.Compare("ceilingterrain")) { sc.CheckString("="); sc.MustGetString(); sec.ceilingterrain = P_FindTerrain(sc.String); } else if (sc.Compare("ceilingangle")) { sc.CheckString("="); sc.MustGetFloat(); sec.angle[sector_t::ceiling] = sc.Float; } else if (sc.Compare("ceilingoffsetx")) { sc.CheckString("="); sc.MustGetFloat(); sec.xoffs[sector_t::ceiling] = sc.Float; } else if (sc.Compare("ceilingoffsety")) { sc.CheckString("="); sc.MustGetFloat(); sec.yoffs[sector_t::ceiling] = sc.Float; } else if (sc.Compare("colormaptop") || sc.Compare("colormapbottom")) { sc.CheckString("="); sc.MustGetString(); // these properties are not implemented by ZDoom } else if (sc.Compare("colormapmid")) { sc.CheckString("="); sc.MustGetString(); // Eternity is based on SMMU and uses colormaps differently than all other ports. // The only solution here is to convert the colormap to an RGB value and set it as the sector's color. uint32_t cmap = R_ColormapNumForName(sc.String); if (cmap != 0) { sec.color = R_BlendForColormap(cmap) & 0xff000000; sec.colorSet = true; } } else if (sc.Compare("overlayalpha")) { sc.MustGetStringName("."); sc.MustGetString(); if (sc.Compare("floor")) { sc.MustGetNumber(); if (sc.CheckString("%")) sc.Float = sc.Number / 100.f; else sc.Float = sc.Number / 255.f; sec.Overlayalpha[sector_t::floor] = sc.Float; } else if (sc.Compare("ceiling")) { sc.MustGetFloat(); if (sc.CheckString("%")) sc.Float = sc.Number / 100.f; else sc.Float = sc.Number / 255.f; sec.Overlayalpha[sector_t::floor] = sc.Float; } } else if (sc.Compare("portalflags")) { int dest = 0; sc.MustGetStringName("."); sc.MustGetString(); if (sc.Compare("floor")) dest = sector_t::floor; else if (sc.Compare("ceiling")) dest = sector_t::ceiling; else sc.ScriptError("Unknown portal type '%s'", sc.String); sc.CheckString("="); do { sc.MustGetString(); for (const char *tok = strtok(sc.String, ",+ \t"); tok != nullptr; tok = strtok(nullptr, ",+ \t")) { if (!stricmp(tok, "DISABLED")) sec.portalflags[dest] |= PLANEF_DISABLED; else if (!stricmp(tok, "NORENDER")) sec.portalflags[dest] |= PLANEF_NORENDER; else if (!stricmp(tok, "NOPASS")) sec.portalflags[dest] |= PLANEF_NOPASS; else if (!stricmp(tok, "BLOCKSOUND")) sec.portalflags[dest] |= PLANEF_BLOCKSOUND; else if (!stricmp(tok, "OVERLAY")) sec.portalflags[dest] |= 0; // we do not use this. Alpha is the sole determinant for overlay drawing else if (!stricmp(tok, "ADDITIVE")) sec.portalflags[dest] |= PLANEF_ADDITIVE; else if (!stricmp(tok, "USEGLOBALTEX")) {} // not implemented else sc.ScriptError("Unknown option '%s'", tok); } } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. } else { sc.ScriptError("Unknown property '%s'", sc.String); } } EDSectors[sec.recordnum] = sec; }
void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, TexInit &init) { FString patchname; int Mirror = 0; sc.MustGetString(); init.TexName = sc.String; sc.MustGetStringName(","); sc.MustGetNumber(); part.OriginX = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); part.OriginY = sc.Number; if (sc.CheckString("{")) { while (!sc.CheckString("}")) { sc.MustGetString(); if (sc.Compare("flipx")) { Mirror |= 1; } else if (sc.Compare("flipy")) { Mirror |= 2; } else if (sc.Compare("rotate")) { sc.MustGetNumber(); sc.Number = (((sc.Number + 90)%360)-90); if (sc.Number != 0 && sc.Number !=90 && sc.Number != 180 && sc.Number != -90) { sc.ScriptError("Rotation must be a multiple of 90 degrees."); } part.Rotate = (sc.Number / 90) & 3; } else if (sc.Compare("Translation")) { int match; bComplex = true; if (part.Translation != NULL) delete part.Translation; part.Translation = NULL; part.Blend = 0; static const char *maps[] = { "inverse", "gold", "red", "green", "blue", NULL }; sc.MustGetString(); match = sc.MatchString(maps); if (match >= 0) { part.Blend = BLEND_SPECIALCOLORMAP1 + match; } else if (sc.Compare("ICE")) { part.Blend = BLEND_ICEMAP; } else if (sc.Compare("DESATURATE")) { sc.MustGetStringName(","); sc.MustGetNumber(); part.Blend = BLEND_DESATURATE1 + clamp(sc.Number-1, 0, 30); } else { sc.UnGet(); part.Translation = new FRemapTable; part.Translation->MakeIdentity(); do { sc.MustGetString(); part.Translation->AddToTranslation(sc.String); } while (sc.CheckString(",")); } } else if (sc.Compare("Colormap")) { float r1,g1,b1; float r2,g2,b2; sc.MustGetFloat(); r1 = (float)sc.Float; sc.MustGetStringName(","); sc.MustGetFloat(); g1 = (float)sc.Float; sc.MustGetStringName(","); sc.MustGetFloat(); b1 = (float)sc.Float; if (!sc.CheckString(",")) { part.Blend = AddSpecialColormap(0,0,0, r1, g1, b1); } else { sc.MustGetFloat(); r2 = (float)sc.Float; sc.MustGetStringName(","); sc.MustGetFloat(); g2 = (float)sc.Float; sc.MustGetStringName(","); sc.MustGetFloat(); b2 = (float)sc.Float; part.Blend = AddSpecialColormap(r1, g1, b1, r2, g2, b2); } } else if (sc.Compare("Blend")) { bComplex = true; if (part.Translation != NULL) delete part.Translation; part.Translation = NULL; part.Blend = 0; if (!sc.CheckNumber()) { sc.MustGetString(); part.Blend = V_GetColor(NULL, sc); } else { int r,g,b; r = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); g = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); b = sc.Number; //sc.MustGetStringName(","); This was never supposed to be here. part.Blend = MAKERGB(r, g, b); } // Blend.a may never be 0 here. if (sc.CheckString(",")) { sc.MustGetFloat(); if (sc.Float > 0.f) part.Blend.a = clamp<int>(int(sc.Float*255), 1, 254); else part.Blend = 0; } else part.Blend.a = 255; } else if (sc.Compare("alpha")) { sc.MustGetFloat(); part.Alpha = clamp<blend_t>(int(sc.Float * BLENDUNIT), 0, BLENDUNIT); // bComplex is not set because it is only needed when the style is not OP_COPY. } else if (sc.Compare("style")) { static const char *styles[] = {"copy", "translucent", "add", "subtract", "reversesubtract", "modulate", "copyalpha", "copynewalpha", "overlay", NULL }; sc.MustGetString(); part.op = sc.MustMatchString(styles); bComplex |= (part.op != OP_COPY); bTranslucentPatches = bComplex; } else if (sc.Compare("useoffsets")) { init.UseOffsets = true; } } } if (Mirror & 2) { part.Rotate = (part.Rotate + 2) & 3; Mirror ^= 1; } if (Mirror & 1) { part.Rotate |= 4; } }
FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, ETextureType usetype) : Pixels (0), Spans(0), Parts(0), bRedirect(false), bTranslucentPatches(false) { TArray<TexPart> parts; TArray<TexInit> inits; bool bSilent = false; bMultiPatch = true; sc.SetCMode(true); sc.MustGetString(); const char* textureName = NULL; if (sc.Compare("optional")) { bSilent = true; sc.MustGetString(); if (sc.Compare(",")) { // this is not right. Apparently a texture named 'optional' is being defined right now... sc.UnGet(); textureName = "optional"; bSilent = false; } } Name = !textureName ? sc.String : textureName; Name.ToUpper(); sc.MustGetStringName(","); sc.MustGetNumber(); Width = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); Height = sc.Number; UseType = usetype; bool offset2set = false; if (sc.CheckString("{")) { while (!sc.CheckString("}")) { sc.MustGetString(); if (sc.Compare("XScale")) { sc.MustGetFloat(); Scale.X = sc.Float; if (Scale.X == 0) sc.ScriptError("Texture %s is defined with null x-scale\n", Name.GetChars()); } else if (sc.Compare("YScale")) { sc.MustGetFloat(); Scale.Y = sc.Float; if (Scale.Y == 0) sc.ScriptError("Texture %s is defined with null y-scale\n", Name.GetChars()); } else if (sc.Compare("WorldPanning")) { bWorldPanning = true; } else if (sc.Compare("NullTexture")) { UseType = ETextureType::Null; } else if (sc.Compare("NoDecals")) { bNoDecals = true; } else if (sc.Compare("Patch")) { TexPart part; TexInit init; ParsePatch(sc, part, init); if (init.TexName.IsNotEmpty()) { parts.Push(part); init.UseType = ETextureType::WallPatch; init.Silent = bSilent; init.HasLine = true; init.sc = sc; inits.Push(init); } part.Texture = NULL; part.Translation = NULL; } else if (sc.Compare("Sprite")) { TexPart part; TexInit init; ParsePatch(sc, part, init); if (init.TexName.IsNotEmpty()) { parts.Push(part); init.UseType = ETextureType::Sprite; init.Silent = bSilent; init.HasLine = true; init.sc = sc; inits.Push(init); } part.Texture = NULL; part.Translation = NULL; } else if (sc.Compare("Graphic")) { TexPart part; TexInit init; ParsePatch(sc, part, init); if (init.TexName.IsNotEmpty()) { parts.Push(part); init.UseType = ETextureType::MiscPatch; init.Silent = bSilent; init.HasLine = true; init.sc = sc; inits.Push(init); } part.Texture = NULL; part.Translation = NULL; } else if (sc.Compare("Offset")) { sc.MustGetNumber(); _LeftOffset[0] = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); _TopOffset[0] = sc.Number; if (!offset2set) { _LeftOffset[1] = _LeftOffset[0]; _TopOffset[1] = _TopOffset[0]; } } else if (sc.Compare("Offset2")) { sc.MustGetNumber(); _LeftOffset[1] = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); _TopOffset[1] = sc.Number; offset2set = true; } else { sc.ScriptError("Unknown texture property '%s'", sc.String); } } NumParts = parts.Size(); Parts = new TexPart[NumParts]; memcpy(Parts, &parts[0], NumParts * sizeof(*Parts)); Inits = new TexInit[NumParts]; for (int i = 0; i < NumParts; i++) { Inits[i] = inits[i]; } } if (Width <= 0 || Height <= 0) { UseType = ETextureType::Null; Printf("Texture %s has invalid dimensions (%d, %d)\n", Name.GetChars(), Width, Height); Width = Height = 1; } CalcBitSize (); sc.SetCMode(false); }
static void ParseOptionMenuBody(FScanner &sc, FOptionMenuDescriptor *desc) { sc.MustGetStringName("{"); while (!sc.CheckString("}")) { sc.MustGetString(); if (sc.Compare("ifgame")) { if (!CheckSkipGameBlock(sc)) { // recursively parse sub-block ParseOptionMenuBody(sc, desc); } } else if (sc.Compare("ifoption")) { if (!CheckSkipOptionBlock(sc)) { // recursively parse sub-block ParseOptionMenuBody(sc, desc); } } else if (sc.Compare("Class")) { sc.MustGetString(); const PClass *cls = PClass::FindClass(sc.String); if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(DOptionMenu))) { sc.ScriptError("Unknown menu class '%s'", sc.String); } desc->mClass = cls; } else if (sc.Compare("Title")) { sc.MustGetString(); desc->mTitle = sc.String; } else if (sc.Compare("Position")) { sc.MustGetNumber(); desc->mPosition = sc.Number; } else if (sc.Compare("DefaultSelection")) { sc.MustGetNumber(); desc->mSelectedItem = sc.Number; } else if (sc.Compare("ScrollTop")) { sc.MustGetNumber(); desc->mScrollTop = sc.Number; } else if (sc.Compare("Indent")) { sc.MustGetNumber(); desc->mIndent = sc.Number; } else if (sc.Compare("Submenu")) { sc.MustGetString(); FString label = sc.String; sc.MustGetStringName(","); sc.MustGetString(); FOptionMenuItem *it = new FOptionMenuItemSubmenu(label, sc.String); desc->mItems.Push(it); } else if (sc.Compare("Option")) { sc.MustGetString(); FString label = sc.String; sc.MustGetStringName(","); sc.MustGetString(); FString cvar = sc.String; sc.MustGetStringName(","); sc.MustGetString(); FString values = sc.String; FString check; int center = 0; if (sc.CheckString(",")) { sc.MustGetString(); if (*sc.String != 0) check = sc.String; if (sc.CheckString(",")) { sc.MustGetNumber(); center = sc.Number; } } FOptionMenuItem *it = new FOptionMenuItemOption(label, cvar, values, check, center); desc->mItems.Push(it); } else if (sc.Compare("Command")) { sc.MustGetString(); FString label = sc.String; sc.MustGetStringName(","); sc.MustGetString(); FOptionMenuItem *it = new FOptionMenuItemCommand(label, sc.String); desc->mItems.Push(it); } else if (sc.Compare("SafeCommand")) { sc.MustGetString(); FString label = sc.String; sc.MustGetStringName(","); sc.MustGetString(); FOptionMenuItem *it = new FOptionMenuItemSafeCommand(label, sc.String); desc->mItems.Push(it); } else if (sc.Compare("Control") || sc.Compare("MapControl")) { bool map = sc.Compare("MapControl"); sc.MustGetString(); FString label = sc.String; sc.MustGetStringName(","); sc.MustGetString(); FOptionMenuItem *it = new FOptionMenuItemControl(label, sc.String, map? &AutomapBindings : &Bindings); desc->mItems.Push(it); } else if (sc.Compare("ColorPicker")) { sc.MustGetString(); FString label = sc.String; sc.MustGetStringName(","); sc.MustGetString(); FOptionMenuItem *it = new FOptionMenuItemColorPicker(label, sc.String); desc->mItems.Push(it); } else if (sc.Compare("StaticText")) { sc.MustGetString(); FString label = sc.String; bool cr = false; if (sc.CheckString(",")) { sc.MustGetNumber(); cr = !!sc.Number; } FOptionMenuItem *it = new FOptionMenuItemStaticText(label, cr); desc->mItems.Push(it); } else if (sc.Compare("StaticTextSwitchable")) { sc.MustGetString(); FString label = sc.String; sc.MustGetStringName(","); sc.MustGetString(); FString label2 = sc.String; sc.MustGetStringName(","); sc.MustGetString(); FName action = sc.String; bool cr = false; if (sc.CheckString(",")) { sc.MustGetNumber(); cr = !!sc.Number; } FOptionMenuItem *it = new FOptionMenuItemStaticTextSwitchable(label, label2, action, cr); desc->mItems.Push(it); } else if (sc.Compare("Slider")) { sc.MustGetString(); FString text = sc.String; sc.MustGetStringName(","); sc.MustGetString(); FString action = sc.String; sc.MustGetStringName(","); sc.MustGetFloat(); double min = sc.Float; sc.MustGetStringName(","); sc.MustGetFloat(); double max = sc.Float; sc.MustGetStringName(","); sc.MustGetFloat(); double step = sc.Float; int showvalue = 1; if (sc.CheckString(",")) { sc.MustGetNumber(); showvalue = sc.Number; } FOptionMenuItem *it = new FOptionMenuSliderCVar(text, action, min, max, step, showvalue); desc->mItems.Push(it); } else if (sc.Compare("screenresolution")) { sc.MustGetString(); FOptionMenuItem *it = new FOptionMenuScreenResolutionLine(sc.String); desc->mItems.Push(it); } else { sc.ScriptError("Unknown keyword '%s'", sc.String); } } }
static void ReadReverbDef (int lump) { FScanner sc; const ReverbContainer *def; ReverbContainer *newenv; REVERB_PROPERTIES props; char *name; int id1, id2, i, j; bool inited[NUM_REVERB_FIELDS]; BYTE bools[32]; sc.OpenLumpNum(lump); while (sc.GetString ()) { name = copystring (sc.String); sc.MustGetNumber (); id1 = sc.Number; sc.MustGetNumber (); id2 = sc.Number; sc.MustGetStringName ("{"); memset (inited, 0, sizeof(inited)); props.Instance = 0; props.Flags = 0; while (sc.MustGetString (), NUM_REVERB_FIELDS > (i = sc.MustMatchString (ReverbFieldNames))) { if (ReverbFields[i].Float) { sc.MustGetFloat (); props.*ReverbFields[i].Float = (float)clamp (sc.Float, double(ReverbFields[i].Min)/1000, double(ReverbFields[i].Max)/1000); } else if (ReverbFields[i].Int) { sc.MustGetNumber (); props.*ReverbFields[i].Int = (j = clamp (sc.Number, ReverbFields[i].Min, ReverbFields[i].Max)); if (i == 0 && j != sc.Number) { sc.ScriptError ("The Environment field is out of range."); } } else { sc.MustGetString (); bools[ReverbFields[i].Flag] = sc.MustMatchString (BoolNames); } inited[i] = true; } if (!inited[0]) { sc.ScriptError ("Sound %s is missing an Environment field.", name); } // Add the new environment to the list, filling in uninitialized fields // with values from the standard environment specified. def = DefaultEnvironments[props.Environment]; for (i = 0; i < NUM_REVERB_FIELDS; ++i) { if (ReverbFields[i].Float) { if (!inited[i]) { props.*ReverbFields[i].Float = def->Properties.*ReverbFields[i].Float; } } else if (ReverbFields[i].Int) { if (!inited[i]) { props.*ReverbFields[i].Int = def->Properties.*ReverbFields[i].Int; } } else { if (!inited[i]) { int mask = 1 << ReverbFields[i].Flag; if (def->Properties.Flags & mask) { props.Flags |= mask; } } else { if (bools[ReverbFields[i].Flag]) { props.Flags |= 1 << ReverbFields[i].Flag; } } } } newenv = new ReverbContainer; newenv->Next = NULL; newenv->Name = name; newenv->ID = (id1 << 8) | id2; newenv->Builtin = false; newenv->Properties = props; newenv->SoftwareWater = false; S_AddEnvironment (newenv); } }
static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defaults, Baggage &bag) { static TArray<FPropParam> params; static TArray<FString> strings; params.Clear(); strings.Clear(); params.Reserve(1); params[0].i = 0; if (prop->params[0] != '0') { const char * p = prop->params; bool nocomma; bool optcomma; while (*p) { FPropParam conv; FPropParam pref; nocomma = false; conv.s = NULL; pref.s = NULL; pref.i = -1; bag.ScriptPosition = sc; switch ((*p) & 223) { case 'X': // Expression in parentheses or number. { FxExpression *x = NULL; if (sc.CheckString ("(")) { x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info)), true); sc.MustGetStringName(")"); } else { sc.MustGetNumber(); if (sc.Number != 0) { x = new FxDamageValue(new FxConstant(sc.Number, bag.ScriptPosition), false); } } conv.exp = x; params.Push(conv); } break; case 'I': sc.MustGetNumber(); conv.i = sc.Number; break; case 'F': sc.MustGetFloat(); conv.d = sc.Float; break; case 'Z': // an optional string. Does not allow any numerical value. if (sc.CheckFloat()) { nocomma = true; sc.UnGet(); break; } // fall through case 'S': sc.MustGetString(); conv.s = strings[strings.Reserve(1)] = sc.String; break; case 'T': sc.MustGetString(); conv.s = strings[strings.Reserve(1)] = strbin1(sc.String); break; case 'C': if (sc.CheckNumber ()) { int R, G, B; R = clamp (sc.Number, 0, 255); sc.CheckString (","); sc.MustGetNumber (); G = clamp (sc.Number, 0, 255); sc.CheckString (","); sc.MustGetNumber (); B = clamp (sc.Number, 0, 255); conv.i = MAKERGB(R, G, B); pref.i = 0; } else { sc.MustGetString (); conv.s = strings[strings.Reserve(1)] = sc.String; pref.i = 1; } break; case 'M': // special case. An expression-aware parser will not need this. conv.i = ParseMorphStyle(sc); break; case 'N': // special case. An expression-aware parser will not need this. conv.i = ParseThingActivation(sc); break; case 'L': // Either a number or a list of strings if (sc.CheckNumber()) { pref.i = 0; conv.i = sc.Number; } else { pref.i = 1; params.Push(pref); params[0].i++; do { sc.MustGetString (); conv.s = strings[strings.Reserve(1)] = sc.String; params.Push(conv); params[0].i++; } while (sc.CheckString(",")); goto endofparm; } break; default: assert(false); break; } if (pref.i != -1) { params.Push(pref); params[0].i++; } params.Push(conv); params[0].i++; endofparm: p++; // Hack for some properties that have to allow comma less // parameter lists for compatibility. if ((optcomma = (*p == '_'))) p++; if (nocomma) { continue; } else if (*p == 0) { break; } else if (*p >= 'a') { if (!sc.CheckString(",")) { if (optcomma) { if (!sc.CheckFloat()) break; else sc.UnGet(); } else break; } } else { if (!optcomma) sc.MustGetStringName(","); else sc.CheckString(","); } } } // call the handler try { prop->Handler(defaults, bag.Info, bag, ¶ms[0]); } catch (CRecoverableError &error) { sc.ScriptError("%s", error.GetMessage()); } return true; }
static void ParseLock(FScanner &sc) { int i,r,g,b; int keynum; Lock sink; Lock *lock = &sink; Keygroup *keygroup; PClassActor *mi; sc.MustGetNumber(); keynum = sc.Number; sc.MustGetString(); if (!sc.Compare("{")) { if (!CheckGame(sc.String, false)) keynum = -1; sc.MustGetStringName("{"); } ignorekey = true; if (keynum > 0 && keynum <= 255) { lock = new Lock; if (locks[keynum]) { delete locks[keynum]; } locks[keynum] = lock; locks[keynum]->locksound.Push("*keytry"); locks[keynum]->locksound.Push("misc/keytry"); ignorekey=false; } else if (keynum != -1) { sc.ScriptError("Lock index %d out of range", keynum); } while (!sc.CheckString("}")) { sc.MustGetString(); switch(i = sc.MatchString(keywords_lock)) { case 0: // Any keygroup = ParseKeygroup(sc); if (keygroup) { lock->keylist.Push(keygroup); } break; case 1: // message sc.MustGetString(); lock->Message = sc.String; break; case 2: // remotemsg sc.MustGetString(); lock->RemoteMsg = sc.String; break; case 3: // mapcolor sc.MustGetNumber(); r = sc.Number; sc.MustGetNumber(); g = sc.Number; sc.MustGetNumber(); b = sc.Number; lock->rgb = MAKERGB(r,g,b); break; case 4: // locksound lock->locksound.Clear(); for (;;) { sc.MustGetString(); lock->locksound.Push(sc.String); if (!sc.GetString()) { break; } if (!sc.Compare(",")) { sc.UnGet(); break; } } break; default: mi = PClass::FindActor(sc.String); if (mi) { keygroup = new Keygroup; AddOneKey(keygroup, mi, sc); if (keygroup) { keygroup->anykeylist.ShrinkToFit(); lock->keylist.Push(keygroup); } } break; } } // copy the messages if the other one does not exist if (lock->RemoteMsg.IsEmpty() && lock->Message.IsNotEmpty()) { lock->RemoteMsg = lock->Message; } if (lock->Message.IsEmpty() && lock->RemoteMsg.IsNotEmpty()) { lock->Message = lock->RemoteMsg; } lock->keylist.ShrinkToFit(); }
bool FCajunMaster::LoadBots () { FScanner sc; FString tmp; bool gotteam = false; int loaded_bots = 0; bglobal.ForgetBots (); tmp = M_GetCajunPath(BOTFILENAME); if (tmp.IsEmpty()) { DPrintf ("No " BOTFILENAME ", so no bots\n"); return false; } sc.OpenFile(tmp); while (sc.GetString ()) { if (!sc.Compare ("{")) { sc.ScriptError ("Unexpected token '%s'\n", sc.String); } botinfo_t *newinfo = new botinfo_t; bool gotclass = false; memset (newinfo, 0, sizeof(*newinfo)); newinfo->info = copystring ("\\autoaim\\0\\movebob\\.25"); for (;;) { sc.MustGetString (); if (sc.Compare ("}")) break; switch (sc.MatchString (BotConfigStrings)) { case BOTCFG_NAME: sc.MustGetString (); appendinfo (newinfo->info, "name"); appendinfo (newinfo->info, sc.String); newinfo->name = copystring (sc.String); break; case BOTCFG_AIMING: sc.MustGetNumber (); newinfo->skill.aiming = sc.Number; break; case BOTCFG_PERFECTION: sc.MustGetNumber (); newinfo->skill.perfection = sc.Number; break; case BOTCFG_REACTION: sc.MustGetNumber (); newinfo->skill.reaction = sc.Number; break; case BOTCFG_ISP: sc.MustGetNumber (); newinfo->skill.isp = sc.Number; break; case BOTCFG_TEAM: { char teamstr[16]; BYTE teamnum; sc.MustGetString (); if (IsNum (sc.String)) { teamnum = atoi (sc.String); if (!TeamLibrary.IsValidTeam (teamnum)) { teamnum = TEAM_NONE; } } else { teamnum = TEAM_NONE; for (unsigned int i = 0; i < Teams.Size(); ++i) { if (stricmp (Teams[i].GetName (), sc.String) == 0) { teamnum = i; break; } } } appendinfo (newinfo->info, "team"); mysnprintf (teamstr, countof(teamstr), "%d", teamnum); appendinfo (newinfo->info, teamstr); gotteam = true; break; } default: if (stricmp (sc.String, "playerclass") == 0) { gotclass = true; } appendinfo (newinfo->info, sc.String); sc.MustGetString (); appendinfo (newinfo->info, sc.String); break; } } if (!gotclass) { // Bots that don't specify a class get a random one appendinfo (newinfo->info, "playerclass"); appendinfo (newinfo->info, "random"); } if (!gotteam) { // Same for bot teams appendinfo (newinfo->info, "team"); appendinfo (newinfo->info, "255"); } newinfo->next = bglobal.botinfo; newinfo->lastteam = TEAM_NONE; bglobal.botinfo = newinfo; loaded_bots++; } Printf ("%d bots read from %s\n", loaded_bots, BOTFILENAME); return true; }
static void GenericParse (FScanner &sc, FGenericParse *parser, const char **keywords, void *fields, const char *type, FName name) { bool notdone = true; int keyword; int val = 0; const PClass *info; do { sc.MustGetString (); keyword = sc.MustMatchString (keywords); switch (parser[keyword].Type) { case GEN_End: notdone = false; break; case GEN_Fixed: sc.MustGetFloat (); SET_FIELD (fixed_t, (fixed_t)(FRACUNIT * sc.Float)); break; case GEN_Sound: sc.MustGetString (); SET_FIELD (FSoundID, FSoundID(sc.String)); /* unknown sounds never produce errors anywhere else so they shouldn't here either. if (val == 0) { Printf ("Unknown sound %s in %s %s\n", sc.String, type, name.GetChars()); } */ break; case GEN_Byte: sc.MustGetNumber (); SET_FIELD (BYTE, sc.Number); break; case GEN_Class: sc.MustGetString (); if (sc.Compare ("None")) { info = NULL; } else { info = PClass::FindClass (sc.String); if (!info->IsDescendantOf (RUNTIME_CLASS(AActor))) { Printf ("%s is not an Actor (in %s %s)\n", sc.String, type, name.GetChars()); info = NULL; } else if (info == NULL) { Printf ("Unknown actor %s in %s %s\n", sc.String, type, name.GetChars()); } } SET_FIELD (const PClass *, info); break; case GEN_Splash: sc.MustGetString (); val = FindSplash (sc.String); SET_FIELD (int, val); if (val == -1) { Printf ("Splash %s is not defined yet (in %s %s)\n", sc.String, type, name.GetChars()); } break; case GEN_Float: sc.MustGetFloat (); SET_FIELD (float, float(sc.Float)); break; case GEN_Time: sc.MustGetFloat (); SET_FIELD (int, (int)(sc.Float * TICRATE)); break; case GEN_Bool: SET_FIELD (bool, true); break; case GEN_Int: sc.MustGetNumber (); SET_FIELD (int, sc.Number); break; case GEN_Custom: parser[keyword].u.Handler (sc, keyword, fields); break; } } while (notdone); }
//========================================================================== //*** // ParseStates // parses a state block // //========================================================================== void ParseStates(FScanner &sc, FActorInfo * actor, AActor * defaults, Baggage &bag) { FString statestring; FState state; char lastsprite[5]=""; sc.MustGetStringName ("{"); sc.SetEscape(false); // disable escape sequences in the state parser while (!sc.CheckString ("}") && !sc.End) { memset(&state,0,sizeof(state)); statestring = ParseStateString(sc); if (!statestring.CompareNoCase("GOTO")) { do_goto: statestring = ParseStateString(sc); if (sc.CheckString ("+")) { sc.MustGetNumber (); statestring += '+'; statestring += sc.String; } if (!bag.statedef.SetGotoLabel(statestring)) { sc.ScriptError("GOTO before first state"); } } else if (!statestring.CompareNoCase("STOP")) { do_stop: if (!bag.statedef.SetStop()) { sc.ScriptError("STOP before first state"); continue; } } else if (!statestring.CompareNoCase("WAIT") || !statestring.CompareNoCase("FAIL")) { if (!bag.statedef.SetWait()) { sc.ScriptError("%s before first state", sc.String); continue; } } else if (!statestring.CompareNoCase("LOOP")) { if (!bag.statedef.SetLoop()) { sc.ScriptError("LOOP before first state"); continue; } } else { sc.MustGetString(); if (sc.Compare (":")) { do { bag.statedef.AddStateLabel(statestring); statestring = ParseStateString(sc); if (!statestring.CompareNoCase("GOTO")) { goto do_goto; } else if (!statestring.CompareNoCase("STOP")) { goto do_stop; } sc.MustGetString (); } while (sc.Compare (":")); // continue; } sc.UnGet (); if (statestring.Len() != 4) { sc.ScriptError ("Sprite names must be exactly 4 characters\n"); } state.sprite = GetSpriteIndex(statestring); state.Misc1 = state.Misc2 = 0; state.ParameterIndex = 0; sc.MustGetString(); statestring = sc.String; if (sc.CheckString("RANDOM")) { int min, max; sc.MustGetStringName("("); sc.MustGetNumber(); min = clamp<int>(sc.Number, -1, SHRT_MAX); sc.MustGetStringName(","); sc.MustGetNumber(); max = clamp<int>(sc.Number, -1, SHRT_MAX); sc.MustGetStringName(")"); if (min > max) { swapvalues(min, max); } state.Tics = min; state.TicRange = max - min; } else { sc.MustGetNumber(); state.Tics = clamp<int>(sc.Number, -1, SHRT_MAX); state.TicRange = 0; } while (sc.GetString() && !sc.Crossed) { if (sc.Compare("BRIGHT")) { state.Fullbright = true; continue; } if (sc.Compare("FAST")) { state.Fast = true; continue; } if (sc.Compare("SLOW")) { state.Slow = true; continue; } if (sc.Compare("NODELAY")) { if (bag.statedef.GetStateLabelIndex(NAME_Spawn) == bag.statedef.GetStateCount()) { state.NoDelay = true; } else { sc.ScriptMessage("NODELAY may only be used immediately after Spawn:"); } continue; } if (sc.Compare("OFFSET")) { // specify a weapon offset sc.MustGetStringName("("); sc.MustGetNumber(); state.Misc1 = sc.Number; sc.MustGetStringName (","); sc.MustGetNumber(); state.Misc2 = sc.Number; sc.MustGetStringName(")"); continue; } if (sc.Compare("LIGHT")) { sc.MustGetStringName("("); do { sc.MustGetString(); #ifdef DYNLIGHT AddStateLight(&state, sc.String); #endif } while (sc.CheckString(",")); sc.MustGetStringName(")"); continue; } if (sc.Compare("CANRAISE")) { state.CanRaise = true; continue; } // Make the action name lowercase strlwr (sc.String); if (DoActionSpecials(sc, state, bag)) { goto endofstate; } FName funcname = FName(sc.String, true); PSymbol *sym = bag.Info->Class->Symbols.FindSymbol (funcname, true); if (sym != NULL && sym->SymbolType == SYM_ActionFunction) { PSymbolActionFunction *afd = static_cast<PSymbolActionFunction *>(sym); state.SetAction(afd, false); if (!afd->Arguments.IsEmpty()) { const char *params = afd->Arguments.GetChars(); int numparams = (int)afd->Arguments.Len(); int v; if (!islower(*params)) { sc.MustGetStringName("("); } else { if (!sc.CheckString("(")) { state.ParameterIndex = afd->defaultparameterindex+1; goto endofstate; } } int paramindex = PrepareStateParameters(&state, numparams, bag.Info->Class); int paramstart = paramindex; bool varargs = params[numparams - 1] == '+'; int varargcount = 0; if (varargs) { paramindex++; } else if (afd->defaultparameterindex > -1) { StateParams.Copy(paramindex, afd->defaultparameterindex, int(afd->Arguments.Len())); } while (*params) { FxExpression *x; if ((*params == 'l' || *params == 'L') && sc.CheckNumber()) { // Special case: State label as an offset if (sc.Number > 0 && statestring.Len() > 1) { sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n"); } v=sc.Number; if (v<0) { sc.ScriptError("Negative jump offsets are not allowed"); } if (v > 0) { x = new FxStateByIndex(bag.statedef.GetStateCount() + v, sc); } else { x = new FxConstant((FState*)NULL, sc); } } else { // Use the generic parameter parser for everything else x = ParseParameter(sc, bag.Info->Class, *params, false); } StateParams.Set(paramindex++, x); params++; if (varargs) { varargcount++; } if (*params) { if (*params == '+') { if (sc.CheckString(")")) { StateParams.Set(paramstart, new FxConstant(varargcount, sc)); goto endofstate; } params--; StateParams.Reserve(1, bag.Info->Class); } else if ((islower(*params) || *params=='!') && sc.CheckString(")")) { goto endofstate; } sc.MustGetStringName (","); } } sc.MustGetStringName(")"); } else { sc.MustGetString(); if (sc.Compare("(")) { sc.ScriptError("You cannot pass parameters to '%s'\n", funcname.GetChars()); } sc.UnGet(); } goto endofstate; } sc.ScriptError("Invalid state parameter %s\n", sc.String); } sc.UnGet(); endofstate: if (!bag.statedef.AddStates(&state, statestring)) { sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars()); } } } sc.SetEscape(true); // re-enable escape sequences }
static void parseMapthing(FScanner &sc, TMap<int, EDMapthing> &EDThings) { EDMapthing mt; memset(&mt, 0, sizeof(mt)); mt.flags |= MTF_SINGLE | MTF_COOPERATIVE | MTF_DEATHMATCH; // Extradata uses inverse logic, like Doom.exe sc.MustGetStringName("{"); while (!sc.CheckString("}")) { sc.MustGetString(); if (sc.Compare("recordnum")) { sc.CheckString("="); sc.MustGetNumber(); mt.recordnum = sc.Number; } else if (sc.Compare("tid")) { sc.CheckString("="); sc.MustGetNumber(); mt.tid = sc.Number; } else if (sc.Compare("type")) { sc.CheckString("="); if (sc.CheckNumber()) { mt.type = sc.Number; } else { // Class name. sc.MustGetString(); // According to the Eternity Wiki a name may be prefixed with 'thing:'. const char *pos = strchr(sc.String, ':'); // Eternity never checks if the prefix actually is 'thing'. if (pos) pos++; else pos = sc.String; const PClass *cls = PClass::FindClass(pos); if (cls != nullptr) { FDoomEdMap::Iterator it(DoomEdMap); FDoomEdMap::Pair *pair; while (it.NextPair(pair)) { if (pair->Value.Type == cls) { mt.type = pair->Key; break; } } } else { // Let's hope this isn't an internal Eternity name. // If so, a name mapping needs to be defined... sc.ScriptError("Unknown type '%s'", sc.String); } } } else if (sc.Compare("args")) { sc.CheckString("="); sc.MustGetStringName("{"); int c = 0; while (!sc.CheckString("}")) { sc.MustGetNumber(); mt.args[c++] = sc.Number; } } else if (sc.Compare("height")) { sc.CheckString("="); sc.MustGetFloat(); // no idea if Eternity allows fractional numbers. Better be safe and do it anyway. mt.height = sc.Float; } else if (sc.Compare("options")) { sc.CheckString("="); do { sc.MustGetString(); for (const char *tok = strtok(sc.String, ",+ \t"); tok != nullptr; tok = strtok(nullptr, ",+ \t")) { if (!stricmp(tok, "EASY")) mt.skillfilter |= 3; else if (!stricmp(tok, "NORMAL")) mt.skillfilter |= 4; else if (!stricmp(tok, "HARD")) mt.skillfilter |= 24; else if (!stricmp(tok, "AMBUSH")) mt.flags |= MTF_AMBUSH; else if (!stricmp(tok, "NOTSINGLE")) mt.flags &= ~MTF_SINGLE; else if (!stricmp(tok, "NOTDM")) mt.flags &= ~MTF_DEATHMATCH; else if (!stricmp(tok, "NOTCOOP")) mt.flags &= ~MTF_COOPERATIVE; else if (!stricmp(tok, "FRIEND")) mt.flags |= MTF_FRIENDLY; else if (!stricmp(tok, "DORMANT")) mt.flags |= MTF_DORMANT; else sc.ScriptError("Unknown option '%s'", tok); } } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. } else { sc.ScriptError("Unknown property '%s'", sc.String); } } EDThings[mt.recordnum] = mt; }
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; }
void FTeam::ParseTeamDefinition (FScanner &Scan) { FTeam Team; int valid = -1; Scan.MustGetString (); Team.m_Name = Scan.String; Scan.MustGetStringName ("{"); while (!Scan.CheckString ("}")) { Scan.MustGetString (); switch (Scan.MatchString (TeamInfoOptions)) { case TEAMINFO_Game: Scan.MustGetString (); if (Scan.Compare("Any")) valid = 1; else if (CheckGame(Scan.String, false)) valid = 1; else if (valid == -1) valid = 0; break; case TEAMINFO_PlayerColor: Scan.MustGetString (); Team.m_iPlayerColor = V_GetColor (NULL, Scan.String); break; case TEAMINFO_TextColor: Scan.MustGetString (); Team.m_TextColor.AppendFormat ("[%s]", Scan.String); break; case TEAMINFO_Logo: Scan.MustGetString (); Team.m_Logo = Scan.String; break; case TEAMINFO_AllowCustomPlayerColor: Team.m_bAllowCustomPlayerColor = true; break; case TEAMINFO_PlayerStartThingNumber: Scan.MustGetNumber (); break; case TEAMINFO_RailColor: case TEAMINFO_FlagItem: case TEAMINFO_SkullItem: case TEAMINFO_SmallFlagHUDIcon: case TEAMINFO_SmallSkullHUDIcon: case TEAMINFO_LargeFlagHUDIcon: case TEAMINFO_LargeSkullHUDIcon: case TEAMINFO_WinnerPic: case TEAMINFO_LoserPic: case TEAMINFO_WinnerTheme: case TEAMINFO_LoserTheme: Scan.MustGetString (); break; default: Scan.ScriptError ("ParseTeamDefinition: Unknown team option '%s'.\n", Scan.String); break; } } if (valid) Teams.Push (Team); }
static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc) { sc.MustGetStringName("{"); while (!sc.CheckString("}")) { sc.MustGetString(); if (sc.Compare("else")) { SkipSubBlock(sc); } else if (sc.Compare("ifgame")) { if (!CheckSkipGameBlock(sc)) { // recursively parse sub-block ParseListMenuBody(sc, desc); } } else if (sc.Compare("ifoption")) { if (!CheckSkipOptionBlock(sc)) { // recursively parse sub-block ParseListMenuBody(sc, desc); } } else if (sc.Compare("Class")) { sc.MustGetString(); const PClass *cls = PClass::FindClass(sc.String); if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(DListMenu))) { sc.ScriptError("Unknown menu class '%s'", sc.String); } desc->mClass = cls; } else if (sc.Compare("Selector")) { sc.MustGetString(); desc->mSelector = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); sc.MustGetStringName(","); sc.MustGetNumber(); desc->mSelectOfsX = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); desc->mSelectOfsY = sc.Number; } else if (sc.Compare("Linespacing")) { sc.MustGetNumber(); desc->mLinespacing = sc.Number; } else if (sc.Compare("Position")) { sc.MustGetNumber(); desc->mXpos = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); desc->mYpos = sc.Number; } else if (sc.Compare("Centermenu")) { desc->mCenter = true; } else if (sc.Compare("MouseWindow")) { sc.MustGetNumber(); desc->mWLeft = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); desc->mWRight = sc.Number; } else if (sc.Compare("StaticPatch") || sc.Compare("StaticPatchCentered")) { bool centered = sc.Compare("StaticPatchCentered"); sc.MustGetNumber(); int x = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); int y = sc.Number; sc.MustGetStringName(","); sc.MustGetString(); FTextureID tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); FListMenuItem *it = new FListMenuItemStaticPatch(x, y, tex, centered); desc->mItems.Push(it); } else if (sc.Compare("StaticText") || sc.Compare("StaticTextCentered")) { bool centered = sc.Compare("StaticTextCentered"); sc.MustGetNumber(); int x = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); int y = sc.Number; sc.MustGetStringName(","); sc.MustGetString(); FListMenuItem *it = new FListMenuItemStaticText(x, y, sc.String, desc->mFont, desc->mFontColor, centered); desc->mItems.Push(it); } else if (sc.Compare("PatchItem")) { sc.MustGetString(); FTextureID tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); sc.MustGetStringName(","); sc.MustGetString(); int hotkey = sc.String[0]; sc.MustGetStringName(","); sc.MustGetString(); FName action = sc.String; int param = 0; if (sc.CheckString(",")) { sc.MustGetNumber(); param = sc.Number; } FListMenuItem *it = new FListMenuItemPatch(desc->mXpos, desc->mYpos, desc->mLinespacing, hotkey, tex, action, param); desc->mItems.Push(it); desc->mYpos += desc->mLinespacing; if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1; } else if (sc.Compare("TextItem")) { sc.MustGetString(); FString text = sc.String; sc.MustGetStringName(","); sc.MustGetString(); int hotkey = sc.String[0]; sc.MustGetStringName(","); sc.MustGetString(); FName action = sc.String; int param = 0; if (sc.CheckString(",")) { sc.MustGetNumber(); param = sc.Number; } FListMenuItem *it = new FListMenuItemText(desc->mXpos, desc->mYpos, desc->mLinespacing, hotkey, text, desc->mFont, desc->mFontColor, desc->mFontColor2, action, param); desc->mItems.Push(it); desc->mYpos += desc->mLinespacing; if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1; } else if (sc.Compare("Font")) { sc.MustGetString(); FFont *newfont = V_GetFont(sc.String); if (newfont != NULL) desc->mFont = newfont; if (sc.CheckString(",")) { sc.MustGetString(); desc->mFontColor2 = desc->mFontColor = V_FindFontColor((FName)sc.String); if (sc.CheckString(",")) { sc.MustGetString(); desc->mFontColor2 = V_FindFontColor((FName)sc.String); } } else { desc->mFontColor = OptionSettings.mFontColor; desc->mFontColor2 = OptionSettings.mFontColorValue; } } else if (sc.Compare("NetgameMessage")) { sc.MustGetString(); desc->mNetgameMessage = sc.String; } else if (sc.Compare("PlayerDisplay")) { bool noportrait = false; FName action = NAME_None; sc.MustGetNumber(); int x = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); int y = sc.Number; sc.MustGetStringName(","); sc.MustGetString(); PalEntry c1 = V_GetColor(NULL, sc.String); sc.MustGetStringName(","); sc.MustGetString(); PalEntry c2 = V_GetColor(NULL, sc.String); if (sc.CheckString(",")) { sc.MustGetNumber(); noportrait = !!sc.Number; if (sc.CheckString(",")) { sc.MustGetString(); action = sc.String; } } FListMenuItemPlayerDisplay *it = new FListMenuItemPlayerDisplay(desc, x, y, c1, c2, noportrait, action); desc->mItems.Push(it); } else if (sc.Compare("PlayerNameBox")) { sc.MustGetString(); FString text = sc.String; sc.MustGetStringName(","); sc.MustGetNumber(); int ofs = sc.Number; sc.MustGetStringName(","); sc.MustGetString(); FListMenuItem *it = new FPlayerNameBox(desc->mXpos, desc->mYpos, desc->mLinespacing, ofs, text, desc->mFont, desc->mFontColor, sc.String); desc->mItems.Push(it); desc->mYpos += desc->mLinespacing; if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1; } else if (sc.Compare("ValueText")) { sc.MustGetString(); FString text = sc.String; sc.MustGetStringName(","); sc.MustGetString(); FName action = sc.String; FName values; if (sc.CheckString(",")) { sc.MustGetString(); values = sc.String; } FListMenuItem *it = new FValueTextItem(desc->mXpos, desc->mYpos, desc->mLinespacing, text, desc->mFont, desc->mFontColor, desc->mFontColor2, action, values); desc->mItems.Push(it); desc->mYpos += desc->mLinespacing; if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1; } else if (sc.Compare("Slider")) { sc.MustGetString(); FString text = sc.String; sc.MustGetStringName(","); sc.MustGetString(); FString action = sc.String; sc.MustGetStringName(","); sc.MustGetNumber(); int min = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); int max = sc.Number; sc.MustGetStringName(","); sc.MustGetNumber(); int step = sc.Number; FListMenuItem *it = new FSliderItem(desc->mXpos, desc->mYpos, desc->mLinespacing, text, desc->mFont, desc->mFontColor, action, min, max, step); desc->mItems.Push(it); desc->mYpos += desc->mLinespacing; if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1; } else { sc.ScriptError("Unknown keyword '%s'", sc.String); } } }
void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block) { while(sc.CheckToken(TK_Identifier)) { SBarInfoCommand cmd; switch(cmd.type = sc.MustMatchString(SBarInfoRoutineLevel)) { case SBARINFO_DRAWSWITCHABLEIMAGE: sc.MustGetToken(TK_Identifier); if(sc.Compare("weaponslot")) { cmd.flags = DRAWIMAGE_WEAPONSLOT; sc.MustGetToken(TK_IntConst); cmd.value = sc.Number; } else if(sc.Compare("invulnerable")) { cmd.flags = DRAWIMAGE_INVULNERABILITY; } else if(sc.Compare("keyslot")) { cmd.flags = DRAWIMAGE_KEYSLOT; sc.MustGetToken(TK_IntConst); cmd.value = sc.Number; } else { cmd.setString(sc, sc.String, 0); const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } } if(sc.CheckToken(TK_AndAnd)) { cmd.flags |= DRAWIMAGE_SWITCHABLE_AND; if(cmd.flags & DRAWIMAGE_KEYSLOT) { sc.MustGetToken(TK_IntConst); cmd.special4 = sc.Number; } else { sc.MustGetToken(TK_Identifier); cmd.setString(sc, sc.String, 1); const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } } sc.MustGetToken(','); sc.MustGetToken(TK_StringConst); cmd.special = newImage(sc.String); sc.MustGetToken(','); sc.MustGetToken(TK_StringConst); cmd.special2 = newImage(sc.String); sc.MustGetToken(','); sc.MustGetToken(TK_StringConst); cmd.special3 = newImage(sc.String); sc.MustGetToken(','); } else { sc.MustGetToken(','); sc.MustGetToken(TK_StringConst); cmd.special = newImage(sc.String); sc.MustGetToken(','); } case SBARINFO_DRAWIMAGE: { bool getImage = true; if(sc.CheckToken(TK_Identifier)) { getImage = false; if(sc.Compare("playericon")) cmd.flags |= DRAWIMAGE_PLAYERICON; else if(sc.Compare("ammoicon1")) cmd.flags |= DRAWIMAGE_AMMO1; else if(sc.Compare("ammoicon2")) cmd.flags |= DRAWIMAGE_AMMO2; else if(sc.Compare("armoricon")) cmd.flags |= DRAWIMAGE_ARMOR; else if(sc.Compare("weaponicon")) cmd.flags |= DRAWIMAGE_WEAPONICON; else if(sc.Compare("sigil")) cmd.flags |= DRAWIMAGE_SIGIL; else if(sc.Compare("hexenarmor")) { cmd.flags = DRAWIMAGE_HEXENARMOR; sc.MustGetToken(TK_Identifier); if(sc.Compare("armor")) cmd.value = 0; else if(sc.Compare("shield")) cmd.value = 1; else if(sc.Compare("helm")) cmd.value = 2; else if(sc.Compare("amulet")) cmd.value = 3; else sc.ScriptError("Unkown armor type: '%s'", sc.String); sc.MustGetToken(','); getImage = true; } else if(sc.Compare("runeicon")) cmd.flags |= DRAWIMAGE_RUNEICON; else if(sc.Compare("translatable")) { cmd.flags |= DRAWIMAGE_TRANSLATABLE; getImage = true; } else { //sc.CheckToken(TK_Identifier); cmd.flags |= DRAWIMAGE_INVENTORYICON; const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } cmd.sprite_index = ((AInventory *)GetDefaultByType(item))->Icon; cmd.image_index = -1; } } if(getImage) { sc.MustGetToken(TK_StringConst); cmd.image_index = newImage(sc.String); cmd.sprite_index.SetInvalid(); } sc.MustGetToken(','); this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); if(sc.CheckToken(',')) { sc.MustGetToken(TK_Identifier); if(sc.Compare("center")) cmd.flags |= DRAWIMAGE_OFFSET_CENTER; else if(sc.Compare("centerbottom")) cmd.flags |= DRAWIMAGE_OFFSET_CENTERBOTTOM; else sc.ScriptError("'%s' is not a valid alignment.", sc.String); } sc.MustGetToken(';'); break; } case SBARINFO_DRAWNUMBER: cmd.special4 = cmd.special3 = -1; sc.MustGetToken(TK_IntConst); cmd.special = sc.Number; sc.MustGetToken(','); sc.MustGetToken(TK_Identifier); cmd.font = V_GetFont(sc.String); if(cmd.font == NULL) sc.ScriptError("Unknown font '%s'.", sc.String); sc.MustGetToken(','); sc.MustGetToken(TK_Identifier); cmd.translation = this->GetTranslation(sc, sc.String); sc.MustGetToken(','); if(sc.CheckToken(TK_IntConst)) { cmd.value = sc.Number; sc.MustGetToken(','); } else { sc.MustGetToken(TK_Identifier); if(sc.Compare("health")) cmd.flags = DRAWNUMBER_HEALTH; else if(sc.Compare("armor")) cmd.flags = DRAWNUMBER_ARMOR; else if(sc.Compare("ammo1")) cmd.flags = DRAWNUMBER_AMMO1; else if(sc.Compare("ammo2")) cmd.flags = DRAWNUMBER_AMMO2; else if(sc.Compare("ammo")) //request the next string to be an ammo type { sc.MustGetToken(TK_Identifier); cmd.setString(sc, sc.String, 0); cmd.flags = DRAWNUMBER_AMMO; const PClass* ammo = PClass::FindClass(sc.String); if(ammo == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo)) //must be a kind of ammo { sc.ScriptError("'%s' is not a type of ammo.", sc.String); } } else if(sc.Compare("ammocapacity")) { sc.MustGetToken(TK_Identifier); cmd.setString(sc, sc.String, 0); cmd.flags = DRAWNUMBER_AMMOCAPACITY; const PClass* ammo = PClass::FindClass(sc.String); if(ammo == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo)) //must be a kind of ammo { sc.ScriptError("'%s' is not a type of ammo.", sc.String); } } else if(sc.Compare("frags")) cmd.flags = DRAWNUMBER_FRAGS; else if(sc.Compare("kills")) cmd.flags |= DRAWNUMBER_KILLS; else if(sc.Compare("monsters")) cmd.flags |= DRAWNUMBER_MONSTERS; else if(sc.Compare("items")) cmd.flags |= DRAWNUMBER_ITEMS; else if(sc.Compare("totalitems")) cmd.flags |= DRAWNUMBER_TOTALITEMS; else if(sc.Compare("secrets")) cmd.flags |= DRAWNUMBER_SECRETS; else if(sc.Compare("totalsecrets")) cmd.flags |= DRAWNUMBER_TOTALSECRETS; else if(sc.Compare("armorclass")) cmd.flags |= DRAWNUMBER_ARMORCLASS; else if(sc.Compare("globalvar")) { cmd.flags |= DRAWNUMBER_GLOBALVAR; sc.MustGetToken(TK_IntConst); if(sc.Number < 0 || sc.Number >= NUM_GLOBALVARS) sc.ScriptError("Global variable number out of range: %d", sc.Number); cmd.value = sc.Number; } else if(sc.Compare("globalarray")) //acts like variable[playernumber()] { cmd.flags |= DRAWNUMBER_GLOBALARRAY; sc.MustGetToken(TK_IntConst); if(sc.Number < 0 || sc.Number >= NUM_GLOBALVARS) sc.ScriptError("Global variable number out of range: %d", sc.Number); cmd.value = sc.Number; } else if(sc.Compare("poweruptime")) { cmd.flags |= DRAWNUMBER_POWERUPTIME; sc.MustGetToken(TK_Identifier); cmd.setString(sc, sc.String, 0); const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !PClass::FindClass("PowerupGiver")->IsAncestorOf(item)) { sc.ScriptError("'%s' is not a type of PowerupGiver.", sc.String); } } else if(sc.Compare("teamscore")) //Takes in a number for team { cmd.flags |= DRAWNUMBER_TEAMSCORE; sc.MustGetToken(TK_StringConst); int t = -1; for(unsigned int i = 0;i < teams.Size();i++) { if(teams[i].Name.CompareNoCase(sc.String) == 0) { t = (int) i; break; } } if(t == -1) sc.ScriptError("'%s' is not a valid team.", sc.String); cmd.value = t; } else { cmd.flags = DRAWNUMBER_INVENTORY; cmd.setString(sc, sc.String, 0); const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of ammo { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } } sc.MustGetToken(','); } while(sc.CheckToken(TK_Identifier)) { if(sc.Compare("fillzeros")) cmd.flags |= DRAWNUMBER_FILLZEROS; else if(sc.Compare("whennotzero")) cmd.flags |= DRAWNUMBER_WHENNOTZERO; else if(sc.Compare("drawshadow")) cmd.flags |= DRAWNUMBER_DRAWSHADOW; else sc.ScriptError("Unknown flag '%s'.", sc.String); if(!sc.CheckToken('|')) sc.MustGetToken(','); } this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); if(sc.CheckToken(',')) { bool needsComma = false; if(sc.CheckToken(TK_IntConst)) //font spacing { cmd.special2 = sc.Number; needsComma = true; } if(!needsComma || sc.CheckToken(',')) //2nd coloring for "low-on" value { sc.MustGetToken(TK_Identifier); cmd.translation2 = this->GetTranslation(sc, sc.String); sc.MustGetToken(','); sc.MustGetToken(TK_IntConst); cmd.special3 = sc.Number; if(sc.CheckToken(',')) //3rd coloring for "high-on" value { sc.MustGetToken(TK_Identifier); cmd.translation3 = this->GetTranslation(sc, sc.String); sc.MustGetToken(','); sc.MustGetToken(TK_IntConst); cmd.special4 = sc.Number; } } } sc.MustGetToken(';'); break; case SBARINFO_DRAWMUGSHOT: if(sc.CheckToken(TK_StringConst)) { cmd.setString(sc, sc.String, 0, 3, true); sc.MustGetToken(','); } sc.MustGetToken(TK_IntConst); //accuracy if(sc.Number < 1 || sc.Number > 9) sc.ScriptError("Expected a number between 1 and 9, got %d instead.", sc.Number); cmd.special = sc.Number; sc.MustGetToken(','); while(sc.CheckToken(TK_Identifier)) { if(sc.Compare("xdeathface")) cmd.flags |= DRAWMUGSHOT_XDEATHFACE; else if(sc.Compare("animatedgodmode")) cmd.flags |= DRAWMUGSHOT_ANIMATEDGODMODE; else if(sc.Compare("disablegrin")) cmd.flags |= DRAWMUGSHOT_DISABLEGRIN; else if(sc.Compare("disableouch")) cmd.flags |= DRAWMUGSHOT_DISABLEOUCH; else if(sc.Compare("disablepain")) cmd.flags |= DRAWMUGSHOT_DISABLEPAIN; else if(sc.Compare("disablerampage")) cmd.flags |= DRAWMUGSHOT_DISABLERAMPAGE; else sc.ScriptError("Unknown flag '%s'.", sc.String); if(!sc.CheckToken('|')) sc.MustGetToken(','); } this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); sc.MustGetToken(';'); break; case SBARINFO_DRAWSELECTEDINVENTORY: { bool alternateonempty = false; while(true) //go until we get a font (non-flag) { sc.MustGetToken(TK_Identifier); if(sc.Compare("alternateonempty")) { alternateonempty = true; cmd.flags |= DRAWSELECTEDINVENTORY_ALTERNATEONEMPTY; } else if(sc.Compare("artiflash")) { cmd.flags |= DRAWSELECTEDINVENTORY_ARTIFLASH; } else if(sc.Compare("alwaysshowcounter")) { cmd.flags |= DRAWSELECTEDINVENTORY_ALWAYSSHOWCOUNTER; } else if(sc.Compare("center")) { cmd.flags |= DRAWSELECTEDINVENTORY_CENTER; } else if(sc.Compare("centerbottom")) { cmd.flags |= DRAWSELECTEDINVENTORY_CENTERBOTTOM; } else if(sc.Compare("drawshadow")) { cmd.flags |= DRAWSELECTEDINVENTORY_DRAWSHADOW; } else { cmd.font = V_GetFont(sc.String); if(cmd.font == NULL) sc.ScriptError("Unknown font '%s'.", sc.String); sc.MustGetToken(','); break; } if(!sc.CheckToken('|')) sc.MustGetToken(','); } this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); cmd.special2 = *(cmd.x + 30); cmd.special3 = *(cmd.y + 24); cmd.translation = CR_GOLD; if(sc.CheckToken(',')) //more font information { this->getCoordinates(sc, block.fullScreenOffsets, cmd.special2, cmd.special3); if(sc.CheckToken(',')) { sc.MustGetToken(TK_Identifier); cmd.translation = this->GetTranslation(sc, sc.String); if(sc.CheckToken(',')) { sc.MustGetToken(TK_IntConst); cmd.special4 = sc.Number; } } } if(alternateonempty) { sc.MustGetToken('{'); cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; this->ParseSBarInfoBlock(sc, cmd.subBlock); } else { sc.MustGetToken(';'); } break; } case SBARINFO_DRAWINVENTORYBAR: sc.MustGetToken(TK_Identifier); if(sc.Compare("Doom")) cmd.special = GAME_Doom; else if(sc.Compare("Heretic")) cmd.special = GAME_Heretic; else if(sc.Compare("Hexen")) cmd.special = GAME_Hexen; else if(sc.Compare("Strife")) cmd.special = GAME_Strife; else sc.ScriptError("Unkown style '%s'.", sc.String); sc.MustGetToken(','); while(sc.CheckToken(TK_Identifier)) { if(sc.Compare("alwaysshow")) { cmd.flags |= DRAWINVENTORYBAR_ALWAYSSHOW; } else if(sc.Compare("noartibox")) { cmd.flags |= DRAWINVENTORYBAR_NOARTIBOX; } else if(sc.Compare("noarrows")) { cmd.flags |= DRAWINVENTORYBAR_NOARROWS; } else if(sc.Compare("alwaysshowcounter")) { cmd.flags |= DRAWINVENTORYBAR_ALWAYSSHOWCOUNTER; } else if(sc.Compare("translucent")) { cmd.flags |= DRAWINVENTORYBAR_TRANSLUCENT; } else { sc.ScriptError("Unknown flag '%s'.", sc.String); } if(!sc.CheckToken('|')) sc.MustGetToken(','); } sc.MustGetToken(TK_IntConst); cmd.value = sc.Number; sc.MustGetToken(','); sc.MustGetToken(TK_Identifier); cmd.font = V_GetFont(sc.String); if(cmd.font == NULL) sc.ScriptError("Unknown font '%s'.", sc.String); sc.MustGetToken(','); this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); cmd.special2 = *(cmd.x + 26); cmd.special3 = *(cmd.y + 22); cmd.translation = CR_GOLD; if(sc.CheckToken(',')) //more font information { this->getCoordinates(sc, block.fullScreenOffsets, cmd.special2, cmd.special3); if(sc.CheckToken(',')) { sc.MustGetToken(TK_Identifier); cmd.translation = this->GetTranslation(sc, sc.String); if(sc.CheckToken(',')) { sc.MustGetToken(TK_IntConst); cmd.special4 = sc.Number; } } } sc.MustGetToken(';'); break; case SBARINFO_DRAWBAR: sc.MustGetToken(TK_StringConst); cmd.image_index = newImage(sc.String); cmd.sprite_index.SetInvalid(); sc.MustGetToken(','); sc.MustGetToken(TK_StringConst); cmd.special = newImage(sc.String); sc.MustGetToken(','); sc.MustGetToken(TK_Identifier); //yeah, this is the same as drawnumber, there might be a better way to copy it... if(sc.Compare("health")) { cmd.flags = DRAWNUMBER_HEALTH; if(sc.CheckToken(TK_Identifier)) //comparing reference { cmd.setString(sc, sc.String, 0); const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of inventory { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } } else cmd.special2 = DRAWBAR_COMPAREDEFAULTS; } else if(sc.Compare("armor")) { cmd.flags = DRAWNUMBER_ARMOR; if(sc.CheckToken(TK_Identifier)) { cmd.setString(sc, sc.String, 0); const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of inventory { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } } else cmd.special2 = DRAWBAR_COMPAREDEFAULTS; } else if(sc.Compare("ammo1")) cmd.flags = DRAWNUMBER_AMMO1; else if(sc.Compare("ammo2")) cmd.flags = DRAWNUMBER_AMMO2; else if(sc.Compare("ammo")) //request the next string to be an ammo type { sc.MustGetToken(TK_Identifier); cmd.setString(sc, sc.String, 0); cmd.flags = DRAWNUMBER_AMMO; const PClass* ammo = PClass::FindClass(sc.String); if(ammo == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo)) //must be a kind of ammo { sc.ScriptError("'%s' is not a type of ammo.", sc.String); } } else if(sc.Compare("frags")) cmd.flags = DRAWNUMBER_FRAGS; else if(sc.Compare("kills")) cmd.flags = DRAWNUMBER_KILLS; else if(sc.Compare("items")) cmd.flags = DRAWNUMBER_ITEMS; else if(sc.Compare("secrets")) cmd.flags = DRAWNUMBER_SECRETS; else if(sc.Compare("poweruptime")) { cmd.flags |= DRAWNUMBER_POWERUPTIME; sc.MustGetToken(TK_Identifier); cmd.setString(sc, sc.String, 0); const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !PClass::FindClass("PowerupGiver")->IsAncestorOf(item)) { sc.ScriptError("'%s' is not a type of PowerupGiver.", sc.String); } } else if(sc.Compare("teamscore")) //Takes in a number for team { cmd.flags |= DRAWNUMBER_TEAMSCORE; sc.MustGetToken(TK_StringConst); int t = -1; for(unsigned int i = 0;i < teams.Size();i++) { if(teams[i].Name.CompareNoCase(sc.String) == 0) { t = (int) i; break; } } if(t == -1) sc.ScriptError("'%s' is not a valid team.", sc.String); cmd.value = t; } else { cmd.flags = DRAWNUMBER_INVENTORY; cmd.setString(sc, sc.String, 0); const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } } sc.MustGetToken(','); sc.MustGetToken(TK_Identifier); if(sc.Compare("horizontal")) cmd.special2 += DRAWBAR_HORIZONTAL; else if(!sc.Compare("vertical")) sc.ScriptError("Unknown direction '%s'.", sc.String); sc.MustGetToken(','); while(sc.CheckToken(TK_Identifier)) { if(sc.Compare("reverse")) cmd.special2 += DRAWBAR_REVERSE; else sc.ScriptError("Unkown flag '%s'.", sc.String); if(!sc.CheckToken('|')) sc.MustGetToken(','); } this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); if(sc.CheckToken(',')) //border { sc.MustGetToken(TK_IntConst); cmd.special3 = sc.Number; } sc.MustGetToken(';'); break; case SBARINFO_DRAWGEM: while(sc.CheckToken(TK_Identifier)) { if(sc.Compare("wiggle")) cmd.flags |= DRAWGEM_WIGGLE; else if(sc.Compare("translatable")) cmd.flags |= DRAWGEM_TRANSLATABLE; else if(sc.Compare("armor")) cmd.flags |= DRAWGEM_ARMOR; else if(sc.Compare("reverse")) cmd.flags |= DRAWGEM_REVERSE; else sc.ScriptError("Unknown drawgem flag '%s'.", sc.String); if(!sc.CheckToken('|')) sc.MustGetToken(','); } sc.MustGetToken(TK_StringConst); //chain cmd.special = newImage(sc.String); sc.MustGetToken(','); sc.MustGetToken(TK_StringConst); //gem cmd.image_index = newImage(sc.String); cmd.sprite_index.SetInvalid(); sc.MustGetToken(','); cmd.special2 = this->getSignedInteger(sc); sc.MustGetToken(','); cmd.special3 = this->getSignedInteger(sc); sc.MustGetToken(','); sc.MustGetToken(TK_IntConst); if(sc.Number < 0) sc.ScriptError("Chain size must be a positive number."); cmd.special4 = sc.Number; sc.MustGetToken(','); this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); sc.MustGetToken(';'); break; case SBARINFO_DRAWSHADER: sc.MustGetToken(TK_IntConst); cmd.special = sc.Number; if(sc.Number < 1) sc.ScriptError("Width must be greater than 1."); sc.MustGetToken(','); sc.MustGetToken(TK_IntConst); cmd.special2 = sc.Number; if(sc.Number < 1) sc.ScriptError("Height must be greater than 1."); sc.MustGetToken(','); sc.MustGetToken(TK_Identifier); if(sc.Compare("vertical")) cmd.flags |= DRAWSHADER_VERTICAL; else if(!sc.Compare("horizontal")) sc.ScriptError("Unknown direction '%s'.", sc.String); sc.MustGetToken(','); if(sc.CheckToken(TK_Identifier)) { if(!sc.Compare("reverse")) { sc.ScriptError("Exspected 'reverse', got '%s' instead.", sc.String); } cmd.flags |= DRAWSHADER_REVERSE; sc.MustGetToken(','); } this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); sc.MustGetToken(';'); break; case SBARINFO_DRAWSTRING: sc.MustGetToken(TK_Identifier); cmd.font = V_GetFont(sc.String); if(cmd.font == NULL) sc.ScriptError("Unknown font '%s'.", sc.String); sc.MustGetToken(','); sc.MustGetToken(TK_Identifier); cmd.translation = this->GetTranslation(sc, sc.String); sc.MustGetToken(','); sc.MustGetToken(TK_StringConst); cmd.setString(sc, sc.String, 0, -1, false); sc.MustGetToken(','); this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); if(sc.CheckToken(',')) //spacing { sc.MustGetToken(TK_IntConst); cmd.special = sc.Number; } sc.MustGetToken(';'); break; case SBARINFO_DRAWKEYBAR: sc.MustGetToken(TK_IntConst); cmd.value = sc.Number; sc.MustGetToken(','); sc.MustGetToken(TK_Identifier); if(sc.Compare("vertical")) cmd.flags |= DRAWKEYBAR_VERTICAL; else if(!sc.Compare("horizontal")) sc.ScriptError("Unknown direction '%s'.", sc.String); sc.MustGetToken(','); while(sc.CheckToken(TK_Identifier)) { if(sc.Compare("reverserows")) cmd.flags |= DRAWKEYBAR_REVERSEROWS; else sc.ScriptError("Unknown flag '%s'.", sc.String); if(!sc.CheckToken('|')) sc.MustGetToken(','); } if(sc.CheckToken(TK_Auto)) cmd.special = -1; else { sc.MustGetToken(TK_IntConst); cmd.special = sc.Number; } sc.MustGetToken(','); this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); if(sc.CheckToken(',')) { //key offset sc.MustGetToken(TK_IntConst); cmd.special2 = sc.Number; if(sc.CheckToken(',')) { //max per row/column sc.MustGetToken(TK_IntConst); cmd.special3 = sc.Number; sc.MustGetToken(','); //row/column spacing (opposite of previous) if(sc.CheckToken(TK_Auto)) cmd.special4 = -1; else { sc.MustGetToken(TK_IntConst); cmd.special4 = sc.Number; } } } sc.MustGetToken(';'); break; case SBARINFO_GAMEMODE: while(sc.CheckToken(TK_Identifier)) { if(sc.Compare("singleplayer")) cmd.flags |= GAMETYPE_SINGLEPLAYER; else if(sc.Compare("cooperative")) cmd.flags |= GAMETYPE_COOPERATIVE; else if(sc.Compare("deathmatch")) cmd.flags |= GAMETYPE_DEATHMATCH; else if(sc.Compare("teamgame")) cmd.flags |= GAMETYPE_TEAMGAME; else if(sc.Compare("ctf")) cmd.flags |= GAMETYPE_CTF; else if(sc.Compare("oneflagctf")) cmd.flags |= GAMETYPE_ONEFLAGCTF; else if(sc.Compare("skulltag")) cmd.flags |= GAMETYPE_SKULLTAG; else if(sc.Compare("invasion")) cmd.flags |= GAMETYPE_INVASION; else if(sc.Compare("possession")) cmd.flags |= GAMETYPE_POSSESSION; else if(sc.Compare("teampossession")) cmd.flags |= GAMETYPE_TEAMPOSSESSION; else if(sc.Compare("lastmanstanding")) cmd.flags |= GAMETYPE_LASTMANSTANDING; else if(sc.Compare("teamlms")) cmd.flags |= GAMETYPE_TEAMLMS; else if(sc.Compare("survival")) cmd.flags |= GAMETYPE_SURVIVAL; else if(sc.Compare("instagib")) cmd.flags |= GAMETYPE_INSTAGIB; else if(sc.Compare("buckshot")) cmd.flags |= GAMETYPE_BUCKSHOT; //else I'm removing this error to allow cross port compatiblity. If it doesn't know what a gamemode is lets just ignore it. // sc.ScriptError("Unknown gamemode: %s", sc.String); if(sc.CheckToken('{')) break; sc.MustGetToken(','); } cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; this->ParseSBarInfoBlock(sc, cmd.subBlock); break; case SBARINFO_PLAYERCLASS: cmd.special = cmd.special2 = cmd.special3 = -1; for(int i = 0;i < 3 && sc.CheckToken(TK_Identifier);i++) //up to 3 classes { bool foundClass = false; for(unsigned int c = 0;c < PlayerClasses.Size();c++) { if(stricmp(sc.String, PlayerClasses[c].Type->Meta.GetMetaString(APMETA_DisplayName)) == 0) { foundClass = true; if(i == 0) cmd.special = PlayerClasses[c].Type->ClassIndex; else if(i == 1) cmd.special2 = PlayerClasses[c].Type->ClassIndex; else //should be 2 cmd.special3 = PlayerClasses[c].Type->ClassIndex; break; } } if(!foundClass) sc.ScriptError("Unkown PlayerClass '%s'.", sc.String); if(sc.CheckToken('{') || i == 2) goto FinishPlayerClass; sc.MustGetToken(','); } FinishPlayerClass: cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; this->ParseSBarInfoBlock(sc, cmd.subBlock); break; case SBARINFO_ASPECTRATIO: sc.MustGetToken(TK_StringConst); if(sc.Compare("4:3")) cmd.value = ASPECTRATIO_4_3; else if(sc.Compare("16:9")) cmd.value = ASPECTRATIO_16_9; else if(sc.Compare("16:10")) cmd.value = ASPECTRATIO_16_10; else if(sc.Compare("5:4")) cmd.value = ASPECTRATIO_5_4; else sc.ScriptError("Unkown aspect ratio: %s", sc.String); sc.MustGetToken('{'); cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; this->ParseSBarInfoBlock(sc, cmd.subBlock); break; case SBARINFO_ISSELECTED: //Using StringConst instead of Identifieres is deperecated! if(sc.CheckToken(TK_Identifier)) { if(sc.Compare("not")) { cmd.flags |= SBARINFOEVENT_NOT; if(!sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); } } else sc.MustGetToken(TK_StringConst); for(int i = 0;i < 2;i++) { cmd.setString(sc, sc.String, i); const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(item)) { sc.ScriptError("'%s' is not a type of weapon.", sc.String); } if(sc.CheckToken(',')) { if(!sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); } else break; } sc.MustGetToken('{'); cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; this->ParseSBarInfoBlock(sc, cmd.subBlock); break; case SBARINFO_USESSECONDARYAMMO: case SBARINFO_USESAMMO: if(sc.CheckToken(TK_Identifier)) { if(sc.Compare("not")) cmd.flags |= SBARINFOEVENT_NOT; else sc.ScriptError("Expected 'not' got '%s' instead.", sc.String); } sc.MustGetToken('{'); cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; this->ParseSBarInfoBlock(sc, cmd.subBlock); break; case SBARINFO_HASWEAPONPIECE: { sc.MustGetToken(TK_Identifier); const PClass* weapon = PClass::FindClass(sc.String); if(weapon == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon)) //must be a weapon sc.ScriptError("%s is not a kind of weapon.", sc.String); cmd.setString(sc, sc.String, 0); sc.MustGetToken(','); sc.MustGetToken(TK_IntConst); if(sc.Number < 1) sc.ScriptError("Weapon piece number can not be less than 1."); cmd.value = sc.Number; sc.MustGetToken('{'); cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; this->ParseSBarInfoBlock(sc, cmd.subBlock); break; } case SBARINFO_INVENTORYBARNOTVISIBLE: sc.MustGetToken('{'); cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; this->ParseSBarInfoBlock(sc, cmd.subBlock); break; case SBARINFO_WEAPONAMMO: sc.MustGetToken(TK_Identifier); if(sc.Compare("not")) { cmd.flags |= SBARINFOEVENT_NOT; sc.MustGetToken(TK_Identifier); } for(int i = 0;i < 2;i++) { cmd.setString(sc, sc.String, i); const PClass* ammo = PClass::FindClass(sc.String); if(ammo == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo)) //must be a kind of ammo { sc.ScriptError("'%s' is not a type of ammo.", sc.String); } if(sc.CheckToken(TK_OrOr)) { cmd.flags |= SBARINFOEVENT_OR; sc.MustGetToken(TK_Identifier); } else if(sc.CheckToken(TK_AndAnd)) { cmd.flags |= SBARINFOEVENT_AND; sc.MustGetToken(TK_Identifier); } else break; } sc.MustGetToken('{'); cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; this->ParseSBarInfoBlock(sc, cmd.subBlock); break; case SBARINFO_ININVENTORY: cmd.special2 = cmd.special3 = 0; sc.MustGetToken(TK_Identifier); if(sc.Compare("not")) { cmd.flags |= SBARINFOEVENT_NOT; sc.MustGetToken(TK_Identifier); } for(int i = 0;i < 2;i++) { cmd.setString(sc, sc.String, i); const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } if (sc.CheckToken(',')) { sc.MustGetNumber(); if (i == 0) cmd.special2 = sc.Number; else cmd.special3 = sc.Number; } if(sc.CheckToken(TK_OrOr)) { cmd.flags |= SBARINFOEVENT_OR; sc.MustGetToken(TK_Identifier); } else if(sc.CheckToken(TK_AndAnd)) { cmd.flags |= SBARINFOEVENT_AND; sc.MustGetToken(TK_Identifier); } else break; } sc.MustGetToken('{'); cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; this->ParseSBarInfoBlock(sc, cmd.subBlock); break; } block.commands.Push(cmd); } sc.MustGetToken('}'); }