diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp
index b40e768..d9d0fd2 100644
--- a/src/game/server/entities/character.cpp
+++ b/src/game/server/entities/character.cpp
@@ -7,7 +7,9 @@
 
 #include "character.h"
 #include "laser.h"
+
 #include "projectile.h"
+#include <game/server/gamemodes/fb.h>
 
 //input count
 struct CInputCount
@@ -35,7 +37,6 @@ CInputCount CountInput(int Prev, int Cur)
 	return c;
 }
 
-
 MACRO_ALLOC_POOL_ID_IMPL(CCharacter, MAX_CLIENTS)
 
 // Character, "physical" player's part
@@ -60,6 +61,11 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos)
 	m_LastWeapon = WEAPON_HAMMER;
 	m_QueuedWeapon = -1;
 	
+ 	m_pBall = NULL;
+	m_GoalCampTick = 0;
+ 	m_CampTick = 0;
+ 	m_CampPos = Pos;
+	
 	m_pPlayer = pPlayer;
 	m_Pos = Pos;
 	
@@ -112,7 +118,7 @@ bool CCharacter::IsGrounded()
 
 void CCharacter::HandleNinja()
 {
-	if(m_ActiveWeapon != WEAPON_NINJA)
+	if(m_ActiveWeapon != WEAPON_NINJA || m_pBall)
 		return;
 	
 	vec2 Direction = normalize(vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY));
@@ -120,12 +126,7 @@ void CCharacter::HandleNinja()
 	if ((Server()->Tick() - m_Ninja.m_ActivationTick) > (g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000))
 	{
 		// time's up, return
-		m_aWeapons[WEAPON_NINJA].m_Got = false;
-		m_ActiveWeapon = m_LastWeapon;
-		if(m_ActiveWeapon == WEAPON_NINJA)
-			m_ActiveWeapon = WEAPON_GUN;
-			
-		SetWeapon(m_ActiveWeapon);
+		RevokeNinja();
 		return;
 	}
 	
@@ -191,8 +192,38 @@ void CCharacter::HandleNinja()
 	}
 
 	return;
+};
+ 
+void CCharacter::ReleaseBall()
+{
+	GameServer()->CreateSoundGlobal(SOUND_CTF_DROP);
+	m_pBall->m_DropTick = Server()->Tick();
+	m_pBall->m_IdleTick = -1;
+	m_pBall->m_pLastCarrierCharacter = this;
+	m_pBall->m_LastCarrierTeam = GetPlayer()->GetTeam();
+	m_pBall->m_pCarryingCharacter = NULL;
+	m_pBall = NULL;
+
+	RevokeNinja();
 }
 
+void CCharacter::DropBall()
+{
+	m_pBall->m_Vel = vec2(0, 0);
+	ReleaseBall();
+}
+
+void CCharacter::ThrowBall(vec2 direction)
+{
+	if (!m_pBall) return;
+	m_pBall->m_Vel = direction;
+	ReleaseBall();
+}
+
+void CCharacter::CaptureBall(CBall* ball)
+{
+	static_cast<CGameControllerFB *>(GameServer()->m_pController)->GrantBall(this, ball);
+}
 
 void CCharacter::DoWeaponSwitch()
 {
@@ -409,15 +440,27 @@ void CCharacter::FireWeapon()
 		} break;
 		
 		case WEAPON_NINJA:
-		{
-			// reset Hit objects
-			m_NumObjectsHit = 0;
-			
-			m_Ninja.m_ActivationDir = Direction;
-			m_Ninja.m_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * Server()->TickSpeed() / 1000;
-			m_Ninja.m_OldVelAmount = length(m_Core.m_Vel);
+		{			
+ 			if (m_pBall)
+ 			{
+ 				ThrowBall(normalize (vec2 (m_LatestInput.m_TargetX, m_LatestInput.m_TargetY)) *
+ 				static_cast<float> (g_Config.m_SvfbBallVelocity / 10.0f));  //20.75f;
+ 				m_ReloadTimer = g_pData->m_Weapons.m_aId[m_ActiveWeapon].m_Firedelay * Server()->TickSpeed() / 1000;	//	prevent shooting
+ 				return;
+ 			}
+ 			else
+ 			{		
+ 				m_AttackTick = Server()->Tick();
+ 				m_Ninja.m_ActivationDir = Direction;
+ 				m_Ninja.m_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * Server()->TickSpeed() / 1000;
+ 				m_Ninja.m_OldVelAmount = length(m_Core.m_Vel);
+ 				
+ 				// reset Hit objects
+ 				m_NumObjectsHit = 0;
+ 				
+ 				GameServer()->CreateSound(m_Pos, SOUND_NINJA_FIRE);
+ 			}
 
-			GameServer()->CreateSound(m_Pos, SOUND_NINJA_FIRE);
 		} break;
 		
 	}
@@ -485,17 +528,31 @@ bool CCharacter::GiveWeapon(int Weapon, int Ammo)
 	return false;
 }
 
-void CCharacter::GiveNinja()
+void CCharacter::BecomeNinja()
 {
 	m_Ninja.m_ActivationTick = Server()->Tick();
 	m_aWeapons[WEAPON_NINJA].m_Got = true;
 	m_aWeapons[WEAPON_NINJA].m_Ammo = -1;
 	m_LastWeapon = m_ActiveWeapon;
 	m_ActiveWeapon = WEAPON_NINJA;
-	
+}
+
+void CCharacter::GiveNinja()
+{
+	BecomeNinja();
 	GameServer()->CreateSound(m_Pos, SOUND_PICKUP_NINJA);
 }
 
+void CCharacter::RevokeNinja()
+{
+	m_aWeapons[WEAPON_NINJA].m_Got = false;
+	m_ActiveWeapon = m_LastWeapon;
+	if(m_ActiveWeapon == WEAPON_NINJA)
+		m_ActiveWeapon = WEAPON_GUN;
+		
+	SetWeapon(m_ActiveWeapon);
+}
+
 void CCharacter::SetEmote(int Emote, int Tick)
 {
 	m_EmoteType = Emote;
@@ -545,6 +602,59 @@ void CCharacter::Tick()
 	m_Core.m_Input = m_Input;
 	m_Core.Tick(true);
 	
+    // direct pass of ball
+ 	if (g_Config.m_SvfbDirectPass && m_pBall && m_Core.m_TriggeredEvents & COREEVENT_HOOK_ATTACH_PLAYER && m_Core.m_HookedPlayer != -1)
+ 	{
+ 		// find catcher. Is there an easier way to do this?
+ 		//CCharacter* catcher = (CCharacter *)GameServer()->m_World.FindFirst(NETOBJTYPE_CHARACTER);
+ 		CCharacter* catcher = static_cast<CCharacter *>(GameServer()->m_World.FindFirst(CGameWorld::ENTTYPE_CHARACTER));	
+ 		while (catcher && &catcher->m_Core != GameServer()->m_World.m_Core.m_apCharacters[m_Core.m_HookedPlayer])
+ 			catcher = (CCharacter *)catcher->TypeNext();
+
+ 		if (catcher)
+ 		{
+			CBall *ball = m_pBall;
+			ReleaseBall();
+			catcher->CaptureBall(ball);
+ 
+ 			// release hook
+ 			m_Core.m_HookedPlayer = -1;
+ 			m_Core.m_HookState = HOOK_RETRACTED;
+ 			m_Core.m_HookPos = m_Core.m_Pos;
+ 		};
+ 	};
+ 
+ 	// hook the flag
+ 	if (g_Config.m_SvfbHookBall && !m_pBall && (m_Core.m_HookState == HOOK_FLYING || m_Core.m_TriggeredEvents & (COREEVENT_HOOK_ATTACH_GROUND + COREEVENT_HOOK_HIT_NOHOOK)))
+ 	{
+ 		// Find the closest ball
+ 		CBall *closest_ball = NULL;
+ 		for (int i = 0; i < FB_MAX_BALLS; ++i)
+ 		{
+ 			CBall *b = static_cast<CGameControllerFB *>(GameServer()->m_pController)->m_apBalls[i];
+ 			if (b && !b->m_pCarryingCharacter)
+ 			{
+ 				// It may be not a good idea to pass this to
+ 				// config, but we need some easy way to test
+ 				// these values
+ 				static vec2 ball_offset(0, -38);
+ 				vec2 ball_pos = b->m_Pos + ball_offset;
+ 				vec2 closest_point = closest_point_on_line(m_Core.m_Pos, m_Core.m_HookPos, ball_pos);
+ 				if (distance(ball_pos, closest_point) < g_Config.m_SvfbBallRadius && (!closest_ball || distance(m_Pos, ball_pos) < distance(m_Pos, closest_ball->m_Pos)))
+ 				{
+ 					closest_ball = b;
+ 				};
+ 			};
+ 		};
+ 		if (closest_ball)
+ 		{
+ 			CaptureBall(closest_ball);
+ 			// retract hook
+ 			m_Core.m_HookState = HOOK_RETRACTED;
+ 			m_Core.m_HookPos = m_Core.m_Pos;
+ 		};
+ 	};
+
 	// handle death-tiles and leaving gamelayer
 	if(GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH ||
 		GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH ||
@@ -701,6 +811,12 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon)
 	if(GameServer()->m_pController->IsFriendlyFire(m_pPlayer->GetCID(), From) && !g_Config.m_SvTeamdamage)
 		return false;
 
+	if (g_Config.m_SvfbInstagib && Weapon == WEAPON_RIFLE)
+	{
+		Die(From, Weapon);
+		return true;
+	}
+
 	// m_pPlayer only inflicts half damage on self
 	if(From == m_pPlayer->GetCID())
 		Dmg = max(1, Dmg/2);
@@ -768,6 +884,12 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon)
 	
 		return false;
 	}
+ 	else
+ 	{
+		// lose flag on every damage
+ 		if (m_pBall && g_Config.m_SvfbBallDamageLose)
+			ReleaseBall();
+ 	}
 
 	if (Dmg > 2)
 		GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_LONG);
diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h
index b400905..4d3f4a2 100644
--- a/src/game/server/entities/character.h
+++ b/src/game/server/entities/character.h
@@ -54,24 +54,27 @@ public:
 	bool IncreaseHealth(int Amount);
 	bool IncreaseArmor(int Amount);
 	
+ 	//	flagball
+	class CBall* m_pBall;
+	int m_GoalCampTick; //	goal camp counter
+	int m_CampTick; //	camp counter
+	vec2 m_CampPos;
+	void ReleaseBall();
+	void DropBall();
+ 	void ThrowBall(vec2 direction);
+	void CaptureBall(CBall *);
+
+	int m_Health;
 	bool GiveWeapon(int Weapon, int Ammo);
-	void GiveNinja();
+	void GiveNinja(); // GiveNinja calls BecomeNinja and makes the sound
+	void BecomeNinja();
+	void RevokeNinja();
 	
 	void SetEmote(int Emote, int Tick);
 	
 	bool IsAlive() const { return m_Alive; }
 	class CPlayer *GetPlayer() { return m_pPlayer; }
-	
-private:
-	// player controlling this character
-	class CPlayer *m_pPlayer;
-	
-	bool m_Alive;
 
-	// weapon info
-	CEntity *m_apHitObjects[10];
-	int m_NumObjectsHit;
-	
 	struct WeaponStat
 	{
 		int m_AmmoRegenStart;
@@ -83,6 +86,17 @@ private:
 	
 	int m_ActiveWeapon;
 	int m_LastWeapon;
+	
+private:
+	// player controlling this character
+	class CPlayer *m_pPlayer;
+	
+	bool m_Alive;
+
+	// weapon info
+	CEntity *m_apHitObjects[10];
+	int m_NumObjectsHit;
+	
 	int m_QueuedWeapon;
 	
 	int m_ReloadTimer;
@@ -108,7 +122,6 @@ private:
 	
 	int m_DamageTakenTick;
 
-	int m_Health;
 	int m_Armor;
 
 	// ninja
diff --git a/src/game/server/entities/laser.cpp b/src/game/server/entities/laser.cpp
index 184702c..01c6e26 100644
--- a/src/game/server/entities/laser.cpp
+++ b/src/game/server/entities/laser.cpp
@@ -3,6 +3,8 @@
 #include <game/generated/protocol.h>
 #include <game/server/gamecontext.h>
 #include "laser.h"
+#include <game/server/gamemodes/fb.h>
+#include <engine/shared/config.h>
 
 CLaser::CLaser(CGameWorld *pGameWorld, vec2 Pos, vec2 Direction, float StartEnergy, int Owner)
 : CEntity(pGameWorld, CGameWorld::ENTTYPE_LASER)
@@ -28,11 +30,30 @@ bool CLaser::HitCharacter(vec2 From, vec2 To)
 
 	m_From = From;
 	m_Pos = At;
+	hit_ball(From, m_Pos);
 	m_Energy = -1;		
 	Hit->TakeDamage(vec2(0.f, 0.f), GameServer()->Tuning()->m_LaserDamage, m_Owner, WEAPON_RIFLE);
 	return true;
 }
 
+void CLaser::hit_ball(vec2 from, vec2 to) {
+ 	if (g_Config.m_SvfbLaserMomentum == 0) return;
+ 	for (int i = 0; i < FB_MAX_BALLS; ++i)
+ 	{
+ 		CBall *ball = static_cast<CGameControllerFB *>(GameServer()->m_pController)->m_apBalls[i];
+ 		if (!ball || ball->m_pCarryingCharacter) continue;
+ 		vec2 ball_pos = ball->m_Pos + vec2(g_Config.m_SvfbBallOffsetX, -g_Config.m_SvfbBallOffsetY);
+ 		if (distance(ball_pos, closest_point_on_line(from, to, ball_pos)) < g_Config.m_SvfbBallRadius)
+ 		{
+ 			ball->m_Vel += normalize(to - from) * g_Config.m_SvfbLaserMomentum * 0.1f;
+ 			ball->m_DropTick = Server()->Tick();
+ 			ball->m_pLastCarrierCharacter = GameServer()->m_apPlayers[m_Owner]->GetCharacter();
+ 			ball->m_LastCarrierTeam = GameServer()->m_apPlayers[m_Owner]->GetTeam();
+                        static_cast<CGameControllerFB *>(GameServer()->m_pController)->SetBallColor(ball, ball->m_LastCarrierTeam);
+ 		}
+ 	};
+}; 
+
 void CLaser::DoBounce()
 {
 	m_EvalTick = Server()->Tick();
@@ -50,6 +71,7 @@ void CLaser::DoBounce()
 	{
 		if(!HitCharacter(m_Pos, To))
 		{
+			hit_ball(m_Pos, To);
 			// intersected
 			m_From = m_Pos;
 			m_Pos = To;
@@ -74,6 +96,7 @@ void CLaser::DoBounce()
 	{
 		if(!HitCharacter(m_Pos, To))
 		{
+			hit_ball(m_Pos, To);
 			m_From = m_Pos;
 			m_Pos = To;
 			m_Energy = -1;
diff --git a/src/game/server/entities/laser.h b/src/game/server/entities/laser.h
index 91ba5df..2c38fe1 100644
--- a/src/game/server/entities/laser.h
+++ b/src/game/server/entities/laser.h
@@ -16,6 +16,7 @@ public:
 	
 protected:
 	bool HitCharacter(vec2 From, vec2 To);
+	void hit_ball(vec2 from, vec2 to);
 	void DoBounce();
 	
 private:
diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp
index a0c1c64..c60ac70 100644
--- a/src/game/server/gamecontext.cpp
+++ b/src/game/server/gamecontext.cpp
@@ -13,6 +13,7 @@
 #include "gamemodes/tdm.h"
 #include "gamemodes/ctf.h"
 #include "gamemodes/mod.h"
+#include "gamemodes/fb.h"
 
 enum
 {
@@ -380,6 +381,7 @@ void CGameContext::SendTuningParams(int ClientID)
 
 void CGameContext::OnTick()
 {
+
 	// check tuning
 	CheckPureTuning();
 
@@ -512,6 +514,18 @@ void CGameContext::OnClientEnter(int ClientID)
 	SendChat(-1, CGameContext::CHAT_ALL, aBuf); 
 
 	str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' team=%d", ClientID, Server()->ClientName(ClientID), m_apPlayers[ClientID]->GetTeam());
+	
+ 	if (str_comp(m_pController->m_pGameType, "FB") == 0 || str_comp(m_pController->m_pGameType, "iFB") == 0)
+ 	{
+ 		// Send MOD-version string
+ 		str_format(aBuf, sizeof (aBuf), "FlagBall version: %s", MOD_VERSION);
+ 		SendChatTarget(ClientID, aBuf);
+ 		
+ 		// Send welcome message
+ 		if (str_length(g_Config.m_SvfbWelcomeMessage))
+ 			SendChatTarget(ClientID, g_Config.m_SvfbWelcomeMessage);
+ 	}
+
 	Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
 
 	m_VoteUpdate = true;
@@ -943,7 +957,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 		
 		SendEmoticon(ClientID, pMsg->m_Emoticon);
 	}
-	else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused)
+	else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused && g_Config.m_SvfbSelfKill)
 	{
 		if(pPlayer->m_LastKill && pPlayer->m_LastKill+Server()->TickSpeed()*3 > Server()->Tick())
 			return;
@@ -1338,7 +1352,9 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/)
 	//players = new CPlayer[MAX_CLIENTS];
 
 	// select gametype
-	if(str_comp(g_Config.m_SvGametype, "mod") == 0)
+ 	if (str_comp(g_Config.m_SvGametype, "fb") == 0)
+ 		m_pController = new CGameControllerFB(this);
+	else if(str_comp(g_Config.m_SvGametype, "mod") == 0)
 		m_pController = new CGameControllerMOD(this);
 	else if(str_comp(g_Config.m_SvGametype, "ctf") == 0)
 		m_pController = new CGameControllerCTF(this);
diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp
index c5a9657..de3efd3 100644
--- a/src/game/server/gamecontroller.cpp
+++ b/src/game/server/gamecontroller.cpp
@@ -9,7 +9,6 @@
 #include "gamecontroller.h"
 #include "gamecontext.h"
 
-
 IGameController::IGameController(class CGameContext *pGameServer)
 {
 	m_pGameServer = pGameServer;
@@ -265,6 +264,7 @@ void IGameController::StartRound()
 	m_aTeamscore[TEAM_RED] = 0;
 	m_aTeamscore[TEAM_BLUE] = 0;
 	m_ForceBalanced = false;
+
 	char aBuf[256];
 	str_format(aBuf, sizeof(aBuf), "start round type='%s' teamplay='%d'", m_pGameType, m_GameFlags&GAMEFLAG_TEAMS);
 	GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
@@ -444,7 +444,9 @@ bool IGameController::IsForceBalanced()
 		return true;
 	}
 	else
+	{
 		return false;
+	}
 }
 
 bool IGameController::CanBeMovedOnBalance(int ClientID)
@@ -454,6 +456,7 @@ bool IGameController::CanBeMovedOnBalance(int ClientID)
 
 void IGameController::Tick()
 {
+
 	// do warmup
 	if(m_Warmup)
 	{
@@ -578,6 +581,7 @@ bool IGameController::IsTeamplay() const
 
 void IGameController::Snap(int SnappingClient)
 {
+
 	CNetObj_GameInfo *pGameInfoObj = (CNetObj_GameInfo *)Server()->SnapNewItem(NETOBJTYPE_GAMEINFO, 0, sizeof(CNetObj_GameInfo));
 	if(!pGameInfoObj)
 		return;
diff --git a/src/game/server/gamecontroller.h b/src/game/server/gamecontroller.h
index c999f84..d6391a4 100644
--- a/src/game/server/gamecontroller.h
+++ b/src/game/server/gamecontroller.h
@@ -59,9 +59,11 @@ protected:
 	
 	int m_GameFlags;
 	int m_UnbalancedTick;
+
 	bool m_ForceBalanced;
 	
 public:
+
 	const char *m_pGameType;
 
 	bool IsTeamplay() const;
diff --git a/src/game/server/gamemodes/fb.cpp b/src/game/server/gamemodes/fb.cpp
new file mode 100644
index 0000000..f6fdfcc
--- /dev/null
+++ b/src/game/server/gamemodes/fb.cpp
@@ -0,0 +1,545 @@
+#include <string.h>
+#include <engine/shared/config.h>
+#include <engine/server.h>
+#include <game/mapitems.h>
+#include <game/server/entities/character.h>
+#include <game/server/player.h>
+#include <game/server/gamecontext.h>
+#include <game/collision.h>
+#include "fb.h"
+
+CBall::CBall(CGameWorld *pGameWorld, int Team, vec2 Pos)
+: CFlag(pGameWorld, Team)
+{
+	m_StandPos = Pos;
+	m_Pos = Pos;
+}
+
+void CBall::Reset()
+{
+	GameServer()->CreateSoundGlobal(SOUND_CTF_RETURN);
+	CFlag::Reset();
+	m_pLastCarrierCharacter = NULL;
+	m_DropTick = 0;
+	m_IdleTick = -1;
+	m_LastCarrierTeam = !m_Team;
+}
+
+void CBall::Tick()
+{
+	//	update ball position
+	if (m_pCarryingCharacter)
+	{
+		m_Pos = m_pCarryingCharacter->m_Pos;
+	}
+	else if (!m_AtStand)
+	{
+		if (GameLayerClipped(m_Pos) || (m_IdleTick >= 0 && Server()->Tick() > m_IdleTick + Server()->TickSpeed() * g_Config.m_SvfbBallResetTime))
+			Reset();
+		else
+		{
+			// do ball physics
+			m_Vel.y += GameServer()->m_World.m_Core.m_Tuning.m_Gravity;
+			if (m_Vel.x > -0.1f && m_Vel.x < 0.1f)
+				m_Vel.x = 0.0f;
+			else if (m_Vel.x < 0)
+				m_Vel.x += 0.055f;
+			else
+				m_Vel.x -= 0.055f;
+
+			float vy = m_Vel.y;
+			GameServer()->Collision()->MoveBox(&m_Pos, &m_Vel, vec2(ms_PhysSize, ms_PhysSize), 0.5f);
+			if (m_Vel.x == 0 && (vy > 0) != (m_Vel.y > 0) && abs(m_Vel.y) < GameServer()->m_World.m_Core.m_Tuning.m_Gravity)
+			{
+				if (m_IdleTick == -1)
+					m_IdleTick = Server()->Tick();
+			}
+			else
+				m_IdleTick = -1;
+		}
+	}
+}
+
+CGameControllerFB::CGameControllerFB(class CGameContext *pGameServer) 
+: IGameController(pGameServer)
+{
+	m_apBalls[0] = NULL;
+	m_apBalls[1] = NULL;
+	m_pGameType = g_Config.m_SvfbInstagib ? "iFB" : "FB";
+	m_GameFlags = GAMEFLAG_TEAMS | GAMEFLAG_FLAGS;
+	m_apGoalPos[0] = vec2(0, 0);
+	m_apGoalPos[1] = vec2(0, 0);
+	m_NumGoals = 0;
+	GameServer()->Tuning()->m_LaserDamage = g_Config.m_SvfbInstagib ? 10 : 5;
+	
+}
+
+bool CGameControllerFB::OnEntity (int index, vec2 pos)
+{
+	
+	//	don't add pickups in instagib
+	if (strcmp (m_pGameType, "iFB") == 0 && index > ENTITY_FLAGSTAND_BLUE)
+		return false;
+	
+	if (IGameController::OnEntity (index, pos))
+		return true;
+	
+	//	add goal positions and balls
+	switch (index)
+	{
+		case ENTITY_SPAWN:
+			if (m_NumGoals < FB_MAX_GOALS)
+				m_apGoalPos[m_NumGoals++] = pos;
+			break;
+		case ENTITY_FLAGSTAND_RED:
+			if (!m_apBalls[TEAM_RED])
+				GameServer()->m_World.InsertEntity(m_apBalls[TEAM_RED] = new CBall(&GameServer()->m_World, TEAM_RED, pos));
+			break;
+		case ENTITY_FLAGSTAND_BLUE:
+			if (!m_apBalls[TEAM_BLUE])
+				GameServer()->m_World.InsertEntity(m_apBalls[TEAM_BLUE] = new CBall(&GameServer()->m_World, TEAM_BLUE, pos));
+			break;
+		default:
+			return false;
+	}
+	return true;
+	
+}
+
+int CGameControllerFB::OnCharacterDeath(class CCharacter *victim, class CPlayer *killer, int weaponid)
+{
+	
+	// do scoreing
+	if (weaponid == WEAPON_SELF || weaponid == WEAPON_WORLD)
+		victim->GetPlayer()->m_Score--;	// suicide or death-tile
+	else if (killer && weaponid != WEAPON_GAME)
+		{
+			if (IsTeamplay() && victim->GetPlayer()->GetTeam() == killer->GetTeam())
+				killer->m_Score--;	// teamkill
+			else
+				killer->m_Score++;	// normal kill
+		}
+
+	//	add fb-score and killing message flags
+	int had_flag = 0;
+	for (int i = 0; i < FB_MAX_BALLS; i++)
+	{
+		CBall *b = m_apBalls[i];
+		if (!b || !b->m_pCarryingCharacter)
+			continue;
+
+		if (killer && b->m_pCarryingCharacter == killer->GetCharacter())
+			had_flag |= 2;
+		if (b->m_pCarryingCharacter == victim)
+		{
+			victim->DropBall();
+
+			if (killer && killer->GetTeam() != victim->GetPlayer()->GetTeam())
+				killer->m_Score++;
+				
+			had_flag |= 1;
+		}
+	}
+
+	return had_flag;
+	
+}
+
+void CGameControllerFB::OnCharacterSpawn(class CCharacter *chr)
+{
+	
+	// default health
+	chr->m_Health = 10;
+	
+	if (strcmp (m_pGameType, "iFB") == 0)
+	{
+		// give instagib weapon
+		chr->m_aWeapons[WEAPON_RIFLE].m_Got = 1;
+		chr->m_aWeapons[WEAPON_RIFLE].m_Ammo = -1;
+		chr->m_ActiveWeapon = WEAPON_RIFLE;
+		chr->m_LastWeapon = WEAPON_RIFLE;
+	}
+	else
+	{
+		// give default weapons
+		chr->m_aWeapons[WEAPON_HAMMER].m_Got = 1;
+		chr->m_aWeapons[WEAPON_HAMMER].m_Ammo = -1;
+		chr->m_aWeapons[WEAPON_GUN].m_Got = 1;
+		chr->m_aWeapons[WEAPON_GUN].m_Ammo = 10;
+	}
+	
+}
+
+bool CGameControllerFB::HandleGoal (CBall *b, int goal)
+{
+	
+	CCharacter *const ch = b->m_pCarryingCharacter ? b->m_pCarryingCharacter : b->m_pLastCarrierCharacter;
+	CPlayer *const p = ch ? ch->GetPlayer() : NULL;
+	const int team = p ? p->GetTeam() : b->m_LastCarrierTeam;
+	const bool own_goal = team == goal;
+	const bool tee_goal = b->m_pCarryingCharacter;
+	
+	//	update scores
+	if (own_goal)
+	{
+		if (!g_Config.m_SvfbOwngoal)
+			return false;
+		
+		if (p)
+		{
+			p->m_Score -= g_Config.m_SvfbOwngoalPenalty;
+			p->m_NumOwngoals++;
+		
+			// send warning to user
+			char chat_msg[256];
+			str_format (chat_msg, sizeof (chat_msg), "!!! Hey %s, you scored an own-goal! Put the ball into the OTHER goal !!!", Server()->ClientName(p->m_ClientID));
+			GameServer()->SendChatTarget (p->m_ClientID, chat_msg);
+		}
+		// there's no sound like "wah...wah" ;)
+		GameServer()->CreateSoundGlobal(SOUND_NINJA_HIT); //SOUND_PLAYER_PAIN_LONG
+	}
+	else
+	{
+		if (p)
+			p->m_Score += tee_goal ? g_Config.m_SvfbScorePlayerTee : g_Config.m_SvfbScorePlayerBall;
+			
+		GameServer()->CreateSoundGlobal(SOUND_CTF_CAPTURE);
+	}
+	m_aTeamscore[goal ^ 1] += tee_goal ? g_Config.m_SvfbScoreTeamTee : g_Config.m_SvfbScoreTeamBall;
+		
+	// let the tee die if it jumped into goal... or when dumb own-goal
+	if (p && (tee_goal || own_goal))
+		p->KillCharacter (WEAPON_GAME);
+	b->Reset();
+	
+	// Cut off long nicknames... the message would jut out on screen!
+	const int nick_length = 18;
+	char nick[64] = {0};
+	str_format (nick, sizeof (nick), "%s", p ? Server()->ClientName(p->m_ClientID) : "player left");
+	if (str_length (nick) > nick_length)
+	{
+		nick[nick_length] = 0;
+		str_append (nick, "...", sizeof (nick));
+	}
+
+	// Build broadcast-message
+	char bc_msg[512] = {0};
+	str_format (bc_msg, sizeof (bc_msg), "%s team (%s) scored with %s!", (goal ^ 1) == 0 ? "Red" : "Blue",
+		nick, tee_goal ? "tee": "ball");
+
+	// wired workaround for multiline broadcast-message center alignment
+	// FIXME: can be done smarter!
+	if (own_goal)
+	{
+		char line2[] = "\nPwned... that was an own-goal!";
+		const int fillup = 2 * (str_length (bc_msg) - (str_length (line2) - 1));
+		str_append (bc_msg, line2, sizeof (bc_msg));
+
+		if (fillup > 0)
+		{
+			char *cur_pos = bc_msg + str_length (bc_msg);
+			for (int l = 0; l < fillup; l++)
+				*cur_pos++ = ' ';
+			*cur_pos = 0;
+		}
+	}
+	// send everyone the scoring-message
+	GameServer()->SendBroadcast(bc_msg, -1);
+
+	// kick unteachable player from server
+	if (g_Config.m_SvfbOwngoalKick && p && p->m_NumOwngoals >= g_Config.m_SvfbOwngoalKick)
+	{
+		char chat_msg[256];
+		str_format (chat_msg, sizeof (chat_msg), "%s was automatically kicked. Cause: Scored too many own-goals (%d).",
+			Server()->ClientName(p->m_ClientID), g_Config.m_SvfbOwngoalKick);
+			
+		Server()->Kick(p->m_ClientID,
+			"You scored too many own-goals! Please play the "
+			"game as it is supposed to be. Thank you!");
+		
+		GameServer()->SendChat(-1, CGameContext::CHAT_ALL, chat_msg);
+	}
+
+	return true;
+	
+}
+
+void CGameControllerFB::OnDisconnect (CPlayer *const p)
+{
+	CCharacter* ch = p->GetCharacter();
+	for (int i = 0; i < FB_MAX_BALLS; ++i)
+	{
+		if (m_apBalls[i])
+		{
+			if (m_apBalls[i]->m_pCarryingCharacter == ch)
+				ch->ReleaseBall();
+			if (m_apBalls[i]->m_pLastCarrierCharacter == ch)
+				m_apBalls[i]->m_pLastCarrierCharacter = NULL;
+		}
+	}
+}
+
+template <typename T> void swap(T& x, T& y)
+{
+	T z = x;
+	x = y;
+	y = z;
+}
+
+void CGameControllerFB::SetBallColor(CBall *&ball, int team)
+{
+	/* The flag color cannot be changed by mere assignment to m_Team. When
+	 * someone carries a repainted flag, it causes lags due to the way flag
+	 * position interpolation is implemented in CItems::RenderFlag in
+	 * game/client/components/items.cpp. A hackish workaround is to swap
+	 * the flags when the other color is requested, but we should take
+	 * special care for the maps where both flags are available */
+
+	if (!ball || ball->m_Team == team) return;
+	CBall *b = m_apBalls[team];
+	if (!b->m_AtStand) return;
+
+	swap(b->m_AtStand,               ball->m_AtStand);
+	swap(b->m_StandPos,              ball->m_StandPos);
+	swap(b->m_Pos,                   ball->m_Pos);
+	swap(b->m_Vel,                   ball->m_Vel);
+	swap(b->m_pCarryingCharacter,    ball->m_pCarryingCharacter);
+	swap(b->m_pLastCarrierCharacter, ball->m_pLastCarrierCharacter);
+	swap(b->m_LastCarrierTeam,       ball->m_LastCarrierTeam);
+	swap(b->m_GrabTick,              ball->m_GrabTick);
+	swap(b->m_DropTick,              ball->m_DropTick);
+
+	ball = b;
+}
+
+void CGameControllerFB::GrantBall(CCharacter *ch, CBall *b)
+{
+	int team = ch->GetPlayer()->GetTeam();
+	if (b->m_AtStand)
+	{
+		m_aTeamscore[team] += g_Config.m_SvfbScoreTeamStand;
+		ch->GetPlayer()->m_Score += g_Config.m_SvfbScorePlayerStand;
+		b->m_AtStand = 0;
+	}
+	b->m_pCarryingCharacter = ch;
+	b->m_Pos = ch->m_Pos;
+
+	if (g_Config.m_SvfbLaserMomentum) 
+		SetBallColor(b, team);
+
+	ch->m_pBall = b;
+
+	for (int c = 0; c < MAX_CLIENTS; ++c)
+	{
+		CPlayer *p = GameServer()->m_apPlayers[c];
+		if (!p)
+			continue;
+		GameServer()->CreateSoundGlobal(p->GetTeam() == team ? SOUND_CTF_GRAB_PL : SOUND_CTF_GRAB_EN, p->GetCID());
+	}
+
+	ch->BecomeNinja();
+}
+
+
+void CGameControllerFB::Tick()
+{
+	
+	IGameController::Tick();
+	DoTeamScoreWincheck();
+
+	if (m_GameOverTick == -1 && m_RoundStartTick != Server()->Tick())
+	{
+		
+		for (int i = 0; i < MAX_CLIENTS; ++i)
+		{
+			if (!GameServer()->m_apPlayers[i]) continue;
+
+			CCharacter *ch = GameServer()->m_apPlayers[i]->GetCharacter();
+			if (!ch || !ch->IsAlive())
+				continue;
+
+			// Check for a goal-camper
+			if (g_Config.m_SvfbGoalcamp)
+			{
+				bool in_range = false;
+				for (int goal = 0; goal < m_NumGoals; ++goal)
+				{
+					if (distance (ch->m_Pos, m_apGoalPos[goal]) <
+						g_Config.m_SvfbGoalsize * static_cast<float> (g_Config.m_SvfbGoalcampFactor / 10.0f))  //	1.5f
+					{
+						// if in range, count up 2 ticks
+						ch->m_GoalCampTick += 2;
+						in_range = true;
+						break;
+					}
+				}
+		
+				if (!in_range)
+				{
+					// if out of range, count down just 1 tick again (slower)
+					if (ch->m_GoalCampTick)
+						ch->m_GoalCampTick--;
+				}
+				else
+				{	
+					//	kill goal camping player
+					if ((ch->m_GoalCampTick >> 1) >= Server()->TickSpeed() * g_Config.m_SvfbGoalcampTime)
+					{
+						GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_GAME);
+				
+						char chat_msg[128];
+						str_format (chat_msg, sizeof (chat_msg), "%s was caught camping near a goal...",
+							Server()->ClientName(GameServer()->m_apPlayers[i]->m_ClientID));
+						GameServer()->SendChat(-1, -2, chat_msg);
+						continue;
+					}
+				}
+			}
+
+			// anti-camping
+			if (g_Config.m_SvfbCampMaxtime)
+			{
+				if (distance (ch->m_Pos, ch->m_CampPos) <= g_Config.m_SvfbCampThreshold && !ch->m_pBall)
+				{
+					// if in range, count up 2 ticks
+					ch->m_CampTick += 2;
+				}
+				else
+				{
+					// if out of range, count down just 1 tick again (slower)
+					if (ch->m_CampTick)
+						ch->m_CampTick--;
+					else
+						ch->m_CampPos = ch->m_Pos;
+				}
+	
+				//	kill camping player
+				if ((ch->m_CampTick >> 1) >= Server()->TickSpeed () * g_Config.m_SvfbCampMaxtime)
+				{
+					GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_GAME);
+					GameServer()->SendChat(-1, -2, "I'm a bloody camper");
+					continue;
+				}
+			}
+		}
+
+		//	update balls
+		for (int bi =  0; bi < FB_MAX_BALLS; ++bi)
+		{
+			CBall *b = m_apBalls[bi];
+
+			if (!b)
+				continue;
+
+			//	check/handle goal
+			bool is_goal = false;
+			for (int g = 0; g < m_NumGoals; g++)
+			{
+				if (distance(b->m_Pos, m_apGoalPos[g]) < g_Config.m_SvfbGoalsize)
+				{
+					is_goal = HandleGoal(b, g);
+					break;
+				}
+			}
+			if (is_goal)
+				continue;
+
+			if (b->m_pCarryingCharacter)
+			{	//	ball is carried by player
+				//	warn ball-carrying player once when he is near his own goal
+				CCharacter *ch = b->m_pCarryingCharacter;
+				CPlayer *p = ch->GetPlayer();
+				int t = p->GetTeam();
+				if (g_Config.m_SvfbOwngoalWarn && !p->m_OwngoalWarned && t < m_NumGoals && distance(ch->m_Pos, m_apGoalPos[t]) < g_Config.m_SvfbGoalsize * 5)
+				{
+					GameServer()->SendBroadcast(
+						"Attention! This is your team's goal\n"
+						"you are approaching. You probably\n"
+						"want to go to the other side!",
+						p->m_ClientID);
+
+					// play the server-chat sound
+					GameServer()->CreateSound(ch->m_Pos, SOUND_CHAT_SERVER, CmaskOne(p->m_ClientID));
+					p->m_OwngoalWarned = true;
+				}
+			}
+			else
+			{	//	ball is carried by none
+				//	small delay for throwing ball a bit away before fetching again
+				if (b->m_AtStand || Server()->Tick() >= b->m_DropTick + Server()->TickSpeed() * 0.2f)
+				{
+					//	find all players that can grab the ball
+					CCharacter *close_characters[MAX_CLIENTS];
+					int max_num = GameServer()->m_World.FindEntities(b->m_Pos, b->ms_PhysSize, (CEntity**)close_characters, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER);
+					int curr_num = 0;
+					for (int i = 0; i < max_num; ++i)
+					{
+						if (!close_characters[i]->IsAlive() || close_characters[i]->GetPlayer()->GetTeam() == -1 || GameServer()->Collision()->IntersectLine(b->m_Pos, close_characters[i]->m_Pos, NULL, NULL) ||
+							// don't take flag if already have one (might be useful with two flags)
+							m_apBalls[bi ^ 1]->m_pCarryingCharacter == close_characters[i]) 
+							continue;
+						close_characters[curr_num++] = close_characters[i];
+					}
+					
+					if (!curr_num)
+						continue;
+
+					GrantBall(close_characters[Server()->Tick() % curr_num], b);
+				}
+			}
+		}
+	}
+}
+
+void CGameControllerFB::Snap(int SnappingClient)
+{
+	
+	IGameController::Snap(SnappingClient);
+
+	CNetObj_GameData *pGameDataObj = (CNetObj_GameData *)Server()->SnapNewItem(NETOBJTYPE_GAMEDATA, 0, sizeof(CNetObj_GameData));
+	if(!pGameDataObj)
+		return;
+
+	pGameDataObj->m_TeamscoreRed = m_aTeamscore[TEAM_RED];
+	pGameDataObj->m_TeamscoreBlue = m_aTeamscore[TEAM_BLUE];
+	
+	if(m_apBalls[TEAM_RED])
+	{
+		if(m_apBalls[TEAM_RED]->m_AtStand)
+		{
+			pGameDataObj->m_FlagCarrierRed = FLAG_ATSTAND;
+		}
+		else if(m_apBalls[TEAM_RED]->m_pCarryingCharacter)
+		{
+			pGameDataObj->m_FlagCarrierRed = m_apBalls[TEAM_RED]->m_pCarryingCharacter->GetPlayer()->GetCID();
+		}
+		else
+		{
+			pGameDataObj->m_FlagCarrierRed = FLAG_TAKEN;
+		}
+	}
+	else
+	{
+		pGameDataObj->m_FlagCarrierRed = FLAG_MISSING;	
+	}
+	
+	if(m_apBalls[TEAM_BLUE])
+	{
+		if(m_apBalls[TEAM_BLUE]->m_AtStand)
+		{
+			pGameDataObj->m_FlagCarrierBlue = FLAG_ATSTAND;
+		}
+		else if(m_apBalls[TEAM_BLUE]->m_pCarryingCharacter)
+		{
+			pGameDataObj->m_FlagCarrierBlue = m_apBalls[TEAM_BLUE]->m_pCarryingCharacter->GetPlayer()->GetCID();
+		}
+		else
+		{
+			pGameDataObj->m_FlagCarrierBlue = FLAG_TAKEN;
+		}
+	}
+	else
+	{
+		pGameDataObj->m_FlagCarrierBlue = FLAG_MISSING;
+	}
+}
diff --git a/src/game/server/gamemodes/fb.h b/src/game/server/gamemodes/fb.h
new file mode 100644
index 0000000..25d75ef
--- /dev/null
+++ b/src/game/server/gamemodes/fb.h
@@ -0,0 +1,45 @@
+#ifndef GAME_SERVER_GAMEMODES_FB_H
+#define GAME_SERVER_GAMEMODES_FB_H
+
+#include <game/server/gamecontroller.h>
+#include <game/server/entities/flag.h>
+
+enum {
+	FB_MAX_GOALS = 2,
+	FB_MAX_BALLS = 2
+};
+
+class CBall: public CFlag
+{
+public:
+	CCharacter* m_pLastCarrierCharacter;
+	int m_LastCarrierTeam;
+	int m_IdleTick;
+
+	CBall(CGameWorld *pGameWorld, int Team, vec2 Pos);
+
+	virtual void Reset();
+	virtual void Tick();
+};
+
+class CGameControllerFB : public IGameController
+{
+public:
+	class CBall *m_apBalls[FB_MAX_BALLS];
+	vec2 m_apGoalPos[FB_MAX_GOALS];
+	int m_NumGoals;
+
+	CGameControllerFB(class CGameContext *pGameServer);
+	virtual void Tick();
+	
+	virtual bool OnEntity (int index, vec2 pos);
+	virtual int OnCharacterDeath (class CCharacter *victim, class CPlayer *killer, int weapon);
+	virtual void OnCharacterSpawn (class CCharacter *chr);
+	virtual void GrantBall(CCharacter *, CBall *);
+	virtual void SetBallColor(CBall *&, int team);
+	virtual bool HandleGoal (CBall *, int goal);
+	virtual void OnDisconnect (CPlayer *const p);
+	virtual void Snap(int SnappingClient);
+};
+
+#endif
diff --git a/src/game/server/gameworld.cpp b/src/game/server/gameworld.cpp
index 8fffabc..4c74ad6 100644
--- a/src/game/server/gameworld.cpp
+++ b/src/game/server/gameworld.cpp
@@ -104,6 +104,7 @@ void CGameWorld::RemoveEntity(CEntity *pEnt)
 //
 void CGameWorld::Snap(int SnappingClient)
 {
+
 	for(int i = 0; i < NUM_ENTTYPES; i++)
 		for(CEntity *pEnt = m_apFirstEntityTypes[i]; pEnt; )
 		{
@@ -149,6 +150,7 @@ void CGameWorld::RemoveEntities()
 
 void CGameWorld::Tick()
 {
+
 	if(m_ResetRequested)
 		Reset();
 
diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp
index cf0e668..770a426 100644
--- a/src/game/server/player.cpp
+++ b/src/game/server/player.cpp
@@ -4,6 +4,9 @@
 #include <engine/shared/config.h>
 #include "player.h"
 
+#include <string.h>
+#include "gamemodes/fb.h"
+
 
 MACRO_ALLOC_POOL_ID_IMPL(CPlayer, MAX_CLIENTS)
 
@@ -17,6 +20,10 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, int Team)
 	m_ScoreStartTick = Server()->Tick();
 	Character = 0;
 	this->m_ClientID = ClientID;
+	
+ 	m_NumOwngoals = 0;
+ 	m_OwngoalWarned = false;
+
 	m_Team = GameServer()->m_pController->ClampTeam(Team);
 	m_SpectatorID = SPEC_FREEVIEW;
 	m_LastActionTick = Server()->Tick();
@@ -146,6 +153,11 @@ void CPlayer::OnDisconnect(const char *pReason)
 
 	if(Server()->ClientIngame(m_ClientID))
 	{
+		//	update leaving player in gamecontroller (flagball)
+		if (str_comp(GameServer()->m_pController->m_pGameType, "FB")==0)
+		{
+			static_cast<CGameControllerFB *> (GameServer()->m_pController)->OnDisconnect(this);
+		}
 		char aBuf[512];
 		if(pReason && *pReason)
 			str_format(aBuf, sizeof(aBuf),  "'%s' has left the game (%s)", Server()->ClientName(m_ClientID), pReason);
@@ -233,6 +245,9 @@ void CPlayer::SetTeam(int Team)
 	
 	GameServer()->m_pController->OnPlayerInfoChange(GameServer()->m_apPlayers[m_ClientID]);
 
+ 	//update active player (idle kicking)
+ 	m_LastActionTick = Server()->Tick();
+
 	if(Team == TEAM_SPECTATORS)
 	{
 		// update spectator modes
diff --git a/src/game/server/player.h b/src/game/server/player.h
index 50f1c1a..c9c1dcb 100644
--- a/src/game/server/player.h
+++ b/src/game/server/player.h
@@ -32,6 +32,10 @@ public:
 	void OnPredictedInput(CNetObj_PlayerInput *NewInput);
 	void OnDisconnect(const char *pReason);
 	
+ 	//	flagball
+	int m_NumOwngoals; //	counter for own-goals
+ 	bool m_OwngoalWarned;	//	own goal warning (only shown once)
+	
 	void KillCharacter(int Weapon = WEAPON_GAME);
 	CCharacter *GetCharacter();
 	
@@ -95,16 +99,16 @@ public:
 		int m_Max;	
 	} m_Latency;
 	
-private:
+
+//private:
 	CCharacter *Character;
 	CGameContext *m_pGameServer;
-	
+	int m_ClientID;
 	CGameContext *GameServer() const { return m_pGameServer; }
 	IServer *Server() const;
 	
 	//
 	bool m_Spawning;
-	int m_ClientID;
 	int m_Team;
 };
 
diff --git a/src/game/variables.h b/src/game/variables.h
index c4a37fa..abb0d51 100644
--- a/src/game/variables.h
+++ b/src/game/variables.h
@@ -62,7 +62,7 @@ MACRO_CONFIG_INT(SvRoundsPerMap, sv_rounds_per_map, 1, 1, 100, CFGFLAG_SERVER, "
 MACRO_CONFIG_INT(SvPowerups, sv_powerups, 1, 0, 1, CFGFLAG_SERVER, "Allow powerups like ninja")
 MACRO_CONFIG_INT(SvScorelimit, sv_scorelimit, 20, 0, 1000, CFGFLAG_SERVER, "Score limit (0 disables)")
 MACRO_CONFIG_INT(SvTimelimit, sv_timelimit, 0, 0, 1000, CFGFLAG_SERVER, "Time limit in minutes (0 disables)")
-MACRO_CONFIG_STR(SvGametype, sv_gametype, 32, "dm", CFGFLAG_SERVER, "Game type (dm, tdm, ctf)")
+MACRO_CONFIG_STR(SvGametype, sv_gametype, 32, "fb", CFGFLAG_SERVER, "Game type (dm, tdm, ctf)")
 MACRO_CONFIG_INT(SvTournamentMode, sv_tournament_mode, 0, 0, 1, CFGFLAG_SERVER, "Tournament mode. When enabled, players joins the server as spectator")
 MACRO_CONFIG_INT(SvSpamprotection, sv_spamprotection, 1, 0, 1, CFGFLAG_SERVER, "Spam protection")
 
@@ -78,6 +78,37 @@ MACRO_CONFIG_INT(SvVoteKick, sv_vote_kick, 1, 0, 1, CFGFLAG_SERVER, "Allow votin
 MACRO_CONFIG_INT(SvVoteKickMin, sv_vote_kick_min, 0, 0, MAX_CLIENTS, CFGFLAG_SERVER, "Minimum number of players required to start a kick vote")
 MACRO_CONFIG_INT(SvVoteKickBantime, sv_vote_kick_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time to ban a player if kicked by vote. 0 makes it just use kick")
 
+/*	flagball	*/
+MACRO_CONFIG_INT(SvfbBallDamageLose, sv_fb_ball_damage_lose, 1, 0, 1, CFGFLAG_SERVER, "Turns on/off turnover on any damage (0=off, 1=on (default=1)).")
+MACRO_CONFIG_INT(SvfbBallResetTime, sv_fb_ball_reset_time, 30, 1, 500, CFGFLAG_SERVER, "Number of seconds needed to reset an unused ball (default=30).")
+MACRO_CONFIG_INT(SvfbBallVelocity, sv_fb_ball_velocity, 207, 10, 3000, CFGFLAG_SERVER, "Velocity of the ball after it got shot (value/10.0 (default=207)).")
+MACRO_CONFIG_INT(SvfbCampMaxtime, sv_fb_camp_maxtime, 0, 0, 100, CFGFLAG_SERVER, "Number of seconds allowed lingering at the same place (0=off (default=0)).")
+MACRO_CONFIG_INT(SvfbCampThreshold, sv_fb_camp_threshold, 200, 64, 1000, CFGFLAG_SERVER, "Threshold for anti-camp distance (default=200).")
+MACRO_CONFIG_INT(SvfbDirectPass, sv_fb_direct_pass, 1, 0, 1, CFGFLAG_SERVER, "Turns on/off direct-passing of ball with hook-key (0=off, 1=on (default=1)).")
+MACRO_CONFIG_INT(SvfbDirectPassDistance, sv_fb_direct_pass_distance, 380, 32, 3200, CFGFLAG_SERVER, "Maximum direct-passing distance (default=380).")
+MACRO_CONFIG_INT(SvfbBallOffsetX, sv_fb_ball_offset_x, 0, 0, 1000, CFGFLAG_SERVER, "X offset of the hookable center of the ball with respect to the lower left corner of the image (default=0)")
+MACRO_CONFIG_INT(SvfbBallOffsetY, sv_fb_ball_offset_y, 38, 0, 1000, CFGFLAG_SERVER, "Y offset of the hookable center of the ball with respect to the lower left corner of the image (default=38)")
+MACRO_CONFIG_INT(SvfbBallRadius, sv_fb_ball_radius, 40, 0, 1000, CFGFLAG_SERVER, "Flag hookable radius (default=40)")
+MACRO_CONFIG_INT(SvfbLaserMomentum, sv_fb_laser_momentum, 207, -3000, 3000, CFGFLAG_SERVER, "Momentum passed to a flag when it is hit by laser (default=207)")
+MACRO_CONFIG_INT(SvfbGoalsize, sv_fb_goalsize, 64, 32, 500, CFGFLAG_SERVER, "Radius defining goal (default=64).")
+MACRO_CONFIG_INT(SvfbGoalcamp, sv_fb_goalcamp, 1, 0, 1, CFGFLAG_SERVER, "Turns on/off goal camp protection (0=off, 1=on (default=1)).")
+MACRO_CONFIG_INT(SvfbGoalcampTime, sv_fb_goalcamp_time, 3, 1, 600, CFGFLAG_SERVER, "Number of seconds allowed lingering near a goal (default=3).")
+MACRO_CONFIG_INT(SvfbGoalcampFactor, sv_fb_goalcamp_factor, 40, 10, 100, CFGFLAG_SERVER, "Goal camp protection radius (value/10.0*sv_fb_goalsize (default=40)).")
+MACRO_CONFIG_INT(SvfbHookBall, sv_fb_hook_ball, 1, 0, 1, CFGFLAG_SERVER, "Turns on/off the possibily to capture the ball by hook (0=off, 1=on (default=1))")
+MACRO_CONFIG_INT(SvfbInstagib, sv_fb_instagib, 1, 0, 1, CFGFLAG_SERVER, "Turns on/off instagib modification (0=off, 1=on (default=1)).")
+MACRO_CONFIG_INT(SvfbOwngoal, sv_fb_owngoal, 0, 0, 1, CFGFLAG_SERVER, "Turns on/off own goals (0=off, 1=on (default=0)).")
+MACRO_CONFIG_INT(SvfbOwngoalKick, sv_fb_owngoal_kick, 2, 0, 20, CFGFLAG_SERVER, "Number of own goals allowed before kicking the player (0=infinite (default=2)).")
+MACRO_CONFIG_INT(SvfbOwngoalPenalty, sv_fb_owngoal_penalty, 30, 0, 999, CFGFLAG_SERVER, "Negative score for own goal player (default=30).")
+MACRO_CONFIG_INT(SvfbOwngoalWarn, sv_fb_owngoal_warn, 0, 0, 1, CFGFLAG_SERVER, "Turns on/off warning when player with ball is near own goal (0=off, 1=on (default=0)).")
+MACRO_CONFIG_INT(SvfbScorePlayerBall, sv_fb_score_player_ball, 5, 0, 100, CFGFLAG_SERVER, "Player score on ball-goal (default=5).")
+MACRO_CONFIG_INT(SvfbScorePlayerStand, sv_fb_score_player_stand, 0, 0, 10, CFGFLAG_SERVER, "Player score for taking ball from stand (default=0).")
+MACRO_CONFIG_INT(SvfbScorePlayerTee, sv_fb_score_player_tee, 10, 0, 100, CFGFLAG_SERVER, "Player-score on tee-goal (default=10).")
+MACRO_CONFIG_INT(SvfbScoreTeamBall, sv_fb_score_team_ball, 50, 1, 100, CFGFLAG_SERVER, "Team-score on ball-goal (default=50).")
+MACRO_CONFIG_INT(SvfbScoreTeamStand, sv_fb_score_team_stand, 0, 0, 10, CFGFLAG_SERVER, " Team score for taking ball from stand (default=0).")
+MACRO_CONFIG_INT(SvfbScoreTeamTee, sv_fb_score_team_tee, 100, 1, 100, CFGFLAG_SERVER, "Team-score on tee-goal (default=100).")
+MACRO_CONFIG_STR(SvfbWelcomeMessage, sv_fb_welcome_message, 512, "", CFGFLAG_SERVER, "Message to display when clients join (default="").")
+MACRO_CONFIG_INT(SvfbSelfKill, sv_fb_self_kill, 0, 0, 1, CFGFLAG_SERVER, "Allow self kill");
+
 // debug
 #ifdef CONF_DEBUG // this one can crash the server if not used correctly
 	MACRO_CONFIG_INT(DbgDummies, dbg_dummies, 0, 0, 15, CFGFLAG_SERVER, "")
diff --git a/src/game/version.h b/src/game/version.h
index 8cf1a7c..f8f4c50 100644
--- a/src/game/version.h
+++ b/src/game/version.h
@@ -5,4 +5,6 @@
 #include "generated/nethash.c"
 #define GAME_VERSION "0.6 trunk"
 #define GAME_NETVERSION "0.6 " GAME_NETVERSION_HASH
+/*	FlagBall-MOD version	*/
+#define MOD_VERSION "0.2.0-beta"
 #endif
