diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp
index 9df81e4..d9d0fd2 100644
--- a/src/game/server/entities/character.cpp
+++ b/src/game/server/entities/character.cpp
@@ -61,10 +61,10 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos)
 	m_LastWeapon = WEAPON_HAMMER;
 	m_QueuedWeapon = -1;
 	
- 	ball = NULL;
- 	goal_camp_tick = 0;
- 	camp_tick = 0;
- 	camp_pos = Pos;
+ 	m_pBall = NULL;
+	m_GoalCampTick = 0;
+ 	m_CampTick = 0;
+ 	m_CampPos = Pos;
 	
 	m_pPlayer = pPlayer;
 	m_Pos = Pos;
@@ -118,7 +118,7 @@ bool CCharacter::IsGrounded()
 
 void CCharacter::HandleNinja()
 {
-	if(m_ActiveWeapon != WEAPON_NINJA || ball)
+	if(m_ActiveWeapon != WEAPON_NINJA || m_pBall)
 		return;
 	
 	vec2 Direction = normalize(vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY));
@@ -126,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;
 	}
 	
@@ -197,49 +192,37 @@ 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();
 }
 
-//	handle ball as weapon
-void CCharacter::ShootBall(vec2 direction)
+void CCharacter::DropBall()
 {
- 	if (!ball) return;
- 
- 	//	drop ball
- 	GameServer()->CreateSound(m_Pos, SOUND_CTF_DROP);
- 	ball->drop_tick = Server()->Tick();
- 	ball->last_carrier = m_pPlayer;
- 	ball->last_carrier_team = m_pPlayer->GetTeam();
- 	ball->carrier = 0;
-	ball->vel = direction;
-    ball = NULL;
- 
- 	// stop ninja-ball-mode
- 	m_aWeapons[WEAPON_NINJA].m_Got = false;
- 	m_ActiveWeapon = m_LastWeapon;
- 	if (m_ActiveWeapon == WEAPON_NINJA)
- 		m_ActiveWeapon = WEAPON_GUN;
- 	SetWeapon(m_ActiveWeapon);
+	m_pBall->m_Vel = vec2(0, 0);
+	ReleaseBall();
 }
- 
-void CCharacter::CaptureBall(BALL* b) 
+
+void CCharacter::ThrowBall(vec2 direction)
 {
- 	ball = b;
- 	b->carrier = this;
- 	b->last_carrier_team = m_pPlayer->GetTeam();
- 	b->m_Pos = m_Core.m_Pos;
- 	b->at_stand = 0;
- 
- 	if (m_pPlayer->GetTeam() == b->team)
- 		GameServer()->CreateSound(m_Pos, SOUND_CTF_GRAB_EN);
- 	else
- 		GameServer()->CreateSound(m_Pos, SOUND_CTF_GRAB_PL);
- 
- 	//      switch to ninja-ball-mode
- 	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;
+	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()
@@ -458,9 +441,9 @@ void CCharacter::FireWeapon()
 		
 		case WEAPON_NINJA:
 		{			
- 			if (ball)
+ 			if (m_pBall)
  			{
- 				ShootBall(normalize (vec2 (m_LatestInput.m_TargetX, m_LatestInput.m_TargetY)) *
+ 				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;
@@ -545,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;
@@ -606,7 +603,7 @@ void CCharacter::Tick()
 	m_Core.Tick(true);
 	
     // direct pass of ball
- 	if (g_Config.m_SvfbDirectPass && ball && m_Core.m_TriggeredEvents & COREEVENT_HOOK_ATTACH_PLAYER && m_Core.m_HookedPlayer != -1)
+ 	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);
@@ -616,10 +613,9 @@ void CCharacter::Tick()
 
  		if (catcher)
  		{
-
- 			BALL* b = ball;
- 			ShootBall(vec2(0, 0));
- 			catcher->CaptureBall(b);
+			CBall *ball = m_pBall;
+			ReleaseBall();
+			catcher->CaptureBall(ball);
  
  			// release hook
  			m_Core.m_HookedPlayer = -1;
@@ -629,19 +625,19 @@ void CCharacter::Tick()
  	};
  
  	// hook the flag
- 	if (g_Config.m_SvfbHookBall && !ball && (m_Core.m_HookState == HOOK_FLYING || m_Core.m_TriggeredEvents & (COREEVENT_HOOK_ATTACH_GROUND + COREEVENT_HOOK_HIT_NOHOOK)))
+ 	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
- 		BALL* closest_ball = NULL;
+ 		CBall *closest_ball = NULL;
  		for (int i = 0; i < FB_MAX_BALLS; ++i)
  		{
- 			BALL* b = static_cast<CGameControllerFB *>(GameServer()->m_pController)->balls[i];
- 			if (b && !b->carrier)
+ 			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(g_Config.m_SvfbBallOffsetX, -g_Config.m_SvfbBallOffsetY);
+ 				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)))
@@ -815,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);
@@ -885,8 +887,8 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon)
  	else
  	{
 		// lose flag on every damage
- 		if (ball && g_Config.m_SvfbBallDamageLose)
- 			ShootBall(vec2(0.0f,3.0f) * 3.75f);
+ 		if (m_pBall && g_Config.m_SvfbBallDamageLose)
+			ReleaseBall();
  	}
 
 	if (Dmg > 2)
diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h
index 7bc5f64..4d3f4a2 100644
--- a/src/game/server/entities/character.h
+++ b/src/game/server/entities/character.h
@@ -55,16 +55,20 @@ public:
 	bool IncreaseArmor(int Amount);
 	
  	//	flagball
-	class BALL* ball;
- 	int goal_camp_tick;	//	goal camp counter
- 	int camp_tick;	//	camp counter
- 	vec2 camp_pos;
- 	void ShootBall (vec2 direction);
- 	void CaptureBall(BALL* ball);
+	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);
 	
diff --git a/src/game/server/entities/laser.cpp b/src/game/server/entities/laser.cpp
index 56da037..01c6e26 100644
--- a/src/game/server/entities/laser.cpp
+++ b/src/game/server/entities/laser.cpp
@@ -40,15 +40,16 @@ void CLaser::hit_ball(vec2 from, vec2 to) {
  	if (g_Config.m_SvfbLaserMomentum == 0) return;
  	for (int i = 0; i < FB_MAX_BALLS; ++i)
  	{
- 		BALL* ball = static_cast<CGameControllerFB *>(GameServer()->m_pController)->balls[i];
- 		if (!ball || ball->carrier) continue;
+ 		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->vel += normalize(to - from) * g_Config.m_SvfbLaserMomentum * 0.1f;
- 			ball->drop_tick = Server()->Tick();
- 			ball->last_carrier = GameServer()->m_apPlayers[m_Owner];
- 			ball->last_carrier_team = GameServer()->m_apPlayers[m_Owner]->GetTeam();
+ 			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);
  		}
  	};
 }; 
diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp
index 72e56ce..c60ac70 100644
--- a/src/game/server/gamecontext.cpp
+++ b/src/game/server/gamecontext.cpp
@@ -515,10 +515,10 @@ void CGameContext::OnClientEnter(int ClientID)
 
 	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)
+ 	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-MOD version: %s", MOD_VERSION);
+ 		str_format(aBuf, sizeof (aBuf), "FlagBall version: %s", MOD_VERSION);
  		SendChatTarget(ClientID, aBuf);
  		
  		// Send welcome message
@@ -615,15 +615,6 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 		}
 		
 		SendChat(ClientID, Team, pMsg->m_pMessage);
-		
-		if(!str_comp(pMsg->m_pMessage, "/info"))
-		{
-			SendChatTarget(ClientID, "Flagball Mod 0.1.17.2 by Nilaya\nContact: johnb820@gmail.com");
-		}
-		else if(!str_comp(pMsg->m_pMessage, "/help"))
-		{
-			SendChatTarget(ClientID, "Score points by putting the flag in the other team's goal.");
-		}
 	}
 	else if(MsgID == NETMSGTYPE_CL_CALLVOTE)
 	{
@@ -966,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;
diff --git a/src/game/server/gamemodes/fb.cpp b/src/game/server/gamemodes/fb.cpp
index 4d1c5c3..f6fdfcc 100644
--- a/src/game/server/gamemodes/fb.cpp
+++ b/src/game/server/gamemodes/fb.cpp
@@ -8,16 +8,68 @@
 #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)
 {
-	balls[0] = 0;
-	balls[1] = 0;
+	m_apBalls[0] = NULL;
+	m_apBalls[1] = NULL;
 	m_pGameType = g_Config.m_SvfbInstagib ? "iFB" : "FB";
 	m_GameFlags = GAMEFLAG_TEAMS | GAMEFLAG_FLAGS;
-	goal_pos[0] = vec2 (0, 0);
-	goal_pos[1] = vec2 (0, 0);
-	num_goals = 0;
+	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;
 	
 }
@@ -35,12 +87,21 @@ bool CGameControllerFB::OnEntity (int index, vec2 pos)
 	//	add goal positions and balls
 	switch (index)
 	{
-	case ENTITY_SPAWN: if (num_goals < FB_MAX_GOALS) goal_pos[num_goals++] = pos; break;
-	case ENTITY_FLAGSTAND_RED: if (balls[0] == 0) GameServer()->m_World.InsertEntity(balls[0] = new BALL(&GameServer()->m_World, 0, pos)); break;
-	case ENTITY_FLAGSTAND_BLUE: if (balls[1] == 0) GameServer()->m_World.InsertEntity(balls[1] = new BALL(&GameServer()->m_World, 1, pos)); break;
-	default: return false;
+		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;
 	
 }
@@ -63,22 +124,15 @@ int CGameControllerFB::OnCharacterDeath(class CCharacter *victim, class CPlayer
 	int had_flag = 0;
 	for (int i = 0; i < FB_MAX_BALLS; i++)
 	{
-		BALL *b = balls[i];
-		if (!b || !b->carrier)
+		CBall *b = m_apBalls[i];
+		if (!b || !b->m_pCarryingCharacter)
 			continue;
 
-		if (killer && b->carrier == killer->GetCharacter())
+		if (killer && b->m_pCarryingCharacter == killer->GetCharacter())
 			had_flag |= 2;
-		if (b->carrier == victim)
+		if (b->m_pCarryingCharacter == victim)
 		{
-			//	drop ball
-			GameServer()->CreateSoundGlobal(SOUND_CTF_DROP);
-			b->drop_tick = Server()->Tick();
-			b->last_carrier = victim->GetPlayer();
-			b->last_carrier_team = victim->GetPlayer()->GetTeam();
-			b->carrier = 0;
-			victim->ball = NULL;
-			b->vel = vec2 (0, 0);
+			victim->DropBall();
 
 			if (killer && killer->GetTeam() != victim->GetPlayer()->GetTeam())
 				killer->m_Score++;
@@ -116,13 +170,14 @@ void CGameControllerFB::OnCharacterSpawn(class CCharacter *chr)
 	
 }
 
-bool CGameControllerFB::HandleGoal (BALL *b, int goal)
+bool CGameControllerFB::HandleGoal (CBall *b, int goal)
 {
 	
-	CPlayer *const p = b->carrier ? b->carrier->GetPlayer() : b->last_carrier;
-	const int team = b->last_carrier_team;
+	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->carrier ? true : false;
+	const bool tee_goal = b->m_pCarryingCharacter;
 	
 	//	update scores
 	if (own_goal)
@@ -133,7 +188,7 @@ bool CGameControllerFB::HandleGoal (BALL *b, int goal)
 		if (p)
 		{
 			p->m_Score -= g_Config.m_SvfbOwngoalPenalty;
-			p->num_owngoals++;
+			p->m_NumOwngoals++;
 		
 			// send warning to user
 			char chat_msg[256];
@@ -192,7 +247,7 @@ bool CGameControllerFB::HandleGoal (BALL *b, int goal)
 	GameServer()->SendBroadcast(bc_msg, -1);
 
 	// kick unteachable player from server
-	if (g_Config.m_SvfbOwngoalKick && p && p->num_owngoals >= g_Config.m_SvfbOwngoalKick)
+	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).",
@@ -209,22 +264,83 @@ bool CGameControllerFB::HandleGoal (BALL *b, int goal)
 	
 }
 
-void CGameControllerFB::OnDisconnect (const CPlayer *const p)
+void CGameControllerFB::OnDisconnect (CPlayer *const p)
 {
-	
+	CCharacter* ch = p->GetCharacter();
 	for (int i = 0; i < FB_MAX_BALLS; ++i)
 	{
-		if (balls[i] && !balls[i]->at_stand)
+		if (m_apBalls[i])
 		{
-			if (balls[i]->carrier && p == balls[i]->carrier->GetPlayer())
-				balls[i]->carrier = NULL;
-			if (p == balls[i]->last_carrier)
-				balls[i]->last_carrier = NULL;
+			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()
 {
 	
@@ -238,37 +354,6 @@ void CGameControllerFB::Tick()
 		{
 			if (!GameServer()->m_apPlayers[i]) continue;
 
-			//	auto-kick if idle
-			if (GameServer()->m_apPlayers[i]->GetTeam() == -1)
-               {
-				if (g_Config.m_SvfbSpectatorIdleTime && GameServer()->m_apPlayers[i]->last_mousemove_tick + g_Config.m_SvfbSpectatorIdleTime * Server()->TickSpeed() <= Server()->Tick())
-				{
-					char chat_msg[256];
-					str_format (chat_msg, sizeof (chat_msg), "%s was automatically kicked. Cause: Has been idling too long (%d).", Server()->ClientName(GameServer()->m_apPlayers[i]->m_ClientID), g_Config.m_SvfbIdleTime);
-					Server()->Kick(GameServer()->m_apPlayers[i]->m_ClientID, "You have been idling too long!");
-				};
-				continue;
-			};
-			if (g_Config.m_SvfbIdleTime &&	GameServer()->m_apPlayers[i]->last_mousemove_tick + g_Config.m_SvfbIdleTime * Server()->TickSpeed() <= Server()->Tick())
-			{	
-				if (strcmp(g_Config.m_SvfbOnIdle, "kick") == 0)
-				{
-					char chat_msg[256];
-					str_format (chat_msg, sizeof (chat_msg), "%s was automatically kicked. Cause: Has been idling too long (%d).", Server()->ClientName(GameServer()->m_apPlayers[i]->m_ClientID), g_Config.m_SvfbIdleTime);
-	                Server()->Kick (GameServer()->m_apPlayers[i]->m_ClientID, "You have been idling too long! When idle please join spectators or leave to free slots!");
-					continue;
-				}
-				else if (strcmp(g_Config.m_SvfbOnIdle, "spectate") == 0)
-				{
-					char chat_msg[256];
-					str_format (chat_msg, sizeof (chat_msg), "%s was automatically joined to spectators. Cause: Has been idling too long (%d).", Server()->ClientName(GameServer()->m_apPlayers[i]->m_ClientID), g_Config.m_SvfbIdleTime);
-					GameServer()->m_apPlayers[i]->SetTeam(-1);
-					CheckTeamBalance();
-					GameServer()->SendChat(-1, -2, chat_msg);
-					continue;
-				}       
-			}
-
 			CCharacter *ch = GameServer()->m_apPlayers[i]->GetCharacter();
 			if (!ch || !ch->IsAlive())
 				continue;
@@ -277,13 +362,13 @@ void CGameControllerFB::Tick()
 			if (g_Config.m_SvfbGoalcamp)
 			{
 				bool in_range = false;
-				for (int goal = 0; goal < num_goals; ++goal)
+				for (int goal = 0; goal < m_NumGoals; ++goal)
 				{
-					if (distance (ch->m_Pos, goal_pos[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->goal_camp_tick += 2;
+						ch->m_GoalCampTick += 2;
 						in_range = true;
 						break;
 					}
@@ -292,13 +377,13 @@ void CGameControllerFB::Tick()
 				if (!in_range)
 				{
 					// if out of range, count down just 1 tick again (slower)
-					if (ch->goal_camp_tick)
-						ch->goal_camp_tick--;
+					if (ch->m_GoalCampTick)
+						ch->m_GoalCampTick--;
 				}
 				else
 				{	
 					//	kill goal camping player
-					if ((ch->goal_camp_tick >> 1) >= Server()->TickSpeed() * g_Config.m_SvfbGoalcampTime)
+					if ((ch->m_GoalCampTick >> 1) >= Server()->TickSpeed() * g_Config.m_SvfbGoalcampTime)
 					{
 						GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_GAME);
 				
@@ -314,22 +399,22 @@ void CGameControllerFB::Tick()
 			// anti-camping
 			if (g_Config.m_SvfbCampMaxtime)
 			{
-				if (distance (ch->m_Pos, ch->camp_pos) <= g_Config.m_SvfbCampThreshold && !ch->ball)
+				if (distance (ch->m_Pos, ch->m_CampPos) <= g_Config.m_SvfbCampThreshold && !ch->m_pBall)
 				{
 					// if in range, count up 2 ticks
-					ch->camp_tick += 2;
+					ch->m_CampTick += 2;
 				}
 				else
 				{
 					// if out of range, count down just 1 tick again (slower)
-					if (ch->camp_tick)
-						ch->camp_tick--;
+					if (ch->m_CampTick)
+						ch->m_CampTick--;
 					else
-						ch->camp_pos = ch->m_Pos;
+						ch->m_CampPos = ch->m_Pos;
 				}
 	
 				//	kill camping player
-				if ((ch->camp_tick >> 1) >= Server()->TickSpeed () * g_Config.m_SvfbCampMaxtime)
+				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");
@@ -341,54 +426,16 @@ void CGameControllerFB::Tick()
 		//	update balls
 		for (int bi =  0; bi < FB_MAX_BALLS; ++bi)
 		{
-			BALL *b = balls[bi];
+			CBall *b = m_apBalls[bi];
 
 			if (!b)
 				continue;
 
-			//	update ball position
-			if (b->carrier)
-			{
-				b->m_Pos = b->carrier->m_Pos;
-			}
-			else if (!b->at_stand)
-			{	
-				//	ball hits death tile
-				if (b->idle_tick == -1 && GameServer()->Collision()->GetCollisionAt(static_cast<int> (b->m_Pos.x), static_cast<int> (b->m_Pos.y)) & CCollision::COLFLAG_DEATH)
-					b->idle_tick = g_Config.m_SvfbBallDeathtileIdle * Server()->TickSpeed();
-					//	flag reset delay (after hitting a death tile)
-				if (b->idle_tick > 0)
-				{
-					b->idle_tick--;
-					continue;
-				}
-				if (Server()->Tick() >= b->drop_tick + Server()->TickSpeed () * g_Config.m_SvfbBallResetTime || !b->idle_tick)
-				{
-					//	reset ball
-					GameServer()->CreateSoundGlobal(SOUND_CTF_RETURN);
-					b->Reset ();
-				}
-				else
-				{
-					// do ball physics
-					b->vel.y += GameServer()->m_World.m_Core.m_Tuning.m_Gravity;
-					if (b->vel.x > -0.1f && b->vel.x < 0.1f) 
-						b->vel.x = 0.0f;
-					else if (b->vel.x < 0)
-						b->vel.x += 0.055f;
-					else
-						b->vel.x -= 0.055f;
-
-					GameServer()->Collision()->MoveBox(&b->m_Pos, &b->vel, vec2 (b->phys_size, b->phys_size), 0.5f);
-				}
-
-			}
-
 			//	check/handle goal
 			bool is_goal = false;
-			for (int g = 0; g < num_goals; g++)
+			for (int g = 0; g < m_NumGoals; g++)
 			{
-				if (distance(b->m_Pos, goal_pos[g]) < g_Config.m_SvfbGoalsize)
+				if (distance(b->m_Pos, m_apGoalPos[g]) < g_Config.m_SvfbGoalsize)
 				{
 					is_goal = HandleGoal(b, g);
 					break;
@@ -397,36 +444,39 @@ void CGameControllerFB::Tick()
 			if (is_goal)
 				continue;
 
-			if (b->carrier)
+			if (b->m_pCarryingCharacter)
 			{	//	ball is carried by player
 				//	warn ball-carrying player once when he is near his own goal
-				if (g_Config.m_SvfbOwngoalWarn && !b->carrier->GetPlayer()->owngoal_warned && b->carrier->GetPlayer()->GetTeam() < num_goals &&
-					(distance(b->carrier->m_Pos, goal_pos[b->carrier->GetPlayer()->GetTeam()]) < g_Config.m_SvfbGoalsize * 5))
+				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!",
-						b->carrier->GetPlayer()->m_ClientID);
+						p->m_ClientID);
 
 					// play the server-chat sound
-					GameServer()->CreateSound(b->carrier->m_Pos, SOUND_CHAT_SERVER, CmaskOne(b->carrier->GetPlayer()->m_ClientID));
-					b->carrier->GetPlayer()->owngoal_warned = true;
+					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->at_stand || Server()->Tick () >= b->drop_tick + Server()->TickSpeed () * 0.2f)
+				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->phys_size, (CEntity**)close_characters, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER);
+					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) ||
-							balls[bi ^ 1]->carrier == close_characters[i]) // don't take flag if already have one (might be useful with two flags)
+							// 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];
 					}
@@ -434,32 +484,11 @@ void CGameControllerFB::Tick()
 					if (!curr_num)
 						continue;
 
-					//	grab the ball
-					CCharacter *ch = close_characters[Server()->Tick() % curr_num];
-					if (b->at_stand)
-					{
-						m_aTeamscore[bi ^ 1] += g_Config.m_SvfbScoreTeamStand;
-						ch->GetPlayer()->m_Score += g_Config.m_SvfbScorePlayerStand;
-						b->at_stand = 0;
-					}				
-
-					ch->CaptureBall(b);
-
-					for (int c = 0; c < MAX_CLIENTS; c++)
-					{
-						if (!GameServer()->m_apPlayers[c])
-							continue;
-							
-						if (GameServer()->m_apPlayers[c]->GetTeam() == bi)
-							GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, GameServer()->m_apPlayers[c]->m_ClientID);
-						else
-							GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_PL, GameServer()->m_apPlayers[c]->m_ClientID);
-					}
+					GrantBall(close_characters[Server()->Tick() % curr_num], b);
 				}
 			}
 		}
 	}
-	
 }
 
 void CGameControllerFB::Snap(int SnappingClient)
@@ -474,15 +503,15 @@ void CGameControllerFB::Snap(int SnappingClient)
 	pGameDataObj->m_TeamscoreRed = m_aTeamscore[TEAM_RED];
 	pGameDataObj->m_TeamscoreBlue = m_aTeamscore[TEAM_BLUE];
 	
-	if(balls[TEAM_RED])
+	if(m_apBalls[TEAM_RED])
 	{
-		if(balls[TEAM_RED]->at_stand)
+		if(m_apBalls[TEAM_RED]->m_AtStand)
 		{
 			pGameDataObj->m_FlagCarrierRed = FLAG_ATSTAND;
 		}
-		else if(balls[TEAM_RED]->carrier && balls[TEAM_RED]->carrier->GetPlayer())
+		else if(m_apBalls[TEAM_RED]->m_pCarryingCharacter)
 		{
-			pGameDataObj->m_FlagCarrierRed = balls[TEAM_RED]->carrier->GetPlayer()->GetCID();
+			pGameDataObj->m_FlagCarrierRed = m_apBalls[TEAM_RED]->m_pCarryingCharacter->GetPlayer()->GetCID();
 		}
 		else
 		{
@@ -494,15 +523,15 @@ void CGameControllerFB::Snap(int SnappingClient)
 		pGameDataObj->m_FlagCarrierRed = FLAG_MISSING;	
 	}
 	
-	if(balls[TEAM_BLUE])
+	if(m_apBalls[TEAM_BLUE])
 	{
-		if(balls[TEAM_BLUE]->at_stand)
+		if(m_apBalls[TEAM_BLUE]->m_AtStand)
 		{
 			pGameDataObj->m_FlagCarrierBlue = FLAG_ATSTAND;
 		}
-		else if(balls[TEAM_BLUE]->carrier && balls[TEAM_BLUE]->carrier->GetPlayer())
+		else if(m_apBalls[TEAM_BLUE]->m_pCarryingCharacter)
 		{
-			pGameDataObj->m_FlagCarrierBlue = balls[TEAM_BLUE]->carrier->GetPlayer()->GetCID();
+			pGameDataObj->m_FlagCarrierBlue = m_apBalls[TEAM_BLUE]->m_pCarryingCharacter->GetPlayer()->GetCID();
 		}
 		else
 		{
@@ -514,52 +543,3 @@ void CGameControllerFB::Snap(int SnappingClient)
 		pGameDataObj->m_FlagCarrierBlue = FLAG_MISSING;
 	}
 }
-
-//	Ball
-BALL::BALL (CGameWorld *pGameWorld, int _team, vec2 _pos)
-:	CEntity (pGameWorld, CGameWorld::ENTTYPE_FLAG)
-{
-	m_ProximityRadius = phys_size;
-	team = _team;
-	stand_pos = _pos;
-	
-	Reset();
-}
-
-void BALL::Reset ()
-{
-	carrier = 0;
-	last_carrier = 0;
-	last_carrier_team = team;
-	at_stand = 1;
-	m_Pos = stand_pos;
-	vel = vec2 (0, 0);
-	grab_tick = 0;
-	drop_tick = Server()->Tick();
-	idle_tick = -1;	
-}
-
-void BALL::Snap (int snapping_client)
-{	
-	if (idle_tick != -1)
-		return;
-			
-	if(NetworkClipped(snapping_client))
-		return;
-
-	CNetObj_Flag *ball = (CNetObj_Flag *)Server()->SnapNewItem(NETOBJTYPE_FLAG, team, sizeof(CNetObj_Flag));
-	if(!ball)
-		return;
-	
-	ball->m_X = (int)m_Pos.x;
-	ball->m_Y = (int)m_Pos.y;
-	
-	/* Was causing strange lag when a player of one team picked up the opposite flag
-	 * Laser Momentum still works as it should but the color of the flag does not change
-	 */
-	//if (g_Config.m_SvfbLaserMomentum)
-	//	ball->m_Team = last_carrier_team;
-	//else
-		ball->m_Team = team;
-}
-
diff --git a/src/game/server/gamemodes/fb.h b/src/game/server/gamemodes/fb.h
index fbc7185..25d75ef 100644
--- a/src/game/server/gamemodes/fb.h
+++ b/src/game/server/gamemodes/fb.h
@@ -1,48 +1,45 @@
+#ifndef GAME_SERVER_GAMEMODES_FB_H
+#define GAME_SERVER_GAMEMODES_FB_H
+
 #include <game/server/gamecontroller.h>
-#include <game/server/entity.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 BALL *balls[FB_MAX_BALLS];
-	vec2 goal_pos[FB_MAX_GOALS];
-	int num_goals;
-	
+	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 bool HandleGoal (BALL *b, int goal);
-	virtual void OnDisconnect (const CPlayer *const p);
-	virtual void Snap(int SnappingClient);
-};
-
-class BALL : public CEntity
-{
-public:
-	static const int phys_size = 14;
-	CCharacter *carrier;
-	CPlayer *last_carrier;
-	int last_carrier_team;
-	vec2 vel;
-	vec2 stand_pos;
-	
-	int team;
-	int at_stand;
-	int drop_tick;
-	int grab_tick;
-	int idle_tick;
-	
-	BALL (CGameWorld *pGameWorld, int _team, vec2 _pos);
-
-	virtual void Reset();
+	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/player.cpp b/src/game/server/player.cpp
index 5d435c4..770a426 100644
--- a/src/game/server/player.cpp
+++ b/src/game/server/player.cpp
@@ -21,10 +21,8 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, int Team)
 	Character = 0;
 	this->m_ClientID = ClientID;
 	
- 	num_owngoals = 0;
- 	owngoal_warned = false;
- 	last_mousemove_tick = Server()->Tick();
- 	last_target_pos = vec2 (0, 0);
+ 	m_NumOwngoals = 0;
+ 	m_OwngoalWarned = false;
 
 	m_Team = GameServer()->m_pController->ClampTeam(Team);
 	m_SpectatorID = SPEC_FREEVIEW;
@@ -191,17 +189,6 @@ void CPlayer::OnDirectInput(CNetObj_PlayerInput *NewInput)
 	if(!Character && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW)
 		m_ViewPos = vec2(NewInput->m_TargetX, NewInput->m_TargetY);
 
-    // 	Looks like this is done anyway now, still working on it
- 	//	update active player (idle kicking)
- 	if (m_LatestActivity.m_TargetX != NewInput->m_TargetX || m_LatestActivity.m_TargetY != NewInput->m_TargetY)
- 	{
- 		m_LatestActivity.m_TargetX = NewInput->m_TargetX;
- 		last_target_pos.y = NewInput->m_TargetY;
- 		last_mousemove_tick = Server()->Tick();
- 		
- 		//Flagball stuff could maybe be added down below in new activity check
- 	}
-
 	// check for activity
 	if(NewInput->m_Direction || m_LatestActivity.m_TargetX != NewInput->m_TargetX ||
 		m_LatestActivity.m_TargetY != NewInput->m_TargetY || NewInput->m_Jump ||
diff --git a/src/game/server/player.h b/src/game/server/player.h
index aeac33d..c9c1dcb 100644
--- a/src/game/server/player.h
+++ b/src/game/server/player.h
@@ -33,10 +33,8 @@ public:
 	void OnDisconnect(const char *pReason);
 	
  	//	flagball
- 	int num_owngoals;	//	counter for own-goals
- 	bool owngoal_warned;	//	own goal warning (only shown once)
- 	int last_mousemove_tick;	//	tick counter for idle kicking
- 	vec2 last_target_pos;	//	used to check for mouse movements (activity) 	
+	int m_NumOwngoals; //	counter for own-goals
+ 	bool m_OwngoalWarned;	//	own goal warning (only shown once)
 	
 	void KillCharacter(int Weapon = WEAPON_GAME);
 	CCharacter *GetCharacter();
diff --git a/src/game/variables.h b/src/game/variables.h
index 092c218..abb0d51 100644
--- a/src/game/variables.h
+++ b/src/game/variables.h
@@ -80,7 +80,6 @@ MACRO_CONFIG_INT(SvVoteKickBantime, sv_vote_kick_bantime, 5, 0, 1440, CFGFLAG_SE
 
 /*	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(SvfbBallDeathtileIdle, sv_fb_ball_deathtile_idle, 3, 0, 60, CFGFLAG_SERVER, "Number of seconds needed to reset a ball after hitting a death tile (0=off (default=3)).")
 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)).")
@@ -96,9 +95,6 @@ MACRO_CONFIG_INT(SvfbGoalcamp, sv_fb_goalcamp, 1, 0, 1, CFGFLAG_SERVER, "Turns o
 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_STR(SvfbOnIdle, sv_fb_on_idle, 10, ".", CFGFLAG_SERVER, "What to do when player idling too long. Possible values: spectate, kick. Default is nothing")
-MACRO_CONFIG_INT(SvfbIdleTime, sv_fb_idle_time, 0, 0, 600, CFGFLAG_SERVER, "Number of seconds after an idling player gets kicked or being forced to join to spectators (0=off (default=90)).")
-MACRO_CONFIG_INT(SvfbSpectatorIdleTime, sv_fb_spectator_idle_time, 0, 0, 10000, CFGFLAG_SERVER, "Number of seconds after an idling spectator gets kicked")
 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)).")
@@ -111,6 +107,7 @@ MACRO_CONFIG_INT(SvfbScoreTeamBall, sv_fb_score_team_ball, 50, 1, 100, CFGFLAG_S
 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
diff --git a/src/game/version.h b/src/game/version.h
index afe37af..f8f4c50 100644
--- a/src/game/version.h
+++ b/src/game/version.h
@@ -6,5 +6,5 @@
 #define GAME_VERSION "0.6 trunk"
 #define GAME_NETVERSION "0.6 " GAME_NETVERSION_HASH
 /*	FlagBall-MOD version	*/
-#define MOD_VERSION "0.1.17.2"
+#define MOD_VERSION "0.2.0-beta"
 #endif
