Ejemplo n.º 1
0
bool C4PlayerList::HasPlayerInTeamSelection()
{
	for (C4Player *pPlr = First; pPlr; pPlr = pPlr->Next)
		if (pPlr->IsChosingTeam())
			return true;
	return false;
}
Ejemplo n.º 2
0
void C4Team::AddPlayer(C4PlayerInfo &rInfo, bool fAdjustPlayer)
{
	// must not happen!
	assert(rInfo.GetID());
	if (!rInfo.GetID()) return;
	// add player; grow vector if necessary
	if (iPlayerCount >= iPlayerCapacity)
	{
		int32_t *piNewPlayers = new int32_t[iPlayerCapacity = (iPlayerCount+4)&~3];
		if (iPlayerCount) memcpy(piNewPlayers, piPlayers, iPlayerCount*sizeof(int32_t));
		delete [] piPlayers; piPlayers = piNewPlayers;
	}
	// store new player
	piPlayers[iPlayerCount++] = rInfo.GetID();
	if (!fAdjustPlayer) return;
	// set values in info
	rInfo.SetTeam(GetID());
	if (Game.Teams.IsTeamColors()) rInfo.SetColor(GetColor());
	// and in actual player, if it is joined already
	if (rInfo.IsJoined())
	{
		C4Player *pJoinedPlr = ::Players.GetByInfoID(rInfo.GetID());
		assert(pJoinedPlr || (rInfo.GetType() == C4PT_Script));
		if (pJoinedPlr)
		{
			pJoinedPlr->Team = GetID();
			if (Game.Teams.IsTeamColors()) pJoinedPlr->SetPlayerColor(GetColor());
		}
	}
}
Ejemplo n.º 3
0
C4Network2Stats::C4Network2Stats() : pSec1Timer(NULL) {
  // set self (needed in CreateGraph-fns)
  Game.pNetworkStatistics = this;
  // init callback timer
  pSec1Timer = new C4Sec1TimerCallback<C4Network2Stats>(this);
  SecondCounter = 0;
  ControlCounter = 0;
  // init graphs
  statObjCount.SetTitle(LoadResStr("IDS_MSG_OBJCOUNT"));
  statFPS.SetTitle(LoadResStr("IDS_MSG_FPS"));
  statNetI.SetTitle(LoadResStr("IDS_NET_INPUT"));
  statNetI.SetColorDw(0x00ff00);
  statNetO.SetTitle(LoadResStr("IDS_NET_OUTPUT"));
  statNetO.SetColorDw(0xff0000);
  graphNetIO.AddGraph(&statNetI);
  graphNetIO.AddGraph(&statNetO);
  statControls.SetTitle(LoadResStr("IDS_NET_CONTROL"));
  statControls.SetAverageTime(100);
  statActions.SetTitle(LoadResStr("IDS_NET_APM"));
  statActions.SetAverageTime(100);
  for (C4Player *pPlr = Game.Players.First; pPlr; pPlr = pPlr->Next)
    pPlr->CreateGraphs();
  C4Network2Client *pClient = NULL;
  while (pClient = Game.Network.Clients.GetNextClient(pClient))
    pClient->CreateGraphs();
}
Ejemplo n.º 4
0
C4Network2Stats::~C4Network2Stats() {
  for (C4Player *pPlr = Game.Players.First; pPlr; pPlr = pPlr->Next)
    pPlr->ClearGraphs();
  C4Network2Client *pClient = NULL;
  while (pClient = Game.Network.Clients.GetNextClient(pClient))
    pClient->ClearGraphs();
  pSec1Timer->Release();
}
Ejemplo n.º 5
0
void C4GameOverDlg::OnShown() {
  // close some other dialogs
  Game.Scoreboard.HideDlg();
  FullScreen.CloseMenu();
  for (C4Player *plr = Game.Players.First; plr; plr = plr->Next)
    plr->CloseMenu();
  // pause game when round results dlg is shown
  Game.Pause();
}
Ejemplo n.º 6
0
void C4PlayerList::Execute()
{
	C4Player *pPlr;
	// Execute
	for (pPlr=First; pPlr; pPlr=pPlr->Next)
		pPlr->Execute();
	// Check retirement
	for (pPlr=First; pPlr; pPlr=pPlr->Next)
		if (pPlr->Eliminated && !pPlr->RetireDelay)
			{ Retire(pPlr); break; }
}
Ejemplo n.º 7
0
bool C4PlayerList::RemoveAtRemoteClient(bool fDisconnect, bool fNoCalls)
{
	C4Player *pPlr;
	// Get players
	while ((pPlr = GetAtRemoteClient()))
	{
		// Log
		Log(FormatString(LoadResStr("IDS_PRC_REMOVEPLR"),pPlr->GetName()).getData());
		// Remove
		Remove(pPlr, fDisconnect, fNoCalls);
	}
	return true;
}
Ejemplo n.º 8
0
bool C4PlayerList::RemoveAtClient(const char *szName, bool fDisconnect)
{
	C4Player *pPlr;
	// Get players
	while ((pPlr = GetAtClient(szName)))
	{
		// Log
		Log(FormatString(LoadResStr("IDS_PRC_REMOVEPLR"),pPlr->GetName()).getData());
		// Remove
		Remove(pPlr, fDisconnect, false);
	}
	return true;
}
Ejemplo n.º 9
0
C4GUI::Edit::InputResult C4ChatInputDialog::OnChatInput(C4GUI::Edit *edt,
                                                        bool fPasting,
                                                        bool fPastingMore) {
  // no double processing
  if (fProcessed) return C4GUI::Edit::IR_CloseDlg;
  // get edit text
  C4GUI::Edit *pEdt = reinterpret_cast<C4GUI::Edit *>(edt);
  char *szInputText = const_cast<char *>(pEdt->GetText());
  // Store to back buffer
  Game.MessageInput.StoreBackBuffer(szInputText);
  // script queried input?
  if (fObjInput) {
    fProcessed = true;
    // check if the target input is still valid
    C4Player *pPlr = Game.Players.Get(iPlr);
    if (!pPlr) return C4GUI::Edit::IR_CloseDlg;
    if (!pPlr->MarkMessageBoardQueryAnswered(pTarget)) {
      // there was no associated query!
      return C4GUI::Edit::IR_CloseDlg;
    }
    // then do a script callback, incorporating the input into the answer
    if (fUppercase) SCapitalize(szInputText);
    StdStrBuf sInput;
    sInput.Copy(szInputText);
    sInput.EscapeString();
    Game.Control.DoInput(
        CID_Script,
        new C4ControlScript(
            FormatString("OnMessageBoardAnswer(Object(%d), %d, \"%s\")",
                         pTarget ? pTarget->Number : 0, iPlr,
                         sInput.getData()).getData()),
        CDT_Decide);
    return C4GUI::Edit::IR_CloseDlg;
  } else
    // reroute to message input class
    Game.MessageInput.ProcessInput(szInputText);
  // safety: message board commands may do strange things
  if (!C4GUI::IsGUIValid() || this != pInstance) return C4GUI::Edit::IR_Abort;
  // select all text to be removed with next keypress
  // just for pasting mode; usually the dlg will be closed now anyway
  pEdt->SelectAll();
  // avoid dlg close, if more content is to be pasted
  if (fPastingMore) return C4GUI::Edit::IR_None;
  fProcessed = true;
  return C4GUI::Edit::IR_CloseDlg;
}
Ejemplo n.º 10
0
bool C4ChatInputDialog::KeyCompleteNick() {
  if (!pEdit) return false;
  char IncompleteNick[256 + 1];
  // get current word in edit
  if (!pEdit->GetCurrentWord(IncompleteNick, 256)) return false;
  if (!*IncompleteNick) return false;
  C4Player *plr = Game.Players.First;
  while (plr) {
    // Compare name and input
    if (SEqualNoCase(plr->GetName(), IncompleteNick, SLen(IncompleteNick))) {
      pEdit->InsertText(plr->GetName() + SLen(IncompleteNick), true);
      return true;
    } else
      plr = plr->Next;
  }
  // no match found
  return false;
}
Ejemplo n.º 11
0
bool C4PlayerList::RemoveLocal(bool fDisconnect, bool fNoCalls)
{
	// (used by league system the set local fate)
	C4Player *pPlr;
	do
		for (pPlr = First; pPlr; pPlr = pPlr->Next)
			if (pPlr->LocalControl)
			{
				// Log
				Log(FormatString(LoadResStr("IDS_PRC_REMOVEPLR"),pPlr->GetName()).getData());
				// Remove
				Remove(pPlr, fDisconnect, fNoCalls);
				break;
			}
	while (pPlr);

	return true;
}
Ejemplo n.º 12
0
void C4ChatInputDialog::OnChatCancel() {
  // abort chat: Make sure msg board query is aborted
  fProcessed = true;
  if (fObjInput) {
    // check if the target input is still valid
    C4Player *pPlr = Game.Players.Get(iPlr);
    if (!pPlr) return;
    if (pPlr->MarkMessageBoardQueryAnswered(pTarget)) {
      // there was an associated query - it must be removed on all clients
      // synchronized via queue
      // do this by calling OnMessageBoardAnswer without an answer
      Game.Control.DoInput(
          CID_Script,
          new C4ControlScript(
              FormatString("OnMessageBoardAnswer(Object(%d), %d, 0)",
                           pTarget ? pTarget->Number : 0, iPlr).getData()),
          CDT_Decide);
    }
  }
}
Ejemplo n.º 13
0
C4Player* C4PlayerList::Join(const char *szFilename, bool fScenarioInit, int iAtClient, const char *szAtClientName, C4PlayerInfo *pInfo, C4ValueNumbers * numbers)
{
	assert(pInfo);
	assert(fScenarioInit || numbers);

	// safeties
	if (szFilename && !*szFilename) szFilename = NULL;

	// Log
	LogF(LoadResStr(fScenarioInit ? "IDS_PRC_JOINPLR" : "IDS_PRC_RECREATE"),pInfo->GetName());

	// Too many players
	if (1) // replay needs to check, too!
		if (GetCount()+1>Game.Parameters.MaxPlayers)
		{
			LogF(LoadResStr("IDS_PRC_TOOMANYPLRS"),Game.Parameters.MaxPlayers);
			return NULL;
		}

	// Check duplicate file usage
	if (szFilename) if (FileInUse(szFilename))
			{ Log(LoadResStr("IDS_PRC_PLRFILEINUSE")); return NULL; }

	// Create
	C4Player *pPlr = new C4Player;

	// Append to player list
	C4Player *pLast=First;
	while (pLast && pLast->Next) pLast=pLast->Next;
	if (pLast) pLast->Next=pPlr; else First = pPlr;

	// Init
	if (!pPlr->Init(GetFreeNumber(),iAtClient,szAtClientName,szFilename,fScenarioInit,pInfo, numbers))
		{ Remove(pPlr, false, false); Log(LoadResStr("IDS_PRC_JOINFAIL")); return NULL; }

	// Done
	return pPlr;
}
Ejemplo n.º 14
0
bool C4MainMenu::MenuCommand(const char *szCommand, bool fIsCloseCommand)
{
	// Determine player
	C4Player *pPlr = ::Players.Get(Player);
	// Activate
	if (SEqual2(szCommand,"ActivateMenu:"))
	{
		if (C4GameOverDlg::IsShown()) return false; // no new menus during game over dlg
		if (SEqual(szCommand+13,"Main")) return ActivateMain(Player);
		if (SEqual(szCommand+13,"Hostility")) return ActivateHostility(Player);
		if (SEqual(szCommand+13,"NewPlayer")) return ActivateNewPlayer(Player);
		if (SEqual(szCommand+13,"Goals"))
		{
			::Control.DoInput(CID_PlrAction, C4ControlPlayerAction::ActivateGoalMenu(::Players.Get(Player)), CDT_Queue);
			return true;
		}
		if (SEqual(szCommand+13,"Rules")) return ActivateRules(Player);
		if (SEqual(szCommand+13,"Host")) return ActivateHost(Player);
		if (SEqual(szCommand+13,"Client")) return ActivateClient(Player);
		if (SEqual(szCommand+13,"Options")) return ActivateOptions(Player);
		if (SEqual(szCommand+13,"Display")) return ActivateDisplay(Player);
		if (SEqual(szCommand+13,"Save:Game")) return ActivateSavegame(Player);
		if (SEqual(szCommand+13,"TeamSel")) return pPlr ? pPlr->ActivateMenuTeamSelection(true) : false;
		if (SEqual(szCommand+13,"Surrender")) return ActivateSurrender(Player);
		if (SEqual(szCommand+13,"Observer")) return ActivateObserver();
	}
	// JoinPlayer
	if (SEqual2(szCommand,"JoinPlayer:"))
	{
		// not in league or replay mode
		if (Game.Parameters.isLeague() || Game.C4S.Head.Replay) return false;
		// join player
		// 2do: not for observers and such?
		Players.JoinNew(szCommand+11);
		return true;
	}
	// SetHostility
	if (SEqual2(szCommand,"SetHostility:"))
	{
		// only if allowed
		if (!Game.Teams.IsHostilityChangeAllowed()) return false;
		int32_t iOpponent; sscanf(szCommand+13,"%i",&iOpponent);
		C4Player *pOpponent = ::Players.Get(iOpponent);
		if (!pOpponent || pOpponent->GetType() != C4PT_User) return false;
		::Control.DoInput(CID_PlrAction, C4ControlPlayerAction::SetHostility(::Players.Get(Player), pOpponent, !::Players.HostilityDeclared(Player, pOpponent->Number)), CDT_Queue);
		return true;
	}
	// Abort
	if (SEqual2(szCommand,"Abort"))
	{
		FullScreen.ShowAbortDlg();
		return true;
	}
	// Surrender
	if (SEqual2(szCommand,"Surrender"))
	{
		::Control.DoInput(CID_PlrAction, C4ControlPlayerAction::Surrender(::Players.Get(Player)), CDT_Queue);
		return true;
	}
	// Save game
	if (SEqual2(szCommand, "Save:Game:"))
	{
		char strFilename[_MAX_PATH + 1]; SCopySegment(szCommand, 2, strFilename, ':', _MAX_PATH);
		char strTitle[_MAX_PATH + 1]; SCopy(szCommand + SCharPos(':', szCommand, 2) + 1, strTitle, _MAX_PATH);
		Game.QuickSave(strFilename, strTitle);
		ActivateSavegame(Player);
		return true;
	}
	// Kick
	if (SEqual2(szCommand,"Host:Kick:"))
	{
		int iClientID = atoi(szCommand+10);
		if (iClientID && ::Network.isEnabled())
		{
			if (Game.Parameters.isLeague() && ::Players.GetAtClient(iClientID))
				::Network.Vote(VT_Kick, true, iClientID);
			else
			{
				C4Client *pClient = Game.Clients.getClientByID(iClientID);
				if (pClient) Game.Clients.CtrlRemove(pClient, LoadResStr("IDS_MSG_KICKBYMENU"));
				Close(true);
			}
		}
		return true;
	}
	// Part
	if (SEqual2(szCommand,"Part"))
	{
		if (::Network.isEnabled())
		{
			if (Game.Parameters.isLeague() && ::Players.GetLocalByIndex(0))
				::Network.Vote(VT_Kick, true, ::Control.ClientID());
			else
			{
				Game.RoundResults.EvaluateNetwork(C4RoundResults::NR_NetError, LoadResStr("IDS_ERR_GAMELEFTVIAPLAYERMENU"));
				::Network.Clear();
			}
		}
		return true;
	}
	// Options
	if (SEqual2(szCommand,"Options:"))
	{
		// Music
		if (SEqual(szCommand + 8, "Music"))
		{
			Application.MusicSystem.ToggleOnOff();
		}
		// Sound
		if (SEqual(szCommand + 8, "Sound"))
		{
			if (Config.Sound.RXSound)
			{
				Application.SoundSystem.Clear();
				Config.Sound.RXSound = false;
			}
			else
			{
				Config.Sound.RXSound = true;
				if (!Application.SoundSystem.Init())
					{ Log(LoadResStr("IDS_PRC_NOSND")); }
			}
		}
		// Reopen with updated options
		ActivateOptions(Player, GetSelection());
		return true;
	}
	// Display
	if (SEqual2(szCommand,"Display:"))
	{
		// Upper board
		if (SEqual(szCommand + 8, "UpperBoard"))
		{
			Config.Graphics.UpperBoard = !Config.Graphics.UpperBoard;
			::Viewports.RecalculateViewports();
		}
		// FPS
		if (SEqual(szCommand + 8, "FPS")) Config.General.FPS = !Config.General.FPS;
		// Player names
		if (SEqual(szCommand + 8, "PlayerNames")) Config.Graphics.ShowCrewNames = !Config.Graphics.ShowCrewNames;
		// Clonk names
		if (SEqual(szCommand + 8, "ClonkNames")) Config.Graphics.ShowCrewCNames = !Config.Graphics.ShowCrewCNames;
		// Clock
		if (SEqual(szCommand + 8, "Clock")) Config.Graphics.ShowClock = !Config.Graphics.ShowClock;
		// Reopen with updated options
		ActivateDisplay(Player, GetSelection());
		return true;
	}
	// Goal info
	if (SEqual2(szCommand,"Player:Goal:") || SEqual2(szCommand,"Player:Rule:"))
	{
		if (!ValidPlr(Player)) return false; // observers may not look at goal/rule info, because it requires queue activation
		Close(true);
		C4Object *pObj; C4ID idItem(szCommand+12); C4Def * pDef = C4Id2Def(idItem);
		if (pDef && (pObj = ::Objects.Find(pDef)))
			::Control.DoInput(CID_PlrAction, C4ControlPlayerAction::ActivateGoal(::Players.Get(Player), pObj), CDT_Queue);
		else
			return false;
		return true;
	}
	// Team selection
	if (SEqual2(szCommand, "TeamSel:"))
	{
		Close(true);
		int32_t idTeam = atoi(szCommand+8);

		// OK, join this team
		if (pPlr) pPlr->DoTeamSelection(idTeam);
		return true;
	}
	// Team switch
	if (SEqual2(szCommand, "TeamSwitch:"))
	{
		Close(true);
		int32_t idTeam = atoi(szCommand+11);

		// check if it's still allowed
		if (!Game.Teams.IsTeamSwitchAllowed()) return false;
		// OK, join this team
		::Control.DoInput(CID_PlrAction, C4ControlPlayerAction::SetTeam(::Players.Get(Player), idTeam), CDT_Queue);
		return true;
	}
	// Observe
	if (SEqual2(szCommand, "Observe:"))
	{
		const char *szObserverTarget = szCommand+8;
		C4Viewport *pVP = ::Viewports.GetViewport(NO_OWNER);
		if (pVP) // viewport may have closed meanwhile
		{
			if (SEqual(szObserverTarget, "Free"))
			{
				// free view
				pVP->Init(NO_OWNER, true);
				return true;
			}
			else
			{
				// view following player
				int32_t iPlr = atoi(szObserverTarget);
				if (ValidPlr(iPlr))
				{
					pVP->Init(iPlr, true);
					return true;
				}
			}
		}
		return false;
	}
	// No valid command
	return false;
}
Ejemplo n.º 15
0
bool C4MainMenu::DoRefillInternal(bool &rfRefilled)
{
	// Variables
	C4FacetSurface fctSymbol;
	C4Player *pPlayer;
	C4IDList ListItems;
	C4Facet fctTarget;
	bool fWasEmpty = !GetItemCount();

	// Refill
	switch (Identification)
	{
		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	case C4MN_Hostility:
	{
		// Clear items
		ClearItems();
		// Refill player
		if (!(pPlayer = ::Players.Get(Player))) return false;
		// Refill items
		C4Player *pPlr; int32_t iIndex;
		for (iIndex=0; (pPlr = ::Players.GetByIndex(iIndex)); iIndex++)
			// Ignore player self and invisible
			if (pPlr != pPlayer) if (!pPlr->IsInvisible())
				{
					// Symbol
					fctSymbol.Create(C4SymbolSize,C4SymbolSize);
					pPlayer->DrawHostility(fctSymbol,iIndex);
					// Message
					StdStrBuf sMsg;
					bool isFriendly = pPlayer->Hostility.find(pPlr) == pPlayer->Hostility.end();
					if (isFriendly)
						sMsg.Format(LoadResStr("IDS_MENU_ATTACK"),pPlr->GetName());
					else
						sMsg.Format(LoadResStr("IDS_MENU_NOATTACK"),pPlr->GetName());
					// Command
					char szCommand[1000];
					sprintf(szCommand,"SetHostility:%i",pPlr->Number);
					// Info caption
					char szInfoCaption[C4MaxTitle+1],szFriendly[50],szNot[30]="";
					SCopy(LoadResStr(isFriendly ? "IDS_MENU_ATTACKHOSTILE" : "IDS_MENU_ATTACKFRIENDLY"),szFriendly);
					if (!isFriendly) SCopy(LoadResStr("IDS_MENU_ATTACKNOT"),szNot);
					sprintf(szInfoCaption,LoadResStr("IDS_MENU_ATTACKINFO"),pPlr->GetName(),szFriendly,szNot);
					if (iIndex==pPlayer->Number) SCopy(LoadResStr("IDS_MENU_ATTACKSELF"),szInfoCaption);
					// Add item
					Add(sMsg.getData(),fctSymbol,szCommand,C4MN_Item_NoCount,NULL,szInfoCaption);
					fctSymbol.Default();
				}
		break;
	}
	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	case C4MN_TeamSelection:
	case C4MN_TeamSwitch:
	{
		// Clear items
		ClearItems();
		// add all teams as menu items
		// 2do: Icon
		C4Team *pTeam; int32_t i=0; bool fAddNewTeam=Game.Teams.IsAutoGenerateTeams();
		for (;;)
		{
			pTeam = Game.Teams.GetTeamByIndex(i);
			if (pTeam)
			{
				// next regular team
				++i;
				// do not add a new team if an empty team exists
				if (!pTeam->GetPlayerCount()) fAddNewTeam = false;
			}
			else if (fAddNewTeam)
			{
				// join new team
				fAddNewTeam = false;
			}
			else
			{
				// all teams done
				break;
			}
			// create team symbol: Icon spec if specified; otherwise flag for empty and crew for nonempty team
			fctSymbol.Create(C4SymbolSize,C4SymbolSize);
			const char *szIconSpec = pTeam ? pTeam->GetIconSpec() : NULL;
			bool fHasIcon = false;
			if (szIconSpec && *szIconSpec)
			{
				fHasIcon = Game.DrawTextSpecImage(fctSymbol, szIconSpec, NULL, pTeam->GetColor());
			}
			if (!fHasIcon)
			{
				if (pTeam && pTeam->GetPlayerCount())
					::GraphicsResource.fctCrewClr.DrawClr(fctSymbol, true, pTeam->GetColor());
				else
					C4GUI::Icon::GetIconFacet(C4GUI::Ico_Team).Draw(fctSymbol, true);
			}
			StdStrBuf sTeamName;
			if (pTeam)
			{
				sTeamName.Take(pTeam->GetNameWithParticipants());
			}
			else
				sTeamName.Ref(LoadResStr("IDS_PRC_NEWTEAM"));
			const char *szOperation = (Identification == C4MN_TeamSwitch) ? "TeamSwitch" : "TeamSel";
			Add(sTeamName.getData(), fctSymbol,FormatString("%s:%d", szOperation, pTeam ? pTeam->GetID() : TEAMID_New).getData(),
			    C4MN_Item_NoCount,NULL,FormatString(LoadResStr("IDS_MSG_JOINTEAM"), sTeamName.getData()).getData(), C4ID(pTeam ? pTeam->GetID() : 0));
			fctSymbol.Default();
		}
		break;
	}
	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	case C4MN_Observer: // observer menu
	{
		// Clear items
		ClearItems();
		// Check validity
		C4Viewport *pVP = ::Viewports.GetViewport(NO_OWNER);
		if (!pVP) return false;
		int32_t iInitialSelection = 0;
		// Add free view
		AddRefSym(LoadResStr("IDS_MSG_FREEVIEW"), C4GUI::Icon::GetIconFacet(C4GUI::Ico_Star), "Observe:Free", C4MN_Item_NoCount, NULL, LoadResStr("IDS_MSG_FREELYSCROLLAROUNDTHEMAP"));
		// Add players
		C4Player *pPlr; int32_t iIndex;
		for (iIndex=0; (pPlr = ::Players.GetByIndex(iIndex)); iIndex++)
		{
			// Ignore invisible
			if (!pPlr->IsInvisible())
			{
				// Symbol
				fctSymbol.Create(C4SymbolSize,C4SymbolSize);
				::GraphicsResource.fctPlayerClr.DrawClr(fctSymbol, true, pPlr->ColorDw);
				// Message
				StdStrBuf sMsg;
				DWORD dwClr = pPlr->ColorDw;
				sMsg.Format("<c %x>%s</c>", (unsigned int)C4GUI::MakeColorReadableOnBlack(dwClr), pPlr->GetName());
				// Command
				StdStrBuf sCommand;
				sCommand.Format("Observe:%d", (int)pPlr->Number);
				// Info caption
				StdStrBuf sInfo;
				sInfo.Format(LoadResStr("IDS_TEXT_FOLLOWVIEWOFPLAYER"), pPlr->GetName());
				// Add item
				Add(sMsg.getData(),fctSymbol,sCommand.getData(),C4MN_Item_NoCount,NULL,sInfo.getData());
				fctSymbol.Default();
				// check if this is the currently selected player
				if (pVP->GetPlayer() == pPlr->Number) iInitialSelection = GetItemCount()-1;
			}
			// Initial selection on followed player
			if (fWasEmpty) SetSelection(iInitialSelection, false, true);
		}
	}
	break;
	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	default:
		// No internal refill needed
		return true;
		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	}

	// Successfull internal refill
	rfRefilled = true;
	return true;
}