Esempio n. 1
0
C4Viewport *C4Menu::GetViewport()
{
	// ask all viewports
	for (C4Viewport *pVP = ::Viewports.GetFirstViewport(); pVP; pVP = pVP->GetNext())
		if (pVP->IsViewportMenu(this))
			return pVP;
	// none matching
	return NULL;
}
static gboolean OnConfigureDareaStatic(GtkWidget* widget, GdkEventConfigure* event, gpointer user_data)
{
	C4ViewportWindow* window = static_cast<C4ViewportWindow*>(user_data);
	C4Viewport* cvp = window->cvp;

	cvp->UpdateOutputSize();

	return false;
}
bool C4FullScreen::ViewportCheck()
{
	int iPlrNum; C4Player *pPlr;
	// Not active
	if (!Active) return false;
	// Determine film mode
	bool fFilm = (Game.C4S.Head.Replay && Game.C4S.Head.Film);
	// Check viewports
	switch (::Viewports.GetViewportCount())
	{
		// No viewports: create no-owner viewport
	case 0:
		iPlrNum = NO_OWNER;
		// Film mode: create viewport for first player (instead of no-owner)
		if (fFilm)
			if ((pPlr = ::Players.First))
				iPlrNum = pPlr->Number;
		// Create viewport
		::Viewports.CreateViewport(iPlrNum, iPlrNum==NO_OWNER);
		// Non-film (observer mode)
		if (!fFilm)
		{
			// Activate mouse control
			::MouseControl.Init(iPlrNum);
			// Display message for how to open observer menu (this message will be cleared if any owned viewport opens)
			StdStrBuf sKey;
			sKey.Format("<c ffff00><%s></c>", Game.KeyboardInput.GetKeyCodeNameByKeyName("FullscreenMenuOpen", false).getData());
			::GraphicsSystem.FlashMessage(FormatString(LoadResStr("IDS_MSG_PRESSORPUSHANYGAMEPADBUTT"), sKey.getData()).getData());
		}
		break;
		// One viewport: do nothing
	case 1:
		break;
		// More than one viewport: remove all no-owner viewports
	default:
		::Viewports.CloseViewport(NO_OWNER, true);
		break;
	}
	// Look for no-owner viewport
	C4Viewport *pNoOwnerVp = ::Viewports.GetViewport(NO_OWNER);
	// No no-owner viewport found
	if (!pNoOwnerVp)
	{
		// Close any open fullscreen menu
		CloseMenu();
	}
	// No-owner viewport present
	else
	{
		// movie mode: player present, and no valid viewport assigned?
		if (Game.C4S.Head.Replay && Game.C4S.Head.Film && (pPlr = ::Players.First))
			// assign viewport to joined player
			pNoOwnerVp->Init(pPlr->Number, true);
	}
	// Done
	return true;
}
bool C4GraphicsSystem::ViewportNextPlayer()
	{
	// safety: switch valid?
	if ((!Game.C4S.Head.Film || !Game.C4S.Head.Replay) && !Game.GraphicsSystem.GetViewport(NO_OWNER)) return false;
	// do switch then
	C4Viewport *vp = GetFirstViewport();
	if (!vp) return false;
	vp->NextPlayer();
	return true;
	}
Esempio n. 5
0
bool C4Video::AdjustPosition()
	{
	// Get source player & viewport
	C4Viewport *pViewport = Game.GraphicsSystem.GetFirstViewport();
	if (!pViewport) return false;
	C4Player *pPlr = Game.Players.Get(pViewport->GetPlayer());
	if (!pPlr) return false;
	// Set camera position
	X = pPlr->ViewX - pViewport->ViewX + pViewport->DrawX - Width/2;
	X = BoundBy( X, 0, pViewport->ViewWdt - Width );
	Y = pPlr->ViewY - pViewport->ViewY + pViewport->DrawY - Height/2;
	Y = BoundBy( Y, 0, pViewport->ViewHgt - Height );
	// Success
	return true;
	}
BOOL C4GraphicsSystem::CreateViewport(int32_t iPlayer, bool fSilent)
	{
	// Create and init new viewport, add to viewport list
	int32_t iLastCount = GetViewportCount();
	C4Viewport *nvp = new C4Viewport;
	BOOL fOkay = FALSE;
	if (Application.isFullScreen) 
		fOkay = nvp->Init(iPlayer, false);
	else 
		fOkay = nvp->Init(&Console,&Application,iPlayer); 
	if (!fOkay)	{ delete nvp; return FALSE; }
	C4Viewport *pLast;
	for (pLast=FirstViewport; pLast && pLast->Next; pLast=pLast->Next);
	if (pLast) pLast->Next=nvp; else FirstViewport=nvp;
	// Recalculate viewports
	RecalculateViewports();
	// Viewports start off at centered position
	nvp->CenterPosition();
	// Action sound
	if (GetViewportCount()!=iLastCount) if (!fSilent)
		StartSoundEffect("CloseViewport");
	return TRUE;
	}
void C4GraphicsSystem::RecalculateViewports()
	{

	// Fullscreen only
	if (!Application.isFullScreen) return;

	// Sort viewports
	SortViewportsByPlayerControl();

	// Viewport area
	int32_t iBorderTop = 0, iBorderBottom = 0;
	if (Config.Graphics.UpperBoard) 
		iBorderTop = C4UpperBoardHeight;
	iBorderBottom = MessageBoard.Output.Hgt;
	ViewportArea.Set(Application.DDraw->lpBack,0,iBorderTop, Config.Graphics.ResX, Config.Graphics.ResY-iBorderTop-iBorderBottom);

	// Redraw flag
	InvalidateBg();
#ifdef _WIN32
	// reset mouse clipping
	ClipCursor(NULL);
#else
	// StdWindow handles this.
#endif
	// reset GUI dlg pos
	if (Game.pGUI)
		Game.pGUI->SetPreferredDlgRect(C4Rect(ViewportArea.X, ViewportArea.Y, ViewportArea.Wdt, ViewportArea.Hgt));

	// fullscreen background: First, cover all of screen
	BackgroundAreas.Clear();
	BackgroundAreas.AddRect(C4Rect(ViewportArea.X, ViewportArea.Y, ViewportArea.Wdt, ViewportArea.Hgt));

	// Viewports
	C4Viewport *cvp;
	int32_t iViews = 0;
	for (cvp=FirstViewport; cvp; cvp=cvp->Next) iViews++;
	if (!iViews) return;
	int32_t iViewsH = (int32_t) sqrt(float(iViews));
	int32_t iViewsX = iViews / iViewsH;
	int32_t iViewsL = iViews % iViewsH;
	int32_t cViewH,cViewX,ciViewsX;
	int32_t cViewWdt,cViewHgt,cOffWdt,cOffHgt,cOffX,cOffY;
	cvp=FirstViewport;
	for (cViewH=0; cViewH<iViewsH; cViewH++)
		{
		ciViewsX = iViewsX;	if (cViewH<iViewsL) ciViewsX++;
		for (cViewX=0; cViewX<ciViewsX; cViewX++)
			{
			cViewWdt = ViewportArea.Wdt/ciViewsX;
			cViewHgt = ViewportArea.Hgt/iViewsH;
			cOffX = ViewportArea.X;
			cOffY = ViewportArea.Y;
			cOffWdt=cOffHgt=0;
			int32_t ViewportScrollBorder = Application.isFullScreen ? C4ViewportScrollBorder : 0;
			if (ciViewsX*Min<int32_t>(cViewWdt, GBackWdt+2*ViewportScrollBorder)<ViewportArea.Wdt)
				cOffX=(ViewportArea.Wdt-ciViewsX*Min<int32_t>(cViewWdt, GBackWdt+2*ViewportScrollBorder))/2;
			if (iViewsH*Min<int32_t>(cViewHgt, GBackHgt+2*ViewportScrollBorder)<ViewportArea.Hgt)
				cOffY=(ViewportArea.Hgt-iViewsH*Min<int32_t>(cViewHgt, GBackHgt+2*ViewportScrollBorder))/2 + ViewportArea.Y;
			if (Config.Graphics.SplitscreenDividers) 
				{
				if (cViewX<ciViewsX-1) cOffWdt=4;
				if (cViewH<iViewsH-1) cOffHgt=4;
				}
			int32_t coViewWdt=cViewWdt-cOffWdt; if (coViewWdt>GBackWdt+2*ViewportScrollBorder) { coViewWdt=GBackWdt+2*ViewportScrollBorder; }
			int32_t coViewHgt=cViewHgt-cOffHgt; if (coViewHgt>GBackHgt+2*ViewportScrollBorder) { coViewHgt=GBackHgt+2*ViewportScrollBorder; }
			C4Rect rcOut(cOffX+cViewX*cViewWdt, cOffY+cViewH*cViewHgt, coViewWdt, coViewHgt);
			cvp->SetOutputSize(rcOut.x,rcOut.y,rcOut.x,rcOut.y,rcOut.Wdt,rcOut.Hgt);
			cvp=cvp->Next;
			// clip down area avaiable for background drawing
			BackgroundAreas.ClipByRect(rcOut);
			}
		}
	}
static gboolean OnExposeStatic(GtkWidget* widget, void *, gpointer user_data)
{
	C4Viewport* cvp = static_cast<C4ViewportWindow*>(user_data)->cvp;
	cvp->Execute();
	return true;
}
Esempio n. 9
0
bool Screen::MouseInput(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam, Dialog *pForDlg, class C4Viewport *pForVP)
	{
	// help mode and button pressed: Abort help and discard button
	if (Game.MouseControl.IsHelp())
		{
		switch (iButton)
			{
			case C4MC_Button_None:
				// just movement
				break;
			case C4MC_Button_LeftDown:
			case C4MC_Button_RightDown:
				// special for left/right down: Just ignore them, but don't stop help yet
				// help should be stopped on button-up, so these won't be processed
				iButton = C4MC_Button_None;
				break;
			default:
				// buttons stop help
				Game.MouseControl.AbortHelp();
				iButton = C4MC_Button_None;
				break;
			}
		}
	// forward to mouse
	Mouse.Input(iButton, iX, iY, dwKeyParam);
	// dragging
	if (Mouse.pDragElement)
		{
		int32_t iX2=iX, iY2=iY;
		Mouse.pDragElement->ScreenPos2ClientPos(iX2, iY2);
		if (!Mouse.IsLDown())
			{
			// stop dragging
			Mouse.pDragElement->StopDragging(Mouse, iX2, iY2, dwKeyParam);
			Mouse.pDragElement = NULL;
			}
		else
			{
			// continue dragging
			Mouse.pDragElement->DoDragging(Mouse, iX2, iY2, dwKeyParam);
			}
		}
	// backup previous MouseOver-element
	Mouse.pPrevMouseOverElement = Mouse.pMouseOverElement;
	Mouse.pMouseOverElement = NULL;
	bool fProcessed = false;
	// active context menu?
	if (!pForVP && pContext && pContext->CtxMouseInput(Mouse, iButton, iX, iY, dwKeyParam))
		{
		// processed by context menu: OK!
		}
	// otherwise: active dlg and inside screen? (or direct forward to specific dlg/viewport dlg)
	else if (rcBounds.Contains(iX, iY) || pForDlg || pForVP)
		{
		// context menu open but mouse down command issued? close context then
		if (pContext && (iButton == C4MC_Button_LeftDown || iButton == C4MC_Button_RightDown))
			AbortContext(true);
		// get client pos
		if (!pForDlg && !pForVP)
			{
			C4Rect &rcClientArea = GetClientRect();
			iX -= rcClientArea.x; iY -= rcClientArea.y;
			}
		// exclusive mode: process active dialog only
		if (IsExclusive() && !pForDlg && !pForVP)
			{
			if (pActiveDlg && pActiveDlg->IsVisible() && !pActiveDlg->IsFading())
				{
				// bounds check to dlg: only if not dragging
				C4Rect &rcDlgBounds = pActiveDlg->GetBounds();
				if (Mouse.IsLDown() || rcDlgBounds.Contains(iX, iY))
					// forward to active dialog
					pActiveDlg->MouseInput(Mouse, iButton, iX - rcDlgBounds.x, iY - rcDlgBounds.y, dwKeyParam);
				else
					Mouse.pMouseOverElement = NULL;
				}
			else
				// outside dialog: own handling (for screen context menu)
				Window::MouseInput(Mouse, iButton, iX, iY, dwKeyParam);
			}
		else
			{
			// non-exclusive mode: process all dialogs; make them active on left-click
			Dialog *pDlg;
			for (Element *pEl = pLast; pEl; pEl = pEl->GetPrev())
				if (pDlg = pEl->GetDlg())
					if (pDlg->IsShown())
						{
						// if specified: process specified dlg only
						if (pForDlg && pDlg != pForDlg) continue;
						// if specified: process specified viewport only
						bool fIsExternalDrawDialog = pDlg->IsExternalDrawDialog();
						C4Viewport *pVP = fIsExternalDrawDialog ? pDlg->GetViewport() : NULL;
						if (pForVP && pForVP != pVP) continue;
						// calc offset
						C4Rect &rcDlgBounds = pDlg->GetBounds();
						int32_t iOffX=0, iOffY=0;
						// special handling for viewport dialogs
						if (fIsExternalDrawDialog)
							{
							// ignore external drawing dialogs without a viepwort assigned
							if (!pVP) continue;
							// always clip to viewport bounds
							C4Rect rcOut(pVP->GetOutputRect());
							if (!rcOut.Contains(iX + rcBounds.x, iY + rcBounds.y)) continue;
							// viewport dialogs: Offset determined by viewport position
							iOffX = rcOut.x; iOffY = rcOut.y;
							}
						// hit test; or special: dragging possible outside active dialog
						if (rcDlgBounds.Contains(iX-iOffX, iY-iOffY) || (pDlg == pActiveDlg && Mouse.pDragElement))
							{
							// Okay; do input
							pDlg->MouseInput(Mouse, iButton, iX - rcDlgBounds.x - iOffX, iY - rcDlgBounds.y - iOffY, dwKeyParam);
							// dlgs may destroy GUI
							if (!IsGUIValid()) return false;
							// CAUTION: pDlg may be invalid now!
							// set processed-flag manually
							fProcessed = true;
							// inactive dialogs get activated by clicks
							if (Mouse.IsLDown() && pDlg != pActiveDlg)
								// but not viewport dialogs!
								if (!pDlg->IsExternalDrawDialog())
									ActivateDialog(pDlg);
							// one dlg only; break loop here
							break;
							}
						}
			}
		// check valid GUI; might be destroyed by mouse input
		if (!IsGUIValid()) return false;
		}

	// check if MouseOver has changed
	if (Mouse.pPrevMouseOverElement != Mouse.pMouseOverElement)
		{
		// send events
		if (Mouse.pPrevMouseOverElement) Mouse.pPrevMouseOverElement->MouseLeave(Mouse);
		if (Mouse.pMouseOverElement) Mouse.pMouseOverElement->MouseEnter(Mouse);
		}
	// return whether anything processed it
	return fProcessed || Mouse.pDragElement || (Mouse.pMouseOverElement && Mouse.pMouseOverElement!=this) || pContext;
	}
Esempio n. 10
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;
}
Esempio n. 11
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;
}