void C4Language::LoadInfos(C4Group &hGroup) { char strEntry[_MAX_FNAME + 1]; char *strTable; // Look for language string tables hGroup.ResetSearch(); while (hGroup.FindNextEntry(C4CFN_Language, strEntry)) // For now, we will only load info on the first string table found for a given // language code as there is currently no handling for selecting different string tables // of the same code - the system always loads the first string table found for a given code if (!FindInfo(GetFilenameOnly(strEntry) + SLen(GetFilenameOnly(strEntry)) - 2)) // Load language string table if (hGroup.LoadEntry(strEntry, &strTable, 0, 1)) { // New language info C4LanguageInfo *pInfo = new C4LanguageInfo; // Get language code by entry name SCopy(GetFilenameOnly(strEntry) + SLen(GetFilenameOnly(strEntry)) - 2, pInfo->Code, 2); SCapitalize(pInfo->Code); // Get language name, info, fallback from table CopyResStr("IDS_LANG_NAME", strTable, pInfo->Name); CopyResStr("IDS_LANG_INFO", strTable, pInfo->Info); CopyResStr("IDS_LANG_FALLBACK", strTable, pInfo->Fallback); // Safety: pipe character is not allowed in any language info string SReplaceChar(pInfo->Name, '|', ' '); SReplaceChar(pInfo->Info, '|', ' '); SReplaceChar(pInfo->Fallback, '|', ' '); // Delete table delete [] strTable; // Add info to list pInfo->Next = Infos; Infos = pInfo; } }
void C4StartupMainDlg::UpdateParticipants() { // First validate all participants (files must exist) StdStrBuf strPlayers, strPlayer; strPlayer.SetLength(1024 + 1); strPlayers.Copy(Config.General.Participants); *Config.General.Participants = 0; for (int i = 0; SCopySegment(strPlayers.getData(), i, strPlayer.getMData(), ';', 1024, true); i++) { const char *szPlayer = strPlayer.getData(); if (!szPlayer || !*szPlayer) continue; if (!FileExists(szPlayer)) continue; if (!SEqualNoCase(GetExtension(szPlayer), "c4p")) continue; // additional sanity check to clear strange exe-path-only // entries in player list? SAddModule(Config.General.Participants, szPlayer); } // Draw selected players - we are currently displaying the players stored in // Config.General.Participants. // Existence of the player files is not validated and player filenames are // displayed directly // (names are not loaded from the player core). strPlayers.Format(LoadResStr("IDS_DESC_PLRS")); if (!Config.General.Participants[0]) strPlayers.Append(LoadResStr("IDS_DLG_NOPLAYERSSELECTED")); else for (int i = 0; SCopySegment(Config.General.Participants, i, strPlayer.getMData(), ';', 1024, true); i++) { if (i > 0) strPlayers.Append(", "); strPlayers.Append(C4Language::IconvClonk( GetFilenameOnly(strPlayer.getData())).getData()); } pParticipantsLbl->SetText(strPlayers.getData()); }
void C4StartupMainDlg::UpdateParticipants() { // First validate all participants (files must exist) std::string strPlayers(Config.General.Participants); std::vector<char> strPlayer(1025); *Config.General.Participants=0; for (int i = 0; SCopySegment(strPlayers.c_str(), i, &strPlayer[0], ';', strPlayer.size() - 1, true); i++) { const char *szPlayer = &strPlayer[0]; std::string strPlayerFile(Config.General.UserDataPath); strPlayerFile.append(szPlayer); if (!szPlayer || !*szPlayer) continue; if (!FileExists(strPlayerFile.c_str())) continue; if (!SEqualNoCase(GetExtension(szPlayer), "ocp")) continue; // additional sanity check to clear strange exe-path-only entries in player list? SAddModule(Config.General.Participants, szPlayer); } // Draw selected players - we are currently displaying the players stored in Config.General.Participants. // Existence of the player files is not validated and player filenames are displayed directly // (names are not loaded from the player core). strPlayers = LoadResStr("IDS_DESC_PLRS"); if (!Config.General.Participants[0]) strPlayers.append(LoadResStr("IDS_DLG_NOPLAYERSSELECTED")); else for (int i = 0; SCopySegment(Config.General.Participants, i, &strPlayer[0], ';', 1024, true); i++) { if (i > 0) strPlayers.append(", "); strPlayers.append(GetFilenameOnly(&strPlayer[0])); } pParticipantsLbl->SetText(strPlayers.c_str()); }
C4GUI::ContextMenu *C4StartupMainDlg::OnPlayerSelContextRemove(C4GUI::Element *pBtn, int32_t iX, int32_t iY) { C4GUI::ContextMenu *pCtx = new C4GUI::ContextMenu(); char szPlayer[1024+1]; for (int i = 0; SCopySegment(Config.General.Participants, i, szPlayer, ';', 1024, true); i++) if (*szPlayer) pCtx->AddItem(GetFilenameOnly(szPlayer), "Remove this player from participation list", C4GUI::Ico_Player, new C4GUI::CBMenuHandlerEx<C4StartupMainDlg, int>(this, &C4StartupMainDlg::OnPlayerSelContextRemovePlr, i), nullptr); return pCtx; }
void C4GameSaveSavegame::AdjustCore(C4Scenario &rC4S) { // Determine save game index from trailing number in group file name int iSaveGameIndex = GetTrailingNumber(GetFilenameOnly(pSaveGroup->GetFullName().getData())); // Looks like a decent index: set numbered icon if (Inside(iSaveGameIndex, 1, 10)) rC4S.Head.Icon = 2 + (iSaveGameIndex - 1); // Else: set normal script icon else rC4S.Head.Icon = 29; }
bool C4VectorFont::Init(C4Group &hGrp, const char *szFilename, C4Config &rCfg) { // name by file Name.Copy(GetFilenameOnly(szFilename)); #if defined(_WIN32) && !defined(HAVE_FREETYPE) // check whether group is directory or packed if (!hGrp.IsPacked()) { // it's open: use the file directly SCopy(hGrp.GetFullName().getData(), FileName, _MAX_PATH); AppendBackslash(FileName); SAppend(szFilename, FileName); if (!FileExists(FileName)) { *FileName=0; return false; } fIsTempFile = false; } else { // it's packed: extract to temp path SCopy(rCfg.AtTempPath(szFilename), FileName, _MAX_PATH); // make sure the filename is not in use, in case multiple instances of the engine are run if (FileExists(FileName)) { RemoveExtension(FileName); StdStrBuf sNewFilename; for (int i=0; i<1000; ++i) { sNewFilename.Format("%s%x", FileName, (int)rand()); if (*GetExtension(szFilename)) { sNewFilename.AppendChar('.'); sNewFilename.Append(GetExtension(szFilename)); } if (!FileExists(sNewFilename.getData())) break; } SCopy(sNewFilename.getData(), FileName, _MAX_PATH); } if (!hGrp.ExtractEntry(szFilename, FileName)) { *FileName=0; return false; } fIsTempFile = true; } // add the font resource //if (!AddFontResourceEx(FileName, FR_PRIVATE, NULL)) requires win2k if (!AddFontResource(FileName)) { if (fIsTempFile) EraseFile(FileName); *FileName='\0'; return false; } #else if (!hGrp.LoadEntry(szFilename, Data)) return false; #endif // success return true; }
C4GUI::ContextMenu *C4StartupMainDlg::OnPlayerSelContextAdd(C4GUI::Element *pBtn, int32_t iX, int32_t iY) { C4GUI::ContextMenu *pCtx = new C4GUI::ContextMenu(); const char *szFn; StdStrBuf sSearchPath(Config.General.UserDataPath); // sSearchPath.Format("%s%s", (const char *) Config.General.ExePath, (const char *) Config.General.PlayerPath); for (DirectoryIterator i(sSearchPath.getData()); (szFn=*i); i++) { szFn = Config.AtRelativePath(szFn); if (*GetFilename(szFn) == '.') continue; if (!WildcardMatch(C4CFN_PlayerFiles, GetFilename(szFn))) continue; if (!SIsModule(Config.General.Participants, szFn, nullptr, false)) pCtx->AddItem(GetFilenameOnly(szFn), "Let this player join in next game", C4GUI::Ico_Player, new C4GUI::CBMenuHandlerEx<C4StartupMainDlg, StdCopyStrBuf>(this, &C4StartupMainDlg::OnPlayerSelContextAddPlr, StdCopyStrBuf(szFn)), nullptr); } return pCtx; }
LinkedList *GetMatchingFiles (const char * const pattern, const bool full_path_flag) { LinkedList *list_p = AllocateLinkedList (FreeStringListNode); if (list_p) { char *filename_p = GetFilenameOnly (pattern); if (filename_p) { char *path_p = GetPathOnly (pattern); if (path_p) { DIR *dir_p = opendir (path_p); if (dir_p) { struct dirent entry; struct dirent *entry_p = &entry; while ((entry_p = readdir (dir_p)) != NULL) { if ((fnmatch (filename_p, entry_p -> d_name, 0)) == 0) { StringListNode *node_p = NULL; if (full_path_flag) { char *full_filename_s = MakeFilename (path_p, entry_p -> d_name); if (full_filename_s) { node_p = AllocateStringListNode (full_filename_s, MF_SHALLOW_COPY); } } else { node_p = AllocateStringListNode (entry_p -> d_name, MF_DEEP_COPY); } if (node_p) { LinkedListAddTail (list_p, (ListItem *) node_p); } } } closedir (dir_p); } FreeMemory (path_p); } FreeMemory (filename_p); } if (list_p -> ll_size > 0) { return list_p; } else { FreeLinkedList (list_p); } } return NULL; }
bool C4FontLoader::InitFont(CStdFont &rFont, const char *szFontName, FontType eType, int32_t iSize, C4GroupSet *pGfxGroups, bool fDoShadow) { // safety if (!szFontName || !*szFontName) { LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } // get font to load // pFontDefs may be NULL if no fonts are loaded; but then iFontDefCount is zero as well // the function must not be aborted, because a standard windows font may be loaded std::vector<C4FontDef>::iterator pFontDefC = FontDefs.begin(), pFontDef = FontDefs.end(); while (pFontDefC != FontDefs.end()) { // check font if (pFontDefC->Name == szFontName) { int32_t iSizeDiff = Abs(pFontDefC->iSize - iSize); // better match than last font? if (pFontDef == FontDefs.end() || Abs(pFontDef->iSize - iSize) >= iSizeDiff) pFontDef = pFontDefC; } // check next one ++pFontDefC; } // if def has not been found, use the def as font name // determine font def string const char *szFontString = szFontName; // special: Fonts without shadow are always newly rendered if (!fDoShadow) { pFontDef=FontDefs.end(); } if (pFontDef!=FontDefs.end()) switch (eType) { case C4FT_Log: szFontString = pFontDef->LogFont.getData(); break; case C4FT_MainSmall:szFontString = pFontDef->SmallFont.getData(); break; case C4FT_Main: szFontString = pFontDef->Font.getData(); break; case C4FT_Caption: szFontString = pFontDef->CaptionFont.getData(); break; case C4FT_Title: szFontString = pFontDef->TitleFont.getData(); break; default: LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; // invalid call } // font not assigned? if (!*szFontString) { // invalid call or spec LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } // get font name char FontFaceName[C4MaxName+1], FontParam[C4MaxName+1]; SCopyUntil(szFontString, FontFaceName, ',', C4MaxName); // is it an image file? const char *szExt = GetExtension(FontFaceName); if (SEqualNoCase(szExt, "png") || SEqualNoCase(szExt, "bmp")) { // image file name: load bitmap font from image file // if no graphics group is given, do not load yet if (!pGfxGroups) { LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } // indent given? int32_t iIndent = 0; if (SCopySegment(szFontString, 1, FontParam, ',', C4MaxName)) sscanf(FontParam, "%i", &iIndent); // load font face from gfx group int32_t iGrpId; C4Group *pGrp = pGfxGroups->FindEntry(FontFaceName, NULL, &iGrpId); if (!pGrp) { LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } // check if it's already loaded from that group with that parameters if (!rFont.IsSameAsID(FontFaceName, iGrpId, iIndent)) { // it's not; so (re-)load it now! if (rFont.IsInitialized()) { // reloading rFont.Clear(); LogF(LoadResStr("IDS_PRC_UPDATEFONT"), FontFaceName, iIndent, 0); } C4Surface sfc; if (!sfc.Load(*pGrp, FontFaceName)) { LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } // init font from face try { rFont.Init(GetFilenameOnly(FontFaceName), &sfc, iIndent); } catch (std::runtime_error & e) { LogFatal(e.what()); LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } rFont.id = iGrpId; } } else { int32_t iDefFontSize; DWORD dwDefWeight=FW_NORMAL; #if defined(_WIN32) && !defined(HAVE_FREETYPE) switch (eType) { case C4FT_Log: iDefFontSize = 8; break; case C4FT_MainSmall:iDefFontSize = iSize+1; break; case C4FT_Main: iDefFontSize = iSize+4; break; case C4FT_Caption: iDefFontSize = iSize+6; dwDefWeight = FW_BOLD; break; case C4FT_Title: iDefFontSize = iSize*3; break; default: LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; // invalid call } #else switch (eType) { case C4FT_Log: iDefFontSize = iSize*12/14; break; case C4FT_MainSmall:iDefFontSize = iSize*13/14; break; case C4FT_Main: iDefFontSize = iSize; break; case C4FT_Caption: iDefFontSize = iSize*16/14; /*dwDefWeight = FW_MEDIUM;*/ break; case C4FT_Title: iDefFontSize = iSize*22/14; /*dwDefWeight = FW_MEDIUM;*/ break; default: LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; // invalid call } #endif // regular font name: let WinGDI or Freetype draw a font with the given parameters // font size given? if (SCopySegment(szFontString, 1, FontParam, ',', C4MaxName)) sscanf(FontParam, "%i", &iDefFontSize); // font weight given? if (SCopySegment(szFontString, 2, FontParam, ',', C4MaxName)) sscanf(FontParam, "%i", &dwDefWeight); // check if it's already loaded from that group with that parameters if (!rFont.IsSameAs(FontFaceName, iDefFontSize, dwDefWeight)) { // it's not; so (re-)load it now! if (rFont.IsInitialized()) { // reloading rFont.Clear(); LogF(LoadResStr("IDS_PRC_UPDATEFONT"), FontFaceName, iDefFontSize, dwDefWeight); } // init with given font name try { // check if one of the internally listed fonts should be used C4VectorFont * pFont = pVectorFonts; while (pFont) { if (SEqual(pFont->Name.getData(), FontFaceName)) { if (InitFont(rFont, pFont, iDefFontSize, dwDefWeight, fDoShadow)) break; } pFont = pFont->pNext; } // no internal font matching? Then create one using the given face/filename (using a system font) if (!pFont) { pFont = new C4VectorFont(); if (pFont->Init(FontFaceName, iDefFontSize, dwDefWeight, Config.General.LanguageCharset)) { AddVectorFont(pFont); if (!InitFont(rFont, pFont, iDefFontSize, dwDefWeight, fDoShadow)) throw std::runtime_error(FormatString("Error initializing font %s", FontFaceName).getData()); } else { delete pFont; // no match for font face found throw std::runtime_error(FormatString("Font face %s undefined", FontFaceName).getData()); } } } catch (std::runtime_error & e) { LogFatal(e.what()); LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } rFont.id = 0; } } // done, success return true; }
BOOL C4Record::Start(bool fInitial) { // no double record if (fRecording) return FALSE; // create demos folder if (!Config.General.CreateSaveFolder(Config.General.SaveDemoFolder.getData(), LoadResStr("IDS_GAME_RECORDSTITLE"))) return FALSE; // various infos StdStrBuf sDemoFolder; sDemoFolder.Ref(Config.General.SaveDemoFolder); char sScenName[_MAX_FNAME + 1]; SCopy(GetFilenameOnly(Game.Parameters.Scenario.getFile()), sScenName, _MAX_FNAME); // remove trailing numbers from scenario name (e.g. from savegames) - could we // perhaps use C4S.Head.Origin instead...? char *pScenNameEnd = sScenName + SLen(sScenName); while (Inside<char>(*--pScenNameEnd, '0', '9')) if (pScenNameEnd == sScenName) break; pScenNameEnd[1] = 0; // determine index (by total number of records) Index = 1; for (DirectoryIterator i(Config.General.SaveDemoFolder.getData()); *i; ++i) if (WildcardMatch(C4CFN_ScenarioFiles, *i)) Index++; // compose record filename sFilename.Format("%s" DirSep "%03i-%s.c4s", sDemoFolder.getData(), Index, sScenName); // log StdStrBuf sLog; sLog.Format(LoadResStr("IDS_PRC_RECORDINGTO"), sFilename.getData()); if (Game.FrameCounter) sLog.AppendFormat(" (Frame %d)", Game.FrameCounter); Log(sLog.getData()); // save game - this also saves player info list C4GameSaveRecord saveRec(fInitial, Index, Game.Parameters.isLeague()); if (!saveRec.Save(sFilename.getData())) return FALSE; saveRec.Close(); // unpack group, if neccessary if (!DirectoryExists(sFilename.getData()) && !C4Group_UnpackDirectory(sFilename.getData())) return FALSE; // open control record file char szCtrlRecFilename[_MAX_PATH + 1 + _MAX_FNAME]; sprintf(szCtrlRecFilename, "%s" DirSep C4CFN_CtrlRec, sFilename.getData()); if (!CtrlRec.Create(szCtrlRecFilename)) return FALSE; // open record group if (!RecordGrp.Open(sFilename.getData())) return FALSE; // record go fStreaming = false; fRecording = true; iLastFrame = 0; return TRUE; }
bool C4MainMenu::ActivateSavegame(int32_t iPlayer) { // Check if saving is possible if (!Game.CanQuickSave()) return false; // Menu symbol/init char DirPath[_MAX_PATH+1]; char ScenName[_MAX_PATH+1]; *ScenName=0; InitRefSym(GfxR->fctMenu.GetPhase(0), LoadResStr("IDS_MENU_CPSAVEGAME"), iPlayer); SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); SetPermanent(true); // target file name mask // get folder & filename to store in // some magic is needed to ensure savegames are stored properly into their folders SCopy(GetFilename(Game.ScenarioFilename), DirPath); if (DirPath[strlen(DirPath) - 1] == '\\') DirPath[strlen(DirPath) - 1] = 0; RemoveExtension(DirPath); if (LooksLikeInteger(DirPath)) { // ScenTitle.ocf\%d.ocs-names (old-style savegames) // get owning folder if (Game.pParentGroup) { // owning folder determines filename SCopy(GetFilenameOnly(Game.pParentGroup->GetName()), ScenName); } else { // no owning folder known: too bad // make a vague guess based on the scenario title SCopy(GetFilenameOnly(Game.ScenarioFilename), ScenName); } } else { // DirPath is a valid filename for now... SCopy(DirPath, ScenName); // but remove trailing numbers to adjust new-style savegames char *pScenNameEnd = ScenName+SLen(ScenName); while (Inside<char>(*--pScenNameEnd, '0', '9')) if (pScenNameEnd == ScenName) { // should not happen: digit-only-filenames should have been caught earlier SCopy("dbg_error!", ScenName); pScenNameEnd = ScenName+SLen(ScenName)-1; } pScenNameEnd[1]=0; } // New Style 2007: // * scenarios are saved into ScenName.ocf/ScenName123.ocs to keep umlauts out of filenames // * language titles are stored in folders as title component StdStrBuf strFilename, strTitle; strFilename.Format("%s.ocf%c%s%%d.ocs", ScenName, DirectorySeparator, ScenName); strTitle = Game.ScenarioTitle; // Create menu items StdStrBuf strFilenameIndexed, strCommand, strCaption, strSavePath; for (int32_t i = 1; i <= 10; i++) { // Index filename strFilenameIndexed.Format(strFilename.getData(), i); // Compose commmand strCommand.Format("Save:Game:%s:%s", strFilenameIndexed.getData(), strTitle.getData()); // Notice: the language title might contain ':' and thus confuse the segment list - but C4Menu::MenuCommand will try to handle this... // Check free slot strSavePath.Format("%s%c%s", Config.AtUserDataPath(C4CFN_Savegames), DirectorySeparator, strFilenameIndexed.getData()); bool fFree = !C4Group_IsGroup(strSavePath.getData()); // Item caption strCaption = LoadResStr("IDS_MENU_CPSAVEGAME"); // add menu item AddRefSym(strCaption.getData(), GfxR->fctMenu.GetPhase(i - 1, fFree ? 2 : 1), strCommand.getData(), C4MN_Item_NoCount, NULL, LoadResStr("IDS_MENU_CPSAVEGAMEINFO")); } // Go back to options menu on close SetCloseCommand("ActivateMenu:Main"); return true; }