Example #1
0
BOOL C4ComponentHost::Load(const char *szName, C4Group &hGroup,
                           const char *szFilename, const char *szLanguage) {
  // Clear any old stuff
  Clear();
  // Store name & filename
  SCopy(szName, Name);
  SCopy(szFilename, Filename);
  // Load component - try all segmented filenames
  char strEntry[_MAX_FNAME + 1], strEntryWithLanguage[_MAX_FNAME + 1];
  for (int iFilename = 0;
       SCopySegment(Filename, iFilename, strEntry, '|', _MAX_FNAME);
       iFilename++) {
    // Try to insert all language codes provided into the filename
    char strCode[3] = "";
    for (int iLang = 0;
         SCopySegment(szLanguage ? szLanguage : "", iLang, strCode, ',', 2);
         iLang++) {
      // Insert language code
      sprintf(strEntryWithLanguage, strEntry, strCode);
      if (hGroup.LoadEntryString(strEntryWithLanguage, Data)) {
        if (pConfig->General.fUTF8) Data.EnsureUnicode();
        // Store actual filename
        hGroup.FindEntry(strEntryWithLanguage, Filename);
        CopyFilePathFromGroup(hGroup);
        // Got it
        return TRUE;
      }
      // Couldn't insert language code anyway - no point in trying other
      // languages
      if (!SSearch(strEntry, "%s")) break;
    }
  }
  // Truncate any additional segments from stored filename
  SReplaceChar(Filename, '|', 0);
  CopyFilePathFromGroup(hGroup);
  // Not loaded
  return FALSE;
}
Example #2
0
C4ScenarioSection::C4ScenarioSection(char *szName) {
  // copy name
  if (szName && !SEqualNoCase(szName, C4ScenSect_Main) && *szName) {
    this->szName = new char[strlen(szName) + 1];
    SCopy(szName, this->szName);
  } else
    this->szName = const_cast<char *>(C4ScenSect_Main);
  // zero fields
  szTempFilename = szFilename = 0;
  fModified = false;
  // link into main list
  pNext = Game.pScenarioSections;
  Game.pScenarioSections = this;
}
C4DefGraphicsPtrBackupEntry::C4DefGraphicsPtrBackupEntry(C4DefGraphics *pSourceGraphics):
	pMeshUpdate(NULL)
{
	// assign graphics + def
	pGraphicsPtr = pSourceGraphics;
	pDef = pSourceGraphics->pDef;
	// assign name
	const char *szName = pGraphicsPtr->GetName();
	if (szName) SCopy(szName, Name, C4MaxName); else *Name=0;

	// assign mesh update
	if(pSourceGraphics->Type == C4DefGraphics::TYPE_Mesh)
		pMeshUpdate = new StdMeshUpdate(*pSourceGraphics->Mesh);
}
void C4GraphicsOverlay::Set(Mode aMode, C4DefGraphics *pGfx, const char *szAction, DWORD dwBMode, C4Object *pOvrlObj)
{
	// set values
	eMode = aMode;
	pSourceGfx = pGfx;
	if (szAction) SCopy(szAction, Action, C4MaxName); else *Action=0;
	dwBlitMode = dwBMode;
	OverlayObj = pOvrlObj;
	// (keep transform)
	// reset phase
	iPhase = 0;
	// update used facet
	UpdateFacet();
}
Example #5
0
void C4Region::Set(int iX, int iY, int iWdt, int iHgt, const char *szCaption,
                   int iCom, int iMoveOverCom, int iHoldCom, int iData,
                   C4Object *pTarget) {
  X = iX;
  Y = iY;
  Wdt = iWdt;
  Hgt = iHgt;
  SCopy(szCaption, Caption, C4RGN_MaxCaption);
  Com = iCom;
  MoveOverCom = iMoveOverCom;
  HoldCom = iHoldCom;
  Data = iData;
  Target = pTarget;
}
Example #6
0
BOOL C4SoundEffect::Load(const char *szFileName, C4Group &hGroup,
                         BOOL fStatic) {
  // Sound check
  if (!Config.Sound.RXSound) return FALSE;
  // Locate sound in file
  StdBuf WaveBuffer;
  if (!hGroup.LoadEntry(szFileName, WaveBuffer)) return FALSE;
  // load it from mem
  if (!Load((BYTE *)WaveBuffer.getData(), WaveBuffer.getSize(), fStatic))
    return FALSE;
  // Set name
  SCopy(szFileName, Name, C4MaxSoundName);
  return TRUE;
}
Example #7
0
C4Group *C4GroupSet::FindSuitableFile(const char *szName, const char * const extensions[], char *szFileName, int32_t *pID)
{
	C4Group *pGrp = nullptr;
	C4Group *pGrp2;
	int iPrio = -1;
	int32_t iPrio2;
	int32_t GroupID;
	char FileName[_MAX_FNAME];
	SCopy(szName, FileName);
	for (int i = 0; extensions[i]; ++i)
	{
		EnforceExtension(FileName, extensions[i]);
		pGrp2=FindEntry(FileName, &iPrio2, &GroupID);
		if ((!pGrp || iPrio2 >= iPrio) && pGrp2)
		{
			if (pID) *pID = GroupID;
			pGrp = pGrp2;
			SCopy(FileName, szFileName);
		}
	}
	// return found group, if any
	return pGrp;
}
Example #8
0
void C4SDefinitions::SetModules(const char *szList, const char *szRelativeToPath, const char *szRelativeToPath2)
{
	int32_t cnt;

	// Empty list: local only
	if (!SModuleCount(szList))
	{
		LocalOnly=true;
		for (cnt=0; cnt<C4S_MaxDefinitions; cnt++) Definition[cnt][0]=0;
		return;
	}

	// Set list
	LocalOnly=false;
	for (cnt=0; cnt<C4S_MaxDefinitions; cnt++)
	{
		SGetModule(szList,cnt,Definition[cnt],_MAX_PATH);
		// Make relative path
		if (szRelativeToPath && *szRelativeToPath)
		{
			if (GetRelativePathS(Definition[cnt],szRelativeToPath) != Definition[cnt])
			{
				SCopy(GetRelativePathS(Definition[cnt],szRelativeToPath),Definition[cnt]);
				continue;
			}
		}
		if (szRelativeToPath2 && *szRelativeToPath2)
		{
			if (GetRelativePathS(Definition[cnt],szRelativeToPath2) != Definition[cnt])
			{
				SCopy(GetRelativePathS(Definition[cnt],szRelativeToPath2),Definition[cnt]);
				continue;
			}
		}
	}

}
Example #9
0
void C4GraphicsOverlay::Write(char *szOutput)
{
	// deprecated
	assert(false && "C4GraphicsOverlay::Write: deprecated");
#if 0
	// safety: Don't save invalid
	if (!pSourceGfx) return;
	C4Def *pDef = pSourceGfx->pDef;
	assert(pDef);
	// get to end of buffer
	szOutput += strlen(szOutput);
	// store ID
	sprintf(OSTR, "%i", iID); SCopy(OSTR, szOutput); szOutput += strlen(szOutput);
	*szOutput = ','; ++szOutput;
	// append C4ID::Graphicsname (or C4ID:: for def graphics)
	SCopy(pDef->id.ToString(), szOutput); szOutput += strlen(szOutput);
	SCopy("::", szOutput); szOutput += strlen(szOutput);
	const char *szGrpName = pSourceGfx->GetName();
	if (szGrpName) { SCopy(szGrpName, szOutput); szOutput += strlen(szOutput); }
	*szOutput = ','; ++szOutput;
	// store mode
	DWORD dwMode = eMode;
	sprintf(OSTR, "%i", dwMode); SCopy(OSTR, szOutput); szOutput += strlen(OSTR);
	// store action
	*szOutput = ','; ++szOutput;
	SCopy(Action, szOutput); szOutput += strlen(szOutput);
	// store blit mode
	*szOutput = ','; ++szOutput;
	sprintf(OSTR, "%i", dwBlitMode); SCopy(OSTR, szOutput); szOutput += strlen(szOutput);
	// store phase
	*szOutput = ','; ++szOutput;
	sprintf(OSTR, "%i", iPhase); SCopy(OSTR, szOutput); szOutput += strlen(szOutput);
	// store transform
	*szOutput = ','; ++szOutput;
	sprintf(OSTR, "(%f,%f,%f,%f,%f,%f,%d)",
	        Transform.mat[0], Transform.mat[1], Transform.mat[2],
	        Transform.mat[3], Transform.mat[4], Transform.mat[5], Transform.FlipDir);
	SCopy(OSTR, szOutput); szOutput += strlen(szOutput);
	// terminate string
	*szOutput=0;
#endif
}
Example #10
0
C4SoundInstance *C4SoundSystem::FindInstance(const char *szSndName,
                                             C4Object *pObj) {
  char szName[C4MaxSoundName + 4 + 1];
  // Evaluate sound name (see GetEffect)
  SCopy(szSndName, szName, C4MaxSoundName);
  DefaultExtension(szName, "wav");
  SReplaceChar(szName, '*', '?');
  // Find an effect with a matching instance
  for (C4SoundEffect *csfx = FirstSound; csfx; csfx = csfx->Next)
    if (WildcardMatch(szName, csfx->Name)) {
      C4SoundInstance *pInst = csfx->GetInstance(pObj);
      if (pInst) return pInst;
    }
  return NULL;
}
Example #11
0
void C4SHead::Default()
{
	Origin.Clear();
	Icon=18;
	*Title = *Loader = *Font = *Engine = *MissionAccess = '\0';
	Secret = false;
	C4XVer[0] = C4XVer[1] = 0;
	Difficulty = RandomSeed = 0;
	SaveGame = Replay = NoInitialize = false;
	Film = 0;
	NetworkGame = NetworkRuntimeJoin = false;

	MaxPlayer=MaxPlayerLeague=C4S_MaxPlayerDefault;
	MinPlayer=0; // auto-determine by mode
	SCopy("Default Title",Title,C4MaxTitle);
}
Example #12
0
void C4GameOptionButtons::OnPasswordSet(const StdStrBuf &rsNewPassword)
{
	// password input dialog answered with OK: Set/clear network password
	const char *szPass;
	::Network.SetPassword(szPass=rsNewPassword.getData());
	// update icon to reflect if a password is set
	UpdatePasswordBtn();
	// remember password for next round
	bool fHasPassword = (szPass && *szPass);
	if (fHasPassword)
	{
		SCopy(szPass, Config.Network.LastPassword, CFG_MaxString);
	}
	// acoustic feedback
	C4GUI::GUISound("UI::Confirmed");
}
Example #13
0
bool EraseItemSafe(const char *szFilename)
{
	char Filename[_MAX_PATH+1];
	SCopy(szFilename, Filename, _MAX_PATH);
	Filename[SLen(Filename)+1]=0;
	SHFILEOPSTRUCTW shs;
	shs.hwnd=0;
	shs.wFunc=FO_DELETE;
	shs.pFrom=GetWideChar(Filename);
	shs.pTo=NULL;
	shs.fFlags=FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT;
	shs.fAnyOperationsAborted=false;
	shs.hNameMappings=0;
	shs.lpszProgressTitle=NULL;
	return !SHFileOperationW(&shs);
}
bool C4Network2ResList::CreateNetworkFolder()
{
	// get network path without trailing backslash
	char szNetworkPath[_MAX_PATH+1];
	SCopy(Config.AtNetworkPath(""), szNetworkPath, _MAX_PATH);
	TruncateBackslash(szNetworkPath);
	// but make sure that the configured path has one
	AppendBackslash(Config.Network.WorkPath);
	// does not exist?
	if (!DirectoryExists(szNetworkPath))
	{
		if (!CreatePath(szNetworkPath))
			{ LogFatal("Network: could not create network path!"); return false; }
		return true;
	}
	return true;
}
bool C4Network2Res::CalculateSHA()
{
	// already present?
	if (Core.hasFileSHA()) return true;
	// get the file
	char szStandalone[_MAX_PATH + 1];
	if (!GetStandalone(szStandalone, _MAX_PATH, false))
		SCopy(szFile, szStandalone, _MAX_PATH);
	// get the hash
	BYTE hash[SHA_DIGEST_LENGTH];
	if (!GetFileSHA1(szStandalone, hash))
		return false;
	// save it back
	Core.SetFileSHA(hash);
	// okay
	return true;
}
QLineEdit *C4ConsoleQtLocalizeStringDlg::AddEditor(const char *language, const char *language_name)
{
	assert(!GetEditorByLanguage(language));
	// Add editor widgets
	int32_t row = edited_languages.size();
	QString language_label_text(language);
	if (language_name) language_label_text.append(FormatString(" (%s)", language_name).getData());
	QLabel *language_label = new QLabel(language_label_text, this);
	ui.mainGrid->addWidget(language_label, row, 0);
	QLineEdit *value_editor = new QLineEdit(this);
	ui.mainGrid->addWidget(value_editor, row, 1);
	// Add to list
	EditedLanguage new_editor;
	SCopy(language, new_editor.language, 2);
	new_editor.value_editor = value_editor;
	edited_languages.push_back(new_editor);
	return value_editor;
}
void C4GraphicsSystem::FlashMessage(const char *szMessage)
	{
	// Store message
	SCopy(szMessage, FlashMessageText, C4MaxTitle);
	// Calculate message time
	FlashMessageTime = SLen(FlashMessageText) * 2;
	// Initial position
	FlashMessageX = -1; 
	FlashMessageY = 10;
	// Upper board active: stay below upper board
	if (Config.Graphics.UpperBoard)
		FlashMessageY += C4UpperBoardHeight;
	// More than one viewport: try to stay below portraits etc.
	if (GetViewportCount() > 1)
		FlashMessageY += 64;
	// New flash message: redraw background (might be drawing one message on top of another)
	InvalidateBg();
	}
Example #18
0
int C4LoaderScreen::SeekLoaderScreens(C4Group &rFromGrp, const char *szWildcard, int iLoaderCount, char *szDstName, C4Group **ppDestGrp)
	{
	BOOL fFound;
	int iLocalLoaders=0;
	char Filename[_MAX_PATH+1];
	for (fFound=rFromGrp.FindEntry(szWildcard, Filename); fFound; fFound=rFromGrp.FindNextEntry(szWildcard, Filename))
		{
		// loader found; choose it, if Daniel wants it that way
		++iLocalLoaders;
		if (!SafeRandom(++iLoaderCount))
			{
			// copy group and path
			*ppDestGrp=&rFromGrp;
			SCopy(Filename, szDstName, _MAX_PATH);
			}
		}
	return iLocalLoaders;
	}
Example #19
0
bool C4ScenarioSection::EnsureTempStore(bool fExtractLandscape,
                                        bool fExtractObjects) {
  // if it's temp store already, don't do anything
  if (szTempFilename) return true;
  // make temp filename
  char *szTmp = const_cast<char *>(
      Config.AtTempPath(szFilename ? GetFilename(szFilename) : szName));
  MakeTempFilename(szTmp);
  // main section: extract section files from main scenario group (create group
  // as open dir)
  if (!szFilename) {
    if (!CreateDirectory(szTmp, NULL)) return false;
    C4Group hGroup;
    if (!hGroup.Open(szTmp, TRUE)) {
      EraseItem(szTmp);
      return false;
    }
    // extract all desired section files
    Game.ScenarioFile.ResetSearch();
    char fn[_MAX_FNAME + 1];
    *fn = 0;
    while (Game.ScenarioFile.FindNextEntry(C4FLS_Section, fn))
      if (fExtractLandscape || !WildcardMatch(C4FLS_SectionLandscape, fn))
        if (fExtractObjects || !WildcardMatch(C4FLS_SectionObjects, fn))
          Game.ScenarioFile.ExtractEntry(fn, szTmp);
    hGroup.Close();
  } else {
    // subsection: simply extract section from main group
    if (!Game.ScenarioFile.ExtractEntry(szFilename, szTmp)) return false;
    // delete undesired landscape/object files
    if (!fExtractLandscape || !fExtractObjects) {
      C4Group hGroup;
      if (hGroup.Open(szFilename)) {
        if (!fExtractLandscape) hGroup.Delete(C4FLS_SectionLandscape);
        if (!fExtractObjects) hGroup.Delete(C4FLS_SectionObjects);
      }
    }
  }
  // copy temp filename
  szTempFilename = new char[strlen(szTmp) + 1];
  SCopy(szTmp, szTempFilename, _MAX_PATH);
  // done, success
  return true;
}
Example #20
0
bool C4MainMenu::ActivateNewPlayer(int32_t iPlayer)
{
	// league or replay game
	if (Game.Parameters.isLeague() || Game.C4S.Head.Replay) return false;
	// Max player limit
	if (::Players.GetCount() >= Game.Parameters.MaxPlayers) return false;

	// Menu symbol/init
	if (GfxR->fctPlayerClr.Surface)
		GfxR->fctPlayerClr.Surface->SetClr(0xff);
	InitRefSym(GfxR->fctPlayerClr, LoadResStr("IDS_MENU_NOPLRFILES"), iPlayer);
	for (DirectoryIterator iter(Config.General.UserDataPath); *iter; ++iter)
		if (WildcardMatch("*.ocp", *iter))
		{
			char szFilename[_MAX_PATH+1], szCommand[_MAX_PATH+30+1];
			SCopy(*iter, szFilename, _MAX_PATH);
			if (DirectoryExists(szFilename)) continue;
			if (::Players.FileInUse(szFilename)) continue;
			// Open group
			C4Group hGroup;
			if (!hGroup.Open(szFilename)) continue;
			// Load player info
			C4PlayerInfoCore C4P;
			if (!C4P.Load(hGroup)) { hGroup.Close(); continue; }
			// Close group
			hGroup.Close();
			// Add player item
			sprintf(szCommand, "JoinPlayer:%s", szFilename);
			StdStrBuf sItemText;
			sItemText.Format(LoadResStr("IDS_MENU_NEWPLAYER"), C4P.PrefName);
			C4FacetSurface fctSymbol;
			// Add menu item
			Add(sItemText.getData(), fctSymbol, szCommand);
			// Reset symbol facet (menu holds on to the surface)
			fctSymbol.Default();
		}

	// Alignment
	SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom);
	// Go back to options menu on close
	SetCloseCommand("ActivateMenu:Main");

	return true;
}
Example #21
0
void C4ValueMapNames::ChangeNameList(const char **pnNames, int32_t *pnExtra, int32_t nSize)
{
	// safe old name list
	char **pOldNames = pNames;
	int32_t *pOldExtra = pExtra;
	int32_t iOldSize = iSize;
	

	// create new lists
	pNames = new char *[nSize];
	pExtra = new int32_t [nSize];

	// copy names
	int32_t i;
	for(i = 0; i < nSize; i++)
	{
		pNames[i] = new char [SLen(pnNames[i]) + 1];
		SCopy(pnNames[i], pNames[i], SLen(pnNames[i]) + 1);
		if(pnExtra) pExtra[i] = pnExtra[i];
	}

	if(!pnExtra)
		ZeroMem(pExtra, sizeof (*pExtra) * nSize);

	// set new size 
	iSize = nSize;

	// call OnNameListChanged list for all "child" lists
	C4ValueMapData *pAktData = pFirst;
	while(pAktData)
	{
		pAktData->OnNameListChanged(const_cast<const char **>(pOldNames), iOldSize);
		pAktData = pAktData->pNext;
	}

	// delete old list
	for(i = 0; i < iOldSize; i++)
		delete[] pOldNames[i];
	delete[] pOldNames;
	delete[] pOldExtra;

	// ok.
}
bool C4PlayerList::FileInUse(const char *szFilename) const
{
	// Check original player files
	C4Player *cPlr=First;
	for (; cPlr; cPlr=cPlr->Next)
		if (ItemIdentical(cPlr->Filename,szFilename))
			return true;
	// Compare to any network path player files with prefix (hack)
	if (::Network.isEnabled())
	{
		char szWithPrefix[_MAX_PATH+1];
		SCopy(GetFilename(szFilename),szWithPrefix);
		SetClientPrefix(szWithPrefix, Game.Clients.getLocalName());
		for (cPlr=First; cPlr; cPlr=cPlr->Next)
			if (SEqualNoCase(GetFilename(cPlr->Filename),szWithPrefix))
				return true;
	}
	// Not in use
	return false;
}
Example #23
0
C4Application::~C4Application() {
  // clear gamepad
  if (pGamePadControl) delete pGamePadControl;
  // Close log
  CloseLog();
  // Launch editor
  if (launchEditor) {
#ifdef _WIN32
    char strCommandLine[_MAX_PATH + 1];
    SCopy(Config.AtExePath(C4CFN_Editor), strCommandLine);
    STARTUPINFO StartupInfo;
    ZeroMemory(&StartupInfo, sizeof StartupInfo);
    StartupInfo.cb = sizeof StartupInfo;
    PROCESS_INFORMATION ProcessInfo;
    ZeroMemory(&ProcessInfo, sizeof ProcessInfo);
    CreateProcess(NULL, strCommandLine, NULL, NULL, TRUE, 0, NULL, NULL,
                  &StartupInfo, &ProcessInfo);
#endif
  }
}
bool C4Network2Res::SetDerived(const char *strName, const char *strFilePath, bool fTemp, C4Network2ResType eType, int32_t iDResID)
{
	Clear();
	CStdLock FileLock(&FileCSec);
	// set core
	Core.Set(eType, C4NetResIDAnonymous, strName, ~0);
	Core.SetDerived(iDResID);
	// save file path
	SCopy(strFilePath, szFile, _MAX_PATH);
	*szStandalone = '\0';
	// set flags
	fDirty = false;
	fTempFile = fTemp;
	fStandaloneFailed = false;
	fRemoved = false;
	iLastReqTime = time(NULL);
	fLoading = false;
	// Do not set any chunk data - anonymous resources are very likely to change.
	// Wait for FinishDerived()-call.
	return true;
}
bool C4NameList::Set(const char *szName, int32_t iCount)
{
	int32_t cnt;
	// Find existing name, set count
	for (cnt=0; cnt<C4MaxNameList; cnt++)
		if (SEqual(Name[cnt],szName))
		{
			Count[cnt]=iCount;
			return true;
		}
	// Find empty spot, set name and count
	for (cnt=0; cnt<C4MaxNameList; cnt++)
		if (Name[cnt][0]==0)
		{
			SCopy(szName,Name[cnt],C4MaxName);
			Count[cnt]=iCount;
			return true;
		}
	// No empty spots
	return false;
}
Example #26
0
bool C4Menu::InitMenu(const char *szEmpty, int32_t iExtra, int32_t iExtraData, int32_t iId, int32_t iStyle)
{
	SCopy(szEmpty,Caption,C4MaxTitle);
	Extra=iExtra; ExtraData=iExtraData;
	Identification=iId;
	if (*Caption || iStyle == C4MN_Style_Dialog) SetTitle(Caption, HasMouse()); else SetTitle(" ", HasMouse());
	if (pTitle) pTitle->SetIcon(Symbol);
	Style=iStyle & C4MN_Style_BaseMask;
	// Menus are synchronous to allow COM_MenuUp/Down to be converted to movements at the clients
	if (Style == C4MN_Style_Normal)
		Columns = 5;
	else
		// in reality, Dialog menus may have two coloumns (first for the portrait)
		// however, they are not uniformly spaced and stuff; so they are better just ignored and handled by the drawing routine
		Columns=1;
	if (iStyle & C4MN_Style_EqualItemHeight) SetEqualItemHeight(true);
	if (Style == C4MN_Style_Dialog) Alignment = C4MN_Align_Top;
	::pGUI->ShowDialog(this, false);
	fTextProgressing = false;
	fActive = true;
	return true;
}
Example #27
0
bool C4StartupNetDlg::DoOK()
{
	// OK in chat mode? Forward to chat control
	if (GetDlgMode() == SNDM_Chat) return pChatCtrl->DlgEnter();
	// OK on editbox with text enetered: Add the specified IP for reference retrieval
	if (GetFocus() == pJoinAddressEdt)
	{
		const char *szDirectJoinAddress = pJoinAddressEdt->GetText();
		if (szDirectJoinAddress && *szDirectJoinAddress)
		{
			// First do some acrobatics to avoid trying to resolve addresses with leading
			// or trailing whitespace, which is easily pasted in with an IP address.
			// We can trivially skip whitespace at the beginning, but we need a copy to
			// omit whitespace at the end.
			while (std::isspace(*szDirectJoinAddress))
				// skip whitespace at the beginning
				++szDirectJoinAddress;
			if (!*szDirectJoinAddress)
				// entry empty, apart from whitespace
				return true;
			const char *szDirectJoinAddressEnd = szDirectJoinAddress + std::strlen(szDirectJoinAddress) - 1;
			while (std::isspace(*szDirectJoinAddressEnd))
				// skip whitespace at the end
				--szDirectJoinAddressEnd;
			if (*++szDirectJoinAddressEnd)
			{
				// Make a temporary copy of the part that is not trailing whitespace, if any
				std::string strDirectJoinAddressStripped(szDirectJoinAddress, szDirectJoinAddressEnd - szDirectJoinAddress);
				AddReferenceQuery(strDirectJoinAddressStripped.c_str(), C4StartupNetListEntry::NRQT_DirectJoin);
			}
			else
				AddReferenceQuery(szDirectJoinAddress, C4StartupNetListEntry::NRQT_DirectJoin);
			// Switch focus to list so another OK joins the specified address
			SetFocus(pGameSelList, true);
			return true;
		}
	}
	if (GetFocus() == pSearchFieldEdt)
	{
		UpdateList();
		return true;
	}
	// get currently selected item
	C4GUI::Element *pSelection = pGameSelList->GetSelectedItem();
	StdCopyStrBuf strNoJoin(LoadResStr("IDS_NET_NOJOIN"));
	if (!pSelection)
	{
		// no ref selected: Oh noes!
		::pGUI->ShowMessageModal(
		  LoadResStr("IDS_NET_NOJOIN_NOREF"),
		  strNoJoin.getData(),
		  C4GUI::MessageDialog::btnOK,
		  C4GUI::Ico_Error);
		return true;
	}
	C4StartupNetListEntry *pRefEntry = static_cast<C4StartupNetListEntry *>(pSelection);
	const char *szError;
	if ((szError = pRefEntry->GetError()))
	{
		// erroneous ref selected: Oh noes!
		::pGUI->ShowMessageModal(
		  FormatString(LoadResStr("IDS_NET_NOJOIN_BADREF"), szError).getData(),
		  strNoJoin.getData(),
		  C4GUI::MessageDialog::btnOK,
		  C4GUI::Ico_Error);
		return true;
	}
	C4Network2Reference *pRef = pRefEntry->GetReference();
	const char *szDirectJoinAddress = pRefEntry->GetJoinAddress();
	if (!pRef && !(szDirectJoinAddress && *szDirectJoinAddress))
	{
		// something strange has been selected (e.g., a masterserver entry). Error.
		::pGUI->ShowMessageModal(
		  LoadResStr("IDS_NET_NOJOIN_NOREF"),
		  strNoJoin.getData(),
		  C4GUI::MessageDialog::btnOK,
		  C4GUI::Ico_Error);
		return true;
	}
	// check if join to this reference is possible at all
	if (pRef)
	{
		// version mismatch
		C4GameVersion verThis;
		if (!(pRef->getGameVersion() == verThis))
		{
			::pGUI->ShowMessageModal(
			  FormatString(LoadResStr("IDS_NET_NOJOIN_BADVER"),
			               pRef->getGameVersion().GetString().getData(),
			               verThis.GetString().getData()).getData(),
			  strNoJoin.getData(),
			  C4GUI::MessageDialog::btnOK,
			  C4GUI::Ico_Error);
			return true;
		}
		if (pRef->getGameStatus().isPastLobby())
		{
			// no runtime join
			if (!pRef->isJoinAllowed())
			{
				if (!::pGUI->ShowMessageModal(
					  LoadResStr("IDS_NET_NOJOIN_NORUNTIME"),
					  strNoJoin.getData(),
					  C4GUI::MessageDialog::btnYes | C4GUI::MessageDialog::btnNo,
					  C4GUI::Ico_Error))
				{
					return true;
				}
			}
			else
			{
				if (!::pGUI->ShowMessageModal(
					  LoadResStr("IDS_NET_NOJOIN_RUNTIMEBROKEN"),
					  strNoJoin.getData(),
					  C4GUI::MessageDialog::btnYes | C4GUI::MessageDialog::btnNo,
					  C4GUI::Ico_Error))
				{
					return true;
				}
			}
		}
	}
	// OK; joining!
	if (pRef->isEditor())
	{
		bool success = false;
		// Editor mode join: Serialize reference to temp file and join on that
		// (could pass through environment, but that's hard to do platform-independent
		// (QProcessEnvironment? But then there's a Qt dependency in the network init code))
		StdStrBuf tmpfn(Config.AtTempPath("ocjoin"), true);
		MakeTempFilename(&tmpfn);
		StdStrBuf join_data = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(*pRef, "Reference"));
		if (join_data.getSize())
		{
			if (join_data.SaveToFile(tmpfn.getData()))
			{
				if (RestartApplication({"--editor", FormatString("--join=%s%s", C4Game::DirectJoinFilePrefix, tmpfn.getData()).getData()})) // hope for no " in temp path
				{
					// Application.Quit() has been called. Will quit after returning from this callback.
					// The temp file will be deleted by the new instance
					success = true;
				}
				else
				{
					EraseFile(tmpfn.getData());
				}
			}
		}
		if (!success)
		{
			C4GUI::TheScreen.ShowErrorMessage(LoadResStr("IDS_ERR_STARTEDITOR"));
		}
		return true;
	}
	else
	{
		// Player mode join
		// Take over reference
		pRefEntry->GrabReference();
		// Set join parameters
		*Game.ScenarioFilename = '\0';
		if (szDirectJoinAddress) SCopy(szDirectJoinAddress, Game.DirectJoinAddress, _MAX_PATH); else *Game.DirectJoinAddress = '\0';
		SCopy("Objects.ocd", Game.DefinitionFilenames);
		Game.NetworkActive = true;
		Game.fObserve = false;
		Game.pJoinReference.reset(pRef);
		// start with this set!
		Application.OpenGame();
		return true;
	}
}
C4AdditionalDefGraphics::C4AdditionalDefGraphics(C4Def *pOwnDef, const char *szName) : C4DefGraphics(pOwnDef)
{
	// store name
	SCopy(szName, Name, C4MaxName);
}
bool C4DefGraphics::Load(C4Group &hGroup, StdMeshSkeletonLoader &loader, bool fColorByOwner)
{
	char Filename[_MAX_PATH+1]; *Filename=0;

	// load skeletons
	hGroup.ResetSearch();
	while (hGroup.FindNextEntry("*", Filename, NULL, !!*Filename))
	{
		if (!WildcardMatch(C4CFN_DefSkeleton, Filename) && !WildcardMatch(C4CFN_DefSkeletonXml, Filename)) continue;
		LoadSkeleton(hGroup, Filename, loader);
	}

	// Try from Mesh first
	if (!LoadMesh(hGroup, C4CFN_DefMesh, loader))
		if(!LoadMesh(hGroup, C4CFN_DefMeshXml, loader))
			LoadBitmap(hGroup, C4CFN_DefGraphics, C4CFN_ClrByOwner, C4CFN_NormalMap, fColorByOwner);

	// load additional graphics
	C4DefGraphics *pLastGraphics = this;
	const int32_t iOverlayWildcardPos = SCharPos('*', C4CFN_ClrByOwnerEx);
	hGroup.ResetSearch(); *Filename=0;
	const char* const AdditionalGraphics[] = { C4CFN_DefGraphicsEx, C4CFN_DefGraphicsExMesh, C4CFN_DefGraphicsExMeshXml, NULL };
	while (hGroup.FindNextEntry("*", Filename, NULL, !!*Filename))
	{
		for(const char* const* szWildcard = AdditionalGraphics; *szWildcard != NULL; ++szWildcard)
		{
			if(!WildcardMatch(*szWildcard, Filename)) continue;
			// skip def graphics
			if (SEqualNoCase(Filename, C4CFN_DefGraphics) || SEqualNoCase(Filename, C4CFN_DefMesh) || SEqualNoCase(Filename, C4CFN_DefMeshXml)) continue;
			// skip scaled def graphics
			if (WildcardMatch(C4CFN_DefGraphicsScaled, Filename)) continue;
			// get name
			char GrpName[_MAX_PATH+1];
			const int32_t iWildcardPos = SCharPos('*', *szWildcard);
			SCopy(Filename + iWildcardPos, GrpName, _MAX_PATH);
			RemoveExtension(GrpName);
			// remove trailing number for scaled graphics
			int32_t extpos; int scale;
			if ((extpos = SCharLastPos('.', GrpName)) > -1)
				if (sscanf(GrpName+extpos+1, "%d", &scale) == 1)
					GrpName[extpos] = '\0';
			// clip to max length
			GrpName[C4MaxName]=0;
			// create new graphics
			pLastGraphics->pNext = new C4AdditionalDefGraphics(pDef, GrpName);
			pLastGraphics = pLastGraphics->pNext;
			if(*szWildcard == AdditionalGraphics[0])
			{
				// create overlay-filename
				char OverlayFn[_MAX_PATH+1];
				if(fColorByOwner)
				{
					// GraphicsX.png -> OverlayX.png
					SCopy(C4CFN_ClrByOwnerEx, OverlayFn, _MAX_PATH);
					OverlayFn[iOverlayWildcardPos]=0;
					SAppend(Filename + iWildcardPos, OverlayFn);
					EnforceExtension(OverlayFn, GetExtension(C4CFN_ClrByOwnerEx));
				}

				// create normal filename
				char NormalFn[_MAX_PATH+1];
				SCopy(C4CFN_NormalMapEx, NormalFn, _MAX_PATH);
				NormalFn[iOverlayWildcardPos]=0;
				SAppend(Filename + iWildcardPos, NormalFn);
				EnforceExtension(NormalFn, GetExtension(C4CFN_NormalMapEx));

				// load them
				if (!pLastGraphics->LoadBitmap(hGroup, Filename, fColorByOwner ? OverlayFn : NULL, NormalFn, fColorByOwner))
					return false;
			}
			else
			{
				if (!pLastGraphics->LoadMesh(hGroup, Filename, loader))
					return false;
			}
		}
	}
	// done, success
	return true;
}
void C4Application::ParseCommandLine(int argc, char * argv[])
{

	StdStrBuf CmdLine("Command line:");
	for(int i = 0; i < argc; ++i) {
		CmdLine.Append(" ");
		CmdLine.Append(argv[i]);
	}
	Log(CmdLine.getData());

	ClearCommandLine();
	Game.NetworkActive = false;
	isEditor = 2;
	int c;
	while (1)
	{

		static struct option long_options[] =
		{
			// option, w/ argument?, set directly, set to...
			{"editor", no_argument, &isEditor, 1},
			{"fullscreen", no_argument, &isEditor, 0},
			{"debugwait", no_argument, &Game.DebugWait, 1},
			{"update", no_argument, &CheckForUpdates, 1},
			{"noruntimejoin", no_argument, &Config.Network.NoRuntimeJoin, 1},
			{"runtimejoin", no_argument, &Config.Network.NoRuntimeJoin, 0},
			{"noleague", no_argument, &Config.Network.LeagueServerSignUp, 0},
			{"league", no_argument, &Config.Network.LeagueServerSignUp, 1},
			{"nosignup", no_argument, &Config.Network.MasterServerSignUp, 0},
			{"signup", no_argument, &Config.Network.MasterServerSignUp, 1},
			
			{"debugrecread", required_argument, 0, 'K'},
			{"debugrecwrite", required_argument, 0, 'w'},

			{"client", required_argument, 0, 'c'},
			{"host", no_argument, 0, 'h'},
			{"debughost", required_argument, 0, 'H'},
			{"debugpass", required_argument, 0, 'P'},
			{"debug", required_argument, 0, 'D'},
			{"data", required_argument, 0, 'd'},
			{"startup", required_argument, 0, 's'},
			{"stream", required_argument, 0, 'e'},
			{"recdump", required_argument, 0, 'R'},
			{"comment", required_argument, 0, 'm'},
			{"pass", required_argument, 0, 'p'},
			{"udpport", required_argument, 0, 'u'},
			{"tcpport", required_argument, 0, 't'},
			{"join", required_argument, 0, 'j'},
			{"language", required_argument, 0, 'L'},
			{"scenpar", required_argument, 0, 'S'},

			{"observe", no_argument, 0, 'o'},
			{"nonetwork", no_argument, 0, 'N'},
			{"network", no_argument, 0, 'n'},
			{"record", no_argument, 0, 'r'},

			{"lobby", required_argument, 0, 'l'},

			{"debug-opengl", no_argument, &Config.Graphics.DebugOpenGL, 1},
			{0, 0, 0, 0}
		};
		int option_index = 0;
		c = getopt_long (argc, argv, "abc:d:f:",
			long_options, &option_index);
     		// no more options
		if (c == -1)
			break;
		switch (c)
		{
		case 0:
			// Signup
			if (SEqualNoCase(long_options[option_index].name, "signup"))
			{
				Game.NetworkActive = true;
			}
			// League
			if (SEqualNoCase(long_options[option_index].name, "league"))
			{
				Game.NetworkActive = true;
				Config.Network.MasterServerSignUp = true;
			}
			break;
		// Lobby
		case 'l':
			Game.fLobby = true;
			// lobby timeout specified? (e.g. --lobby=120)
			if (optarg)
			{
				Game.iLobbyTimeout = atoi(optarg);
				if (Game.iLobbyTimeout < 0) Game.iLobbyTimeout = 0;
			}
			break;
		case 'o': Game.fObserve = true; break;
		// Direct join
		case 'j':
			Game.NetworkActive = true;
			SCopy(optarg, Game.DirectJoinAddress, _MAX_PATH);
			break;
		case 'K':
			if (optarg && optarg[0])
			{
				LogF("Reading from DebugRec file '%s'", optarg);
				SCopy(optarg, Config.General.DebugRecExternalFile, _MAX_PATH);
			}
			else
				Log("Reading DebugRec from CtrlRec file in scenario record");
			Config.General.DebugRec = 1;
			Config.General.DebugRecWrite = 0;
			break;
		case 'w':
			if (optarg && optarg[0])
			{
				LogF("Writing to DebugRec file '%s'", optarg);
				SCopy(optarg, Config.General.DebugRecExternalFile, _MAX_PATH);
			}
			else
				Log("Writing DebugRec to CtrlRec file in scenario record");
			Config.General.DebugRec = 1;
			Config.General.DebugRecWrite = 1;
			break;
		case 'r': Game.Record = true; break;
		case 'n': Game.NetworkActive = true; break;
		case 'N': Game.NetworkActive = false; break;
		// Language override by parameter
		case 'L': SCopy(optarg, Config.General.LanguageEx, CFG_MaxString);
		// port overrides
		case 't': Config.Network.PortTCP = atoi(optarg); break;
		case 'u': Config.Network.PortUDP = atoi(optarg); break;
		// network game password
		case 'p': Network.SetPassword(optarg); break;
		// network game comment
		case 'm': Config.Network.Comment.CopyValidated(optarg); break;
		// record dump
		case 'R': Game.RecordDumpFile.Copy(optarg); break;
		// record stream
		case 'e': Game.RecordStream.Copy(optarg); break;
		// startup start screen
		case 's': C4Startup::SetStartScreen(optarg); break;
		// additional read-only data path
		case 'd': Reloc.AddPath(optarg); break;
		// debug options
		case 'D': Game.DebugPort = atoi(optarg); break;
		case 'P': Game.DebugPassword = optarg; break;
		case 'H': Game.DebugHost = optarg; break;
		// set custom scenario parameter by command line
		case 'S':
			{
			StdStrBuf sopt, soptval; sopt.Copy(optarg);
			int32_t val=1;
			if (sopt.SplitAtChar('=', &soptval)) val=atoi(soptval.getData());
			Game.StartupScenarioParameters.SetValue(sopt.getData(), val, false);
			}
			break;
		// debug configs
		case 'h':
			Game.NetworkActive = true;
			Game.fLobby = true;
			Config.Network.PortTCP = 11112;
			Config.Network.PortUDP = 11113;
			Config.Network.MasterServerSignUp = Config.Network.LeagueServerSignUp = false;
			break;
		case 'c':
			Game.NetworkActive = true;
			SCopy("localhost", Game.DirectJoinAddress, _MAX_PATH);
			Game.fLobby = true;
			Config.Network.PortTCP = 11112 + 2*(atoi(optarg)+1);
			Config.Network.PortUDP = 11113 + 2*(atoi(optarg)+1);
			break;
		case '?': /* getopt_long already printed an error message. */ break;
		default: assert(!"unexpected getopt_long return value");
		}
	}
	if (!Config.Network.MasterServerSignUp)
		Config.Network.LeagueServerSignUp = false;
	if (Game.fObserve || Game.fLobby)
		Game.NetworkActive = true;

	while (optind < argc)
	{
		char * szParameter = argv[optind++];
		{ // Strip trailing / that result from tab-completing unpacked c4groups
			int iLen = SLen(szParameter);
			if (iLen > 5 && szParameter[iLen-1] == '/' && szParameter[iLen-5] == '.' && szParameter[iLen-4] == 'o' && szParameter[iLen-3] == 'c')
			{
				szParameter[iLen-1] = '\0';
			}
		}
		// Scenario file
		if (SEqualNoCase(GetExtension(szParameter),"ocs"))
		{
			if(IsGlobalPath(szParameter))
				Game.SetScenarioFilename(szParameter);
			else
				Game.SetScenarioFilename((std::string(GetWorkingDirectory()) + DirSep + szParameter).c_str());

			continue;
		}
		if (SEqualNoCase(GetFilename(szParameter),"scenario.txt"))
		{
			Game.SetScenarioFilename(szParameter);
			continue;
		}
		// Player file
		if (SEqualNoCase(GetExtension(szParameter),"ocp"))
		{
			if(IsGlobalPath(szParameter))
				SAddModule(Game.PlayerFilenames, szParameter);
			else
				SAddModule(Game.PlayerFilenames, (std::string(GetWorkingDirectory()) + DirSep + szParameter).c_str());

			continue;
		}
		// Definition file
		if (SEqualNoCase(GetExtension(szParameter),"ocd"))
		{
			SAddModule(Game.DefinitionFilenames,szParameter);
			continue;
		}
		// Key file
		if (SEqualNoCase(GetExtension(szParameter),"c4k"))
		{
			Application.IncomingKeyfile.Copy(szParameter);
			continue;
		}
		// Update file
		if (SEqualNoCase(GetExtension(szParameter),"ocu"))
		{
			Application.IncomingUpdate.Copy(szParameter);
			continue;
		}
		// record stream
		if (SEqualNoCase(GetExtension(szParameter),"c4r"))
		{
			Game.RecordStream.Copy(szParameter);
		}
		// Direct join by URL
		if (SEqual2NoCase(szParameter, "clonk:"))
		{
			// Store address
			SCopy(szParameter + 6, Game.DirectJoinAddress, _MAX_PATH);
			SClearFrontBack(Game.DirectJoinAddress, '/');
			// Special case: if the target address is "update" then this is used for update initiation by url
			if (SEqualNoCase(Game.DirectJoinAddress, "update"))
			{
				Application.CheckForUpdates = true;
				Game.DirectJoinAddress[0] = 0;
				continue;
			}
			// Self-enable network
			Game.NetworkActive = true;
			continue;
		}
	}

#ifdef _WIN32
	// Clean up some forward/backward slach confusion since many internal OC file functions cannot handle both
	SReplaceChar(Game.ScenarioFilename, AltDirectorySeparator, DirectorySeparator);
	SReplaceChar(Game.PlayerFilenames, AltDirectorySeparator, DirectorySeparator);
	SReplaceChar(Game.DefinitionFilenames, AltDirectorySeparator, DirectorySeparator);
	Application.IncomingKeyfile.ReplaceChar(AltDirectorySeparator, DirectorySeparator);
	Application.IncomingUpdate.ReplaceChar(AltDirectorySeparator, DirectorySeparator);
	Game.RecordStream.ReplaceChar(AltDirectorySeparator, DirectorySeparator);
#endif

	// Default to editor if scenario given, player mode otherwise
	if (isEditor == 2)
		isEditor = !!*Game.ScenarioFilename && !Config.General.OpenScenarioInGameMode;

	// record?
	Game.Record = Game.Record || (Config.Network.LeagueServerSignUp && Game.NetworkActive);

	// startup dialog required?
	QuitAfterGame = !isEditor && Game.HasScenario();
}