int R_FindCustomTranslation(FName name) { switch (name) { case NAME_Ice: // Ice is a special case which will remain in its original slot. return TRANSLATION(TRANSLATION_Standard, 7); case NAME_None: return 0; case NAME_RainPillar1: case NAME_RainPillar2: case NAME_RainPillar3: case NAME_RainPillar4: case NAME_RainPillar5: case NAME_RainPillar6: case NAME_RainPillar7: case NAME_RainPillar8: return TRANSLATION(TRANSLATION_RainPillar, name.GetIndex() - NAME_RainPillar1); case NAME_Player1: case NAME_Player2: case NAME_Player3: case NAME_Player4: case NAME_Player5: case NAME_Player6: case NAME_Player7: case NAME_Player8: return TRANSLATION(TRANSLATION_Players, name.GetIndex() - NAME_Player1); } int *t = customTranslationMap.CheckKey(FName(name, true)); return (t != nullptr)? *t : -1; }
void Net_WriteWeapon(PClassWeapon *type) { int index, *index_p; index_p = Weapons_hton.CheckKey(type); if (index_p == NULL) { index = 0; } else { index = *index_p; } // 32767 weapons better be enough for anybody. assert(index >= 0 && index <= 32767); if (index < 128) { Net_WriteByte(index); } else { Net_WriteByte(0x80 | index); Net_WriteByte(index >> 7); } }
unsigned int LumpRemapper::LumpSampleRate(FResourceFile *Owner) { const int file = Wads.GetLumpFile(Owner->GetFirstLump()); const unsigned int* rate = sampleRateMap.CheckKey(file); if(rate) return 1000000/(256 - *rate); return 1000000/(256 - TIMER_VALUE_DEFAULT); }
void CheckCompatibility(MapData *map) { FMD5Holder md5; FCompatValues *flags; ii_compatflags = 0; ii_compatflags2 = 0; ib_compatflags = 0; ii_compatparams = -1; // When playing Doom IWAD levels force COMPAT_SHORTTEX and COMPATF_LIGHT. // I'm not sure if the IWAD maps actually need COMPATF_LIGHT but it certainly does not hurt. // TNT's MAP31 also needs COMPATF_STAIRINDEX but that only gets activated for TNT.WAD. if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATSHORTTEX) && level.maptype == MAPTYPE_DOOM) { ii_compatflags = COMPATF_SHORTTEX|COMPATF_LIGHT; if (gameinfo.flags & GI_COMPATSTAIRS) ii_compatflags |= COMPATF_STAIRINDEX; } map->GetChecksum(md5.Bytes); flags = BCompatMap.CheckKey(md5); if (developer >= DMSG_NOTIFY) { Printf("MD5 = "); for (size_t j = 0; j < sizeof(md5.Bytes); ++j) { Printf("%02X", md5.Bytes[j]); } if (flags != NULL) { Printf(", cflags = %08x, cflags2 = %08x, bflags = %08x\n", flags->CompatFlags[SLOT_COMPAT], flags->CompatFlags[SLOT_COMPAT2], flags->CompatFlags[SLOT_BCOMPAT]); } else { Printf("\n"); } } if (flags != NULL) { ii_compatflags |= flags->CompatFlags[SLOT_COMPAT]; ii_compatflags2 |= flags->CompatFlags[SLOT_COMPAT2]; ib_compatflags |= flags->CompatFlags[SLOT_BCOMPAT]; ii_compatparams = flags->ExtCommandIndex; } // Reset i_compatflags compatflags.Callback(); compatflags2.Callback(); // Set floatbob compatibility for all maps with an original Hexen MAPINFO. if (level.flags2 & LEVEL2_HEXENHACK) { ib_compatflags |= BCOMPATF_FLOATBOB; } }
void LumpRemapper::AddFile(const char* extension, FResourceFile *file, Type type) { LumpRemapper *iter = remaps.CheckKey(extension); if(iter == NULL) { LumpRemapper remaper(extension); remaper.AddFile(file, type); remaps.Insert(extension, remaper); return; } iter->AddFile(file, type); }
void LumpRemapper::LoadMap(const char* extension, const char* name, const char* data, unsigned int length) { LumpRemapper *iter = remaps.CheckKey(extension); if(iter == NULL) { LumpRemapper remaper(extension); remaper.LoadMap(name, data, length); remaps.Insert(extension, remaper); return; } iter->LoadMap(name, data, length); }
FxExpression *FxGlobalFunctionCall::StaticCreate (FName methodname, FArgumentList *args, const FScriptPosition &pos) { Creator *creator = CreatorMap.CheckKey(methodname); if (!creator) { pos.Message(MSG_ERROR, "Call to unknown function '%s'", methodname.GetChars()); return NULL; } return (*creator)(methodname, args, pos); }
static uint32_t ParticleColor(int rgb) { int *val; int stuff; val = ColorSaver.CheckKey(rgb); if (val != NULL) { return *val; } stuff = rgb | (ColorMatcher.Pick(RPART(rgb), GPART(rgb), BPART(rgb)) << 24); ColorSaver[rgb] = stuff; return stuff; }
static void ParseSpawnMap(FScanner &sc, SpawnMap & themap, const char *descript) { TMap<int, bool> defined; int error = 0; MapinfoSpawnItem editem; editem.filename = sc.ScriptName; 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("%s %d defined more than once", descript, ednum); error++; } else if (ednum < 0) { sc.ScriptMessage("%s must be positive, got %d", descript, ednum); error++; } defined[ednum] = true; editem.classname = sc.String; editem.linenum = sc.Line; themap.Insert(ednum, editem); } else { sc.ScriptError("Number expected"); } } if (error > 0) { sc.ScriptError("%d errors encountered in %s definition", error, descript); } }
const PClass *P_GetSpawnableType(int spawnnum) { if (spawnnum < 0) { // A named arg from a UDMF map FName spawnname = FName(ENamedName(-spawnnum)); if (spawnname.IsValidName()) { return PClass::FindClass(spawnname); } } else { // A numbered arg from a Hexen or UDMF map const PClass **type = SpawnableThings.CheckKey(spawnnum); if (type != NULL) { return *type; } } return NULL; }
//***************************************************************************** // void COOP_PotentiallyStoreUVDPickup ( const PClass *pType ) { // [BB] The current game mode doesn't need voodoo dolls, so no need to store any pickups. if ( COOP_VoodooDollsSelectedByGameMode() == false ) return; // [BB] There is no ingame joining in such gamemodes, so no need to store any pickups. if ( GAMEMODE_GetFlags( GAMEMODE_GetCurrentMode( )) & GMF_MAPRESETS ) return; // [BB] Nothing to store. if ( pType == NULL ) return; // [BB] We only store weapons and keys since they might be crucial to finish a map. if ( ( pType->IsDescendantOf( RUNTIME_CLASS( AWeapon )) == false ) && ( pType->IsDescendantOf( RUNTIME_CLASS( AKey )) == false ) ) return; const FName pickupName = pType->TypeName.GetChars(); if ( UVDpickupMap.CheckKey( pickupName ) == false ) UVDpickupMap.Insert( pickupName, 1 ); }
//========================================================================== // // CheckForUnsafeStates // // Performs a quick analysis to find potentially bad states. // This is not perfect because it cannot track jumps by function. // For such cases a runtime check in the relevant places is also present. // //========================================================================== static void CheckForUnsafeStates(PClassActor *obj) { static ENamedName weaponstates[] = { NAME_Ready, NAME_Deselect, NAME_Select, NAME_Fire, NAME_AltFire, NAME_Hold, NAME_AltHold, NAME_Flash, NAME_AltFlash, NAME_None }; static ENamedName pickupstates[] = { NAME_Pickup, NAME_Drop, NAME_Use, NAME_None }; TMap<FState *, bool> checked; ENamedName *test; if (obj->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { if (obj->Size == RUNTIME_CLASS(AWeapon)->Size) return; // This class cannot have user variables. test = weaponstates; } else if (obj->IsDescendantOf(RUNTIME_CLASS(ACustomInventory))) { if (obj->Size == RUNTIME_CLASS(ACustomInventory)->Size) return; // This class cannot have user variables. test = pickupstates; } else return; // something else derived from AStateProvider. We do not know what this may be. for (; *test != NAME_None; test++) { FState *state = obj->FindState(*test); while (state != nullptr && checked.CheckKey(state) == nullptr) // have we checked this state already. If yes, we can stop checking the current chain. { checked[state] = true; if (state->ActionFunc && state->ActionFunc->Unsafe) { // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. auto owner = FState::StaticFindStateOwner(state); GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "Unsafe state call in state %s.%d which accesses user variables, reached by %s.%s.\n", owner->TypeName.GetChars(), state - owner->OwnedStates, obj->TypeName.GetChars(), FName(*test).GetChars()); } state = state->NextState; } } }
DamageTypeDefinition *DamageTypeDefinition::Get(FName type) { return GlobalDamageDefinitions.CheckKey(type); }
void CheckCompatibility(MapData *map) { FMD5Holder md5; FCompatValues *flags; bool onlyparams = true; // When playing Doom IWAD levels force COMPAT_SHORTTEX and COMPATF_LIGHT. // I'm not sure if the IWAD maps actually need COMPATF_LIGHT but it certainly does not hurt. // TNT's MAP31 also needs COMPATF_STAIRINDEX but that only gets activated for TNT.WAD. if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATSHORTTEX) && level.maptype == MAPTYPE_DOOM) { ii_compatflags = COMPATF_SHORTTEX|COMPATF_LIGHT; if (gameinfo.flags & GI_COMPATSTAIRS) ii_compatflags |= COMPATF_STAIRINDEX; ii_compatflags2 = 0; ib_compatflags = 0; ii_compatparams = -1; } else if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATPOLY1) && Wads.CheckLumpName(map->lumpnum, "MAP36")) { ii_compatflags = COMPATF_POLYOBJ; ii_compatflags2 = 0; ib_compatflags = 0; ii_compatparams = -1; } else if (Wads.GetLumpFile(map->lumpnum) == 2 && (gameinfo.flags & GI_COMPATPOLY2) && Wads.CheckLumpName(map->lumpnum, "MAP47")) { ii_compatflags = COMPATF_POLYOBJ; ii_compatflags2 = 0; ib_compatflags = 0; ii_compatparams = -1; } else { onlyparams = false; } map->GetChecksum(md5.Bytes); flags = BCompatMap.CheckKey(md5); if (developer) { Printf("MD5 = "); for (size_t j = 0; j < sizeof(md5.Bytes); ++j) { Printf("%02X", md5.Bytes[j]); } if (flags != NULL) { Printf(", cflags = %08x, cflags2 = %08x, bflags = %08x\n", flags->CompatFlags[SLOT_COMPAT], flags->CompatFlags[SLOT_COMPAT2], flags->CompatFlags[SLOT_BCOMPAT]); } else { Printf("\n"); } } if (flags != NULL) { if (!onlyparams) { ii_compatflags = flags->CompatFlags[SLOT_COMPAT]; ii_compatflags2 = flags->CompatFlags[SLOT_COMPAT2]; ib_compatflags = flags->CompatFlags[SLOT_BCOMPAT]; } ii_compatparams = flags->ExtCommandIndex; } else { if (!onlyparams) { ii_compatflags = 0; ii_compatflags2 = 0; ib_compatflags = 0; } ii_compatparams = -1; } // Reset i_compatflags compatflags.Callback(); compatflags2.Callback(); }
static void DoParse(const char *filename) { if (TokenMap.CountUsed() == 0) { InitTokenMap(); } FScanner sc; void *parser; int tokentype; int lump; bool failed; ZCCToken value; lump = Wads.CheckNumForFullName(filename, true); if (lump >= 0) { sc.OpenLumpNum(lump); } else if (FileExists(filename)) { sc.OpenFile(filename); } else { Printf("Could not find script lump '%s'\n", filename); return; } parser = ZCCParseAlloc(malloc); failed = false; #ifdef _DEBUG FILE *f = fopen("trace.txt", "w"); char prompt = '\0'; ZCCParseTrace(f, &prompt); #endif ZCCParseState state(sc); while (sc.GetToken()) { value.SourceLoc = sc.GetMessageLine(); switch (sc.TokenType) { case TK_StringConst: value.String = state.Strings.Alloc(sc.String, sc.StringLen); tokentype = ZCC_STRCONST; break; case TK_NameConst: value.Int = sc.Name; tokentype = ZCC_NAMECONST; break; case TK_IntConst: value.Int = sc.Number; tokentype = ZCC_INTCONST; break; case TK_UIntConst: value.Int = sc.Number; tokentype = ZCC_UINTCONST; break; case TK_FloatConst: value.Float = sc.Float; tokentype = ZCC_FLOATCONST; break; case TK_Identifier: value.Int = FName(sc.String); tokentype = ZCC_IDENTIFIER; break; case TK_NonWhitespace: value.Int = FName(sc.String); tokentype = ZCC_NWS; break; default: TokenMapEntry *zcctoken = TokenMap.CheckKey(sc.TokenType); if (zcctoken != NULL) { tokentype = zcctoken->TokenType; value.Int = zcctoken->TokenName; } else { sc.ScriptMessage("Unexpected token %s.\n", sc.TokenName(sc.TokenType).GetChars()); goto parse_end; } break; } ZCCParse(parser, tokentype, value, &state); if (failed) { sc.ScriptMessage("Parse failed\n"); goto parse_end; } } parse_end: value.Int = -1; ZCCParse(parser, ZCC_EOF, value, &state); ZCCParse(parser, 0, value, &state); ZCCParseFree(parser, free); PSymbolTable symbols(&GlobalSymbols); ZCCCompiler cc(state, NULL, symbols); cc.Compile(); #ifdef _DEBUG if (f != NULL) { fclose(f); } FString ast = ZCC_PrintAST(state.TopNode); FString astfile = ExtractFileBase(filename, false); astfile << ".ast"; f = fopen(astfile, "w"); if (f != NULL) { fputs(ast.GetChars(), f); fclose(f); } #endif }
void FFont::ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height, const DVector2 &Scale) { // all valid lumps must be named with a hex number that represents the Unicode character index for its first character, TArray<TexPart> part(1, true); TMap<int, FTexture*> charMap; int minchar = INT_MAX; int maxchar = INT_MIN; for (auto &entry : folderdata) { char *endp; auto base = ExtractFileBase(entry.name); auto position = strtoll(base.GetChars(), &endp, 16); if ((*endp == 0 || (*endp == '.' && position >= 0 && position < 0xffff))) // Sheet fonts may fill in the low control chars. { auto lump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch); if (lump.isValid()) { auto tex = TexMan.GetTexture(lump); int numtex_x = tex->GetWidth() / width; int numtex_y = tex->GetHeight() / height; int maxinsheet = int(position) + numtex_x * numtex_y - 1; if (minchar > position) minchar = int(position); if (maxchar < maxinsheet) maxchar = maxinsheet; for (int y = 0; y < numtex_y; y++) { for (int x = 0; x < numtex_x; x++) { part[0].OriginX = -width * x; part[0].OriginY = -height * y; part[0].Image = tex->GetImage(); FMultiPatchTexture *image = new FMultiPatchTexture(width, height, part, false, false); FImageTexture *tex = new FImageTexture(image, ""); tex->SetUseType(ETextureType::FontChar); tex->bMultiPatch = true; tex->Width = width; tex->Height = height; tex->_LeftOffset[0] = tex->_LeftOffset[1] = tex->_TopOffset[0] = tex->_TopOffset[1] = 0; tex->Scale = Scale; tex->bMasked = true; tex->bTranslucent = -1; tex->bWorldPanning = true; tex->bNoDecals = false; tex->SourceLump = -1; // We do not really care. TexMan.AddTexture(tex); charMap.Insert(int(position) + x + y * numtex_x, tex); } } } } } FirstChar = minchar; bool map1252 = false; if (minchar < 0x80 && maxchar >= 0xa0) // should be a settable option, but that'd probably cause more problems than it'd solve. { if (maxchar < 0x2122) maxchar = 0x2122; map1252 = true; } LastChar = maxchar; auto count = maxchar - minchar + 1; Chars.Resize(count); int fontheight = 0; for (int i = 0; i < count; i++) { auto lump = charMap.CheckKey(FirstChar + i); if (lump != nullptr) { FTexture *pic = *lump; auto b = pic->Get8BitPixels(false); Chars[i].OriginalPic = pic; Chars[i].TranslatedPic = new FImageTexture(new FFontChar1(pic->GetImage()), ""); Chars[i].TranslatedPic->CopySize(pic); Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); TexMan.AddTexture(Chars[i].TranslatedPic); } Chars[i].XMove = width; } if (map1252) { // Move the Windows-1252 characters to their proper place. for (int i = 0x80; i < 0xa0; i++) { if (win1252map[i - 0x80] != i && Chars[i - minchar].TranslatedPic != nullptr && Chars[win1252map[i - 0x80] - minchar].TranslatedPic == nullptr) { std::swap(Chars[i - minchar], Chars[win1252map[i - 0x80] - minchar]); } } } SpaceWidth = width; }
FFont::FFont (const char *name, const char *nametemplate, const char *filetemplate, int lfirst, int lcount, int start, int fdlump, int spacewidth, bool notranslate, bool iwadonly) { int i; FTextureID lump; char buffer[12]; int maxyoffs; bool doomtemplate = (nametemplate && (gameinfo.gametype & GAME_DoomChex)) ? strncmp (nametemplate, "STCFN", 5) == 0 : false; DVector2 Scale = { 1, 1 }; noTranslate = notranslate; Lump = fdlump; GlobalKerning = false; FontName = name; Next = FirstFont; FirstFont = this; Cursor = '_'; ActiveColors = 0; SpaceWidth = 0; FontHeight = 0; uint8_t pp = 0; for (auto &p : PatchRemap) p = pp++; translateUntranslated = false; int FixedWidth = 0; maxyoffs = 0; TMap<int, FTexture*> charMap; int minchar = INT_MAX; int maxchar = INT_MIN; // Read the font's configuration. // This will not be done for the default fonts, because they are not atomic and the default content does not need it. TArray<FolderEntry> folderdata; if (filetemplate != nullptr) { FStringf path("fonts/%s/", filetemplate); // If a name template is given, collect data from all resource files. // For anything else, each folder is being treated as an atomic, self-contained unit and mixing from different glyph sets is blocked. Wads.GetLumpsInFolder(path, folderdata, nametemplate == nullptr); //if (nametemplate == nullptr) { FStringf infpath("fonts/%s/font.inf", filetemplate); unsigned index = folderdata.FindEx([=](const FolderEntry &entry) { return infpath.CompareNoCase(entry.name) == 0; }); if (index < folderdata.Size()) { FScanner sc; sc.OpenLumpNum(folderdata[index].lumpnum); while (sc.GetToken()) { sc.TokenMustBe(TK_Identifier); if (sc.Compare("Kerning")) { sc.MustGetValue(false); GlobalKerning = sc.Number; } else if (sc.Compare("Scale")) { sc.MustGetValue(true); Scale.Y = Scale.X = sc.Float; if (sc.CheckToken(',')) { sc.MustGetValue(true); Scale.Y = sc.Float; } } else if (sc.Compare("SpaceWidth")) { sc.MustGetValue(false); SpaceWidth = sc.Number; } else if (sc.Compare("FontHeight")) { sc.MustGetValue(false); FontHeight = sc.Number; } else if (sc.Compare("CellSize")) { sc.MustGetValue(false); FixedWidth = sc.Number; sc.MustGetToken(','); sc.MustGetValue(false); FontHeight = sc.Number; } else if (sc.Compare("Translationtype")) { sc.MustGetToken(TK_Identifier); if (sc.Compare("console")) { TranslationType = 1; } else if (sc.Compare("standard")) { TranslationType = 0; } else { sc.ScriptError("Unknown translation type %s", sc.String); } } } } } } if (FixedWidth > 0) { ReadSheetFont(folderdata, FixedWidth, FontHeight, Scale); Type = Folder; } else { if (nametemplate != nullptr) { if (!iwadonly) { for (i = 0; i < lcount; i++) { int position = lfirst + i; mysnprintf(buffer, countof(buffer), nametemplate, i + start); lump = TexMan.CheckForTexture(buffer, ETextureType::MiscPatch); if (doomtemplate && lump.isValid() && i + start == 121) { // HACKHACK: Don't load STCFN121 in doom(2), because // it's not really a lower-case 'y' but a '|'. // Because a lot of wads with their own font seem to foolishly // copy STCFN121 and make it a '|' themselves, wads must // provide STCFN120 (x) and STCFN122 (z) for STCFN121 to load as a 'y'. if (!TexMan.CheckForTexture("STCFN120", ETextureType::MiscPatch).isValid() || !TexMan.CheckForTexture("STCFN122", ETextureType::MiscPatch).isValid()) { // insert the incorrectly named '|' graphic in its correct position. position = 124; } } if (lump.isValid()) { Type = Multilump; if (position < minchar) minchar = position; if (position > maxchar) maxchar = position; charMap.Insert(position, TexMan.GetTexture(lump)); } } } else { FTexture *texs[256] = {}; if (lcount > 256 - start) lcount = 256 - start; for (i = 0; i < lcount; i++) { TArray<FTextureID> array; mysnprintf(buffer, countof(buffer), nametemplate, i + start); TexMan.ListTextures(buffer, array, true); for (auto entry : array) { FTexture *tex = TexMan.GetTexture(entry, false); if (tex && tex->SourceLump >= 0 && Wads.GetLumpFile(tex->SourceLump) <= Wads.GetIwadNum() && tex->UseType == ETextureType::MiscPatch) { texs[i] = tex; } } } if (doomtemplate) { // Handle the misplaced '|'. if (texs[121 - '!'] && !texs[120 - '!'] && !texs[122 - '!'] && !texs[124 - '!']) { texs[124 - '!'] = texs[121 - '!']; texs[121 - '!'] = nullptr; } } for (i = 0; i < lcount; i++) { if (texs[i]) { int position = lfirst + i; Type = Multilump; if (position < minchar) minchar = position; if (position > maxchar) maxchar = position; charMap.Insert(position, texs[i]); } } } } if (folderdata.Size() > 0) { // all valid lumps must be named with a hex number that represents its Unicode character index. for (auto &entry : folderdata) { char *endp; auto base = ExtractFileBase(entry.name); auto position = strtoll(base.GetChars(), &endp, 16); if ((*endp == 0 || (*endp == '.' && position >= '!' && position < 0xffff))) { auto lump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch); if (lump.isValid()) { if ((int)position < minchar) minchar = (int)position; if ((int)position > maxchar) maxchar = (int)position; auto tex = TexMan.GetTexture(lump); tex->SetScale(Scale); charMap.Insert((int)position, tex); Type = Folder; } } } } FirstChar = minchar; LastChar = maxchar; auto count = maxchar - minchar + 1; Chars.Resize(count); int fontheight = 0; for (i = 0; i < count; i++) { auto lump = charMap.CheckKey(FirstChar + i); if (lump != nullptr) { FTexture *pic = *lump; if (pic != nullptr) { int height = pic->GetDisplayHeight(); int yoffs = pic->GetDisplayTopOffset(); if (yoffs > maxyoffs) { maxyoffs = yoffs; } height += abs(yoffs); if (height > fontheight) { fontheight = height; } } pic->SetUseType(ETextureType::FontChar); if (!noTranslate) { Chars[i].OriginalPic = pic; Chars[i].TranslatedPic = new FImageTexture(new FFontChar1(pic->GetImage()), ""); Chars[i].TranslatedPic->CopySize(pic); Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); TexMan.AddTexture(Chars[i].TranslatedPic); } else { Chars[i].TranslatedPic = pic; } Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth(); } else { Chars[i].TranslatedPic = nullptr; Chars[i].XMove = INT_MIN; } } if (SpaceWidth == 0) // An explicit override from the .inf file must always take precedence { if (spacewidth != -1) { SpaceWidth = spacewidth; } else if ('N' - FirstChar >= 0 && 'N' - FirstChar < count && Chars['N' - FirstChar].TranslatedPic != nullptr) { SpaceWidth = (Chars['N' - FirstChar].XMove + 1) / 2; } else { SpaceWidth = 4; } } if (FontHeight == 0) FontHeight = fontheight; FixXMoves(); } if (!noTranslate) LoadTranslations(); }
FScriptPosition & GetStateSource(FState *state) { auto check = StateSourceLines.CheckKey(state); return check ? *check : unknownstatesource; }
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); } }