diff -rupN d:\t052/datasrc/compile.py d:\eg/datasrc/compile.py
--- d:\t052/datasrc/compile.py	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/datasrc/compile.py	2010-02-04 10:53:13.000000000 +0100
@@ -118,6 +118,7 @@ if gen_network_header:
 		
 	EmitEnum(["SOUND_%s"%i.name.value.upper() for i in content.container.sounds.items], "NUM_SOUNDS")
 	EmitEnum(["WEAPON_%s"%i.name.value.upper() for i in content.container.weapons.id.items], "NUM_WEAPONS")
+	EmitEnum(["SPECIAL_%s"%i.name.value.upper() for i in content.container.specials.id.items], "NUM_SPECIALS")
 
 	print "int netobj_validate(int type, void *data, int size);"
 	print "const char *netobj_get_name(int type);"
diff -rupN d:\t052/datasrc/content.py d:\eg/datasrc/content.py
--- d:\t052/datasrc/content.py	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/datasrc/content.py	2010-02-04 10:53:13.000000000 +0100
@@ -46,6 +46,14 @@ class Pickup(Struct):
 		self.name = String(name)
 		self.respawntime = Int(respawntime)
 		self.spawndelay = Int(spawndelay)
+		
+class SpecialSpec(Struct):
+	def __init__(self, name="", respawntime=15, spawndelay=0):
+		Struct.__init__(self, "SPECIALSPEC")
+		self.name = String(name)
+		self.respawntime = Int(respawntime)
+		self.spawndelay = Int(spawndelay)
+		self.duration = Int(30000)
 
 class AnimKeyframe(Struct):
 	def __init__(self, time=0, x=0, y=0, angle=0):
@@ -89,6 +97,8 @@ class WeaponSpec(Struct):
 		self.muzzleoffsetx = Float(0)
 		self.muzzleoffsety = Float(0)
 		self.muzzleduration = Float(5)
+		
+		self.bulletoffset = Float(12)
 
 		# dig out sprites if we have a container
 		if container:
@@ -138,6 +148,23 @@ class Weapon_Rifle(Struct):
 		self.bounce_num = Int(1)
 		self.bounce_cost = Float(0)
 		
+class Weapon_Shaft(Struct):
+	def __init__(self):
+		Struct.__init__(self, "WEAPONSPEC_SHAFT")
+		self.base = Pointer(WeaponSpec, WeaponSpec())
+		self.reach = Float(600.0)
+		
+class Weapon_Spingun(Struct):
+	def __init__(self):
+		Struct.__init__(self, "WEAPONSPEC_SPINGUN")
+		self.base = Pointer(WeaponSpec, WeaponSpec())
+		self.reach = Float(300.0)
+		
+class Weapon_Biorifle(Struct):
+	def __init__(self):
+		Struct.__init__(self, "WEAPONSPEC_BIORIFLE")
+		self.base = Pointer(WeaponSpec, WeaponSpec())
+		
 class Weapon_Ninja(Struct):
 	def __init__(self):
 		Struct.__init__(self, "WEAPONSPEC_NINJA")
@@ -145,18 +172,74 @@ class Weapon_Ninja(Struct):
 		self.duration = Int(15000)
 		self.movetime = Int(200)
 		self.velocity = Int(50)
+		
+class Weapon_Hook(Struct):
+	def __init__(self):
+		Struct.__init__(self, "WEAPONSPEC_HOOK")
+		self.base = Pointer(WeaponSpec, WeaponSpec())
 
 class Weapons(Struct):
 	def __init__(self):
 		Struct.__init__(self, "WEAPONSPECS")
 		self.hammer = Weapon_Hammer()
-		self.gun = Weapon_Hammer()
+		self.gun = Weapon_Gun()
 		self.shotgun = Weapon_Shotgun()
 		self.grenade = Weapon_Grenade()
 		self.rifle = Weapon_Rifle()
+		self.shaft = Weapon_Shaft()
+		self.spingun = Weapon_Spingun()
+		self.biorifle = Weapon_Biorifle()
 		self.ninja = Weapon_Ninja()
+		self.hook = Weapon_Hook()
 		self.id = Array(WeaponSpec())
 
+class SpecialSpec_Nospecial(Struct):
+	def __init__(self):
+		Struct.__init__(self, "SPECIALSPEC_NOSPECIAL")
+		self.base = Pointer(SpecialSpec, SpecialSpec())		
+		
+class SpecialSpec_Megahealth(Struct):
+	def __init__(self):
+		Struct.__init__(self, "SPECIALSPEC_MEGAHEALTH")
+		self.base = Pointer(SpecialSpec, SpecialSpec())
+		
+class SpecialSpec_Yellowarmor(Struct):
+	def __init__(self):
+		Struct.__init__(self, "SPECIALSPEC_YELLOWARMOR")
+		self.base = Pointer(SpecialSpec, SpecialSpec())
+		
+class SpecialSpec_Redarmor(Struct):
+	def __init__(self):
+		Struct.__init__(self, "SPECIALSPEC_REDARMOR")
+		self.base = Pointer(SpecialSpec, SpecialSpec())
+		
+class SpecialSpec_Powersuit(Struct):
+	def __init__(self):
+		Struct.__init__(self, "SPECIALSPEC_POWERSUIT")
+		self.base = Pointer(SpecialSpec, SpecialSpec())
+	
+class SpecialSpec_Ninjapwr(Struct):
+	def __init__(self):
+		Struct.__init__(self, "SPECIALSPEC_NINJAPWR")
+		self.base = Pointer(SpecialSpec, SpecialSpec())
+		
+class SpecialSpec_Hookpwr(Struct):
+	def __init__(self):
+		Struct.__init__(self, "SPECIALSPEC_HOOKPWR")
+		self.base = Pointer(SpecialSpec, SpecialSpec())
+
+class Specials(Struct):
+	def __init__(self):
+		Struct.__init__(self, "SPECIALSPECS")
+		self.nospecial = SpecialSpec_Nospecial()
+		self.megahealth = SpecialSpec_Megahealth()
+		self.yellowarmor = SpecialSpec_Yellowarmor()
+		self.redarmor = SpecialSpec_Redarmor()
+		self.powersuit = SpecialSpec_Powersuit()
+		self.ninjapwr = SpecialSpec_Ninjapwr()
+		self.hookpwr = SpecialSpec_Hookpwr()
+		self.id = Array(SpecialSpec())
+
 class DataContainer(Struct):
 	def __init__(self):
 		Struct.__init__(self, "DATACONTAINER")
@@ -167,6 +250,7 @@ class DataContainer(Struct):
 		self.sprites = Array(Sprite())
 		self.animations = Array(Animation())
 		self.weapons = Weapons()
+		self.specials = Specials()
 
 def FileList(format, num):
 	return [format%(x+1) for x in xrange(0,num)]
@@ -175,15 +259,21 @@ container = DataContainer()
 container.sounds.Add(SoundSet("gun_fire", FileList("audio/wp_gun_fire-%02d.wv", 3)))
 container.sounds.Add(SoundSet("shotgun_fire", FileList("audio/wp_shotty_fire-%02d.wv", 3)))
 
+container.sounds.Add(SoundSet("biorifle_fire", FileList("audio/wp_bio_fire-%02d.wv", 3)))
 container.sounds.Add(SoundSet("grenade_fire", FileList("audio/wp_flump_launch-%02d.wv", 3)))
 container.sounds.Add(SoundSet("hammer_fire", FileList("audio/wp_hammer_swing-%02d.wv", 3)))
 container.sounds.Add(SoundSet("hammer_hit", FileList("audio/wp_hammer_hit-%02d.wv", 3)))
 container.sounds.Add(SoundSet("ninja_fire", FileList("audio/wp_ninja_attack-%02d.wv", 3)))
+container.sounds.Add(SoundSet("spin_impact", FileList("audio/wp_spin_impact-%02d.wv", 3)))
 container.sounds.Add(SoundSet("grenade_explode", FileList("audio/wp_flump_explo-%02d.wv", 3)))
+container.sounds.Add(SoundSet("bio_explode", FileList("audio/wp_bio_explo-%02d.wv", 3)))
+container.sounds.Add(SoundSet("bio_impact", FileList("audio/wp_bio_impact-%02d.wv", 2)))
 container.sounds.Add(SoundSet("ninja_hit", FileList("audio/wp_ninja_hit-%02d.wv", 3)))
+container.sounds.Add(SoundSet("shaft_fire", FileList("audio/wp_shaft_fire-%02d.wv", 2)))
 container.sounds.Add(SoundSet("rifle_fire", FileList("audio/wp_rifle_fire-%02d.wv", 3)))
 container.sounds.Add(SoundSet("rifle_bounce", FileList("audio/wp_rifle_bnce-%02d.wv", 3)))
 container.sounds.Add(SoundSet("weapon_switch", FileList("audio/wp_switch-%02d.wv", 3)))
+container.sounds.Add(SoundSet("gold_attach_player", ["audio/wp_hook_attach.wv"]))
 
 container.sounds.Add(SoundSet("player_pain_short", FileList("audio/vo_teefault_pain_short-%02d.wv", 12)))
 container.sounds.Add(SoundSet("player_pain_long", FileList("audio/vo_teefault_pain_long-%02d.wv", 2)))
@@ -207,6 +297,8 @@ container.sounds.Add(SoundSet("pickup_ar
 container.sounds.Add(SoundSet("pickup_grenade", ["audio/sfx_pickup_launcher.wv"]))
 container.sounds.Add(SoundSet("pickup_shotgun", ["audio/sfx_pickup_sg.wv"]))
 container.sounds.Add(SoundSet("pickup_ninja", ["audio/sfx_pickup_ninja.wv"]))
+container.sounds.Add(SoundSet("pickup_suit", ["audio/sfx_pickup_suit.wv"]))
+container.sounds.Add(SoundSet("pickup_gold", ["audio/sfx_pickup_gold.wv"]))
 container.sounds.Add(SoundSet("weapon_spawn", FileList("audio/sfx_spawn_wpn-%02d.wv", 3)))
 container.sounds.Add(SoundSet("weapon_noammo", FileList("audio/wp_noammo-%02d.wv", 5)))
 
@@ -223,11 +315,13 @@ container.sounds.Add(SoundSet("ctf_captu
 image_null = Image("null", "")
 image_particles = Image("particles", "particles.png")
 image_game = Image("game", "game.png")
+image_egame = Image("egame", "egame.png")
 image_browseicons = Image("browseicons", "browse_icons.png")
 image_emoticons = Image("emoticons", "emoticons.png")
 
 container.images.Add(image_null)
 container.images.Add(image_game)
+container.images.Add(image_egame)
 container.images.Add(image_particles)
 container.images.Add(Image("cursor", "gui_cursor.png"))
 container.images.Add(Image("banner", "gui_logo.png"))
@@ -239,16 +333,18 @@ container.images.Add(Image("console_bar"
 container.pickups.Add(Pickup("health"))
 container.pickups.Add(Pickup("armor"))
 container.pickups.Add(Pickup("weapon"))
-container.pickups.Add(Pickup("ninja", 90, 90))
+container.pickups.Add(Pickup("special", 90, 90))
 
 set_particles = SpriteSet("particles", image_particles, 8, 8)
 set_game = SpriteSet("game", image_game, 32, 16)
+set_egame = SpriteSet("egame", image_egame, 32, 16)
 set_tee = SpriteSet("tee", image_null, 8, 4)
 set_browseicons = SpriteSet("browseicons", image_browseicons, 4, 1)
 set_emoticons = SpriteSet("emoticons", image_emoticons, 4, 4)
 
 container.spritesets.Add(set_particles)
 container.spritesets.Add(set_game)
+container.spritesets.Add(set_egame)
 container.spritesets.Add(set_tee)
 container.spritesets.Add(set_browseicons)
 container.spritesets.Add(set_emoticons)
@@ -264,8 +360,10 @@ container.sprites.Add(Sprite("part_shell
 container.sprites.Add(Sprite("part_expl01", set_particles, 0,4,4,4))
 container.sprites.Add(Sprite("part_airjump", set_particles, 2,2,2,2))
 
+container.sprites.Add(Sprite("health_overfill", set_egame, 10,0,2,2))
 container.sprites.Add(Sprite("health_full", set_game, 21,0,2,2))
 container.sprites.Add(Sprite("health_empty", set_game, 23,0,2,2))
+container.sprites.Add(Sprite("armor_overfill", set_egame, 10,2,2,2))
 container.sprites.Add(Sprite("armor_full", set_game, 21,2,2,2))
 container.sprites.Add(Sprite("armor_empty", set_game, 23,2,2,2))
 
@@ -313,6 +411,34 @@ container.sprites.Add(Sprite("weapon_rif
 container.sprites.Add(Sprite("weapon_rifle_cursor", set_game, 0,12,2,2))
 container.sprites.Add(Sprite("weapon_rifle_proj", set_game, 10,12,2,2))
 
+container.sprites.Add(Sprite("weapon_hook_body", set_game, 3,0,2,1))
+container.sprites.Add(Sprite("weapon_hook_cursor", set_game, 3,0,2,1))
+container.sprites.Add(Sprite("weapon_hook_proj", set_game, 3,0,2,1))
+
+container.sprites.Add(Sprite("weapon_shaft_body", set_egame, 2,0,7,4))
+container.sprites.Add(Sprite("weapon_shaft_cursor", set_egame, 0,1,2,2))
+container.sprites.Add(Sprite("weapon_shaft_proj", set_egame, 0,0,1,1))
+
+container.sprites.Add(Sprite("weapon_spingun_body", set_egame, 2,4,7,3))
+container.sprites.Add(Sprite("weapon_spingun_cursor", set_egame, 0,3,2,2))
+container.sprites.Add(Sprite("weapon_spingun_proj", set_egame, 10,4,2,2))
+container.sprites.Add(Sprite("weapon_spingun_vortex", set_egame, 19,0,4,4))
+container.sprites.Add(Sprite("weapon_spingun_lightning1", set_egame, 23,0,2,4))
+container.sprites.Add(Sprite("weapon_spingun_lightning2", set_egame, 25,0,2,4))
+container.sprites.Add(Sprite("weapon_spingun_halo", set_egame, 27,0,4,4))
+
+container.sprites.Add(Sprite("weapon_biorifle_body", set_egame, 2,7,7,3))
+container.sprites.Add(Sprite("weapon_biorifle_cursor", set_egame, 0,5,2,2))
+container.sprites.Add(Sprite("weapon_biorifle_proj", set_egame, 27,0,4,4))
+container.sprites.Add(Sprite("weapon_biorifle_sticky1", set_egame, 0,9,2,2))
+container.sprites.Add(Sprite("weapon_biorifle_sticky2", set_egame, 0,11,2,2))
+container.sprites.Add(Sprite("weapon_biorifle_splash", set_egame, 0,13,2,2))
+
+container.sprites.Add(Sprite("shaft_end1", set_egame, 13,2,2,2))
+container.sprites.Add(Sprite("shaft_end2", set_egame, 15,2,2,2))
+container.sprites.Add(Sprite("shaft_end3", set_egame, 17,2,2,2))
+container.sprites.Add(Sprite("shaft_beam1", set_egame, 13,4,7,2))
+
 container.sprites.Add(Sprite("hook_chain", set_game, 2,0,1,1))
 container.sprites.Add(Sprite("hook_head", set_game, 3,0,2,1))
 
@@ -452,6 +578,7 @@ container.weapons.id.Add(weapon)
 weapon = WeaponSpec(container, "grenade")
 weapon.firedelay.Set(500) # TODO: fix this
 weapon.visual_size.Set(96)
+weapon.damage.Set(6)
 weapon.offsetx.Set(24)
 weapon.offsety.Set(-2)
 container.weapons.grenade.base.Set(weapon)
@@ -466,6 +593,41 @@ weapon.offsety.Set(-2)
 container.weapons.rifle.base.Set(weapon)
 container.weapons.id.Add(weapon)
 
+weapon = WeaponSpec(container, "shaft")
+weapon.firedelay.Set(55)
+weapon.maxammo.Set(100)
+weapon.damage.Set(1)
+weapon.visual_size.Set(115)
+weapon.offsetx.Set(24)
+weapon.offsety.Set(-2)
+weapon.bulletoffset.Set(1.75)
+container.weapons.shaft.base.Set(weapon)
+container.weapons.id.Add(weapon)
+
+weapon = WeaponSpec(container, "spingun")
+weapon.firedelay.Set(1000)
+weapon.maxammo.Set(5)
+weapon.damage.Set(12)
+weapon.visual_size.Set(96)
+weapon.offsetx.Set(24)
+weapon.offsety.Set(-2)
+weapon.bulletoffset.Set(24)
+container.weapons.spingun.base.Set(weapon)
+container.weapons.id.Add(weapon)
+
+weapon = WeaponSpec(container, "biorifle")
+weapon.firedelay.Set(140)
+weapon.maxammo.Set(35)
+weapon.visual_size.Set(100)
+weapon.damage.Set(2)
+weapon.offsetx.Set(24)
+weapon.offsety.Set(0)
+weapon.bulletoffset.Set(3)
+weapon.muzzleoffsetx.Set(50)
+weapon.muzzleoffsety.Set(6)
+container.weapons.biorifle.base.Set(weapon)
+container.weapons.id.Add(weapon)
+
 weapon = WeaponSpec(container, "ninja")
 weapon.firedelay.Set(800)
 weapon.damage.Set(9)
@@ -476,3 +638,42 @@ weapon.muzzleoffsetx.Set(40)
 weapon.muzzleoffsety.Set(-4)
 container.weapons.ninja.base.Set(weapon)
 container.weapons.id.Add(weapon)
+
+weapon = WeaponSpec(container, "hook")
+weapon.firedelay.Set(10)
+weapon.damage.Set(0)
+weapon.visual_size.Set(0)
+weapon.offsetx.Set(0)
+weapon.offsety.Set(0)
+weapon.muzzleoffsetx.Set(0)
+weapon.muzzleoffsety.Set(0)
+container.weapons.hook.base.Set(weapon)
+container.weapons.id.Add(weapon)
+
+special = SpecialSpec("nospecial", 0, 0)
+container.specials.nospecial.base.Set(special)
+container.specials.id.Add(special)
+
+special = SpecialSpec("megahealth", 35, 10)
+container.specials.megahealth.base.Set(special)
+container.specials.id.Add(special)
+
+special = SpecialSpec("yellowarmor", 25, 1)
+container.specials.yellowarmor.base.Set(special)
+container.specials.id.Add(special)
+
+special = SpecialSpec("redarmor", 25, 1)
+container.specials.redarmor.base.Set(special)
+container.specials.id.Add(special)
+
+special = SpecialSpec("powersuit", 30, 10)
+container.specials.powersuit.base.Set(special)
+container.specials.id.Add(special)
+
+special = SpecialSpec("ninjapwr", 30, 15)
+container.specials.ninjapwr.base.Set(special)
+container.specials.id.Add(special)
+
+special = SpecialSpec("hookpwr", 60, 45)
+container.specials.hookpwr.base.Set(special)
+container.specials.id.Add(special)
\ No newline at end of file
diff -rupN d:\t052/datasrc/network.py d:\eg/datasrc/network.py
--- d:\t052/datasrc/network.py	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/datasrc/network.py	2010-02-04 10:53:13.000000000 +0100
@@ -6,7 +6,7 @@ GameFlags = ["TEAMS", "FLAGS"]
 
 Emoticons = [str(x) for x in xrange(1,16)]
 
-Powerups = ["HEALTH", "ARMOR", "WEAPON", "NINJA"]
+Powerups = ["HEALTH", "ARMOR", "WEAPON", "SPECIAL"]
 
 RawHeader = '''
 enum
@@ -41,6 +41,7 @@ Objects = [
 		NetIntAny("jump"),
 		NetIntAny("fire"),
 		NetIntAny("hook"),
+		NetIntAny("drop"),
 		
 		NetIntRange("player_state", 0, len(PlayerStates)),
 		
@@ -58,13 +59,25 @@ Objects = [
 		NetIntRange("type", 0, 'NUM_WEAPONS-1'),
 		NetTick("start_tick"),
 	]),
-
+	
 	NetObject("Laser", [
 		NetIntAny("x"),
 		NetIntAny("y"),
 		NetIntAny("from_x"),
 		NetIntAny("from_y"),
 		
+		NetIntRange("type", 0, 'NUM_WEAPONS-1'),
+		NetTick("start_tick"),
+	]),
+	
+	NetObject("Shaft_Beam", [
+		NetIntAny("x"),
+		NetIntAny("y"),
+		NetIntAny("from_x"),
+		NetIntAny("from_y"),
+		NetIntAny("playerID"),
+		
+		NetIntRange("type", 0, 'NUM_WEAPONS-1'),
 		NetTick("start_tick"),
 	]),
 
@@ -75,6 +88,16 @@ Objects = [
 		NetIntRange("type", 0, 'max_int'),
 		NetIntRange("subtype", 0, 'max_int'),
 	]),
+	
+	NetObject("Dropped_Weapon", [
+		NetIntAny("x"),
+		NetIntAny("y"),
+		NetIntAny("vx"),
+		NetIntAny("vy"),
+		
+		NetIntRange("subtype", 0, 'max_int'),
+		NetTick("start_tick"),
+	]),
 
 	NetObject("Flag", [
 		NetIntAny("x"),
@@ -118,6 +141,8 @@ Objects = [
 		NetIntRange("hooked_player", 0, 'MAX_CLIENTS-1'),
 		NetIntRange("hook_state", -1, 5),
 		NetTick("hook_tick"),
+		
+		NetIntRange("specialstate", 0, 3),
 
 		NetIntAny("hook_x"),
 		NetIntAny("hook_y"),
@@ -127,9 +152,9 @@ Objects = [
 
 	NetObject("Character:Character_Core", [
 		NetIntRange("player_state", 0, 'NUM_PLAYERSTATES-1'),
-		NetIntRange("health", 0, 10),
-		NetIntRange("armor", 0, 10),
-		NetIntRange("ammocount", 0, 10),
+		NetIntRange("health", 0, 20),
+		NetIntRange("armor", 0, 20),
+		NetIntRange("ammocount", 0, 100),
 		NetIntRange("weapon", 0, 'NUM_WEAPONS-1'),
 		NetIntRange("emote", 0, len(Emotes)),
 		NetIntRange("attacktick", 0, 'max_int'),
@@ -140,7 +165,18 @@ Objects = [
 		NetIntRange("cid", 0, 'MAX_CLIENTS-1'),
 		NetIntRange("team", -1, 1),
 
+		NetIntRange("overall_accuracy", 0, 100),
+		# NetIntRange("hammer_percentage", 0, 100),
+		# NetIntRange("gun_percentage", 0, 100),
+		# NetIntRange("shotgun_percentage", 0, 100),
+		# NetIntRange("grenade_percentage", 0, 100),
+		# NetIntRange("rifle_percentage", 0, 100),
+		# NetIntRange("shaft_percentage", 0, 100),
+		# NetIntRange("spin_percentage", 0, 100),
+		# NetIntRange("bio_percentage", 0, 100),
+		
 		NetIntAny("score"),
+		NetIntAny("netscore"),
 		NetIntAny("latency"),
 		NetIntAny("latency_flux"),
 	]),
@@ -171,6 +207,9 @@ Objects = [
 	NetEvent("Explosion:Common", []),
 	NetEvent("Spawn:Common", []),
 	NetEvent("HammerHit:Common", []),
+	NetEvent("BioSplash:Common", [
+		NetIntAny("playSound"),
+	]),
 	
 	NetEvent("Death:Common", [
 		NetIntRange("cid", 0, 'MAX_CLIENTS-1'),
diff -rupN d:\t052/default.bam d:\eg/default.bam
--- d:\t052/default.bam	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/default.bam	2010-02-04 10:53:13.000000000 +0100
@@ -112,8 +112,8 @@ function build(settings)
 	else
 		settings.cc.flags:Add("-Wall", "-fno-exceptions")
 		if platform == "macosx" then
-			settings.cc.flags:Add("-mmacosx-version-min=10.4", "-isysroot /Developer/SDKs/MacOSX10.4u.sdk")
-			settings.link.flags:Add("-mmacosx-version-min=10.4", "-isysroot /Developer/SDKs/MacOSX10.4u.sdk")
+			settings.cc.flags:Add("-mmacosx-version-min=10.5", "-isysroot /Developer/SDKs/MacOSX10.5.sdk")
+			settings.link.flags:Add("-mmacosx-version-min=10.5", "-isysroot /Developer/SDKs/MacOSX10.5.sdk")
 		elseif config.stackprotector.value == 1 then
 			settings.cc.flags:Add("-fstack-protector", "-fstack-protector-all")
 			settings.link.flags:Add("-fstack-protector", "-fstack-protector-all")
diff -rupN d:\t052/src/engine/client/ec_gfx.c d:\eg/src/engine/client/ec_gfx.c
--- d:\t052/src/engine/client/ec_gfx.c	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/engine/client/ec_gfx.c	2010-02-04 10:53:13.000000000 +0100
@@ -463,6 +463,13 @@ void gfx_blend_additive()
 	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
 }
 
+void gfx_blend_subtractive()
+{
+	if(no_gfx) return;
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
+}
+
 int gfx_memory_usage() { return memory_usage; }
 
 static unsigned char sample(int w, int h, const unsigned char *data, int u, int v, int offset)
diff -rupN d:\t052/src/engine/e_if_gfx.h d:\eg/src/engine/e_if_gfx.h
--- d:\t052/src/engine/e_if_gfx.h	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/engine/e_if_gfx.h	2010-02-04 10:53:13.000000000 +0100
@@ -506,6 +506,8 @@ void gfx_blend_normal();
 */
 void gfx_blend_additive();
 
+void gfx_blend_subtractive();
+
 /*
 	Function: gfx_blend_none
 		Disables blending
diff -rupN d:\t052/src/game/client/components/binds.cpp d:\eg/src/game/client/components/binds.cpp
--- d:\t052/src/game/client/components/binds.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/components/binds.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -86,6 +86,7 @@ void BINDS::set_defaults()
 	bind(KEY_F2, "toggle_remote_console");
 	bind(KEY_TAB, "+scoreboard");
 	bind(KEY_F10, "screenshot");
+	bind('^', "personal_scoreboard");
 
 	bind('a', "+left");
 	bind('d', "+right");
@@ -100,10 +101,15 @@ void BINDS::set_defaults()
 	bind('3', "+weapon3");
 	bind('4', "+weapon4");
 	bind('5', "+weapon5");
+	bind('6', "+weapon6");
+	bind('7', "+weapon7");
+	bind('8', "+weapon8");
 	
 	bind(KEY_MOUSE_WHEEL_UP, "+prevweapon");
 	bind(KEY_MOUSE_WHEEL_DOWN, "+nextweapon");
 	
+	bind('f', "+dropweapon");
+	
 	bind('t', "chat all");
 	bind('y', "chat team");	
 
diff -rupN d:\t052/src/game/client/components/controls.cpp d:\eg/src/game/client/components/controls.cpp
--- d:\t052/src/game/client/components/controls.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/components/controls.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -53,12 +53,16 @@ void CONTROLS::on_console_init()
 	MACRO_REGISTER_COMMAND("+jump", "", CFGFLAG_CLIENT, con_key_input_state, &input_data.jump, "Jump");
 	MACRO_REGISTER_COMMAND("+hook", "", CFGFLAG_CLIENT, con_key_input_state, &input_data.hook, "Hook");
 	MACRO_REGISTER_COMMAND("+fire", "", CFGFLAG_CLIENT, con_key_input_counter, &input_data.fire, "Fire");
+	MACRO_REGISTER_COMMAND("+dropweapon", "", CFGFLAG_CLIENT, con_key_input_state, &input_data.drop, "Drop Weapon");
 
 	{ static INPUTSET set = {this, &input_data.wanted_weapon, 1};  MACRO_REGISTER_COMMAND("+weapon1", "", CFGFLAG_CLIENT, con_key_input_set, (void *)&set, "Switch to hammer"); }
 	{ static INPUTSET set = {this, &input_data.wanted_weapon, 2};  MACRO_REGISTER_COMMAND("+weapon2", "", CFGFLAG_CLIENT, con_key_input_set, (void *)&set, "Switch to gun"); }
 	{ static INPUTSET set = {this, &input_data.wanted_weapon, 3};  MACRO_REGISTER_COMMAND("+weapon3", "", CFGFLAG_CLIENT, con_key_input_set, (void *)&set, "Switch to shotgun"); }
 	{ static INPUTSET set = {this, &input_data.wanted_weapon, 4};  MACRO_REGISTER_COMMAND("+weapon4", "", CFGFLAG_CLIENT, con_key_input_set, (void *)&set, "Switch to grenade"); }
 	{ static INPUTSET set = {this, &input_data.wanted_weapon, 5};  MACRO_REGISTER_COMMAND("+weapon5", "", CFGFLAG_CLIENT, con_key_input_set, (void *)&set, "Switch to rifle"); }
+	{ static INPUTSET set = {this, &input_data.wanted_weapon, 6};  MACRO_REGISTER_COMMAND("+weapon6", "", CFGFLAG_CLIENT, con_key_input_set, (void *)&set, "Switch to shaft"); }
+	{ static INPUTSET set = {this, &input_data.wanted_weapon, 7};  MACRO_REGISTER_COMMAND("+weapon7", "", CFGFLAG_CLIENT, con_key_input_set, (void *)&set, "Switch to spin gun"); }
+	{ static INPUTSET set = {this, &input_data.wanted_weapon, 8};  MACRO_REGISTER_COMMAND("+weapon8", "", CFGFLAG_CLIENT, con_key_input_set, (void *)&set, "Switch to bio-rifle"); }
 
 	{ static INPUTSET set = {this, &input_data.next_weapon, 0};  MACRO_REGISTER_COMMAND("+nextweapon", "", CFGFLAG_CLIENT, con_key_input_nextprev_weapon, (void *)&set, "Switch to next weapon"); }
 	{ static INPUTSET set = {this, &input_data.prev_weapon, 0};  MACRO_REGISTER_COMMAND("+prevweapon", "", CFGFLAG_CLIENT, con_key_input_nextprev_weapon, (void *)&set, "Switch to previous weapon"); }
@@ -99,6 +103,7 @@ int CONTROLS::snapinput(int *data)
 		last_data.direction = 0;
 		last_data.hook = 0;
 		last_data.jump = 0;
+		last_data.drop = 0;
 		input_data = last_data;
 		
 		input_direction_left = 0;
@@ -145,6 +150,7 @@ int CONTROLS::snapinput(int *data)
 		else if(input_data.jump != last_data.jump) send = true;
 		else if(input_data.fire != last_data.fire) send = true;
 		else if(input_data.hook != last_data.hook) send = true;
+		else if(input_data.drop != last_data.drop) send = true;
 		else if(input_data.player_state != last_data.player_state) send = true;
 		else if(input_data.wanted_weapon != last_data.wanted_weapon) send = true;
 		else if(input_data.next_weapon != last_data.next_weapon) send = true;
diff -rupN d:\t052/src/game/client/components/effects.cpp d:\eg/src/game/client/components/effects.cpp
--- d:\t052/src/game/client/components/effects.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/components/effects.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -42,6 +42,30 @@ void EFFECTS::air_jump(vec2 pos)
 	gameclient.sounds->play(SOUNDS::CHN_WORLD, SOUND_PLAYER_AIRJUMP, 1.0f, pos);
 }
 
+void EFFECTS::biosplash(vec2 pos, bool sound)
+{
+	int num = 10;
+	for (int i=0; i<num; i++)
+	{
+		PARTICLE p;
+		p.set_default();
+		p.spr = SPRITE_PART_SMOKE;
+		p.pos = pos;
+		p.vel = vec2(frandom(), frandom())*800;
+		p.start_size = 15.0f + frandom()*8;
+		p.gravity = frandom()*500.0f;
+		p.start_size = 8.0f + frandom()*4;
+		p.life_span = 0.2 + frandom()*0.3f;		
+		p.end_size = 0;
+		p.friction = 1;
+		
+		p.color = vec4(0.75f,0.15f,0.85f,1.0f);
+		p.flow_affected = 0;		
+		gameclient.particles->add(PARTICLES::GROUP_PROJECTILE_TRAIL, &p);					
+	}	
+	gameclient.sounds->play(SOUNDS::CHN_WORLD, SOUND_BIO_EXPLODE, 1.0f, pos);
+}
+
 void EFFECTS::damage_indicator(vec2 pos, vec2 dir)
 {
 	gameclient.damageind->create(pos, dir);
diff -rupN d:\t052/src/game/client/components/effects.hpp d:\eg/src/game/client/components/effects.hpp
--- d:\t052/src/game/client/components/effects.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/components/effects.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -17,6 +17,7 @@ public:
 	void air_jump(vec2 pos);
 	void damage_indicator(vec2 pos, vec2 dir);
 	void playerspawn(vec2 pos);
+	void biosplash(vec2 pos, bool sound);
 	void playerdeath(vec2 pos, int cid);
 	void powerupshine(vec2 pos, vec2 size);
 
diff -rupN d:\t052/src/game/client/components/hud.cpp d:\eg/src/game/client/components/hud.cpp
--- d:\t052/src/game/client/components/hud.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/components/hud.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -227,7 +227,12 @@ void HUD::render_cursor()
 		return;
 		
 	mapscreen_to_group(gameclient.camera->center.x, gameclient.camera->center.y, layers_game_group());
-	gfx_texture_set(data->images[IMAGE_GAME].id);
+	if ((gameclient.snap.local_character->weapon == WEAPON_SPINGUN) ||
+	    (gameclient.snap.local_character->weapon == WEAPON_SHAFT) ||
+		(gameclient.snap.local_character->weapon == WEAPON_BIORIFLE))
+		gfx_texture_set(data->images[IMAGE_EGAME].id);
+	else
+		gfx_texture_set(data->images[IMAGE_GAME].id);
 	gfx_quads_begin();
 
 	// render cursor
@@ -250,31 +255,72 @@ void HUD::render_healthandammo()
 	gfx_texture_set(data->images[IMAGE_GAME].id);
 	gfx_mapscreen(0,0,width,300);
 	
-	gfx_quads_begin();
+	int w = gameclient.snap.local_character->weapon;
+	
+	if ((w == WEAPON_SHAFT) || (w==WEAPON_SPINGUN) || (w==WEAPON_BIORIFLE))
+		gfx_texture_set(data->images[IMAGE_EGAME].id);
+	else
+		gfx_texture_set(data->images[IMAGE_GAME].id);
+	
+	// added offset variable
+	int bulletoffset = data->weapons.id[gameclient.snap.local_character->weapon%NUM_WEAPONS].bulletoffset;
+	gfx_quads_begin();	
+		// if weaponstage is active, put a "glow" around the stage ammo
+		select_sprite(data->weapons.id[gameclient.snap.local_character->weapon%NUM_WEAPONS].sprite_proj);
+		for (int i = 0; i < min(gameclient.snap.local_character->ammocount, 100); i++)
+		{
+			gfx_quads_drawTL(x+i*bulletoffset,y+24,10,10);
+		}
+	
 	
-	// if weaponstage is active, put a "glow" around the stage ammo
-	select_sprite(data->weapons.id[gameclient.snap.local_character->weapon%NUM_WEAPONS].sprite_proj);
-	for (int i = 0; i < min(gameclient.snap.local_character->ammocount, 10); i++)
-		gfx_quads_drawTL(x+i*12,y+24,10,10);
-
 	gfx_quads_end();
 
+
+
+	gfx_texture_set(data->images[IMAGE_EGAME].id);
+
 	gfx_quads_begin();
 	int h = 0;
 
 	// render health
+	select_sprite(SPRITE_HEALTH_OVERFILL);
+	for(; h < (gameclient.snap.local_character->health - 10); h++)
+		gfx_quads_drawTL(x+h*12,y,10,10);
+	
+	gfx_quads_end();
+	
+	gfx_texture_set(data->images[IMAGE_GAME].id);
+	
+	gfx_quads_begin();
+	
 	select_sprite(SPRITE_HEALTH_FULL);
-	for(; h < gameclient.snap.local_character->health; h++)
+	for(int z = h; h < (gameclient.snap.local_character->health - z); h++)
 		gfx_quads_drawTL(x+h*12,y,10,10);
 
 	select_sprite(SPRITE_HEALTH_EMPTY);
 	for(; h < 10; h++)
 		gfx_quads_drawTL(x+h*12,y,10,10);
 
+	gfx_quads_end();
+	
+	gfx_texture_set(data->images[IMAGE_EGAME].id);
+
+	gfx_quads_begin();
+	
 	// render armor meter
 	h = 0;
+	select_sprite(SPRITE_ARMOR_OVERFILL);
+	for(; h < (gameclient.snap.local_character->armor - 10); h++)
+		gfx_quads_drawTL(x+h*12,y+12,10,10);
+		
+	gfx_quads_end();
+	
+	gfx_texture_set(data->images[IMAGE_GAME].id);
+	
+	gfx_quads_begin();
+	
 	select_sprite(SPRITE_ARMOR_FULL);
-	for(; h < gameclient.snap.local_character->armor; h++)
+	for(int z = h; h < (gameclient.snap.local_character->armor - z); h++)
 		gfx_quads_drawTL(x+h*12,y+12,10,10);
 
 	select_sprite(SPRITE_ARMOR_EMPTY);
diff -rupN d:\t052/src/game/client/components/items.cpp d:\eg/src/game/client/components/items.cpp
--- d:\t052/src/game/client/components/items.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/components/items.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -3,21 +3,29 @@
 #include <game/generated/gc_data.hpp>
 
 #include <game/gamecore.hpp> // get_angle
+#include <game/collision.hpp>
+
 #include <game/client/gameclient.hpp>
 #include <game/client/ui.hpp>
 #include <game/client/render.hpp>
 
+#include <math.h>
+
+#include <game/client/components/players.hpp>
+#include <game/client/components/controls.hpp>
 #include <game/client/components/flow.hpp>
 #include <game/client/components/effects.hpp>
+#include <game/client/components/particles.hpp>
+
+#include <game/server/entities/vortex.hpp>
 
 #include "items.hpp"
 
 void ITEMS::render_projectile(const NETOBJ_PROJECTILE *current, int itemid)
 {
-
 	// get positions
-	float curvature = 0;
 	float speed = 0;
+	float curvature = 0;
 	if(current->type == WEAPON_GRENADE)
 	{
 		curvature = gameclient.tuning.grenade_curvature;
@@ -33,9 +41,14 @@ void ITEMS::render_projectile(const NETO
 		curvature = gameclient.tuning.gun_curvature;
 		speed = gameclient.tuning.gun_speed;
 	}
+	else if(current->type == WEAPON_BIORIFLE)
+	{
+		curvature = gameclient.tuning.biorifle_curvature;
+		speed = gameclient.tuning.biorifle_speed;
+	}
 
 	float ct = (client_prevtick()-current->start_tick)/(float)SERVER_TICK_SPEED + client_ticktime();
-	if(ct < 0)
+	if(ct < 0 && current->type != WEAPON_BIORIFLE)
 		return; // projectile havn't been shot yet
 		
 	vec2 startpos(current->x, current->y);
@@ -44,13 +57,16 @@ void ITEMS::render_projectile(const NETO
 	vec2 prevpos = calc_pos(startpos, startvel, curvature, speed, ct-0.001f);
 
 
-	gfx_texture_set(data->images[IMAGE_GAME].id);
+	if (current->type == WEAPON_BIORIFLE)
+		gfx_texture_set(data->images[IMAGE_EGAME].id);
+	else
+		gfx_texture_set(data->images[IMAGE_GAME].id);
 	gfx_quads_begin();
 	
 	select_sprite(data->weapons.id[clamp(current->type, 0, NUM_WEAPONS-1)].sprite_proj);
 	vec2 vel = pos-prevpos;
 	//vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick());
-	
+	float size = 32;
 
 	// add particle for this projectile
 	if(current->type == WEAPON_GRENADE)
@@ -59,26 +75,100 @@ void ITEMS::render_projectile(const NETO
 		gameclient.flow->add(pos, vel*1000*client_frametime(), 10.0f);
 		gfx_quads_setrotation(client_localtime()*pi*2*2 + itemid);
 	}
-	else
+	else if(current->type != WEAPON_BIORIFLE)
 	{
 		gameclient.effects->bullettrail(pos);
 		gameclient.flow->add(pos, vel*1000*client_frametime(), 10.0f);
-
+	
 		if(length(vel) > 0.00001f)
 			gfx_quads_setrotation(get_angle(vel));
-		else
-			gfx_quads_setrotation(0);
+		else {
+			gfx_quads_setrotation(0);			
+		}
 
+	} 
+	else if(current->type == WEAPON_BIORIFLE)
+	{
+		{
+			PARTICLE p;
+			p.set_default();
+			p.spr = SPRITE_PART_SMOKE;
+			p.pos = pos;
+			if (length(vel) > 0.00001f) {
+				p.vel = vel*100;
+				p.start_size = 12.0f + frandom()*8;
+				p.gravity = frandom()*500.0f;
+			}
+			else 
+			{
+				p.vel = vec2(get_dir(client_localtime()*10))*80;
+				p.gravity = 0;
+			}
+			p.start_size = 8.0f + frandom()*4;
+			p.life_span = 0.1 + frandom()*0.3f;		
+			p.end_size = 0;
+			p.friction = 1;
+			
+			p.color = vec4(0.75f,0.15f,0.85f,1.0f);
+			p.flow_affected = 0;
+			if(length(vel) > 0.00001f)
+				p.gravity *= 2;
+			gameclient.particles->add(PARTICLES::GROUP_PROJECTILE_TRAIL, &p);					
+		}
+				
+		gfx_setcolor(0.8, 0.1, 0.9, 1);
+		if(length(vel) <= 0.00001f) {
+			gfx_setcolor(0.8, 0.1, 0.9, cosf(client_localtime()*20)/2+1);		
+			select_sprite(SPRITE_WEAPON_SPINGUN_HALO);
+			size = size + 10 * cosf(client_localtime()*5);
+		} 
+		else {
+			gfx_quads_setrotation(get_angle(vel));
+		}
 	}
 
-	gfx_quads_draw(pos.x, pos.y, 32, 32);
+	gfx_quads_draw(pos.x, pos.y, size, size);
+	gfx_quads_setrotation(0);
+	gfx_quads_end();
+}
+
+void ITEMS::render_DROPPEDWEAPON(const NETOBJ_DROPPED_WEAPON *current)
+{
+	float size = 64.0f;
+	float ct = (client_prevtick()-current->start_tick)/(float)SERVER_TICK_SPEED + client_ticktime();
+	float curvature = gameclient.tuning.droppedweapon_curvature;
+	float speed = gameclient.tuning.droppedweapon_speed;
+	
+	if(current->subtype >WEAPON_RIFLE)
+		gfx_texture_set(data->images[IMAGE_EGAME].id);
+	else
+		gfx_texture_set(data->images[IMAGE_GAME].id);
+	
+	gfx_quads_begin();
+	select_sprite(data->weapons.id[clamp(current->subtype, 0, NUM_WEAPONS-1)].sprite_body);
+	size = data->weapons.id[clamp(current->subtype, 0, NUM_WEAPONS-1)].visual_size;
+	
+	vec2 startpos(current->x, current->y);
+	vec2 startvel(current->vx/100.0f, current->vy/100.0f);
+	vec2 pos = calc_pos(startpos, startvel, curvature, speed, ct);
+	vec2 prevpos = calc_pos(startpos, startvel, curvature, speed, ct-0.001f);
+	
 	gfx_quads_setrotation(0);
+	float offset = pos.y/32.0f + pos.x/32.0f;
+	pos.x += cosf(client_localtime()*2.0f+offset)*2.5f;
+	pos.y += sinf(client_localtime()*2.0f+offset)*2.5f;
+	draw_sprite(pos.x, pos.y, size);
 	gfx_quads_end();
 }
 
 void ITEMS::render_pickup(const NETOBJ_PICKUP *prev, const NETOBJ_PICKUP *current)
 {
-	gfx_texture_set(data->images[IMAGE_GAME].id);
+	if ((current->type == POWERUP_WEAPON && (current->subtype >WEAPON_RIFLE && current->subtype != WEAPON_NINJA))
+	|| (current->type == POWERUP_SPECIAL && current->subtype != SPECIAL_NINJAPWR && current->subtype != SPECIAL_YELLOWARMOR))
+		gfx_texture_set(data->images[IMAGE_EGAME].id);
+	else
+		gfx_texture_set(data->images[IMAGE_GAME].id);
+	
 	gfx_quads_begin();
 	vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick());
 	float angle = 0.0f;
@@ -89,23 +179,32 @@ void ITEMS::render_pickup(const NETOBJ_P
 		select_sprite(data->weapons.id[clamp(current->subtype, 0, NUM_WEAPONS-1)].sprite_body);
 		size = data->weapons.id[clamp(current->subtype, 0, NUM_WEAPONS-1)].visual_size;
 	}
-	else
+	else if (current->type == POWERUP_SPECIAL)
 	{
 		const int c[] = {
-			SPRITE_PICKUP_HEALTH,
-			SPRITE_PICKUP_ARMOR,
-			SPRITE_PICKUP_WEAPON,
-			SPRITE_PICKUP_NINJA
+			0,
+			SPRITE_HEALTH_OVERFILL,
+			SPRITE_ARMOR_FULL,
+			SPRITE_ARMOR_OVERFILL,
+			SPRITE_HOOK_CHAIN,
+			SPRITE_PICKUP_NINJA,
+			SPRITE_HOOK_HEAD,
 			};
-		select_sprite(c[current->type]);
-
-		if(c[current->type] == SPRITE_PICKUP_NINJA)
-		{
+			select_sprite(c[current->subtype]);
+		
 			gameclient.effects->powerupshine(pos, vec2(96,18));
 			size *= 2.0f;
 			pos.x += 10.0f;
-		}
 	}
+	else
+	{
+		const int c[] = {
+			SPRITE_PICKUP_HEALTH,
+			SPRITE_PICKUP_ARMOR,
+			};
+			select_sprite(c[current->type]);
+	}
+
 
 	gfx_quads_setrotation(angle);
 
@@ -146,71 +245,251 @@ void ITEMS::render_flag(const NETOBJ_FLA
 	gfx_quads_end();
 }
 
+void ITEMS::render_shaft_beam(const struct NETOBJ_SHAFT_BEAM *current) {
+		vec2 pos = vec2(current->x, current->y);
+		vec2 from = PLAYERS::get_intratick_pos(current->playerID);
+		vec2 dir = normalize(pos-from);
+		float dist = length(pos-from);
+		
+	
+		// beam is from local player? use local (more precise) coords then
+		if (current->playerID == gameclient.snap.local_cid) {
+			from = gameclient.predicted_char.pos;
+			// get the intersecting position TODO: get this from the /server/character's activesparkle somehow...			
+			//pos = (from + normalize(pos-from)*tuning.shaft_range);
+			//col_intersect_line(from, pos, &pos, 0x0);
+			pos = gameclient.controls->target_pos;
+			// approximate by length of ray from "unprecise" ray
+			dir = normalize(pos-from);
+			pos = from + (dir*dist);
+		}
+		dist = length(pos-from);
 
-void ITEMS::render_laser(const struct NETOBJ_LASER *current)
-{
-	vec2 pos = vec2(current->x, current->y);
-	vec2 from = vec2(current->from_x, current->from_y);
-	vec2 dir = normalize(pos-from);
-
-	float ticks = client_tick() + client_intratick() - current->start_tick;
-	float ms = (ticks/50.0f) * 1000.0f;
-	float a =  ms / gameclient.tuning.laser_bounce_delay;
-	a = clamp(a, 0.0f, 1.0f);
-	float ia = 1-a;
+		vec2 out, border;
 	
-	vec2 out, border;
+		
+		// render inner beam
+		gfx_blend_normal();		
+		gfx_texture_set(-1);
 	
-	gfx_blend_normal();
-	gfx_texture_set(-1);
-	gfx_quads_begin();
+		gfx_quads_begin();		
+		// do outline
+		gfx_setcolor(1.0,1.0,0.8,1.0f);
+		out = vec2(dir.y, -dir.x) * 3;
+
+		gfx_quads_draw_freeform(
+				from.x-out.x, from.y-out.y,
+				from.x+out.x, from.y+out.y,
+				pos.x-out.x, pos.y-out.y,
+				pos.x+out.x, pos.y+out.y
+			);
+			
+		gfx_quads_end();
 	
-	//vec4 inner_color(0.15f,0.35f,0.75f,1.0f);
-	//vec4 outer_color(0.65f,0.85f,1.0f,1.0f);
-
-	// do outline
-	vec4 outer_color(0.075f,0.075f,0.25f,1.0f);
-	gfx_setcolor(outer_color.r,outer_color.g,outer_color.b,1.0f);
-	out = vec2(dir.y, -dir.x) * (7.0f*ia);
-
-	gfx_quads_draw_freeform(
-			from.x-out.x, from.y-out.y,
-			from.x+out.x, from.y+out.y,
-			pos.x-out.x, pos.y-out.y,
-			pos.x+out.x, pos.y+out.y
-		);
-
-	// do inner	
-	vec4 inner_color(0.5f,0.5f,1.0f,1.0f);
-	out = vec2(dir.y, -dir.x) * (5.0f*ia);
-	gfx_setcolor(inner_color.r, inner_color.g, inner_color.b, 1.0f); // center
-	
-	gfx_quads_draw_freeform(
-			from.x-out.x, from.y-out.y,
-			from.x+out.x, from.y+out.y,
-			pos.x-out.x, pos.y-out.y,
-			pos.x+out.x, pos.y+out.y
-		);
+	
+		// render sprites
+		gfx_blend_additive();		
+		gfx_texture_set(data->images[IMAGE_EGAME].id);		
 		
-	gfx_quads_end();
+		gfx_quads_begin();		
+		select_sprite(SPRITE_SHAFT_BEAM1);
+		gfx_setcolor(1.0,1.0,0.8,1.0f);
 	
-	// render head
+		gfx_quads_setrotation(get_angle(dir));
+	
+		float size = 15;
+		float offset = 40;
+		float move = offset - dist/2;
+		
+		gfx_quads_draw(pos.x+dir.x*move, pos.y+dir.y*move, dist - offset/2, 2*size + 10 * cos((float)client_tick()));			
+		gfx_quads_end();
+		
+		// render head
+		{
+			gfx_blend_additive();
+			gfx_texture_set(data->images[IMAGE_EGAME].id);
+			gfx_quads_begin();
+
+			gfx_setcolor(1.0,1.0,1.0,0.3f);
+			int sprites[] = {SPRITE_SHAFT_END1, SPRITE_SHAFT_END2, SPRITE_SHAFT_END3};
+			select_sprite(sprites[client_tick()%3]);
+			gfx_quads_setrotation(client_tick());
+			gfx_quads_draw(pos.x, pos.y, 50,50);
+			
+			gfx_setcolor(1.0,1.0,1.0,1.0f);
+			gfx_quads_setrotation(client_tick()*2);
+			gfx_quads_draw(pos.x, pos.y, 25,25);
+			gfx_quads_end();
+		}
+		
+		gfx_blend_normal();
+}
+
+void ITEMS::render_laser(const struct NETOBJ_LASER *current)
+{
+	if (current->type == WEAPON_RIFLE) 
 	{
+		vec2 pos = vec2(current->x, current->y);
+		vec2 from = vec2(current->from_x, current->from_y);
+		vec2 dir = normalize(pos-from);
+
+		float ticks = client_tick() + client_intratick() - current->start_tick;
+		float ms = (ticks/50.0f) * 1000.0f;
+		float a =  ms / gameclient.tuning.laser_bounce_delay;
+		a = clamp(a, 0.0f, 1.0f);
+		float ia = 1-a;
+		
+		vec2 out, border;
+		
 		gfx_blend_normal();
-		gfx_texture_set(data->images[IMAGE_PARTICLES].id);
+		gfx_texture_set(-1);
 		gfx_quads_begin();
+		
+		//vec4 inner_color(0.15f,0.35f,0.75f,1.0f);
+		//vec4 outer_color(0.65f,0.85f,1.0f,1.0f);
 
-		int sprites[] = {SPRITE_PART_SPLAT01, SPRITE_PART_SPLAT02, SPRITE_PART_SPLAT03};
-		select_sprite(sprites[client_tick()%3]);
-		gfx_quads_setrotation(client_tick());
+		// do outline
+		vec4 outer_color(0.075f,0.075f,0.25f,1.0f);
 		gfx_setcolor(outer_color.r,outer_color.g,outer_color.b,1.0f);
-		gfx_quads_draw(pos.x, pos.y, 24,24);
-		gfx_setcolor(inner_color.r, inner_color.g, inner_color.b, 1.0f);
-		gfx_quads_draw(pos.x, pos.y, 20,20);
+		out = vec2(dir.y, -dir.x) * (7.0f*ia);
+
+		gfx_quads_draw_freeform(
+				from.x-out.x, from.y-out.y,
+				from.x+out.x, from.y+out.y,
+				pos.x-out.x, pos.y-out.y,
+				pos.x+out.x, pos.y+out.y
+			);
+
+		// do inner	
+		vec4 inner_color(0.5f,0.5f,1.0f,1.0f);
+		out = vec2(dir.y, -dir.x) * (5.0f*ia);
+		gfx_setcolor(inner_color.r, inner_color.g, inner_color.b, 1.0f); // center
+		
+		gfx_quads_draw_freeform(
+				from.x-out.x, from.y-out.y,
+				from.x+out.x, from.y+out.y,
+				pos.x-out.x, pos.y-out.y,
+				pos.x+out.x, pos.y+out.y
+			);
+			
 		gfx_quads_end();
+		
+		// render head
+		{
+			gfx_blend_normal();
+			gfx_texture_set(data->images[IMAGE_PARTICLES].id);
+			gfx_quads_begin();
+
+			int sprites[] = {SPRITE_PART_SPLAT01, SPRITE_PART_SPLAT02, SPRITE_PART_SPLAT03};
+			select_sprite(sprites[client_tick()%3]);
+			gfx_quads_setrotation(client_tick());
+			gfx_setcolor(outer_color.r,outer_color.g,outer_color.b,1.0f);
+			gfx_quads_draw(pos.x, pos.y, 24,24);
+			gfx_setcolor(inner_color.r, inner_color.g, inner_color.b, 1.0f);
+			gfx_quads_draw(pos.x, pos.y, 20,20);
+			gfx_quads_end();
+		}
+		
+		gfx_blend_normal();
+	}
+	else if (current->type == WEAPON_SPINGUN)
+	{
+		render_vortex(current);
 	}
+	return;
+}
+
+void ITEMS::render_vortex(const struct NETOBJ_LASER *current)
+{
+	vec2 pos = vec2(current->x, current->y);
+	
+	float ticks = client_tick() + client_intratick() - current->start_tick;
+	float tfactor = client_tickspeed() / 1000.0f;
+	float lifespan = tfactor*VORTEX::lifespan(); // in client ticks
+	
+	float size = 120;
+	float a = (lifespan-ticks)/lifespan;
+	float shrinktresh = 0.7;
+
+	if (a<shrinktresh)
+		size = size * a / shrinktresh;
+
+	gfx_texture_set(data->images[IMAGE_EGAME].id);
+	// render halos
+	gfx_blend_additive();
+	gfx_quads_begin();
+	select_sprite(SPRITE_WEAPON_SPINGUN_HALO);		
+	gfx_setcolor(0.5, 0.5, 0.9, a/2);
+	float hs = (1-a)*20;
+	hs = hs*hs + 30;
+	
+	gfx_quads_draw(pos.x, pos.y, hs*2, hs*2);	
+	gfx_quads_end();
+	
+	gfx_quads_begin();
+	select_sprite(SPRITE_WEAPON_SPINGUN_HALO);
+	hs = (1-a)*100 + 30;	
+	
+	// render vortexes
+	gfx_blend_subtractive();	
+	
+	gfx_setcolor(0.6, 0.7, 1.0, a/4);
+	gfx_quads_draw(pos.x, pos.y, hs, hs);	
+	
+	select_sprite(SPRITE_WEAPON_SPINGUN_VORTEX);		
+	gfx_setcolor(1.0f, 1.0, 1.0, a/2);	
+	gfx_quads_setrotation(ticks/25.0);
+	gfx_quads_draw(pos.x, pos.y, size*1.5, size*1.5);
+	
+	gfx_setcolor(0.9, 0.90, 1.0, a);
+	gfx_quads_setrotation(ticks/10.0);
+	gfx_quads_draw(pos.x, pos.y, size*1.1, size*1.1);
+	
+	// render lightnings
+	gfx_quads_end();
+	gfx_blend_additive();
+	gfx_quads_begin();
+	
+	float times[] = {1, 0.95, 0.92, 0.85, 0.80};
+	int sprites[] = {SPRITE_WEAPON_SPINGUN_LIGHTNING1, SPRITE_WEAPON_SPINGUN_LIGHTNING2};
+	float ls = 0.4;
+	
+	for (int i=0; i<5; i++) {
+		if (a < times[i] - ls)
+			continue;
+		if (a > times[i])
+			break;
+		
+		select_sprite(sprites[i%2]);
+		
+		gfx_setcolor(1.0f, 1.0, 1.0, (a - (times[i]-ls))/ls);
+		float angle = i * 27 * (current->start_tick % 300); 
+		
+		vec2 dir = get_dir(angle);
+		angle = get_angle(dir);
+		gfx_quads_setrotation(angle - pi/2);
+		float s = 50;
+		gfx_quads_draw(pos.x - dir.x * s , pos.y - dir.y*s, s, s*2);
+	}
+	
+	gfx_quads_end();
+	gfx_blend_subtractive();
+	
+	gfx_quads_begin();
+	select_sprite(SPRITE_WEAPON_SPINGUN_VORTEX);
+	// rest of vortex
+	gfx_setcolor(1.0f, 1.0, 1.0, a);
+	gfx_quads_setrotation(ticks/8.0);
+	gfx_quads_draw(pos.x, pos.y, size*0.8, size*0.8);	
+	
+	gfx_setcolor(1.0f, 1.0, 1.0, a);
+	gfx_quads_setrotation(ticks/6.0);
+	gfx_quads_draw(pos.x, pos.y, size*0.6, size*0.6);
+	
+	gfx_quads_end();	
+	
+	gfx_blend_normal();
 	
-	gfx_blend_normal();	
 }
 
 void ITEMS::on_render()
@@ -225,6 +504,10 @@ void ITEMS::on_render()
 		{
 			render_projectile((const NETOBJ_PROJECTILE *)data, item.id);
 		}
+		else if(item.type == NETOBJTYPE_DROPPED_WEAPON)
+		{
+			render_DROPPEDWEAPON((const NETOBJ_DROPPED_WEAPON *)data);
+		}
 		else if(item.type == NETOBJTYPE_PICKUP)
 		{
 			const void *prev = snap_find_item(SNAP_PREV, item.type, item.id);
@@ -240,6 +523,10 @@ void ITEMS::on_render()
 			const void *prev = snap_find_item(SNAP_PREV, item.type, item.id);
 			if (prev)
 				render_flag((const NETOBJ_FLAG *)prev, (const NETOBJ_FLAG *)data);
+		} 
+		else if(item.type == NETOBJTYPE_SHAFT_BEAM)
+		{
+			render_shaft_beam((const NETOBJ_SHAFT_BEAM *)data);
 		}
 	}
 
diff -rupN d:\t052/src/game/client/components/items.hpp d:\eg/src/game/client/components/items.hpp
--- d:\t052/src/game/client/components/items.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/components/items.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -3,11 +3,13 @@
 class ITEMS : public COMPONENT
 {	
 	void render_projectile(const NETOBJ_PROJECTILE *current, int itemid);
+	void render_DROPPEDWEAPON(const NETOBJ_DROPPED_WEAPON *current);
 	void render_pickup(const NETOBJ_PICKUP *prev, const NETOBJ_PICKUP *current);
 	void render_flag(const NETOBJ_FLAG *prev, const NETOBJ_FLAG *current);
 	void render_laser(const struct NETOBJ_LASER *current);
+	void render_vortex(const struct NETOBJ_LASER *current);
+	void render_shaft_beam(const struct NETOBJ_SHAFT_BEAM *current);
 	
 public:
 	virtual void on_render();
-};
-
+};
\ No newline at end of file
diff -rupN d:\t052/src/game/client/components/killmessages.cpp d:\eg/src/game/client/components/killmessages.cpp
--- d:\t052/src/game/client/components/killmessages.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/components/killmessages.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -86,7 +86,11 @@ void KILLMESSAGES::on_render()
 		x -= 44.0f;
 		if (killmsgs[r].weapon >= 0)
 		{
-			gfx_texture_set(data->images[IMAGE_GAME].id);
+			if(killmsgs[r].weapon > WEAPON_RIFLE && killmsgs[r].weapon != WEAPON_NINJA)
+				gfx_texture_set(data->images[IMAGE_EGAME].id);
+			else
+				gfx_texture_set(data->images[IMAGE_GAME].id);
+				
 			gfx_quads_begin();
 			select_sprite(data->weapons.id[killmsgs[r].weapon].sprite_body);
 			draw_sprite(x, y+28, 96);
diff -rupN d:\t052/src/game/client/components/menus_settings.cpp d:\eg/src/game/client/components/menus_settings.cpp
--- d:\t052/src/game/client/components/menus_settings.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/components/menus_settings.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -260,8 +260,12 @@ KEYINFO keys[] = 
 	{ "Shotgun:", "+weapon3", 0 },
 	{ "Grenade:", "+weapon4", 0 },
 	{ "Rifle:", "+weapon5", 0 },
+	{ "Shaft:", "+weapon6", 0 },
+	{ "Spin Gun:", "+weapon7", 0 },
+	{ "Biorifle:", "+weapon8", 0 },
 	{ "Next Weapon:", "+nextweapon", 0 },
 	{ "Prev. Weapon:", "+prevweapon", 0 },
+	{ "Drop Weapon:", "+dropweapon", 0 },
 	{ "Vote Yes:", "vote yes", 0 },
 	{ "Vote No:", "vote no", 0 },
 	{ "Chat:", "chat all", 0 },
@@ -271,6 +275,7 @@ KEYINFO keys[] = 
 	{ "Remote Console:", "toggle_remote_console", 0 },
 	{ "Screenshot:", "screenshot", 0 },
 	{ "Scoreboard:", "+scoreboard", 0 },
+	{ "Personal Scoreboard:", "+personal_scoreboard", 0 },
 };
 
 const int key_count = sizeof(keys) / sizeof(KEYINFO);
@@ -321,7 +326,8 @@ void MENUS::render_settings_controls(REC
 	
 	/* movement settings */
 	{
-		ui_hsplit_t(&movement_settings, main_view.h/2-5.0f, &movement_settings, &weapon_settings);
+		//ui_hsplit_t(&movement_settings, main_view.h/2-5.0f, &movement_settings, &weapon_settings);
+		ui_hsplit_t(&movement_settings, main_view.h/2-55.0f, &movement_settings, &weapon_settings);
 		ui_draw_rect(&movement_settings, vec4(1,1,1,0.25f), CORNER_ALL, 10.0f);
 		ui_margin(&movement_settings, 10.0f, &movement_settings);
 		
@@ -346,6 +352,7 @@ void MENUS::render_settings_controls(REC
 	
 	/* weapon settings */
 	{
+		//ui_hsplit_t(&weapon_settings, 10.0f, 0, &weapon_settings);
 		ui_hsplit_t(&weapon_settings, 10.0f, 0, &weapon_settings);
 		ui_draw_rect(&weapon_settings, vec4(1,1,1,0.25f), CORNER_ALL, 10.0f);
 		ui_margin(&weapon_settings, 10.0f, &weapon_settings);
@@ -353,7 +360,7 @@ void MENUS::render_settings_controls(REC
 		gfx_text(0, weapon_settings.x, weapon_settings.y, 14, "Weapon", -1);
 		
 		ui_hsplit_t(&weapon_settings, 14.0f+5.0f+10.0f, 0, &weapon_settings);
-		ui_do_getbuttons(5, 12, weapon_settings);
+		ui_do_getbuttons(5, 16, weapon_settings);
 	}
 	
 	/* voting settings */
@@ -366,7 +373,7 @@ void MENUS::render_settings_controls(REC
 		gfx_text(0, voting_settings.x, voting_settings.y, 14, "Voting", -1);
 		
 		ui_hsplit_t(&voting_settings, 14.0f+5.0f+10.0f, 0, &voting_settings);
-		ui_do_getbuttons(12, 14, voting_settings);
+		ui_do_getbuttons(16, 18, voting_settings);
 	}
 	
 	/* chat settings */
@@ -379,7 +386,7 @@ void MENUS::render_settings_controls(REC
 		gfx_text(0, chat_settings.x, chat_settings.y, 14, "Chat", -1);
 		
 		ui_hsplit_t(&chat_settings, 14.0f+5.0f+10.0f, 0, &chat_settings);
-		ui_do_getbuttons(14, 16, chat_settings);
+		ui_do_getbuttons(18, 20, chat_settings);
 	}
 	
 	/* misc settings */
@@ -392,7 +399,7 @@ void MENUS::render_settings_controls(REC
 		gfx_text(0, misc_settings.x, misc_settings.y, 14, "Miscellaneous", -1);
 		
 		ui_hsplit_t(&misc_settings, 14.0f+5.0f+10.0f, 0, &misc_settings);
-		ui_do_getbuttons(16, 21, misc_settings);
+		ui_do_getbuttons(20, 26, misc_settings);
 	}
 	
 	// defaults
diff -rupN d:\t052/src/game/client/components/players.cpp d:\eg/src/game/client/components/players.cpp
--- d:\t052/src/game/client/components/players.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/components/players.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -97,6 +97,23 @@ void PLAYERS::render_player(
 	if(gameclient.snap.gameobj)
 		is_teamplay = (gameclient.snap.gameobj->flags&GAMEFLAG_TEAMS) != 0;
 
+	// check for powersuit
+	if (player.specialstate == 1 || player.specialstate == 3)
+	{
+		int skin = gameclient.skins->find("x_suit");
+		if(skin != -1)
+		{
+			if(is_teamplay)
+				render_info.texture = gameclient.skins->get(skin)->color_texture;
+			else
+			{
+				render_info.texture = gameclient.skins->get(skin)->org_texture;
+				render_info.color_body = vec4(1,1,1,1);
+				render_info.color_feet = vec4(1,1,1,1);
+			}
+		}	
+	}
+	
 	// check for ninja	
 	if (player.weapon == WEAPON_NINJA)
 	{
@@ -114,7 +131,7 @@ void PLAYERS::render_player(
 			}
 		}	
 	}
-	
+
 	// set size
 	render_info.size = 64.0f;
 
@@ -265,6 +282,10 @@ void PLAYERS::render_player(
 		// render head
 		select_sprite(SPRITE_HOOK_HEAD);
 		gfx_quads_draw(hook_pos.x, hook_pos.y, 24,16);
+		if(player.specialstate == 2 || player.specialstate == 3)
+		{
+			gameclient.effects->powerupshine(vec2(hook_pos.x, hook_pos.y), vec2(18,18));
+		}
 
 		// render chain
 		select_sprite(SPRITE_HOOK_CHAIN);
@@ -273,6 +294,11 @@ void PLAYERS::render_player(
 		{
 			vec2 p = hook_pos + dir*f;
 			gfx_quads_draw(p.x, p.y,24,16);
+			
+			if(player.specialstate == 2 || player.specialstate == 3)
+			{
+				gameclient.effects->powerupshine(vec2(p.x, p.y), vec2(18,18));
+			}
 		}
 
 		gfx_quads_setrotation(0);
@@ -283,7 +309,11 @@ void PLAYERS::render_player(
 
 	// draw gun
 	{
-		gfx_texture_set(data->images[IMAGE_GAME].id);
+		if(player.weapon > WEAPON_RIFLE && player.weapon != WEAPON_NINJA)		
+			gfx_texture_set(data->images[IMAGE_EGAME].id);
+		else 
+			gfx_texture_set(data->images[IMAGE_GAME].id);
+
 		gfx_quads_begin();
 		gfx_quads_setrotation(state.attach.angle*pi*2+angle);
 
@@ -492,3 +522,12 @@ void PLAYERS::on_render()
 		}
 	}
 }
+
+vec2 PLAYERS::get_intratick_pos(int clientID) 
+{
+	NETOBJ_CHARACTER prev_char = gameclient.snap.characters[clientID].prev;
+	NETOBJ_CHARACTER cur_char = gameclient.snap.characters[clientID].cur;
+	float intratick = client_intratick();
+	vec2 position = mix(vec2(prev_char.x, prev_char.y), vec2(cur_char.x, cur_char.y), intratick);
+	return position;
+}
\ No newline at end of file
diff -rupN d:\t052/src/game/client/components/players.hpp d:\eg/src/game/client/components/players.hpp
--- d:\t052/src/game/client/components/players.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/components/players.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -12,5 +12,6 @@ class PLAYERS : public COMPONENT
 	
 public:
 	virtual void on_render();
+	static vec2 get_intratick_pos(int clientID);
 };
 
diff -rupN d:\t052/src/game/client/components/scoreboard.cpp d:\eg/src/game/client/components/scoreboard.cpp
--- d:\t052/src/game/client/components/scoreboard.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/components/scoreboard.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -106,7 +106,7 @@ void SCOREBOARD::render_spectators(float
 
 void SCOREBOARD::render_scoreboard(float x, float y, float w, int team, const char *title)
 {
-	//float ystart = y;
+	float ystart = y;
 	float h = 750.0f;
 
 	gfx_blend_normal();
@@ -145,7 +145,13 @@ void SCOREBOARD::render_scoreboard(float
 		}
 	}
 
-	y += 54.0f;
+	gfx_text(0, x+w/2-70, y, 24.0f, "Avg", -1);
+	gfx_text(0, x+w/2+40, y, 24.0f, "Avg", -1);
+	y += 27.0f;
+
+	gfx_text(0, x+w/2-70, y, 24.0f, "Acc", -1);
+	gfx_text(0, x+w/2+40, y, 24.0f, "Ping", -1);
+	y += 27.0f;
 
 	// find players
 	const NETOBJ_PLAYER_INFO *players[MAX_CLIENTS] = {0};
@@ -184,6 +190,8 @@ void SCOREBOARD::render_scoreboard(float
 	gfx_text(0, x+10, y, 24.0f, "Score", -1);
 	gfx_text(0, x+125, y, 24.0f, "Name", -1);
 	gfx_text(0, x+w-70, y, 24.0f, "Ping", -1);
+	gfx_text(0, x+w-255, y, 24.0f, "Net", -1);
+	gfx_text(0, x+w-200, y, 24.0f, "Accuracy", -1);
 	y += 29.0f;
 
 	float font_size = 35.0f;
@@ -199,6 +207,8 @@ void SCOREBOARD::render_scoreboard(float
 		tee_offset = -5.0f;
 	}
 	
+	int avgping = 0;
+	int avgaccuracy = 0;
 	// render player scores
 	for(int i = 0; i < num_players; i++)
 	{
@@ -220,6 +230,12 @@ void SCOREBOARD::render_scoreboard(float
 		str_format(buf, sizeof(buf), "%4d", info->score);
 		gfx_text(0, x+60-gfx_text_width(0, font_size,buf,-1), y, font_size, buf, -1);
 		
+		str_format(buf, sizeof(buf), "%4d", info->overall_accuracy);
+		gfx_text(0, x+w-140-gfx_text_width(0, font_size,buf,-1), y, font_size, buf, -1);
+		
+		str_format(buf, sizeof(buf), "%4d", info->netscore);
+		gfx_text(0, x+w-225-gfx_text_width(0, font_size,buf,-1), y, font_size, buf, -1);
+		
 		gfx_text(0, x+128, y, font_size, gameclient.clients[info->cid].name, -1);
 
 		str_format(buf, sizeof(buf), "%4d", info->latency);
@@ -246,9 +262,25 @@ void SCOREBOARD::render_scoreboard(float
 		teeinfo.size *= tee_sizemod;
 		render_tee(ANIMSTATE::get_idle(), &teeinfo, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28+tee_offset));
 
+		avgping += info->latency;
+		avgaccuracy += info->overall_accuracy;
 		
 		y += line_height;
 	}
+	if(num_players > 1)
+	{
+		avgping = avgping / num_players;
+		avgaccuracy = avgaccuracy / (num_players + 1);
+	}
+	
+	char buf[128];
+	str_format(buf, sizeof(buf), "%d", avgping);
+	tw = gfx_text_width(0, 48, buf, -1);
+	gfx_text(0, x+w-tw-170, ystart, 48, buf, -1);
+	
+	str_format(buf, sizeof(buf), "%d", avgaccuracy);
+	tw = gfx_text_width(0, 48, buf, -1);
+	gfx_text(0, x+w-tw-300, ystart, 48, buf, -1);
 }
 
 void SCOREBOARD::on_render()
@@ -261,7 +293,7 @@ void SCOREBOARD::on_render()
 		
 	if(gameclient.snap.local_info && gameclient.snap.local_info->team != -1)
 	{
-		// we are not a spectator, check if we are ead
+		// we are not a spectator, check if we are dead
 		if(!gameclient.snap.local_character || gameclient.snap.local_character->health < 0)
 			do_scoreboard = true;
 	}
diff -rupN d:\t052/src/game/client/gameclient.cpp d:\eg/src/game/client/gameclient.cpp
--- d:\t052/src/game/client/gameclient.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/client/gameclient.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -504,6 +504,11 @@ void GAMECLIENT::process_events()
 			NETEVENT_HAMMERHIT *ev = (NETEVENT_HAMMERHIT *)data;
 			gameclient.effects->hammerhit(vec2(ev->x, ev->y));
 		}
+		else if(item.type == NETEVENTTYPE_BIOSPLASH)
+		{
+			NETEVENT_BIOSPLASH *ev = (NETEVENT_BIOSPLASH *)data;
+			gameclient.effects->biosplash(vec2(ev->x, ev->y), ev->playSound);
+		}
 		else if(item.type == NETEVENTTYPE_SPAWN)
 		{
 			NETEVENT_SPAWN *ev = (NETEVENT_SPAWN *)data;
diff -rupN d:\t052/src/game/collision.cpp d:\eg/src/game/collision.cpp
--- d:\t052/src/game/collision.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/collision.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -12,6 +12,10 @@
 static TILE *tiles;
 static int width = 0;
 static int height = 0;
+//tele
+static int *dest[42];
+static int len[42];
+static int tele[42];
 
 int col_width() { return width; }
 int col_height() { return height; }
@@ -22,6 +26,31 @@ int col_init()
 	height = layers_game_layer()->height;
 	tiles = (TILE *)map_get_data(layers_game_layer()->data);
 	
+// more tele
+	mem_zero(&len, sizeof(len));
+	mem_zero(&tele, sizeof(tele));
+	for(int i = width*height-1; i >= 0; i--)
+	{
+		if(tiles[i].index > 34 && tiles[i].index < 85)
+		{
+			if(tiles[i].index&1)
+				len[tiles[i].index >> 1]++;
+			else if(!(tiles[i].index&1))
+				tele[(tiles[i].index-1) >> 1]++;
+		}
+	}
+	for(int i = 0; i < 42; i++)
+	{
+		dest[i] = new int[len[i]];
+		len[i] = 0;
+	}
+	for(int i = width*height-1; i >= 0; i--)
+	{
+		if(tiles[i].index&1 && tiles[i].index > 34 && tiles[i].index < 85)
+			dest[tiles[i].index>>1][len[tiles[i].index>>1]++] = i;
+	}
+
+	
 	for(int i = 0; i < width*height; i++)
 	{
 		int index = tiles[i].index;
@@ -36,7 +65,7 @@ int col_init()
 		else if(index == TILE_NOHOOK)
 			tiles[i].index = COLFLAG_SOLID|COLFLAG_NOHOOK;
 		else
-			tiles[i].index = 0;
+			tiles[i].index = index;
 	}
 				
 	return 1;
@@ -50,7 +79,10 @@ int col_get(int x, int y)
 	
 	if(tiles[ny*width+nx].index > 128)
 		return 0;
-	return tiles[ny*width+nx].index;
+	if(tiles[ny*width+nx].index == COLFLAG_SOLID || tiles[ny*width+nx].index == (COLFLAG_SOLID|COLFLAG_NOHOOK) || tiles[ny*width+nx].index == COLFLAG_DEATH)
+		return tiles[ny*width+nx].index;
+	else
+		return 0;
 }
 
 int col_is_solid(int x, int y)
@@ -58,6 +90,42 @@ int col_is_solid(int x, int y)
 	return col_get(x,y)&COLFLAG_SOLID;
 }
 
+//even more tele
+int col_is_teleport(int x, int y)
+{
+	int nx = x/32;
+	int ny = y/32;
+	if(y < 0 || nx < 0 || nx >= width || ny >= height)
+		return 0;
+	
+	int z = tiles[ny*width+nx].index-1;
+	if(z > 34 && z < 85 && z&1)
+		return z>>1;
+	return 0;
+}
+
+int col_get_index(int x, int y)
+{
+	int nx = x/32;
+	int ny = y/32;
+	if(y<0 || nx < 0 || nx >= width || ny >= height)
+		return 0;
+	
+	return tiles[ny*width+nx].index;
+}
+
+vec2 teleport(int z)
+{
+	if(len[z] > 0)
+	{
+		int r = rand()%len[z];
+		int x = (dest[z][r]%width)<<5;
+		int y = (dest[z][r]/width)<<5;
+		return vec2((float)x+16.0, (float)y+16.0);
+	}
+	else
+		return vec2(0,0);
+}
 
 // TODO: rewrite this smarter!
 int col_intersect_line(vec2 pos0, vec2 pos1, vec2 *out_collision, vec2 *out_before_collision)
diff -rupN d:\t052/src/game/collision.hpp d:\eg/src/game/collision.hpp
--- d:\t052/src/game/collision.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/collision.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -9,10 +9,14 @@ enum
 	COLFLAG_SOLID=1,
 	COLFLAG_DEATH=2,
 	COLFLAG_NOHOOK=4,
+	COLFLAG_TELE=7,
 };
 
 int col_init();
 int col_is_solid(int x, int y);
+int col_is_teleport(int x, int y);
+int col_get_index(int x, int y);
+vec2 teleport(int z);
 int col_get(int x, int y);
 int col_width();
 int col_height();
diff -rupN d:\t052/src/game/gamecore.cpp d:\eg/src/game/gamecore.cpp
--- d:\t052/src/game/gamecore.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/gamecore.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -1,6 +1,7 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
 #include <string.h>
 #include "gamecore.hpp"
+#include <game/generated/gs_data.hpp>
 
 const char *TUNING_PARAMS::names[] =
 {
@@ -177,6 +178,8 @@ void CHARACTER_CORE::reset()
 	hooked_player = -1;
 	jumped = 0;
 	triggered_events = 0;
+	hook_power = GREY;
+	suit = false;
 }
 
 void CHARACTER_CORE::tick(bool use_input)
@@ -199,6 +202,24 @@ void CHARACTER_CORE::tick(bool use_input
 	float accel = grounded ? world->tuning.ground_control_accel : world->tuning.air_control_accel;
 	float friction = grounded ? world->tuning.ground_friction : world->tuning.air_friction;
 	
+	// the hook-powerup
+	if (hook_power)
+	{
+		if(gold_decaytick > data->specials.id[SPECIAL_HOOKPWR].duration * SERVER_TICK_SPEED / 1000)
+			hook_power = GREY;
+		else 
+			gold_decaytick++;
+	}
+	
+	// the powersuit
+	if (suit)
+	{
+		if(suit_decaytick > data->specials.id[SPECIAL_POWERSUIT].duration * SERVER_TICK_SPEED / 1000)
+			suit = false;
+		else 
+			suit_decaytick++;
+	}
+	
 	// handle input
 	if(use_input)
 	{
@@ -305,7 +326,7 @@ void CHARACTER_CORE::tick(bool use_input
 		int hit = col_intersect_line(hook_pos, new_pos, &new_pos, 0);
 		if(hit)
 		{
-			if(hit&COLFLAG_NOHOOK)
+			if(hit&COLFLAG_NOHOOK && !(hook_power))
 				going_to_retract = true;
 			else
 				going_to_hit_ground = true;
@@ -333,7 +354,17 @@ void CHARACTER_CORE::tick(bool use_input
 					}
 				}
 			}
-		}
+		
+		if(hooked_player != -1 && world->characters[hooked_player])
+			if (world->characters[hooked_player]->suit)
+			{
+				hook_state = HOOK_RETRACTED;
+				triggered_events |= COREEVENT_HOOK_RETRACT;
+				going_to_retract = true;
+			}
+
+	}
+		
 		
 		if(hook_state == HOOK_FLYING)
 		{
@@ -397,8 +428,17 @@ void CHARACTER_CORE::tick(bool use_input
 				
 		}
 
-		// release hook (max hook time is 1.25
+		// release hook (max hook time is 1.25)
 		hook_tick++;
+		
+		if(hooked_player != -1 && world->characters[hooked_player])
+			if(world->characters[hooked_player]->suit)
+			{
+				hooked_player = -1;
+				hook_state = HOOK_RETRACTED;
+				hook_pos = pos;
+			}
+			
 		if(hooked_player != -1 && (hook_tick > SERVER_TICK_SPEED+SERVER_TICK_SPEED/5 || !world->characters[hooked_player]))
 		{
 			hooked_player = -1;
@@ -485,6 +525,7 @@ void CHARACTER_CORE::write(NETOBJ_CHARAC
 	obj_core->jumped = jumped;
 	obj_core->direction = direction;
 	obj_core->angle = angle;
+	obj_core->specialstate = hook_power + (int)suit;
 }
 
 void CHARACTER_CORE::read(const NETOBJ_CHARACTER_CORE *obj_core)
@@ -503,6 +544,16 @@ void CHARACTER_CORE::read(const NETOBJ_C
 	jumped = obj_core->jumped;
 	direction = obj_core->direction;
 	angle = obj_core->angle;
+	if(obj_core->specialstate == 3)
+	{
+		hook_power = GOLD;
+		suit = true;
+	}
+	else if(obj_core->specialstate == 2)
+		hook_power = GOLD;
+	else if(obj_core->specialstate == 1)
+		suit = true;
+	else return;
 }
 
 void CHARACTER_CORE::quantize()
diff -rupN d:\t052/src/game/gamecore.hpp d:\eg/src/game/gamecore.hpp
--- d:\t052/src/game/gamecore.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/gamecore.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -137,6 +137,9 @@ enum
 	HOOK_FLYING,
 	HOOK_GRABBED,
 	
+	GREY=0,
+	GOLD=2,
+	
 	COREEVENT_GROUND_JUMP=0x01,
 	COREEVENT_AIR_JUMP=0x02,
 	COREEVENT_HOOK_LAUNCH=0x04,
@@ -171,6 +174,11 @@ public:
 	int hook_tick;
 	int hook_state;
 	int hooked_player;
+	int hook_power;
+	int gold_decaytick;
+	
+	bool suit;
+	int suit_decaytick;
 	
 	int jumped;
 	
diff -rupN d:\t052/src/game/mapitems.hpp d:\eg/src/game/mapitems.hpp
--- d:\t052/src/game/mapitems.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/mapitems.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -39,12 +39,32 @@ enum
 	ENTITY_WEAPON_GRENADE,
 	ENTITY_POWERUP_NINJA,
 	ENTITY_WEAPON_RIFLE,
+	ENTITY_POWERUP_HOOK,
+	ENTITY_WEAPON_SHAFT,
+	ENTITY_WEAPON_SPINGUN,
+	ENTITY_ARMOR_5,
+	ENTITY_ARMOR_10,
+	ENTITY_HEALTH_10,
+	ENTITY_POWERUP_SUIT,
+	ENTITY_WEAPON_BIORIFLE,
 	NUM_ENTITIES,
 	
 	TILE_AIR=0,
 	TILE_SOLID,
 	TILE_DEATH,
 	TILE_NOHOOK,
+	TILE_JUMPPAD_WEAK=23,
+	TILE_JUMPPAD_AVERAGE,
+	TILE_JUMPPAD_STRONG,
+	TILE_BOOSTDOWN_WEAK,
+	TILE_BOOSTDOWN_AVERAGE,
+	TILE_BOOSTDOWN_STRONG,
+	TILE_BOOSTLEFT_WEAK,
+	TILE_BOOSTLEFT_AVERAGE,
+	TILE_BOOSTLEFT_STRONG,
+	TILE_BOOSTRIGHT_WEAK,
+	TILE_BOOSTRIGHT_AVERAGE,
+	TILE_BOOSTRIGHT_STRONG,
 	
 	TILEFLAG_VFLIP=1,
 	TILEFLAG_HFLIP=2,
diff -rupN d:\t052/src/game/server/entities/character.cpp d:\eg/src/game/server/entities/character.cpp
--- d:\t052/src/game/server/entities/character.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/entities/character.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -3,10 +3,14 @@
 #include <engine/e_config.h>
 #include <game/server/gamecontext.hpp>
 #include <game/mapitems.hpp>
+#include <string.h>
 
 #include "character.hpp"
 #include "laser.hpp"
+#include "sparkle.hpp"
 #include "projectile.hpp"
+#include "vortex.hpp"
+#include "droppedweapon.hpp"
 
 struct INPUT_COUNT
 {
@@ -261,7 +265,8 @@ void CHARACTER::fire_weapon()
 	vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y));
 	
 	bool fullauto = false;
-	if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN || active_weapon == WEAPON_RIFLE)
+	if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN || active_weapon == WEAPON_RIFLE 
+		|| active_weapon == WEAPON_SHAFT || active_weapon == WEAPON_BIORIFLE)
 		fullauto = true;
 
 
@@ -349,13 +354,16 @@ void CHARACTER::fire_weapon()
 		case WEAPON_SHOTGUN:
 		{
 			int shotspread = 2;
+			
+			if(game.controller->is_extended())
+				shotspread = 3;
 
 			msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0);
 			msg_pack_int(shotspread*2+1);
 			
 			for(int i = -shotspread; i <= shotspread; i++)
 			{
-				float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f};
+				float spreading[] = {-0.400f, -0.185f, -0.070f, 0, 0.070f, 0.185f, 0.400f, 0.450f};
 				float a = get_angle(direction);
 				a += spreading[i+2];
 				float v = 1-(abs(i)/(float)shotspread);
@@ -410,6 +418,32 @@ void CHARACTER::fire_weapon()
 			game.create_sound(pos, SOUND_RIFLE_FIRE);
 		} break;
 		
+		case WEAPON_SHAFT:
+		{
+			// sparkle isn't recreated, so there can be a constant animation
+			if(activesparkle)
+				activesparkle->cooled = true;
+			else
+				activesparkle = new SPARKLE(pos, direction, player->client_id);
+		} break;
+		
+		case WEAPON_SPINGUN:
+		{
+			new VORTEX(pos, direction, player->client_id);
+		} break;
+		
+		case WEAPON_BIORIFLE:
+		{
+			PROJECTILE *proj = new PROJECTILE(WEAPON_BIORIFLE,
+			player->client_id,
+			projectile_startpos,
+			direction,
+			(int)(server_tickspeed()*tuning.biorifle_lifetime),
+			1, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_BIO_IMPACT, WEAPON_BIORIFLE);
+			
+			game.create_sound(pos, SOUND_BIORIFLE_FIRE);
+		} break;
+		
 		case WEAPON_NINJA:
 		{
 			attack_tick = server_tick();
@@ -426,7 +460,21 @@ void CHARACTER::fire_weapon()
 		} break;
 		
 	}
-
+	
+	//last entry is overall
+	if(active_weapon == WEAPON_SHOTGUN)
+	{
+		player->weapons[NUM_WEAPONS].shots += 5;
+		player->weapons[WEAPON_SHOTGUN].shots += 5;
+	}
+	else
+	{
+		player->weapons[NUM_WEAPONS].shots++;
+		player->weapons[active_weapon].shots++;
+	}
+	
+	update_accuracy(active_weapon);
+	
 	if(weapons[active_weapon].ammo > 0) // -1 == unlimited
 		weapons[active_weapon].ammo--;
 	attack_tick = server_tick();
@@ -437,7 +485,32 @@ void CHARACTER::fire_weapon()
 int CHARACTER::handle_weapons()
 {
 	vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y));
-
+	
+	if (input.drop && !previnput.drop && active_weapon > WEAPON_GUN && active_weapon != WEAPON_NINJA && weapons[active_weapon].ammo)
+	{
+		new DROPPEDWEAPON(pos, direction, active_weapon, weapons[active_weapon].ammo);
+		weapons[active_weapon].ammo = 0;
+		weapons[active_weapon].got = false;
+		
+		if(!weapons[last_weapon].got)
+		{
+			for(int i = 0; i < NUM_WEAPONS; i++)
+			{
+				if(weapons[i].got)
+					last_weapon = i;
+			}
+		}
+		active_weapon = last_weapon;
+	}
+		
+	if (activesparkle)
+		if (latest_input.fire&1 && active_weapon == WEAPON_SHAFT && weapons[WEAPON_SHAFT].ammo)
+			activesparkle->adjust_position(core.pos, direction);
+		else
+		{
+			game.world.destroy_entity(activesparkle);
+			activesparkle = 0x0;
+		}
 	/*
 	if(config.dbg_stress)
 	{
@@ -544,6 +617,89 @@ void CHARACTER::tick()
 	core.input = input;
 	core.tick(true);
 	
+	//overfilldecay
+	if(decaytimer)
+	{
+		decaytimer--;
+		
+		if(!decaytimer)
+		{
+			armor = armor - (int)(armor/11);
+			health = health - (int)(health/11);
+	
+			if(health > 10 || armor > 10)
+				decaytimer = (int)(server_tickspeed()*tuning.overfill_decayrate);
+		}
+	}
+		
+	
+	//check if player is hooked by someone with hook-powerup (hook_power)
+	for (int i = 0; i < MAX_CLIENTS; i++)
+	{
+		if(!core.world->characters[i]) continue;
+		if(core.world->characters[i]->hooked_player == player->client_id && core.world->characters[i]->hook_tick % 17 == 0 && core.world->characters[i]->hook_power)
+		{
+			vec2 dir = normalize(core.pos - core.world->characters[i]->pos);
+			take_damage(dir * 0.001f, tuning.hook_damage, i, WEAPON_HOOK);
+		}
+	}
+	
+	int current_tile_index = col_get_index(core.pos.x, core.pos.y);
+	
+	if(current_tile_index > 22 && current_tile_index < 35 && game.controller->is_extended())
+	{
+		// weak, average, strong = 1 , 2,  3.
+		int boostmultiplier = ((current_tile_index-2) % 3) + 1;
+		
+		// up, down, left, right = 8, 9, 10, 11.
+		int boostdir = (int)round((float)current_tile_index / 3);
+		
+		//up
+		if(boostdir == 8)
+		{
+			core.vel.y = -40 * boostmultiplier;
+		}
+		
+		//down
+		if(boostdir == 9)
+		{
+			core.vel.y = 40 * boostmultiplier;
+		}
+		
+		//left
+		if(boostdir == 10)
+		{
+			core.vel.x = -40 * boostmultiplier;
+		}
+		
+		//right
+		if(boostdir == 11)
+		{
+			core.vel.x = 40 * boostmultiplier;
+		}
+		
+	}
+	
+	
+	int z = col_is_teleport(pos.x, pos.y);
+	if(config.sv_teleport && z && game.controller->is_extended())
+	{
+		core.hooked_player = -1;
+		core.hook_state = HOOK_RETRACTED;
+		core.triggered_events |= COREEVENT_HOOK_RETRACT;
+		core.hook_state = HOOK_RETRACTED;
+		core.pos = teleport(z);
+		core.hook_pos = core.pos;
+/* 		if(config.sv_strip)
+		{
+			active_weapon = WEAPON_HAMMER;
+			last_weapon = WEAPON_HAMMER;
+			weapons[0].got = true;
+			for(int i = 1; i < 5; i++)
+				weapons[i].got = false;
+		} */
+	}
+	
 	float phys_size = 28.0f;
 	// handle death-tiles
 	if(col_get((int)(pos.x+phys_size/2), (int)(pos.y-phys_size/2))&COLFLAG_DEATH ||
@@ -606,7 +762,8 @@ void CHARACTER::tick_defered()
 		if(events&COREEVENT_GROUND_JUMP) game.create_sound(pos, SOUND_PLAYER_JUMP, mask);
 		
 		//if(events&COREEVENT_HOOK_LAUNCH) snd_play_random(CHN_WORLD, SOUND_HOOK_LOOP, 1.0f, pos);
-		if(events&COREEVENT_HOOK_ATTACH_PLAYER) game.create_sound(pos, SOUND_HOOK_ATTACH_PLAYER, cmask_all());
+		if(events&COREEVENT_HOOK_ATTACH_PLAYER && !core.hook_power) game.create_sound(pos, SOUND_HOOK_ATTACH_PLAYER, cmask_all());
+		if(events&COREEVENT_HOOK_ATTACH_PLAYER && core.hook_power) game.create_sound(pos, SOUND_GOLD_ATTACH_PLAYER, cmask_all());
 		if(events&COREEVENT_HOOK_ATTACH_GROUND) game.create_sound(pos, SOUND_HOOK_ATTACH_GROUND, mask);
 		if(events&COREEVENT_HOOK_HIT_NOHOOK) game.create_sound(pos, SOUND_HOOK_NOATTACH, mask);
 		//if(events&COREEVENT_HOOK_RETRACT) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos);
@@ -639,17 +796,42 @@ void CHARACTER::tick_defered()
 
 bool CHARACTER::increase_health(int amount)
 {
-	if(health >= 10)
+	//no filling with maxhealth
+	if(health >= 20)
+		return false;
+	
+	//only mega overfills
+	if((health >= 10) && (amount < 10))
 		return false;
-	health = clamp(health+amount, 0, 10);
+		
+	//when it's no overfilling, health maxes out at 10
+	
+	if((health < 10) && (amount < 10))
+	{
+		health = clamp(health+amount, 0, 10);
+		return true;
+	}
+	
+	//must be overfilling by now
+	//set decaytimer if not set	
+	if(!decaytimer && (health+amount) > 10)
+		decaytimer = (int)(server_tickspeed()*tuning.overfill_decayrate);
+	
+	//overfilling maxes out at 20
+	health = clamp(health+amount, 0, 20);
 	return true;
 }
 
 bool CHARACTER::increase_armor(int amount)
 {
-	if(armor >= 10)
+	if(armor >= 10 + (10*(int)game.controller->is_extended()))
 		return false;
-	armor = clamp(armor+amount, 0, 10);
+		
+	//armor always overfills
+	if((armor + amount) > 10 && !decaytimer && game.controller->is_extended())
+		decaytimer = (int)(server_tickspeed()*tuning.overfill_decayrate);
+		
+	armor = clamp(armor+amount, 0, 10 + (10*(int)game.controller->is_extended()));
 	return true;
 }
 
@@ -682,11 +864,18 @@ void CHARACTER::die(int killer, int weap
 	dead = true;
 	*/
 	
+	if(active_weapon > WEAPON_GUN && active_weapon != WEAPON_NINJA && weapons[active_weapon].ammo)
+		new DROPPEDWEAPON(pos, vec2(0, 0), active_weapon, weapons[active_weapon].ammo);
+	
 	// this is for auto respawn after 3 secs
 	player->die_tick = server_tick();
 	
 	alive = false;
 	game.world.remove_entity(this);
+	
+	if(activesparkle)
+		game.world.destroy_entity(activesparkle);
+	
 	game.world.core.characters[player->client_id] = 0;
 	game.create_death(pos, player->client_id);
 	
@@ -701,9 +890,16 @@ bool CHARACTER::take_damage(vec2 force, 
 	if(game.controller->is_friendly_fire(player->client_id, from) && !config.sv_teamdamage)
 		return false;
 
-	// player only inflicts half damage on self
+	// player only inflicts half [changed to: 3/4] damage on self
 	if(from == player->client_id)
-		dmg = max(1, dmg/2);
+		dmg = (int)max(0, ((float)dmg/4 *3));
+		
+	if(weapon != WEAPON_HOOK)
+	{
+		game.players[from]->weapons[NUM_WEAPONS].hits++;
+		game.players[from]->weapons[weapon].hits++;
+		game.players[from]->get_character()->update_accuracy(weapon);
+	}
 
 	damage_taken++;
 
@@ -781,6 +977,12 @@ bool CHARACTER::take_damage(vec2 force, 
 	return true;
 }
 
+void CHARACTER::update_accuracy(int weapon)
+{
+	player->weapons[weapon].accuracy = ((float)player->weapons[weapon].hits / (float)player->weapons[weapon].shots) * 100;
+	player->weapons[NUM_WEAPONS].accuracy = ((float)player->weapons[NUM_WEAPONS].hits / (float)player->weapons[NUM_WEAPONS].shots) *100;
+}
+
 void CHARACTER::snap(int snapping_client)
 {
 	if(networkclipped(snapping_client))
diff -rupN d:\t052/src/game/server/entities/character.hpp d:\eg/src/game/server/entities/character.hpp
--- d:\t052/src/game/server/entities/character.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/entities/character.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -39,10 +39,12 @@ public:
 	int active_weapon;
 	int last_weapon;
 	int queued_weapon;
+	class SPARKLE *activesparkle;
 	
 	int reload_timer;
 	int attack_tick;
 	
+	
 	int damage_taken;
 
 	int emote_type;
@@ -70,6 +72,7 @@ public:
 
 	int health;
 	int armor;
+	int decaytimer;
 
 	// ninja
 	struct
@@ -115,7 +118,8 @@ public:
 	void die(int killer, int weapon);
 
 	bool take_damage(vec2 force, int dmg, int from, int weapon);	
-
+	
+	void update_accuracy(int weapon);
 	
 	bool spawn(PLAYER *player, vec2 pos, int team);
 	//bool init_tryspawn(int team);
diff -rupN d:\t052/src/game/server/entities/droppedweapon.cpp d:\eg/src/game/server/entities/droppedweapon.cpp
--- d:\t052/src/game/server/entities/droppedweapon.cpp	1970-01-01 01:00:00.000000000 +0100
+++ d:\eg/src/game/server/entities/droppedweapon.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -0,0 +1,88 @@
+#include <engine/e_server_interface.h>
+#include <game/generated/g_protocol.hpp>
+#include <game/server/gamecontext.hpp>
+#include "droppedweapon.hpp"
+
+
+DROPPEDWEAPON::DROPPEDWEAPON(vec2 pos, vec2 direction, int subtype, int ammunition)
+: ENTITY(NETOBJTYPE_DROPPED_WEAPON)
+{
+	this->pos = vec2(pos.x, pos.y-30);
+	this->direction = direction;
+	this->subtype = subtype;
+	this->ammunition = ammunition;
+	curvature = tuning.droppedweapon_curvature;
+	speed = tuning.droppedweapon_speed;
+	droptick = server_tick();
+	game.world.insert_entity(this);
+}
+
+vec2 DROPPEDWEAPON::get_pos(float time)
+{
+	return calc_pos(pos, direction, curvature, speed, time);
+}
+
+void DROPPEDWEAPON::tick()
+{
+	if(!still)
+	{
+		float pt = (server_tick()-droptick-1)/(float)server_tickspeed();
+		float ct = (server_tick()-droptick)/(float)server_tickspeed();
+		vec2 prevpos = get_pos(pt);
+		vec2 curpos = get_pos(ct);
+
+		int collide = col_intersect_line(prevpos, curpos, &curpos, 0);
+		
+		if(collide)
+		{
+			curvature = 0.0f;
+			pos = prevpos;
+			speed = 0.0f;
+			still = true;
+			direction = vec2(0, 0);
+		}
+	}
+	
+	if(server_tick() > droptick + server_tickspeed() * tuning.droppedweapon_decayrate)
+		game.world.destroy_entity(this);
+	else if(subtype < NUM_WEAPONS && server_tick() > droptick + server_tickspeed())
+		{
+			CHARACTER *chr = game.world.closest_character(pos, 20.0f, 0);
+
+			if(chr && chr->alive && (chr->weapons[subtype].ammo < data->weapons.id[subtype].maxammo || !chr->weapons[subtype].got))
+				{
+					chr->weapons[subtype].got = true;
+					chr->weapons[subtype].ammo = min((chr->weapons[subtype].ammo + ammunition), data->weapons.id[subtype].maxammo);
+						
+						//TODO: data compiler should take care of stuff like this
+					if(subtype == WEAPON_GRENADE)
+						game.create_sound(pos, SOUND_PICKUP_GRENADE);
+					else if(subtype == WEAPON_SHOTGUN)
+						game.create_sound(pos, SOUND_PICKUP_SHOTGUN);
+					else if(subtype == WEAPON_RIFLE)
+						game.create_sound(pos, SOUND_PICKUP_SHOTGUN);
+
+					if(chr->player)
+						game.send_weapon_pickup(chr->player->client_id, subtype);
+						
+					game.world.destroy_entity(this);
+				}
+			
+		}
+	else return;
+}
+
+void DROPPEDWEAPON::snap(int snapping_client)
+{
+	NETOBJ_DROPPED_WEAPON *dw = (NETOBJ_DROPPED_WEAPON *)snap_new_item(NETOBJTYPE_DROPPED_WEAPON, id, sizeof(NETOBJ_DROPPED_WEAPON));
+	dw->x = (int)pos.x;
+	dw->y = (int)pos.y;
+	dw->vx = (int)(direction.x*100.0f);
+	dw->vy = (int)(direction.y*100.0f);
+	dw->subtype = subtype;
+	
+	if(still)
+		dw->start_tick = server_tick();
+	else
+		dw->start_tick = droptick;
+}
\ No newline at end of file
diff -rupN d:\t052/src/game/server/entities/droppedweapon.hpp d:\eg/src/game/server/entities/droppedweapon.hpp
--- d:\t052/src/game/server/entities/droppedweapon.hpp	1970-01-01 01:00:00.000000000 +0100
+++ d:\eg/src/game/server/entities/droppedweapon.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -0,0 +1,27 @@
+
+
+#ifndef GAME_SERVER_ENTITY_DROPPEDWEAPON_H
+#define GAME_SERVER_ENTITY_DROPPEDWEAPON_H
+
+#include <game/server/entity.hpp>
+
+class DROPPEDWEAPON : public ENTITY
+{
+public:
+	static const int phys_size = 14;
+	int subtype;
+	int ammunition;
+	int droptick;
+	float speed;
+	float curvature;
+	bool still;
+	vec2 direction;
+	
+	DROPPEDWEAPON(vec2 pos, vec2 direction, int subtype, int ammunition);
+	
+	vec2 get_pos(float time);
+	virtual void tick();
+	virtual void snap(int snapping_client);
+};
+
+#endif
\ No newline at end of file
diff -rupN d:\t052/src/game/server/entities/laser.cpp d:\eg/src/game/server/entities/laser.cpp
--- d:\t052/src/game/server/entities/laser.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/entities/laser.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -16,6 +16,7 @@ LASER::LASER(vec2 pos, vec2 direction, f
 	dir = direction;
 	bounces = 0;
 	do_bounce();
+	type = WEAPON_RIFLE;
 	
 	game.world.insert_entity(this);
 }
@@ -31,8 +32,9 @@ bool LASER::hit_character(vec2 from, vec
 
 	this->from = from;
 	pos = at;
-	energy = -1;		
-	hit->take_damage(vec2(0,0), tuning.laser_damage, owner, WEAPON_RIFLE);
+	energy = -1;
+	int dmg = (int)(tuning.laser_damage + (tuning.laser_damage * 0.6f * (int)game.controller->is_extended()));
+	hit->take_damage(vec2(0,0), dmg, owner, WEAPON_RIFLE);
 	return true;
 }
 
@@ -111,5 +113,6 @@ void LASER::snap(int snapping_client)
 	obj->y = (int)pos.y;
 	obj->from_x = (int)from.x;
 	obj->from_y = (int)from.y;
+	obj->type = type;
 	obj->start_tick = eval_tick;
 }
diff -rupN d:\t052/src/game/server/entities/laser.hpp d:\eg/src/game/server/entities/laser.hpp
--- d:\t052/src/game/server/entities/laser.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/entities/laser.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -14,15 +14,16 @@ class LASER : public ENTITY
 	float energy;
 	int bounces;
 	int eval_tick;
-	int owner;
-	
-	bool hit_character(vec2 from, vec2 to);
+
 	void do_bounce();
 	
 public:
+	int owner;
+	int type;
 	
 	LASER(vec2 pos, vec2 direction, float start_energy, int owner);
 	
+	virtual bool hit_character(vec2 from, vec2 to);
 	virtual void reset();
 	virtual void tick();
 	virtual void snap(int snapping_client);
diff -rupN d:\t052/src/game/server/entities/pickup.cpp d:\eg/src/game/server/entities/pickup.cpp
--- d:\t052/src/game/server/entities/pickup.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/entities/pickup.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -21,7 +21,9 @@ PICKUP::PICKUP(int _type, int _subtype)
 
 void PICKUP::reset()
 {
-	if (data->pickups[type].spawndelay > 0)
+	if (type == POWERUP_SPECIAL && data->specials.id[subtype].spawndelay > 0 && game.controller->is_extended())
+		spawntick = server_tick() + server_tickspeed() * data->specials.id[subtype].spawndelay;
+	else if (data->pickups[type].spawndelay > 0)
 		spawntick = server_tick() + server_tickspeed() * data->pickups[type].spawndelay;
 	else
 		spawntick = -1;
@@ -53,35 +55,40 @@ void PICKUP::tick()
 		switch (type)
 		{
 		case POWERUP_HEALTH:
-			if(chr->increase_health(1))
+			if(!subtype)
 			{
-				game.create_sound(pos, SOUND_PICKUP_HEALTH);
-				respawntime = data->pickups[type].respawntime;
+				if(chr->increase_health(1))
+				{
+					game.create_sound(pos, SOUND_PICKUP_HEALTH);
+					respawntime = data->pickups[type].respawntime;
+				}
 			}
 			break;
+			
 		case POWERUP_ARMOR:
-			if(chr->increase_armor(1))
-			{
-				game.create_sound(pos, SOUND_PICKUP_ARMOR);
-				respawntime = data->pickups[type].respawntime;
-			}
-			break;
+			if(!subtype)
+				{
+					if(chr->increase_armor(1))
+					{
+						game.create_sound(pos, SOUND_PICKUP_ARMOR);
+						respawntime = data->pickups[type].respawntime;
+					}
+				}
+				break;
 
-		case POWERUP_WEAPON:
-			if(subtype >= 0 && subtype < NUM_WEAPONS)
+		case POWERUP_WEAPON: // 
+			if(subtype >= 0 && subtype < NUM_WEAPONS) 
 			{
 				if(chr->weapons[subtype].ammo < data->weapons.id[subtype].maxammo || !chr->weapons[subtype].got)
 				{
 					chr->weapons[subtype].got = true;
-					chr->weapons[subtype].ammo = min(data->weapons.id[subtype].maxammo, chr->weapons[subtype].ammo + 10);
+					chr->weapons[subtype].ammo = min(data->weapons.id[subtype].maxammo, chr->weapons[subtype].ammo + 100);
 					respawntime = data->pickups[type].respawntime;
 
 					// TODO: data compiler should take care of stuff like this
-					if(subtype == WEAPON_GRENADE)
+					if(subtype == WEAPON_GRENADE || subtype == WEAPON_SPINGUN || subtype == WEAPON_SHAFT)
 						game.create_sound(pos, SOUND_PICKUP_GRENADE);
-					else if(subtype == WEAPON_SHOTGUN)
-						game.create_sound(pos, SOUND_PICKUP_SHOTGUN);
-					else if(subtype == WEAPON_RIFLE)
+					else if(subtype == WEAPON_SHOTGUN || subtype == WEAPON_RIFLE || WEAPON_BIORIFLE)
 						game.create_sound(pos, SOUND_PICKUP_SHOTGUN);
 
 					if(chr->player)
@@ -89,33 +96,73 @@ void PICKUP::tick()
 				}
 			}
 			break;
-		case POWERUP_NINJA:
+		case POWERUP_SPECIAL:
 			{
-				// activate ninja on target player
-				chr->ninja.activationtick = server_tick();
-				chr->weapons[WEAPON_NINJA].got = true;
-				chr->weapons[WEAPON_NINJA].ammo = -1;
-				chr->last_weapon = chr->active_weapon;
-				chr->active_weapon = WEAPON_NINJA;
-				respawntime = data->pickups[type].respawntime;
-				game.create_sound(pos, SOUND_PICKUP_NINJA);
-
-				// loop through all players, setting their emotes
-				ENTITY *ents[64];
-				int num = game.world.find_entities(vec2(0, 0), 1000000, ents, 64, NETOBJTYPE_CHARACTER);
-				for (int i = 0; i < num; i++)
+				if(subtype == SPECIAL_NINJAPWR)
 				{
-					CHARACTER *c = (CHARACTER *)ents[i];
-					if (c != chr)
+					// activate ninja on target player
+					chr->ninja.activationtick = server_tick();
+					chr->weapons[WEAPON_NINJA].got = true;
+					chr->weapons[WEAPON_NINJA].ammo = -1;
+					chr->last_weapon = chr->active_weapon;
+					chr->active_weapon = WEAPON_NINJA;
+					respawntime = data->pickups[type].respawntime;
+					game.create_sound(pos, SOUND_PICKUP_NINJA);
+
+					// loop through all players, setting their emotes
+					ENTITY *ents[64];
+					int num = game.world.find_entities(vec2(0, 0), 1000000, ents, 64, NETOBJTYPE_CHARACTER);
+					for (int i = 0; i < num; i++)
 					{
-						c->emote_type = EMOTE_SURPRISE;
-						c->emote_stop = server_tick() + server_tickspeed();
+						CHARACTER *c = (CHARACTER *)ents[i];
+						if (c != chr)
+						{
+							c->emote_type = EMOTE_SURPRISE;
+							c->emote_stop = server_tick() + server_tickspeed();
+						}
 					}
-				}
 
-				chr->emote_type = EMOTE_ANGRY;
-				chr->emote_stop = server_tick() + 1200 * server_tickspeed() / 1000;
-				
+					chr->emote_type = EMOTE_ANGRY;
+					chr->emote_stop = server_tick() + 1200 * server_tickspeed() / 1000;
+				}
+				else if(subtype == SPECIAL_HOOKPWR)
+				{
+					chr->core.gold_decaytick = 0;
+					chr->core.hook_power = GOLD;
+					respawntime = data->pickups[type].respawntime;
+					game.create_sound_global(SOUND_PICKUP_GOLD);
+				}
+				else if(subtype == SPECIAL_POWERSUIT)
+				{
+					chr->core.suit_decaytick = 0;
+					chr->core.suit = true;
+					respawntime = data->specials.id[subtype].respawntime;
+					game.create_sound_global(SOUND_PICKUP_SUIT);
+				}
+				else if(subtype == SPECIAL_MEGAHEALTH)
+				{
+					if(chr->increase_health(10))
+					{
+						game.create_sound(pos, SOUND_PICKUP_HEALTH);
+						respawntime = data->specials.id[subtype].respawntime;
+					}
+				}
+				else if(subtype == SPECIAL_YELLOWARMOR)
+				{
+					if(chr->increase_armor(5))
+					{
+						game.create_sound(pos, SOUND_PICKUP_ARMOR);
+						respawntime = data->specials.id[subtype].respawntime;
+					}
+				}
+				else if(subtype == SPECIAL_REDARMOR)
+				{
+					if(chr->increase_armor(10))
+					{
+						game.create_sound(pos, SOUND_PICKUP_ARMOR);
+						respawntime = data->specials.id[subtype].respawntime;
+					}
+				}
 				break;
 			}
 		default:
diff -rupN d:\t052/src/game/server/entities/projectile.cpp d:\eg/src/game/server/entities/projectile.cpp
--- d:\t052/src/game/server/entities/projectile.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/entities/projectile.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -1,7 +1,9 @@
 #include <engine/e_server_interface.h>
 #include <game/generated/g_protocol.hpp>
+#include <engine/e_config.h>
 #include <game/server/gamecontext.hpp>
 #include "projectile.hpp"
+#include <game/generated/g_protocol.hpp>
 
 
 //////////////////////////////////////////////////
@@ -23,18 +25,9 @@ PROJECTILE::PROJECTILE(int type, int own
 	this->weapon = weapon;
 	this->bounce = 0;
 	this->start_tick = server_tick();
+	sticked = false;
 	game.world.insert_entity(this);
-}
-
-void PROJECTILE::reset()
-{
-	game.world.destroy_entity(this);
-}
-
-vec2 PROJECTILE::get_pos(float time)
-{
-	float curvature = 0;
-	float speed = 0;
+	
 	if(type == WEAPON_GRENADE)
 	{
 		curvature = tuning.grenade_curvature;
@@ -50,7 +43,20 @@ vec2 PROJECTILE::get_pos(float time)
 		curvature = tuning.gun_curvature;
 		speed = tuning.gun_speed;
 	}
-	
+	else if(type == WEAPON_BIORIFLE)
+	{
+		curvature = tuning.biorifle_curvature;
+		speed = tuning.biorifle_speed;
+	}
+}
+
+void PROJECTILE::reset()
+{
+	game.world.destroy_entity(this);
+}
+
+vec2 PROJECTILE::get_pos(float time)
+{
 	return calc_pos(pos, direction, curvature, speed, time);
 }
 
@@ -64,12 +70,72 @@ void PROJECTILE::tick()
 	vec2 curpos = get_pos(ct);
 
 	lifespan--;
-	
+
 	int collide = col_intersect_line(prevpos, curpos, &curpos, 0);
 	//int collide = col_check_point((int)curpos.x, (int)curpos.y);
 	CHARACTER *ownerchar = game.get_player_char(owner);
 	CHARACTER *targetchr = game.world.intersect_character(prevpos, curpos, 6.0f, curpos, ownerchar);
-	if(targetchr || collide || lifespan < 0)
+	
+	if(type == WEAPON_BIORIFLE && collide || sticked)
+	{
+		if(!sticked)
+		{
+			sticked = true;
+			NETEVENT_BIOSPLASH *ev = (NETEVENT_BIOSPLASH *)game.events.create(NETEVENTTYPE_BIOSPLASH, sizeof(NETEVENT_BIOSPLASH));
+			ev->x = curpos.x; ev->y = curpos.y;	ev->playSound = false;
+			pos = curpos;
+			game.create_sound(curpos, SOUND_BIO_IMPACT);
+		}
+		
+		direction = vec2(0, 0);
+		pos = prevpos;
+		speed = 0.0f;
+		start_tick = server_tick();
+
+		CHARACTER *ents[2];
+		int hit = game.world.find_entities(pos, 42.0f, (ENTITY**)ents, 2, NETOBJTYPE_CHARACTER);
+		if (hit)
+		{
+			NETEVENT_BIOSPLASH *ev = (NETEVENT_BIOSPLASH *)game.events.create(NETEVENTTYPE_BIOSPLASH, sizeof(NETEVENT_BIOSPLASH));
+			ev->x = curpos.x; ev->y = curpos.y;	ev->playSound = true;
+			game.create_explosion(pos, owner, weapon, false);
+			game.create_sound(curpos, SOUND_BIO_EXPLODE);
+			game.world.destroy_entity(this);
+			return;
+		}
+		//formerly 28.0f
+		hit = game.world.find_entities(pos, 42.0f, (ENTITY**)ents, 2, -1);
+		if (hit > 1)
+		{
+			NETEVENT_BIOSPLASH *ev = (NETEVENT_BIOSPLASH *)game.events.create(NETEVENTTYPE_BIOSPLASH, sizeof(NETEVENT_BIOSPLASH));
+			ev->x = curpos.x; ev->y = curpos.y;	ev->playSound = true;
+			game.world.destroy_entity(this);
+			return;
+		}
+		
+		if (lifespan < 0)
+		{
+			NETEVENT_BIOSPLASH *ev = (NETEVENT_BIOSPLASH *)game.events.create(NETEVENTTYPE_BIOSPLASH, sizeof(NETEVENT_BIOSPLASH));
+			ev->x = curpos.x; ev->y = curpos.y;	ev->playSound = true;
+			game.world.destroy_entity(this);
+			return;
+		}
+	}
+	
+	PROJECTILE *projs[8];
+	int num = game.world.find_entities(curpos, 28.0f, (ENTITY**)projs, 8, NETOBJTYPE_PROJECTILE);
+	for(int i = 0; i < num; i++)
+	{
+		if(projs[i]->type == WEAPON_BIORIFLE && projs[i] != this)
+		{
+			NETEVENT_BIOSPLASH *ev = (NETEVENT_BIOSPLASH *)game.events.create(NETEVENTTYPE_BIOSPLASH, sizeof(NETEVENT_BIOSPLASH));
+			ev->x = curpos.x; ev->y = curpos.y;	ev->playSound = false;
+			game.world.destroy_entity(projs[i]);
+			collide = 1;
+		}
+	}
+		
+	if(targetchr || (collide && type != WEAPON_BIORIFLE) || lifespan < 0)
 	{
 		if(lifespan >= 0 || weapon == WEAPON_GRENADE)
 			game.create_sound(curpos, sound_impact);
@@ -81,6 +147,13 @@ void PROJECTILE::tick()
 
 		game.world.destroy_entity(this);
 	}
+	
+	int z = col_is_teleport((int)curpos.x,curpos.y);
+  	if(config.sv_teleport && z && game.controller->is_extended())
+  	{
+ 		pos = teleport(z);
+  		start_tick = server_tick();
+	}
 }
 
 void PROJECTILE::fill_info(NETOBJ_PROJECTILE *proj)
@@ -90,7 +163,7 @@ void PROJECTILE::fill_info(NETOBJ_PROJEC
 	proj->vx = (int)(direction.x*100.0f);
 	proj->vy = (int)(direction.y*100.0f);
 	proj->start_tick = start_tick;
-	proj->type = type;
+	proj->type = type; 
 }
 
 void PROJECTILE::snap(int snapping_client)
@@ -100,6 +173,9 @@ void PROJECTILE::snap(int snapping_clien
 	if(networkclipped(snapping_client, get_pos(ct)))
 		return;
 
+	
 	NETOBJ_PROJECTILE *proj = (NETOBJ_PROJECTILE *)snap_new_item(NETOBJTYPE_PROJECTILE, id, sizeof(NETOBJ_PROJECTILE));
 	fill_info(proj);
+	
+	
 }
diff -rupN d:\t052/src/game/server/entities/projectile.hpp d:\eg/src/game/server/entities/projectile.hpp
--- d:\t052/src/game/server/entities/projectile.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/entities/projectile.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -22,6 +22,9 @@ public:
 	int bounce;
 	float force;
 	int start_tick;
+	float curvature;
+	float speed;
+	bool sticked;
 	
 	PROJECTILE(int type, int owner, vec2 pos, vec2 vel, int span,
 		int damage, int flags, float force, int sound_impact, int weapon);
diff -rupN d:\t052/src/game/server/entities/sparkle.cpp d:\eg/src/game/server/entities/sparkle.cpp
--- d:\t052/src/game/server/entities/sparkle.cpp	1970-01-01 01:00:00.000000000 +0100
+++ d:\eg/src/game/server/entities/sparkle.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -0,0 +1,66 @@
+
+#include <engine/e_server_interface.h>
+#include <game/generated/g_protocol.hpp>
+#include <game/server/gamecontext.hpp>
+#include "sparkle.hpp"
+
+
+SPARKLE::SPARKLE(vec2 pos, vec2 direction, int owner)
+: ENTITY(NETOBJTYPE_SHAFT_BEAM)
+{
+	this->from = pos;
+	this->owner = owner;
+	dir = direction;
+	cooled = true;
+	type = WEAPON_SHAFT;
+	eval_tick = server_tick();
+	this->pos = (from + direction*tuning.shaft_range);
+	
+	game.world.insert_entity(this);
+}
+
+
+void SPARKLE::hit_character(vec2 from, vec2 to)
+{
+	CHARACTER *owner_char = game.get_player_char(owner);
+	CHARACTER *hit = game.world.intersect_character(from, to, 0.0f, pos, owner_char);
+	if(!hit)
+		return;
+
+	hit->take_damage(vec2(0,0), tuning.shaft_damage, owner, WEAPON_SHAFT);
+	return;
+}
+
+void SPARKLE::adjust_position(vec2 newfrom, vec2 newdir)
+{
+	from = newfrom;
+	pos = (from + newdir*tuning.shaft_range);
+	col_intersect_line(from, pos, &pos, 0x0);
+	game.world.intersect_character(from, pos, 0.0f, pos, game.get_player_char(owner));
+}
+
+void SPARKLE::tick()
+{
+	game.create_sound(from, SOUND_SHAFT_FIRE);
+	game.create_sound(pos, SOUND_SHAFT_FIRE);
+	if (cooled)
+	{
+		hit_character(from, pos);
+		cooled = false;
+	}
+}
+
+void SPARKLE::snap(int snapping_client)
+{
+	if(networkclipped(snapping_client))
+		return;
+
+	NETOBJ_SHAFT_BEAM *obj = (NETOBJ_SHAFT_BEAM *)snap_new_item(NETOBJTYPE_SHAFT_BEAM, id, sizeof(NETOBJ_SHAFT_BEAM));
+	obj->x = (int)pos.x;
+	obj->y = (int)pos.y;
+	obj->from_x = (int)from.x;
+	obj->from_y = (int)from.y;
+	obj->type = type;
+	obj->playerID = owner;
+	obj->start_tick = eval_tick;
+}
\ No newline at end of file
diff -rupN d:\t052/src/game/server/entities/sparkle.hpp d:\eg/src/game/server/entities/sparkle.hpp
--- d:\t052/src/game/server/entities/sparkle.hpp	1970-01-01 01:00:00.000000000 +0100
+++ d:\eg/src/game/server/entities/sparkle.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -0,0 +1,32 @@
+
+
+#ifndef GAME_SERVER_ENTITY_SPARKLE_H
+#define GAME_SERVER_ENTITY_SPARKLE_H
+
+
+
+
+#include <game/server/entity.hpp>
+
+class SPARKLE : public ENTITY
+{
+
+	vec2 from;
+	vec2 dir;
+	int eval_tick;
+	
+	void hit_character(vec2 from, vec2 to);
+
+	public:
+		SPARKLE(vec2 pos, vec2 direction, int owner);
+	
+	int owner;
+	int type;
+	bool cooled;
+	
+	void tick();
+	void snap(int snapping_client);
+	void adjust_position(vec2 newfrom, vec2 newdir);
+};
+
+#endif
\ No newline at end of file
diff -rupN d:\t052/src/game/server/entities/vortex.cpp d:\eg/src/game/server/entities/vortex.cpp
--- d:\t052/src/game/server/entities/vortex.cpp	1970-01-01 01:00:00.000000000 +0100
+++ d:\eg/src/game/server/entities/vortex.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -0,0 +1,75 @@
+
+#include <engine/e_server_interface.h>
+#include <game/generated/g_protocol.hpp>
+#include <game/server/gamecontext.hpp>
+#include "vortex.hpp"
+
+
+VORTEX::VORTEX(vec2 pos, vec2 direction, int owner)
+: ENTITY(NETOBJTYPE_LASER)
+{
+	this->from = pos;
+	this->owner = owner;
+	dir = direction;
+	type = WEAPON_SPINGUN;
+	hit_done = false;
+	eval_tick = server_tick();
+	this->pos = (from + direction*tuning.spingun_impactdistance);
+	
+	game.world.insert_entity(this);
+}
+
+
+void VORTEX::hit_character(vec2 pos)
+{
+	CHARACTER *ents[32];
+	CHARACTER *owner_char = game.get_player_char(owner);
+	int num = game.world.find_entities(pos, tuning.spingun_impactradius, (ENTITY**)ents, 32, NETOBJTYPE_CHARACTER);
+	
+	float radius = tuning.spingun_impactradius;
+	float innerradius = tuning.spingun_impactradius/3;
+	for(int i = 0; i < num; i++)
+		{
+			if(!ents[i]->core.suit)
+			{
+				vec2 diff = ents[i]->pos - this->pos;
+				vec2 forcedir(0,1);
+				float l = length(diff);
+				if(l)
+					forcedir = normalize(diff*2);
+				l = 1-clamp((l-innerradius)/(radius-innerradius), 0.0f, 1.0f);
+				float dmg = tuning.spingun_maxdamage * l;
+				if((int)dmg)
+				ents[i]->take_damage(forcedir*dmg*10, (int)dmg, owner, type);
+				ents[i]->core.triggered_events |= COREEVENT_HOOK_HIT_NOHOOK;
+				ents[i]->core.hook_state = HOOK_RETRACT_START;
+			}
+		}
+}
+
+void VORTEX::tick()
+{
+	if (!hit_done) {
+		hit_character(pos);
+		game.create_sound(pos, SOUND_SPIN_IMPACT);
+	}
+	
+	hit_done = true;		
+	
+	if(server_tick() > eval_tick+(server_tickspeed()*lifespan())/1000.0f)
+		game.world.destroy_entity(this);
+}
+
+void VORTEX::snap(int snapping_client)
+{
+	if(networkclipped(snapping_client))
+		return;
+
+	NETOBJ_LASER *obj = (NETOBJ_LASER *)snap_new_item(NETOBJTYPE_LASER, id, sizeof(NETOBJ_LASER));
+	obj->x = (int)pos.x;
+	obj->y = (int)pos.y;
+	obj->from_x = (int)from.x;
+	obj->from_y = (int)from.y;
+	obj->type = type;
+	obj->start_tick = eval_tick;
+}
\ No newline at end of file
diff -rupN d:\t052/src/game/server/entities/vortex.hpp d:\eg/src/game/server/entities/vortex.hpp
--- d:\t052/src/game/server/entities/vortex.hpp	1970-01-01 01:00:00.000000000 +0100
+++ d:\eg/src/game/server/entities/vortex.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -0,0 +1,32 @@
+
+
+#ifndef GAME_SERVER_ENTITY_VORTEX_H
+#define GAME_SERVER_ENTITY_VORTEX_H
+
+
+
+
+#include <game/server/entity.hpp>
+
+class VORTEX : public ENTITY
+{
+
+	vec2 from;
+	vec2 dir;
+	int eval_tick;
+	bool hit_done;
+	
+	void hit_character(vec2 pos);
+
+	public:
+		VORTEX(vec2 pos, vec2 direction, int owner);
+	
+	int owner;
+	int type;
+	
+	void tick();
+	void snap(int snapping_client);
+	static float lifespan() {return 1000;};
+};
+
+#endif
\ No newline at end of file
diff -rupN d:\t052/src/game/server/gamecontext.cpp d:\eg/src/game/server/gamecontext.cpp
--- d:\t052/src/game/server/gamecontext.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/gamecontext.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -91,9 +91,9 @@ void GAMECONTEXT::create_explosion(vec2 
 			if(l)
 				forcedir = normalize(diff);
 			l = 1-clamp((l-innerradius)/(radius-innerradius), 0.0f, 1.0f);
-			float dmg = 6 * l;
+			float dmg = data->weapons.id[weapon].damage * l;
 			if((int)dmg)
-				ents[i]->take_damage(forcedir*dmg*2, (int)dmg, owner, weapon);
+				ents[i]->take_damage(forcedir*dmg*2, (int)round(dmg*(1^ents[i]->core.suit)), owner, weapon);
 		}
 	}
 }
diff -rupN d:\t052/src/game/server/gamecontroller.cpp d:\eg/src/game/server/gamecontroller.cpp
--- d:\t052/src/game/server/gamecontroller.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/gamecontroller.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -124,6 +124,21 @@ bool GAMECONTROLLER::on_entity(int index
 		type = POWERUP_ARMOR;
 	else if(index == ENTITY_HEALTH_1)
 		type = POWERUP_HEALTH;
+	else if(index == ENTITY_ARMOR_5 && is_extended())
+	{
+		type = POWERUP_SPECIAL;
+		subtype = SPECIAL_YELLOWARMOR;
+	}
+	else if(index == ENTITY_ARMOR_10 && is_extended())
+	{
+		type = POWERUP_SPECIAL;
+		subtype = SPECIAL_REDARMOR;
+	}
+	else if(index == ENTITY_HEALTH_10 && is_extended())
+	{
+		type = POWERUP_SPECIAL;
+		subtype = SPECIAL_MEGAHEALTH;
+	}
 	else if(index == ENTITY_WEAPON_SHOTGUN)
 	{
 		type = POWERUP_WEAPON;
@@ -139,10 +154,35 @@ bool GAMECONTROLLER::on_entity(int index
 		type = POWERUP_WEAPON;
 		subtype = WEAPON_RIFLE;
 	}
+	else if(index == ENTITY_WEAPON_SHAFT && is_extended())
+	{
+		type = POWERUP_WEAPON;
+		subtype = WEAPON_SHAFT;
+	}
+	else if(index == ENTITY_WEAPON_SPINGUN && is_extended())
+	{
+		type = POWERUP_WEAPON;
+		subtype = WEAPON_SPINGUN;
+	}
+	else if(index == ENTITY_WEAPON_BIORIFLE && is_extended())
+	{
+		type = POWERUP_WEAPON;
+		subtype = WEAPON_BIORIFLE;
+	}
 	else if(index == ENTITY_POWERUP_NINJA && config.sv_powerups)
 	{
-		type = POWERUP_NINJA;
-		subtype = WEAPON_NINJA;
+		type = POWERUP_SPECIAL;
+		subtype = SPECIAL_NINJAPWR;
+	}
+	else if(index == ENTITY_POWERUP_HOOK && config.sv_powerups && is_extended())
+	{
+		type = POWERUP_SPECIAL;
+		subtype = SPECIAL_HOOKPWR;
+	}
+	else if(index == ENTITY_POWERUP_SUIT && config.sv_powerups && is_extended())
+	{
+		type = POWERUP_SPECIAL;
+		subtype = SPECIAL_POWERSUIT;
 	}
 	
 	if(type != -1)
@@ -320,6 +360,7 @@ int GAMECONTROLLER::on_character_death(c
 		else
 			killer->score++; // normal kill
 	}
+	victim->player->deaths++;
 	return 0;
 }
 
@@ -327,6 +368,7 @@ void GAMECONTROLLER::on_character_spawn(
 {
 	// default health
 	chr->health = 10;
+	chr->armor = 5 * (1&(int)is_extended());
 	
 	// give default weapons
 	chr->weapons[WEAPON_HAMMER].got = 1;
@@ -659,6 +701,11 @@ void GAMECONTROLLER::do_team_score_winch
 	}
 }
 
+bool GAMECONTROLLER::is_extended() const
+{
+	return false;
+}
+
 int GAMECONTROLLER::clampteam(int team)
 {
 	if(team < 0) // spectator
diff -rupN d:\t052/src/game/server/gamecontroller.hpp d:\eg/src/game/server/gamecontroller.hpp
--- d:\t052/src/game/server/gamecontroller.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/gamecontroller.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -131,6 +131,8 @@ public:
 	int clampteam(int team);
 
 	virtual void post_reset();
+	
+	virtual bool is_extended() const;
 };
 
 #endif
diff -rupN d:\t052/src/game/server/gamemodes/edm.cpp d:\eg/src/game/server/gamemodes/edm.cpp
--- d:\t052/src/game/server/gamemodes/edm.cpp	1970-01-01 01:00:00.000000000 +0100
+++ d:\eg/src/game/server/gamemodes/edm.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -0,0 +1,16 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+#include "edm.hpp"
+
+GAMECONTROLLER_EDM::GAMECONTROLLER_EDM()
+{
+	// Exchange this to a string that identifies your game mode.
+	// DM, TDM and CTF are reserved for teeworlds original modes.
+	gametype = "eDM";
+	
+	//game_flags = GAMEFLAG_TEAMS; // GAMEFLAG_TEAMS makes it a two-team gamemode
+}
+
+bool GAMECONTROLLER_EDM::is_extended() const
+{
+	return true;
+}
\ No newline at end of file
diff -rupN d:\t052/src/game/server/gamemodes/edm.hpp d:\eg/src/game/server/gamemodes/edm.hpp
--- d:\t052/src/game/server/gamemodes/edm.hpp	1970-01-01 01:00:00.000000000 +0100
+++ d:\eg/src/game/server/gamemodes/edm.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -0,0 +1,14 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+
+#include <game/server/gamecontroller.hpp>
+#include <game/server/gamemodes/dm.hpp>
+
+// you can subclass GAMECONTROLLER_CTF, GAMECONTROLLER_TDM etc if you want
+// todo a modification with their base as well.
+class GAMECONTROLLER_EDM : public GAMECONTROLLER_DM
+{
+public:
+	GAMECONTROLLER_EDM();
+	virtual bool is_extended() const;
+	// add more virtual functions here if you wish
+};
diff -rupN d:\t052/src/game/server/gamemodes/etdm.cpp d:\eg/src/game/server/gamemodes/etdm.cpp
--- d:\t052/src/game/server/gamemodes/etdm.cpp	1970-01-01 01:00:00.000000000 +0100
+++ d:\eg/src/game/server/gamemodes/etdm.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -0,0 +1,14 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+#include "etdm.hpp"
+
+GAMECONTROLLER_ETDM::GAMECONTROLLER_ETDM()
+{
+	// Exchange this to a string that identifies your game mode.
+	// DM, TDM and CTF are reserved for teeworlds original modes.
+	gametype = "eTDM";
+}
+
+bool GAMECONTROLLER_ETDM::is_extended() const
+{
+	return true;
+}
\ No newline at end of file
diff -rupN d:\t052/src/game/server/gamemodes/etdm.hpp d:\eg/src/game/server/gamemodes/etdm.hpp
--- d:\t052/src/game/server/gamemodes/etdm.hpp	1970-01-01 01:00:00.000000000 +0100
+++ d:\eg/src/game/server/gamemodes/etdm.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -0,0 +1,14 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+
+#include <game/server/gamecontroller.hpp>
+#include <game/server/gamemodes/tdm.hpp>
+
+// you can subclass GAMECONTROLLER_CTF, GAMECONTROLLER_TDM etc if you want
+// todo a modification with their base as well.
+class GAMECONTROLLER_ETDM : public GAMECONTROLLER_TDM
+{
+public:
+	GAMECONTROLLER_ETDM();
+	virtual bool is_extended() const;
+	// add more virtual functions here if you wish
+};
diff -rupN d:\t052/src/game/server/gameworld.hpp d:\eg/src/game/server/gameworld.hpp
--- d:\t052/src/game/server/gameworld.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/gameworld.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -18,7 +18,7 @@ class GAMEWORLD
 
 	enum
 	{
-		NUM_ENT_TYPES=10, // TODO: are more exact value perhaps? :)
+		NUM_ENT_TYPES=15, // TODO: are more exact value perhaps? :)
 	};
 
 	// TODO: two lists seams kinda not good, shouldn't be needed
diff -rupN d:\t052/src/game/server/hooks.cpp d:\eg/src/game/server/hooks.cpp
--- d:\t052/src/game/server/hooks.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/hooks.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -18,10 +18,9 @@ extern "C"
 #include <game/gamecore.hpp>
 
 #include "gamecontext.hpp"
-#include "gamemodes/dm.hpp"
-#include "gamemodes/tdm.hpp"
 #include "gamemodes/ctf.hpp"
-#include "gamemodes/mod.hpp"
+#include "gamemodes/edm.hpp"
+#include "gamemodes/etdm.hpp"
 
 TUNING_PARAMS tuning;
 
@@ -531,12 +530,14 @@ void mods_init()
 	//players = new PLAYER[MAX_CLIENTS];
 
 	// select gametype
-	if(strcmp(config.sv_gametype, "mod") == 0)
-		game.controller = new GAMECONTROLLER_MOD;
-	else if(strcmp(config.sv_gametype, "ctf") == 0)
+	if(strcmp(config.sv_gametype, "ctf") == 0)
 		game.controller = new GAMECONTROLLER_CTF;
 	else if(strcmp(config.sv_gametype, "tdm") == 0)
 		game.controller = new GAMECONTROLLER_TDM;
+	else if(strcmp(config.sv_gametype, "edm") == 0)
+		game.controller = new GAMECONTROLLER_EDM;
+	else if(strcmp(config.sv_gametype, "etdm") == 0)
+		game.controller = new GAMECONTROLLER_ETDM;
 	else
 		game.controller = new GAMECONTROLLER_DM;
 
diff -rupN d:\t052/src/game/server/player.cpp d:\eg/src/game/server/player.cpp
--- d:\t052/src/game/server/player.cpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/player.cpp	2010-02-04 10:53:13.000000000 +0100
@@ -79,11 +79,23 @@ void PLAYER::snap(int snapping_client)
 	info->latency_flux = latency.max-latency.min;
 	info->local = 0;
 	info->cid = client_id;
+	info->overall_accuracy = (int)weapons[NUM_WEAPONS].accuracy;
 	info->score = score;
+	info->netscore = score-deaths;
 	info->team = team;
 
 	if(client_id == snapping_client)
-		info->local = 1;	
+	{
+		info->local = 1;
+		// info->hammer_percentage = weapons[WEAPON_HAMMER].accuracy;
+		// info->gun_percentage = weapons[WEAPON_GUN].accuracy;
+		// info->shotgun_percentage = weapons[WEAPON_SHOTGUN].accuracy;
+		// info->grenade_percentage = weapons[WEAPON_GRENADE].accuracy;
+		// info->rifle_percentage = weapons[WEAPON_RIFLE].accuracy;
+		// info->shaft_percentage = weapons[WEAPON_SHAFT].accuracy;
+		// info->spin_percentage = weapons[WEAPON_SPINGUN].accuracy;
+		// info->bio_percentage = weapons[WEAPON_BIORIFLE].accuracy;
+	}
 }
 
 void PLAYER::on_disconnect()
@@ -157,6 +169,7 @@ void PLAYER::set_team(int new_team)
 	kill_character(WEAPON_GAME);
 	team = new_team;
 	score = 0;
+	deaths = 0;
 	dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), team);
 	
 	game.controller->on_player_info_change(game.players[client_id]);
diff -rupN d:\t052/src/game/server/player.hpp d:\eg/src/game/server/player.hpp
--- d:\t052/src/game/server/player.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/server/player.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -27,8 +27,16 @@ public:
 	int client_id;
 	int team;
 	int score;
+	int deaths;
 	bool force_balanced;
 	
+	struct ACCURACYSTATS
+	{
+		int hits;
+		int shots;
+		float accuracy;
+	} weapons[NUM_WEAPONS+1];
+	
 	//
 	int vote;
 	int64 last_votecall;
@@ -70,6 +78,7 @@ public:
 	void on_direct_input(NETOBJ_PLAYER_INPUT *new_input);
 	void on_predicted_input(NETOBJ_PLAYER_INPUT *new_input);
 	void on_disconnect();
+	
 };
 
 #endif
diff -rupN d:\t052/src/game/tuning.hpp d:\eg/src/game/tuning.hpp
--- d:\t052/src/game/tuning.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/tuning.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -8,6 +8,7 @@ MACRO_TUNING_PARAM(air_control_speed, 25
 MACRO_TUNING_PARAM(air_control_accel, 1.5f)
 MACRO_TUNING_PARAM(air_friction, 0.95f)
 MACRO_TUNING_PARAM(hook_length, 380.0f)
+MACRO_TUNING_PARAM(hook_damage, 5)
 MACRO_TUNING_PARAM(hook_fire_speed, 80.0f)
 MACRO_TUNING_PARAM(hook_drag_accel, 3.0f)
 MACRO_TUNING_PARAM(hook_drag_speed, 15.0f)
@@ -17,6 +18,12 @@ MACRO_TUNING_PARAM(velramp_start, 550)
 MACRO_TUNING_PARAM(velramp_range, 2000)
 MACRO_TUNING_PARAM(velramp_curvature, 1.4f)
 
+MACRO_TUNING_PARAM(overfill_decayrate, 4.0f)
+
+MACRO_TUNING_PARAM(droppedweapon_curvature, 14.0f)
+MACRO_TUNING_PARAM(droppedweapon_speed, 1000.0f)
+MACRO_TUNING_PARAM(droppedweapon_decayrate, 10.0f)
+
 /* weapon tuning */
 MACRO_TUNING_PARAM(gun_curvature, 1.25f)
 MACRO_TUNING_PARAM(gun_speed, 2200.0f)
@@ -37,5 +44,19 @@ MACRO_TUNING_PARAM(laser_bounce_num, 1)
 MACRO_TUNING_PARAM(laser_bounce_cost, 0)
 MACRO_TUNING_PARAM(laser_damage, 5)
 
+MACRO_TUNING_PARAM(shaft_damage, 1)
+MACRO_TUNING_PARAM(shaft_range, 750.0f)
+
+MACRO_TUNING_PARAM(spingun_maxdamage, 14)
+MACRO_TUNING_PARAM(spingun_impactradius, 150.0f)
+MACRO_TUNING_PARAM(spingun_impactdistance, 300.0f)
+MACRO_TUNING_PARAM(spingun_spinduration, 2.0f)
+
+MACRO_TUNING_PARAM(biorifle_curvature, 0.0f)
+MACRO_TUNING_PARAM(biorifle_speed, 1800.0f)
+MACRO_TUNING_PARAM(biorifle_lifetime, 7.5f)
+
 MACRO_TUNING_PARAM(player_collision, 1)
 MACRO_TUNING_PARAM(player_hooking, 1)
+
+MACRO_TUNING_PARAM(special_duration, 15000)
diff -rupN d:\t052/src/game/variables.hpp d:\eg/src/game/variables.hpp
--- d:\t052/src/game/variables.hpp	2009-10-26 19:04:30.000000000 +0100
+++ d:\eg/src/game/variables.hpp	2010-02-04 10:53:13.000000000 +0100
@@ -47,15 +47,16 @@ MACRO_CONFIG_INT(gfx_noclip, 0, 0, 1, CF
 /* server */
 MACRO_CONFIG_INT(sv_warmup, 0, 0, 0, CFGFLAG_SERVER, "Number of seconds to do warpup before round starts")
 MACRO_CONFIG_STR(sv_motd, 900, "", CFGFLAG_SERVER, "Message of the day to display for the clients")
-MACRO_CONFIG_INT(sv_teamdamage, 0, 0, 1, CFGFLAG_SERVER, "Team damage")
+MACRO_CONFIG_INT(sv_teamdamage, 1, 0, 1, CFGFLAG_SERVER, "Team damage")
 MACRO_CONFIG_STR(sv_maprotation, 768, "", CFGFLAG_SERVER, "Maps to rotate between")
 MACRO_CONFIG_INT(sv_rounds_per_map, 1, 1, 100, CFGFLAG_SERVER, "Number of rounds on each map before rotating")
 MACRO_CONFIG_INT(sv_powerups, 1, 0, 1, CFGFLAG_SERVER, "Allow powerups like ninja")
 MACRO_CONFIG_INT(sv_scorelimit, 20, 0, 1000, CFGFLAG_SERVER, "Score limit (0 disables)")
 MACRO_CONFIG_INT(sv_timelimit, 0, 0, 1000, CFGFLAG_SERVER, "Time limit in minutes (0 disables)")
 MACRO_CONFIG_STR(sv_gametype, 32, "dm", CFGFLAG_SERVER, "Game type (dm, tdm, ctf)")
-MACRO_CONFIG_INT(sv_tournament_mode, 0, 0, 1, CFGFLAG_SERVER, "Tournament mode. When enabled, players joins the server as spectator")
+MACRO_CONFIG_INT(sv_tournament_mode, 1, 0, 1, CFGFLAG_SERVER, "Tournament mode. When enabled, players joins the server as spectator")
 MACRO_CONFIG_INT(sv_spamprotection, 1, 0, 1, CFGFLAG_SERVER, "Spam protection")
+MACRO_CONFIG_INT(sv_teleport, 1, 0, 1, CFGFLAG_SERVER, "Enable or disable teleportation")
 
 MACRO_CONFIG_INT(sv_spectator_slots, 0, 0, MAX_CLIENTS, CFGFLAG_SERVER, "Number of slots to reserve for spectators")
 MACRO_CONFIG_INT(sv_teambalance_time, 1, 0, 1000, CFGFLAG_SERVER, "How many minutes to wait before autobalancing teams")
