shithub: qk2

Download patch

ref: 61e35a208c16f339e39e5b4d6244e12ddcc980f7
parent: 4cae69d325329e3c1d7bf043eb52d610369a26bb
author: Konstantinn Bonnet <qu7uux@gmail.com>
date: Sun Jun 28 12:02:21 EDT 2015

more mostly pointless file shuffling

- merge headers (except adivtab.h, anorms.h, rand1k.h) → dat.h, fns.h and
  game/game.h. game.h remains for mod shit
- remove const qualifiers (mostly from menu stuff)
- put TARG in mk.$game for setting binary's name for each mod
- plan9-ish C style for some files

--- /dev/null
+++ b/adivtab.h
@@ -1,0 +1,1058 @@
+// table of quotients and remainders for [-15...16] / [-15...16]
+
+// numerator = -15
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{1, -7},
+{2, -1},
+{2, -3},
+{3, 0},
+{3, -3},
+{5, 0},
+{7, -1},
+{15, 0},
+{0, 0},
+{-15, 0},
+{-8, 1},
+{-5, 0},
+{-4, 1},
+{-3, 0},
+{-3, 3},
+{-3, 6},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-2, 11},
+{-2, 13},
+{-1, 0},
+{-1, 1},
+// numerator = -14
+{0, -14},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{2, 0},
+{2, -2},
+{2, -4},
+{3, -2},
+{4, -2},
+{7, 0},
+{14, 0},
+{0, 0},
+{-14, 0},
+{-7, 0},
+{-5, 1},
+{-4, 2},
+{-3, 1},
+{-3, 4},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-2, 10},
+{-2, 12},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+// numerator = -13
+{0, -13},
+{0, -13},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{2, -1},
+{2, -3},
+{3, -1},
+{4, -1},
+{6, -1},
+{13, 0},
+{0, 0},
+{-13, 0},
+{-7, 1},
+{-5, 2},
+{-4, 3},
+{-3, 2},
+{-3, 5},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-2, 11},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+// numerator = -12
+{0, -12},
+{0, -12},
+{0, -12},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{2, 0},
+{2, -2},
+{3, 0},
+{4, 0},
+{6, 0},
+{12, 0},
+{0, 0},
+{-12, 0},
+{-6, 0},
+{-4, 0},
+{-3, 0},
+{-3, 3},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-2, 10},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+// numerator = -11
+{0, -11},
+{0, -11},
+{0, -11},
+{0, -11},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{2, -1},
+{2, -3},
+{3, -2},
+{5, -1},
+{11, 0},
+{0, 0},
+{-11, 0},
+{-6, 1},
+{-4, 1},
+{-3, 1},
+{-3, 4},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+// numerator = -10
+{0, -10},
+{0, -10},
+{0, -10},
+{0, -10},
+{0, -10},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{2, 0},
+{2, -2},
+{3, -1},
+{5, 0},
+{10, 0},
+{0, 0},
+{-10, 0},
+{-5, 0},
+{-4, 2},
+{-3, 2},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+// numerator = -9
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{2, -1},
+{3, 0},
+{4, -1},
+{9, 0},
+{0, 0},
+{-9, 0},
+{-5, 1},
+{-3, 0},
+{-3, 3},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+// numerator = -8
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{2, 0},
+{2, -2},
+{4, 0},
+{8, 0},
+{0, 0},
+{-8, 0},
+{-4, 0},
+{-3, 1},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+// numerator = -7
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{2, -1},
+{3, -1},
+{7, 0},
+{0, 0},
+{-7, 0},
+{-4, 1},
+{-3, 2},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+// numerator = -6
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{1, 0},
+{1, -1},
+{1, -2},
+{2, 0},
+{3, 0},
+{6, 0},
+{0, 0},
+{-6, 0},
+{-3, 0},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+// numerator = -5
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{1, 0},
+{1, -1},
+{1, -2},
+{2, -1},
+{5, 0},
+{0, 0},
+{-5, 0},
+{-3, 1},
+{-2, 1},
+{-2, 3},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+// numerator = -4
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{1, 0},
+{1, -1},
+{2, 0},
+{4, 0},
+{0, 0},
+{-4, 0},
+{-2, 0},
+{-2, 2},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+// numerator = -3
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{1, 0},
+{1, -1},
+{3, 0},
+{0, 0},
+{-3, 0},
+{-2, 1},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+// numerator = -2
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{1, 0},
+{2, 0},
+{0, 0},
+{-2, 0},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+{-1, 14},
+// numerator = -1
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{1, 0},
+{0, 0},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+{-1, 14},
+{-1, 15},
+// numerator = 0
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+// numerator = 1
+{-1, -14},
+{-1, -13},
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{0, 0},
+{1, 0},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+// numerator = 2
+{-1, -13},
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, 0},
+{0, 0},
+{2, 0},
+{1, 0},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+// numerator = 3
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -1},
+{-3, 0},
+{0, 0},
+{3, 0},
+{1, 1},
+{1, 0},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+// numerator = 4
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -2},
+{-2, 0},
+{-4, 0},
+{0, 0},
+{4, 0},
+{2, 0},
+{1, 1},
+{1, 0},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+// numerator = 5
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -3},
+{-2, -1},
+{-3, -1},
+{-5, 0},
+{0, 0},
+{5, 0},
+{2, 1},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+// numerator = 6
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, 0},
+{-6, 0},
+{0, 0},
+{6, 0},
+{3, 0},
+{2, 0},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+// numerator = 7
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -2},
+{-4, -1},
+{-7, 0},
+{0, 0},
+{7, 0},
+{3, 1},
+{2, 1},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+// numerator = 8
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -1},
+{-4, 0},
+{-8, 0},
+{0, 0},
+{8, 0},
+{4, 0},
+{2, 2},
+{2, 0},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+// numerator = 9
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -3},
+{-3, 0},
+{-5, -1},
+{-9, 0},
+{0, 0},
+{9, 0},
+{4, 1},
+{3, 0},
+{2, 1},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+// numerator = 10
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -2},
+{-4, -2},
+{-5, 0},
+{-10, 0},
+{0, 0},
+{10, 0},
+{5, 0},
+{3, 1},
+{2, 2},
+{2, 0},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+// numerator = 11
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -4},
+{-3, -1},
+{-4, -1},
+{-6, -1},
+{-11, 0},
+{0, 0},
+{11, 0},
+{5, 1},
+{3, 2},
+{2, 3},
+{2, 1},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 11},
+{0, 11},
+{0, 11},
+{0, 11},
+{0, 11},
+// numerator = 12
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -3},
+{-3, 0},
+{-4, 0},
+{-6, 0},
+{-12, 0},
+{0, 0},
+{12, 0},
+{6, 0},
+{4, 0},
+{3, 0},
+{2, 2},
+{2, 0},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 12},
+{0, 12},
+{0, 12},
+{0, 12},
+// numerator = 13
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -11},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -5},
+{-3, -2},
+{-4, -3},
+{-5, -2},
+{-7, -1},
+{-13, 0},
+{0, 0},
+{13, 0},
+{6, 1},
+{4, 1},
+{3, 1},
+{2, 3},
+{2, 1},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 13},
+{0, 13},
+{0, 13},
+// numerator = 14
+{-1, -1},
+{-1, 0},
+{-2, -12},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -4},
+{-3, -1},
+{-4, -2},
+{-5, -1},
+{-7, 0},
+{-14, 0},
+{0, 0},
+{14, 0},
+{7, 0},
+{4, 2},
+{3, 2},
+{2, 4},
+{2, 2},
+{2, 0},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 14},
+{0, 14},
+// numerator = 15
+{-1, 0},
+{-2, -13},
+{-2, -11},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -6},
+{-3, -3},
+{-3, 0},
+{-4, -1},
+{-5, 0},
+{-8, -1},
+{-15, 0},
+{0, 0},
+{15, 0},
+{7, 1},
+{5, 0},
+{3, 3},
+{3, 0},
+{2, 3},
+{2, 1},
+{1, 7},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 15},
+// numerator = 16
+{-2, -14},
+{-2, -12},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -5},
+{-3, -2},
+{-4, -4},
+{-4, 0},
+{-6, -2},
+{-8, 0},
+{-16, 0},
+{0, 0},
+{16, 0},
+{8, 0},
+{5, 1},
+{4, 0},
+{3, 1},
+{2, 4},
+{2, 2},
+{2, 0},
+{1, 7},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
--- /dev/null
+++ b/cd.c
@@ -1,0 +1,415 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+qboolean cdValid = false;
+qboolean playing = false;
+qboolean wasPlaying = false;
+qboolean initialized = false;
+qboolean enabled = true;
+qboolean playLooping = false;
+float cdvolume;
+byte remap[100];
+byte playTrack;
+byte maxTrack;
+int cdfile = -1;
+
+cvar_t	*cd_volume;
+cvar_t *cd_nocd;
+cvar_t *cd_dev;
+
+
+void CDAudio_Eject(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+
+	Com_DPrintf("CDAudio_Eject: PORTME\n");
+	/*
+	if ( ioctl(cdfile, CDROMEJECT) == -1 ) 
+		Com_DPrintf("ioctl cdromeject failed\n");
+	*/
+}
+
+void CDAudio_CloseDoor(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+
+	Com_DPrintf("CDAudio_CloseDoor: PORTME\n");
+	/*
+	if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 ) 
+		Com_DPrintf("ioctl cdromclosetray failed\n");
+	*/
+}
+
+int CDAudio_GetAudioDiskInfo(void)
+{
+	cdValid = false;
+	Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
+	return -1;
+
+	/*
+	struct cdrom_tochdr tochdr;
+
+	if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 ) 
+	{
+		Com_DPrintf("ioctl cdromreadtochdr failed\n");
+		return -1;
+	}
+
+	if (tochdr.cdth_trk0 < 1)
+	{
+		Com_DPrintf("CDAudio: no music tracks\n");
+		return -1;
+	}
+
+	cdValid = true;
+	maxTrack = tochdr.cdth_trk1;
+	return 0;
+	*/
+}
+
+void CDAudio_Pause(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+	if (!playing)
+		return;
+
+	Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
+
+	/*
+	if ( ioctl(cdfile, CDROMPAUSE) == -1 ) 
+		Com_DPrintf("ioctl cdrompause failed\n");
+
+	wasPlaying = playing;
+	playing = false;
+	*/
+}
+
+void CDAudio_Play(int track, qboolean looping)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+	if (!cdValid)
+	{
+		CDAudio_GetAudioDiskInfo();
+		if (!cdValid)
+			return;
+	}
+
+	track = remap[track];
+	if (track < 1 || track > maxTrack)
+	{
+		Com_DPrintf("CDAudio: Bad track number %u.\n", track);
+		return;
+	}
+
+	USED(looping);
+	Com_DPrintf("CDAudio_Play: PORTME\n");
+
+	/*
+	struct cdrom_tocentry entry;
+	struct cdrom_ti ti;
+
+	// don't try to play a non-audio track
+	entry.cdte_track = track;
+	entry.cdte_format = CDROM_MSF;
+	if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 )
+	{
+		Com_DPrintf("ioctl cdromreadtocentry failed\n");
+		return;
+	}
+	if (entry.cdte_ctrl == CDROM_DATA_TRACK)
+	{
+		Com_Printf("CDAudio: track %i is not audio\n", track);
+		return;
+	}
+
+	if (playing)
+	{
+		if (playTrack == track)
+			return;
+		CDAudio_Stop();
+	}
+
+	ti.cdti_trk0 = track;
+	ti.cdti_trk1 = track;
+	ti.cdti_ind0 = 1;
+	ti.cdti_ind1 = 99;
+	if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 ) 
+	{
+		Com_DPrintf("ioctl cdromplaytrkind failed\n");
+		return;
+	}
+	if ( ioctl(cdfile, CDROMRESUME) == -1 ) 
+		Com_DPrintf("ioctl cdromresume failed\n");
+
+	playLooping = looping;
+	playTrack = track;
+	playing = true;
+
+	if (cd_volume->value == 0.0)
+		CDAudio_Pause ();
+	*/
+}
+
+
+void CDAudio_Stop(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+	if (!playing)
+		return;
+
+	Com_DPrintf("CDAudio_Stop: PORTME\n");
+
+	/*
+	if ( ioctl(cdfile, CDROMSTOP) == -1 )
+		Com_DPrintf("ioctl cdromstop failed (%d)\n", errno);
+
+	wasPlaying = false;
+	playing = false;
+	*/
+}
+
+void CDAudio_Resume(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+	if (!cdValid)
+		return;
+	if (!wasPlaying)
+		return;
+
+	Com_DPrintf("CDAudio_Stop: PORTME\n");
+
+	/*
+	if ( ioctl(cdfile, CDROMRESUME) == -1 ) 
+		Com_DPrintf("ioctl cdromresume failed\n");
+	playing = true;
+	*/
+}
+
+static void CD_f (void)
+{
+	char	*command;
+	int n, ret;
+
+	if (Cmd_Argc() < 2)
+		return;
+
+	command = Cmd_Argv (1);
+
+	if (cistrcmp(command, "on") == 0)
+	{
+		enabled = true;
+		return;
+	}
+
+	if (cistrcmp(command, "off") == 0)
+	{
+		if (playing)
+			CDAudio_Stop();
+		enabled = false;
+		return;
+	}
+
+	if (cistrcmp(command, "reset") == 0)
+	{
+		enabled = true;
+		if (playing)
+			CDAudio_Stop();
+		for (n = 0; n < 100; n++)
+			remap[n] = n;
+		CDAudio_GetAudioDiskInfo();
+		return;
+	}
+
+	if (cistrcmp(command, "remap") == 0)
+	{
+		ret = Cmd_Argc() - 2;
+		if (ret <= 0)
+		{
+			for (n = 1; n < 100; n++)
+				if (remap[n] != n)
+					Com_Printf("  %u -> %u\n", n, remap[n]);
+			return;
+		}
+		for (n = 1; n <= ret; n++)
+			remap[n] = atoi(Cmd_Argv (n+1));
+		return;
+	}
+
+	if (cistrcmp(command, "close") == 0)
+	{
+		CDAudio_CloseDoor();
+		return;
+	}
+
+	if (!cdValid)
+	{
+		CDAudio_GetAudioDiskInfo();
+		if (!cdValid)
+		{
+			Com_Printf("No CD in player.\n");
+			return;
+		}
+	}
+
+	if (cistrcmp(command, "play") == 0)
+	{
+		CDAudio_Play((byte)atoi(Cmd_Argv (2)), false);
+		return;
+	}
+
+	if (cistrcmp(command, "loop") == 0)
+	{
+		CDAudio_Play((byte)atoi(Cmd_Argv (2)), true);
+		return;
+	}
+
+	if (cistrcmp(command, "stop") == 0)
+	{
+		CDAudio_Stop();
+		return;
+	}
+
+	if (cistrcmp(command, "pause") == 0)
+	{
+		CDAudio_Pause();
+		return;
+	}
+
+	if (cistrcmp(command, "resume") == 0)
+	{
+		CDAudio_Resume();
+		return;
+	}
+
+	if (cistrcmp(command, "eject") == 0)
+	{
+		if (playing)
+			CDAudio_Stop();
+		CDAudio_Eject();
+		cdValid = false;
+		return;
+	}
+
+	if (cistrcmp(command, "info") == 0)
+	{
+		Com_Printf("%u tracks\n", maxTrack);
+		if (playing)
+			Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
+		else if (wasPlaying)
+			Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
+		Com_Printf("Volume is %f\n", cdvolume);
+		return;
+	}
+}
+
+void CDAudio_Update(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+	if (cd_volume && cd_volume->value != cdvolume)
+	{
+		if (cdvolume)
+		{
+			Cvar_SetValue ("cd_volume", 0.0);
+			cdvolume = cd_volume->value;
+			CDAudio_Pause ();
+		}
+		else
+		{
+			Cvar_SetValue ("cd_volume", 1.0);
+			cdvolume = cd_volume->value;
+			CDAudio_Resume ();
+		}
+	}
+
+	Com_DPrintf("CDAudio_Stop: PORTME\n");
+
+	/*
+	struct cdrom_subchnl subchnl;
+	static time_t lastchk;
+
+	if (playing && lastchk < time(NULL)) {
+		lastchk = time(NULL) + 2; //two seconds between chks
+		subchnl.cdsc_format = CDROM_MSF;
+		if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) {
+			Com_DPrintf("ioctl cdromsubchnl failed\n");
+			playing = false;
+			return;
+		}
+		if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY &&
+			subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) {
+			playing = false;
+			if (playLooping)
+				CDAudio_Play(playTrack, true);
+		}
+	}
+	*/
+}
+
+int CDAudio_Init(void)
+{
+	int i;
+	cvar_t	*cv;
+
+	cv = Cvar_Get ("nocdaudio", "0", CVAR_NOSET);
+	if (cv->value)
+		return -1;
+
+	cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
+	if ( cd_nocd->value)
+		return -1;
+
+	cd_volume = Cvar_Get ("cd_volume", "1", CVAR_ARCHIVE);
+
+	cd_dev = Cvar_Get("cd_dev", "/dev/cdrom", CVAR_ARCHIVE);
+
+	if((cdfile = open(cd_dev->string, OREAD)) < 0){
+		fprint(2, "CDAudio_Init: %r\n");
+		Com_Printf("CDAudio_Init: failed to open \"%s\"\n", cd_dev->string);
+		cdfile = -1;
+		return -1;
+	}
+
+	for (i = 0; i < 100; i++)
+		remap[i] = i;
+	initialized = true;
+	enabled = true;
+
+	if (CDAudio_GetAudioDiskInfo())
+	{
+		Com_Printf("CDAudio_Init: No CD in player.\n");
+		cdValid = false;
+	}
+
+	Cmd_AddCommand ("cd", CD_f);
+
+	Com_Printf("CD Audio Initialized\n");
+
+	return 0;
+}
+
+void CDAudio_Activate (qboolean active)
+{
+	if (active)
+		CDAudio_Resume ();
+	else
+		CDAudio_Pause ();
+}
+
+void CDAudio_Shutdown(void)
+{
+	if (!initialized)
+		return;
+	CDAudio_Stop();
+	close(cdfile);
+	cdfile = -1;
+}
--- /dev/null
+++ b/cl_cin.c
@@ -1,0 +1,633 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef struct
+{
+	byte	*data;
+	int		count;
+} cblock_t;
+
+typedef struct
+{
+	qboolean	restart_sound;
+	int		s_rate;
+	int		s_width;
+	int		s_channels;
+
+	int		width;
+	int		height;
+	byte	*pic;
+	byte	*pic_pending;
+
+	// order 1 huffman stuff
+	int		*hnodes1;	// [256][256][2];
+	int		numhnodes1[256];
+
+	int		h_used[512];
+	int		h_count[512];
+} cinematics_t;
+
+cinematics_t	cin;
+
+/*
+=================================================================
+
+PCX LOADING
+
+=================================================================
+*/
+
+
+/*
+==============
+SCR_LoadPCX
+==============
+*/
+void SCR_LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
+{
+	byte	*raw;
+	pcx_t	*pcx;
+	int		x, y;
+	int		len;
+	int		dataByte, runLength;
+	byte	*out, *pix;
+
+	*pic = NULL;
+
+	//
+	// load the file
+	//
+	len = FS_LoadFile (filename, (void **)&raw);
+	if (!raw)
+		return;	// Com_Printf ("Bad pcx file %s\n", filename);
+
+	//
+	// parse the PCX file
+	//
+	pcx = (pcx_t *)raw;
+	raw = &pcx->data;
+
+	if (pcx->manufacturer != 0x0a
+		|| pcx->version != 5
+		|| pcx->encoding != 1
+		|| pcx->bits_per_pixel != 8
+		|| pcx->xmax >= 640
+		|| pcx->ymax >= 480)
+	{
+		Com_Printf ("Bad pcx file %s\n", filename);
+		return;
+	}
+
+	out = Z_Malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
+
+	*pic = out;
+
+	pix = out;
+
+	if (palette)
+	{
+		*palette = Z_Malloc(768);
+		memcpy (*palette, (byte *)pcx + len - 768, 768);
+	}
+
+	if (width)
+		*width = pcx->xmax+1;
+	if (height)
+		*height = pcx->ymax+1;
+
+	for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
+	{
+		for (x=0 ; x<=pcx->xmax ; )
+		{
+			dataByte = *raw++;
+
+			if((dataByte & 0xC0) == 0xC0)
+			{
+				runLength = dataByte & 0x3F;
+				dataByte = *raw++;
+			}
+			else
+				runLength = 1;
+
+			while(runLength-- > 0)
+				pix[x++] = dataByte;
+		}
+
+	}
+
+	if ( raw - (byte *)pcx > len)
+	{
+		Com_Printf ("PCX file %s was malformed", filename);
+		Z_Free (*pic);
+		*pic = NULL;
+	}
+
+	FS_FreeFile (pcx);
+}
+
+//=============================================================
+
+/*
+==================
+SCR_StopCinematic
+==================
+*/
+void SCR_StopCinematic (void)
+{
+	cl.cinematictime = 0;	// done
+	if (cin.pic)
+	{
+		Z_Free (cin.pic);
+		cin.pic = NULL;
+	}
+	if (cin.pic_pending)
+	{
+		Z_Free (cin.pic_pending);
+		cin.pic_pending = NULL;
+	}
+	if (cl.cinematicpalette_active)
+	{
+		re.CinematicSetPalette(NULL);
+		cl.cinematicpalette_active = false;
+	}
+	if (cl.cinematic_file)
+	{
+		fclose (cl.cinematic_file);
+		cl.cinematic_file = NULL;
+	}
+	if (cin.hnodes1)
+	{
+		Z_Free (cin.hnodes1);
+		cin.hnodes1 = NULL;
+	}
+
+	// switch back down to 11 khz sound if necessary
+	if (cin.restart_sound)
+	{
+		cin.restart_sound = false;
+		CL_Snd_Restart_f ();
+	}
+
+}
+
+/*
+====================
+SCR_FinishCinematic
+
+Called when either the cinematic completes, or it is aborted
+====================
+*/
+void SCR_FinishCinematic (void)
+{
+	// tell the server to advance to the next map / cinematic
+	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+	SZ_Print (&cls.netchan.message, va("nextserver %i\n", cl.servercount));
+}
+
+//==========================================================================
+
+/*
+==================
+SmallestNode1
+==================
+*/
+int	SmallestNode1 (int numhnodes)
+{
+	int		i;
+	int		best, bestnode;
+
+	best = 99999999;
+	bestnode = -1;
+	for (i=0 ; i<numhnodes ; i++)
+	{
+		if (cin.h_used[i])
+			continue;
+		if (!cin.h_count[i])
+			continue;
+		if (cin.h_count[i] < best)
+		{
+			best = cin.h_count[i];
+			bestnode = i;
+		}
+	}
+
+	if (bestnode == -1)
+		return -1;
+
+	cin.h_used[bestnode] = true;
+	return bestnode;
+}
+
+
+/*
+==================
+Huff1TableInit
+
+Reads the 64k counts table and initializes the node trees
+==================
+*/
+void Huff1TableInit (void)
+{
+	int		prev;
+	int		j;
+	int		*node, *nodebase;
+	byte	counts[256];
+	int		numhnodes;
+
+	cin.hnodes1 = Z_Malloc (256*256*2*4);
+	memset (cin.hnodes1, 0, 256*256*2*4);
+
+	for (prev=0 ; prev<256 ; prev++)
+	{
+		memset (cin.h_count,0,sizeof(cin.h_count));
+		memset (cin.h_used,0,sizeof(cin.h_used));
+
+		// read a row of counts
+		FS_Read (counts, sizeof(counts), cl.cinematic_file);
+		for (j=0 ; j<256 ; j++)
+			cin.h_count[j] = counts[j];
+
+		// build the nodes
+		numhnodes = 256;
+		nodebase = cin.hnodes1 + prev*256*2;
+
+		while (numhnodes != 511)
+		{
+			node = nodebase + (numhnodes-256)*2;
+
+			// pick two lowest counts
+			node[0] = SmallestNode1 (numhnodes);
+			if (node[0] == -1)
+				break;	// no more
+
+			node[1] = SmallestNode1 (numhnodes);
+			if (node[1] == -1)
+				break;
+
+			cin.h_count[numhnodes] = cin.h_count[node[0]] + cin.h_count[node[1]];
+			numhnodes++;
+		}
+
+		cin.numhnodes1[prev] = numhnodes-1;
+	}
+}
+
+/*
+==================
+Huff1Decompress
+==================
+*/
+cblock_t Huff1Decompress (cblock_t in)
+{
+	byte		*input;
+	byte		*out_p;
+	int			nodenum;
+	int			count;
+	cblock_t	out;
+	int			inbyte;
+	int			*hnodes, *hnodesbase;
+//int		i;
+
+	// get decompressed count
+	count = in.data[0] + (in.data[1]<<8) + (in.data[2]<<16) + (in.data[3]<<24);
+	input = in.data + 4;
+	out_p = out.data = Z_Malloc (count);
+
+	// read bits
+
+	hnodesbase = cin.hnodes1 - 256*2;	// nodes 0-255 aren't stored
+
+	hnodes = hnodesbase;
+	nodenum = cin.numhnodes1[0];
+	while (count)
+	{
+		inbyte = *input++;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+	}
+
+	if (input - in.data != in.count && input - in.data != in.count+1)
+	{
+		Com_Printf ("Decompression overread by %i", (input - in.data) - in.count);
+	}
+	out.count = out_p - out.data;
+
+	return out;
+}
+
+/*
+==================
+SCR_ReadNextFrame
+==================
+*/
+byte *SCR_ReadNextFrame (void)
+{
+	int		r;
+	int		command;
+	byte	samples[22050/14*4];
+	byte	compressed[0x20000];
+	int		size;
+	byte	*pic;
+	cblock_t	in, huf1;
+	int		start, end, count;
+
+	// read the next frame
+	r = fread (&command, 4, 1, cl.cinematic_file);
+	if (r == 0)		// we'll give it one more chance
+		r = fread (&command, 4, 1, cl.cinematic_file);
+
+	if (r != 1)
+		return NULL;
+	command = LittleLong(command);
+	if (command == 2)
+		return NULL;	// last frame marker
+
+	if (command == 1)
+	{	// read palette
+		FS_Read (cl.cinematicpalette, sizeof(cl.cinematicpalette), cl.cinematic_file);
+		cl.cinematicpalette_active=0;	// dubious....  exposes an edge case
+	}
+
+	// decompress the next frame
+	FS_Read (&size, 4, cl.cinematic_file);
+	size = LittleLong(size);
+	if (size > sizeof(compressed) || size < 1)
+		Com_Error (ERR_DROP, "Bad compressed frame size");
+	FS_Read (compressed, size, cl.cinematic_file);
+
+	// read sound
+	start = cl.cinematicframe*cin.s_rate/14;
+	end = (cl.cinematicframe+1)*cin.s_rate/14;
+	count = end - start;
+
+	FS_Read (samples, count*cin.s_width*cin.s_channels, cl.cinematic_file);
+
+	S_RawSamples (count, cin.s_rate, cin.s_width, cin.s_channels, samples);
+
+	in.data = compressed;
+	in.count = size;
+
+	huf1 = Huff1Decompress (in);
+
+	pic = huf1.data;
+
+	cl.cinematicframe++;
+
+	return pic;
+}
+
+
+/*
+==================
+SCR_RunCinematic
+
+==================
+*/
+void SCR_RunCinematic (void)
+{
+	int		frame;
+
+	if (cl.cinematictime <= 0)
+	{
+		SCR_StopCinematic ();
+		return;
+	}
+
+	if (cl.cinematicframe == -1)
+		return;		// static image
+
+	if (cls.key_dest != key_game)
+	{	// pause if menu or console is up
+		cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
+		return;
+	}
+
+	frame = (cls.realtime - cl.cinematictime)*14.0/1000;
+	if (frame <= cl.cinematicframe)
+		return;
+	if (frame > cl.cinematicframe+1)
+	{
+		Com_Printf ("Dropped frame: %i > %i\n", frame, cl.cinematicframe+1);
+		cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
+	}
+	if (cin.pic)
+		Z_Free (cin.pic);
+	cin.pic = cin.pic_pending;
+	cin.pic_pending = NULL;
+	cin.pic_pending = SCR_ReadNextFrame ();
+	if (!cin.pic_pending)
+	{
+		SCR_StopCinematic ();
+		SCR_FinishCinematic ();
+		cl.cinematictime = 1;	// hack to get the black screen behind loading
+		SCR_BeginLoadingPlaque ();
+		cl.cinematictime = 0;
+		return;
+	}
+}
+
+/*
+==================
+SCR_DrawCinematic
+
+Returns true if a cinematic is active, meaning the view rendering
+should be skipped
+==================
+*/
+qboolean SCR_DrawCinematic (void)
+{
+	if (cl.cinematictime <= 0)
+	{
+		return false;
+	}
+
+	if (cls.key_dest == key_menu)
+	{	// blank screen and pause if menu is up
+		re.CinematicSetPalette(NULL);
+		cl.cinematicpalette_active = false;
+		return true;
+	}
+
+	if (!cl.cinematicpalette_active)
+	{
+		re.CinematicSetPalette((uchar *)cl.cinematicpalette);
+		cl.cinematicpalette_active = true;
+	}
+
+	if (!cin.pic)
+		return true;
+
+	re.DrawStretchRaw (0, 0, vid.width, vid.height, cin.width, cin.height, cin.pic);
+
+	return true;
+}
+
+/*
+==================
+SCR_PlayCinematic
+
+==================
+*/
+void SCR_PlayCinematic (char *arg)
+{
+	int		width, height;
+	byte	*palette;
+	char	name[MAX_OSPATH], *dot;
+	int		old_khz;
+
+	// make sure CD isn't playing music
+	CDAudio_Stop();
+
+	cl.cinematicframe = 0;
+	dot = strstr (arg, ".");
+	if (dot && !strcmp (dot, ".pcx"))
+	{	// static pcx image
+		Com_sprintf (name, sizeof(name), "pics/%s", arg);
+		SCR_LoadPCX (name, &cin.pic, &palette, &cin.width, &cin.height);
+		cl.cinematicframe = -1;
+		cl.cinematictime = 1;
+		SCR_EndLoadingPlaque ();
+		cls.state = ca_active;
+		if (!cin.pic)
+		{
+			Com_Printf ("%s not found.\n", name);
+			cl.cinematictime = 0;
+		}
+		else
+		{
+			memcpy (cl.cinematicpalette, palette, sizeof(cl.cinematicpalette));
+			Z_Free (palette);
+		}
+		return;
+	}
+
+	Com_sprintf (name, sizeof(name), "video/%s", arg);
+	FS_FOpenFile (name, &cl.cinematic_file);
+	if (!cl.cinematic_file)
+	{
+//		Com_Error (ERR_DROP, "Cinematic %s not found.\n", name);
+		SCR_FinishCinematic ();
+		cl.cinematictime = 0;	// done
+		return;
+	}
+
+	SCR_EndLoadingPlaque ();
+
+	cls.state = ca_active;
+
+	FS_Read (&width, 4, cl.cinematic_file);
+	FS_Read (&height, 4, cl.cinematic_file);
+	cin.width = LittleLong(width);
+	cin.height = LittleLong(height);
+
+	FS_Read (&cin.s_rate, 4, cl.cinematic_file);
+	cin.s_rate = LittleLong(cin.s_rate);
+	FS_Read (&cin.s_width, 4, cl.cinematic_file);
+	cin.s_width = LittleLong(cin.s_width);
+	FS_Read (&cin.s_channels, 4, cl.cinematic_file);
+	cin.s_channels = LittleLong(cin.s_channels);
+
+	Huff1TableInit ();
+
+	// switch up to 22 khz sound if necessary
+	old_khz = Cvar_VariableValue ("s_khz");
+	if (old_khz != cin.s_rate/1000)
+	{
+		cin.restart_sound = true;
+		Cvar_SetValue ("s_khz", cin.s_rate/1000);
+		CL_Snd_Restart_f ();
+		Cvar_SetValue ("s_khz", old_khz);
+	}
+
+	cl.cinematicframe = 0;
+	cin.pic = SCR_ReadNextFrame ();
+	cl.cinematictime = Sys_Milliseconds ();
+}
--- /dev/null
+++ b/cl_ents.c
@@ -1,0 +1,1479 @@
+// cl_ents.c -- entity parsing and management
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+extern model_t *cl_mod_powerscreen;
+int	vidref_val;
+
+/*
+=========================================================================
+
+FRAME PARSING
+
+=========================================================================
+*/
+
+/* the following are commented out in release
+
+typedef struct
+{
+	int		modelindex;
+	int		num; // entity number
+	int		effects;
+	vec3_t	origin;
+	vec3_t	oldorigin;
+	vec3_t	angles;
+	qboolean present;
+} projectile_t;
+
+#define	MAX_PROJECTILES	64
+projectile_t	cl_projectiles[MAX_PROJECTILES];
+
+void CL_ClearProjectiles (void)
+{
+	int i;
+
+	for (i = 0; i < MAX_PROJECTILES; i++) {
+//		if (cl_projectiles[i].present)
+//			Com_DPrintf("PROJ: %d CLEARED\n", cl_projectiles[i].num);
+		cl_projectiles[i].present = false;
+	}
+}
+
+*/
+
+/*
+=====================
+CL_ParseProjectiles
+
+Flechettes are passed as efficient temporary entities
+=====================
+*/
+/*
+void CL_ParseProjectiles (void)
+{
+	int		i, c, j;
+	byte	bits[8];
+	byte	b;
+	projectile_t	pr;
+	int lastempty = -1;
+	qboolean old = false;
+
+	c = MSG_ReadByte (&net_message);
+	for (i=0 ; i<c ; i++)
+	{
+		bits[0] = MSG_ReadByte (&net_message);
+		bits[1] = MSG_ReadByte (&net_message);
+		bits[2] = MSG_ReadByte (&net_message);
+		bits[3] = MSG_ReadByte (&net_message);
+		bits[4] = MSG_ReadByte (&net_message);
+		pr.origin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
+		pr.origin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
+		pr.origin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
+		VectorCopy(pr.origin, pr.oldorigin);
+
+		if (bits[4] & 64)
+			pr.effects = EF_BLASTER;
+		else
+			pr.effects = 0;
+
+		if (bits[4] & 128) {
+			old = true;
+			bits[0] = MSG_ReadByte (&net_message);
+			bits[1] = MSG_ReadByte (&net_message);
+			bits[2] = MSG_ReadByte (&net_message);
+			bits[3] = MSG_ReadByte (&net_message);
+			bits[4] = MSG_ReadByte (&net_message);
+			pr.oldorigin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
+			pr.oldorigin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
+			pr.oldorigin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
+		}
+
+		bits[0] = MSG_ReadByte (&net_message);
+		bits[1] = MSG_ReadByte (&net_message);
+		bits[2] = MSG_ReadByte (&net_message);
+
+		pr.angles[0] = 360*bits[0]/256;
+		pr.angles[1] = 360*bits[1]/256;
+		pr.modelindex = bits[2];
+
+		b = MSG_ReadByte (&net_message);
+		pr.num = (b & 0x7f);
+		if (b & 128) // extra entity number byte
+			pr.num |= (MSG_ReadByte (&net_message) << 7);
+
+		pr.present = true;
+
+		// find if this projectile already exists from previous frame 
+		for (j = 0; j < MAX_PROJECTILES; j++) {
+			if (cl_projectiles[j].modelindex) {
+				if (cl_projectiles[j].num == pr.num) {
+					// already present, set up oldorigin for interpolation
+					if (!old)
+						VectorCopy(cl_projectiles[j].origin, pr.oldorigin);
+					cl_projectiles[j] = pr;
+					break;
+				}
+			} else
+				lastempty = j;
+		}
+
+		// not present previous frame, add it
+		if (j == MAX_PROJECTILES) {
+			if (lastempty != -1) {
+				cl_projectiles[lastempty] = pr;
+			}
+		}
+	}
+}
+*/
+
+/*
+=============
+CL_LinkProjectiles
+
+=============
+*/
+/*
+void CL_AddProjectiles (void)
+{
+	int		i, j;
+	projectile_t	*pr;
+	entity_t		ent;
+
+	memset (&ent, 0, sizeof(ent));
+
+	for (i=0, pr=cl_projectiles ; i < MAX_PROJECTILES ; i++, pr++)
+	{
+		// grab an entity to fill in
+		if (pr->modelindex < 1)
+			continue;
+		if (!pr->present) {
+			pr->modelindex = 0;
+			continue; // not present this frame (it was in the previous frame)
+		}
+
+		ent.model = cl.model_draw[pr->modelindex];
+
+		// interpolate origin
+		for (j=0 ; j<3 ; j++)
+		{
+			ent.origin[j] = ent.oldorigin[j] = pr->oldorigin[j] + cl.lerpfrac * 
+				(pr->origin[j] - pr->oldorigin[j]);
+
+		}
+
+		if (pr->effects & EF_BLASTER)
+			CL_BlasterTrail (pr->oldorigin, ent.origin);
+		V_AddLight (pr->origin, 200, 1, 1, 0);
+
+		VectorCopy (pr->angles, ent.angles);
+		V_AddEntity (&ent);
+	}
+}
+*/
+
+/*
+=================
+CL_ParseEntityBits
+
+Returns the entity number and the header bits
+=================
+*/
+int	bitcounts[32];	/// just for protocol profiling
+int CL_ParseEntityBits (int *bits)
+{
+	unsigned	b, total;
+	int			i;
+	int			number;
+
+	total = MSG_ReadByte (&net_message);
+	if (total & U_MOREBITS1)
+	{
+		b = MSG_ReadByte (&net_message);
+		total |= b<<8;
+	}
+	if (total & U_MOREBITS2)
+	{
+		b = MSG_ReadByte (&net_message);
+		total |= b<<16;
+	}
+	if (total & U_MOREBITS3)
+	{
+		b = MSG_ReadByte (&net_message);
+		total |= b<<24;
+	}
+
+	// count the bits for net profiling
+	for (i=0 ; i<32 ; i++)
+		if (total&(1<<i))
+			bitcounts[i]++;
+
+	if (total & U_NUMBER16)
+		number = MSG_ReadShort (&net_message);
+	else
+		number = MSG_ReadByte (&net_message);
+
+	*bits = total;
+
+	return number;
+}
+
+/*
+==================
+CL_ParseDelta
+
+Can go from either a baseline or a previous packet_entity
+==================
+*/
+void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits)
+{
+	// set everything to the state we are delta'ing from
+	*to = *from;
+
+	VectorCopy (from->origin, to->old_origin);
+	to->number = number;
+
+	if (bits & U_MODEL)
+		to->modelindex = MSG_ReadByte (&net_message);
+	if (bits & U_MODEL2)
+		to->modelindex2 = MSG_ReadByte (&net_message);
+	if (bits & U_MODEL3)
+		to->modelindex3 = MSG_ReadByte (&net_message);
+	if (bits & U_MODEL4)
+		to->modelindex4 = MSG_ReadByte (&net_message);
+		
+	if (bits & U_FRAME8)
+		to->frame = MSG_ReadByte (&net_message);
+	if (bits & U_FRAME16)
+		to->frame = MSG_ReadShort (&net_message);
+
+	if ((bits & U_SKIN8) && (bits & U_SKIN16))		//used for laser colors
+		to->skinnum = MSG_ReadLong(&net_message);
+	else if (bits & U_SKIN8)
+		to->skinnum = MSG_ReadByte(&net_message);
+	else if (bits & U_SKIN16)
+		to->skinnum = MSG_ReadShort(&net_message);
+
+	if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
+		to->effects = MSG_ReadLong(&net_message);
+	else if (bits & U_EFFECTS8)
+		to->effects = MSG_ReadByte(&net_message);
+	else if (bits & U_EFFECTS16)
+		to->effects = MSG_ReadShort(&net_message);
+
+	if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
+		to->renderfx = MSG_ReadLong(&net_message);
+	else if (bits & U_RENDERFX8)
+		to->renderfx = MSG_ReadByte(&net_message);
+	else if (bits & U_RENDERFX16)
+		to->renderfx = MSG_ReadShort(&net_message);
+
+	if (bits & U_ORIGIN1)
+		to->origin[0] = MSG_ReadCoord (&net_message);
+	if (bits & U_ORIGIN2)
+		to->origin[1] = MSG_ReadCoord (&net_message);
+	if (bits & U_ORIGIN3)
+		to->origin[2] = MSG_ReadCoord (&net_message);
+		
+	if (bits & U_ANGLE1)
+		to->angles[0] = MSG_ReadAngle(&net_message);
+	if (bits & U_ANGLE2)
+		to->angles[1] = MSG_ReadAngle(&net_message);
+	if (bits & U_ANGLE3)
+		to->angles[2] = MSG_ReadAngle(&net_message);
+
+	if (bits & U_OLDORIGIN)
+		MSG_ReadPos (&net_message, to->old_origin);
+
+	if (bits & U_SOUND)
+		to->sound = MSG_ReadByte (&net_message);
+
+	if (bits & U_EVENT)
+		to->event = MSG_ReadByte (&net_message);
+	else
+		to->event = 0;
+
+	if (bits & U_SOLID)
+		to->solid = MSG_ReadShort (&net_message);
+}
+
+/*
+==================
+CL_DeltaEntity
+
+Parses deltas from the given base and adds the resulting entity
+to the current frame
+==================
+*/
+void CL_DeltaEntity (frame_t *frame, int newnum, entity_state_t *old, int bits)
+{
+	centity_t	*ent;
+	entity_state_t	*state;
+
+	ent = &cl_entities[newnum];
+
+	state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)];
+	cl.parse_entities++;
+	frame->num_entities++;
+
+	CL_ParseDelta (old, state, newnum, bits);
+
+	// some data changes will force no lerping
+	if (state->modelindex != ent->current.modelindex
+		|| state->modelindex2 != ent->current.modelindex2
+		|| state->modelindex3 != ent->current.modelindex3
+		|| state->modelindex4 != ent->current.modelindex4
+		|| abs(state->origin[0] - ent->current.origin[0]) > 512
+		|| abs(state->origin[1] - ent->current.origin[1]) > 512
+		|| abs(state->origin[2] - ent->current.origin[2]) > 512
+		|| state->event == EV_PLAYER_TELEPORT
+		|| state->event == EV_OTHER_TELEPORT
+		)
+	{
+		ent->serverframe = -99;
+	}
+
+	if (ent->serverframe != cl.frame.serverframe - 1)
+	{	// wasn't in last update, so initialize some things
+		ent->trailcount = 1024;		// for diminishing rocket / grenade trails
+		// duplicate the current state so lerping doesn't hurt anything
+		ent->prev = *state;
+		if (state->event == EV_OTHER_TELEPORT)
+		{
+			VectorCopy (state->origin, ent->prev.origin);
+			VectorCopy (state->origin, ent->lerp_origin);
+		}
+		else
+		{
+			VectorCopy (state->old_origin, ent->prev.origin);
+			VectorCopy (state->old_origin, ent->lerp_origin);
+		}
+	}
+	else
+	{	// shuffle the last state to previous
+		ent->prev = ent->current;
+	}
+
+	ent->serverframe = cl.frame.serverframe;
+	ent->current = *state;
+}
+
+/*
+==================
+CL_ParsePacketEntities
+
+An svc_packetentities has just been parsed, deal with the
+rest of the data stream.
+==================
+*/
+void CL_ParsePacketEntities (frame_t *oldframe, frame_t *newframe)
+{
+	int			newnum;
+	int			bits;
+	entity_state_t	*oldstate = nil;
+	int			oldindex, oldnum;
+
+	newframe->parse_entities = cl.parse_entities;
+	newframe->num_entities = 0;
+
+	// delta from the entities present in oldframe
+	oldindex = 0;
+	if (!oldframe)
+		oldnum = 99999;
+	else
+	{
+		if (oldindex >= oldframe->num_entities)
+			oldnum = 99999;
+		else
+		{
+			oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+			oldnum = oldstate->number;
+		}
+	}
+
+	while (1)
+	{
+		newnum = CL_ParseEntityBits (&bits);
+		if (newnum >= MAX_EDICTS)
+			Com_Error (ERR_DROP,"CL_ParsePacketEntities: bad number:%i", newnum);
+
+		if (net_message.readcount > net_message.cursize)
+			Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
+
+		if (!newnum)
+			break;
+
+		while (oldnum < newnum)
+		{	// one or more entities from the old packet are unchanged
+			if (cl_shownet->value == 3)
+				Com_Printf ("   unchanged: %i\n", oldnum);
+			CL_DeltaEntity (newframe, oldnum, oldstate, 0);
+			
+			oldindex++;
+
+			if (oldindex >= oldframe->num_entities)
+				oldnum = 99999;
+			else
+			{
+				oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+				oldnum = oldstate->number;
+			}
+		}
+
+		if (bits & U_REMOVE)
+		{	// the entity present in oldframe is not in the current frame
+			if (cl_shownet->value == 3)
+				Com_Printf ("   remove: %i\n", newnum);
+			if (oldnum != newnum)
+				Com_Printf ("U_REMOVE: oldnum != newnum\n");
+
+			oldindex++;
+
+			if (oldindex >= oldframe->num_entities)
+				oldnum = 99999;
+			else
+			{
+				oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+				oldnum = oldstate->number;
+			}
+			continue;
+		}
+
+		if (oldnum == newnum)
+		{	// delta from previous state
+			if (cl_shownet->value == 3)
+				Com_Printf ("   delta: %i\n", newnum);
+			CL_DeltaEntity (newframe, newnum, oldstate, bits);
+
+			oldindex++;
+
+			if (oldindex >= oldframe->num_entities)
+				oldnum = 99999;
+			else
+			{
+				oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+				oldnum = oldstate->number;
+			}
+			continue;
+		}
+
+		if (oldnum > newnum)
+		{	// delta from baseline
+			if (cl_shownet->value == 3)
+				Com_Printf ("   baseline: %i\n", newnum);
+			CL_DeltaEntity (newframe, newnum, &cl_entities[newnum].baseline, bits);
+			continue;
+		}
+
+	}
+
+	// any remaining entities in the old frame are copied over
+	while (oldnum != 99999)
+	{	// one or more entities from the old packet are unchanged
+		if (cl_shownet->value == 3)
+			Com_Printf ("   unchanged: %i\n", oldnum);
+		CL_DeltaEntity (newframe, oldnum, oldstate, 0);
+		
+		oldindex++;
+
+		if (oldindex >= oldframe->num_entities)
+			oldnum = 99999;
+		else
+		{
+			oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+			oldnum = oldstate->number;
+		}
+	}
+}
+
+
+
+/*
+===================
+CL_ParsePlayerstate
+===================
+*/
+void CL_ParsePlayerstate (frame_t *oldframe, frame_t *newframe)
+{
+	int			flags;
+	player_state_t	*state;
+	int			i;
+	int			statbits;
+
+	state = &newframe->playerstate;
+
+	// clear to old value before delta parsing
+	if (oldframe)
+		*state = oldframe->playerstate;
+	else
+		memset (state, 0, sizeof(*state));
+
+	flags = MSG_ReadShort (&net_message);
+
+	//
+	// parse the pmove_state_t
+	//
+	if (flags & PS_M_TYPE)
+		state->pmove.pm_type = MSG_ReadByte (&net_message);
+
+	if (flags & PS_M_ORIGIN)
+	{
+		state->pmove.origin[0] = MSG_ReadShort (&net_message);
+		state->pmove.origin[1] = MSG_ReadShort (&net_message);
+		state->pmove.origin[2] = MSG_ReadShort (&net_message);
+	}
+
+	if (flags & PS_M_VELOCITY)
+	{
+		state->pmove.velocity[0] = MSG_ReadShort (&net_message);
+		state->pmove.velocity[1] = MSG_ReadShort (&net_message);
+		state->pmove.velocity[2] = MSG_ReadShort (&net_message);
+	}
+
+	if (flags & PS_M_TIME)
+		state->pmove.pm_time = MSG_ReadByte (&net_message);
+
+	if (flags & PS_M_FLAGS)
+		state->pmove.pm_flags = MSG_ReadByte (&net_message);
+
+	if (flags & PS_M_GRAVITY)
+		state->pmove.gravity = MSG_ReadShort (&net_message);
+
+	if (flags & PS_M_DELTA_ANGLES)
+	{
+		state->pmove.delta_angles[0] = MSG_ReadShort (&net_message);
+		state->pmove.delta_angles[1] = MSG_ReadShort (&net_message);
+		state->pmove.delta_angles[2] = MSG_ReadShort (&net_message);
+	}
+
+	if (cl.attractloop)
+		state->pmove.pm_type = PM_FREEZE;		// demo playback
+
+	//
+	// parse the rest of the player_state_t
+	//
+	if (flags & PS_VIEWOFFSET)
+	{
+		state->viewoffset[0] = MSG_ReadChar (&net_message) * 0.25;
+		state->viewoffset[1] = MSG_ReadChar (&net_message) * 0.25;
+		state->viewoffset[2] = MSG_ReadChar (&net_message) * 0.25;
+	}
+
+	if (flags & PS_VIEWANGLES)
+	{
+		state->viewangles[0] = MSG_ReadAngle16 (&net_message);
+		state->viewangles[1] = MSG_ReadAngle16 (&net_message);
+		state->viewangles[2] = MSG_ReadAngle16 (&net_message);
+	}
+
+	if (flags & PS_KICKANGLES)
+	{
+		state->kick_angles[0] = MSG_ReadChar (&net_message) * 0.25;
+		state->kick_angles[1] = MSG_ReadChar (&net_message) * 0.25;
+		state->kick_angles[2] = MSG_ReadChar (&net_message) * 0.25;
+	}
+
+	if (flags & PS_WEAPONINDEX)
+	{
+		state->gunindex = MSG_ReadByte (&net_message);
+	}
+
+	if (flags & PS_WEAPONFRAME)
+	{
+		state->gunframe = MSG_ReadByte (&net_message);
+		state->gunoffset[0] = MSG_ReadChar (&net_message)*0.25;
+		state->gunoffset[1] = MSG_ReadChar (&net_message)*0.25;
+		state->gunoffset[2] = MSG_ReadChar (&net_message)*0.25;
+		state->gunangles[0] = MSG_ReadChar (&net_message)*0.25;
+		state->gunangles[1] = MSG_ReadChar (&net_message)*0.25;
+		state->gunangles[2] = MSG_ReadChar (&net_message)*0.25;
+	}
+
+	if (flags & PS_BLEND)
+	{
+		state->blend[0] = MSG_ReadByte (&net_message)/255.0;
+		state->blend[1] = MSG_ReadByte (&net_message)/255.0;
+		state->blend[2] = MSG_ReadByte (&net_message)/255.0;
+		state->blend[3] = MSG_ReadByte (&net_message)/255.0;
+	}
+
+	if (flags & PS_FOV)
+		state->fov = MSG_ReadByte (&net_message);
+
+	if (flags & PS_RDFLAGS)
+		state->rdflags = MSG_ReadByte (&net_message);
+
+	// parse stats
+	statbits = MSG_ReadLong (&net_message);
+	for (i=0 ; i<MAX_STATS ; i++)
+		if (statbits & (1<<i) )
+			state->stats[i] = MSG_ReadShort(&net_message);
+}
+
+
+/*
+==================
+CL_FireEntityEvents
+
+==================
+*/
+void CL_FireEntityEvents (frame_t *frame)
+{
+	entity_state_t		*s1;
+	int					pnum, num;
+
+	for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
+	{
+		num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1);
+		s1 = &cl_parse_entities[num];
+		if (s1->event)
+			CL_EntityEvent (s1);
+
+		// EF_TELEPORTER acts like an event, but is not cleared each frame
+		if (s1->effects & EF_TELEPORTER)
+			CL_TeleporterParticles (s1);
+	}
+}
+
+
+/*
+================
+CL_ParseFrame
+================
+*/
+void CL_ParseFrame (void)
+{
+	int			cmd;
+	int			len;
+	frame_t		*old;
+
+	memset (&cl.frame, 0, sizeof(cl.frame));
+
+/*
+	CL_ClearProjectiles(); // clear projectiles for new frame
+*/
+
+	cl.frame.serverframe = MSG_ReadLong (&net_message);
+	cl.frame.deltaframe = MSG_ReadLong (&net_message);
+	cl.frame.servertime = cl.frame.serverframe*100;
+
+	// BIG HACK to let old demos continue to work
+	if (cls.serverProtocol != 26)
+		cl.surpressCount = MSG_ReadByte (&net_message);
+
+	if (cl_shownet->value == 3)
+		Com_Printf ("   frame:%i  delta:%i\n", cl.frame.serverframe,
+		cl.frame.deltaframe);
+
+	// If the frame is delta compressed from data that we
+	// no longer have available, we must suck up the rest of
+	// the frame, but not use it, then ask for a non-compressed
+	// message 
+	if (cl.frame.deltaframe <= 0)
+	{
+		cl.frame.valid = true;		// uncompressed frame
+		old = NULL;
+		cls.demowaiting = false;	// we can start recording now
+	}
+	else
+	{
+		old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
+		if (!old->valid)
+		{	// should never happen
+			Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
+		}
+		if (old->serverframe != cl.frame.deltaframe)
+		{	// The frame that the server did the delta from
+			// is too old, so we can't reconstruct it properly.
+			Com_Printf ("Delta frame too old.\n");
+		}
+		else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128)
+		{
+			Com_Printf ("Delta parse_entities too old.\n");
+		}
+		else
+			cl.frame.valid = true;	// valid delta parse
+	}
+
+	// clamp time 
+	if (cl.time > cl.frame.servertime)
+		cl.time = cl.frame.servertime;
+	else if (cl.time < cl.frame.servertime - 100)
+		cl.time = cl.frame.servertime - 100;
+
+	// read areabits
+	len = MSG_ReadByte (&net_message);
+	MSG_ReadData (&net_message, cl.frame.areabits, len);
+
+	// read playerinfo
+	cmd = MSG_ReadByte (&net_message);
+	SHOWNET(svc_strings[cmd]);
+	if (cmd != svc_playerinfo)
+		Com_Error (ERR_DROP, "CL_ParseFrame: not playerinfo");
+	CL_ParsePlayerstate (old, &cl.frame);
+
+	// read packet entities
+	cmd = MSG_ReadByte (&net_message);
+	SHOWNET(svc_strings[cmd]);
+	if (cmd != svc_packetentities)
+		Com_Error (ERR_DROP, "CL_ParseFrame: not packetentities");
+	CL_ParsePacketEntities (old, &cl.frame);
+
+/*
+	if (cmd == svc_packetentities2)
+		CL_ParseProjectiles();
+*/
+
+	// save the frame off in the backup array for later delta comparisons
+	cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;
+
+	if (cl.frame.valid)
+	{
+		// getting a valid frame message ends the connection process
+		if (cls.state != ca_active)
+		{
+			cls.state = ca_active;
+			cl.force_refdef = true;
+			cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
+			cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
+			cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125;
+			VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles);
+			if (cls.disable_servercount != cl.servercount
+				&& cl.refresh_prepped)
+				SCR_EndLoadingPlaque ();	// get rid of loading plaque
+		}
+		cl.sound_prepped = true;	// can start mixing ambient sounds
+	
+		// fire entity events
+		CL_FireEntityEvents (&cl.frame);
+		CL_CheckPredictionError ();
+	}
+}
+
+/*
+==========================================================================
+
+INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
+
+==========================================================================
+*/
+
+model_t *
+S_RegisterSexedModel(entity_state_t *ent, char *base)
+{
+	int				n;
+	char			*p;
+	model_t	*mdl;
+	char			model[MAX_QPATH];
+	char			buffer[MAX_QPATH];
+
+	// determine what model the client is using
+	model[0] = 0;
+	n = CS_PLAYERSKINS + ent->number - 1;
+	if (cl.configstrings[n][0])
+	{
+		p = strchr(cl.configstrings[n], '\\');
+		if (p)
+		{
+			p += 1;
+			strcpy(model, p);
+			p = strchr(model, '/');
+			if (p)
+				*p = 0;
+		}
+	}
+	// if we can't figure it out, they're male
+	if (!model[0])
+		strcpy(model, "male");
+
+	Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", model, base+1);
+	mdl = re.RegisterModel(buffer);
+	if (!mdl) {
+		// not found, try default weapon model
+		Com_sprintf (buffer, sizeof(buffer), "players/%s/weapon.md2", model);
+		mdl = re.RegisterModel(buffer);
+		if (!mdl) {
+			// no, revert to the male model
+			Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", "male", base+1);
+			mdl = re.RegisterModel(buffer);
+			if (!mdl) {
+				// last try, default male weapon.md2
+				Com_sprintf (buffer, sizeof(buffer), "players/male/weapon.md2");
+				mdl = re.RegisterModel(buffer);
+			}
+		} 
+	}
+
+	return mdl;
+}
+
+/*
+===============
+CL_AddPacketEntities
+
+===============
+*/
+void CL_AddPacketEntities (frame_t *frame)
+{
+	entity_t			ent;
+	entity_state_t		*s1;
+	float				autorotate;
+	int					i;
+	int					pnum;
+	centity_t			*cent;
+	int					autoanim;
+	clientinfo_t		*ci;
+	unsigned int		effects, renderfx;
+
+	// bonus items rotate at a fixed rate
+	autorotate = anglemod(cl.time/10);
+
+	// brush models can auto animate their frames
+	autoanim = 2*cl.time/1000;
+
+	memset (&ent, 0, sizeof(ent));
+
+	for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
+	{
+		s1 = &cl_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)];
+
+		cent = &cl_entities[s1->number];
+
+		effects = s1->effects;
+		renderfx = s1->renderfx;
+
+			// set frame
+		if (effects & EF_ANIM01)
+			ent.frame = autoanim & 1;
+		else if (effects & EF_ANIM23)
+			ent.frame = 2 + (autoanim & 1);
+		else if (effects & EF_ANIM_ALL)
+			ent.frame = autoanim;
+		else if (effects & EF_ANIM_ALLFAST)
+			ent.frame = cl.time / 100;
+		else
+			ent.frame = s1->frame;
+
+		// quad and pent can do different things on client
+		if (effects & EF_PENT)
+		{
+			effects &= ~EF_PENT;
+			effects |= EF_COLOR_SHELL;
+			renderfx |= RF_SHELL_RED;
+		}
+
+		if (effects & EF_QUAD)
+		{
+			effects &= ~EF_QUAD;
+			effects |= EF_COLOR_SHELL;
+			renderfx |= RF_SHELL_BLUE;
+		}
+//======
+// PMM
+		if (effects & EF_DOUBLE)
+		{
+			effects &= ~EF_DOUBLE;
+			effects |= EF_COLOR_SHELL;
+			renderfx |= RF_SHELL_DOUBLE;
+		}
+
+		if (effects & EF_HALF_DAMAGE)
+		{
+			effects &= ~EF_HALF_DAMAGE;
+			effects |= EF_COLOR_SHELL;
+			renderfx |= RF_SHELL_HALF_DAM;
+		}
+// pmm
+//======
+		ent.oldframe = cent->prev.frame;
+		ent.backlerp = 1.0 - cl.lerpfrac;
+
+		if (renderfx & (RF_FRAMELERP|RF_BEAM))
+		{	// step origin discretely, because the frames
+			// do the animation properly
+			VectorCopy (cent->current.origin, ent.origin);
+			VectorCopy (cent->current.old_origin, ent.oldorigin);
+		}
+		else
+		{	// interpolate origin
+			for (i=0 ; i<3 ; i++)
+			{
+				ent.origin[i] = ent.oldorigin[i] = cent->prev.origin[i] + cl.lerpfrac * 
+					(cent->current.origin[i] - cent->prev.origin[i]);
+			}
+		}
+
+		// create a new entity
+	
+		// tweak the color of beams
+		if ( renderfx & RF_BEAM )
+		{	// the four beam colors are encoded in 32 bits of skinnum (hack)
+			ent.alpha = 0.30;
+			ent.skinnum = (s1->skinnum >> ((rand() % 4)*8)) & 0xff;
+			ent.model = NULL;
+		}
+		else
+		{
+			// set skin
+			if (s1->modelindex == 255)
+			{	// use custom player skin
+				ent.skinnum = 0;
+				ci = &cl.clientinfo[s1->skinnum & 0xff];
+				ent.skin = ci->skin;
+				ent.model = ci->model;
+				if (!ent.skin || !ent.model)
+				{
+					ent.skin = cl.baseclientinfo.skin;
+					ent.model = cl.baseclientinfo.model;
+				}
+
+//============
+//PGM
+				if (renderfx & RF_USE_DISGUISE)
+				{
+					if(!strncmp((char *)ent.skin, "players/male", 12))
+					{
+						ent.skin = re.RegisterSkin ("players/male/disguise.pcx");
+						ent.model = re.RegisterModel ("players/male/tris.md2");
+					}
+					else if(!strncmp((char *)ent.skin, "players/female", 14))
+					{
+						ent.skin = re.RegisterSkin ("players/female/disguise.pcx");
+						ent.model = re.RegisterModel ("players/female/tris.md2");
+					}
+					else if(!strncmp((char *)ent.skin, "players/cyborg", 14))
+					{
+						ent.skin = re.RegisterSkin ("players/cyborg/disguise.pcx");
+						ent.model = re.RegisterModel ("players/cyborg/tris.md2");
+					}
+				}
+//PGM
+//============
+			}
+			else
+			{
+				ent.skinnum = s1->skinnum;
+				ent.skin = NULL;
+				ent.model = cl.model_draw[s1->modelindex];
+			}
+		}
+
+		// only used for black hole model right now, FIXME: do better
+		if (renderfx == RF_TRANSLUCENT)
+			ent.alpha = 0.70;
+
+		// render effects (fullbright, translucent, etc)
+		if ((effects & EF_COLOR_SHELL))
+			ent.flags = 0;	// renderfx go on color shell entity
+		else
+			ent.flags = renderfx;
+
+		// calculate angles
+		if (effects & EF_ROTATE)
+		{	// some bonus items auto-rotate
+			ent.angles[0] = 0;
+			ent.angles[1] = autorotate;
+			ent.angles[2] = 0;
+		}
+		// RAFAEL
+		else if (effects & EF_SPINNINGLIGHTS)
+		{
+			ent.angles[0] = 0;
+			ent.angles[1] = anglemod(cl.time/2) + s1->angles[1];
+			ent.angles[2] = 180;
+			{
+				vec3_t forward;
+				vec3_t start;
+
+				AngleVectors (ent.angles, forward, NULL, NULL);
+				VectorMA (ent.origin, 64, forward, start);
+				V_AddLight (start, 100, 1, 0, 0);
+			}
+		}
+		else
+		{	// interpolate angles
+			float	a1, a2;
+
+			for (i=0 ; i<3 ; i++)
+			{
+				a1 = cent->current.angles[i];
+				a2 = cent->prev.angles[i];
+				ent.angles[i] = LerpAngle (a2, a1, cl.lerpfrac);
+			}
+		}
+
+		if (s1->number == cl.playernum+1)
+		{
+			ent.flags |= RF_VIEWERMODEL;	// only draw from mirrors
+			// FIXME: still pass to refresh
+
+			if (effects & EF_FLAG1)
+				V_AddLight (ent.origin, 225, 1.0, 0.1, 0.1);
+			else if (effects & EF_FLAG2)
+				V_AddLight (ent.origin, 225, 0.1, 0.1, 1.0);
+			else if (effects & EF_TAGTRAIL)						//PGM
+				V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);	//PGM
+			else if (effects & EF_TRACKERTRAIL)					//PGM
+				V_AddLight (ent.origin, 225, -1.0, -1.0, -1.0);	//PGM
+
+			continue;
+		}
+
+		// if set to invisible, skip
+		if (!s1->modelindex)
+			continue;
+
+		if (effects & EF_BFG)
+		{
+			ent.flags |= RF_TRANSLUCENT;
+			ent.alpha = 0.30;
+		}
+
+		// RAFAEL
+		if (effects & EF_PLASMA)
+		{
+			ent.flags |= RF_TRANSLUCENT;
+			ent.alpha = 0.6;
+		}
+
+		if (effects & EF_SPHERETRANS)
+		{
+			ent.flags |= RF_TRANSLUCENT;
+			// PMM - *sigh*  yet more EF overloading
+			if (effects & EF_TRACKERTRAIL)
+				ent.alpha = 0.6;
+			else
+				ent.alpha = 0.3;
+		}
+//pmm
+
+		// add to refresh list
+		V_AddEntity (&ent);
+
+		// color shells generate a seperate entity for the main model
+		if (effects & EF_COLOR_SHELL)
+		{
+			ent.flags = renderfx | RF_TRANSLUCENT;
+			ent.alpha = 0.30;
+			V_AddEntity (&ent);
+		}
+
+		ent.skin = NULL;		// never use a custom skin on others
+		ent.skinnum = 0;
+		ent.flags = 0;
+		ent.alpha = 0;
+
+		// duplicate for linked models
+		if (s1->modelindex2)
+		{
+			if (s1->modelindex2 == 255)
+			{	// custom weapon
+				ci = &cl.clientinfo[s1->skinnum & 0xff];
+				i = (s1->skinnum >> 8); // 0 is default weapon model
+				if (!cl_vwep->value || i > MAX_CLIENTWEAPONMODELS - 1)
+					i = 0;
+				ent.model = ci->weaponmodel[i];
+				if (!ent.model) {
+					if (i != 0)
+						ent.model = ci->weaponmodel[0];
+					if (!ent.model)
+						ent.model = cl.baseclientinfo.weaponmodel[0];
+				}
+			}
+			//PGM - hack to allow translucent linked models (defender sphere's shell)
+			//		set the high bit 0x80 on modelindex2 to enable translucency
+			else if(s1->modelindex2 & 0x80)
+			{
+				ent.model = cl.model_draw[s1->modelindex2 & 0x7F];
+				ent.alpha = 0.32;
+				ent.flags = RF_TRANSLUCENT;
+			}
+			//PGM
+			else
+				ent.model = cl.model_draw[s1->modelindex2];
+			V_AddEntity (&ent);
+
+			//PGM - make sure these get reset.
+			ent.flags = 0;
+			ent.alpha = 0;
+			//PGM
+		}
+		if (s1->modelindex3)
+		{
+			ent.model = cl.model_draw[s1->modelindex3];
+			V_AddEntity (&ent);
+		}
+		if (s1->modelindex4)
+		{
+			ent.model = cl.model_draw[s1->modelindex4];
+			V_AddEntity (&ent);
+		}
+
+		if ( effects & EF_POWERSCREEN )
+		{
+			ent.model = cl_mod_powerscreen;
+			ent.oldframe = 0;
+			ent.frame = 0;
+			ent.flags |= (RF_TRANSLUCENT | RF_SHELL_GREEN);
+			ent.alpha = 0.30;
+			V_AddEntity (&ent);
+		}
+
+		// add automatic particle trails
+		if ( (effects&~EF_ROTATE) )
+		{
+			if (effects & EF_ROCKET)
+			{
+				CL_RocketTrail (cent->lerp_origin, ent.origin, cent);
+				V_AddLight (ent.origin, 200, 1, 1, 0);
+			}
+			// PGM - Do not reorder EF_BLASTER and EF_HYPERBLASTER. 
+			// EF_BLASTER | EF_TRACKER is a special case for EF_BLASTER2... Cheese!
+			else if (effects & EF_BLASTER)
+			{
+//				CL_BlasterTrail (cent->lerp_origin, ent.origin);
+//PGM
+				if (effects & EF_TRACKER)	// lame... problematic?
+				{
+					CL_BlasterTrail2 (cent->lerp_origin, ent.origin);
+					V_AddLight (ent.origin, 200, 0, 1, 0);		
+				}
+				else
+				{
+					CL_BlasterTrail (cent->lerp_origin, ent.origin);
+					V_AddLight (ent.origin, 200, 1, 1, 0);
+				}
+//PGM
+			}
+			else if (effects & EF_HYPERBLASTER)
+			{
+				if (effects & EF_TRACKER)						// PGM	overloaded for blaster2.
+					V_AddLight (ent.origin, 200, 0, 1, 0);		// PGM
+				else											// PGM
+					V_AddLight (ent.origin, 200, 1, 1, 0);
+			}
+			else if (effects & EF_GIB)
+			{
+				CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
+			}
+			else if (effects & EF_GRENADE)
+			{
+				CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
+			}
+			else if (effects & EF_FLIES)
+			{
+				CL_FlyEffect (cent, ent.origin);
+			}
+			else if (effects & EF_BFG)
+			{
+				static int bfg_lightramp[6] = {300, 400, 600, 300, 150, 75};
+
+				if (effects & EF_ANIM_ALLFAST)
+				{
+					CL_BfgParticles (&ent);
+					i = 200;
+				}
+				else
+				{
+					i = bfg_lightramp[s1->frame];
+				}
+				V_AddLight (ent.origin, i, 0, 1, 0);
+			}
+			// RAFAEL
+			else if (effects & EF_TRAP)
+			{
+				ent.origin[2] += 32;
+				CL_TrapParticles (&ent);
+				i = (rand()%100) + 100;
+				V_AddLight (ent.origin, i, 1, 0.8, 0.1);
+			}
+			else if (effects & EF_FLAG1)
+			{
+				CL_FlagTrail (cent->lerp_origin, ent.origin, 242);
+				V_AddLight (ent.origin, 225, 1, 0.1, 0.1);
+			}
+			else if (effects & EF_FLAG2)
+			{
+				CL_FlagTrail (cent->lerp_origin, ent.origin, 115);
+				V_AddLight (ent.origin, 225, 0.1, 0.1, 1);
+			}
+//======
+//ROGUE
+			else if (effects & EF_TAGTRAIL)
+			{
+				CL_TagTrail (cent->lerp_origin, ent.origin, 220);
+				V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);
+			}
+			else if (effects & EF_TRACKERTRAIL)
+			{
+				if (effects & EF_TRACKER)
+				{
+					float intensity;
+
+					intensity = 50 + (500 * (sin(cl.time/500.0) + 1.0));
+					// FIXME - check out this effect in rendition
+					if(vidref_val == VIDREF_GL)
+						V_AddLight (ent.origin, intensity, -1.0, -1.0, -1.0);
+					else
+						V_AddLight (ent.origin, -1.0 * intensity, 1.0, 1.0, 1.0);
+					}
+				else
+				{
+					CL_Tracker_Shell (cent->lerp_origin);
+					V_AddLight (ent.origin, 155, -1.0, -1.0, -1.0);
+				}
+			}
+			else if (effects & EF_TRACKER)
+			{
+				CL_TrackerTrail (cent->lerp_origin, ent.origin, 0);
+				// FIXME - check out this effect in rendition
+				if(vidref_val == VIDREF_GL)
+					V_AddLight (ent.origin, 200, -1, -1, -1);
+				else
+					V_AddLight (ent.origin, -200, 1, 1, 1);
+			}
+//ROGUE
+//======
+			// RAFAEL
+			else if (effects & EF_GREENGIB)
+			{
+				CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);				
+			}
+			// RAFAEL
+			else if (effects & EF_IONRIPPER)
+			{
+				CL_IonripperTrail (cent->lerp_origin, ent.origin);
+				V_AddLight (ent.origin, 100, 1, 0.5, 0.5);
+			}
+			// RAFAEL
+			else if (effects & EF_BLUEHYPERBLASTER)
+			{
+				V_AddLight (ent.origin, 200, 0, 0, 1);
+			}
+			// RAFAEL
+			else if (effects & EF_PLASMA)
+			{
+				if (effects & EF_ANIM_ALLFAST)
+				{
+					CL_BlasterTrail (cent->lerp_origin, ent.origin);
+				}
+				V_AddLight (ent.origin, 130, 1, 0.5, 0.5);
+			}
+		}
+
+		VectorCopy (ent.origin, cent->lerp_origin);
+	}
+}
+
+
+
+/*
+==============
+CL_AddViewWeapon
+==============
+*/
+void CL_AddViewWeapon (player_state_t *ps, player_state_t *ops)
+{
+	entity_t	gun;		// view model
+	int			i;
+
+	// allow the gun to be completely removed
+	if (!cl_gun->value)
+		return;
+
+	// don't draw gun if in wide angle view
+	if (ps->fov > 90)
+		return;
+
+	memset (&gun, 0, sizeof(gun));
+
+	if (gun_model)
+		gun.model = gun_model;	// development tool
+	else
+		gun.model = cl.model_draw[ps->gunindex];
+	if (!gun.model)
+		return;
+
+	// set up gun position
+	for (i=0 ; i<3 ; i++)
+	{
+		gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i]
+			+ cl.lerpfrac * (ps->gunoffset[i] - ops->gunoffset[i]);
+		gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->gunangles[i],
+			ps->gunangles[i], cl.lerpfrac);
+	}
+
+	if (gun_frame)
+	{
+		gun.frame = gun_frame;	// development tool
+		gun.oldframe = gun_frame;	// development tool
+	}
+	else
+	{
+		gun.frame = ps->gunframe;
+		if (gun.frame == 0)
+			gun.oldframe = 0;	// just changed weapons, don't lerp from old
+		else
+			gun.oldframe = ops->gunframe;
+	}
+
+	gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
+	gun.backlerp = 1.0 - cl.lerpfrac;
+	VectorCopy (gun.origin, gun.oldorigin);	// don't lerp at all
+	V_AddEntity (&gun);
+}
+
+
+/*
+===============
+CL_CalcViewValues
+
+Sets cl.refdef view values
+===============
+*/
+void CL_CalcViewValues (void)
+{
+	int			i;
+	float		lerp, backlerp;
+	frame_t		*oldframe;
+	player_state_t	*ps, *ops;
+
+	// find the previous frame to interpolate from
+	ps = &cl.frame.playerstate;
+	i = (cl.frame.serverframe - 1) & UPDATE_MASK;
+	oldframe = &cl.frames[i];
+	if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
+		oldframe = &cl.frame;		// previous frame was dropped or involid
+	ops = &oldframe->playerstate;
+
+	// see if the player entity was teleported this frame
+	if ( fabs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256*8
+		|| abs(ops->pmove.origin[1] - ps->pmove.origin[1]) > 256*8
+		|| abs(ops->pmove.origin[2] - ps->pmove.origin[2]) > 256*8)
+		ops = ps;		// don't interpolate
+
+	lerp = cl.lerpfrac;
+
+	// calculate the origin
+	if ((cl_predict->value) && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
+	{	// use predicted values
+		unsigned	delta;
+
+		backlerp = 1.0 - lerp;
+		for (i=0 ; i<3 ; i++)
+		{
+			cl.refdef.vieworg[i] = cl.predicted_origin[i] + ops->viewoffset[i] 
+				+ cl.lerpfrac * (ps->viewoffset[i] - ops->viewoffset[i])
+				- backlerp * cl.prediction_error[i];
+		}
+
+		// smooth out stair climbing
+		delta = cls.realtime - cl.predicted_step_time;
+		if (delta < 100)
+			cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01;
+	}
+	else
+	{	// just use interpolated values
+		for (i=0 ; i<3 ; i++)
+			cl.refdef.vieworg[i] = ops->pmove.origin[i]*0.125 + ops->viewoffset[i] 
+				+ lerp * (ps->pmove.origin[i]*0.125 + ps->viewoffset[i] 
+				- (ops->pmove.origin[i]*0.125 + ops->viewoffset[i]) );
+	}
+
+	// if not running a demo or on a locked frame, add the local angle movement
+	if ( cl.frame.playerstate.pmove.pm_type < PM_DEAD )
+	{	// use predicted values
+		for (i=0 ; i<3 ; i++)
+			cl.refdef.viewangles[i] = cl.predicted_angles[i];
+	}
+	else
+	{	// just use interpolated values
+		for (i=0 ; i<3 ; i++)
+			cl.refdef.viewangles[i] = LerpAngle (ops->viewangles[i], ps->viewangles[i], lerp);
+	}
+
+	for (i=0 ; i<3 ; i++)
+		cl.refdef.viewangles[i] += LerpAngle (ops->kick_angles[i], ps->kick_angles[i], lerp);
+
+	AngleVectors (cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up);
+
+	// interpolate field of view
+	cl.refdef.fov_x = ops->fov + lerp * (ps->fov - ops->fov);
+
+	// don't interpolate blend color
+	for (i=0 ; i<4 ; i++)
+		cl.refdef.blend[i] = ps->blend[i];
+
+	// add the weapon
+	CL_AddViewWeapon (ps, ops);
+}
+
+/*
+===============
+CL_AddEntities
+
+Emits all entities, particles, and lights to the refresh
+===============
+*/
+void CL_AddEntities (void)
+{
+	if (cls.state != ca_active)
+		return;
+
+	if (cl.time > cl.frame.servertime)
+	{
+		if (cl_showclamp->value)
+			Com_Printf ("high clamp %i\n", cl.time - cl.frame.servertime);
+		cl.time = cl.frame.servertime;
+		cl.lerpfrac = 1.0;
+	}
+	else if (cl.time < cl.frame.servertime - 100)
+	{
+		if (cl_showclamp->value)
+			Com_Printf ("low clamp %i\n", cl.frame.servertime-100 - cl.time);
+		cl.time = cl.frame.servertime - 100;
+		cl.lerpfrac = 0;
+	}
+	else
+		cl.lerpfrac = 1.0 - (cl.frame.servertime - cl.time) * 0.01;
+
+	if (cl_timedemo->value)
+		cl.lerpfrac = 1.0;
+
+//	CL_AddPacketEntities (&cl.frame);
+//	CL_AddTEnts ();
+//	CL_AddParticles ();
+//	CL_AddDLights ();
+//	CL_AddLightStyles ();
+
+	CL_CalcViewValues ();
+	// PMM - moved this here so the heat beam has the right values for the vieworg, and can lock the beam to the gun
+	CL_AddPacketEntities (&cl.frame);
+/*
+	CL_AddProjectiles ();
+*/
+	CL_AddTEnts ();
+	CL_AddParticles ();
+	CL_AddDLights ();
+	CL_AddLightStyles ();
+}
+
+/* the sound code makes callbacks to the client for entitiy position
+ * information, so entities can be dynamically re-spatialized */
+void CL_GetEntitySoundOrigin (int ent, vec3_t org)
+{
+	centity_t	*old;
+
+	if (ent < 0 || ent >= MAX_EDICTS)
+		Com_Error (ERR_DROP, "CL_GetEntitySoundOrigin: bad ent");
+	old = &cl_entities[ent];
+	VectorCopy (old->lerp_origin, org);
+
+	// FIXME: bmodel issues...
+}
--- /dev/null
+++ b/cl_fx.c
@@ -1,0 +1,2266 @@
+// cl_fx.c -- entity effects parsing and management
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+void CL_LogoutEffect (vec3_t org, int type);
+void CL_ItemRespawnParticles (vec3_t org);
+
+static vec3_t avelocities [NUMVERTEXNORMALS];
+
+extern model_t *cl_mod_smoke;
+extern model_t *cl_mod_flash;
+
+/*
+==============================================================
+
+LIGHT STYLE MANAGEMENT
+
+==============================================================
+*/
+
+typedef struct
+{
+	int		length;
+	float	value[3];
+	float	map[MAX_QPATH];
+} clightstyle_t;
+
+clightstyle_t	cl_lightstyle[MAX_LIGHTSTYLES];
+int			lastofs;
+
+/*
+================
+CL_ClearLightStyles
+================
+*/
+void CL_ClearLightStyles (void)
+{
+	memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
+	lastofs = -1;
+}
+
+/*
+================
+CL_RunLightStyles
+================
+*/
+void CL_RunLightStyles (void)
+{
+	int		ofs;
+	int		i;
+	clightstyle_t	*ls;
+
+	ofs = cl.time / 100;
+	if (ofs == lastofs)
+		return;
+	lastofs = ofs;
+
+	for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
+	{
+		if (!ls->length)
+		{
+			ls->value[0] = ls->value[1] = ls->value[2] = 1.0;
+			continue;
+		}
+		if (ls->length == 1)
+			ls->value[0] = ls->value[1] = ls->value[2] = ls->map[0];
+		else
+			ls->value[0] = ls->value[1] = ls->value[2] = ls->map[ofs%ls->length];
+	}
+}
+
+
+void CL_SetLightstyle (int i)
+{
+	char	*s;
+	int		j, k;
+
+	s = cl.configstrings[i+CS_LIGHTS];
+
+	j = strlen (s);
+	if (j >= MAX_QPATH)
+		Com_Error (ERR_DROP, "svc_lightstyle length=%i", j);
+
+	cl_lightstyle[i].length = j;
+
+	for (k=0 ; k<j ; k++)
+		cl_lightstyle[i].map[k] = (float)(s[k]-'a')/(float)('m'-'a');
+}
+
+/*
+================
+CL_AddLightStyles
+================
+*/
+void CL_AddLightStyles (void)
+{
+	int		i;
+	clightstyle_t	*ls;
+
+	for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
+		V_AddLightStyle (i, ls->value[0], ls->value[1], ls->value[2]);
+}
+
+/*
+==============================================================
+
+DLIGHT MANAGEMENT
+
+==============================================================
+*/
+
+cdlight_t		cl_dlights[MAX_DLIGHTS];
+
+/*
+================
+CL_ClearDlights
+================
+*/
+void CL_ClearDlights (void)
+{
+	memset (cl_dlights, 0, sizeof(cl_dlights));
+}
+
+/*
+===============
+CL_AllocDlight
+
+===============
+*/
+cdlight_t *CL_AllocDlight (int key)
+{
+	int		i;
+	cdlight_t	*dl;
+
+// first look for an exact key match
+	if (key)
+	{
+		dl = cl_dlights;
+		for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+		{
+			if (dl->key == key)
+			{
+				memset (dl, 0, sizeof(*dl));
+				dl->key = key;
+				return dl;
+			}
+		}
+	}
+
+// then look for anything else
+	dl = cl_dlights;
+	for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+	{
+		if (dl->die < cl.time)
+		{
+			memset (dl, 0, sizeof(*dl));
+			dl->key = key;
+			return dl;
+		}
+	}
+
+	dl = &cl_dlights[0];
+	memset (dl, 0, sizeof(*dl));
+	dl->key = key;
+	return dl;
+}
+
+/*
+===============
+CL_NewDlight
+===============
+*/
+void CL_NewDlight (int key, float x, float y, float z, float radius, float time)
+{
+	cdlight_t	*dl;
+
+	dl = CL_AllocDlight (key);
+	dl->origin[0] = x;
+	dl->origin[1] = y;
+	dl->origin[2] = z;
+	dl->radius = radius;
+	dl->die = cl.time + time;
+}
+
+
+/*
+===============
+CL_RunDLights
+
+===============
+*/
+void CL_RunDLights (void)
+{
+	int			i;
+	cdlight_t	*dl;
+
+	dl = cl_dlights;
+	for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+	{
+		if (!dl->radius)
+			continue;
+		
+		if (dl->die < cl.time)
+		{
+			dl->radius = 0;
+			return;
+		}
+		dl->radius -= cls.frametime*dl->decay;
+		if (dl->radius < 0)
+			dl->radius = 0;
+	}
+}
+
+/*
+==============
+CL_ParseMuzzleFlash
+==============
+*/
+void CL_ParseMuzzleFlash (void)
+{
+	vec3_t		fv, rv;
+	cdlight_t	*dl;
+	int			i, weapon;
+	centity_t	*pl;
+	int			silenced;
+	float		volume;
+	char		soundname[64];
+
+	i = MSG_ReadShort (&net_message);
+	if (i < 1 || i >= MAX_EDICTS)
+		Com_Error (ERR_DROP, "CL_ParseMuzzleFlash: bad entity");
+
+	weapon = MSG_ReadByte (&net_message);
+	silenced = weapon & MZ_SILENCED;
+	weapon &= ~MZ_SILENCED;
+
+	pl = &cl_entities[i];
+
+	dl = CL_AllocDlight (i);
+	VectorCopy (pl->current.origin,  dl->origin);
+	AngleVectors (pl->current.angles, fv, rv, NULL);
+	VectorMA (dl->origin, 18, fv, dl->origin);
+	VectorMA (dl->origin, 16, rv, dl->origin);
+	if (silenced)
+		dl->radius = 100 + (rand()&31);
+	else
+		dl->radius = 200 + (rand()&31);
+	dl->minlight = 32;
+	dl->die = cl.time; // + 0.1;
+
+	if (silenced)
+		volume = 0.2;
+	else
+		volume = 1;
+
+	switch (weapon)
+	{
+	case MZ_BLASTER:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_BLUEHYPERBLASTER:
+		dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_HYPERBLASTER:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_MACHINEGUN:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+		break;
+	case MZ_SHOTGUN:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotgf1b.wav"), volume, ATTN_NORM, 0);
+		S_StartSound (NULL, i, CHAN_AUTO,   S_RegisterSound("weapons/shotgr1b.wav"), volume, ATTN_NORM, 0.1);
+		break;
+	case MZ_SSHOTGUN:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/sshotf1b.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_CHAINGUN1:
+		dl->radius = 200 + (rand()&31);
+		dl->color[0] = 1;dl->color[1] = 0.25;dl->color[2] = 0;
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+		break;
+	case MZ_CHAINGUN2:
+		dl->radius = 225 + (rand()&31);
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
+		dl->die = cl.time  + 0.1;	// long delay
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.05);
+		break;
+	case MZ_CHAINGUN3:
+		dl->radius = 250 + (rand()&31);
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		dl->die = cl.time  + 0.1;	// long delay
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.033);
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.066);
+		break;
+	case MZ_RAILGUN:
+		dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/railgf1a.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_ROCKET:
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rocklf1a.wav"), volume, ATTN_NORM, 0);
+		S_StartSound (NULL, i, CHAN_AUTO,   S_RegisterSound("weapons/rocklr1b.wav"), volume, ATTN_NORM, 0.1);
+		break;
+	case MZ_GRENADE:
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0);
+		S_StartSound (NULL, i, CHAN_AUTO,   S_RegisterSound("weapons/grenlr1b.wav"), volume, ATTN_NORM, 0.1);
+		break;
+	case MZ_BFG:
+		dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0);
+		break;
+
+	case MZ_LOGIN:
+		dl->color[0] = 0;dl->color[1] = 1; dl->color[2] = 0;
+		dl->die = cl.time + 1.0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+		CL_LogoutEffect (pl->current.origin, weapon);
+		break;
+	case MZ_LOGOUT:
+		dl->color[0] = 1;dl->color[1] = 0; dl->color[2] = 0;
+		dl->die = cl.time + 1.0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+		CL_LogoutEffect (pl->current.origin, weapon);
+		break;
+	case MZ_RESPAWN:
+		dl->color[0] = 1;dl->color[1] = 1; dl->color[2] = 0;
+		dl->die = cl.time + 1.0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+		CL_LogoutEffect (pl->current.origin, weapon);
+		break;
+	// RAFAEL
+	case MZ_PHALANX:
+		dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/plasshot.wav"), volume, ATTN_NORM, 0);
+		break;
+	// RAFAEL
+	case MZ_IONRIPPER:	
+		dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0);
+		break;
+
+// ======================
+// PGM
+	case MZ_ETF_RIFLE:
+		dl->color[0] = 0.9;dl->color[1] = 0.7;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_SHOTGUN2:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_HEATBEAM:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		dl->die = cl.time + 100;
+//		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_BLASTER2:
+		dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
+		// FIXME - different sound for blaster2 ??
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_TRACKER:
+		// negative flashes handled the same in gl/soft until CL_AddDLights
+		dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), volume, ATTN_NORM, 0);
+		break;		
+	case MZ_NUKE1:
+		dl->color[0] = 1;dl->color[1] = 0;dl->color[2] = 0;
+		dl->die = cl.time + 100;
+		break;
+	case MZ_NUKE2:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		dl->die = cl.time + 100;
+		break;
+	case MZ_NUKE4:
+		dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
+		dl->die = cl.time + 100;
+		break;
+	case MZ_NUKE8:
+		dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 1;
+		dl->die = cl.time + 100;
+		break;
+// PGM
+// ======================
+	}
+}
+
+
+/*
+==============
+CL_ParseMuzzleFlash2
+==============
+*/
+void CL_ParseMuzzleFlash2 (void) 
+{
+	int			ent;
+	vec3_t		origin;
+	int			flash_number;
+	cdlight_t	*dl;
+	vec3_t		forward, right;
+	char		soundname[64];
+
+	ent = MSG_ReadShort (&net_message);
+	if (ent < 1 || ent >= MAX_EDICTS)
+		Com_Error (ERR_DROP, "CL_ParseMuzzleFlash2: bad entity");
+
+	flash_number = MSG_ReadByte (&net_message);
+
+	// locate the origin
+	AngleVectors (cl_entities[ent].current.angles, forward, right, NULL);
+	origin[0] = cl_entities[ent].current.origin[0] + forward[0] * monster_flash_offset[flash_number][0] + right[0] * monster_flash_offset[flash_number][1];
+	origin[1] = cl_entities[ent].current.origin[1] + forward[1] * monster_flash_offset[flash_number][0] + right[1] * monster_flash_offset[flash_number][1];
+	origin[2] = cl_entities[ent].current.origin[2] + forward[2] * monster_flash_offset[flash_number][0] + right[2] * monster_flash_offset[flash_number][1] + monster_flash_offset[flash_number][2];
+
+	dl = CL_AllocDlight (ent);
+	VectorCopy (origin,  dl->origin);
+	dl->radius = 200 + (rand()&31);
+	dl->minlight = 32;
+	dl->die = cl.time;	// + 0.1;
+
+	switch (flash_number)
+	{
+	case MZ2_INFANTRY_MACHINEGUN_1:
+	case MZ2_INFANTRY_MACHINEGUN_2:
+	case MZ2_INFANTRY_MACHINEGUN_3:
+	case MZ2_INFANTRY_MACHINEGUN_4:
+	case MZ2_INFANTRY_MACHINEGUN_5:
+	case MZ2_INFANTRY_MACHINEGUN_6:
+	case MZ2_INFANTRY_MACHINEGUN_7:
+	case MZ2_INFANTRY_MACHINEGUN_8:
+	case MZ2_INFANTRY_MACHINEGUN_9:
+	case MZ2_INFANTRY_MACHINEGUN_10:
+	case MZ2_INFANTRY_MACHINEGUN_11:
+	case MZ2_INFANTRY_MACHINEGUN_12:
+	case MZ2_INFANTRY_MACHINEGUN_13:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_SOLDIER_MACHINEGUN_1:
+	case MZ2_SOLDIER_MACHINEGUN_2:
+	case MZ2_SOLDIER_MACHINEGUN_3:
+	case MZ2_SOLDIER_MACHINEGUN_4:
+	case MZ2_SOLDIER_MACHINEGUN_5:
+	case MZ2_SOLDIER_MACHINEGUN_6:
+	case MZ2_SOLDIER_MACHINEGUN_7:
+	case MZ2_SOLDIER_MACHINEGUN_8:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_GUNNER_MACHINEGUN_1:
+	case MZ2_GUNNER_MACHINEGUN_2:
+	case MZ2_GUNNER_MACHINEGUN_3:
+	case MZ2_GUNNER_MACHINEGUN_4:
+	case MZ2_GUNNER_MACHINEGUN_5:
+	case MZ2_GUNNER_MACHINEGUN_6:
+	case MZ2_GUNNER_MACHINEGUN_7:
+	case MZ2_GUNNER_MACHINEGUN_8:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_ACTOR_MACHINEGUN_1:
+	case MZ2_SUPERTANK_MACHINEGUN_1:
+	case MZ2_SUPERTANK_MACHINEGUN_2:
+	case MZ2_SUPERTANK_MACHINEGUN_3:
+	case MZ2_SUPERTANK_MACHINEGUN_4:
+	case MZ2_SUPERTANK_MACHINEGUN_5:
+	case MZ2_SUPERTANK_MACHINEGUN_6:
+	case MZ2_TURRET_MACHINEGUN:			// PGM
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_BOSS2_MACHINEGUN_L1:
+	case MZ2_BOSS2_MACHINEGUN_L2:
+	case MZ2_BOSS2_MACHINEGUN_L3:
+	case MZ2_BOSS2_MACHINEGUN_L4:
+	case MZ2_BOSS2_MACHINEGUN_L5:
+	case MZ2_CARRIER_MACHINEGUN_L1:		// PMM
+	case MZ2_CARRIER_MACHINEGUN_L2:		// PMM
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0);
+		break;
+
+	case MZ2_SOLDIER_BLASTER_1:
+	case MZ2_SOLDIER_BLASTER_2:
+	case MZ2_SOLDIER_BLASTER_3:
+	case MZ2_SOLDIER_BLASTER_4:
+	case MZ2_SOLDIER_BLASTER_5:
+	case MZ2_SOLDIER_BLASTER_6:
+	case MZ2_SOLDIER_BLASTER_7:
+	case MZ2_SOLDIER_BLASTER_8:
+	case MZ2_TURRET_BLASTER:			// PGM
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck2.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_FLYER_BLASTER_1:
+	case MZ2_FLYER_BLASTER_2:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("flyer/flyatck3.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_MEDIC_BLASTER_1:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("medic/medatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_HOVER_BLASTER_1:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("hover/hovatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_FLOAT_BLASTER_1:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("floater/fltatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_SOLDIER_SHOTGUN_1:
+	case MZ2_SOLDIER_SHOTGUN_2:
+	case MZ2_SOLDIER_SHOTGUN_3:
+	case MZ2_SOLDIER_SHOTGUN_4:
+	case MZ2_SOLDIER_SHOTGUN_5:
+	case MZ2_SOLDIER_SHOTGUN_6:
+	case MZ2_SOLDIER_SHOTGUN_7:
+	case MZ2_SOLDIER_SHOTGUN_8:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_TANK_BLASTER_1:
+	case MZ2_TANK_BLASTER_2:
+	case MZ2_TANK_BLASTER_3:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_TANK_MACHINEGUN_1:
+	case MZ2_TANK_MACHINEGUN_2:
+	case MZ2_TANK_MACHINEGUN_3:
+	case MZ2_TANK_MACHINEGUN_4:
+	case MZ2_TANK_MACHINEGUN_5:
+	case MZ2_TANK_MACHINEGUN_6:
+	case MZ2_TANK_MACHINEGUN_7:
+	case MZ2_TANK_MACHINEGUN_8:
+	case MZ2_TANK_MACHINEGUN_9:
+	case MZ2_TANK_MACHINEGUN_10:
+	case MZ2_TANK_MACHINEGUN_11:
+	case MZ2_TANK_MACHINEGUN_12:
+	case MZ2_TANK_MACHINEGUN_13:
+	case MZ2_TANK_MACHINEGUN_14:
+	case MZ2_TANK_MACHINEGUN_15:
+	case MZ2_TANK_MACHINEGUN_16:
+	case MZ2_TANK_MACHINEGUN_17:
+	case MZ2_TANK_MACHINEGUN_18:
+	case MZ2_TANK_MACHINEGUN_19:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		Com_sprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + rand() % 5);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound(soundname), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_CHICK_ROCKET_1:
+	case MZ2_TURRET_ROCKET:			// PGM
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("chick/chkatck2.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_TANK_ROCKET_1:
+	case MZ2_TANK_ROCKET_2:
+	case MZ2_TANK_ROCKET_3:
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_SUPERTANK_ROCKET_1:
+	case MZ2_SUPERTANK_ROCKET_2:
+	case MZ2_SUPERTANK_ROCKET_3:
+	case MZ2_BOSS2_ROCKET_1:
+	case MZ2_BOSS2_ROCKET_2:
+	case MZ2_BOSS2_ROCKET_3:
+	case MZ2_BOSS2_ROCKET_4:
+	case MZ2_CARRIER_ROCKET_1:
+//	case MZ2_CARRIER_ROCKET_2:
+//	case MZ2_CARRIER_ROCKET_3:
+//	case MZ2_CARRIER_ROCKET_4:
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/rocket.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_GUNNER_GRENADE_1:
+	case MZ2_GUNNER_GRENADE_2:
+	case MZ2_GUNNER_GRENADE_3:
+	case MZ2_GUNNER_GRENADE_4:
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck3.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_GLADIATOR_RAILGUN_1:
+	// PMM
+	case MZ2_CARRIER_RAILGUN:
+	case MZ2_WIDOW_RAIL:
+	// pmm
+		dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
+		break;
+
+// --- Xian's shit starts ---
+	case MZ2_MAKRON_BFG:
+		dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
+		//S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_MAKRON_BLASTER_1:
+	case MZ2_MAKRON_BLASTER_2:
+	case MZ2_MAKRON_BLASTER_3:
+	case MZ2_MAKRON_BLASTER_4:
+	case MZ2_MAKRON_BLASTER_5:
+	case MZ2_MAKRON_BLASTER_6:
+	case MZ2_MAKRON_BLASTER_7:
+	case MZ2_MAKRON_BLASTER_8:
+	case MZ2_MAKRON_BLASTER_9:
+	case MZ2_MAKRON_BLASTER_10:
+	case MZ2_MAKRON_BLASTER_11:
+	case MZ2_MAKRON_BLASTER_12:
+	case MZ2_MAKRON_BLASTER_13:
+	case MZ2_MAKRON_BLASTER_14:
+	case MZ2_MAKRON_BLASTER_15:
+	case MZ2_MAKRON_BLASTER_16:
+	case MZ2_MAKRON_BLASTER_17:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/blaster.wav"), 1, ATTN_NORM, 0);
+		break;
+	
+	case MZ2_JORG_MACHINEGUN_L1:
+	case MZ2_JORG_MACHINEGUN_L2:
+	case MZ2_JORG_MACHINEGUN_L3:
+	case MZ2_JORG_MACHINEGUN_L4:
+	case MZ2_JORG_MACHINEGUN_L5:
+	case MZ2_JORG_MACHINEGUN_L6:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("boss3/xfire.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_JORG_MACHINEGUN_R1:
+	case MZ2_JORG_MACHINEGUN_R2:
+	case MZ2_JORG_MACHINEGUN_R3:
+	case MZ2_JORG_MACHINEGUN_R4:
+	case MZ2_JORG_MACHINEGUN_R5:
+	case MZ2_JORG_MACHINEGUN_R6:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		break;
+
+	case MZ2_JORG_BFG_1:
+		dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
+		break;
+
+	case MZ2_BOSS2_MACHINEGUN_R1:
+	case MZ2_BOSS2_MACHINEGUN_R2:
+	case MZ2_BOSS2_MACHINEGUN_R3:
+	case MZ2_BOSS2_MACHINEGUN_R4:
+	case MZ2_BOSS2_MACHINEGUN_R5:
+	case MZ2_CARRIER_MACHINEGUN_R1:			// PMM
+	case MZ2_CARRIER_MACHINEGUN_R2:			// PMM
+
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		break;
+
+// ======
+// ROGUE
+	case MZ2_STALKER_BLASTER:
+	case MZ2_DAEDALUS_BLASTER:
+	case MZ2_MEDIC_BLASTER_2:
+	case MZ2_WIDOW_BLASTER:
+	case MZ2_WIDOW_BLASTER_SWEEP1:
+	case MZ2_WIDOW_BLASTER_SWEEP2:
+	case MZ2_WIDOW_BLASTER_SWEEP3:
+	case MZ2_WIDOW_BLASTER_SWEEP4:
+	case MZ2_WIDOW_BLASTER_SWEEP5:
+	case MZ2_WIDOW_BLASTER_SWEEP6:
+	case MZ2_WIDOW_BLASTER_SWEEP7:
+	case MZ2_WIDOW_BLASTER_SWEEP8:
+	case MZ2_WIDOW_BLASTER_SWEEP9:
+	case MZ2_WIDOW_BLASTER_100:
+	case MZ2_WIDOW_BLASTER_90:
+	case MZ2_WIDOW_BLASTER_80:
+	case MZ2_WIDOW_BLASTER_70:
+	case MZ2_WIDOW_BLASTER_60:
+	case MZ2_WIDOW_BLASTER_50:
+	case MZ2_WIDOW_BLASTER_40:
+	case MZ2_WIDOW_BLASTER_30:
+	case MZ2_WIDOW_BLASTER_20:
+	case MZ2_WIDOW_BLASTER_10:
+	case MZ2_WIDOW_BLASTER_0:
+	case MZ2_WIDOW_BLASTER_10L:
+	case MZ2_WIDOW_BLASTER_20L:
+	case MZ2_WIDOW_BLASTER_30L:
+	case MZ2_WIDOW_BLASTER_40L:
+	case MZ2_WIDOW_BLASTER_50L:
+	case MZ2_WIDOW_BLASTER_60L:
+	case MZ2_WIDOW_BLASTER_70L:
+	case MZ2_WIDOW_RUN_1:
+	case MZ2_WIDOW_RUN_2:
+	case MZ2_WIDOW_RUN_3:
+	case MZ2_WIDOW_RUN_4:
+	case MZ2_WIDOW_RUN_5:
+	case MZ2_WIDOW_RUN_6:
+	case MZ2_WIDOW_RUN_7:
+	case MZ2_WIDOW_RUN_8:
+		dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_WIDOW_DISRUPTOR:
+		dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_WIDOW_PLASMABEAM:
+	case MZ2_WIDOW2_BEAMER_1:
+	case MZ2_WIDOW2_BEAMER_2:
+	case MZ2_WIDOW2_BEAMER_3:
+	case MZ2_WIDOW2_BEAMER_4:
+	case MZ2_WIDOW2_BEAMER_5:
+	case MZ2_WIDOW2_BEAM_SWEEP_1:
+	case MZ2_WIDOW2_BEAM_SWEEP_2:
+	case MZ2_WIDOW2_BEAM_SWEEP_3:
+	case MZ2_WIDOW2_BEAM_SWEEP_4:
+	case MZ2_WIDOW2_BEAM_SWEEP_5:
+	case MZ2_WIDOW2_BEAM_SWEEP_6:
+	case MZ2_WIDOW2_BEAM_SWEEP_7:
+	case MZ2_WIDOW2_BEAM_SWEEP_8:
+	case MZ2_WIDOW2_BEAM_SWEEP_9:
+	case MZ2_WIDOW2_BEAM_SWEEP_10:
+	case MZ2_WIDOW2_BEAM_SWEEP_11:
+		dl->radius = 300 + (rand()&100);
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		dl->die = cl.time + 200;
+		break;
+// ROGUE
+// ======
+
+// --- Xian's shit ends ---
+
+	}
+}
+
+
+/*
+===============
+CL_AddDLights
+
+===============
+*/
+void CL_AddDLights (void)
+{
+	int			i;
+	cdlight_t	*dl;
+
+	dl = cl_dlights;
+
+//=====
+//PGM
+	if(vidref_val == VIDREF_GL)
+	{
+		for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+		{
+			if (!dl->radius)
+				continue;
+			V_AddLight (dl->origin, dl->radius,
+				dl->color[0], dl->color[1], dl->color[2]);
+		}
+	}
+	else
+	{
+		for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+		{
+			if (!dl->radius)
+				continue;
+
+			// negative light in software. only black allowed
+			if ((dl->color[0] < 0) || (dl->color[1] < 0) || (dl->color[2] < 0))
+			{
+				dl->radius = -(dl->radius);
+				dl->color[0] = 1;
+				dl->color[1] = 1;
+				dl->color[2] = 1;
+			}
+			V_AddLight (dl->origin, dl->radius,
+				dl->color[0], dl->color[1], dl->color[2]);
+		}
+	}
+//PGM
+//=====
+}
+
+
+
+/*
+==============================================================
+
+PARTICLE MANAGEMENT
+
+==============================================================
+*/
+
+cparticle_t	*active_particles, *free_particles;
+
+cparticle_t	particles[MAX_PARTICLES];
+int			cl_numparticles = MAX_PARTICLES;
+
+
+/*
+===============
+CL_ClearParticles
+===============
+*/
+void CL_ClearParticles (void)
+{
+	int		i;
+	
+	free_particles = &particles[0];
+	active_particles = NULL;
+
+	for (i=0 ;i<cl_numparticles ; i++)
+		particles[i].next = &particles[i+1];
+	particles[cl_numparticles-1].next = NULL;
+}
+
+
+/*
+===============
+CL_ParticleEffect
+
+Wall impact puffs
+===============
+*/
+void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color + (rand()&7);
+
+		d = rand()&31;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+			p->vel[j] = crand()*20;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_ParticleEffect2
+===============
+*/
+void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color;
+
+		d = rand()&7;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+			p->vel[j] = crand()*20;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+	}
+}
+
+
+// RAFAEL
+/*
+===============
+CL_ParticleEffect3
+===============
+*/
+void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color;
+
+		d = rand()&7;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+			p->vel[j] = crand()*20;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+	}
+}
+
+/*
+===============
+CL_TeleporterParticles
+===============
+*/
+void CL_TeleporterParticles (entity_state_t *ent)
+{
+	int			i, j;
+	cparticle_t	*p;
+
+	for (i=0 ; i<8 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = 0xdb;
+
+		for (j=0 ; j<2 ; j++)
+		{
+			p->org[j] = ent->origin[j] - 16 + (rand()&31);
+			p->vel[j] = crand()*14;
+		}
+
+		p->org[2] = ent->origin[2] - 8 + (rand()&7);
+		p->vel[2] = 80 + (rand()&7);
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -0.5;
+	}
+}
+
+
+/*
+===============
+CL_LogoutEffect
+
+===============
+*/
+void CL_LogoutEffect (vec3_t org, int type)
+{
+	int			i, j;
+	cparticle_t	*p;
+
+	for (i=0 ; i<500 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+
+		if (type == MZ_LOGIN)
+			p->color = 0xd0 + (rand()&7);	// green
+		else if (type == MZ_LOGOUT)
+			p->color = 0x40 + (rand()&7);	// red
+		else
+			p->color = 0xe0 + (rand()&7);	// yellow
+
+		p->org[0] = org[0] - 16 + qfrand()*32;
+		p->org[1] = org[1] - 16 + qfrand()*32;
+		p->org[2] = org[2] - 24 + qfrand()*56;
+
+		for (j=0 ; j<3 ; j++)
+			p->vel[j] = crand()*20;
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (1.0 + qfrand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_ItemRespawnParticles
+
+===============
+*/
+void CL_ItemRespawnParticles (vec3_t org)
+{
+	int			i, j;
+	cparticle_t	*p;
+
+	for (i=0 ; i<64 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+
+		p->color = 0xd4 + (rand()&3);	// green
+
+		p->org[0] = org[0] + crand()*8;
+		p->org[1] = org[1] + crand()*8;
+		p->org[2] = org[2] + crand()*8;
+
+		for (j=0 ; j<3 ; j++)
+			p->vel[j] = crand()*8;
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY*0.2;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (1.0 + qfrand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_ExplosionParticles
+===============
+*/
+void CL_ExplosionParticles (vec3_t org)
+{
+	int			i, j;
+	cparticle_t	*p;
+
+	for (i=0 ; i<256 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = 0xe0 + (rand()&7);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()%32)-16);
+			p->vel[j] = (rand()%384)-192;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_BigTeleportParticles
+===============
+*/
+void CL_BigTeleportParticles (vec3_t org)
+{
+	int			i;
+	cparticle_t	*p;
+	float		angle, dist;
+	static int colortable[4] = {2*8,13*8,21*8,18*8};
+
+	for (i=0 ; i<4096 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+
+		p->color = colortable[rand()&3];
+
+		angle = M_PI*2*(rand()&1023)/1023.0;
+		dist = rand()&31;
+		p->org[0] = org[0] + cos(angle)*dist;
+		p->vel[0] = cos(angle)*(70+(rand()&63));
+		p->accel[0] = -cos(angle)*100;
+
+		p->org[1] = org[1] + sin(angle)*dist;
+		p->vel[1] = sin(angle)*(70+(rand()&63));
+		p->accel[1] = -sin(angle)*100;
+
+		p->org[2] = org[2] + 8 + (rand()%90);
+		p->vel[2] = -100 + (rand()&31);
+		p->accel[2] = PARTICLE_GRAVITY*4;
+		p->alpha = 1.0;
+
+		p->alphavel = -0.3 / (0.5 + qfrand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_BlasterParticles
+
+Wall impact puffs
+===============
+*/
+void CL_BlasterParticles (vec3_t org, vec3_t dir)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+	int			count;
+
+	count = 40;
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = 0xe0 + (rand()&7);
+
+		d = rand()&15;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+			p->vel[j] = dir[j] * 30 + crand()*40;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_BlasterTrail
+
+===============
+*/
+void CL_BlasterTrail (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	// FIXME: this is a really silly way to have a loop
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.3+qfrand()*0.2);
+		p->color = 0xe0;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand();
+			p->vel[j] = crand()*5;
+			p->accel[j] = 0;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+/*
+===============
+CL_QuadTrail
+
+===============
+*/
+void CL_QuadTrail (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.8+qfrand()*0.2);
+		p->color = 115;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*16;
+			p->vel[j] = crand()*5;
+			p->accel[j] = 0;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+/*
+===============
+CL_FlagTrail
+
+===============
+*/
+void CL_FlagTrail (vec3_t start, vec3_t end, float color)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.8+qfrand()*0.2);
+		p->color = color;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*16;
+			p->vel[j] = crand()*5;
+			p->accel[j] = 0;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+/*
+===============
+CL_DiminishingTrail
+
+===============
+*/
+void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	float		dec;
+	float		orgscale;
+	float		velscale;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 0.5;
+	VectorScale (vec, dec, vec);
+
+	if (old->trailcount > 900)
+	{
+		orgscale = 4;
+		velscale = 15;
+	}
+	else if (old->trailcount > 800)
+	{
+		orgscale = 2;
+		velscale = 10;
+	}
+	else
+	{
+		orgscale = 1;
+		velscale = 5;
+	}
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+
+		// drop less particles as it flies
+		if ((rand()&1023) < old->trailcount)
+		{
+			p = free_particles;
+			free_particles = p->next;
+			p->next = active_particles;
+			active_particles = p;
+			VectorClear (p->accel);
+		
+			p->time = cl.time;
+
+			if (flags & EF_GIB)
+			{
+				p->alpha = 1.0;
+				p->alphavel = -1.0 / (1+qfrand()*0.4);
+				p->color = 0xe8 + (rand()&7);
+				for (j=0 ; j<3 ; j++)
+				{
+					p->org[j] = move[j] + crand()*orgscale;
+					p->vel[j] = crand()*velscale;
+					p->accel[j] = 0;
+				}
+				p->vel[2] -= PARTICLE_GRAVITY;
+			}
+			else if (flags & EF_GREENGIB)
+			{
+				p->alpha = 1.0;
+				p->alphavel = -1.0 / (1+qfrand()*0.4);
+				p->color = 0xdb + (rand()&7);
+				for (j=0; j< 3; j++)
+				{
+					p->org[j] = move[j] + crand()*orgscale;
+					p->vel[j] = crand()*velscale;
+					p->accel[j] = 0;
+				}
+				p->vel[2] -= PARTICLE_GRAVITY;
+			}
+			else
+			{
+				p->alpha = 1.0;
+				p->alphavel = -1.0 / (1+qfrand()*0.2);
+				p->color = 4 + (rand()&7);
+				for (j=0 ; j<3 ; j++)
+				{
+					p->org[j] = move[j] + crand()*orgscale;
+					p->vel[j] = crand()*velscale;
+				}
+				p->accel[2] = 20;
+			}
+		}
+
+		old->trailcount -= 5;
+		if (old->trailcount < 100)
+			old->trailcount = 100;
+		VectorAdd (move, vec, move);
+	}
+}
+
+void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up)
+{
+	float		d;
+
+	// this rotate and negat guarantees a vector
+	// not colinear with the original
+	right[1] = -forward[0];
+	right[2] = forward[1];
+	right[0] = forward[2];
+
+	d = DotProduct (right, forward);
+	VectorMA (right, -d, forward, right);
+	VectorNormalize (right);
+	CrossProduct (right, forward, up);
+}
+
+/*
+===============
+CL_RocketTrail
+
+===============
+*/
+void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	float		dec;
+
+	// smoke
+	CL_DiminishingTrail (start, end, old, EF_ROCKET);
+
+	// fire
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 1;
+	VectorScale (vec, dec, vec);
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+
+		if ( (rand()&7) == 0)
+		{
+			p = free_particles;
+			free_particles = p->next;
+			p->next = active_particles;
+			active_particles = p;
+			
+			VectorClear (p->accel);
+			p->time = cl.time;
+
+			p->alpha = 1.0;
+			p->alphavel = -1.0 / (1+qfrand()*0.2);
+			p->color = 0xdc + (rand()&3);
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = move[j] + crand()*5;
+				p->vel[j] = crand()*20;
+			}
+			p->accel[2] = -PARTICLE_GRAVITY;
+		}
+		VectorAdd (move, vec, move);
+	}
+}
+
+/*
+===============
+CL_RailTrail
+
+===============
+*/
+void CL_RailTrail (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	float		dec;
+	vec3_t		right, up;
+	int			i;
+	float		d, c, s;
+	vec3_t		dir;
+	byte		clr = 0x74;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	MakeNormalVectors (vec, right, up);
+
+	for (i=0 ; i<len ; i++)
+	{
+		if (!free_particles)
+			return;
+
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		
+		p->time = cl.time;
+		VectorClear (p->accel);
+
+		d = i * 0.1;
+		c = cos(d);
+		s = sin(d);
+
+		VectorScale (right, c, dir);
+		VectorMA (dir, s, up, dir);
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (1+qfrand()*0.2);
+		p->color = clr + (rand()&7);
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + dir[j]*3;
+			p->vel[j] = dir[j]*6;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+
+	dec = 0.75;
+	VectorScale (vec, dec, vec);
+	VectorCopy (start, move);
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		VectorClear (p->accel);
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.6+qfrand()*0.2);
+		p->color = 0x0 + rand()&15;
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*3;
+			p->vel[j] = crand()*3;
+			p->accel[j] = 0;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+// RAFAEL
+/*
+===============
+CL_IonripperTrail
+===============
+*/
+void CL_IonripperTrail (vec3_t start, vec3_t ent)
+{
+	vec3_t	move;
+	vec3_t	vec;
+	float	len;
+	int		j;
+	cparticle_t *p;
+	int		dec;
+	int     left = 0;
+
+	VectorCopy (start, move);
+	VectorSubtract (ent, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+
+		p->time = cl.time;
+		p->alpha = 0.5;
+		p->alphavel = -1.0 / (0.3 + qfrand() * 0.2);
+		p->color = 0xe4 + (rand()&3);
+
+		for (j=0; j<3; j++)
+		{
+			p->org[j] = move[j];
+			p->accel[j] = 0;
+		}
+		if (left)
+		{
+			left = 0;
+			p->vel[0] = 10;
+		}
+		else 
+		{
+			left = 1;
+			p->vel[0] = -10;
+		}
+
+		p->vel[1] = 0;
+		p->vel[2] = 0;
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+
+/*
+===============
+CL_BubbleTrail
+
+===============
+*/
+void CL_BubbleTrail (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			i, j;
+	cparticle_t	*p;
+	float		dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 32;
+	VectorScale (vec, dec, vec);
+
+	for (i=0 ; i<len ; i+=dec)
+	{
+		if (!free_particles)
+			return;
+
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		VectorClear (p->accel);
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (1+qfrand()*0.2);
+		p->color = 4 + (rand()&7);
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*2;
+			p->vel[j] = crand()*5;
+		}
+		p->vel[2] += 6;
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+
+/*
+===============
+CL_FlyParticles
+===============
+*/
+
+#define	BEAMLENGTH	16
+
+void CL_FlyParticles (vec3_t origin, int count)
+{
+	int			i;
+	cparticle_t	*p;
+	float		angle;
+	float		sp, sy, cp, cy;
+	vec3_t		forward;
+	float		dist;
+	float		ltime;
+
+
+	if (count > NUMVERTEXNORMALS)
+		count = NUMVERTEXNORMALS;
+
+	if (!avelocities[0][0])
+	{
+		for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
+			avelocities[0][i] = (rand()&255) * 0.01;
+	}
+
+
+	ltime = (float)cl.time / 1000.0;
+	for (i=0 ; i<count ; i+=2)
+	{
+		angle = ltime * avelocities[i][0];
+		sy = sin(angle);
+		cy = cos(angle);
+		angle = ltime * avelocities[i][1];
+		sp = sin(angle);
+		cp = cos(angle);
+		/*
+		angle = ltime * avelocities[i][2];
+		sr = sin(angle);
+		cr = cos(angle);
+		*/
+	
+		forward[0] = cp*cy;
+		forward[1] = cp*sy;
+		forward[2] = -sp;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+
+		dist = sin(ltime + i)*64;
+		p->org[0] = origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
+		p->org[1] = origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
+		p->org[2] = origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
+
+		VectorClear (p->vel);
+		VectorClear (p->accel);
+
+		p->color = 0;
+		p->colorvel = 0;
+
+		p->alpha = 1;
+		p->alphavel = -100;
+	}
+}
+
+void CL_FlyEffect (centity_t *ent, vec3_t origin)
+{
+	int		n;
+	int		count;
+	int		starttime;
+
+	if (ent->fly_stoptime < cl.time)
+	{
+		starttime = cl.time;
+		ent->fly_stoptime = cl.time + 60000;
+	}
+	else
+	{
+		starttime = ent->fly_stoptime - 60000;
+	}
+
+	n = cl.time - starttime;
+	if (n < 20000)
+		count = n * 162 / 20000.0;
+	else
+	{
+		n = ent->fly_stoptime - cl.time;
+		if (n < 20000)
+			count = n * 162 / 20000.0;
+		else
+			count = 162;
+	}
+
+	CL_FlyParticles (origin, count);
+}
+
+
+/*
+===============
+CL_BfgParticles
+===============
+*/
+
+void CL_BfgParticles (entity_t *ent)
+{
+	int			i;
+	cparticle_t	*p;
+	float		angle;
+	float		sp, sy, cp, cy;
+	vec3_t		forward;
+	float		dist;
+	vec3_t		v;
+	float		ltime;
+	
+	if (!avelocities[0][0])
+	{
+		for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
+			avelocities[0][i] = (rand()&255) * 0.01;
+	}
+
+
+	ltime = (float)cl.time / 1000.0;
+	for (i=0 ; i<NUMVERTEXNORMALS ; i++)
+	{
+		angle = ltime * avelocities[i][0];
+		sy = sin(angle);
+		cy = cos(angle);
+		angle = ltime * avelocities[i][1];
+		sp = sin(angle);
+		cp = cos(angle);
+		/*
+		angle = ltime * avelocities[i][2];
+		sr = sin(angle);
+		cr = cos(angle);
+		*/
+	
+		forward[0] = cp*cy;
+		forward[1] = cp*sy;
+		forward[2] = -sp;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+
+		dist = sin(ltime + i)*64;
+		p->org[0] = ent->origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
+		p->org[1] = ent->origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
+		p->org[2] = ent->origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
+
+		VectorClear (p->vel);
+		VectorClear (p->accel);
+
+		VectorSubtract (p->org, ent->origin, v);
+		dist = VectorLength(v) / 90.0;
+		p->color = floor (0xd0 + dist * 7);
+		p->colorvel = 0;
+
+		p->alpha = 1.0 - dist;
+		p->alphavel = -100;
+	}
+}
+
+
+/*
+===============
+CL_TrapParticles
+===============
+*/
+// RAFAEL
+void CL_TrapParticles (entity_t *ent)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	vec3_t		start, end;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+
+	ent->origin[2]-=14;
+	VectorCopy (ent->origin, start);
+	VectorCopy (ent->origin, end);
+	end[2]+=64;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	// FIXME: this is a really silly way to have a loop
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.3+qfrand()*0.2);
+		p->color = 0xe0;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand();
+			p->vel[j] = crand()*15;
+			p->accel[j] = 0;
+		}
+		p->accel[2] = PARTICLE_GRAVITY;
+
+		VectorAdd (move, vec, move);
+	}
+
+	{
+
+	
+	int			i, j, k;
+	cparticle_t	*p;
+	float		vel;
+	vec3_t		dir;
+	vec3_t		org;
+
+	
+	ent->origin[2]+=14;
+	VectorCopy (ent->origin, org);
+
+
+	for (i=-2 ; i<=2 ; i+=4)
+		for (j=-2 ; j<=2 ; j+=4)
+			for (k=-2 ; k<=4 ; k+=4)
+			{
+				if (!free_particles)
+					return;
+				p = free_particles;
+				free_particles = p->next;
+				p->next = active_particles;
+				active_particles = p;
+
+				p->time = cl.time;
+				p->color = 0xe0 + (rand()&3);
+
+				p->alpha = 1.0;
+				p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
+				
+				p->org[0] = org[0] + i + ((rand()&23) * crand());
+				p->org[1] = org[1] + j + ((rand()&23) * crand());
+				p->org[2] = org[2] + k + ((rand()&23) * crand());
+	
+				dir[0] = j * 8;
+				dir[1] = i * 8;
+				dir[2] = k * 8;
+	
+				VectorNormalize (dir);						
+				vel = 50 + rand()&63;
+				VectorScale (dir, vel, p->vel);
+
+				p->accel[0] = p->accel[1] = 0;
+				p->accel[2] = -PARTICLE_GRAVITY;
+			}
+	}
+}
+
+
+/*
+===============
+CL_BFGExplosionParticles
+===============
+*/
+//FIXME combined with CL_ExplosionParticles
+void CL_BFGExplosionParticles (vec3_t org)
+{
+	int			i, j;
+	cparticle_t	*p;
+
+	for (i=0 ; i<256 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = 0xd0 + (rand()&7);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()%32)-16);
+			p->vel[j] = (rand()%384)-192;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_TeleportParticles
+
+===============
+*/
+void CL_TeleportParticles (vec3_t org)
+{
+	int			i, j, k;
+	cparticle_t	*p;
+	float		vel;
+	vec3_t		dir;
+
+	for (i=-16 ; i<=16 ; i+=4)
+		for (j=-16 ; j<=16 ; j+=4)
+			for (k=-16 ; k<=32 ; k+=4)
+			{
+				if (!free_particles)
+					return;
+				p = free_particles;
+				free_particles = p->next;
+				p->next = active_particles;
+				active_particles = p;
+
+				p->time = cl.time;
+				p->color = 7 + (rand()&7);
+
+				p->alpha = 1.0;
+				p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
+				
+				p->org[0] = org[0] + i + (rand()&3);
+				p->org[1] = org[1] + j + (rand()&3);
+				p->org[2] = org[2] + k + (rand()&3);
+	
+				dir[0] = j*8;
+				dir[1] = i*8;
+				dir[2] = k*8;
+	
+				VectorNormalize (dir);						
+				vel = 50 + (rand()&63);
+				VectorScale (dir, vel, p->vel);
+
+				p->accel[0] = p->accel[1] = 0;
+				p->accel[2] = -PARTICLE_GRAVITY;
+			}
+}
+
+
+/*
+===============
+CL_AddParticles
+===============
+*/
+void CL_AddParticles (void)
+{
+	cparticle_t		*p, *next;
+	float			alpha;
+	float			time = 0, time2;
+	vec3_t			org;
+	int				color;
+	cparticle_t		*active, *tail;
+
+	active = NULL;
+	tail = NULL;
+
+	for (p=active_particles ; p ; p=next)
+	{
+		next = p->next;
+
+		// PMM - added INSTANT_PARTICLE handling for heat beam
+		if (p->alphavel != INSTANT_PARTICLE)
+		{
+			time = (cl.time - p->time)*0.001;
+			alpha = p->alpha + time*p->alphavel;
+			if (alpha <= 0)
+			{	// faded out
+				p->next = free_particles;
+				free_particles = p;
+				continue;
+			}
+		}
+		else
+		{
+			alpha = p->alpha;
+		}
+
+		p->next = NULL;
+		if (!tail)
+			active = tail = p;
+		else
+		{
+			tail->next = p;
+			tail = p;
+		}
+
+		if (alpha > 1.0)
+			alpha = 1;
+		color = p->color;
+
+		time2 = time*time;
+
+		org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
+		org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
+		org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
+
+		V_AddParticle (org, color, alpha);
+		// PMM
+		if (p->alphavel == INSTANT_PARTICLE)
+		{
+			p->alphavel = 0.0;
+			p->alpha = 0.0;
+		}
+	}
+
+	active_particles = active;
+}
+
+
+/*
+==============
+CL_EntityEvent
+
+An entity has just been parsed that has an event value
+
+the female events are there for backwards compatability
+==============
+*/
+struct sfx_t *cl_sfx_footsteps[4];
+
+void CL_EntityEvent (entity_state_t *ent)
+{
+	switch (ent->event)
+	{
+	case EV_ITEM_RESPAWN:
+		S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("items/respawn1.wav"), 1, ATTN_IDLE, 0);
+		CL_ItemRespawnParticles (ent->origin);
+		break;
+	case EV_PLAYER_TELEPORT:
+		S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("misc/tele1.wav"), 1, ATTN_IDLE, 0);
+		CL_TeleportParticles (ent->origin);
+		break;
+	case EV_FOOTSTEP:
+		if (cl_footsteps->value)
+			S_StartSound (NULL, ent->number, CHAN_BODY, cl_sfx_footsteps[rand()&3], 1, ATTN_NORM, 0);
+		break;
+	case EV_FALLSHORT:
+		S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("player/land1.wav"), 1, ATTN_NORM, 0);
+		break;
+	case EV_FALL:
+		S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall2.wav"), 1, ATTN_NORM, 0);
+		break;
+	case EV_FALLFAR:
+		S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall1.wav"), 1, ATTN_NORM, 0);
+		break;
+	}
+}
+
+
+/*
+==============
+CL_ClearEffects
+
+==============
+*/
+void CL_ClearEffects (void)
+{
+	CL_ClearParticles ();
+	CL_ClearDlights ();
+	CL_ClearLightStyles ();
+}
--- /dev/null
+++ b/cl_input.c
@@ -1,0 +1,526 @@
+// cl.input.c  -- builds an intended movement command to send to the server
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+cvar_t	*cl_nodelta;
+
+unsigned	frame_msec;
+unsigned	old_sys_frame_time;
+
+/*
+===============================================================================
+
+KEY BUTTONS
+
+Continuous button event tracking is complicated by the fact that two different
+input sources (say, mouse button 1 and the control key) can both press the
+same button, but the button should only be released when both of the
+pressing key have been released.
+
+When a key event issues a button command (+forward, +attack, etc), it appends
+its key number as a parameter to the command so it can be matched up with
+the release.
+
+state bit 0 is the current state of the key
+state bit 1 is edge triggered on the up to down transition
+state bit 2 is edge triggered on the down to up transition
+
+
+Key_Event (int key, qboolean down, unsigned time);
+
+  +mlook src time
+
+===============================================================================
+*/
+
+
+kbutton_t	in_klook;
+kbutton_t	in_left, in_right, in_forward, in_back;
+kbutton_t	in_lookup, in_lookdown, in_moveleft, in_moveright;
+kbutton_t	in_strafe, in_speed, in_use, in_attack;
+kbutton_t	in_up, in_down;
+
+int			in_impulse;
+
+
+void KeyDown (kbutton_t *b)
+{
+	int		k;
+	char	*c;
+	
+	c = Cmd_Argv(1);
+	if (c[0])
+		k = atoi(c);
+	else
+		k = -1;		// typed manually at the console for continuous down
+
+	if (k == b->down[0] || k == b->down[1])
+		return;		// repeating key
+	
+	if (!b->down[0])
+		b->down[0] = k;
+	else if (!b->down[1])
+		b->down[1] = k;
+	else
+	{
+		Com_Printf ("Three keys down for a button!\n");
+		return;
+	}
+	
+	if (b->state & 1)
+		return;		// still down
+
+	// save timestamp
+	c = Cmd_Argv(2);
+	b->downtime = atoi(c);
+	if (!b->downtime)
+		b->downtime = sys_frame_time - 100;
+
+	b->state |= 1 + 2;	// down + impulse down
+}
+
+void KeyUp (kbutton_t *b)
+{
+	int		k;
+	char	*c;
+	unsigned	uptime;
+
+	c = Cmd_Argv(1);
+	if (c[0])
+		k = atoi(c);
+	else
+	{ // typed manually at the console, assume for unsticking, so clear all
+		b->down[0] = b->down[1] = 0;
+		b->state = 4;	// impulse up
+		return;
+	}
+
+	if (b->down[0] == k)
+		b->down[0] = 0;
+	else if (b->down[1] == k)
+		b->down[1] = 0;
+	else
+		return;		// key up without coresponding down (menu pass through)
+	if (b->down[0] || b->down[1])
+		return;		// some other key is still holding it down
+
+	if (!(b->state & 1))
+		return;		// still up (this should not happen)
+
+	// save timestamp
+	c = Cmd_Argv(2);
+	uptime = atoi(c);
+	if (uptime)
+		b->msec += uptime - b->downtime;
+	else
+		b->msec += 10;
+
+	b->state &= ~1;		// now up
+	b->state |= 4; 		// impulse up
+}
+
+void IN_KLookDown (void) {KeyDown(&in_klook);}
+void IN_KLookUp (void) {KeyUp(&in_klook);}
+void IN_UpDown(void) {KeyDown(&in_up);}
+void IN_UpUp(void) {KeyUp(&in_up);}
+void IN_DownDown(void) {KeyDown(&in_down);}
+void IN_DownUp(void) {KeyUp(&in_down);}
+void IN_LeftDown(void) {KeyDown(&in_left);}
+void IN_LeftUp(void) {KeyUp(&in_left);}
+void IN_RightDown(void) {KeyDown(&in_right);}
+void IN_RightUp(void) {KeyUp(&in_right);}
+void IN_ForwardDown(void) {KeyDown(&in_forward);}
+void IN_ForwardUp(void) {KeyUp(&in_forward);}
+void IN_BackDown(void) {KeyDown(&in_back);}
+void IN_BackUp(void) {KeyUp(&in_back);}
+void IN_LookupDown(void) {KeyDown(&in_lookup);}
+void IN_LookupUp(void) {KeyUp(&in_lookup);}
+void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
+void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
+void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
+void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
+void IN_MoverightDown(void) {KeyDown(&in_moveright);}
+void IN_MoverightUp(void) {KeyUp(&in_moveright);}
+
+void IN_SpeedDown(void) {KeyDown(&in_speed);}
+void IN_SpeedUp(void) {KeyUp(&in_speed);}
+void IN_StrafeDown(void) {KeyDown(&in_strafe);}
+void IN_StrafeUp(void) {KeyUp(&in_strafe);}
+
+void IN_AttackDown(void) {KeyDown(&in_attack);}
+void IN_AttackUp(void) {KeyUp(&in_attack);}
+
+void IN_UseDown (void) {KeyDown(&in_use);}
+void IN_UseUp (void) {KeyUp(&in_use);}
+
+void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
+
+/*
+===============
+CL_KeyState
+
+Returns the fraction of the frame that the key was down
+===============
+*/
+float CL_KeyState (kbutton_t *key)
+{
+	float		val;
+	int			msec;
+
+	key->state &= 1;		// clear impulses
+
+	msec = key->msec;
+	key->msec = 0;
+
+	if (key->state)
+	{	// still down
+		msec += sys_frame_time - key->downtime;
+		key->downtime = sys_frame_time;
+	}
+
+/*
+	if (msec)
+	{
+		Com_Printf ("%i ", msec);
+	}
+*/
+
+	val = (float)msec / frame_msec;
+	if (val < 0)
+		val = 0;
+	if (val > 1)
+		val = 1;
+
+	return val;
+}
+
+
+
+
+//==========================================================================
+
+cvar_t	*cl_upspeed;
+cvar_t	*cl_forwardspeed;
+cvar_t	*cl_sidespeed;
+
+cvar_t	*cl_yawspeed;
+cvar_t	*cl_pitchspeed;
+
+cvar_t	*cl_run;
+
+cvar_t	*cl_anglespeedkey;
+
+
+/*
+================
+CL_AdjustAngles
+
+Moves the local angle positions
+================
+*/
+void CL_AdjustAngles (void)
+{
+	float	speed;
+	float	up, down;
+	
+	if (in_speed.state & 1)
+		speed = cls.frametime * cl_anglespeedkey->value;
+	else
+		speed = cls.frametime;
+
+	if (!(in_strafe.state & 1))
+	{
+		cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
+		cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
+	}
+	if (in_klook.state & 1)
+	{
+		cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward);
+		cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back);
+	}
+	
+	up = CL_KeyState (&in_lookup);
+	down = CL_KeyState(&in_lookdown);
+	
+	cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * up;
+	cl.viewangles[PITCH] += speed*cl_pitchspeed->value * down;
+}
+
+/*
+================
+CL_BaseMove
+
+Send the intended movement message to the server
+================
+*/
+void CL_BaseMove (usercmd_t *cmd)
+{	
+	CL_AdjustAngles ();
+	
+	memset (cmd, 0, sizeof(*cmd));
+	
+	VectorCopy (cl.viewangles, cmd->angles);
+	if (in_strafe.state & 1)
+	{
+		cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right);
+		cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left);
+	}
+
+	cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright);
+	cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft);
+
+	cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up);
+	cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down);
+
+	if (! (in_klook.state & 1) )
+	{	
+		cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward);
+		cmd->forwardmove -= cl_forwardspeed->value * CL_KeyState (&in_back);
+	}	
+
+//
+// adjust for speed key / running
+//
+	if ( (in_speed.state & 1) ^ (int)(cl_run->value) )
+	{
+		cmd->forwardmove *= 2;
+		cmd->sidemove *= 2;
+		cmd->upmove *= 2;
+	}	
+}
+
+void CL_ClampPitch (void)
+{
+	float	pitch;
+
+	pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
+	if (pitch > 180)
+		pitch -= 360;
+	if (cl.viewangles[PITCH] + pitch > 89)
+		cl.viewangles[PITCH] = 89 - pitch;
+	if (cl.viewangles[PITCH] + pitch < -89)
+		cl.viewangles[PITCH] = -89 - pitch;
+}
+
+/*
+==============
+CL_FinishMove
+==============
+*/
+void CL_FinishMove (usercmd_t *cmd)
+{
+	int		ms;
+	int		i;
+
+//
+// figure button bits
+//	
+	if ( in_attack.state & 3 )
+		cmd->buttons |= BUTTON_ATTACK;
+	in_attack.state &= ~2;
+	
+	if (in_use.state & 3)
+		cmd->buttons |= BUTTON_USE;
+	in_use.state &= ~2;
+
+	if (anykeydown && cls.key_dest == key_game)
+		cmd->buttons |= BUTTON_ANY;
+
+	// send milliseconds of time to apply the move
+	ms = cls.frametime * 1000;
+	if (ms > 250)
+		ms = 100;		// time was unreasonable
+	cmd->msec = ms;
+
+	CL_ClampPitch ();
+	for (i=0 ; i<3 ; i++)
+		cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
+
+	cmd->impulse = in_impulse;
+	in_impulse = 0;
+
+// send the ambient light level at the player's current position
+	cmd->lightlevel = (byte)cl_lightlevel->value;
+}
+
+/*
+=================
+CL_CreateCmd
+=================
+*/
+usercmd_t CL_CreateCmd (void)
+{
+	usercmd_t	cmd;
+
+	frame_msec = sys_frame_time - old_sys_frame_time;
+	if (frame_msec < 1)
+		frame_msec = 1;
+	if (frame_msec > 200)
+		frame_msec = 200;
+	
+	// get basic movement from keyboard
+	CL_BaseMove (&cmd);
+
+	// allow mice or other external controllers to add to the move
+	IN_Move (&cmd);
+
+	CL_FinishMove (&cmd);
+
+	old_sys_frame_time = sys_frame_time;
+
+//cmd.impulse = cls.framecount;
+
+	return cmd;
+}
+
+
+void IN_CenterView (void)
+{
+	cl.viewangles[PITCH] = -SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
+}
+
+/*
+============
+CL_InitInput
+============
+*/
+void CL_InitInput (void)
+{
+	Cmd_AddCommand ("centerview",IN_CenterView);
+
+	Cmd_AddCommand ("+moveup",IN_UpDown);
+	Cmd_AddCommand ("-moveup",IN_UpUp);
+	Cmd_AddCommand ("+movedown",IN_DownDown);
+	Cmd_AddCommand ("-movedown",IN_DownUp);
+	Cmd_AddCommand ("+left",IN_LeftDown);
+	Cmd_AddCommand ("-left",IN_LeftUp);
+	Cmd_AddCommand ("+right",IN_RightDown);
+	Cmd_AddCommand ("-right",IN_RightUp);
+	Cmd_AddCommand ("+forward",IN_ForwardDown);
+	Cmd_AddCommand ("-forward",IN_ForwardUp);
+	Cmd_AddCommand ("+back",IN_BackDown);
+	Cmd_AddCommand ("-back",IN_BackUp);
+	Cmd_AddCommand ("+lookup", IN_LookupDown);
+	Cmd_AddCommand ("-lookup", IN_LookupUp);
+	Cmd_AddCommand ("+lookdown", IN_LookdownDown);
+	Cmd_AddCommand ("-lookdown", IN_LookdownUp);
+	Cmd_AddCommand ("+strafe", IN_StrafeDown);
+	Cmd_AddCommand ("-strafe", IN_StrafeUp);
+	Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
+	Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
+	Cmd_AddCommand ("+moveright", IN_MoverightDown);
+	Cmd_AddCommand ("-moveright", IN_MoverightUp);
+	Cmd_AddCommand ("+speed", IN_SpeedDown);
+	Cmd_AddCommand ("-speed", IN_SpeedUp);
+	Cmd_AddCommand ("+attack", IN_AttackDown);
+	Cmd_AddCommand ("-attack", IN_AttackUp);
+	Cmd_AddCommand ("+use", IN_UseDown);
+	Cmd_AddCommand ("-use", IN_UseUp);
+	Cmd_AddCommand ("impulse", IN_Impulse);
+	Cmd_AddCommand ("+klook", IN_KLookDown);
+	Cmd_AddCommand ("-klook", IN_KLookUp);
+
+	cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
+}
+
+
+
+/*
+=================
+CL_SendCmd
+=================
+*/
+void CL_SendCmd (void)
+{
+	sizebuf_t	buf;
+	byte		data[128];
+	int			i;
+	usercmd_t	*cmd, *oldcmd;
+	usercmd_t	nullcmd;
+	int			checksumIndex;
+
+	// build a command even if not connected
+
+	// save this command off for prediction
+	i = cls.netchan.outgoing_sequence & (CMD_BACKUP-1);
+	cmd = &cl.cmds[i];
+	cl.cmd_time[i] = cls.realtime;	// for netgraph ping calculation
+
+	*cmd = CL_CreateCmd ();
+
+	cl.cmd = *cmd;
+
+	if (cls.state == ca_disconnected || cls.state == ca_connecting)
+		return;
+
+	if ( cls.state == ca_connected)
+	{
+		if (cls.netchan.message.cursize	|| curtime - cls.netchan.last_sent > 1000 )
+			Netchan_Transmit (&cls.netchan, 0, buf.data);	
+		return;
+	}
+
+	// send a userinfo update if needed
+	if (userinfo_modified)
+	{
+		CL_FixUpGender();
+		userinfo_modified = false;
+		MSG_WriteByte (&cls.netchan.message, clc_userinfo);
+		MSG_WriteString (&cls.netchan.message, Cvar_Userinfo() );
+	}
+
+	SZ_Init (&buf, data, sizeof(data));
+
+	if (cmd->buttons && cl.cinematictime > 0 && !cl.attractloop 
+		&& cls.realtime - cl.cinematictime > 1000)
+	{	// skip the rest of the cinematic
+		SCR_FinishCinematic ();
+	}
+
+	// begin a client move command
+	MSG_WriteByte (&buf, clc_move);
+
+	// save the position for a checksum byte
+	checksumIndex = buf.cursize;
+	MSG_WriteByte (&buf, 0);
+
+	// let the server know what the last frame we
+	// got was, so the next message can be delta compressed
+	if (cl_nodelta->value || !cl.frame.valid || cls.demowaiting)
+		MSG_WriteLong (&buf, -1);	// no compression
+	else
+		MSG_WriteLong (&buf, cl.frame.serverframe);
+
+	// send this and the previous cmds in the message, so
+	// if the last packet was dropped, it can be recovered
+	i = (cls.netchan.outgoing_sequence-2) & (CMD_BACKUP-1);
+	cmd = &cl.cmds[i];
+	memset (&nullcmd, 0, sizeof(nullcmd));
+	MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd);
+	oldcmd = cmd;
+
+	i = (cls.netchan.outgoing_sequence-1) & (CMD_BACKUP-1);
+	cmd = &cl.cmds[i];
+	MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
+	oldcmd = cmd;
+
+	i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP-1);
+	cmd = &cl.cmds[i];
+	MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
+
+	// calculate a checksum over the move commands
+	buf.data[checksumIndex] = COM_BlockSequenceCRCByte(
+		buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,
+		cls.netchan.outgoing_sequence);
+
+	//
+	// deliver the message
+	//
+	Netchan_Transmit (&cls.netchan, buf.cursize, buf.data);	
+}
+
+
--- /dev/null
+++ b/cl_inv.c
@@ -1,0 +1,127 @@
+// cl_inv.c -- client inventory screen
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+================
+CL_ParseInventory
+================
+*/
+void CL_ParseInventory (void)
+{
+	int		i;
+
+	for (i=0 ; i<MAX_ITEMS ; i++)
+		cl.inventory[i] = MSG_ReadShort (&net_message);
+}
+
+
+/*
+================
+Inv_DrawString
+================
+*/
+void Inv_DrawString (int x, int y, char *string)
+{
+	while (*string)
+	{
+		re.DrawChar (x, y, *string);
+		x+=8;
+		string++;
+	}
+}
+
+void SetStringHighBit (char *s)
+{
+	while (*s)
+		*s++ |= 128;
+}
+
+/*
+================
+CL_DrawInventory
+================
+*/
+#define	DISPLAY_ITEMS	17
+
+void CL_DrawInventory (void)
+{
+	int		i, j;
+	int		num, selected_num, item;
+	int		index[MAX_ITEMS];
+	char	string[1024];
+	int		x, y;
+	char	binding[1024];
+	char	*bind;
+	int		selected;
+	int		top;
+
+	selected = cl.frame.playerstate.stats[STAT_SELECTED_ITEM];
+
+	num = 0;
+	selected_num = 0;
+	for (i=0 ; i<MAX_ITEMS ; i++)
+	{
+		if (i==selected)
+			selected_num = num;
+		if (cl.inventory[i])
+		{
+			index[num] = i;
+			num++;
+		}
+	}
+
+	// determine scroll point
+	top = selected_num - DISPLAY_ITEMS/2;
+	if (num - top < DISPLAY_ITEMS)
+		top = num - DISPLAY_ITEMS;
+	if (top < 0)
+		top = 0;
+
+	x = (vid.width-256)/2;
+	y = (vid.height-240)/2;
+
+	// repaint everything next frame
+	SCR_DirtyScreen ();
+
+	re.DrawPic (x, y+8, "inventory");
+
+	y += 24;
+	x += 24;
+	Inv_DrawString (x, y, "hotkey ### item");
+	Inv_DrawString (x, y+8, "------ --- ----");
+	y += 16;
+	for (i=top ; i<num && i < top+DISPLAY_ITEMS ; i++)
+	{
+		item = index[i];
+		// search for a binding
+		Com_sprintf (binding, sizeof(binding), "use %s", cl.configstrings[CS_ITEMS+item]);
+		bind = "";
+		for (j=0 ; j<256 ; j++)
+			if (keybindings[j] && !cistrcmp (keybindings[j], binding))
+			{
+				bind = Key_KeynumToString(j);
+				break;
+			}
+
+		Com_sprintf (string, sizeof(string), "%6s %3i %s", bind, cl.inventory[item],
+			cl.configstrings[CS_ITEMS+item] );
+		if (item != selected)
+			SetStringHighBit (string);
+		else	// draw a blinky cursor by the selected item
+		{
+			if ( (int)(cls.realtime*10) & 1)
+				re.DrawChar (x-8, y, 15);
+		}
+		Inv_DrawString (x, y, string);
+		y += 8;
+	}
+
+
+}
+
+
--- /dev/null
+++ b/cl_main.c
@@ -1,0 +1,1773 @@
+// cl_main.c  -- client main loop
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+cvar_t	*adr0;
+cvar_t	*adr1;
+cvar_t	*adr2;
+cvar_t	*adr3;
+cvar_t	*adr4;
+cvar_t	*adr5;
+cvar_t	*adr6;
+cvar_t	*adr7;
+cvar_t	*adr8;
+
+cvar_t	*cl_stereo_separation;
+cvar_t	*cl_stereo;
+
+cvar_t	*rcon_client_password;
+cvar_t	*rcon_address;
+
+cvar_t	*cl_noskins;
+cvar_t	*cl_autoskins;
+cvar_t	*cl_footsteps;
+cvar_t	*cl_timeout;
+cvar_t	*cl_predict;
+//cvar_t	*cl_minfps;
+cvar_t	*cl_maxfps;
+cvar_t	*cl_gun;
+
+cvar_t	*cl_add_particles;
+cvar_t	*cl_add_lights;
+cvar_t	*cl_add_entities;
+cvar_t	*cl_add_blend;
+
+cvar_t	*cl_shownet;
+cvar_t	*cl_showmiss;
+cvar_t	*cl_showclamp;
+
+cvar_t	*cl_paused;
+cvar_t	*cl_timedemo;
+
+cvar_t	*cl_lightlevel;
+
+//
+// userinfo
+//
+cvar_t	*info_password;
+cvar_t	*info_spectator;
+cvar_t	*name;
+cvar_t	*skin;
+cvar_t	*rate;
+cvar_t	*fov;
+cvar_t	*msg;
+cvar_t	*hand;
+cvar_t	*gender;
+cvar_t	*gender_auto;
+
+cvar_t	*cl_vwep;
+
+client_static_t	cls;
+client_state_t	cl;
+
+centity_t		cl_entities[MAX_EDICTS];
+
+entity_state_t	cl_parse_entities[MAX_PARSE_ENTITIES];
+
+extern	cvar_t *allow_download;
+extern	cvar_t *allow_download_players;
+extern	cvar_t *allow_download_models;
+extern	cvar_t *allow_download_sounds;
+extern	cvar_t *allow_download_maps;
+
+//======================================================================
+
+
+/*
+====================
+CL_WriteDemoMessage
+
+Dumps the current net message, prefixed by the length
+====================
+*/
+void CL_WriteDemoMessage (void)
+{
+	int		len, swlen;
+
+	// the first eight bytes are just packet sequencing stuff
+	len = net_message.cursize-8;
+	swlen = LittleLong(len);
+	fwrite (&swlen, 4, 1, cls.demofile);
+	fwrite (net_message.data+8,	len, 1, cls.demofile);
+}
+
+
+/*
+====================
+CL_Stop_f
+
+stop recording a demo
+====================
+*/
+void CL_Stop_f (void)
+{
+	int		len;
+
+	if (!cls.demorecording)
+	{
+		Com_Printf ("Not recording a demo.\n");
+		return;
+	}
+
+// finish up
+	len = -1;
+	fwrite (&len, 4, 1, cls.demofile);
+	fclose (cls.demofile);
+	cls.demofile = NULL;
+	cls.demorecording = false;
+	Com_Printf ("Stopped demo.\n");
+}
+
+/*
+====================
+CL_Record_f
+
+record <demoname>
+
+Begins recording a demo from the current position
+====================
+*/
+void CL_Record_f (void)
+{
+	char	name[MAX_OSPATH];
+	char	buf_data[MAX_MSGLEN];
+	sizebuf_t	buf;
+	int		i;
+	int		len;
+	entity_state_t	*ent;
+	entity_state_t	nullstate;
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("record <demoname>\n");
+		return;
+	}
+
+	if (cls.demorecording)
+	{
+		Com_Printf ("Already recording.\n");
+		return;
+	}
+
+	if (cls.state != ca_active)
+	{
+		Com_Printf ("You must be in a level to record.\n");
+		return;
+	}
+
+	//
+	// open the demo file
+	//
+	Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
+
+	Com_Printf ("recording to %s.\n", name);
+	FS_CreatePath (name);
+	cls.demofile = fopen (name, "wb");
+	if (!cls.demofile)
+	{
+		Com_Printf ("ERROR: couldn't open.\n");
+		return;
+	}
+	cls.demorecording = true;
+
+	// don't start saving messages until a non-delta compressed message is received
+	cls.demowaiting = true;
+
+	//
+	// write out messages to hold the startup information
+	//
+	SZ_Init (&buf, (uchar *)buf_data, sizeof(buf_data));
+
+	// send the serverdata
+	MSG_WriteByte (&buf, svc_serverdata);
+	MSG_WriteLong (&buf, PROTOCOL_VERSION);
+	MSG_WriteLong (&buf, 0x10000 + cl.servercount);
+	MSG_WriteByte (&buf, 1);	// demos are always attract loops
+	MSG_WriteString (&buf, cl.gamedir);
+	MSG_WriteShort (&buf, cl.playernum);
+
+	MSG_WriteString (&buf, cl.configstrings[CS_NAME]);
+
+	// configstrings
+	for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
+	{
+		if (cl.configstrings[i][0])
+		{
+			if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
+			{	// write it out
+				len = LittleLong (buf.cursize);
+				fwrite (&len, 4, 1, cls.demofile);
+				fwrite (buf.data, buf.cursize, 1, cls.demofile);
+				buf.cursize = 0;
+			}
+
+			MSG_WriteByte (&buf, svc_configstring);
+			MSG_WriteShort (&buf, i);
+			MSG_WriteString (&buf, cl.configstrings[i]);
+		}
+
+	}
+
+	// baselines
+	memset (&nullstate, 0, sizeof(nullstate));
+	for (i=0; i<MAX_EDICTS ; i++)
+	{
+		ent = &cl_entities[i].baseline;
+		if (!ent->modelindex)
+			continue;
+
+		if (buf.cursize + 64 > buf.maxsize)
+		{	// write it out
+			len = LittleLong (buf.cursize);
+			fwrite (&len, 4, 1, cls.demofile);
+			fwrite (buf.data, buf.cursize, 1, cls.demofile);
+			buf.cursize = 0;
+		}
+
+		MSG_WriteByte (&buf, svc_spawnbaseline);		
+		MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
+	}
+
+	MSG_WriteByte (&buf, svc_stufftext);
+	MSG_WriteString (&buf, "precache\n");
+
+	// write it to the demo file
+
+	len = LittleLong (buf.cursize);
+	fwrite (&len, 4, 1, cls.demofile);
+	fwrite (buf.data, buf.cursize, 1, cls.demofile);
+
+	// the rest of the demo file will be individual frames
+}
+
+/* adds the current command line as a clc_stringcmd to the client message.
+ * things like godmode, noclip, etc, are commands directed to the server, so
+ * when they are typed in at the console, they will need to be forwarded. */
+void Cmd_ForwardToServer (void)
+{
+	char *cmd;
+
+	cmd = Cmd_Argv(0);
+	if(cls.state <= ca_connected || *cmd == '-' || *cmd == '+'){
+		Com_Printf("Unknown command \"%s\"\n", cmd);
+		return;
+	}
+
+	MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
+	SZ_Print(&cls.netchan.message, cmd);
+	if(Cmd_Argc() > 1){
+		SZ_Print(&cls.netchan.message, " ");
+		SZ_Print(&cls.netchan.message, Cmd_Args());
+	}
+}
+
+void
+CL_Setenv_f(void)
+{
+	int i, l = 0, argc;
+	char name[1024], val[1024], *env;
+
+	argc = Cmd_Argc();
+
+	if(argc > 2){
+		strncpy(name, Cmd_Argv(1), sizeof name);
+		for(i = 2; i < argc; i++){
+			strncpy(val+l, Cmd_Argv(i), sizeof(name) - l - 2);
+			val[sizeof(val)-2] = 0;
+			strcat(val, " ");
+			l = strlen(val);
+		}
+		putenv(name, val);
+	}else if(argc == 2){
+		env = getenv(Cmd_Argv(1));
+		if(env){
+			Com_Printf("%s=%s\n", Cmd_Argv(1), env);
+			free(env);
+		}else
+			Com_Printf("%s undefined\n", Cmd_Argv(1), env);
+	}
+}
+
+void
+CL_ForwardToServer_f(void)
+{
+	if(cls.state != ca_connected && cls.state != ca_active){
+		Com_Printf("Can't \"%s\", not connected\n", Cmd_Argv(0));
+		return;
+	}
+	/* don't forward the first argument */
+	if(Cmd_Argc() > 1){
+		MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
+		SZ_Print(&cls.netchan.message, Cmd_Args());
+	}
+}
+
+
+/*
+==================
+CL_Pause_f
+==================
+*/
+void CL_Pause_f (void)
+{
+	// never pause in multiplayer
+	if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
+	{
+		Cvar_SetValue ("paused", 0);
+		return;
+	}
+
+	Cvar_SetValue ("paused", !cl_paused->value);
+}
+
+/*
+==================
+CL_Quit_f
+==================
+*/
+void CL_Quit_f (void)
+{
+	CL_Disconnect ();
+	Com_Quit ();
+}
+
+/*
+================
+CL_Drop
+
+Called after an ERR_DROP was thrown
+================
+*/
+void CL_Drop (void)
+{
+	if (cls.state == ca_uninitialized)
+		return;
+	if (cls.state == ca_disconnected)
+		return;
+
+	CL_Disconnect ();
+
+	// drop loading plaque unless this is the initial game start
+	if (cls.disable_servercount != -1)
+		SCR_EndLoadingPlaque ();	// get rid of loading plaque
+}
+
+
+/*
+=======================
+CL_SendConnectPacket
+
+We have gotten a challenge from the server, so try and
+connect.
+======================
+*/
+void CL_SendConnectPacket (void)
+{
+	netadr_t	adr;
+	int		port;
+
+	if (!NET_StringToAdr (cls.servername, &adr))
+	{
+		Com_Printf ("Bad server address\n");
+		cls.connect_time = 0;
+		return;
+	}
+	if (adr.port == 0)
+		adr.port = BigShort (PORT_SERVER);
+
+	port = Cvar_VariableValue ("qport");
+	userinfo_modified = false;
+
+	Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n",
+		PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );
+}
+
+/*
+=================
+CL_CheckForResend
+
+Resend a connect message if the last one has timed out
+=================
+*/
+void CL_CheckForResend (void)
+{
+	netadr_t	adr;
+
+	// if the local server is running and we aren't
+	// then connect
+	if (cls.state == ca_disconnected && Com_ServerState() )
+	{
+		cls.state = ca_connecting;
+		strncpy (cls.servername, "localhost", sizeof(cls.servername)-1);
+		// we don't need a challenge on the localhost
+		CL_SendConnectPacket ();
+		return;
+//		cls.connect_time = -99999;	// CL_CheckForResend() will fire immediately
+	}
+
+	// resend if we haven't gotten a reply yet
+	if (cls.state != ca_connecting)
+		return;
+
+	if (cls.realtime - cls.connect_time < 3000)
+		return;
+
+	if (!NET_StringToAdr (cls.servername, &adr))
+	{
+		Com_Printf ("Bad server address\n");
+		cls.state = ca_disconnected;
+		return;
+	}
+	if (adr.port == 0)
+		adr.port = BigShort (PORT_SERVER);
+
+	cls.connect_time = cls.realtime;	// for retransmit requests
+
+	Com_Printf ("Connecting to %s...\n", cls.servername);
+
+	Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
+}
+
+
+/*
+================
+CL_Connect_f
+
+================
+*/
+void CL_Connect_f (void)
+{
+	char	*server;
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("usage: connect <server>\n");
+		return;	
+	}
+	
+	if (Com_ServerState ())
+	{	// if running a local server, kill it and reissue
+		SV_Shutdown (va("Server quit\n", msg), false);
+	}
+	else
+	{
+		CL_Disconnect ();
+	}
+
+	server = Cmd_Argv (1);
+
+	NET_Config (true);		// allow remote
+
+	CL_Disconnect ();
+
+	cls.state = ca_connecting;
+	strncpy (cls.servername, server, sizeof(cls.servername)-1);
+	cls.connect_time = -99999;	// CL_CheckForResend() will fire immediately
+}
+
+
+/*
+=====================
+CL_Rcon_f
+
+  Send the rest of the command line over as
+  an unconnected command.
+=====================
+*/
+void CL_Rcon_f (void)
+{
+	char	message[1024];
+	int		i;
+	netadr_t	to;
+
+	if (!rcon_client_password->string)
+	{
+		Com_Printf ("You must set 'rcon_password' before\n"
+					"issuing an rcon command.\n");
+		return;
+	}
+
+	message[0] = (char)255;
+	message[1] = (char)255;
+	message[2] = (char)255;
+	message[3] = (char)255;
+	message[4] = 0;
+
+	NET_Config (true);		// allow remote
+
+	strcat (message, "rcon ");
+
+	strcat (message, rcon_client_password->string);
+	strcat (message, " ");
+
+	for (i=1 ; i<Cmd_Argc() ; i++)
+	{
+		strcat (message, Cmd_Argv(i));
+		strcat (message, " ");
+	}
+
+	if (cls.state >= ca_connected)
+		to = cls.netchan.remote_address;
+	else
+	{
+		if (!strlen(rcon_address->string))
+		{
+			Com_Printf ("You must either be connected,\n"
+						"or set the 'rcon_address' cvar\n"
+						"to issue rcon commands\n");
+
+			return;
+		}
+		NET_StringToAdr (rcon_address->string, &to);
+		if (to.port == 0)
+			to.port = BigShort (PORT_SERVER);
+	}
+	
+	NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
+}
+
+
+/*
+=====================
+CL_ClearState
+
+=====================
+*/
+void CL_ClearState (void)
+{
+	S_StopAllSounds ();
+	CL_ClearEffects ();
+	CL_ClearTEnts ();
+
+// wipe the entire cl structure
+	memset (&cl, 0, sizeof(cl));
+	memset (cl_entities, 0, sizeof(cl_entities));
+
+	SZ_Clear (&cls.netchan.message);
+
+}
+
+/*
+=====================
+CL_Disconnect
+
+Goes from a connected state to full screen console state
+Sends a disconnect message to the server
+This is also called on Com_Error, so it shouldn't cause any errors
+=====================
+*/
+void CL_Disconnect (void)
+{
+	byte	final[32];
+
+	if (cls.state == ca_disconnected)
+		return;
+
+	if (cl_timedemo && cl_timedemo->value)
+	{
+		int	time;
+		
+		time = Sys_Milliseconds () - cl.timedemo_start;
+		if (time > 0)
+			Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
+			time/1000.0, cl.timedemo_frames*1000.0 / time);
+	}
+
+	VectorClear (cl.refdef.blend);
+	re.CinematicSetPalette(NULL);
+
+	M_ForceMenuOff ();
+
+	cls.connect_time = 0;
+
+	SCR_StopCinematic ();
+
+	if (cls.demorecording)
+		CL_Stop_f ();
+
+	// send a disconnect message to the server
+	final[0] = clc_stringcmd;
+	strcpy ((char *)final+1, "disconnect");
+	Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
+	Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
+	Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
+
+	CL_ClearState ();
+
+	// stop download
+	if (cls.download) {
+		fclose(cls.download);
+		cls.download = NULL;
+	}
+
+	cls.state = ca_disconnected;
+}
+
+void CL_Disconnect_f (void)
+{
+	Com_Error (ERR_DROP, "Disconnected from server");
+}
+
+
+/*
+====================
+CL_Packet_f
+
+packet <destination> <contents>
+
+Contents allows \n escape character
+====================
+*/
+void CL_Packet_f (void)
+{
+	char	send[2048];
+	int		i, l;
+	char	*in, *out;
+	netadr_t	adr;
+
+	if (Cmd_Argc() != 3)
+	{
+		Com_Printf ("packet <destination> <contents>\n");
+		return;
+	}
+
+	NET_Config (true);		// allow remote
+
+	if (!NET_StringToAdr (Cmd_Argv(1), &adr))
+	{
+		Com_Printf ("Bad address\n");
+		return;
+	}
+	if (!adr.port)
+		adr.port = BigShort (PORT_SERVER);
+
+	in = Cmd_Argv(2);
+	out = send+4;
+	send[0] = send[1] = send[2] = send[3] = (char)0xff;
+
+	l = strlen (in);
+	for (i=0 ; i<l ; i++)
+	{
+		if (in[i] == '\\' && in[i+1] == 'n')
+		{
+			*out++ = '\n';
+			i++;
+		}
+		else
+			*out++ = in[i];
+	}
+	*out = 0;
+
+	NET_SendPacket (NS_CLIENT, out-send, send, adr);
+}
+
+/*
+=================
+CL_Changing_f
+
+Just sent as a hint to the client that they should
+drop to full console
+=================
+*/
+void CL_Changing_f (void)
+{
+	//ZOID
+	//if we are downloading, we don't change!  This so we don't suddenly stop downloading a map
+	if (cls.download)
+		return;
+
+	SCR_BeginLoadingPlaque ();
+	cls.state = ca_connected;	// not active anymore, but not disconnected
+	Com_Printf ("\nChanging map...\n");
+}
+
+
+/*
+=================
+CL_Reconnect_f
+
+The server is changing levels
+=================
+*/
+void CL_Reconnect_f (void)
+{
+	//ZOID
+	//if we are downloading, we don't change!  This so we don't suddenly stop downloading a map
+	if (cls.download)
+		return;
+
+	S_StopAllSounds ();
+	if (cls.state == ca_connected) {
+		Com_Printf ("reconnecting...\n");
+		cls.state = ca_connected;
+		MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
+		MSG_WriteString (&cls.netchan.message, "new");		
+		return;
+	}
+
+	if (*cls.servername) {
+		if (cls.state >= ca_connected) {
+			CL_Disconnect();
+			cls.connect_time = cls.realtime - 1500;
+		} else
+			cls.connect_time = -99999; // fire immediately
+
+		cls.state = ca_connecting;
+		Com_Printf ("reconnecting...\n");
+	}
+}
+
+/*
+=================
+CL_ParseStatusMessage
+
+Handle a reply from a ping
+=================
+*/
+void CL_ParseStatusMessage (void)
+{
+	char	*s;
+
+	s = MSG_ReadString(&net_message);
+
+	Com_Printf ("%s\n", s);
+	M_AddToServerList (net_from, s);
+}
+
+
+/*
+=================
+CL_PingServers_f
+=================
+*/
+void CL_PingServers_f (void)
+{
+	int			i;
+	netadr_t	adr;
+	char		name[32];
+	char		*adrstring;
+	cvar_t		*noudp;
+	cvar_t		*noipx;
+
+	NET_Config (true);		// allow remote
+
+	// send a broadcast packet
+	Com_Printf ("pinging broadcast...\n");
+
+	noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
+	if (!noudp->value)
+	{
+		adr.type = NA_BROADCAST;
+		adr.port = BigShort(PORT_SERVER);
+		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
+	}
+
+	noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
+	if (!noipx->value)
+	{
+		adr.type = NA_BROADCAST_IPX;
+		adr.port = BigShort(PORT_SERVER);
+		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
+	}
+
+	// send a packet to each address book entry
+	for (i=0 ; i<16 ; i++)
+	{
+		Com_sprintf (name, sizeof(name), "adr%i", i);
+		adrstring = Cvar_VariableString (name);
+		if (!adrstring || !adrstring[0])
+			continue;
+
+		Com_Printf ("pinging %s...\n", adrstring);
+		if (!NET_StringToAdr (adrstring, &adr))
+		{
+			Com_Printf ("Bad address: %s\n", adrstring);
+			continue;
+		}
+		if (!adr.port)
+			adr.port = BigShort(PORT_SERVER);
+		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
+	}
+}
+
+
+/*
+=================
+CL_Skins_f
+
+Load or download any custom player skins and models
+=================
+*/
+void CL_Skins_f (void)
+{
+	int		i;
+
+	for (i=0 ; i<MAX_CLIENTS ; i++)
+	{
+		if (!cl.configstrings[CS_PLAYERSKINS+i][0])
+			continue;
+		Com_Printf ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]); 
+		SCR_UpdateScreen ();
+		Sys_SendKeyEvents ();	// pump message loop
+		CL_ParseClientinfo (i);
+	}
+}
+
+
+/*
+=================
+CL_ConnectionlessPacket
+
+Responses to broadcasts, etc
+=================
+*/
+void CL_ConnectionlessPacket (void)
+{
+	char	*s;
+	char	*c;
+	
+	MSG_BeginReading (&net_message);
+	MSG_ReadLong (&net_message);	// skip the -1
+
+	s = MSG_ReadStringLine (&net_message);
+
+	Cmd_TokenizeString (s, false);
+
+	c = Cmd_Argv(0);
+
+	Com_Printf ("%s: %s\n", NET_AdrToString (net_from), c);
+
+	// server connection
+	if (!strcmp(c, "client_connect"))
+	{
+		if (cls.state == ca_connected)
+		{
+			Com_Printf ("Dup connect received.  Ignored.\n");
+			return;
+		}
+		Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
+		MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
+		MSG_WriteString (&cls.netchan.message, "new");	
+		cls.state = ca_connected;
+		return;
+	}
+
+	// server responding to a status broadcast
+	if (!strcmp(c, "info"))
+	{
+		CL_ParseStatusMessage ();
+		return;
+	}
+
+	// remote command from gui front end
+	if (!strcmp(c, "cmd"))
+	{
+		if (!NET_IsLocalAddress(net_from))
+		{
+			Com_Printf ("Command packet from remote host.  Ignored.\n");
+			return;
+		}
+		Sys_AppActivate ();
+		s = MSG_ReadString (&net_message);
+		Cbuf_AddText (s);
+		Cbuf_AddText ("\n");
+		return;
+	}
+	// print command from somewhere
+	if (!strcmp(c, "print"))
+	{
+		s = MSG_ReadString (&net_message);
+		Com_Printf ("%s", s);
+		return;
+	}
+
+	// ping from somewhere
+	if (!strcmp(c, "ping"))
+	{
+		Netchan_OutOfBandPrint (NS_CLIENT, net_from, "ack");
+		return;
+	}
+
+	// challenge from the server we are connecting to
+	if (!strcmp(c, "challenge"))
+	{
+		cls.challenge = atoi(Cmd_Argv(1));
+		CL_SendConnectPacket ();
+		return;
+	}
+
+	// echo request from server
+	if (!strcmp(c, "echo"))
+	{
+		Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
+		return;
+	}
+
+	Com_Printf ("Unknown command.\n");
+}
+
+
+/*
+=================
+CL_DumpPackets
+
+A vain attempt to help bad TCP stacks that cause problems
+when they overflow
+=================
+*/
+void CL_DumpPackets (void)
+{
+	while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
+	{
+		Com_Printf ("dumnping a packet\n");
+	}
+}
+
+/*
+=================
+CL_ReadPackets
+=================
+*/
+void CL_ReadPackets (void)
+{
+	while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
+	{
+//	Com_Printf ("packet\n");
+		//
+		// remote command packet
+		//
+		if (*(int *)net_message.data == -1)
+		{
+			CL_ConnectionlessPacket ();
+			continue;
+		}
+
+		if (cls.state == ca_disconnected || cls.state == ca_connecting)
+			continue;		// dump it if not connected
+
+		if (net_message.cursize < 8)
+		{
+			Com_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
+			continue;
+		}
+
+		//
+		// packet from server
+		//
+		if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
+		{
+			Com_DPrintf ("%s:sequenced packet without connection\n"
+				,NET_AdrToString(net_from));
+			continue;
+		}
+		if (!Netchan_Process(&cls.netchan, &net_message))
+			continue;		// wasn't accepted for some reason
+		CL_ParseServerMessage ();
+	}
+
+	//
+	// check timeout
+	//
+	if (cls.state >= ca_connected
+	 && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000)
+	{
+		if (++cl.timeoutcount > 5)	// timeoutcount saves debugger
+		{
+			Com_Printf ("\nServer connection timed out.\n");
+			CL_Disconnect ();
+			return;
+		}
+	}
+	else
+		cl.timeoutcount = 0;
+	
+}
+
+
+//=============================================================================
+
+/*
+==============
+CL_FixUpGender_f
+==============
+*/
+void CL_FixUpGender(void)
+{
+	char *p;
+	char sk[80];
+
+	if (gender_auto->value) {
+
+		if (gender->modified) {
+			// was set directly, don't override the user
+			gender->modified = false;
+			return;
+		}
+
+		strncpy(sk, skin->string, sizeof(sk) - 1);
+		if ((p = strchr(sk, '/')) != NULL)
+			*p = 0;
+		if (cistrcmp(sk, "male") == 0 || cistrcmp(sk, "cyborg") == 0)
+			Cvar_Set ("gender", "male");
+		else if (cistrcmp(sk, "female") == 0 || cistrcmp(sk, "crackhor") == 0)
+			Cvar_Set ("gender", "female");
+		else
+			Cvar_Set ("gender", "none");
+		gender->modified = false;
+	}
+}
+
+/*
+==============
+CL_Userinfo_f
+==============
+*/
+void CL_Userinfo_f (void)
+{
+	Com_Printf ("User info settings:\n");
+	Info_Print (Cvar_Userinfo());
+}
+
+/*
+=================
+CL_Snd_Restart_f
+
+Restart the sound subsystem so it can pick up
+new parameters and flush all sounds
+=================
+*/
+void CL_Snd_Restart_f (void)
+{
+	S_Shutdown ();
+	S_Init ();
+	CL_RegisterSounds ();
+}
+
+int precache_check; // for autodownload of precache items
+int precache_spawncount;
+int precache_tex;
+int precache_model_skin;
+
+byte *precache_model; // used for skin checking in alias models
+
+#define PLAYER_MULT 5
+
+// ENV_CNT is map load, ENV_CNT+1 is first env map
+#define ENV_CNT (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
+#define TEXTURE_CNT (ENV_CNT+13)
+
+static char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+
+void CL_RequestNextDownload (void)
+{
+	unsigned	map_checksum;		// for detecting cheater maps
+	char fn[MAX_OSPATH];
+	dmdl_t *pheader;
+
+	if (cls.state != ca_connected)
+		return;
+
+	if (!allow_download->value && precache_check < ENV_CNT)
+		precache_check = ENV_CNT;
+
+//ZOID
+	if (precache_check == CS_MODELS) { // confirm map
+		precache_check = CS_MODELS+2; // 0 isn't used
+		if (allow_download_maps->value)
+			if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
+				return; // started a download
+	}
+	if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS) {
+		if (allow_download_models->value) {
+			while (precache_check < CS_MODELS+MAX_MODELS &&
+				cl.configstrings[precache_check][0]) {
+				if (cl.configstrings[precache_check][0] == '*' ||
+					cl.configstrings[precache_check][0] == '#') {
+					precache_check++;
+					continue;
+				}
+				if (precache_model_skin == 0) {
+					if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
+						precache_model_skin = 1;
+						return; // started a download
+					}
+					precache_model_skin = 1;
+				}
+
+				// checking for skins in the model
+				if (!precache_model) {
+
+					FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model);
+					if (!precache_model) {
+						precache_model_skin = 0;
+						precache_check++;
+						continue; // couldn't load it
+					}
+					if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER) {
+						// not an alias model
+						FS_FreeFile(precache_model);
+						precache_model = 0;
+						precache_model_skin = 0;
+						precache_check++;
+						continue;
+					}
+					pheader = (dmdl_t *)precache_model;
+					if (LittleLong (pheader->version) != ALIAS_VERSION) {
+						precache_check++;
+						precache_model_skin = 0;
+						continue; // couldn't load it
+					}
+				}
+
+				pheader = (dmdl_t *)precache_model;
+
+				while (precache_model_skin - 1 < LittleLong(pheader->num_skins)) {
+					if (!CL_CheckOrDownloadFile((char *)precache_model +
+						LittleLong(pheader->ofs_skins) + 
+						(precache_model_skin - 1)*MAX_SKINNAME)) {
+						precache_model_skin++;
+						return; // started a download
+					}
+					precache_model_skin++;
+				}
+				if (precache_model) { 
+					FS_FreeFile(precache_model);
+					precache_model = 0;
+				}
+				precache_model_skin = 0;
+				precache_check++;
+			}
+		}
+		precache_check = CS_SOUNDS;
+	}
+	if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS) { 
+		if (allow_download_sounds->value) {
+			if (precache_check == CS_SOUNDS)
+				precache_check++; // zero is blank
+			while (precache_check < CS_SOUNDS+MAX_SOUNDS &&
+				cl.configstrings[precache_check][0]) {
+				if (cl.configstrings[precache_check][0] == '*') {
+					precache_check++;
+					continue;
+				}
+				Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]);
+				if (!CL_CheckOrDownloadFile(fn))
+					return; // started a download
+			}
+		}
+		precache_check = CS_IMAGES;
+	}
+	if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES) {
+		if (precache_check == CS_IMAGES)
+			precache_check++; // zero is blank
+		while (precache_check < CS_IMAGES+MAX_IMAGES &&
+			cl.configstrings[precache_check][0]) {
+			Com_sprintf(fn, sizeof(fn), "pics/%s.pcx", cl.configstrings[precache_check++]);
+			if (!CL_CheckOrDownloadFile(fn))
+				return; // started a download
+		}
+		precache_check = CS_PLAYERSKINS;
+	}
+	// skins are special, since a player has three things to download:
+	// model, weapon model and skin
+	// so precache_check is now *3
+	if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
+		if (allow_download_players->value) {
+			while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
+				int i, n;
+				char model[MAX_QPATH], skin[MAX_QPATH], *p;
+
+				i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
+				n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
+
+				if (!cl.configstrings[CS_PLAYERSKINS+i][0]) {
+					precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
+					continue;
+				}
+
+				if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
+					p++;
+				else
+					p = cl.configstrings[CS_PLAYERSKINS+i];
+				strcpy(model, p);
+				p = strchr(model, '/');
+				if (!p)
+					p = strchr(model, '\\');
+				if (p) {
+					*p++ = 0;
+					strcpy(skin, p);
+				} else
+					*skin = 0;
+
+				switch (n) {
+				case 0: // model
+					Com_sprintf(fn, sizeof(fn), "players/%s/tris.md2", model);
+					if (!CL_CheckOrDownloadFile(fn)) {
+						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
+						return; // started a download
+					}
+					/*FALL THROUGH*/
+
+				case 1: // weapon model
+					Com_sprintf(fn, sizeof(fn), "players/%s/weapon.md2", model);
+					if (!CL_CheckOrDownloadFile(fn)) {
+						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
+						return; // started a download
+					}
+					/*FALL THROUGH*/
+
+				case 2: // weapon skin
+					Com_sprintf(fn, sizeof(fn), "players/%s/weapon.pcx", model);
+					if (!CL_CheckOrDownloadFile(fn)) {
+						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
+						return; // started a download
+					}
+					/*FALL THROUGH*/
+
+				case 3: // skin
+					Com_sprintf(fn, sizeof(fn), "players/%s/%s.pcx", model, skin);
+					if (!CL_CheckOrDownloadFile(fn)) {
+						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
+						return; // started a download
+					}
+					/*FALL THROUGH*/
+
+				case 4: // skin_i
+					Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.pcx", model, skin);
+					if (!CL_CheckOrDownloadFile(fn)) {
+						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
+						return; // started a download
+					}
+					// move on to next model
+					precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
+				}
+			}
+		}
+		// precache phase completed
+		precache_check = ENV_CNT;
+	}
+
+	if (precache_check == ENV_CNT) {
+		precache_check = ENV_CNT + 1;
+
+		CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
+
+		if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM])) {
+			Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n",
+				map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
+			return;
+		}
+	}
+
+	if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) {
+		if (allow_download->value && allow_download_maps->value) {
+			while (precache_check < TEXTURE_CNT) {
+				int n = precache_check++ - ENV_CNT - 1;
+
+				if (n & 1)
+					Com_sprintf(fn, sizeof(fn), "env/%s%s.pcx", 
+						cl.configstrings[CS_SKY], env_suf[n/2]);
+				else
+					Com_sprintf(fn, sizeof(fn), "env/%s%s.tga", 
+						cl.configstrings[CS_SKY], env_suf[n/2]);
+				if (!CL_CheckOrDownloadFile(fn))
+					return; // started a download
+			}
+		}
+		precache_check = TEXTURE_CNT;
+	}
+
+	if (precache_check == TEXTURE_CNT) {
+		precache_check = TEXTURE_CNT+1;
+		precache_tex = 0;
+	}
+
+	// confirm existance of textures, download any that don't exist
+	if (precache_check == TEXTURE_CNT+1) {
+		// from qcommon/cmodel.c
+		extern int			numtexinfo;
+		extern mapsurface_t	map_surfaces[];
+
+		if (allow_download->value && allow_download_maps->value) {
+			while (precache_tex < numtexinfo) {
+				char fn[MAX_OSPATH];
+
+				sprintf(fn, "textures/%s.wal", map_surfaces[precache_tex++].rname);
+				if (!CL_CheckOrDownloadFile(fn))
+					return; // started a download
+			}
+		}
+		precache_check = TEXTURE_CNT+999;
+	}
+
+//ZOID
+	CL_RegisterSounds ();
+	CL_PrepRefresh ();
+
+	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+	MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) );
+}
+
+/*
+=================
+CL_Precache_f
+
+The server will send this command right
+before allowing the client into the server
+=================
+*/
+void CL_Precache_f (void)
+{
+	//Yet another hack to let old demos work
+	//the old precache sequence
+	if (Cmd_Argc() < 2) {
+		unsigned	map_checksum;		// for detecting cheater maps
+
+		CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
+		CL_RegisterSounds ();
+		CL_PrepRefresh ();
+		return;
+	}
+
+	precache_check = CS_MODELS;
+	precache_spawncount = atoi(Cmd_Argv(1));
+	precache_model = 0;
+	precache_model_skin = 0;
+
+	CL_RequestNextDownload();
+}
+
+
+/*
+=================
+CL_InitLocal
+=================
+*/
+void CL_InitLocal (void)
+{
+	cls.state = ca_disconnected;
+	cls.realtime = Sys_Milliseconds ();
+
+	CL_InitInput ();
+
+	adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE );
+	adr1 = Cvar_Get( "adr1", "", CVAR_ARCHIVE );
+	adr2 = Cvar_Get( "adr2", "", CVAR_ARCHIVE );
+	adr3 = Cvar_Get( "adr3", "", CVAR_ARCHIVE );
+	adr4 = Cvar_Get( "adr4", "", CVAR_ARCHIVE );
+	adr5 = Cvar_Get( "adr5", "", CVAR_ARCHIVE );
+	adr6 = Cvar_Get( "adr6", "", CVAR_ARCHIVE );
+	adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE );
+	adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE );
+
+//
+// register our variables
+//
+	cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE );
+	cl_stereo = Cvar_Get( "cl_stereo", "0", 0 );
+
+	cl_add_blend = Cvar_Get ("cl_blend", "1", 0);
+	cl_add_lights = Cvar_Get ("cl_lights", "1", 0);
+	cl_add_particles = Cvar_Get ("cl_particles", "1", 0);
+	cl_add_entities = Cvar_Get ("cl_entities", "1", 0);
+	cl_gun = Cvar_Get ("cl_gun", "1", 0);
+	cl_footsteps = Cvar_Get ("cl_footsteps", "1", 0);
+	cl_noskins = Cvar_Get ("cl_noskins", "0", 0);
+	cl_autoskins = Cvar_Get ("cl_autoskins", "0", 0);
+	cl_predict = Cvar_Get ("cl_predict", "1", 0);
+//	cl_minfps = Cvar_Get ("cl_minfps", "5", 0);
+	cl_maxfps = Cvar_Get ("cl_maxfps", "90", 0);
+
+	cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0);
+	cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0);
+	cl_sidespeed = Cvar_Get ("cl_sidespeed", "200", 0);
+	cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0);
+	cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0);
+	cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
+
+	cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE);
+
+	cl_shownet = Cvar_Get ("cl_shownet", "0", 0);
+	cl_showmiss = Cvar_Get ("cl_showmiss", "0", 0);
+	cl_showclamp = Cvar_Get ("showclamp", "0", 0);
+	cl_timeout = Cvar_Get ("cl_timeout", "120", 0);
+	cl_paused = Cvar_Get ("paused", "0", 0);
+	cl_timedemo = Cvar_Get ("timedemo", "0", 0);
+
+	rcon_client_password = Cvar_Get ("rcon_password", "", 0);
+	rcon_address = Cvar_Get ("rcon_address", "", 0);
+
+	cl_lightlevel = Cvar_Get ("r_lightlevel", "0", 0);
+
+	//
+	// userinfo
+	//
+	info_password = Cvar_Get ("password", "", CVAR_USERINFO);
+	info_spectator = Cvar_Get ("spectator", "0", CVAR_USERINFO);
+	name = Cvar_Get ("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE);
+	skin = Cvar_Get ("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
+	rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE);	// FIXME
+	msg = Cvar_Get ("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
+	hand = Cvar_Get ("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
+	fov = Cvar_Get ("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE);
+	gender = Cvar_Get ("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
+	gender_auto = Cvar_Get ("gender_auto", "1", CVAR_ARCHIVE);
+	gender->modified = false; // clear this so we know when user sets it manually
+
+	cl_vwep = Cvar_Get ("cl_vwep", "1", CVAR_ARCHIVE);
+
+
+	//
+	// register our commands
+	//
+	Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
+	Cmd_AddCommand ("pause", CL_Pause_f);
+	Cmd_AddCommand ("pingservers", CL_PingServers_f);
+	Cmd_AddCommand ("skins", CL_Skins_f);
+
+	Cmd_AddCommand ("userinfo", CL_Userinfo_f);
+	Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
+
+	Cmd_AddCommand ("changing", CL_Changing_f);
+	Cmd_AddCommand ("disconnect", CL_Disconnect_f);
+	Cmd_AddCommand ("record", CL_Record_f);
+	Cmd_AddCommand ("stop", CL_Stop_f);
+
+	Cmd_AddCommand ("quit", CL_Quit_f);
+
+	Cmd_AddCommand ("connect", CL_Connect_f);
+	Cmd_AddCommand ("reconnect", CL_Reconnect_f);
+
+	Cmd_AddCommand ("rcon", CL_Rcon_f);
+
+// 	Cmd_AddCommand ("packet", CL_Packet_f); // this is dangerous to leave in
+
+	Cmd_AddCommand ("setenv", CL_Setenv_f );
+
+	Cmd_AddCommand ("precache", CL_Precache_f);
+
+	Cmd_AddCommand ("download", CL_Download_f);
+
+	//
+	// forward to server commands
+	//
+	// the only thing this does is allow command completion
+	// to work -- all unknown commands are automatically
+	// forwarded to the server
+	Cmd_AddCommand ("wave", NULL);
+	Cmd_AddCommand ("inven", NULL);
+	Cmd_AddCommand ("kill", NULL);
+	Cmd_AddCommand ("use", NULL);
+	Cmd_AddCommand ("drop", NULL);
+	Cmd_AddCommand ("say", NULL);
+	Cmd_AddCommand ("say_team", NULL);
+	Cmd_AddCommand ("info", NULL);
+	Cmd_AddCommand ("prog", NULL);
+	Cmd_AddCommand ("give", NULL);
+	Cmd_AddCommand ("god", NULL);
+	Cmd_AddCommand ("notarget", NULL);
+	Cmd_AddCommand ("noclip", NULL);
+	Cmd_AddCommand ("invuse", NULL);
+	Cmd_AddCommand ("invprev", NULL);
+	Cmd_AddCommand ("invnext", NULL);
+	Cmd_AddCommand ("invdrop", NULL);
+	Cmd_AddCommand ("weapnext", NULL);
+	Cmd_AddCommand ("weapprev", NULL);
+}
+
+
+
+/*
+===============
+CL_WriteConfiguration
+
+Writes key bindings and archived cvars to config.cfg
+===============
+*/
+void CL_WriteConfiguration (void)
+{
+	FILE	*f;
+	char	path[MAX_QPATH];
+
+	if (cls.state == ca_uninitialized)
+		return;
+
+	Com_sprintf (path, sizeof(path),"%s/config.cfg",FS_Gamedir());
+	f = fopen (path, "w");
+	if (!f)
+	{
+		Com_Printf ("Couldn't write config.cfg.\n");
+		return;
+	}
+
+	fprintf (f, "// generated by quake, do not modify\n");
+	Key_WriteBindings (f);
+	fclose (f);
+
+	Cvar_WriteVariables (path);
+}
+
+
+/*
+==================
+CL_FixCvarCheats
+
+==================
+*/
+
+typedef struct
+{
+	char	*name;
+	char	*value;
+	cvar_t	*var;
+} cheatvar_t;
+
+cheatvar_t	cheatvars[] = {
+	{"timescale", "1"},
+	{"timedemo", "0"},
+	{"r_drawworld", "1"},
+	{"cl_testlights", "0"},
+	{"r_fullbright", "0"},
+	{"r_drawflat", "0"},
+	{"paused", "0"},
+	{"fixedtime", "0"},
+	{"sw_draworder", "0"},
+	{"gl_lightmap", "0"},
+	{"gl_saturatelighting", "0"},
+	{NULL, NULL}
+};
+
+int		numcheatvars;
+
+void CL_FixCvarCheats (void)
+{
+	int			i;
+	cheatvar_t	*var;
+
+	if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1") 
+		|| !cl.configstrings[CS_MAXCLIENTS][0] )
+		return;		// single player can cheat
+
+	// find all the cvars if we haven't done it yet
+	if (!numcheatvars)
+	{
+		while (cheatvars[numcheatvars].name)
+		{
+			cheatvars[numcheatvars].var = Cvar_Get (cheatvars[numcheatvars].name,
+					cheatvars[numcheatvars].value, 0);
+			numcheatvars++;
+		}
+	}
+
+	// make sure they are all set to the proper values
+	for (i=0, var = cheatvars ; i<numcheatvars ; i++, var++)
+	{
+		if ( strcmp (var->var->string, var->value) )
+		{
+			Cvar_Set (var->name, var->value);
+		}
+	}
+}
+
+//============================================================================
+
+/*
+==================
+CL_SendCommand
+
+==================
+*/
+void CL_SendCommand (void)
+{
+	// get new key events
+	Sys_SendKeyEvents ();
+
+	// allow mice or other external controllers to add commands
+	IN_Commands ();
+
+	// process console commands
+	Cbuf_Execute ();
+
+	// fix any cheating cvars
+	CL_FixCvarCheats ();
+
+	// send intentions now
+	CL_SendCmd ();
+
+	// resend a connection request if necessary
+	CL_CheckForResend ();
+}
+
+
+/*
+==================
+CL_Frame
+
+==================
+*/
+void CL_Frame (int msec)
+{
+	static int	extratime;
+	static int  lasttimecalled;
+
+	if (dedicated->value)
+		return;
+
+	extratime += msec;
+
+	if (!cl_timedemo->value)
+	{
+		if (cls.state == ca_connected && extratime < 100)
+			return;			// don't flood packets out while connecting
+		if (extratime < 1000/cl_maxfps->value)
+			return;			// framerate is too high
+	}
+
+	// let the mouse activate or deactivate
+	IN_Frame ();
+
+	// decide the simulation time
+	cls.frametime = extratime/1000.0;
+	cl.time += extratime;
+	cls.realtime = curtime;
+
+	extratime = 0;
+/*
+	if (cls.frametime > (1.0 / cl_minfps->value))
+		cls.frametime = (1.0 / cl_minfps->value);
+*/
+	if (cls.frametime > (1.0 / 5))
+		cls.frametime = (1.0 / 5);
+
+	// if in the debugger last frame, don't timeout
+	if (msec > 5000)
+		cls.netchan.last_received = Sys_Milliseconds ();
+
+	// fetch results from server
+	CL_ReadPackets ();
+
+	// send a new command message to the server
+	CL_SendCommand ();
+
+	// predict all unacknowledged movements
+	CL_PredictMovement ();
+
+	// allow rendering DLL change
+	VID_CheckChanges ();
+	if (!cl.refresh_prepped && cls.state == ca_active)
+		CL_PrepRefresh ();
+
+	// update the screen
+	if (host_speeds->value)
+		time_before_ref = Sys_Milliseconds ();
+	SCR_UpdateScreen ();
+	if (host_speeds->value)
+		time_after_ref = Sys_Milliseconds ();
+
+	// update audio
+	S_Update (cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up);
+	
+	CDAudio_Update();
+
+	// advance local effects for next frame
+	CL_RunDLights ();
+	CL_RunLightStyles ();
+	SCR_RunCinematic ();
+	SCR_RunConsole ();
+
+	cls.framecount++;
+
+	if ( log_stats->value )
+	{
+		if ( cls.state == ca_active )
+		{
+			if ( !lasttimecalled )
+			{
+				lasttimecalled = Sys_Milliseconds();
+				if ( log_stats_file )
+					fprintf( log_stats_file, "0\n" );
+			}
+			else
+			{
+				int now = Sys_Milliseconds();
+
+				if ( log_stats_file )
+					fprintf( log_stats_file, "%d\n", now - lasttimecalled );
+				lasttimecalled = now;
+			}
+		}
+	}
+}
+
+
+//============================================================================
+
+/*
+====================
+CL_Init
+====================
+*/
+void CL_Init (void)
+{
+	IN_Init();
+
+	if(dedicated->value)
+		return;		// nothing running on the client
+
+	// all archived variables will now be loaded
+
+	Con_Init ();
+	S_Init ();	
+	VID_Init ();
+	
+	V_Init ();
+	
+	net_message.data = net_message_buffer;
+	net_message.maxsize = sizeof(net_message_buffer);
+
+	M_Init ();	
+	
+	SCR_Init ();
+	cls.disable_screen = true;	// don't draw yet
+
+	CDAudio_Init ();
+	CL_InitLocal ();
+
+//	Cbuf_AddText ("exec autoexec.cfg\n");
+	FS_ExecAutoexec ();
+	Cbuf_Execute ();
+}
+
+
+/*
+===============
+CL_Shutdown
+
+FIXME: this is a callback from Sys_Quit and Com_Error.  It would be better
+to run quit through here before the final handoff to the sys code.
+===============
+*/
+void CL_Shutdown(void)
+{
+	static qboolean isdown = false;
+	
+	if (isdown)
+	{
+		printf ("recursive shutdown\n");
+		return;
+	}
+	isdown = true;
+
+	CL_WriteConfiguration (); 
+
+	CDAudio_Shutdown ();
+	S_Shutdown();
+	IN_Shutdown ();
+	VID_Shutdown();
+}
+
+
--- /dev/null
+++ b/cl_newfx.c
@@ -1,0 +1,1307 @@
+// cl_newfx.c -- MORE entity effects parsing and management
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+extern cparticle_t	*active_particles, *free_particles;
+extern cparticle_t	particles[MAX_PARTICLES];
+extern int			cl_numparticles;
+
+extern void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up);
+
+
+/*
+======
+vectoangles2 - this is duplicated in the game DLL, but I need it here.
+======
+*/
+void vectoangles2 (vec3_t value1, vec3_t angles)
+{
+	float	forward;
+	float	yaw, pitch;
+	
+	if (value1[1] == 0 && value1[0] == 0)
+	{
+		yaw = 0;
+		if (value1[2] > 0)
+			pitch = 90;
+		else
+			pitch = 270;
+	}
+	else
+	{
+	// PMM - fixed to correct for pitch of 0
+		if (value1[0])
+			yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
+		else if (value1[1] > 0)
+			yaw = 90;
+		else
+			yaw = 270;
+
+		if (yaw < 0)
+			yaw += 360;
+
+		forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
+		pitch = (atan2(value1[2], forward) * 180 / M_PI);
+		if (pitch < 0)
+			pitch += 360;
+	}
+
+	angles[PITCH] = -pitch;
+	angles[YAW] = yaw;
+	angles[ROLL] = 0;
+}
+
+//=============
+//=============
+void CL_Flashlight (int ent, vec3_t pos)
+{
+	cdlight_t	*dl;
+
+	dl = CL_AllocDlight (ent);
+	VectorCopy (pos,  dl->origin);
+	dl->radius = 400;
+	dl->minlight = 250;
+	dl->die = cl.time + 100;
+	dl->color[0] = 1;
+	dl->color[1] = 1;
+	dl->color[2] = 1;
+}
+
+/*
+======
+CL_ColorFlash - flash of light
+======
+*/
+void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b)
+{
+	cdlight_t	*dl;
+
+	if((vidref_val == VIDREF_SOFT) && ((r < 0) || (g<0) || (b<0)))
+	{
+		intensity = -intensity;
+		r = -r;
+		g = -g;
+		b = -b;
+	}
+
+	dl = CL_AllocDlight (ent);
+	VectorCopy (pos,  dl->origin);
+	dl->radius = intensity;
+	dl->minlight = 250;
+	dl->die = cl.time + 100;
+	dl->color[0] = r;
+	dl->color[1] = g;
+	dl->color[2] = b;
+}
+
+
+/*
+======
+CL_DebugTrail
+======
+*/
+void CL_DebugTrail (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+//	int			j;
+	cparticle_t	*p;
+	float		dec;
+	vec3_t		right, up;
+//	int			i;
+//	float		d, c, s;
+//	vec3_t		dir;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	MakeNormalVectors (vec, right, up);
+
+//	VectorScale(vec, RT2_SKIP, vec);
+
+//	dec = 1.0;
+//	dec = 0.75;
+	dec = 3;
+	VectorScale (vec, dec, vec);
+	VectorCopy (start, move);
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		VectorClear (p->accel);
+		VectorClear (p->vel);
+		p->alpha = 1.0;
+		p->alphavel = -0.1;
+//		p->alphavel = 0;
+		p->color = 0x74 + (rand()&7);
+		VectorCopy (move, p->org);
+/*
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*2;
+			p->vel[j] = crand()*3;
+			p->accel[j] = 0;
+		}
+*/
+		VectorAdd (move, vec, move);
+	}
+
+}
+
+/*
+===============
+CL_SmokeTrail
+===============
+*/
+void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	VectorScale (vec, spacing, vec);
+
+	// FIXME: this is a really silly way to have a loop
+	while (len > 0)
+	{
+		len -= spacing;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (1+qfrand()*0.5);
+		p->color = colorStart + (rand() % colorRun);
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*3;
+			p->accel[j] = 0;
+		}
+		p->vel[2] = 20 + crand()*5;
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+void CL_ForceWall (vec3_t start, vec3_t end, int color)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	VectorScale (vec, 4, vec);
+
+	// FIXME: this is a really silly way to have a loop
+	while (len > 0)
+	{
+		len -= 4;
+
+		if (!free_particles)
+			return;
+		
+		if (qfrand() > 0.3)
+		{
+			p = free_particles;
+			free_particles = p->next;
+			p->next = active_particles;
+			active_particles = p;
+			VectorClear (p->accel);
+			
+			p->time = cl.time;
+
+			p->alpha = 1.0;
+			p->alphavel =  -1.0 / (3.0+qfrand()*0.5);
+			p->color = color;
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = move[j] + crand()*3;
+				p->accel[j] = 0;
+			}
+			p->vel[0] = 0;
+			p->vel[1] = 0;
+			p->vel[2] = -40 - (crand()*10);
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+void CL_FlameEffects (centity_t */*ent*/, vec3_t origin)
+{
+	int			n, count;
+	int			j;
+	cparticle_t	*p;
+
+	count = rand() & 0xF;
+
+	for(n=0;n<count;n++)
+	{
+		if (!free_particles)
+			return;
+			
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		
+		VectorClear (p->accel);
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (1+qfrand()*0.2);
+		p->color = 226 + (rand() % 4);
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = origin[j] + crand()*5;
+			p->vel[j] = crand()*5;
+		}
+		p->vel[2] = crand() * -10;
+		p->accel[2] = -PARTICLE_GRAVITY;
+	}
+
+	count = rand() & 0x7;
+
+	for(n=0;n<count;n++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (1+qfrand()*0.5);
+		p->color = 0 + (rand() % 4);
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = origin[j] + crand()*3;
+		}
+		p->vel[2] = 20 + crand()*5;
+	}
+
+}
+
+
+/*
+===============
+CL_GenericParticleEffect
+===============
+*/
+void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		if (numcolors > 1)
+			p->color = color + (rand() & numcolors);
+		else
+			p->color = color;
+
+		d = rand() & dirspread;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+			p->vel[j] = crand()*20;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+//		VectorCopy (accel, p->accel);
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + qfrand()*alphavel);
+//		p->alphavel = alphavel;
+	}
+}
+
+/*
+===============
+CL_BubbleTrail2 (lets you control the # of bubbles by setting the distance between the spawns)
+
+===============
+*/
+void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			i, j;
+	cparticle_t	*p;
+	float		dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = dist;
+	VectorScale (vec, dec, vec);
+
+	for (i=0 ; i<len ; i+=dec)
+	{
+		if (!free_particles)
+			return;
+
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		VectorClear (p->accel);
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (1+qfrand()*0.1);
+		p->color = 4 + (rand()&7);
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*2;
+			p->vel[j] = crand()*10;
+		}
+		p->org[2] -= 4;
+//		p->vel[2] += 6;
+		p->vel[2] += 20;
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+//#define CORKSCREW		1
+//#define DOUBLE_SCREW	1
+#define	RINGS		1
+//#define	SPRAY		1
+
+#ifdef CORKSCREW
+void CL_Heatbeam (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j,k;
+	cparticle_t	*p;
+	vec3_t		right, up;
+	int			i;
+	float		d, c, s;
+	vec3_t		dir;
+	float		ltime;
+	float		step = 5.0;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+//	MakeNormalVectors (vec, right, up);
+	VectorCopy (cl.v_right, right);
+	VectorCopy (cl.v_up, up);
+	VectorMA (move, -1, right, move);
+	VectorMA (move, -1, up, move);
+
+	VectorScale (vec, step, vec);
+	ltime = (float) cl.time/1000.0;
+
+//	for (i=0 ; i<len ; i++)
+	for (i=0 ; i<len ; i+=step)
+	{
+		d = i * 0.1 - fmod(ltime,16.0)*M_PI;
+		c = cos(d)/1.75;
+		s = sin(d)/1.75;
+#ifdef DOUBLE_SCREW		
+		for (k=-1; k<2; k+=2)
+		{
+#else
+		k=1;
+#endif
+			if (!free_particles)
+				return;
+
+			p = free_particles;
+			free_particles = p->next;
+			p->next = active_particles;
+			active_particles = p;
+			
+			p->time = cl.time;
+			VectorClear (p->accel);
+
+			p->alpha = 0.5;
+	//		p->alphavel = -1.0 / (1+qfrand()*0.2);
+			// only last one frame!
+			p->alphavel = INSTANT_PARTICLE;
+	//		p->color = 0x74 + (rand()&7);
+//			p->color = 223 - (rand()&7);
+			p->color = 223;
+//			p->color = 240;
+
+			// trim it so it looks like it's starting at the origin
+			if (i < 10)
+			{
+				VectorScale (right, c*(i/10.0)*k, dir);
+				VectorMA (dir, s*(i/10.0)*k, up, dir);
+			}
+			else
+			{
+				VectorScale (right, c*k, dir);
+				VectorMA (dir, s*k, up, dir);
+			}
+			
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = move[j] + dir[j]*3;
+	//			p->vel[j] = dir[j]*6;
+				p->vel[j] = 0;
+			}
+#ifdef DOUBLE_SCREW
+		}
+#endif
+		VectorAdd (move, vec, move);
+	}
+}
+#endif
+#ifdef RINGS
+//void CL_Heatbeam (vec3_t start, vec3_t end)
+void CL_Heatbeam (vec3_t start, vec3_t forward)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	vec3_t		right, up;
+	int			i;
+	float		c, s;
+	vec3_t		dir;
+	float		ltime;
+	float		step = 32.0, rstep;
+	float		start_pt;
+	float		rot;
+	float		variance;
+	vec3_t		end;
+
+	VectorMA (start, 4096, forward, end);
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	// FIXME - pmm - these might end up using old values?
+//	MakeNormalVectors (vec, right, up);
+	VectorCopy (cl.v_right, right);
+	VectorCopy (cl.v_up, up);
+	if (vidref_val == VIDREF_GL)
+	{ // GL mode
+		VectorMA (move, -0.5, right, move);
+		VectorMA (move, -0.5, up, move);
+	}
+	// otherwise assume SOFT
+
+	ltime = (float) cl.time/1000.0;
+	start_pt = fmod(ltime*96.0,step);
+	VectorMA (move, start_pt, vec, move);
+
+	VectorScale (vec, step, vec);
+
+//	Com_Printf ("%f\n", ltime);
+	rstep = M_PI/10.0;
+	for (i=start_pt ; i<len ; i+=step)
+	{
+		if (i>step*5) // don't bother after the 5th ring
+			break;
+
+		for (rot = 0; rot < M_PI*2; rot += rstep)
+		{
+
+			if (!free_particles)
+				return;
+
+			p = free_particles;
+			free_particles = p->next;
+			p->next = active_particles;
+			active_particles = p;
+			
+			p->time = cl.time;
+			VectorClear (p->accel);
+//			rot+= fmod(ltime, 12.0)*M_PI;
+//			c = cos(rot)/2.0;
+//			s = sin(rot)/2.0;
+//			variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2;
+			variance = 0.5;
+			c = cos(rot)*variance;
+			s = sin(rot)*variance;
+			
+			// trim it so it looks like it's starting at the origin
+			if (i < 10)
+			{
+				VectorScale (right, c*(i/10.0), dir);
+				VectorMA (dir, s*(i/10.0), up, dir);
+			}
+			else
+			{
+				VectorScale (right, c, dir);
+				VectorMA (dir, s, up, dir);
+			}
+		
+			p->alpha = 0.5;
+	//		p->alphavel = -1.0 / (1+qfrand()*0.2);
+			p->alphavel = -1000.0;
+	//		p->color = 0x74 + (rand()&7);
+			p->color = 223 - (rand()&7);
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = move[j] + dir[j]*3;
+	//			p->vel[j] = dir[j]*6;
+				p->vel[j] = 0;
+			}
+		}
+		VectorAdd (move, vec, move);
+	}
+}
+#endif
+#ifdef SPRAY
+void CL_Heatbeam (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	vec3_t		forward, right, up;
+	int			i;
+	float		d, c, s;
+	vec3_t		dir;
+	float		ltime;
+	float		step = 32.0, rstep;
+	float		start_pt;
+	float		rot;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+//	MakeNormalVectors (vec, right, up);
+	VectorCopy (cl.v_forward, forward);
+	VectorCopy (cl.v_right, right);
+	VectorCopy (cl.v_up, up);
+	VectorMA (move, -0.5, right, move);
+	VectorMA (move, -0.5, up, move);
+
+	for (i=0; i<8; i++)
+	{
+		if (!free_particles)
+			return;
+
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		
+		p->time = cl.time;
+		VectorClear (p->accel);
+		
+		d = crand()*M_PI;
+		c = cos(d)*30;
+		s = sin(d)*30;
+
+		p->alpha = 1.0;
+		p->alphavel = -5.0 / (1+qfrand());
+		p->color = 223 - (rand()&7);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j];
+		}
+		VectorScale (vec, 450, p->vel);
+		VectorMA (p->vel, c, right, p->vel);
+		VectorMA (p->vel, s, up, p->vel);
+	}
+/*
+
+	ltime = (float) cl.time/1000.0;
+	start_pt = fmod(ltime*16.0,step);
+	VectorMA (move, start_pt, vec, move);
+
+	VectorScale (vec, step, vec);
+
+//	Com_Printf ("%f\n", ltime);
+	rstep = M_PI/12.0;
+	for (i=start_pt ; i<len ; i+=step)
+	{
+		if (i>step*5) // don't bother after the 5th ring
+			break;
+
+		for (rot = 0; rot < M_PI*2; rot += rstep)
+		{
+			if (!free_particles)
+				return;
+
+			p = free_particles;
+			free_particles = p->next;
+			p->next = active_particles;
+			active_particles = p;
+			
+			p->time = cl.time;
+			VectorClear (p->accel);
+//			rot+= fmod(ltime, 12.0)*M_PI;
+//			c = cos(rot)/2.0;
+//			s = sin(rot)/2.0;
+			c = cos(rot)/1.5;
+			s = sin(rot)/1.5;
+			
+			// trim it so it looks like it's starting at the origin
+			if (i < 10)
+			{
+				VectorScale (right, c*(i/10.0), dir);
+				VectorMA (dir, s*(i/10.0), up, dir);
+			}
+			else
+			{
+				VectorScale (right, c, dir);
+				VectorMA (dir, s, up, dir);
+			}
+		
+			p->alpha = 0.5;
+	//		p->alphavel = -1.0 / (1+qfrand()*0.2);
+			p->alphavel = -1000.0;
+	//		p->color = 0x74 + (rand()&7);
+			p->color = 223 - (rand()&7);
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = move[j] + dir[j]*3;
+	//			p->vel[j] = dir[j]*6;
+				p->vel[j] = 0;
+			}
+		}
+		VectorAdd (move, vec, move);
+	}
+*/
+}
+#endif
+
+/*
+===============
+CL_ParticleSteamEffect
+
+Puffs with velocity along direction, with some randomness thrown in
+===============
+*/
+void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+	vec3_t		r, u;
+
+//	vectoangles2 (dir, angle_dir);
+//	AngleVectors (angle_dir, f, r, u);
+
+	MakeNormalVectors (dir, r, u);
+
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color + (rand()&7);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + magnitude*0.1*crand();
+//			p->vel[j] = dir[j]*magnitude;
+		}
+		VectorScale (dir, magnitude, p->vel);
+		d = crand()*magnitude/3;
+		VectorMA (p->vel, d, r, p->vel);
+		d = crand()*magnitude/3;
+		VectorMA (p->vel, d, u, p->vel);
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY/2;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+	}
+}
+
+void CL_ParticleSteamEffect2 (cl_sustain_t *self)
+//vec3_t org, vec3_t dir, int color, int count, int magnitude)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+	vec3_t		r, u;
+	vec3_t		dir;
+
+//	vectoangles2 (dir, angle_dir);
+//	AngleVectors (angle_dir, f, r, u);
+
+	VectorCopy (self->dir, dir);
+	MakeNormalVectors (dir, r, u);
+
+	for (i=0 ; i<self->count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = self->color + (rand()&7);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = self->org[j] + self->magnitude*0.1*crand();
+//			p->vel[j] = dir[j]*magnitude;
+		}
+		VectorScale (dir, self->magnitude, p->vel);
+		d = crand()*self->magnitude/3;
+		VectorMA (p->vel, d, r, p->vel);
+		d = crand()*self->magnitude/3;
+		VectorMA (p->vel, d, u, p->vel);
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY/2;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+	}
+	self->nextthink += self->thinkinterval;
+}
+
+/*
+===============
+CL_TrackerTrail
+===============
+*/
+void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	vec3_t		forward,right,up,angle_dir;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+	float		dist;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	VectorCopy(vec, forward);
+	vectoangles2 (forward, angle_dir);
+	AngleVectors (angle_dir, forward, right, up);
+
+	dec = 3;
+	VectorScale (vec, 3, vec);
+
+	// FIXME: this is a really silly way to have a loop
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -2.0;
+		p->color = particleColor;
+		dist = DotProduct(move, forward);
+		VectorMA(move, 8 * cos(dist), up, p->org);
+		for (j=0 ; j<3 ; j++)
+		{
+//			p->org[j] = move[j] + crand();
+			p->vel[j] = 0;
+			p->accel[j] = 0;
+		}
+		p->vel[2] = 5;
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+void CL_Tracker_Shell(vec3_t origin)
+{
+	vec3_t			dir;
+	int				i;
+	cparticle_t		*p;
+
+	for(i=0;i<300;i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = INSTANT_PARTICLE;
+		p->color = 0;
+
+		dir[0] = crand();
+		dir[1] = crand();
+		dir[2] = crand();
+		VectorNormalize(dir);
+	
+		VectorMA(origin, 40, dir, p->org);
+	}
+}
+
+void CL_MonsterPlasma_Shell(vec3_t origin)
+{
+	vec3_t			dir;
+	int				i;
+	cparticle_t		*p;
+
+	for(i=0;i<40;i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = INSTANT_PARTICLE;
+		p->color = 0xe0;
+
+		dir[0] = crand();
+		dir[1] = crand();
+		dir[2] = crand();
+		VectorNormalize(dir);
+	
+		VectorMA(origin, 10, dir, p->org);
+//		VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
+	}
+}
+
+void CL_Widowbeamout (cl_sustain_t *self)
+{
+	vec3_t			dir;
+	int				i;
+	cparticle_t		*p;
+	static int colortable[4] = {2*8,13*8,21*8,18*8};
+	float			ratio;
+
+	ratio = 1.0 - (((float)self->endtime - (float)cl.time)/2100.0);
+
+	for(i=0;i<300;i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = INSTANT_PARTICLE;
+		p->color = colortable[rand()&3];
+
+		dir[0] = crand();
+		dir[1] = crand();
+		dir[2] = crand();
+		VectorNormalize(dir);
+	
+		VectorMA(self->org, (45.0 * ratio), dir, p->org);
+//		VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
+	}
+}
+
+void CL_Nukeblast (cl_sustain_t *self)
+{
+	vec3_t			dir;
+	int				i;
+	cparticle_t		*p;
+	static int colortable[4] = {110, 112, 114, 116};
+	float			ratio;
+
+	ratio = 1.0 - (((float)self->endtime - (float)cl.time)/1000.0);
+
+	for(i=0;i<700;i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = INSTANT_PARTICLE;
+		p->color = colortable[rand()&3];
+
+		dir[0] = crand();
+		dir[1] = crand();
+		dir[2] = crand();
+		VectorNormalize(dir);
+	
+		VectorMA(self->org, (200.0 * ratio), dir, p->org);
+//		VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
+	}
+}
+
+void CL_WidowSplash (vec3_t org)
+{
+	static int colortable[4] = {2*8,13*8,21*8,18*8};
+	int			i;
+	cparticle_t	*p;
+	vec3_t		dir;
+
+	for (i=0 ; i<256 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = colortable[rand()&3];
+
+		dir[0] = crand();
+		dir[1] = crand();
+		dir[2] = crand();
+		VectorNormalize(dir);
+		VectorMA(org, 45.0, dir, p->org);
+		VectorMA(vec3_origin, 40.0, dir, p->vel);
+
+		p->accel[0] = p->accel[1] = 0;
+		p->alpha = 1.0;
+
+		p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
+	}
+
+}
+
+void CL_Tracker_Explode(vec3_t	origin)
+{
+	vec3_t			dir, backdir;
+	int				i;
+	cparticle_t		*p;
+
+	for(i=0;i<300;i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0;
+		p->color = 0;
+
+		dir[0] = crand();
+		dir[1] = crand();
+		dir[2] = crand();
+		VectorNormalize(dir);
+		VectorScale(dir, -1, backdir);
+	
+		VectorMA(origin, 64, dir, p->org);
+		VectorScale(backdir, 64, p->vel);
+	}
+	
+}
+
+/*
+===============
+CL_TagTrail
+
+===============
+*/
+void CL_TagTrail (vec3_t start, vec3_t end, float color)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	while (len >= 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.8+qfrand()*0.2);
+		p->color = color;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*16;
+			p->vel[j] = crand()*5;
+			p->accel[j] = 0;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+/*
+===============
+CL_ColorExplosionParticles
+===============
+*/
+void CL_ColorExplosionParticles (vec3_t org, int color, int run)
+{
+	int			i, j;
+	cparticle_t	*p;
+
+	for (i=0 ; i<128 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color + (rand() % run);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()%32)-16);
+			p->vel[j] = (rand()%256)-128;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -0.4 / (0.6 + qfrand()*0.2);
+	}
+}
+
+/*
+===============
+CL_ParticleSmokeEffect - like the steam effect, but unaffected by gravity
+===============
+*/
+void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+	vec3_t		r, u;
+
+	MakeNormalVectors (dir, r, u);
+
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color + (rand()&7);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + magnitude*0.1*crand();
+//			p->vel[j] = dir[j]*magnitude;
+		}
+		VectorScale (dir, magnitude, p->vel);
+		d = crand()*magnitude/3;
+		VectorMA (p->vel, d, r, p->vel);
+		d = crand()*magnitude/3;
+		VectorMA (p->vel, d, u, p->vel);
+
+		p->accel[0] = p->accel[1] = p->accel[2] = 0;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+	}
+}
+
+/*
+===============
+CL_BlasterParticles2
+
+Wall impact puffs (Green)
+===============
+*/
+void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+	int			count;
+
+	count = 40;
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color + (rand()&7);
+
+		d = rand()&15;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+			p->vel[j] = dir[j] * 30 + crand()*40;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+	}
+}
+
+/*
+===============
+CL_BlasterTrail2
+
+Green!
+===============
+*/
+void CL_BlasterTrail2 (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	// FIXME: this is a really silly way to have a loop
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.3+qfrand()*0.2);
+		p->color = 0xd0;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand();
+			p->vel[j] = crand()*5;
+			p->accel[j] = 0;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
--- /dev/null
+++ b/cl_parse.c
@@ -1,0 +1,803 @@
+// cl_parse.c  -- parse a message received from the server
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+char *svc_strings[256] =
+{
+	"svc_bad",
+
+	"svc_muzzleflash",
+	"svc_muzzlflash2",
+	"svc_temp_entity",
+	"svc_layout",
+	"svc_inventory",
+
+	"svc_nop",
+	"svc_disconnect",
+	"svc_reconnect",
+	"svc_sound",
+	"svc_print",
+	"svc_stufftext",
+	"svc_serverdata",
+	"svc_configstring",
+	"svc_spawnbaseline",	
+	"svc_centerprint",
+	"svc_download",
+	"svc_playerinfo",
+	"svc_packetentities",
+	"svc_deltapacketentities",
+	"svc_frame"
+};
+
+//=============================================================================
+
+void CL_DownloadFileName(char *dest, int destlen, char *fn)
+{
+	if (strncmp(fn, "players", 7) == 0)
+		Com_sprintf (dest, destlen, "%s/%s", BASEDIRNAME, fn);
+	else
+		Com_sprintf (dest, destlen, "%s/%s", FS_Gamedir(), fn);
+}
+
+/*
+===============
+CL_CheckOrDownloadFile
+
+Returns true if the file exists, otherwise it attempts
+to start a download from the server.
+===============
+*/
+qboolean	CL_CheckOrDownloadFile (char *filename)
+{
+	FILE *fp;
+	char	name[MAX_OSPATH];
+
+	if (strstr (filename, ".."))
+	{
+		Com_Printf ("Refusing to download a path with ..\n");
+		return true;
+	}
+
+	if (FS_LoadFile (filename, NULL) != -1)
+	{	// it exists, no need to download
+		return true;
+	}
+
+	strcpy (cls.downloadname, filename);
+
+	// download to a temp name, and only rename
+	// to the real name when done, so if interrupted
+	// a runt file wont be left
+	COM_StripExtension (cls.downloadname, cls.downloadtempname);
+	strcat (cls.downloadtempname, ".tmp");
+
+//ZOID
+	// check to see if we already have a tmp for this file, if so, try to resume
+	// open the file if not opened yet
+	CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
+
+//	FS_CreatePath (name);
+
+	fp = fopen (name, "r+b");
+	if (fp) { // it exists
+		int len;
+		fseek(fp, 0, SEEK_END);
+		len = ftell(fp);
+
+		cls.download = fp;
+
+		// give the server an offset to start the download
+		Com_Printf ("Resuming %s\n", cls.downloadname);
+		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+		MSG_WriteString (&cls.netchan.message,
+			va("download %s %i", cls.downloadname, len));
+	} else {
+		Com_Printf ("Downloading %s\n", cls.downloadname);
+		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+		MSG_WriteString (&cls.netchan.message,
+			va("download %s", cls.downloadname));
+	}
+
+	cls.downloadnumber++;
+
+	return false;
+}
+
+/*
+===============
+CL_Download_f
+
+Request a download from the server
+===============
+*/
+void	CL_Download_f (void)
+{
+	char filename[MAX_OSPATH];
+
+	if (Cmd_Argc() != 2) {
+		Com_Printf("Usage: download <filename>\n");
+		return;
+	}
+
+	Com_sprintf(filename, sizeof(filename), "%s", Cmd_Argv(1));
+
+	if (strstr (filename, ".."))
+	{
+		Com_Printf ("Refusing to download a path with ..\n");
+		return;
+	}
+
+	if (FS_LoadFile (filename, NULL) != -1)
+	{	// it exists, no need to download
+		Com_Printf("File already exists.\n");
+		return;
+	}
+
+	strcpy (cls.downloadname, filename);
+	Com_Printf ("Downloading %s\n", cls.downloadname);
+
+	// download to a temp name, and only rename
+	// to the real name when done, so if interrupted
+	// a runt file wont be left
+	COM_StripExtension (cls.downloadname, cls.downloadtempname);
+	strcat (cls.downloadtempname, ".tmp");
+
+	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+	MSG_WriteString (&cls.netchan.message,
+		va("download %s", cls.downloadname));
+
+	cls.downloadnumber++;
+}
+
+/*
+======================
+CL_RegisterSounds
+======================
+*/
+void CL_RegisterSounds (void)
+{
+	int		i;
+
+	S_BeginRegistration ();
+	CL_RegisterTEntSounds ();
+	for (i=1 ; i<MAX_SOUNDS ; i++)
+	{
+		if (!cl.configstrings[CS_SOUNDS+i][0])
+			break;
+		cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
+		Sys_SendKeyEvents ();	// pump message loop
+	}
+	S_EndRegistration ();
+}
+
+static void
+rename(char *old, char *new)
+{
+	char *p;
+	Dir d;
+
+	if((p = strrchr(new, '/')) == nil)
+		p = new;
+	else
+		p++;
+	nulldir(&d);
+	d.name = p;
+	if(dirwstat(old, &d) < 0)
+		fprint(2, "rename: %r\n");
+}
+
+/*
+=====================
+CL_ParseDownload
+
+A download message has been received from the server
+=====================
+*/
+void CL_ParseDownload (void)
+{
+	int		size, percent;
+	char	name[MAX_OSPATH];
+
+	// read the data
+	size = MSG_ReadShort (&net_message);
+	percent = MSG_ReadByte (&net_message);
+	if (size == -1)
+	{
+		Com_Printf ("Server does not have this file.\n");
+		if (cls.download)
+		{
+			// if here, we tried to resume a file but the server said no
+			fclose (cls.download);
+			cls.download = NULL;
+		}
+		CL_RequestNextDownload ();
+		return;
+	}
+
+	// open the file if not opened yet
+	if (!cls.download)
+	{
+		CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
+
+		FS_CreatePath (name);
+
+		cls.download = fopen (name, "wb");
+		if (!cls.download)
+		{
+			net_message.readcount += size;
+			Com_Printf ("Failed to open %s\n", cls.downloadtempname);
+			CL_RequestNextDownload ();
+			return;
+		}
+	}
+
+	fwrite (net_message.data + net_message.readcount, 1, size, cls.download);
+	net_message.readcount += size;
+
+	if (percent != 100)
+	{
+		// request next block
+// change display routines by zoid
+/*
+		Com_Printf (".");
+		if (10*(percent/10) != cls.downloadpercent)
+		{
+			cls.downloadpercent = 10*(percent/10);
+			Com_Printf ("%i%%", cls.downloadpercent);
+		}
+*/
+		cls.downloadpercent = percent;
+
+		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+		SZ_Print (&cls.netchan.message, "nextdl");
+	}
+	else
+	{
+		char	oldn[MAX_OSPATH];
+		char	newn[MAX_OSPATH];
+
+//		Com_Printf ("100%%\n");
+
+		fclose (cls.download);
+
+		// rename the temp file to it's final name
+		CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
+		CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
+		rename (oldn, newn);	/* FIXME */
+
+		cls.download = NULL;
+		cls.downloadpercent = 0;
+
+		// get another file if needed
+
+		CL_RequestNextDownload ();
+	}
+}
+
+
+/*
+=====================================================================
+
+  SERVER CONNECTING MESSAGES
+
+=====================================================================
+*/
+
+/*
+==================
+CL_ParseServerData
+==================
+*/
+void CL_ParseServerData (void)
+{
+	extern cvar_t	*fs_gamedirvar;
+	char	*str;
+	int		i;
+	
+	Com_DPrintf ("Serverdata packet received.\n");
+//
+// wipe the client_state_t struct
+//
+	CL_ClearState ();
+	cls.state = ca_connected;
+
+// parse protocol version number
+	i = MSG_ReadLong (&net_message);
+	cls.serverProtocol = i;
+
+	// BIG HACK to let demos from release work with the 3.0x patch!!!
+	if (Com_ServerState() && PROTOCOL_VERSION == 34)
+	{
+	}
+	else if (i != PROTOCOL_VERSION)
+		Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
+
+	cl.servercount = MSG_ReadLong (&net_message);
+	cl.attractloop = MSG_ReadByte (&net_message);
+
+	// game directory
+	str = MSG_ReadString (&net_message);
+	strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
+
+	// set gamedir
+	if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
+		Cvar_Set("game", str);
+
+	// parse player entity number
+	cl.playernum = MSG_ReadShort (&net_message);
+
+	// get the full level name
+	str = MSG_ReadString (&net_message);
+
+	if (cl.playernum == -1)
+	{	// playing a cinematic or showing a pic, not a level
+		SCR_PlayCinematic (str);
+	}
+	else
+	{
+		// seperate the printfs so the server message can have a color
+		Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+		Com_Printf ("%c%s\n", 2, str);
+
+		// need to prep refresh at next oportunity
+		cl.refresh_prepped = false;
+	}
+}
+
+/*
+==================
+CL_ParseBaseline
+==================
+*/
+void CL_ParseBaseline (void)
+{
+	entity_state_t	*es;
+	int				bits;
+	int				newnum;
+	entity_state_t	nullstate;
+
+	memset (&nullstate, 0, sizeof(nullstate));
+
+	newnum = CL_ParseEntityBits (&bits);
+	es = &cl_entities[newnum].baseline;
+	CL_ParseDelta (&nullstate, es, newnum, bits);
+}
+
+
+/*
+================
+CL_LoadClientinfo
+
+================
+*/
+void CL_LoadClientinfo (clientinfo_t *ci, char *s)
+{
+	int i;
+	char		*t;
+	char		model_name[MAX_QPATH];
+	char		skin_name[MAX_QPATH];
+	char		model_filename[MAX_QPATH];
+	char		skin_filename[MAX_QPATH];
+	char		weapon_filename[MAX_QPATH];
+
+	strncpy(ci->cinfo, s, sizeof(ci->cinfo));
+	ci->cinfo[sizeof(ci->cinfo)-1] = 0;
+
+	// isolate the player's name
+	strncpy(ci->name, s, sizeof(ci->name));
+	ci->name[sizeof(ci->name)-1] = 0;
+	t = strstr (s, "\\");
+	if (t)
+	{
+		ci->name[t-s] = 0;
+		s = t+1;
+	}
+
+	if (cl_noskins->value || *s == 0)
+	{
+		Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
+		Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/weapon.md2");
+		Com_sprintf (skin_filename, sizeof(skin_filename), "players/male/grunt.pcx");
+		Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/male/grunt_i.pcx");
+		ci->model = re.RegisterModel (model_filename);
+		memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
+		ci->weaponmodel[0] = re.RegisterModel (weapon_filename);
+		ci->skin = re.RegisterSkin (skin_filename);
+		ci->icon = re.RegisterPic (ci->iconname);
+	}
+	else
+	{
+		// isolate the model name
+		strcpy (model_name, s);
+		t = strstr(model_name, "/");
+		if (!t)
+			t = strstr(model_name, "\\");
+		if (!t)
+			t = model_name;
+		*t = 0;
+
+		// isolate the skin name
+		strcpy (skin_name, s + strlen(model_name) + 1);
+
+		// model file
+		Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
+		ci->model = re.RegisterModel (model_filename);
+		if (!ci->model)
+		{
+			strcpy(model_name, "male");
+			Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
+			ci->model = re.RegisterModel (model_filename);
+		}
+
+		// skin file
+		Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
+		ci->skin = re.RegisterSkin (skin_filename);
+
+		// if we don't have the skin and the model wasn't male,
+		// see if the male has it (this is for CTF's skins)
+ 		if (!ci->skin && cistrcmp(model_name, "male"))
+		{
+			// change model to male
+			strcpy(model_name, "male");
+			Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
+			ci->model = re.RegisterModel (model_filename);
+
+			// see if the skin exists for the male model
+			Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
+			ci->skin = re.RegisterSkin (skin_filename);
+		}
+
+		// if we still don't have a skin, it means that the male model didn't have
+		// it, so default to grunt
+		if (!ci->skin) {
+			// see if the skin exists for the male model
+			Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/grunt.pcx", model_name, skin_name);
+			ci->skin = re.RegisterSkin (skin_filename);
+		}
+
+		// weapon file
+		for (i = 0; i < num_cl_weaponmodels; i++) {
+			Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
+			ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
+			if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
+				// try male
+				Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
+				ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
+			}
+			if (!cl_vwep->value)
+				break; // only one when vwep is off
+		}
+
+		// icon file
+		Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
+		ci->icon = re.RegisterPic (ci->iconname);
+	}
+
+	// must have loaded all data types to be valud
+	if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
+	{
+		ci->skin = NULL;
+		ci->icon = NULL;
+		ci->model = NULL;
+		ci->weaponmodel[0] = NULL;
+		return;
+	}
+}
+
+/*
+================
+CL_ParseClientinfo
+
+Load the skin, icon, and model for a client
+================
+*/
+void CL_ParseClientinfo (int player)
+{
+	char			*s;
+	clientinfo_t	*ci;
+
+	s = cl.configstrings[player+CS_PLAYERSKINS];
+
+	ci = &cl.clientinfo[player];
+
+	CL_LoadClientinfo (ci, s);
+}
+
+
+/*
+================
+CL_ParseConfigString
+================
+*/
+void CL_ParseConfigString (void)
+{
+	int		i;
+	char	*s;
+
+	i = MSG_ReadShort (&net_message);
+	if (i < 0 || i >= MAX_CONFIGSTRINGS)
+		Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
+	s = MSG_ReadString(&net_message);
+	strcpy (cl.configstrings[i], s);
+
+	// do something apropriate 
+
+	if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
+		CL_SetLightstyle (i - CS_LIGHTS);
+	else if (i == CS_CDTRACK)
+	{
+		if (cl.refresh_prepped)
+			CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
+	}
+	else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS)
+	{
+		if (cl.refresh_prepped)
+		{
+			cl.model_draw[i-CS_MODELS] = re.RegisterModel (cl.configstrings[i]);
+			if (cl.configstrings[i][0] == '*')
+				cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
+			else
+				cl.model_clip[i-CS_MODELS] = NULL;
+		}
+	}
+	else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)
+	{
+		if (cl.refresh_prepped)
+			cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
+	}
+	else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS)
+	{
+		if (cl.refresh_prepped)
+			cl.image_precache[i-CS_IMAGES] = re.RegisterPic (cl.configstrings[i]);
+	}
+	else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS)
+	{
+		if (cl.refresh_prepped)
+			CL_ParseClientinfo (i-CS_PLAYERSKINS);
+	}
+}
+
+
+/*
+=====================================================================
+
+ACTION MESSAGES
+
+=====================================================================
+*/
+
+/*
+==================
+CL_ParseStartSoundPacket
+==================
+*/
+void CL_ParseStartSoundPacket(void)
+{
+    vec3_t  pos_v;
+	float	*pos;
+    int 	channel, ent;
+    int 	sound_num;
+    float 	volume;
+    float 	attenuation;  
+	int		flags;
+	float	ofs;
+
+	flags = MSG_ReadByte (&net_message);
+	sound_num = MSG_ReadByte (&net_message);
+
+    if (flags & SND_VOLUME)
+		volume = MSG_ReadByte (&net_message) / 255.0;
+	else
+		volume = DEFAULT_SOUND_PACKET_VOLUME;
+	
+    if (flags & SND_ATTENUATION)
+		attenuation = MSG_ReadByte (&net_message) / 64.0;
+	else
+		attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;	
+
+    if (flags & SND_OFFSET)
+		ofs = MSG_ReadByte (&net_message) / 1000.0;
+	else
+		ofs = 0;
+
+	if (flags & SND_ENT)
+	{	// entity reletive
+		channel = MSG_ReadShort(&net_message); 
+		ent = channel>>3;
+		if (ent > MAX_EDICTS)
+			Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
+
+		channel &= 7;
+	}
+	else
+	{
+		ent = 0;
+		channel = 0;
+	}
+
+	if (flags & SND_POS)
+	{	// positioned in space
+		MSG_ReadPos (&net_message, pos_v);
+ 
+		pos = pos_v;
+	}
+	else	// use entity number
+		pos = NULL;
+
+	if (!cl.sound_precache[sound_num])
+		return;
+
+	S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
+}       
+
+
+void SHOWNET(char *s)
+{
+	if (cl_shownet->value>=2)
+		Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
+}
+
+/*
+=====================
+CL_ParseServerMessage
+=====================
+*/
+void CL_ParseServerMessage (void)
+{
+	int			cmd;
+	char		*s;
+	int			i;
+
+//
+// if recording demos, copy the message out
+//
+	if (cl_shownet->value == 1)
+		Com_Printf ("%i ",net_message.cursize);
+	else if (cl_shownet->value >= 2)
+		Com_Printf ("------------------\n");
+
+
+//
+// parse the message
+//
+	while (1)
+	{
+		if (net_message.readcount > net_message.cursize)
+		{
+			Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
+			break;
+		}
+
+		cmd = MSG_ReadByte (&net_message);
+
+		if (cmd == -1)
+		{
+			SHOWNET("END OF MESSAGE");
+			break;
+		}
+
+		if (cl_shownet->value>=2)
+		{
+			if (!svc_strings[cmd])
+				Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
+			else
+				SHOWNET(svc_strings[cmd]);
+		}
+	
+	// other commands
+		switch (cmd)
+		{
+		default:
+			Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
+			break;
+			
+		case svc_nop:
+//			Com_Printf ("svc_nop\n");
+			break;
+			
+		case svc_disconnect:
+			Com_Error (ERR_DISCONNECT,"Server disconnected\n");
+			break;
+
+		case svc_reconnect:
+			Com_Printf ("Server disconnected, reconnecting\n");
+			if (cls.download) {
+				//ZOID, close download
+				fclose (cls.download);
+				cls.download = NULL;
+			}
+			cls.state = ca_connecting;
+			cls.connect_time = -99999;	// CL_CheckForResend() will fire immediately
+			break;
+
+		case svc_print:
+			i = MSG_ReadByte (&net_message);
+			if (i == PRINT_CHAT)
+			{
+				S_StartLocalSound ("misc/talk.wav");
+				con.ormask = 128;
+			}
+			Com_Printf ("%s", MSG_ReadString (&net_message));
+			con.ormask = 0;
+			break;
+			
+		case svc_centerprint:
+			SCR_CenterPrint (MSG_ReadString (&net_message));
+			break;
+			
+		case svc_stufftext:
+			s = MSG_ReadString (&net_message);
+			Com_DPrintf ("stufftext: %s\n", s);
+			Cbuf_AddText (s);
+			break;
+			
+		case svc_serverdata:
+			Cbuf_Execute ();		// make sure any stuffed commands are done
+			CL_ParseServerData ();
+			break;
+			
+		case svc_configstring:
+			CL_ParseConfigString ();
+			break;
+			
+		case svc_sound:
+			CL_ParseStartSoundPacket();
+			break;
+			
+		case svc_spawnbaseline:
+			CL_ParseBaseline ();
+			break;
+
+		case svc_temp_entity:
+			CL_ParseTEnt ();
+			break;
+
+		case svc_muzzleflash:
+			CL_ParseMuzzleFlash ();
+			break;
+
+		case svc_muzzleflash2:
+			CL_ParseMuzzleFlash2 ();
+			break;
+
+		case svc_download:
+			CL_ParseDownload ();
+			break;
+
+		case svc_frame:
+			CL_ParseFrame ();
+			break;
+
+		case svc_inventory:
+			CL_ParseInventory ();
+			break;
+
+		case svc_layout:
+			s = MSG_ReadString (&net_message);
+			strncpy (cl.layout, s, sizeof(cl.layout)-1);
+			break;
+
+		case svc_playerinfo:
+		case svc_packetentities:
+		case svc_deltapacketentities:
+			Com_Error (ERR_DROP, "Out of place frame data");
+			break;
+		}
+	}
+
+	CL_AddNetgraph ();
+
+	//
+	// we don't know if it is ok to save a demo message until
+	// after we have parsed the frame
+	//
+	if (cls.demorecording && !cls.demowaiting)
+		CL_WriteDemoMessage ();
+
+}
+
+
--- /dev/null
+++ b/cl_pred.c
@@ -1,0 +1,260 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+/*
+===================
+CL_CheckPredictionError
+===================
+*/
+void CL_CheckPredictionError (void)
+{
+	int		frame;
+	int		delta[3];
+	int		i;
+	int		len;
+
+	if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
+		return;
+
+	// calculate the last usercmd_t we sent that the server has processed
+	frame = cls.netchan.incoming_acknowledged;
+	frame &= (CMD_BACKUP-1);
+
+	// compare what the server returned with what we had predicted it to be
+	VectorSubtract (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame], delta);
+
+	// save the prediction error for interpolation
+	len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
+	if (len > 640)	// 80 world units
+	{	// a teleport or something
+		VectorClear (cl.prediction_error);
+	}
+	else
+	{
+		if (cl_showmiss->value && (delta[0] || delta[1] || delta[2]) )
+			Com_Printf ("prediction miss on %i: %i\n", cl.frame.serverframe, 
+			delta[0] + delta[1] + delta[2]);
+
+		VectorCopy (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame]);
+
+		// save for error itnerpolation
+		for (i=0 ; i<3 ; i++)
+			cl.prediction_error[i] = delta[i]*0.125;
+	}
+}
+
+
+/*
+====================
+CL_ClipMoveToEntities
+
+====================
+*/
+void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
+{
+	int			i, x, zd, zu;
+	trace_t		trace;
+	int			headnode;
+	float		*angles;
+	entity_state_t	*ent;
+	int			num;
+	cmodel_t		*cmodel;
+	vec3_t		bmins, bmaxs;
+
+	for (i=0 ; i<cl.frame.num_entities ; i++)
+	{
+		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+		ent = &cl_parse_entities[num];
+
+		if (!ent->solid)
+			continue;
+
+		if (ent->number == cl.playernum+1)
+			continue;
+
+		if (ent->solid == 31)
+		{	// special value for bmodel
+			cmodel = cl.model_clip[ent->modelindex];
+			if (!cmodel)
+				continue;
+			headnode = cmodel->headnode;
+			angles = ent->angles;
+		}
+		else
+		{	// encoded bbox
+			x = 8*(ent->solid & 31);
+			zd = 8*((ent->solid>>5) & 31);
+			zu = 8*((ent->solid>>10) & 63) - 32;
+
+			bmins[0] = bmins[1] = -x;
+			bmaxs[0] = bmaxs[1] = x;
+			bmins[2] = -zd;
+			bmaxs[2] = zu;
+
+			headnode = CM_HeadnodeForBox (bmins, bmaxs);
+			angles = vec3_origin;	// boxes don't rotate
+		}
+
+		if (tr->allsolid)
+			return;
+
+		trace = CM_TransformedBoxTrace (start, end,
+			mins, maxs, headnode,  MASK_PLAYERSOLID,
+			ent->origin, angles);
+
+		if (trace.allsolid || trace.startsolid ||
+		trace.fraction < tr->fraction)
+		{
+			trace.ent = (edict_t *)ent;
+		 	if (tr->startsolid)
+			{
+				*tr = trace;
+				tr->startsolid = true;
+			}
+			else
+				*tr = trace;
+		}
+		else if (trace.startsolid)
+			tr->startsolid = true;
+	}
+}
+
+
+/*
+================
+CL_PMTrace
+================
+*/
+trace_t		CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
+{
+	trace_t	t;
+
+	// check against world
+	t = CM_BoxTrace (start, end, mins, maxs, 0, MASK_PLAYERSOLID);
+	if (t.fraction < 1.0)
+		t.ent = (edict_t *)1;
+
+	// check all other solid models
+	CL_ClipMoveToEntities (start, mins, maxs, end, &t);
+
+	return t;
+}
+
+int		CL_PMpointcontents (vec3_t point)
+{
+	int			i;
+	entity_state_t	*ent;
+	int			num;
+	cmodel_t		*cmodel;
+	int			contents;
+
+	contents = CM_PointContents (point, 0);
+
+	for (i=0 ; i<cl.frame.num_entities ; i++)
+	{
+		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+		ent = &cl_parse_entities[num];
+
+		if (ent->solid != 31) // special value for bmodel
+			continue;
+
+		cmodel = cl.model_clip[ent->modelindex];
+		if (!cmodel)
+			continue;
+
+		contents |= CM_TransformedPointContents (point, cmodel->headnode, ent->origin, ent->angles);
+	}
+
+	return contents;
+}
+
+
+/*
+=================
+CL_PredictMovement
+
+Sets cl.predicted_origin and cl.predicted_angles
+=================
+*/
+void CL_PredictMovement (void)
+{
+	int			ack, current;
+	int			frame;
+	int			oldframe;
+	usercmd_t	*cmd;
+	pmove_t		pm;
+	int			i;
+	int			step;
+	int			oldz;
+
+	if (cls.state != ca_active)
+		return;
+
+	if (cl_paused->value)
+		return;
+
+	if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
+	{	// just set angles
+		for (i=0 ; i<3 ; i++)
+		{
+			cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]);
+		}
+		return;
+	}
+
+	ack = cls.netchan.incoming_acknowledged;
+	current = cls.netchan.outgoing_sequence;
+
+	// if we are too far out of date, just freeze
+	if (current - ack >= CMD_BACKUP)
+	{
+		if (cl_showmiss->value)
+			Com_Printf ("exceeded CMD_BACKUP\n");
+		return;	
+	}
+
+	// copy current state to pmove
+	memset (&pm, 0, sizeof(pm));
+	pm.trace = CL_PMTrace;
+	pm.pointcontents = CL_PMpointcontents;
+
+	pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
+
+	pm.s = cl.frame.playerstate.pmove;
+
+//	SCR_DebugGraph (current - ack - 1, 0);
+
+	// run frames
+	while (++ack < current)
+	{
+		frame = ack & (CMD_BACKUP-1);
+		cmd = &cl.cmds[frame];
+
+		pm.cmd = *cmd;
+		Pmove (&pm);
+
+		// save for debug checking
+		VectorCopy (pm.s.origin, cl.predicted_origins[frame]);
+	}
+
+	oldframe = (ack-2) & (CMD_BACKUP-1);
+	oldz = cl.predicted_origins[oldframe][2];
+	step = pm.s.origin[2] - oldz;
+	if (step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND) )
+	{
+		cl.predicted_step = step * 0.125;
+		cl.predicted_step_time = cls.realtime - cls.frametime * 500;
+	}
+
+
+	// copy results out for rendering
+	cl.predicted_origin[0] = pm.s.origin[0]*0.125;
+	cl.predicted_origin[1] = pm.s.origin[1]*0.125;
+	cl.predicted_origin[2] = pm.s.origin[2]*0.125;
+
+	VectorCopy (pm.viewangles, cl.predicted_angles);
+}
--- /dev/null
+++ b/cl_scrn.c
@@ -1,0 +1,1368 @@
+// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
+
+/*
+
+  full screen console
+  put up loading plaque
+  blanked background with loading plaque
+  blanked background with menu
+  cinematics
+  full screen image for quit and victory
+
+  end of unit intermissions
+
+  */
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+float		scr_con_current;	// aproaches scr_conlines at scr_conspeed
+float		scr_conlines;		// 0.0 to 1.0 lines of console to display
+
+qboolean	scr_initialized;		// ready to draw
+
+int			scr_draw_loading;
+
+vrect_t		scr_vrect;		// position of render window on screen
+
+
+cvar_t		*scr_viewsize;
+cvar_t		*scr_conspeed;
+cvar_t		*scr_centertime;
+cvar_t		*scr_showturtle;
+cvar_t		*scr_showpause;
+cvar_t		*scr_printspeed;
+
+cvar_t		*scr_netgraph;
+cvar_t		*scr_timegraph;
+cvar_t		*scr_debuggraph;
+cvar_t		*scr_graphheight;
+cvar_t		*scr_graphscale;
+cvar_t		*scr_graphshift;
+cvar_t		*scr_drawall;
+
+typedef struct
+{
+	int		x1, y1, x2, y2;
+} dirty_t;
+
+dirty_t		scr_dirty, scr_old_dirty[2];
+
+char		crosshair_pic[MAX_QPATH];
+int			crosshair_width, crosshair_height;
+
+void SCR_TimeRefresh_f (void);
+void SCR_Loading_f (void);
+
+
+/*
+===============================================================================
+
+BAR GRAPHS
+
+===============================================================================
+*/
+
+/*
+==============
+CL_AddNetgraph
+
+A new packet was just parsed
+==============
+*/
+void CL_AddNetgraph (void)
+{
+	int		i;
+	int		in;
+	int		ping;
+
+	// if using the debuggraph for something else, don't
+	// add the net lines
+	if (scr_debuggraph->value || scr_timegraph->value)
+		return;
+
+	for (i=0 ; i<cls.netchan.dropped ; i++)
+		SCR_DebugGraph (30, 0x40);
+
+	for (i=0 ; i<cl.surpressCount ; i++)
+		SCR_DebugGraph (30, 0xdf);
+
+	// see what the latency was on this packet
+	in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
+	ping = cls.realtime - cl.cmd_time[in];
+	ping /= 30;
+	if (ping > 30)
+		ping = 30;
+	SCR_DebugGraph (ping, 0xd0);
+}
+
+
+typedef struct
+{
+	float	value;
+	int		color;
+} graphsamp_t;
+
+static	int			current;
+static	graphsamp_t	values[1024];
+
+/* this is in the client code, but can be used for debugging from server */
+void SCR_DebugGraph (float value, int color)
+{
+	values[current&1023].value = value;
+	values[current&1023].color = color;
+	current++;
+}
+
+/*
+==============
+SCR_DrawDebugGraph
+==============
+*/
+void SCR_DrawDebugGraph (void)
+{
+	int		a, x, y, w, i, h;
+	float	v;
+	int		color;
+
+	//
+	// draw the graph
+	//
+	w = scr_vrect.width;
+
+	x = scr_vrect.x;
+	y = scr_vrect.y+scr_vrect.height;
+	re.DrawFill (x, y-scr_graphheight->value,
+		w, scr_graphheight->value, 8);
+
+	for (a=0 ; a<w ; a++)
+	{
+		i = (current-1-a+1024) & 1023;
+		v = values[i].value;
+		color = values[i].color;
+		v = v*scr_graphscale->value + scr_graphshift->value;
+		
+		if (v < 0)
+			v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
+		h = (int)v % (int)scr_graphheight->value;
+		re.DrawFill (x+w-1-a, y - h, 1,	h, color);
+	}
+}
+
+/*
+===============================================================================
+
+CENTER PRINTING
+
+===============================================================================
+*/
+
+char		scr_centerstring[1024];
+float		scr_centertime_start;	// for slow victory printing
+float		scr_centertime_off;
+int			scr_center_lines;
+int			scr_erase_center;
+
+/*
+==============
+SCR_CenterPrint
+
+Called for important messages that should stay in the center of the screen
+for a few moments
+==============
+*/
+void SCR_CenterPrint (char *str)
+{
+	char	*s;
+	char	line[64];
+	int		i, j, l;
+
+	strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
+	scr_centertime_off = scr_centertime->value;
+	scr_centertime_start = cl.time;
+
+	// count the number of lines for centering
+	scr_center_lines = 1;
+	s = str;
+	while (*s)
+	{
+		if (*s == '\n')
+			scr_center_lines++;
+		s++;
+	}
+
+	// echo it to the console
+	Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+
+	s = str;
+	do	
+	{
+	// scan the width of the line
+		for (l=0 ; l<40 ; l++)
+			if (s[l] == '\n' || !s[l])
+				break;
+		for (i=0 ; i<(40-l)/2 ; i++)
+			line[i] = ' ';
+
+		for (j=0 ; j<l ; j++)
+		{
+			line[i++] = s[j];
+		}
+
+		line[i] = '\n';
+		line[i+1] = 0;
+
+		Com_Printf ("%s", line);
+
+		while (*s && *s != '\n')
+			s++;
+
+		if (!*s)
+			break;
+		s++;		// skip the \n
+	} while (1);
+	Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+	Con_ClearNotify ();
+}
+
+
+void SCR_DrawCenterString (void)
+{
+	char	*start;
+	int		l;
+	int		j;
+	int		x, y;
+	int		remaining;
+
+// the finale prints the characters one at a time
+	remaining = 9999;
+
+	scr_erase_center = 0;
+	start = scr_centerstring;
+
+	if (scr_center_lines <= 4)
+		y = vid.height*0.35;
+	else
+		y = 48;
+
+	do	
+	{
+	// scan the width of the line
+		for (l=0 ; l<40 ; l++)
+			if (start[l] == '\n' || !start[l])
+				break;
+		x = (vid.width - l*8)/2;
+		SCR_AddDirtyPoint (x, y);
+		for (j=0 ; j<l ; j++, x+=8)
+		{
+			re.DrawChar (x, y, start[j]);	
+			if (!remaining--)
+				return;
+		}
+		SCR_AddDirtyPoint (x, y+8);
+			
+		y += 8;
+
+		while (*start && *start != '\n')
+			start++;
+
+		if (!*start)
+			break;
+		start++;		// skip the \n
+	} while (1);
+}
+
+void SCR_CheckDrawCenterString (void)
+{
+	scr_centertime_off -= cls.frametime;
+	
+	if (scr_centertime_off <= 0)
+		return;
+
+	SCR_DrawCenterString ();
+}
+
+//=============================================================================
+
+/*
+=================
+SCR_CalcVrect
+
+Sets scr_vrect, the coordinates of the rendered window
+=================
+*/
+static void SCR_CalcVrect (void)
+{
+	int		size;
+
+	// bound viewsize
+	if (scr_viewsize->value < 40)
+		Cvar_Set ("viewsize","40");
+	if (scr_viewsize->value > 100)
+		Cvar_Set ("viewsize","100");
+
+	size = scr_viewsize->value;
+
+	scr_vrect.width = vid.width*size/100;
+	scr_vrect.width &= ~7;
+
+	scr_vrect.height = vid.height*size/100;
+	scr_vrect.height &= ~1;
+
+	scr_vrect.x = (vid.width - scr_vrect.width)/2;
+	scr_vrect.y = (vid.height - scr_vrect.height)/2;
+}
+
+
+/*
+=================
+SCR_SizeUp_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeUp_f (void)
+{
+	Cvar_SetValue ("viewsize",scr_viewsize->value+10);
+}
+
+
+/*
+=================
+SCR_SizeDown_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeDown_f (void)
+{
+	Cvar_SetValue ("viewsize",scr_viewsize->value-10);
+}
+
+/*
+=================
+SCR_Sky_f
+
+Set a specific sky and rotation speed
+=================
+*/
+void SCR_Sky_f (void)
+{
+	float	rotate;
+	vec3_t	axis;
+
+	if (Cmd_Argc() < 2)
+	{
+		Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
+		return;
+	}
+	if (Cmd_Argc() > 2)
+		rotate = atof(Cmd_Argv(2));
+	else
+		rotate = 0;
+	if (Cmd_Argc() == 6)
+	{
+		axis[0] = atof(Cmd_Argv(3));
+		axis[1] = atof(Cmd_Argv(4));
+		axis[2] = atof(Cmd_Argv(5));
+	}
+	else
+	{
+		axis[0] = 0;
+		axis[1] = 0;
+		axis[2] = 1;
+	}
+
+	re.SetSky (Cmd_Argv(1), rotate, axis);
+}
+
+//============================================================================
+
+/*
+==================
+SCR_Init
+==================
+*/
+void SCR_Init (void)
+{
+	scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
+	scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
+	scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
+	scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
+	scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
+	scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
+	scr_netgraph = Cvar_Get ("netgraph", "0", 0);
+	scr_timegraph = Cvar_Get ("timegraph", "0", 0);
+	scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
+	scr_graphheight = Cvar_Get ("graphheight", "32", 0);
+	scr_graphscale = Cvar_Get ("graphscale", "1", 0);
+	scr_graphshift = Cvar_Get ("graphshift", "0", 0);
+	scr_drawall = Cvar_Get ("scr_drawall", "0", 0);
+
+//
+// register our commands
+//
+	Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
+	Cmd_AddCommand ("loading",SCR_Loading_f);
+	Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
+	Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
+	Cmd_AddCommand ("sky",SCR_Sky_f);
+
+	scr_initialized = true;
+}
+
+
+/*
+==============
+SCR_DrawNet
+==============
+*/
+void SCR_DrawNet (void)
+{
+	if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged 
+		< CMD_BACKUP-1)
+		return;
+
+	re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");
+}
+
+/*
+==============
+SCR_DrawPause
+==============
+*/
+void SCR_DrawPause (void)
+{
+	int		w, h;
+
+	if (!scr_showpause->value)		// turn off for screenshots
+		return;
+
+	if (!cl_paused->value)
+		return;
+
+	re.DrawGetPicSize (&w, &h, "pause");
+	re.DrawPic ((vid.width-w)/2, vid.height/2 + 8, "pause");
+}
+
+/*
+==============
+SCR_DrawLoading
+==============
+*/
+void SCR_DrawLoading (void)
+{
+	int		w, h;
+		
+	if (!scr_draw_loading)
+		return;
+
+	scr_draw_loading = false;
+	re.DrawGetPicSize (&w, &h, "loading");
+	re.DrawPic ((vid.width-w)/2, (vid.height-h)/2, "loading");
+}
+
+//=============================================================================
+
+/*
+==================
+SCR_RunConsole
+
+Scroll it up or down
+==================
+*/
+void SCR_RunConsole (void)
+{
+// decide on the height of the console
+	if (cls.key_dest == key_console)
+		scr_conlines = 0.5;		// half screen
+	else
+		scr_conlines = 0;				// none visible
+	
+	if (scr_conlines < scr_con_current)
+	{
+		scr_con_current -= scr_conspeed->value*cls.frametime;
+		if (scr_conlines > scr_con_current)
+			scr_con_current = scr_conlines;
+
+	}
+	else if (scr_conlines > scr_con_current)
+	{
+		scr_con_current += scr_conspeed->value*cls.frametime;
+		if (scr_conlines < scr_con_current)
+			scr_con_current = scr_conlines;
+	}
+
+}
+
+/*
+==================
+SCR_DrawConsole
+==================
+*/
+void SCR_DrawConsole (void)
+{
+	Con_CheckResize ();
+	
+	if (cls.state == ca_disconnected || cls.state == ca_connecting)
+	{	// forced full screen console
+		Con_DrawConsole (1.0);
+		return;
+	}
+
+	if (cls.state != ca_active || !cl.refresh_prepped)
+	{	// connected, but can't render
+		Con_DrawConsole (0.5);
+		re.DrawFill (0, vid.height/2, vid.width, vid.height/2, 0);
+		return;
+	}
+
+	if (scr_con_current)
+	{
+		Con_DrawConsole (scr_con_current);
+	}
+	else
+	{
+		if (cls.key_dest == key_game || cls.key_dest == key_message)
+			Con_DrawNotify ();	// only draw notify in game
+	}
+}
+
+//=============================================================================
+
+/*
+================
+SCR_BeginLoadingPlaque
+================
+*/
+void SCR_BeginLoadingPlaque (void)
+{
+	S_StopAllSounds ();
+	cl.sound_prepped = false;		// don't play ambients
+	CDAudio_Stop ();
+	if (cls.disable_screen)
+		return;
+	if (developer->value)
+		return;
+	if (cls.state == ca_disconnected)
+		return;	// if at console, don't bring up the plaque
+	if (cls.key_dest == key_console)
+		return;
+	if (cl.cinematictime > 0)
+		scr_draw_loading = 2;	// clear to balack first
+	else
+		scr_draw_loading = 1;
+	SCR_UpdateScreen ();
+	cls.disable_screen = Sys_Milliseconds ();
+	cls.disable_servercount = cl.servercount;
+}
+
+/*
+================
+SCR_EndLoadingPlaque
+================
+*/
+void SCR_EndLoadingPlaque (void)
+{
+	cls.disable_screen = 0;
+	Con_ClearNotify ();
+}
+
+/*
+================
+SCR_Loading_f
+================
+*/
+void SCR_Loading_f (void)
+{
+	SCR_BeginLoadingPlaque ();
+}
+
+int
+entitycmpfnc(entity_t *a, entity_t *b)
+{
+	/* all other models are sorted by model then skin */
+	if(a->model == b->model)
+		return (uintptr)a->skin - (uintptr)b->skin;
+	else
+		return (uintptr)a->model - (uintptr)b->model;
+}
+
+void SCR_TimeRefresh_f (void)
+{
+	int		i;
+	int		start, stop;
+	float	time;
+
+	if ( cls.state != ca_active )
+		return;
+
+	start = Sys_Milliseconds ();
+
+	if (Cmd_Argc() == 2)
+	{	// run without page flipping
+		re.BeginFrame( 0 );
+		for (i=0 ; i<128 ; i++)
+		{
+			cl.refdef.viewangles[1] = i/128.0*360.0;
+			re.RenderFrame (&cl.refdef);
+		}
+		re.EndFrame();
+	}
+	else
+	{
+		for (i=0 ; i<128 ; i++)
+		{
+			cl.refdef.viewangles[1] = i/128.0*360.0;
+
+			re.BeginFrame( 0 );
+			re.RenderFrame (&cl.refdef);
+			re.EndFrame();
+		}
+	}
+
+	stop = Sys_Milliseconds ();
+	time = (stop-start)/1000.0;
+	Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
+}
+
+/*
+=================
+SCR_AddDirtyPoint
+=================
+*/
+void SCR_AddDirtyPoint (int x, int y)
+{
+	if (x < scr_dirty.x1)
+		scr_dirty.x1 = x;
+	if (x > scr_dirty.x2)
+		scr_dirty.x2 = x;
+	if (y < scr_dirty.y1)
+		scr_dirty.y1 = y;
+	if (y > scr_dirty.y2)
+		scr_dirty.y2 = y;
+}
+
+void SCR_DirtyScreen (void)
+{
+	SCR_AddDirtyPoint (0, 0);
+	SCR_AddDirtyPoint (vid.width-1, vid.height-1);
+}
+
+/*
+==============
+SCR_TileClear
+
+Clear any parts of the tiled background that were drawn on last frame
+==============
+*/
+void SCR_TileClear (void)
+{
+	int		i;
+	int		top, bottom, left, right;
+	dirty_t	clear;
+
+	if (scr_drawall->value)
+		SCR_DirtyScreen ();	// for power vr or broken page flippers...
+
+	if (scr_con_current == 1.0)
+		return;		// full screen console
+	if (scr_viewsize->value == 100)
+		return;		// full screen rendering
+	if (cl.cinematictime > 0)
+		return;		// full screen cinematic
+
+	// erase rect will be the union of the past three frames
+	// so tripple buffering works properly
+	clear = scr_dirty;
+	for (i=0 ; i<2 ; i++)
+	{
+		if (scr_old_dirty[i].x1 < clear.x1)
+			clear.x1 = scr_old_dirty[i].x1;
+		if (scr_old_dirty[i].x2 > clear.x2)
+			clear.x2 = scr_old_dirty[i].x2;
+		if (scr_old_dirty[i].y1 < clear.y1)
+			clear.y1 = scr_old_dirty[i].y1;
+		if (scr_old_dirty[i].y2 > clear.y2)
+			clear.y2 = scr_old_dirty[i].y2;
+	}
+
+	scr_old_dirty[1] = scr_old_dirty[0];
+	scr_old_dirty[0] = scr_dirty;
+
+	scr_dirty.x1 = 9999;
+	scr_dirty.x2 = -9999;
+	scr_dirty.y1 = 9999;
+	scr_dirty.y2 = -9999;
+
+	// don't bother with anything convered by the console)
+	top = scr_con_current*vid.height;
+	if (top >= clear.y1)
+		clear.y1 = top;
+
+	if (clear.y2 <= clear.y1)
+		return;		// nothing disturbed
+
+	top = scr_vrect.y;
+	bottom = top + scr_vrect.height-1;
+	left = scr_vrect.x;
+	right = left + scr_vrect.width-1;
+
+	if (clear.y1 < top)
+	{	// clear above view screen
+		i = clear.y2 < top-1 ? clear.y2 : top-1;
+		re.DrawTileClear (clear.x1 , clear.y1,
+			clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
+		clear.y1 = top;
+	}
+	if (clear.y2 > bottom)
+	{	// clear below view screen
+		i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
+		re.DrawTileClear (clear.x1, i,
+			clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
+		clear.y2 = bottom;
+	}
+	if (clear.x1 < left)
+	{	// clear left of view screen
+		i = clear.x2 < left-1 ? clear.x2 : left-1;
+		re.DrawTileClear (clear.x1, clear.y1,
+			i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
+		clear.x1 = left;
+	}
+	if (clear.x2 > right)
+	{	// clear left of view screen
+		i = clear.x1 > right+1 ? clear.x1 : right+1;
+		re.DrawTileClear (i, clear.y1,
+			clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
+		clear.x2 = right;
+	}
+
+}
+
+
+//===============================================================
+
+
+#define STAT_MINUS		10	// num frame for '-' stats digit
+char		*sb_nums[2][11] = 
+{
+	{"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
+	"num_6", "num_7", "num_8", "num_9", "num_minus"},
+	{"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
+	"anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
+};
+
+#define	ICON_WIDTH	24
+#define	ICON_HEIGHT	24
+#define	CHAR_WIDTH	16
+#define	ICON_SPACE	8
+
+
+
+/*
+================
+SizeHUDString
+
+Allow embedded \n in the string
+================
+*/
+void SizeHUDString (char *string, int *w, int *h)
+{
+	int		lines, width, current;
+
+	lines = 1;
+	width = 0;
+
+	current = 0;
+	while (*string)
+	{
+		if (*string == '\n')
+		{
+			lines++;
+			current = 0;
+		}
+		else
+		{
+			current++;
+			if (current > width)
+				width = current;
+		}
+		string++;
+	}
+
+	*w = width * 8;
+	*h = lines * 8;
+}
+
+void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)
+{
+	int		margin;
+	char	line[1024];
+	int		width;
+	int		i;
+
+	margin = x;
+
+	while (*string)
+	{
+		// scan out one line of text from the string
+		width = 0;
+		while (*string && *string != '\n')
+			line[width++] = *string++;
+		line[width] = 0;
+
+		if (centerwidth)
+			x = margin + (centerwidth - width*8)/2;
+		else
+			x = margin;
+		for (i=0 ; i<width ; i++)
+		{
+			re.DrawChar (x, y, line[i]^xor);
+			x += 8;
+		}
+		if (*string)
+		{
+			string++;	// skip the \n
+			y += 8;
+		}
+	}
+}
+
+
+/*
+==============
+SCR_DrawField
+==============
+*/
+void SCR_DrawField (int x, int y, int color, int width, int value)
+{
+	char	num[16], *ptr;
+	int		l;
+	int		frame;
+
+	if (width < 1)
+		return;
+
+	// draw number string
+	if (width > 5)
+		width = 5;
+
+	SCR_AddDirtyPoint (x, y);
+	SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);
+
+	Com_sprintf (num, sizeof(num), "%i", value);
+	l = strlen(num);
+	if (l > width)
+		l = width;
+	x += 2 + CHAR_WIDTH*(width - l);
+
+	ptr = num;
+	while (*ptr && l)
+	{
+		if (*ptr == '-')
+			frame = STAT_MINUS;
+		else
+			frame = *ptr -'0';
+
+		re.DrawPic (x,y,sb_nums[color][frame]);
+		x += CHAR_WIDTH;
+		ptr++;
+		l--;
+	}
+}
+
+
+/*
+===============
+SCR_TouchPics
+
+Allows rendering code to cache all needed sbar graphics
+===============
+*/
+void SCR_TouchPics (void)
+{
+	int		i, j;
+
+	for (i=0 ; i<2 ; i++)
+		for (j=0 ; j<11 ; j++)
+			re.RegisterPic (sb_nums[i][j]);
+
+	if (crosshair->value)
+	{
+		if (crosshair->value > 3 || crosshair->value < 0)
+			crosshair->value = 3;
+
+		Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));
+		re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
+		if (!crosshair_width)
+			crosshair_pic[0] = 0;
+	}
+}
+
+/*
+================
+SCR_ExecuteLayoutString 
+
+================
+*/
+void SCR_ExecuteLayoutString (char *s)
+{
+	int		x, y;
+	int		value;
+	char	*token;
+	int		width;
+	int		index;
+	clientinfo_t	*ci;
+
+	if (cls.state != ca_active || !cl.refresh_prepped)
+		return;
+
+	if (!s[0])
+		return;
+
+	x = 0;
+	y = 0;
+
+	while (s)
+	{
+		token = COM_Parse (&s);
+		if (!strcmp(token, "xl"))
+		{
+			token = COM_Parse (&s);
+			x = atoi(token);
+			continue;
+		}
+		if (!strcmp(token, "xr"))
+		{
+			token = COM_Parse (&s);
+			x = vid.width + atoi(token);
+			continue;
+		}
+		if (!strcmp(token, "xv"))
+		{
+			token = COM_Parse (&s);
+			x = vid.width/2 - 160 + atoi(token);
+			continue;
+		}
+
+		if (!strcmp(token, "yt"))
+		{
+			token = COM_Parse (&s);
+			y = atoi(token);
+			continue;
+		}
+		if (!strcmp(token, "yb"))
+		{
+			token = COM_Parse (&s);
+			y = vid.height + atoi(token);
+			continue;
+		}
+		if (!strcmp(token, "yv"))
+		{
+			token = COM_Parse (&s);
+			y = vid.height/2 - 120 + atoi(token);
+			continue;
+		}
+
+		if (!strcmp(token, "pic"))
+		{	// draw a pic from a stat number
+			token = COM_Parse (&s);
+			value = cl.frame.playerstate.stats[atoi(token)];
+			if (value >= MAX_IMAGES)
+				Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
+			if (cl.configstrings[CS_IMAGES+value])
+			{
+				SCR_AddDirtyPoint (x, y);
+				SCR_AddDirtyPoint (x+23, y+23);
+				re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
+			}
+			continue;
+		}
+
+		if (!strcmp(token, "client"))
+		{	// draw a deathmatch client block
+			int		score, ping, time;
+
+			token = COM_Parse (&s);
+			x = vid.width/2 - 160 + atoi(token);
+			token = COM_Parse (&s);
+			y = vid.height/2 - 120 + atoi(token);
+			SCR_AddDirtyPoint (x, y);
+			SCR_AddDirtyPoint (x+159, y+31);
+
+			token = COM_Parse (&s);
+			value = atoi(token);
+			if (value >= MAX_CLIENTS || value < 0)
+				Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
+			ci = &cl.clientinfo[value];
+
+			token = COM_Parse (&s);
+			score = atoi(token);
+
+			token = COM_Parse (&s);
+			ping = atoi(token);
+
+			token = COM_Parse (&s);
+			time = atoi(token);
+
+			DrawAltString (x+32, y, ci->name);
+			DrawString (x+32, y+8,  "Score: ");
+			DrawAltString (x+32+7*8, y+8,  va("%i", score));
+			DrawString (x+32, y+16, va("Ping:  %i", ping));
+			DrawString (x+32, y+24, va("Time:  %i", time));
+
+			if (!ci->icon)
+				ci = &cl.baseclientinfo;
+			re.DrawPic (x, y, ci->iconname);
+			continue;
+		}
+
+		if (!strcmp(token, "ctf"))
+		{	// draw a ctf client block
+			int		score, ping;
+			char	block[80];
+
+			token = COM_Parse (&s);
+			x = vid.width/2 - 160 + atoi(token);
+			token = COM_Parse (&s);
+			y = vid.height/2 - 120 + atoi(token);
+			SCR_AddDirtyPoint (x, y);
+			SCR_AddDirtyPoint (x+159, y+31);
+
+			token = COM_Parse (&s);
+			value = atoi(token);
+			if (value >= MAX_CLIENTS || value < 0)
+				Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
+			ci = &cl.clientinfo[value];
+
+			token = COM_Parse (&s);
+			score = atoi(token);
+
+			token = COM_Parse (&s);
+			ping = atoi(token);
+			if (ping > 999)
+				ping = 999;
+
+			sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
+
+			if (value == cl.playernum)
+				DrawAltString (x, y, block);
+			else
+				DrawString (x, y, block);
+			continue;
+		}
+
+		if (!strcmp(token, "picn"))
+		{	// draw a pic from a name
+			token = COM_Parse (&s);
+			SCR_AddDirtyPoint (x, y);
+			SCR_AddDirtyPoint (x+23, y+23);
+			re.DrawPic (x, y, token);
+			continue;
+		}
+
+		if (!strcmp(token, "num"))
+		{	// draw a number
+			token = COM_Parse (&s);
+			width = atoi(token);
+			token = COM_Parse (&s);
+			value = cl.frame.playerstate.stats[atoi(token)];
+			SCR_DrawField (x, y, 0, width, value);
+			continue;
+		}
+
+		if (!strcmp(token, "hnum"))
+		{	// health number
+			int		color;
+
+			width = 3;
+			value = cl.frame.playerstate.stats[STAT_HEALTH];
+			if (value > 25)
+				color = 0;	// green
+			else if (value > 0)
+				color = (cl.frame.serverframe>>2) & 1;		// flash
+			else
+				color = 1;
+
+			if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)
+				re.DrawPic (x, y, "field_3");
+
+			SCR_DrawField (x, y, color, width, value);
+			continue;
+		}
+
+		if (!strcmp(token, "anum"))
+		{	// ammo number
+			int		color;
+
+			width = 3;
+			value = cl.frame.playerstate.stats[STAT_AMMO];
+			if (value > 5)
+				color = 0;	// green
+			else if (value >= 0)
+				color = (cl.frame.serverframe>>2) & 1;		// flash
+			else
+				continue;	// negative number = don't show
+
+			if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)
+				re.DrawPic (x, y, "field_3");
+
+			SCR_DrawField (x, y, color, width, value);
+			continue;
+		}
+
+		if (!strcmp(token, "rnum"))
+		{	// armor number
+			int		color;
+
+			width = 3;
+			value = cl.frame.playerstate.stats[STAT_ARMOR];
+			if (value < 1)
+				continue;
+
+			color = 0;	// green
+
+			if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)
+				re.DrawPic (x, y, "field_3");
+
+			SCR_DrawField (x, y, color, width, value);
+			continue;
+		}
+
+
+		if (!strcmp(token, "stat_string"))
+		{
+			token = COM_Parse (&s);
+			index = atoi(token);
+			if (index < 0 || index >= MAX_CONFIGSTRINGS)
+				Com_Error (ERR_DROP, "Bad stat_string index");
+			index = cl.frame.playerstate.stats[index];
+			if (index < 0 || index >= MAX_CONFIGSTRINGS)
+				Com_Error (ERR_DROP, "Bad stat_string index");
+			DrawString (x, y, cl.configstrings[index]);
+			continue;
+		}
+
+		if (!strcmp(token, "cstring"))
+		{
+			token = COM_Parse (&s);
+			DrawHUDString (token, x, y, 320, 0);
+			continue;
+		}
+
+		if (!strcmp(token, "string"))
+		{
+			token = COM_Parse (&s);
+			DrawString (x, y, token);
+			continue;
+		}
+
+		if (!strcmp(token, "cstring2"))
+		{
+			token = COM_Parse (&s);
+			DrawHUDString (token, x, y, 320,0x80);
+			continue;
+		}
+
+		if (!strcmp(token, "string2"))
+		{
+			token = COM_Parse (&s);
+			DrawAltString (x, y, token);
+			continue;
+		}
+
+		if (!strcmp(token, "if"))
+		{	// draw a number
+			token = COM_Parse (&s);
+			value = cl.frame.playerstate.stats[atoi(token)];
+			if (!value)
+			{	// skip to endif
+				while (s && strcmp(token, "endif") )
+				{
+					token = COM_Parse (&s);
+				}
+			}
+
+			continue;
+		}
+
+
+	}
+}
+
+
+/*
+================
+SCR_DrawStats
+
+The status bar is a small layout program that
+is based on the stats array
+================
+*/
+void SCR_DrawStats (void)
+{
+	SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
+}
+
+
+/*
+================
+SCR_DrawLayout
+
+================
+*/
+void SCR_DrawLayout (void)
+{
+	if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
+		return;
+	SCR_ExecuteLayoutString (cl.layout);
+}
+
+//=======================================================
+
+/*
+==================
+SCR_UpdateScreen
+
+This is called every frame, and can also be called explicitly to flush
+text to the screen.
+==================
+*/
+void SCR_UpdateScreen (void)
+{
+	int numframes;
+	int i;
+	float separation[2] = { 0, 0 };
+
+	// if the screen is disabled (loading plaque is up, or vid mode changing)
+	// do nothing at all
+	if (cls.disable_screen)
+	{
+		if (Sys_Milliseconds() - cls.disable_screen > 120000)
+		{
+			cls.disable_screen = 0;
+			Com_Printf ("Loading plaque timed out.\n");
+		}
+		return;
+	}
+
+	if (!scr_initialized || !con.initialized)
+		return;				// not initialized yet
+
+	/*
+	** range check cl_camera_separation so we don't inadvertently fry someone's
+	** brain
+	*/
+	if ( cl_stereo_separation->value > 1.0 )
+		Cvar_SetValue( "cl_stereo_separation", 1.0 );
+	else if ( cl_stereo_separation->value < 0 )
+		Cvar_SetValue( "cl_stereo_separation", 0.0 );
+
+	if ( cl_stereo->value )
+	{
+		numframes = 2;
+		separation[0] = -cl_stereo_separation->value / 2;
+		separation[1] =  cl_stereo_separation->value / 2;
+	}		
+	else
+	{
+		separation[0] = 0;
+		separation[1] = 0;
+		numframes = 1;
+	}
+
+	for ( i = 0; i < numframes; i++ )
+	{
+		re.BeginFrame( separation[i] );
+
+		if (scr_draw_loading == 2)
+		{	//  loading plaque over black screen
+			int		w, h;
+
+			re.CinematicSetPalette(NULL);
+			scr_draw_loading = false;
+			re.DrawGetPicSize (&w, &h, "loading");
+			re.DrawPic ((vid.width-w)/2, (vid.height-h)/2, "loading");
+//			re.EndFrame();
+//			return;
+		} 
+		// if a cinematic is supposed to be running, handle menus
+		// and console specially
+		else if (cl.cinematictime > 0)
+		{
+			if (cls.key_dest == key_menu)
+			{
+				if (cl.cinematicpalette_active)
+				{
+					re.CinematicSetPalette(NULL);
+					cl.cinematicpalette_active = false;
+				}
+				M_Draw ();
+//				re.EndFrame();
+//				return;
+			}
+			else if (cls.key_dest == key_console)
+			{
+				if (cl.cinematicpalette_active)
+				{
+					re.CinematicSetPalette(NULL);
+					cl.cinematicpalette_active = false;
+				}
+				SCR_DrawConsole ();
+//				re.EndFrame();
+//				return;
+			}
+			else
+			{
+				SCR_DrawCinematic();
+//				re.EndFrame();
+//				return;
+			}
+		}
+		else 
+		{
+
+			// make sure the game palette is active
+			if (cl.cinematicpalette_active)
+			{
+				re.CinematicSetPalette(NULL);
+				cl.cinematicpalette_active = false;
+			}
+
+			// do 3D refresh drawing, and then update the screen
+			SCR_CalcVrect ();
+
+			// clear any dirty part of the background
+			SCR_TileClear ();
+
+			V_RenderView ( separation[i] );
+
+			SCR_DrawStats ();
+			if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
+				SCR_DrawLayout ();
+			if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
+				CL_DrawInventory ();
+
+			SCR_DrawNet ();
+			SCR_CheckDrawCenterString ();
+
+			if (scr_timegraph->value)
+				SCR_DebugGraph (cls.frametime*300, 0);
+
+			if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
+				SCR_DrawDebugGraph ();
+
+			SCR_DrawPause ();
+
+			SCR_DrawConsole ();
+
+			M_Draw ();
+
+			SCR_DrawLoading ();
+		}
+	}
+	re.EndFrame();
+}
--- /dev/null
+++ b/cl_tent.c
@@ -1,0 +1,1718 @@
+// cl_tent.c -- client side temporary entities
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef enum
+{
+	ex_free, ex_explosion, ex_misc, ex_flash, ex_mflash, ex_poly, ex_poly2
+} exptype_t;
+
+typedef struct
+{
+	exptype_t	type;
+	entity_t	ent;
+
+	int			frames;
+	float		light;
+	vec3_t		lightcolor;
+	float		start;
+	int			baseframe;
+} explosion_t;
+
+
+
+#define	MAX_EXPLOSIONS	32
+explosion_t	cl_explosions[MAX_EXPLOSIONS];
+
+
+#define	MAX_BEAMS	32
+typedef struct
+{
+	int		entity;
+	int		dest_entity;
+	model_t	*model;
+	int		endtime;
+	vec3_t	offset;
+	vec3_t	start, end;
+} beam_t;
+beam_t		cl_beams[MAX_BEAMS];
+//PMM - added this for player-linked beams.  Currently only used by the plasma beam
+beam_t		cl_playerbeams[MAX_BEAMS];
+
+
+#define	MAX_LASERS	32
+typedef struct
+{
+	entity_t	ent;
+	int			endtime;
+} laser_t;
+laser_t		cl_lasers[MAX_LASERS];
+
+//ROGUE
+cl_sustain_t	cl_sustains[MAX_SUSTAINS];
+//ROGUE
+
+//PGM
+extern void CL_TeleportParticles (vec3_t org);
+//PGM
+
+void CL_BlasterParticles (vec3_t org, vec3_t dir);
+void CL_ExplosionParticles (vec3_t org);
+void CL_BFGExplosionParticles (vec3_t org);
+// RAFAEL
+void CL_BlueBlasterParticles (vec3_t org, vec3_t dir);
+
+sfx_t *cl_sfx_ric1;
+sfx_t *cl_sfx_ric2;
+sfx_t *cl_sfx_ric3;
+sfx_t *cl_sfx_lashit;
+sfx_t *cl_sfx_spark5;
+sfx_t *cl_sfx_spark6;
+sfx_t *cl_sfx_spark7;
+sfx_t *cl_sfx_railg;
+sfx_t *cl_sfx_rockexp;
+sfx_t *cl_sfx_grenexp;
+sfx_t *cl_sfx_watrexp;
+sfx_t *cl_sfx_plasexp;
+sfx_t *cl_sfx_footsteps[4];
+
+model_t *cl_mod_explode;
+model_t *cl_mod_smoke;
+model_t *cl_mod_flash;
+model_t *cl_mod_parasite_segment;
+model_t *cl_mod_grapple_cable;
+model_t *cl_mod_parasite_tip;
+model_t *cl_mod_explo4;
+model_t *cl_mod_bfg_explo;
+model_t *cl_mod_powerscreen;
+// RAFAEL
+model_t *cl_mod_plasmaexplo;
+
+//ROGUE
+sfx_t *cl_sfx_lightning;
+sfx_t *cl_sfx_disrexp;
+model_t *cl_mod_lightning;
+model_t *cl_mod_heatbeam;
+model_t *cl_mod_monster_heatbeam;
+model_t *cl_mod_explo4_big;
+
+//ROGUE
+/*
+=================
+CL_RegisterTEntSounds
+=================
+*/
+void CL_RegisterTEntSounds (void)
+{
+	int		i;
+	char	name[MAX_QPATH];
+
+	// PMM - version stuff
+//	Com_Printf ("%s\n", ROGUE_VERSION_STRING);
+	// PMM
+	cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav");
+	cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav");
+	cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav");
+	cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav");
+	cl_sfx_spark5 = S_RegisterSound ("world/spark5.wav");
+	cl_sfx_spark6 = S_RegisterSound ("world/spark6.wav");
+	cl_sfx_spark7 = S_RegisterSound ("world/spark7.wav");
+	cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav");
+	cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav");
+	cl_sfx_grenexp = S_RegisterSound ("weapons/grenlx1a.wav");
+	cl_sfx_watrexp = S_RegisterSound ("weapons/xpld_wat.wav");
+	// RAFAEL
+	// cl_sfx_plasexp = S_RegisterSound ("weapons/plasexpl.wav");
+	S_RegisterSound ("player/land1.wav");
+
+	S_RegisterSound ("player/fall2.wav");
+	S_RegisterSound ("player/fall1.wav");
+
+	for (i=0 ; i<4 ; i++)
+	{
+		Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
+		cl_sfx_footsteps[i] = S_RegisterSound (name);
+	}
+
+//PGM
+	cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav");
+	cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav");
+	// version stuff
+	sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID);
+	if (name[0] == 'w')
+		name[0] = 'W';
+//PGM
+}	
+
+/*
+=================
+CL_RegisterTEntModels
+=================
+*/
+void CL_RegisterTEntModels (void)
+{
+	cl_mod_explode = re.RegisterModel ("models/objects/explode/tris.md2");
+	cl_mod_smoke = re.RegisterModel ("models/objects/smoke/tris.md2");
+	cl_mod_flash = re.RegisterModel ("models/objects/flash/tris.md2");
+	cl_mod_parasite_segment = re.RegisterModel ("models/monsters/parasite/segment/tris.md2");
+	cl_mod_grapple_cable = re.RegisterModel ("models/ctf/segment/tris.md2");
+	cl_mod_parasite_tip = re.RegisterModel ("models/monsters/parasite/tip/tris.md2");
+	cl_mod_explo4 = re.RegisterModel ("models/objects/r_explode/tris.md2");
+	cl_mod_bfg_explo = re.RegisterModel ("sprites/s_bfg2.sp2");
+	cl_mod_powerscreen = re.RegisterModel ("models/items/armor/effect/tris.md2");
+
+re.RegisterModel ("models/objects/laser/tris.md2");
+re.RegisterModel ("models/objects/grenade2/tris.md2");
+re.RegisterModel ("models/weapons/v_machn/tris.md2");
+re.RegisterModel ("models/weapons/v_handgr/tris.md2");
+re.RegisterModel ("models/weapons/v_shotg2/tris.md2");
+re.RegisterModel ("models/objects/gibs/bone/tris.md2");
+re.RegisterModel ("models/objects/gibs/sm_meat/tris.md2");
+re.RegisterModel ("models/objects/gibs/bone2/tris.md2");
+// RAFAEL
+// re.RegisterModel ("models/objects/blaser/tris.md2");
+
+re.RegisterPic ("w_machinegun");
+re.RegisterPic ("a_bullets");
+re.RegisterPic ("i_health");
+re.RegisterPic ("a_grenades");
+
+//ROGUE
+	cl_mod_explo4_big = re.RegisterModel ("models/objects/r_explode2/tris.md2");
+	cl_mod_lightning = re.RegisterModel ("models/proj/lightning/tris.md2");
+	cl_mod_heatbeam = re.RegisterModel ("models/proj/beam/tris.md2");
+	cl_mod_monster_heatbeam = re.RegisterModel ("models/proj/widowbeam/tris.md2");
+//ROGUE
+}	
+
+/*
+=================
+CL_ClearTEnts
+=================
+*/
+void CL_ClearTEnts (void)
+{
+	memset (cl_beams, 0, sizeof(cl_beams));
+	memset (cl_explosions, 0, sizeof(cl_explosions));
+	memset (cl_lasers, 0, sizeof(cl_lasers));
+
+//ROGUE
+	memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
+	memset (cl_sustains, 0, sizeof(cl_sustains));
+//ROGUE
+}
+
+/*
+=================
+CL_AllocExplosion
+=================
+*/
+explosion_t *CL_AllocExplosion (void)
+{
+	int		i;
+	int		time;
+	int		index;
+	
+	for (i=0 ; i<MAX_EXPLOSIONS ; i++)
+	{
+		if (cl_explosions[i].type == ex_free)
+		{
+			memset (&cl_explosions[i], 0, sizeof (cl_explosions[i]));
+			return &cl_explosions[i];
+		}
+	}
+// find the oldest explosion
+	time = cl.time;
+	index = 0;
+
+	for (i=0 ; i<MAX_EXPLOSIONS ; i++)
+		if (cl_explosions[i].start < time)
+		{
+			time = cl_explosions[i].start;
+			index = i;
+		}
+	memset (&cl_explosions[index], 0, sizeof (cl_explosions[index]));
+	return &cl_explosions[index];
+}
+
+/*
+=================
+CL_SmokeAndFlash
+=================
+*/
+void CL_SmokeAndFlash(vec3_t origin)
+{
+	explosion_t	*ex;
+
+	ex = CL_AllocExplosion ();
+	VectorCopy (origin, ex->ent.origin);
+	ex->type = ex_misc;
+	ex->frames = 4;
+	ex->ent.flags = RF_TRANSLUCENT;
+	ex->start = cl.frame.servertime - 100;
+	ex->ent.model = cl_mod_smoke;
+
+	ex = CL_AllocExplosion ();
+	VectorCopy (origin, ex->ent.origin);
+	ex->type = ex_flash;
+	ex->ent.flags = RF_FULLBRIGHT;
+	ex->frames = 2;
+	ex->start = cl.frame.servertime - 100;
+	ex->ent.model = cl_mod_flash;
+}
+
+/*
+=================
+CL_ParseParticles
+=================
+*/
+void CL_ParseParticles (void)
+{
+	int		color, count;
+	vec3_t	pos, dir;
+
+	MSG_ReadPos (&net_message, pos);
+	MSG_ReadDir (&net_message, dir);
+
+	color = MSG_ReadByte (&net_message);
+
+	count = MSG_ReadByte (&net_message);
+
+	CL_ParticleEffect (pos, dir, color, count);
+}
+
+int
+CL_ParseBeam(model_t *model)
+{
+	int		ent;
+	vec3_t	start, end;
+	beam_t	*b;
+	int		i;
+	
+	ent = MSG_ReadShort (&net_message);
+	
+	MSG_ReadPos (&net_message, start);
+	MSG_ReadPos (&net_message, end);
+
+// override any beam with the same entity
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+		if (b->entity == ent)
+		{
+			b->entity = ent;
+			b->model = model;
+			b->endtime = cl.time + 200;
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorClear (b->offset);
+			return ent;
+		}
+
+// find a free beam
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+	{
+		if (!b->model || b->endtime < cl.time)
+		{
+			b->entity = ent;
+			b->model = model;
+			b->endtime = cl.time + 200;
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorClear (b->offset);
+			return ent;
+		}
+	}
+	Com_Printf ("beam list overflow!\n");	
+	return ent;
+}
+
+int
+CL_ParseBeam2(model_t *model)
+{
+	int		ent;
+	vec3_t	start, end, offset;
+	beam_t	*b;
+	int		i;
+	
+	ent = MSG_ReadShort (&net_message);
+	
+	MSG_ReadPos (&net_message, start);
+	MSG_ReadPos (&net_message, end);
+	MSG_ReadPos (&net_message, offset);
+
+//	Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
+
+// override any beam with the same entity
+
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+		if (b->entity == ent)
+		{
+			b->entity = ent;
+			b->model = model;
+			b->endtime = cl.time + 200;
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorCopy (offset, b->offset);
+			return ent;
+		}
+
+// find a free beam
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+	{
+		if (!b->model || b->endtime < cl.time)
+		{
+			b->entity = ent;
+			b->model = model;
+			b->endtime = cl.time + 200;	
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorCopy (offset, b->offset);
+			return ent;
+		}
+	}
+	Com_Printf ("beam list overflow!\n");	
+	return ent;
+}
+
+// ROGUE
+/*
+=================
+CL_ParsePlayerBeam
+  - adds to the cl_playerbeam array instead of the cl_beams array
+=================
+*/
+int
+CL_ParsePlayerBeam(model_t *model)
+{
+	int		ent;
+	vec3_t	start, end, offset;
+	beam_t	*b;
+	int		i;
+	
+	ent = MSG_ReadShort (&net_message);
+	
+	MSG_ReadPos (&net_message, start);
+	MSG_ReadPos (&net_message, end);
+	// PMM - network optimization
+	if (model == cl_mod_heatbeam)
+		VectorSet(offset, 2, 7, -3);
+	else if (model == cl_mod_monster_heatbeam)
+	{
+		model = cl_mod_heatbeam;
+		VectorSet(offset, 0, 0, 0);
+	}
+	else
+		MSG_ReadPos (&net_message, offset);
+
+//	Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
+
+// override any beam with the same entity
+// PMM - For player beams, we only want one per player (entity) so..
+	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
+	{
+		if (b->entity == ent)
+		{
+			b->entity = ent;
+			b->model = model;
+			b->endtime = cl.time + 200;
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorCopy (offset, b->offset);
+			return ent;
+		}
+	}
+
+// find a free beam
+	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
+	{
+		if (!b->model || b->endtime < cl.time)
+		{
+			b->entity = ent;
+			b->model = model;
+			b->endtime = cl.time + 100;		// PMM - this needs to be 100 to prevent multiple heatbeams
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorCopy (offset, b->offset);
+			return ent;
+		}
+	}
+	Com_Printf ("beam list overflow!\n");	
+	return ent;
+}
+//rogue
+
+int
+CL_ParseLightning(model_t *model)
+{
+	int		srcEnt, destEnt;
+	vec3_t	start, end;
+	beam_t	*b;
+	int		i;
+	
+	srcEnt = MSG_ReadShort (&net_message);
+	destEnt = MSG_ReadShort (&net_message);
+
+	MSG_ReadPos (&net_message, start);
+	MSG_ReadPos (&net_message, end);
+
+// override any beam with the same source AND destination entities
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+		if (b->entity == srcEnt && b->dest_entity == destEnt)
+		{
+//			Com_Printf("%d: OVERRIDE  %d -> %d\n", cl.time, srcEnt, destEnt);
+			b->entity = srcEnt;
+			b->dest_entity = destEnt;
+			b->model = model;
+			b->endtime = cl.time + 200;
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorClear (b->offset);
+			return srcEnt;
+		}
+
+// find a free beam
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+	{
+		if (!b->model || b->endtime < cl.time)
+		{
+//			Com_Printf("%d: NORMAL  %d -> %d\n", cl.time, srcEnt, destEnt);
+			b->entity = srcEnt;
+			b->dest_entity = destEnt;
+			b->model = model;
+			b->endtime = cl.time + 200;
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorClear (b->offset);
+			return srcEnt;
+		}
+	}
+	Com_Printf ("beam list overflow!\n");	
+	return srcEnt;
+}
+
+/*
+=================
+CL_ParseLaser
+=================
+*/
+void CL_ParseLaser (int colors)
+{
+	vec3_t	start;
+	vec3_t	end;
+	laser_t	*l;
+	int		i;
+
+	MSG_ReadPos (&net_message, start);
+	MSG_ReadPos (&net_message, end);
+
+	for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
+	{
+		if (l->endtime < cl.time)
+		{
+			l->ent.flags = RF_TRANSLUCENT | RF_BEAM;
+			VectorCopy (start, l->ent.origin);
+			VectorCopy (end, l->ent.oldorigin);
+			l->ent.alpha = 0.30;
+			l->ent.skinnum = (colors >> ((rand() % 4)*8)) & 0xff;
+			l->ent.model = NULL;
+			l->ent.frame = 4;
+			l->endtime = cl.time + 100;
+			return;
+		}
+	}
+}
+
+//=============
+//ROGUE
+void CL_ParseSteam (void)
+{
+	vec3_t	pos, dir;
+	int		id, i;
+	int		r;
+	int		cnt;
+	int		color;
+	int		magnitude;
+	cl_sustain_t	*s, *free_sustain;
+
+	id = MSG_ReadShort (&net_message);		// an id of -1 is an instant effect
+	if (id != -1) // sustains
+	{
+//			Com_Printf ("Sustain effect id %d\n", id);
+		free_sustain = NULL;
+		for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
+		{
+			if (s->id == 0)
+			{
+				free_sustain = s;
+				break;
+			}
+		}
+		if (free_sustain)
+		{
+			s->id = id;
+			s->count = MSG_ReadByte (&net_message);
+			MSG_ReadPos (&net_message, s->org);
+			MSG_ReadDir (&net_message, s->dir);
+			r = MSG_ReadByte (&net_message);
+			s->color = r & 0xff;
+			s->magnitude = MSG_ReadShort (&net_message);
+			s->endtime = cl.time + MSG_ReadLong (&net_message);
+			s->think = CL_ParticleSteamEffect2;
+			s->thinkinterval = 100;
+			s->nextthink = cl.time;
+		}
+		else
+		{
+//				Com_Printf ("No free sustains!\n");
+			// FIXME - read the stuff anyway	/* and toss the results */
+			MSG_ReadByte (&net_message);
+			MSG_ReadPos (&net_message, pos);
+			MSG_ReadDir (&net_message, dir);
+			MSG_ReadByte (&net_message);
+			MSG_ReadShort (&net_message);
+			MSG_ReadLong (&net_message); // really interval
+		}
+	}
+	else // instant
+	{
+		cnt = MSG_ReadByte (&net_message);
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		r = MSG_ReadByte (&net_message);
+		magnitude = MSG_ReadShort (&net_message);
+		color = r & 0xff;
+		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
+//		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+	}
+}
+
+void CL_ParseWidow (void)
+{
+	vec3_t	pos;
+	int		id, i;
+	cl_sustain_t	*s, *free_sustain;
+
+	id = MSG_ReadShort (&net_message);
+
+	free_sustain = NULL;
+	for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
+	{
+		if (s->id == 0)
+		{
+			free_sustain = s;
+			break;
+		}
+	}
+	if (free_sustain)
+	{
+		s->id = id;
+		MSG_ReadPos (&net_message, s->org);
+		s->endtime = cl.time + 2100;
+		s->think = CL_Widowbeamout;
+		s->thinkinterval = 1;
+		s->nextthink = cl.time;
+	}
+	else // no free sustains
+	{
+		// FIXME - read the stuff anyway
+		MSG_ReadPos (&net_message, pos);
+	}
+}
+
+void CL_ParseNuke (void)
+{
+	vec3_t	pos;
+	int		i;
+	cl_sustain_t	*s, *free_sustain;
+
+	free_sustain = NULL;
+	for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
+	{
+		if (s->id == 0)
+		{
+			free_sustain = s;
+			break;
+		}
+	}
+	if (free_sustain)
+	{
+		s->id = 21000;
+		MSG_ReadPos (&net_message, s->org);
+		s->endtime = cl.time + 1000;
+		s->think = CL_Nukeblast;
+		s->thinkinterval = 1;
+		s->nextthink = cl.time;
+	}
+	else // no free sustains
+	{
+		// FIXME - read the stuff anyway
+		MSG_ReadPos (&net_message, pos);
+	}
+}
+
+//ROGUE
+//=============
+
+
+/*
+=================
+CL_ParseTEnt
+=================
+*/
+static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
+
+void CL_ParseTEnt (void)
+{
+	int		type;
+	vec3_t	pos, pos2, dir;
+	explosion_t	*ex;
+	int		cnt;
+	int		color;
+	int		r;
+	int		ent;
+	int		magnitude;
+
+	type = MSG_ReadByte (&net_message);
+
+	switch (type)
+	{
+	case TE_BLOOD:			// bullet hitting flesh
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		CL_ParticleEffect (pos, dir, 0xe8, 60);
+		break;
+
+	case TE_GUNSHOT:			// bullet hitting wall
+	case TE_SPARKS:
+	case TE_BULLET_SPARKS:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		if (type == TE_GUNSHOT)
+			CL_ParticleEffect (pos, dir, 0, 40);
+		else
+			CL_ParticleEffect (pos, dir, 0xe0, 6);
+
+		if (type != TE_SPARKS)
+		{
+			CL_SmokeAndFlash(pos);
+			
+			// impact sound
+			cnt = rand()&15;
+			if (cnt == 1)
+				S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
+			else if (cnt == 2)
+				S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
+			else if (cnt == 3)
+				S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
+		}
+
+		break;
+		
+	case TE_SCREEN_SPARKS:
+	case TE_SHIELD_SPARKS:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		if (type == TE_SCREEN_SPARKS)
+			CL_ParticleEffect (pos, dir, 0xd0, 40);
+		else
+			CL_ParticleEffect (pos, dir, 0xb0, 40);
+		//FIXME : replace or remove this sound
+		S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+		
+	case TE_SHOTGUN:			// bullet hitting wall
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		CL_ParticleEffect (pos, dir, 0, 20);
+		CL_SmokeAndFlash(pos);
+		break;
+
+	case TE_SPLASH:			// bullet hitting water
+		cnt = MSG_ReadByte (&net_message);
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		r = MSG_ReadByte (&net_message);
+		if (r > 6)
+			color = 0x00;
+		else
+			color = splash_color[r];
+		CL_ParticleEffect (pos, dir, color, cnt);
+
+		if (r == SPLASH_SPARKS)
+		{
+			r = rand() & 3;
+			if (r == 0)
+				S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
+			else if (r == 1)
+				S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
+			else
+				S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
+		}
+		break;
+
+	case TE_LASER_SPARKS:
+		cnt = MSG_ReadByte (&net_message);
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		color = MSG_ReadByte (&net_message);
+		CL_ParticleEffect2 (pos, dir, color, cnt);
+		break;
+
+	// RAFAEL
+	case TE_BLUEHYPERBLASTER:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadPos (&net_message, dir);
+		CL_BlasterParticles (pos, dir);
+		break;
+
+	case TE_BLASTER:			// blaster hitting wall
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		CL_BlasterParticles (pos, dir);
+
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->ent.angles[0] = acos(dir[2])/M_PI*180;
+	// PMM - fixed to correct for pitch of 0
+		if (dir[0])
+			ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
+		else if (dir[1] > 0)
+			ex->ent.angles[1] = 90;
+		else if (dir[1] < 0)
+			ex->ent.angles[1] = 270;
+		else
+			ex->ent.angles[1] = 0;
+
+		ex->type = ex_misc;
+		ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 150;
+		ex->lightcolor[0] = 1;
+		ex->lightcolor[1] = 1;
+		ex->ent.model = cl_mod_explode;
+		ex->frames = 4;
+		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+		
+	case TE_RAILTRAIL:			// railgun effect
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadPos (&net_message, pos2);
+		CL_RailTrail (pos, pos2);
+		S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_EXPLOSION2:
+	case TE_GRENADE_EXPLOSION:
+	case TE_GRENADE_EXPLOSION_WATER:
+		MSG_ReadPos (&net_message, pos);
+
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->type = ex_poly;
+		ex->ent.flags = RF_FULLBRIGHT;
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 350;
+		ex->lightcolor[0] = 1.0;
+		ex->lightcolor[1] = 0.5;
+		ex->lightcolor[2] = 0.5;
+		ex->ent.model = cl_mod_explo4;
+		ex->frames = 19;
+		ex->baseframe = 30;
+		ex->ent.angles[1] = rand() % 360;
+		CL_ExplosionParticles (pos);
+		if (type == TE_GRENADE_EXPLOSION_WATER)
+			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+		else
+			S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
+		break;
+
+	// RAFAEL
+	case TE_PLASMA_EXPLOSION:
+		MSG_ReadPos (&net_message, pos);
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->type = ex_poly;
+		ex->ent.flags = RF_FULLBRIGHT;
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 350;
+		ex->lightcolor[0] = 1.0; 
+		ex->lightcolor[1] = 0.5;
+		ex->lightcolor[2] = 0.5;
+		ex->ent.angles[1] = rand() % 360;
+		ex->ent.model = cl_mod_explo4;
+		if (qfrand() < 0.5)
+			ex->baseframe = 15;
+		ex->frames = 15;
+		CL_ExplosionParticles (pos);
+		S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+		break;
+	
+	case TE_EXPLOSION1:
+	case TE_EXPLOSION1_BIG:						// PMM
+	case TE_ROCKET_EXPLOSION:
+	case TE_ROCKET_EXPLOSION_WATER:
+	case TE_EXPLOSION1_NP:						// PMM
+		MSG_ReadPos (&net_message, pos);
+
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->type = ex_poly;
+		ex->ent.flags = RF_FULLBRIGHT;
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 350;
+		ex->lightcolor[0] = 1.0;
+		ex->lightcolor[1] = 0.5;
+		ex->lightcolor[2] = 0.5;
+		ex->ent.angles[1] = rand() % 360;
+		if (type != TE_EXPLOSION1_BIG)				// PMM
+			ex->ent.model = cl_mod_explo4;			// PMM
+		else
+			ex->ent.model = cl_mod_explo4_big;
+		if (qfrand() < 0.5)
+			ex->baseframe = 15;
+		ex->frames = 15;
+		if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP))		// PMM
+			CL_ExplosionParticles (pos);									// PMM
+		if (type == TE_ROCKET_EXPLOSION_WATER)
+			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+		else
+			S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_BFG_EXPLOSION:
+		MSG_ReadPos (&net_message, pos);
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->type = ex_poly;
+		ex->ent.flags = RF_FULLBRIGHT;
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 350;
+		ex->lightcolor[0] = 0.0;
+		ex->lightcolor[1] = 1.0;
+		ex->lightcolor[2] = 0.0;
+		ex->ent.model = cl_mod_bfg_explo;
+		ex->ent.flags |= RF_TRANSLUCENT;
+		ex->ent.alpha = 0.30;
+		ex->frames = 4;
+		break;
+
+	case TE_BFG_BIGEXPLOSION:
+		MSG_ReadPos (&net_message, pos);
+		CL_BFGExplosionParticles (pos);
+		break;
+
+	case TE_BFG_LASER:
+		CL_ParseLaser (0xd0d1d2d3);
+		break;
+
+	case TE_BUBBLETRAIL:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadPos (&net_message, pos2);
+		CL_BubbleTrail (pos, pos2);
+		break;
+
+	case TE_PARASITE_ATTACK:
+	case TE_MEDIC_CABLE_ATTACK:
+		CL_ParseBeam (cl_mod_parasite_segment);		/* toss result */
+		break;
+
+	case TE_BOSSTPORT:			// boss teleporting to station
+		MSG_ReadPos (&net_message, pos);
+		CL_BigTeleportParticles (pos);
+		S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0);
+		break;
+
+	case TE_GRAPPLE_CABLE:
+		CL_ParseBeam2 (cl_mod_grapple_cable);		/* toss result */
+		break;
+
+	// RAFAEL
+	case TE_WELDING_SPARKS:
+		cnt = MSG_ReadByte (&net_message);
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		color = MSG_ReadByte (&net_message);
+		CL_ParticleEffect2 (pos, dir, color, cnt);
+
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->type = ex_flash;
+		// note to self
+		// we need a better no draw flag
+		ex->ent.flags = RF_BEAM;
+		ex->start = cl.frame.servertime - 0.1;
+		ex->light = 100 + (rand()%75);
+		ex->lightcolor[0] = 1.0;
+		ex->lightcolor[1] = 1.0;
+		ex->lightcolor[2] = 0.3;
+		ex->ent.model = cl_mod_flash;
+		ex->frames = 2;
+		break;
+
+	case TE_GREENBLOOD:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		CL_ParticleEffect2 (pos, dir, 0xdf, 30);
+		break;
+
+	// RAFAEL
+	case TE_TUNNEL_SPARKS:
+		cnt = MSG_ReadByte (&net_message);
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		color = MSG_ReadByte (&net_message);
+		CL_ParticleEffect3 (pos, dir, color, cnt);
+		break;
+
+//=============
+//PGM
+		// PMM -following code integrated for flechette (different color)
+	case TE_BLASTER2:			// green blaster hitting wall
+	case TE_FLECHETTE:			// flechette
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		
+		// PMM
+		if (type == TE_BLASTER2)
+			CL_BlasterParticles2 (pos, dir, 0xd0);
+		else
+			CL_BlasterParticles2 (pos, dir, 0x6f); // 75
+
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->ent.angles[0] = acos(dir[2])/M_PI*180;
+	// PMM - fixed to correct for pitch of 0
+		if (dir[0])
+			ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
+		else if (dir[1] > 0)
+			ex->ent.angles[1] = 90;
+		else if (dir[1] < 0)
+			ex->ent.angles[1] = 270;
+		else
+			ex->ent.angles[1] = 0;
+
+		ex->type = ex_misc;
+		ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+
+		// PMM
+		if (type == TE_BLASTER2)
+			ex->ent.skinnum = 1;
+		else // flechette
+			ex->ent.skinnum = 2;
+
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 150;
+		// PMM
+		if (type == TE_BLASTER2)
+			ex->lightcolor[1] = 1;
+		else // flechette
+		{
+			ex->lightcolor[0] = 0.19;
+			ex->lightcolor[1] = 0.41;
+			ex->lightcolor[2] = 0.75;
+		}
+		ex->ent.model = cl_mod_explode;
+		ex->frames = 4;
+		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+
+
+	case TE_LIGHTNING:
+		ent = CL_ParseLightning (cl_mod_lightning);
+		S_StartSound (NULL, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_DEBUGTRAIL:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadPos (&net_message, pos2);
+		CL_DebugTrail (pos, pos2);
+		break;
+
+	case TE_PLAIN_EXPLOSION:
+		MSG_ReadPos (&net_message, pos);
+
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->type = ex_poly;
+		ex->ent.flags = RF_FULLBRIGHT;
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 350;
+		ex->lightcolor[0] = 1.0;
+		ex->lightcolor[1] = 0.5;
+		ex->lightcolor[2] = 0.5;
+		ex->ent.angles[1] = rand() % 360;
+		ex->ent.model = cl_mod_explo4;
+		if (qfrand() < 0.5)
+			ex->baseframe = 15;
+		ex->frames = 15;
+		if (type == TE_ROCKET_EXPLOSION_WATER)
+			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+		else
+			S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_FLASHLIGHT:
+		MSG_ReadPos(&net_message, pos);
+		ent = MSG_ReadShort(&net_message);
+		CL_Flashlight(ent, pos);
+		break;
+
+	case TE_FORCEWALL:
+		MSG_ReadPos(&net_message, pos);
+		MSG_ReadPos(&net_message, pos2);
+		color = MSG_ReadByte (&net_message);
+		CL_ForceWall(pos, pos2, color);
+		break;
+
+	case TE_HEATBEAM:
+		CL_ParsePlayerBeam (cl_mod_heatbeam);		/* toss result */
+		break;
+
+	case TE_MONSTER_HEATBEAM:
+		CL_ParsePlayerBeam (cl_mod_monster_heatbeam);	/* toss result */
+		break;
+
+	case TE_HEATBEAM_SPARKS:
+//		cnt = MSG_ReadByte (&net_message);
+		cnt = 50;
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+//		r = MSG_ReadByte (&net_message);
+//		magnitude = MSG_ReadShort (&net_message);
+		r = 8;
+		magnitude = 60;
+		color = r & 0xff;
+		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
+		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+	
+	case TE_HEATBEAM_STEAM:
+//		cnt = MSG_ReadByte (&net_message);
+		cnt = 20;
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+//		r = MSG_ReadByte (&net_message);
+//		magnitude = MSG_ReadShort (&net_message);
+//		color = r & 0xff;
+		color = 0xe0;
+		magnitude = 60;
+		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
+		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_STEAM:
+		CL_ParseSteam();
+		break;
+
+	case TE_BUBBLETRAIL2:
+//		cnt = MSG_ReadByte (&net_message);
+		cnt = 8;
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadPos (&net_message, pos2);
+		CL_BubbleTrail2 (pos, pos2, cnt);
+		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_MOREBLOOD:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		CL_ParticleEffect (pos, dir, 0xe8, 250);
+		break;
+
+	case TE_CHAINFIST_SMOKE:
+		dir[0]=0; dir[1]=0; dir[2]=1;
+		MSG_ReadPos(&net_message, pos);
+		CL_ParticleSmokeEffect (pos, dir, 0, 20, 20);
+		break;
+
+	case TE_ELECTRIC_SPARKS:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+//		CL_ParticleEffect (pos, dir, 109, 40);
+		CL_ParticleEffect (pos, dir, 0x75, 40);
+		//FIXME : replace or remove this sound
+		S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_TRACKER_EXPLOSION:
+		MSG_ReadPos (&net_message, pos);
+		CL_ColorFlash (pos, 0, 150, -1, -1, -1);
+		CL_ColorExplosionParticles (pos, 0, 1);
+//		CL_Tracker_Explode (pos);
+		S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_TELEPORT_EFFECT:
+	case TE_DBALL_GOAL:
+		MSG_ReadPos (&net_message, pos);
+		CL_TeleportParticles (pos);
+		break;
+
+	case TE_WIDOWBEAMOUT:
+		CL_ParseWidow ();
+		break;
+
+	case TE_NUKEBLAST:
+		CL_ParseNuke ();
+		break;
+
+	case TE_WIDOWSPLASH:
+		MSG_ReadPos (&net_message, pos);
+		CL_WidowSplash (pos);
+		break;
+//PGM
+//==============
+
+	default:
+		Com_Error (ERR_DROP, "CL_ParseTEnt: bad type");
+	}
+}
+
+/*
+=================
+CL_AddBeams
+=================
+*/
+void CL_AddBeams (void)
+{
+	int			i,j;
+	beam_t		*b;
+	vec3_t		dist, org;
+	float		d;
+	entity_t	ent;
+	float		yaw, pitch;
+	float		forward;
+	float		len, steps;
+	float		model_length;
+	
+// update beams
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+	{
+		if (!b->model || b->endtime < cl.time)
+			continue;
+
+		// if coming from the player, update the start position
+		if (b->entity == cl.playernum+1)	// entity 0 is the world
+		{
+			VectorCopy (cl.refdef.vieworg, b->start);
+			b->start[2] -= 22;	// adjust for view height
+		}
+		VectorAdd (b->start, b->offset, org);
+
+	// calculate pitch and yaw
+		VectorSubtract (b->end, org, dist);
+
+		if (dist[1] == 0 && dist[0] == 0)
+		{
+			yaw = 0;
+			if (dist[2] > 0)
+				pitch = 90;
+			else
+				pitch = 270;
+		}
+		else
+		{
+	// PMM - fixed to correct for pitch of 0
+			if (dist[0])
+				yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
+			else if (dist[1] > 0)
+				yaw = 90;
+			else
+				yaw = 270;
+			if (yaw < 0)
+				yaw += 360;
+	
+			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
+			pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
+			if (pitch < 0)
+				pitch += 360.0;
+		}
+
+	// add new entities for the beams
+		d = VectorNormalize(dist);
+
+		memset (&ent, 0, sizeof(ent));
+		if (b->model == cl_mod_lightning)
+		{
+			model_length = 35.0;
+			d-= 20.0;  // correction so it doesn't end in middle of tesla
+		}
+		else
+		{
+			model_length = 30.0;
+		}
+		steps = ceil(d/model_length);
+		len = (d-model_length)/(steps-1);
+
+		// PMM - special case for lightning model .. if the real length is shorter than the model,
+		// flip it around & draw it from the end to the start.  This prevents the model from going
+		// through the tesla mine (instead it goes through the target)
+		if ((b->model == cl_mod_lightning) && (d <= model_length))
+		{
+//			Com_Printf ("special case\n");
+			VectorCopy (b->end, ent.origin);
+			// offset to push beam outside of tesla model (negative because dist is from end to start
+			// for this beam)
+//			for (j=0 ; j<3 ; j++)
+//				ent.origin[j] -= dist[j]*10.0;
+			ent.model = b->model;
+			ent.flags = RF_FULLBRIGHT;
+			ent.angles[0] = pitch;
+			ent.angles[1] = yaw;
+			ent.angles[2] = rand()%360;
+			V_AddEntity (&ent);			
+			return;
+		}
+		while (d > 0)
+		{
+			VectorCopy (org, ent.origin);
+			ent.model = b->model;
+			if (b->model == cl_mod_lightning)
+			{
+				ent.flags = RF_FULLBRIGHT;
+				ent.angles[0] = -pitch;
+				ent.angles[1] = yaw + 180.0;
+				ent.angles[2] = rand()%360;
+			}
+			else
+			{
+				ent.angles[0] = pitch;
+				ent.angles[1] = yaw;
+				ent.angles[2] = rand()%360;
+			}
+			
+//			Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
+			V_AddEntity (&ent);
+
+			for (j=0 ; j<3 ; j++)
+				org[j] += dist[j]*len;
+			d -= model_length;
+		}
+	}
+}
+
+
+/*
+//				Com_Printf ("Endpoint:  %f %f %f\n", b->end[0], b->end[1], b->end[2]);
+//				Com_Printf ("Pred View Angles:  %f %f %f\n", cl.predicted_angles[0], cl.predicted_angles[1], cl.predicted_angles[2]);
+//				Com_Printf ("Act View Angles: %f %f %f\n", cl.refdef.viewangles[0], cl.refdef.viewangles[1], cl.refdef.viewangles[2]);
+//				VectorCopy (cl.predicted_origin, b->start);
+//				b->start[2] += 22;	// adjust for view height
+//				if (fabs(cl.refdef.vieworg[2] - b->start[2]) >= 10) {
+//					b->start[2] = cl.refdef.vieworg[2];
+//				}
+
+//				Com_Printf ("Time:  %d %d %f\n", cl.time, cls.realtime, cls.frametime);
+*/
+
+extern cvar_t *hand;
+
+/*
+=================
+ROGUE - draw player locked beams
+CL_AddPlayerBeams
+=================
+*/
+void CL_AddPlayerBeams (void)
+{
+	int			i,j;
+	beam_t		*b;
+	vec3_t		dist, org;
+	float		d;
+	entity_t	ent;
+	float		yaw, pitch;
+	float		forward;
+	float		len, steps;
+	int			framenum = 0;
+	float		model_length;
+	
+	float		hand_multiplier;
+	frame_t		*oldframe;
+	player_state_t	*ps, *ops;
+
+//PMM
+	if (hand)
+	{
+		if (hand->value == 2)
+			hand_multiplier = 0;
+		else if (hand->value == 1)
+			hand_multiplier = -1;
+		else
+			hand_multiplier = 1;
+	}
+	else 
+	{
+		hand_multiplier = 1;
+	}
+//PMM
+
+// update beams
+	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
+	{
+		vec3_t		f,r,u;
+		if (!b->model || b->endtime < cl.time)
+			continue;
+
+		if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
+		{
+
+			// if coming from the player, update the start position
+			if (b->entity == cl.playernum+1)	// entity 0 is the world
+			{	
+				// set up gun position
+				// code straight out of CL_AddViewWeapon
+				ps = &cl.frame.playerstate;
+				j = (cl.frame.serverframe - 1) & UPDATE_MASK;
+				oldframe = &cl.frames[j];
+				if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
+					oldframe = &cl.frame;		// previous frame was dropped or involid
+				ops = &oldframe->playerstate;
+				for (j=0 ; j<3 ; j++)
+				{
+					b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j]
+						+ cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]);
+				}
+				VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org);
+				VectorMA (     org, b->offset[1], cl.v_forward, org);
+				VectorMA (     org, b->offset[2], cl.v_up, org);
+				if ((hand) && (hand->value == 2)) {
+					VectorMA (org, -1, cl.v_up, org);
+				}
+				// FIXME - take these out when final
+				VectorCopy (cl.v_right, r);
+				VectorCopy (cl.v_forward, f);
+				VectorCopy (cl.v_up, u);
+
+			}
+			else
+				VectorCopy (b->start, org);
+		}
+		else
+		{
+			// if coming from the player, update the start position
+			if (b->entity == cl.playernum+1)	// entity 0 is the world
+			{
+				VectorCopy (cl.refdef.vieworg, b->start);
+				b->start[2] -= 22;	// adjust for view height
+			}
+			VectorAdd (b->start, b->offset, org);
+		}
+
+	// calculate pitch and yaw
+		VectorSubtract (b->end, org, dist);
+
+//PMM
+		if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1))
+		{
+			vec_t len;
+
+			len = VectorLength (dist);
+			VectorScale (f, len, dist);
+			VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist);
+			VectorMA (dist, b->offset[1], f, dist);
+			VectorMA (dist, b->offset[2], u, dist);
+			if ((hand) && (hand->value == 2)) {
+				VectorMA (org, -1, cl.v_up, org);
+			}
+		}
+//PMM
+
+		if (dist[1] == 0 && dist[0] == 0)
+		{
+			yaw = 0;
+			if (dist[2] > 0)
+				pitch = 90;
+			else
+				pitch = 270;
+		}
+		else
+		{
+	// PMM - fixed to correct for pitch of 0
+			if (dist[0])
+				yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
+			else if (dist[1] > 0)
+				yaw = 90;
+			else
+				yaw = 270;
+			if (yaw < 0)
+				yaw += 360;
+	
+			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
+			pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
+			if (pitch < 0)
+				pitch += 360.0;
+		}
+		
+		if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
+		{
+			if (b->entity != cl.playernum+1)
+			{
+				framenum = 2;
+//				Com_Printf ("Third person\n");
+				ent.angles[0] = -pitch;
+				ent.angles[1] = yaw + 180.0;
+				ent.angles[2] = 0;
+//				Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b->offset[0], b->offset[1], b->offset[2]);
+				AngleVectors(ent.angles, f, r, u);
+					
+				// if it's a non-origin offset, it's a player, so use the hardcoded player offset
+				if (!VectorCompare (b->offset, vec3_origin))
+				{
+					VectorMA (org, -(b->offset[0])+1, r, org);
+					VectorMA (org, -(b->offset[1]), f, org);
+					VectorMA (org, -(b->offset[2])-10, u, org);
+				}
+				else
+				{
+					// if it's a monster, do the particle effect
+					CL_MonsterPlasma_Shell(b->start);
+				}
+			}
+			else
+			{
+				framenum = 1;
+			}
+		}
+
+		// if it's the heatbeam, draw the particle effect
+		if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1)))
+		{
+			CL_Heatbeam (org, dist);
+		}
+
+	// add new entities for the beams
+		d = VectorNormalize(dist);
+
+		memset (&ent, 0, sizeof(ent));
+		if (b->model == cl_mod_heatbeam)
+		{
+			model_length = 32.0;
+		}
+		else if (b->model == cl_mod_lightning)
+		{
+			model_length = 35.0;
+			d-= 20.0;  // correction so it doesn't end in middle of tesla
+		}
+		else
+		{
+			model_length = 30.0;
+		}
+		steps = ceil(d/model_length);
+		len = (d-model_length)/(steps-1);
+
+		// PMM - special case for lightning model .. if the real length is shorter than the model,
+		// flip it around & draw it from the end to the start.  This prevents the model from going
+		// through the tesla mine (instead it goes through the target)
+		if ((b->model == cl_mod_lightning) && (d <= model_length))
+		{
+//			Com_Printf ("special case\n");
+			VectorCopy (b->end, ent.origin);
+			// offset to push beam outside of tesla model (negative because dist is from end to start
+			// for this beam)
+//			for (j=0 ; j<3 ; j++)
+//				ent.origin[j] -= dist[j]*10.0;
+			ent.model = b->model;
+			ent.flags = RF_FULLBRIGHT;
+			ent.angles[0] = pitch;
+			ent.angles[1] = yaw;
+			ent.angles[2] = rand()%360;
+			V_AddEntity (&ent);			
+			return;
+		}
+		while (d > 0)
+		{
+			VectorCopy (org, ent.origin);
+			ent.model = b->model;
+			if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
+			{
+//				ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+//				ent.alpha = 0.3;
+				ent.flags = RF_FULLBRIGHT;
+				ent.angles[0] = -pitch;
+				ent.angles[1] = yaw + 180.0;
+				ent.angles[2] = (cl.time) % 360;
+//				ent.angles[2] = rand()%360;
+				ent.frame = framenum;
+			}
+			else if (b->model == cl_mod_lightning)
+			{
+				ent.flags = RF_FULLBRIGHT;
+				ent.angles[0] = -pitch;
+				ent.angles[1] = yaw + 180.0;
+				ent.angles[2] = rand()%360;
+			}
+			else
+			{
+				ent.angles[0] = pitch;
+				ent.angles[1] = yaw;
+				ent.angles[2] = rand()%360;
+			}
+			
+//			Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
+			V_AddEntity (&ent);
+
+			for (j=0 ; j<3 ; j++)
+				org[j] += dist[j]*len;
+			d -= model_length;
+		}
+	}
+}
+
+/*
+=================
+CL_AddExplosions
+=================
+*/
+void CL_AddExplosions (void)
+{
+	entity_t	*ent;
+	int			i;
+	explosion_t	*ex;
+	float		frac;
+	int			f;
+
+	memset (&ent, 0, sizeof(ent));
+
+	for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++)
+	{
+		if (ex->type == ex_free)
+			continue;
+		frac = (cl.time - ex->start)/100.0;
+		f = floor(frac);
+
+		ent = &ex->ent;
+
+		switch (ex->type)
+		{
+		case ex_mflash:
+			if (f >= ex->frames-1)
+				ex->type = ex_free;
+			break;
+		case ex_misc:
+			if (f >= ex->frames-1)
+			{
+				ex->type = ex_free;
+				break;
+			}
+			ent->alpha = 1.0 - frac/(ex->frames-1);
+			break;
+		case ex_flash:
+			if (f >= 1)
+			{
+				ex->type = ex_free;
+				break;
+			}
+			ent->alpha = 1.0;
+			break;
+		case ex_poly:
+			if (f >= ex->frames-1)
+			{
+				ex->type = ex_free;
+				break;
+			}
+
+			ent->alpha = (16.0 - (float)f)/16.0;
+
+			if (f < 10)
+			{
+				ent->skinnum = (f>>1);
+				if (ent->skinnum < 0)
+					ent->skinnum = 0;
+			}
+			else
+			{
+				ent->flags |= RF_TRANSLUCENT;
+				if (f < 13)
+					ent->skinnum = 5;
+				else
+					ent->skinnum = 6;
+			}
+			break;
+		case ex_poly2:
+			if (f >= ex->frames-1)
+			{
+				ex->type = ex_free;
+				break;
+			}
+
+			ent->alpha = (5.0 - (float)f)/5.0;
+			ent->skinnum = 0;
+			ent->flags |= RF_TRANSLUCENT;
+			break;
+		}
+
+		if (ex->type == ex_free)
+			continue;
+		if (ex->light)
+		{
+			V_AddLight (ent->origin, ex->light*ent->alpha,
+				ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]);
+		}
+
+		VectorCopy (ent->origin, ent->oldorigin);
+
+		if (f < 0)
+			f = 0;
+		ent->frame = ex->baseframe + f + 1;
+		ent->oldframe = ex->baseframe + f;
+		ent->backlerp = 1.0 - cl.lerpfrac;
+
+		V_AddEntity (ent);
+	}
+}
+
+
+/*
+=================
+CL_AddLasers
+=================
+*/
+void CL_AddLasers (void)
+{
+	laser_t		*l;
+	int			i;
+
+	for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
+	{
+		if (l->endtime >= cl.time)
+			V_AddEntity (&l->ent);
+	}
+}
+
+/* PMM - CL_Sustains */
+void CL_ProcessSustain (void)
+{
+	cl_sustain_t	*s;
+	int				i;
+
+	for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++)
+	{
+		if (s->id)
+			if ((s->endtime >= cl.time) && (cl.time >= s->nextthink))
+			{
+//				Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval);
+				s->think (s);
+			}
+			else if (s->endtime < cl.time)
+				s->id = 0;
+	}
+}
+
+/*
+=================
+CL_AddTEnts
+=================
+*/
+void CL_AddTEnts (void)
+{
+	CL_AddBeams ();
+	// PMM - draw plasma beams
+	CL_AddPlayerBeams ();
+	CL_AddExplosions ();
+	CL_AddLasers ();
+	// PMM - set up sustain
+	CL_ProcessSustain();
+}
--- /dev/null
+++ b/cl_view.c
@@ -1,0 +1,569 @@
+// cl_view.c -- player rendering positioning
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+//=============
+//
+// development tools for weapons
+//
+int			gun_frame;
+model_t	*gun_model;
+
+//=============
+
+cvar_t		*crosshair;
+cvar_t		*cl_testparticles;
+cvar_t		*cl_testentities;
+cvar_t		*cl_testlights;
+cvar_t		*cl_testblend;
+
+cvar_t		*cl_stats;
+
+
+int			r_numdlights;
+dlight_t	r_dlights[MAX_DLIGHTS];
+
+int			r_numentities;
+entity_t	r_entities[MAX_ENTITIES];
+
+int			r_numparticles;
+particle_t	r_particles[MAX_PARTICLES];
+
+lightstyle_t	r_lightstyles[MAX_LIGHTSTYLES];
+
+char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
+int num_cl_weaponmodels;
+
+/*
+====================
+V_ClearScene
+
+Specifies the model that will be used as the world
+====================
+*/
+void V_ClearScene (void)
+{
+	r_numdlights = 0;
+	r_numentities = 0;
+	r_numparticles = 0;
+}
+
+
+/*
+=====================
+V_AddEntity
+
+=====================
+*/
+void V_AddEntity (entity_t *ent)
+{
+	if (r_numentities >= MAX_ENTITIES)
+		return;
+	r_entities[r_numentities++] = *ent;
+}
+
+
+/*
+=====================
+V_AddParticle
+
+=====================
+*/
+void V_AddParticle (vec3_t org, int color, float alpha)
+{
+	particle_t	*p;
+
+	if (r_numparticles >= MAX_PARTICLES)
+		return;
+	p = &r_particles[r_numparticles++];
+	VectorCopy (org, p->origin);
+	p->color = color;
+	p->alpha = alpha;
+}
+
+/*
+=====================
+V_AddLight
+
+=====================
+*/
+void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
+{
+	dlight_t	*dl;
+
+	if (r_numdlights >= MAX_DLIGHTS)
+		return;
+	dl = &r_dlights[r_numdlights++];
+	VectorCopy (org, dl->origin);
+	dl->intensity = intensity;
+	dl->color[0] = r;
+	dl->color[1] = g;
+	dl->color[2] = b;
+}
+
+
+/*
+=====================
+V_AddLightStyle
+
+=====================
+*/
+void V_AddLightStyle (int style, float r, float g, float b)
+{
+	lightstyle_t	*ls;
+
+	if (style < 0 || style > MAX_LIGHTSTYLES)
+		Com_Error (ERR_DROP, "Bad light style %i", style);
+	ls = &r_lightstyles[style];
+
+	ls->white = r+g+b;
+	ls->rgb[0] = r;
+	ls->rgb[1] = g;
+	ls->rgb[2] = b;
+}
+
+/*
+================
+V_TestParticles
+
+If cl_testparticles is set, create 4096 particles in the view
+================
+*/
+void V_TestParticles (void)
+{
+	particle_t	*p;
+	int			i, j;
+	float		d, r, u;
+
+	r_numparticles = MAX_PARTICLES;
+	for (i=0 ; i<r_numparticles ; i++)
+	{
+		d = i*0.25;
+		r = 4*((i&7)-3.5);
+		u = 4*(((i>>3)&7)-3.5);
+		p = &r_particles[i];
+
+		for (j=0 ; j<3 ; j++)
+			p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*d +
+			cl.v_right[j]*r + cl.v_up[j]*u;
+
+		p->color = 8;
+		p->alpha = cl_testparticles->value;
+	}
+}
+
+/*
+================
+V_TestEntities
+
+If cl_testentities is set, create 32 player models
+================
+*/
+void V_TestEntities (void)
+{
+	int			i, j;
+	float		f, r;
+	entity_t	*ent;
+
+	r_numentities = 32;
+	memset (r_entities, 0, sizeof(r_entities));
+
+	for (i=0 ; i<r_numentities ; i++)
+	{
+		ent = &r_entities[i];
+
+		r = 64 * ( (i%4) - 1.5 );
+		f = 64 * (i/4) + 128;
+
+		for (j=0 ; j<3 ; j++)
+			ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
+			cl.v_right[j]*r;
+
+		ent->model = cl.baseclientinfo.model;
+		ent->skin = cl.baseclientinfo.skin;
+	}
+}
+
+/*
+================
+V_TestLights
+
+If cl_testlights is set, create 32 lights models
+================
+*/
+void V_TestLights (void)
+{
+	int			i, j;
+	float		f, r;
+	dlight_t	*dl;
+
+	r_numdlights = 32;
+	memset (r_dlights, 0, sizeof(r_dlights));
+
+	for (i=0 ; i<r_numdlights ; i++)
+	{
+		dl = &r_dlights[i];
+
+		r = 64 * ( (i%4) - 1.5 );
+		f = 64 * (i/4) + 128;
+
+		for (j=0 ; j<3 ; j++)
+			dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
+			cl.v_right[j]*r;
+		dl->color[0] = ((i%6)+1) & 1;
+		dl->color[1] = (((i%6)+1) & 2)>>1;
+		dl->color[2] = (((i%6)+1) & 4)>>2;
+		dl->intensity = 200;
+	}
+}
+
+//===================================================================
+
+/*
+=================
+CL_PrepRefresh
+
+Call before entering a new level, or after changing dlls
+=================
+*/
+void CL_PrepRefresh (void)
+{
+	char		mapname[32];
+	int			i;
+	char		name[MAX_QPATH];
+	float		rotate;
+	vec3_t		axis;
+
+	if (!cl.configstrings[CS_MODELS+1][0])
+		return;		// no map loaded
+
+	SCR_AddDirtyPoint (0, 0);
+	SCR_AddDirtyPoint (vid.width-1, vid.height-1);
+
+	// let the render dll load the map
+	strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5);	// skip "maps/"
+	mapname[strlen(mapname)-4] = 0;		// cut off ".bsp"
+
+	// register models, pics, and skins
+	Com_Printf ("Map: %s\r", mapname); 
+	SCR_UpdateScreen ();
+	re.BeginRegistration (mapname);
+	Com_Printf ("                                     \r");
+
+	// precache status bar pics
+	Com_Printf ("pics\r"); 
+	SCR_UpdateScreen ();
+	SCR_TouchPics ();
+	Com_Printf ("                                     \r");
+
+	CL_RegisterTEntModels ();
+
+	num_cl_weaponmodels = 1;
+	strcpy(cl_weaponmodels[0], "weapon.md2");
+
+	for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
+	{
+		strcpy (name, cl.configstrings[CS_MODELS+i]);
+		name[37] = 0;	// never go beyond one line
+		if (name[0] != '*')
+			Com_Printf ("%s\r", name); 
+		SCR_UpdateScreen ();
+		Sys_SendKeyEvents ();	// pump message loop
+		if (name[0] == '#')
+		{
+			// special player weapon model
+			if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
+			{
+				strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
+					sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
+				num_cl_weaponmodels++;
+			}
+		} 
+		else
+		{
+			cl.model_draw[i] = re.RegisterModel (cl.configstrings[CS_MODELS+i]);
+			if (name[0] == '*')
+				cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
+			else
+				cl.model_clip[i] = NULL;
+		}
+		if (name[0] != '*')
+			Com_Printf ("                                     \r");
+	}
+
+	Com_Printf ("images\r", i); 
+	SCR_UpdateScreen ();
+	for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
+	{
+		cl.image_precache[i] = re.RegisterPic (cl.configstrings[CS_IMAGES+i]);
+		Sys_SendKeyEvents ();	// pump message loop
+	}
+	
+	Com_Printf ("                                     \r");
+	for (i=0 ; i<MAX_CLIENTS ; i++)
+	{
+		if (!cl.configstrings[CS_PLAYERSKINS+i][0])
+			continue;
+		Com_Printf ("client %i\r", i); 
+		SCR_UpdateScreen ();
+		Sys_SendKeyEvents ();	// pump message loop
+		CL_ParseClientinfo (i);
+		Com_Printf ("                                     \r");
+	}
+
+	CL_LoadClientinfo (&cl.baseclientinfo, "unnamed\\male/grunt");
+
+	// set sky textures and speed
+	Com_Printf ("sky\r", i); 
+	SCR_UpdateScreen ();
+	rotate = atof (cl.configstrings[CS_SKYROTATE]);
+	sscanf (cl.configstrings[CS_SKYAXIS], "%f %f %f", 
+		&axis[0], &axis[1], &axis[2]);
+	re.SetSky (cl.configstrings[CS_SKY], rotate, axis);
+	Com_Printf ("                                     \r");
+
+	// the renderer can now free unneeded stuff
+	re.EndRegistration ();
+
+	// clear any lines of console text
+	Con_ClearNotify ();
+
+	SCR_UpdateScreen ();
+	cl.refresh_prepped = true;
+	cl.force_refdef = true;	// make sure we have a valid refdef
+
+	// start the cd track
+	CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
+}
+
+/*
+====================
+CalcFov
+====================
+*/
+float CalcFov (float fov_x, float width, float height)
+{
+	float	a;
+	float	x;
+
+	if (fov_x < 1 || fov_x > 179)
+		Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
+
+	x = width/tan(fov_x/360*M_PI);
+
+	a = atan (height/x);
+
+	a = a*360/M_PI;
+
+	return a;
+}
+
+//============================================================================
+
+// gun frame debugging functions
+void V_Gun_Next_f (void)
+{
+	gun_frame++;
+	Com_Printf ("frame %i\n", gun_frame);
+}
+
+void V_Gun_Prev_f (void)
+{
+	gun_frame--;
+	if (gun_frame < 0)
+		gun_frame = 0;
+	Com_Printf ("frame %i\n", gun_frame);
+}
+
+void V_Gun_Model_f (void)
+{
+	char	name[MAX_QPATH];
+
+	if (Cmd_Argc() != 2)
+	{
+		gun_model = NULL;
+		return;
+	}
+	Com_sprintf (name, sizeof(name), "models/%s/tris.md2", Cmd_Argv(1));
+	gun_model = re.RegisterModel (name);
+}
+
+//============================================================================
+
+
+/*
+=================
+SCR_DrawCrosshair
+=================
+*/
+void SCR_DrawCrosshair (void)
+{
+	if (!crosshair->value)
+		return;
+
+	if (crosshair->modified)
+	{
+		crosshair->modified = false;
+		SCR_TouchPics ();
+	}
+
+	if (!crosshair_pic[0])
+		return;
+
+	re.DrawPic (scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1)
+	, scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1), crosshair_pic);
+}
+
+/*
+==================
+V_RenderView
+
+==================
+*/
+void V_RenderView( float stereo_separation )
+{
+	extern int entitycmpfnc(entity_t *, entity_t *);
+
+	if (cls.state != ca_active)
+		return;
+
+	if (!cl.refresh_prepped)
+		return;			// still loading
+
+	if (cl_timedemo->value)
+	{
+		if (!cl.timedemo_start)
+			cl.timedemo_start = Sys_Milliseconds ();
+		cl.timedemo_frames++;
+	}
+
+	// an invalid frame will just use the exact previous refdef
+	// we can't use the old frame if the video mode has changed, though...
+	if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
+	{
+		cl.force_refdef = false;
+
+		V_ClearScene ();
+
+		// build a refresh entity list and calc cl.sim*
+		// this also calls CL_CalcViewValues which loads
+		// v_forward, etc.
+		CL_AddEntities ();
+
+		if (cl_testparticles->value)
+			V_TestParticles ();
+		if (cl_testentities->value)
+			V_TestEntities ();
+		if (cl_testlights->value)
+			V_TestLights ();
+		if (cl_testblend->value)
+		{
+			cl.refdef.blend[0] = 1;
+			cl.refdef.blend[1] = 0.5;
+			cl.refdef.blend[2] = 0.25;
+			cl.refdef.blend[3] = 0.5;
+		}
+
+		// offset vieworg appropriately if we're doing stereo separation
+		if ( stereo_separation != 0 )
+		{
+			vec3_t tmp;
+
+			VectorScale( cl.v_right, stereo_separation, tmp );
+			VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
+		}
+
+		// never let it sit exactly on a node line, because a water plane can
+		// dissapear when viewed with the eye exactly on it.
+		// the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
+		cl.refdef.vieworg[0] += 1.0/16;
+		cl.refdef.vieworg[1] += 1.0/16;
+		cl.refdef.vieworg[2] += 1.0/16;
+
+		cl.refdef.x = scr_vrect.x;
+		cl.refdef.y = scr_vrect.y;
+		cl.refdef.width = scr_vrect.width;
+		cl.refdef.height = scr_vrect.height;
+		cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
+		cl.refdef.time = cl.time*0.001;
+
+		cl.refdef.areabits = cl.frame.areabits;
+
+		if (!cl_add_entities->value)
+			r_numentities = 0;
+		if (!cl_add_particles->value)
+			r_numparticles = 0;
+		if (!cl_add_lights->value)
+			r_numdlights = 0;
+		if (!cl_add_blend->value)
+		{
+			VectorClear (cl.refdef.blend);
+		}
+
+		cl.refdef.num_entities = r_numentities;
+		cl.refdef.entities = r_entities;
+		cl.refdef.num_particles = r_numparticles;
+		cl.refdef.particles = r_particles;
+		cl.refdef.num_dlights = r_numdlights;
+		cl.refdef.dlights = r_dlights;
+		cl.refdef.lightstyles = r_lightstyles;
+
+		cl.refdef.rdflags = cl.frame.playerstate.rdflags;
+
+		// sort entities for better cache locality
+        qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(void *, void *))entitycmpfnc );
+	}
+
+	re.RenderFrame (&cl.refdef);
+	if (cl_stats->value)
+		Com_Printf ("ent:%i  lt:%i  part:%i\n", r_numentities, r_numdlights, r_numparticles);
+	if ( log_stats->value && ( log_stats_file != 0 ) )
+		fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
+
+
+	SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y);
+	SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1,
+		scr_vrect.y+scr_vrect.height-1);
+
+	SCR_DrawCrosshair ();
+}
+
+
+/*
+=============
+V_Viewpos_f
+=============
+*/
+void V_Viewpos_f (void)
+{
+	Com_Printf ("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
+		(int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2], 
+		(int)cl.refdef.viewangles[YAW]);
+}
+
+/*
+=============
+V_Init
+=============
+*/
+void V_Init (void)
+{
+	Cmd_AddCommand ("gun_next", V_Gun_Next_f);
+	Cmd_AddCommand ("gun_prev", V_Gun_Prev_f);
+	Cmd_AddCommand ("gun_model", V_Gun_Model_f);
+
+	Cmd_AddCommand ("viewpos", V_Viewpos_f);
+
+	crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
+
+	cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
+	cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
+	cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
+	cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
+
+	cl_stats = Cvar_Get ("cl_stats", "0", 0);
+}
--- a/client/cdaudio.h
+++ /dev/null
@@ -1,6 +1,0 @@
-int	CDAudio_Init(void);
-void	CDAudio_Shutdown(void);
-void	CDAudio_Play(int track, qboolean looping);
-void	CDAudio_Stop(void);
-void	CDAudio_Update(void);
-void	CDAudio_Activate (qboolean active);
--- a/client/cl_cin.c
+++ /dev/null
@@ -1,632 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-typedef struct
-{
-	byte	*data;
-	int		count;
-} cblock_t;
-
-typedef struct
-{
-	qboolean	restart_sound;
-	int		s_rate;
-	int		s_width;
-	int		s_channels;
-
-	int		width;
-	int		height;
-	byte	*pic;
-	byte	*pic_pending;
-
-	// order 1 huffman stuff
-	int		*hnodes1;	// [256][256][2];
-	int		numhnodes1[256];
-
-	int		h_used[512];
-	int		h_count[512];
-} cinematics_t;
-
-cinematics_t	cin;
-
-/*
-=================================================================
-
-PCX LOADING
-
-=================================================================
-*/
-
-
-/*
-==============
-SCR_LoadPCX
-==============
-*/
-void SCR_LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
-{
-	byte	*raw;
-	pcx_t	*pcx;
-	int		x, y;
-	int		len;
-	int		dataByte, runLength;
-	byte	*out, *pix;
-
-	*pic = NULL;
-
-	//
-	// load the file
-	//
-	len = FS_LoadFile (filename, (void **)&raw);
-	if (!raw)
-		return;	// Com_Printf ("Bad pcx file %s\n", filename);
-
-	//
-	// parse the PCX file
-	//
-	pcx = (pcx_t *)raw;
-	raw = &pcx->data;
-
-	if (pcx->manufacturer != 0x0a
-		|| pcx->version != 5
-		|| pcx->encoding != 1
-		|| pcx->bits_per_pixel != 8
-		|| pcx->xmax >= 640
-		|| pcx->ymax >= 480)
-	{
-		Com_Printf ("Bad pcx file %s\n", filename);
-		return;
-	}
-
-	out = Z_Malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
-
-	*pic = out;
-
-	pix = out;
-
-	if (palette)
-	{
-		*palette = Z_Malloc(768);
-		memcpy (*palette, (byte *)pcx + len - 768, 768);
-	}
-
-	if (width)
-		*width = pcx->xmax+1;
-	if (height)
-		*height = pcx->ymax+1;
-
-	for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
-	{
-		for (x=0 ; x<=pcx->xmax ; )
-		{
-			dataByte = *raw++;
-
-			if((dataByte & 0xC0) == 0xC0)
-			{
-				runLength = dataByte & 0x3F;
-				dataByte = *raw++;
-			}
-			else
-				runLength = 1;
-
-			while(runLength-- > 0)
-				pix[x++] = dataByte;
-		}
-
-	}
-
-	if ( raw - (byte *)pcx > len)
-	{
-		Com_Printf ("PCX file %s was malformed", filename);
-		Z_Free (*pic);
-		*pic = NULL;
-	}
-
-	FS_FreeFile (pcx);
-}
-
-//=============================================================
-
-/*
-==================
-SCR_StopCinematic
-==================
-*/
-void SCR_StopCinematic (void)
-{
-	cl.cinematictime = 0;	// done
-	if (cin.pic)
-	{
-		Z_Free (cin.pic);
-		cin.pic = NULL;
-	}
-	if (cin.pic_pending)
-	{
-		Z_Free (cin.pic_pending);
-		cin.pic_pending = NULL;
-	}
-	if (cl.cinematicpalette_active)
-	{
-		re.CinematicSetPalette(NULL);
-		cl.cinematicpalette_active = false;
-	}
-	if (cl.cinematic_file)
-	{
-		fclose (cl.cinematic_file);
-		cl.cinematic_file = NULL;
-	}
-	if (cin.hnodes1)
-	{
-		Z_Free (cin.hnodes1);
-		cin.hnodes1 = NULL;
-	}
-
-	// switch back down to 11 khz sound if necessary
-	if (cin.restart_sound)
-	{
-		cin.restart_sound = false;
-		CL_Snd_Restart_f ();
-	}
-
-}
-
-/*
-====================
-SCR_FinishCinematic
-
-Called when either the cinematic completes, or it is aborted
-====================
-*/
-void SCR_FinishCinematic (void)
-{
-	// tell the server to advance to the next map / cinematic
-	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
-	SZ_Print (&cls.netchan.message, va("nextserver %i\n", cl.servercount));
-}
-
-//==========================================================================
-
-/*
-==================
-SmallestNode1
-==================
-*/
-int	SmallestNode1 (int numhnodes)
-{
-	int		i;
-	int		best, bestnode;
-
-	best = 99999999;
-	bestnode = -1;
-	for (i=0 ; i<numhnodes ; i++)
-	{
-		if (cin.h_used[i])
-			continue;
-		if (!cin.h_count[i])
-			continue;
-		if (cin.h_count[i] < best)
-		{
-			best = cin.h_count[i];
-			bestnode = i;
-		}
-	}
-
-	if (bestnode == -1)
-		return -1;
-
-	cin.h_used[bestnode] = true;
-	return bestnode;
-}
-
-
-/*
-==================
-Huff1TableInit
-
-Reads the 64k counts table and initializes the node trees
-==================
-*/
-void Huff1TableInit (void)
-{
-	int		prev;
-	int		j;
-	int		*node, *nodebase;
-	byte	counts[256];
-	int		numhnodes;
-
-	cin.hnodes1 = Z_Malloc (256*256*2*4);
-	memset (cin.hnodes1, 0, 256*256*2*4);
-
-	for (prev=0 ; prev<256 ; prev++)
-	{
-		memset (cin.h_count,0,sizeof(cin.h_count));
-		memset (cin.h_used,0,sizeof(cin.h_used));
-
-		// read a row of counts
-		FS_Read (counts, sizeof(counts), cl.cinematic_file);
-		for (j=0 ; j<256 ; j++)
-			cin.h_count[j] = counts[j];
-
-		// build the nodes
-		numhnodes = 256;
-		nodebase = cin.hnodes1 + prev*256*2;
-
-		while (numhnodes != 511)
-		{
-			node = nodebase + (numhnodes-256)*2;
-
-			// pick two lowest counts
-			node[0] = SmallestNode1 (numhnodes);
-			if (node[0] == -1)
-				break;	// no more
-
-			node[1] = SmallestNode1 (numhnodes);
-			if (node[1] == -1)
-				break;
-
-			cin.h_count[numhnodes] = cin.h_count[node[0]] + cin.h_count[node[1]];
-			numhnodes++;
-		}
-
-		cin.numhnodes1[prev] = numhnodes-1;
-	}
-}
-
-/*
-==================
-Huff1Decompress
-==================
-*/
-cblock_t Huff1Decompress (cblock_t in)
-{
-	byte		*input;
-	byte		*out_p;
-	int			nodenum;
-	int			count;
-	cblock_t	out;
-	int			inbyte;
-	int			*hnodes, *hnodesbase;
-//int		i;
-
-	// get decompressed count
-	count = in.data[0] + (in.data[1]<<8) + (in.data[2]<<16) + (in.data[3]<<24);
-	input = in.data + 4;
-	out_p = out.data = Z_Malloc (count);
-
-	// read bits
-
-	hnodesbase = cin.hnodes1 - 256*2;	// nodes 0-255 aren't stored
-
-	hnodes = hnodesbase;
-	nodenum = cin.numhnodes1[0];
-	while (count)
-	{
-		inbyte = *input++;
-		//-----------
-		if (nodenum < 256)
-		{
-			hnodes = hnodesbase + (nodenum<<9);
-			*out_p++ = nodenum;
-			if (!--count)
-				break;
-			nodenum = cin.numhnodes1[nodenum];
-		}
-		nodenum = hnodes[nodenum*2 + (inbyte&1)];
-		inbyte >>=1;
-		//-----------
-		if (nodenum < 256)
-		{
-			hnodes = hnodesbase + (nodenum<<9);
-			*out_p++ = nodenum;
-			if (!--count)
-				break;
-			nodenum = cin.numhnodes1[nodenum];
-		}
-		nodenum = hnodes[nodenum*2 + (inbyte&1)];
-		inbyte >>=1;
-		//-----------
-		if (nodenum < 256)
-		{
-			hnodes = hnodesbase + (nodenum<<9);
-			*out_p++ = nodenum;
-			if (!--count)
-				break;
-			nodenum = cin.numhnodes1[nodenum];
-		}
-		nodenum = hnodes[nodenum*2 + (inbyte&1)];
-		inbyte >>=1;
-		//-----------
-		if (nodenum < 256)
-		{
-			hnodes = hnodesbase + (nodenum<<9);
-			*out_p++ = nodenum;
-			if (!--count)
-				break;
-			nodenum = cin.numhnodes1[nodenum];
-		}
-		nodenum = hnodes[nodenum*2 + (inbyte&1)];
-		inbyte >>=1;
-		//-----------
-		if (nodenum < 256)
-		{
-			hnodes = hnodesbase + (nodenum<<9);
-			*out_p++ = nodenum;
-			if (!--count)
-				break;
-			nodenum = cin.numhnodes1[nodenum];
-		}
-		nodenum = hnodes[nodenum*2 + (inbyte&1)];
-		inbyte >>=1;
-		//-----------
-		if (nodenum < 256)
-		{
-			hnodes = hnodesbase + (nodenum<<9);
-			*out_p++ = nodenum;
-			if (!--count)
-				break;
-			nodenum = cin.numhnodes1[nodenum];
-		}
-		nodenum = hnodes[nodenum*2 + (inbyte&1)];
-		inbyte >>=1;
-		//-----------
-		if (nodenum < 256)
-		{
-			hnodes = hnodesbase + (nodenum<<9);
-			*out_p++ = nodenum;
-			if (!--count)
-				break;
-			nodenum = cin.numhnodes1[nodenum];
-		}
-		nodenum = hnodes[nodenum*2 + (inbyte&1)];
-		inbyte >>=1;
-		//-----------
-		if (nodenum < 256)
-		{
-			hnodes = hnodesbase + (nodenum<<9);
-			*out_p++ = nodenum;
-			if (!--count)
-				break;
-			nodenum = cin.numhnodes1[nodenum];
-		}
-		nodenum = hnodes[nodenum*2 + (inbyte&1)];
-	}
-
-	if (input - in.data != in.count && input - in.data != in.count+1)
-	{
-		Com_Printf ("Decompression overread by %i", (input - in.data) - in.count);
-	}
-	out.count = out_p - out.data;
-
-	return out;
-}
-
-/*
-==================
-SCR_ReadNextFrame
-==================
-*/
-byte *SCR_ReadNextFrame (void)
-{
-	int		r;
-	int		command;
-	byte	samples[22050/14*4];
-	byte	compressed[0x20000];
-	int		size;
-	byte	*pic;
-	cblock_t	in, huf1;
-	int		start, end, count;
-
-	// read the next frame
-	r = fread (&command, 4, 1, cl.cinematic_file);
-	if (r == 0)		// we'll give it one more chance
-		r = fread (&command, 4, 1, cl.cinematic_file);
-
-	if (r != 1)
-		return NULL;
-	command = LittleLong(command);
-	if (command == 2)
-		return NULL;	// last frame marker
-
-	if (command == 1)
-	{	// read palette
-		FS_Read (cl.cinematicpalette, sizeof(cl.cinematicpalette), cl.cinematic_file);
-		cl.cinematicpalette_active=0;	// dubious....  exposes an edge case
-	}
-
-	// decompress the next frame
-	FS_Read (&size, 4, cl.cinematic_file);
-	size = LittleLong(size);
-	if (size > sizeof(compressed) || size < 1)
-		Com_Error (ERR_DROP, "Bad compressed frame size");
-	FS_Read (compressed, size, cl.cinematic_file);
-
-	// read sound
-	start = cl.cinematicframe*cin.s_rate/14;
-	end = (cl.cinematicframe+1)*cin.s_rate/14;
-	count = end - start;
-
-	FS_Read (samples, count*cin.s_width*cin.s_channels, cl.cinematic_file);
-
-	S_RawSamples (count, cin.s_rate, cin.s_width, cin.s_channels, samples);
-
-	in.data = compressed;
-	in.count = size;
-
-	huf1 = Huff1Decompress (in);
-
-	pic = huf1.data;
-
-	cl.cinematicframe++;
-
-	return pic;
-}
-
-
-/*
-==================
-SCR_RunCinematic
-
-==================
-*/
-void SCR_RunCinematic (void)
-{
-	int		frame;
-
-	if (cl.cinematictime <= 0)
-	{
-		SCR_StopCinematic ();
-		return;
-	}
-
-	if (cl.cinematicframe == -1)
-		return;		// static image
-
-	if (cls.key_dest != key_game)
-	{	// pause if menu or console is up
-		cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
-		return;
-	}
-
-	frame = (cls.realtime - cl.cinematictime)*14.0/1000;
-	if (frame <= cl.cinematicframe)
-		return;
-	if (frame > cl.cinematicframe+1)
-	{
-		Com_Printf ("Dropped frame: %i > %i\n", frame, cl.cinematicframe+1);
-		cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
-	}
-	if (cin.pic)
-		Z_Free (cin.pic);
-	cin.pic = cin.pic_pending;
-	cin.pic_pending = NULL;
-	cin.pic_pending = SCR_ReadNextFrame ();
-	if (!cin.pic_pending)
-	{
-		SCR_StopCinematic ();
-		SCR_FinishCinematic ();
-		cl.cinematictime = 1;	// hack to get the black screen behind loading
-		SCR_BeginLoadingPlaque ();
-		cl.cinematictime = 0;
-		return;
-	}
-}
-
-/*
-==================
-SCR_DrawCinematic
-
-Returns true if a cinematic is active, meaning the view rendering
-should be skipped
-==================
-*/
-qboolean SCR_DrawCinematic (void)
-{
-	if (cl.cinematictime <= 0)
-	{
-		return false;
-	}
-
-	if (cls.key_dest == key_menu)
-	{	// blank screen and pause if menu is up
-		re.CinematicSetPalette(NULL);
-		cl.cinematicpalette_active = false;
-		return true;
-	}
-
-	if (!cl.cinematicpalette_active)
-	{
-		re.CinematicSetPalette((uchar *)cl.cinematicpalette);
-		cl.cinematicpalette_active = true;
-	}
-
-	if (!cin.pic)
-		return true;
-
-	re.DrawStretchRaw (0, 0, vid.width, vid.height, cin.width, cin.height, cin.pic);
-
-	return true;
-}
-
-/*
-==================
-SCR_PlayCinematic
-
-==================
-*/
-void SCR_PlayCinematic (char *arg)
-{
-	int		width, height;
-	byte	*palette;
-	char	name[MAX_OSPATH], *dot;
-	int		old_khz;
-
-	// make sure CD isn't playing music
-	CDAudio_Stop();
-
-	cl.cinematicframe = 0;
-	dot = strstr (arg, ".");
-	if (dot && !strcmp (dot, ".pcx"))
-	{	// static pcx image
-		Com_sprintf (name, sizeof(name), "pics/%s", arg);
-		SCR_LoadPCX (name, &cin.pic, &palette, &cin.width, &cin.height);
-		cl.cinematicframe = -1;
-		cl.cinematictime = 1;
-		SCR_EndLoadingPlaque ();
-		cls.state = ca_active;
-		if (!cin.pic)
-		{
-			Com_Printf ("%s not found.\n", name);
-			cl.cinematictime = 0;
-		}
-		else
-		{
-			memcpy (cl.cinematicpalette, palette, sizeof(cl.cinematicpalette));
-			Z_Free (palette);
-		}
-		return;
-	}
-
-	Com_sprintf (name, sizeof(name), "video/%s", arg);
-	FS_FOpenFile (name, &cl.cinematic_file);
-	if (!cl.cinematic_file)
-	{
-//		Com_Error (ERR_DROP, "Cinematic %s not found.\n", name);
-		SCR_FinishCinematic ();
-		cl.cinematictime = 0;	// done
-		return;
-	}
-
-	SCR_EndLoadingPlaque ();
-
-	cls.state = ca_active;
-
-	FS_Read (&width, 4, cl.cinematic_file);
-	FS_Read (&height, 4, cl.cinematic_file);
-	cin.width = LittleLong(width);
-	cin.height = LittleLong(height);
-
-	FS_Read (&cin.s_rate, 4, cl.cinematic_file);
-	cin.s_rate = LittleLong(cin.s_rate);
-	FS_Read (&cin.s_width, 4, cl.cinematic_file);
-	cin.s_width = LittleLong(cin.s_width);
-	FS_Read (&cin.s_channels, 4, cl.cinematic_file);
-	cin.s_channels = LittleLong(cin.s_channels);
-
-	Huff1TableInit ();
-
-	// switch up to 22 khz sound if necessary
-	old_khz = Cvar_VariableValue ("s_khz");
-	if (old_khz != cin.s_rate/1000)
-	{
-		cin.restart_sound = true;
-		Cvar_SetValue ("s_khz", cin.s_rate/1000);
-		CL_Snd_Restart_f ();
-		Cvar_SetValue ("s_khz", old_khz);
-	}
-
-	cl.cinematicframe = 0;
-	cin.pic = SCR_ReadNextFrame ();
-	cl.cinematictime = Sys_Milliseconds ();
-}
--- a/client/cl_ents.c
+++ /dev/null
@@ -1,1487 +1,0 @@
-// cl_ents.c -- entity parsing and management
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-
-extern	struct model_s	*cl_mod_powerscreen;
-
-//PGM
-int	vidref_val;
-//PGM
-
-/*
-=========================================================================
-
-FRAME PARSING
-
-=========================================================================
-*/
-
-/* the following are commented out in release
-
-typedef struct
-{
-	int		modelindex;
-	int		num; // entity number
-	int		effects;
-	vec3_t	origin;
-	vec3_t	oldorigin;
-	vec3_t	angles;
-	qboolean present;
-} projectile_t;
-
-#define	MAX_PROJECTILES	64
-projectile_t	cl_projectiles[MAX_PROJECTILES];
-
-void CL_ClearProjectiles (void)
-{
-	int i;
-
-	for (i = 0; i < MAX_PROJECTILES; i++) {
-//		if (cl_projectiles[i].present)
-//			Com_DPrintf("PROJ: %d CLEARED\n", cl_projectiles[i].num);
-		cl_projectiles[i].present = false;
-	}
-}
-
-*/
-
-/*
-=====================
-CL_ParseProjectiles
-
-Flechettes are passed as efficient temporary entities
-=====================
-*/
-/*
-void CL_ParseProjectiles (void)
-{
-	int		i, c, j;
-	byte	bits[8];
-	byte	b;
-	projectile_t	pr;
-	int lastempty = -1;
-	qboolean old = false;
-
-	c = MSG_ReadByte (&net_message);
-	for (i=0 ; i<c ; i++)
-	{
-		bits[0] = MSG_ReadByte (&net_message);
-		bits[1] = MSG_ReadByte (&net_message);
-		bits[2] = MSG_ReadByte (&net_message);
-		bits[3] = MSG_ReadByte (&net_message);
-		bits[4] = MSG_ReadByte (&net_message);
-		pr.origin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
-		pr.origin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
-		pr.origin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
-		VectorCopy(pr.origin, pr.oldorigin);
-
-		if (bits[4] & 64)
-			pr.effects = EF_BLASTER;
-		else
-			pr.effects = 0;
-
-		if (bits[4] & 128) {
-			old = true;
-			bits[0] = MSG_ReadByte (&net_message);
-			bits[1] = MSG_ReadByte (&net_message);
-			bits[2] = MSG_ReadByte (&net_message);
-			bits[3] = MSG_ReadByte (&net_message);
-			bits[4] = MSG_ReadByte (&net_message);
-			pr.oldorigin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
-			pr.oldorigin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
-			pr.oldorigin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
-		}
-
-		bits[0] = MSG_ReadByte (&net_message);
-		bits[1] = MSG_ReadByte (&net_message);
-		bits[2] = MSG_ReadByte (&net_message);
-
-		pr.angles[0] = 360*bits[0]/256;
-		pr.angles[1] = 360*bits[1]/256;
-		pr.modelindex = bits[2];
-
-		b = MSG_ReadByte (&net_message);
-		pr.num = (b & 0x7f);
-		if (b & 128) // extra entity number byte
-			pr.num |= (MSG_ReadByte (&net_message) << 7);
-
-		pr.present = true;
-
-		// find if this projectile already exists from previous frame 
-		for (j = 0; j < MAX_PROJECTILES; j++) {
-			if (cl_projectiles[j].modelindex) {
-				if (cl_projectiles[j].num == pr.num) {
-					// already present, set up oldorigin for interpolation
-					if (!old)
-						VectorCopy(cl_projectiles[j].origin, pr.oldorigin);
-					cl_projectiles[j] = pr;
-					break;
-				}
-			} else
-				lastempty = j;
-		}
-
-		// not present previous frame, add it
-		if (j == MAX_PROJECTILES) {
-			if (lastempty != -1) {
-				cl_projectiles[lastempty] = pr;
-			}
-		}
-	}
-}
-*/
-
-/*
-=============
-CL_LinkProjectiles
-
-=============
-*/
-/*
-void CL_AddProjectiles (void)
-{
-	int		i, j;
-	projectile_t	*pr;
-	entity_t		ent;
-
-	memset (&ent, 0, sizeof(ent));
-
-	for (i=0, pr=cl_projectiles ; i < MAX_PROJECTILES ; i++, pr++)
-	{
-		// grab an entity to fill in
-		if (pr->modelindex < 1)
-			continue;
-		if (!pr->present) {
-			pr->modelindex = 0;
-			continue; // not present this frame (it was in the previous frame)
-		}
-
-		ent.model = cl.model_draw[pr->modelindex];
-
-		// interpolate origin
-		for (j=0 ; j<3 ; j++)
-		{
-			ent.origin[j] = ent.oldorigin[j] = pr->oldorigin[j] + cl.lerpfrac * 
-				(pr->origin[j] - pr->oldorigin[j]);
-
-		}
-
-		if (pr->effects & EF_BLASTER)
-			CL_BlasterTrail (pr->oldorigin, ent.origin);
-		V_AddLight (pr->origin, 200, 1, 1, 0);
-
-		VectorCopy (pr->angles, ent.angles);
-		V_AddEntity (&ent);
-	}
-}
-*/
-
-/*
-=================
-CL_ParseEntityBits
-
-Returns the entity number and the header bits
-=================
-*/
-int	bitcounts[32];	/// just for protocol profiling
-int CL_ParseEntityBits (int *bits)
-{
-	unsigned	b, total;
-	int			i;
-	int			number;
-
-	total = MSG_ReadByte (&net_message);
-	if (total & U_MOREBITS1)
-	{
-		b = MSG_ReadByte (&net_message);
-		total |= b<<8;
-	}
-	if (total & U_MOREBITS2)
-	{
-		b = MSG_ReadByte (&net_message);
-		total |= b<<16;
-	}
-	if (total & U_MOREBITS3)
-	{
-		b = MSG_ReadByte (&net_message);
-		total |= b<<24;
-	}
-
-	// count the bits for net profiling
-	for (i=0 ; i<32 ; i++)
-		if (total&(1<<i))
-			bitcounts[i]++;
-
-	if (total & U_NUMBER16)
-		number = MSG_ReadShort (&net_message);
-	else
-		number = MSG_ReadByte (&net_message);
-
-	*bits = total;
-
-	return number;
-}
-
-/*
-==================
-CL_ParseDelta
-
-Can go from either a baseline or a previous packet_entity
-==================
-*/
-void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits)
-{
-	// set everything to the state we are delta'ing from
-	*to = *from;
-
-	VectorCopy (from->origin, to->old_origin);
-	to->number = number;
-
-	if (bits & U_MODEL)
-		to->modelindex = MSG_ReadByte (&net_message);
-	if (bits & U_MODEL2)
-		to->modelindex2 = MSG_ReadByte (&net_message);
-	if (bits & U_MODEL3)
-		to->modelindex3 = MSG_ReadByte (&net_message);
-	if (bits & U_MODEL4)
-		to->modelindex4 = MSG_ReadByte (&net_message);
-		
-	if (bits & U_FRAME8)
-		to->frame = MSG_ReadByte (&net_message);
-	if (bits & U_FRAME16)
-		to->frame = MSG_ReadShort (&net_message);
-
-	if ((bits & U_SKIN8) && (bits & U_SKIN16))		//used for laser colors
-		to->skinnum = MSG_ReadLong(&net_message);
-	else if (bits & U_SKIN8)
-		to->skinnum = MSG_ReadByte(&net_message);
-	else if (bits & U_SKIN16)
-		to->skinnum = MSG_ReadShort(&net_message);
-
-	if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
-		to->effects = MSG_ReadLong(&net_message);
-	else if (bits & U_EFFECTS8)
-		to->effects = MSG_ReadByte(&net_message);
-	else if (bits & U_EFFECTS16)
-		to->effects = MSG_ReadShort(&net_message);
-
-	if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
-		to->renderfx = MSG_ReadLong(&net_message);
-	else if (bits & U_RENDERFX8)
-		to->renderfx = MSG_ReadByte(&net_message);
-	else if (bits & U_RENDERFX16)
-		to->renderfx = MSG_ReadShort(&net_message);
-
-	if (bits & U_ORIGIN1)
-		to->origin[0] = MSG_ReadCoord (&net_message);
-	if (bits & U_ORIGIN2)
-		to->origin[1] = MSG_ReadCoord (&net_message);
-	if (bits & U_ORIGIN3)
-		to->origin[2] = MSG_ReadCoord (&net_message);
-		
-	if (bits & U_ANGLE1)
-		to->angles[0] = MSG_ReadAngle(&net_message);
-	if (bits & U_ANGLE2)
-		to->angles[1] = MSG_ReadAngle(&net_message);
-	if (bits & U_ANGLE3)
-		to->angles[2] = MSG_ReadAngle(&net_message);
-
-	if (bits & U_OLDORIGIN)
-		MSG_ReadPos (&net_message, to->old_origin);
-
-	if (bits & U_SOUND)
-		to->sound = MSG_ReadByte (&net_message);
-
-	if (bits & U_EVENT)
-		to->event = MSG_ReadByte (&net_message);
-	else
-		to->event = 0;
-
-	if (bits & U_SOLID)
-		to->solid = MSG_ReadShort (&net_message);
-}
-
-/*
-==================
-CL_DeltaEntity
-
-Parses deltas from the given base and adds the resulting entity
-to the current frame
-==================
-*/
-void CL_DeltaEntity (frame_t *frame, int newnum, entity_state_t *old, int bits)
-{
-	centity_t	*ent;
-	entity_state_t	*state;
-
-	ent = &cl_entities[newnum];
-
-	state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)];
-	cl.parse_entities++;
-	frame->num_entities++;
-
-	CL_ParseDelta (old, state, newnum, bits);
-
-	// some data changes will force no lerping
-	if (state->modelindex != ent->current.modelindex
-		|| state->modelindex2 != ent->current.modelindex2
-		|| state->modelindex3 != ent->current.modelindex3
-		|| state->modelindex4 != ent->current.modelindex4
-		|| abs(state->origin[0] - ent->current.origin[0]) > 512
-		|| abs(state->origin[1] - ent->current.origin[1]) > 512
-		|| abs(state->origin[2] - ent->current.origin[2]) > 512
-		|| state->event == EV_PLAYER_TELEPORT
-		|| state->event == EV_OTHER_TELEPORT
-		)
-	{
-		ent->serverframe = -99;
-	}
-
-	if (ent->serverframe != cl.frame.serverframe - 1)
-	{	// wasn't in last update, so initialize some things
-		ent->trailcount = 1024;		// for diminishing rocket / grenade trails
-		// duplicate the current state so lerping doesn't hurt anything
-		ent->prev = *state;
-		if (state->event == EV_OTHER_TELEPORT)
-		{
-			VectorCopy (state->origin, ent->prev.origin);
-			VectorCopy (state->origin, ent->lerp_origin);
-		}
-		else
-		{
-			VectorCopy (state->old_origin, ent->prev.origin);
-			VectorCopy (state->old_origin, ent->lerp_origin);
-		}
-	}
-	else
-	{	// shuffle the last state to previous
-		ent->prev = ent->current;
-	}
-
-	ent->serverframe = cl.frame.serverframe;
-	ent->current = *state;
-}
-
-/*
-==================
-CL_ParsePacketEntities
-
-An svc_packetentities has just been parsed, deal with the
-rest of the data stream.
-==================
-*/
-void CL_ParsePacketEntities (frame_t *oldframe, frame_t *newframe)
-{
-	int			newnum;
-	int			bits;
-	entity_state_t	*oldstate = nil;
-	int			oldindex, oldnum;
-
-	newframe->parse_entities = cl.parse_entities;
-	newframe->num_entities = 0;
-
-	// delta from the entities present in oldframe
-	oldindex = 0;
-	if (!oldframe)
-		oldnum = 99999;
-	else
-	{
-		if (oldindex >= oldframe->num_entities)
-			oldnum = 99999;
-		else
-		{
-			oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
-			oldnum = oldstate->number;
-		}
-	}
-
-	while (1)
-	{
-		newnum = CL_ParseEntityBits (&bits);
-		if (newnum >= MAX_EDICTS)
-			Com_Error (ERR_DROP,"CL_ParsePacketEntities: bad number:%i", newnum);
-
-		if (net_message.readcount > net_message.cursize)
-			Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
-
-		if (!newnum)
-			break;
-
-		while (oldnum < newnum)
-		{	// one or more entities from the old packet are unchanged
-			if (cl_shownet->value == 3)
-				Com_Printf ("   unchanged: %i\n", oldnum);
-			CL_DeltaEntity (newframe, oldnum, oldstate, 0);
-			
-			oldindex++;
-
-			if (oldindex >= oldframe->num_entities)
-				oldnum = 99999;
-			else
-			{
-				oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
-				oldnum = oldstate->number;
-			}
-		}
-
-		if (bits & U_REMOVE)
-		{	// the entity present in oldframe is not in the current frame
-			if (cl_shownet->value == 3)
-				Com_Printf ("   remove: %i\n", newnum);
-			if (oldnum != newnum)
-				Com_Printf ("U_REMOVE: oldnum != newnum\n");
-
-			oldindex++;
-
-			if (oldindex >= oldframe->num_entities)
-				oldnum = 99999;
-			else
-			{
-				oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
-				oldnum = oldstate->number;
-			}
-			continue;
-		}
-
-		if (oldnum == newnum)
-		{	// delta from previous state
-			if (cl_shownet->value == 3)
-				Com_Printf ("   delta: %i\n", newnum);
-			CL_DeltaEntity (newframe, newnum, oldstate, bits);
-
-			oldindex++;
-
-			if (oldindex >= oldframe->num_entities)
-				oldnum = 99999;
-			else
-			{
-				oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
-				oldnum = oldstate->number;
-			}
-			continue;
-		}
-
-		if (oldnum > newnum)
-		{	// delta from baseline
-			if (cl_shownet->value == 3)
-				Com_Printf ("   baseline: %i\n", newnum);
-			CL_DeltaEntity (newframe, newnum, &cl_entities[newnum].baseline, bits);
-			continue;
-		}
-
-	}
-
-	// any remaining entities in the old frame are copied over
-	while (oldnum != 99999)
-	{	// one or more entities from the old packet are unchanged
-		if (cl_shownet->value == 3)
-			Com_Printf ("   unchanged: %i\n", oldnum);
-		CL_DeltaEntity (newframe, oldnum, oldstate, 0);
-		
-		oldindex++;
-
-		if (oldindex >= oldframe->num_entities)
-			oldnum = 99999;
-		else
-		{
-			oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
-			oldnum = oldstate->number;
-		}
-	}
-}
-
-
-
-/*
-===================
-CL_ParsePlayerstate
-===================
-*/
-void CL_ParsePlayerstate (frame_t *oldframe, frame_t *newframe)
-{
-	int			flags;
-	player_state_t	*state;
-	int			i;
-	int			statbits;
-
-	state = &newframe->playerstate;
-
-	// clear to old value before delta parsing
-	if (oldframe)
-		*state = oldframe->playerstate;
-	else
-		memset (state, 0, sizeof(*state));
-
-	flags = MSG_ReadShort (&net_message);
-
-	//
-	// parse the pmove_state_t
-	//
-	if (flags & PS_M_TYPE)
-		state->pmove.pm_type = MSG_ReadByte (&net_message);
-
-	if (flags & PS_M_ORIGIN)
-	{
-		state->pmove.origin[0] = MSG_ReadShort (&net_message);
-		state->pmove.origin[1] = MSG_ReadShort (&net_message);
-		state->pmove.origin[2] = MSG_ReadShort (&net_message);
-	}
-
-	if (flags & PS_M_VELOCITY)
-	{
-		state->pmove.velocity[0] = MSG_ReadShort (&net_message);
-		state->pmove.velocity[1] = MSG_ReadShort (&net_message);
-		state->pmove.velocity[2] = MSG_ReadShort (&net_message);
-	}
-
-	if (flags & PS_M_TIME)
-		state->pmove.pm_time = MSG_ReadByte (&net_message);
-
-	if (flags & PS_M_FLAGS)
-		state->pmove.pm_flags = MSG_ReadByte (&net_message);
-
-	if (flags & PS_M_GRAVITY)
-		state->pmove.gravity = MSG_ReadShort (&net_message);
-
-	if (flags & PS_M_DELTA_ANGLES)
-	{
-		state->pmove.delta_angles[0] = MSG_ReadShort (&net_message);
-		state->pmove.delta_angles[1] = MSG_ReadShort (&net_message);
-		state->pmove.delta_angles[2] = MSG_ReadShort (&net_message);
-	}
-
-	if (cl.attractloop)
-		state->pmove.pm_type = PM_FREEZE;		// demo playback
-
-	//
-	// parse the rest of the player_state_t
-	//
-	if (flags & PS_VIEWOFFSET)
-	{
-		state->viewoffset[0] = MSG_ReadChar (&net_message) * 0.25;
-		state->viewoffset[1] = MSG_ReadChar (&net_message) * 0.25;
-		state->viewoffset[2] = MSG_ReadChar (&net_message) * 0.25;
-	}
-
-	if (flags & PS_VIEWANGLES)
-	{
-		state->viewangles[0] = MSG_ReadAngle16 (&net_message);
-		state->viewangles[1] = MSG_ReadAngle16 (&net_message);
-		state->viewangles[2] = MSG_ReadAngle16 (&net_message);
-	}
-
-	if (flags & PS_KICKANGLES)
-	{
-		state->kick_angles[0] = MSG_ReadChar (&net_message) * 0.25;
-		state->kick_angles[1] = MSG_ReadChar (&net_message) * 0.25;
-		state->kick_angles[2] = MSG_ReadChar (&net_message) * 0.25;
-	}
-
-	if (flags & PS_WEAPONINDEX)
-	{
-		state->gunindex = MSG_ReadByte (&net_message);
-	}
-
-	if (flags & PS_WEAPONFRAME)
-	{
-		state->gunframe = MSG_ReadByte (&net_message);
-		state->gunoffset[0] = MSG_ReadChar (&net_message)*0.25;
-		state->gunoffset[1] = MSG_ReadChar (&net_message)*0.25;
-		state->gunoffset[2] = MSG_ReadChar (&net_message)*0.25;
-		state->gunangles[0] = MSG_ReadChar (&net_message)*0.25;
-		state->gunangles[1] = MSG_ReadChar (&net_message)*0.25;
-		state->gunangles[2] = MSG_ReadChar (&net_message)*0.25;
-	}
-
-	if (flags & PS_BLEND)
-	{
-		state->blend[0] = MSG_ReadByte (&net_message)/255.0;
-		state->blend[1] = MSG_ReadByte (&net_message)/255.0;
-		state->blend[2] = MSG_ReadByte (&net_message)/255.0;
-		state->blend[3] = MSG_ReadByte (&net_message)/255.0;
-	}
-
-	if (flags & PS_FOV)
-		state->fov = MSG_ReadByte (&net_message);
-
-	if (flags & PS_RDFLAGS)
-		state->rdflags = MSG_ReadByte (&net_message);
-
-	// parse stats
-	statbits = MSG_ReadLong (&net_message);
-	for (i=0 ; i<MAX_STATS ; i++)
-		if (statbits & (1<<i) )
-			state->stats[i] = MSG_ReadShort(&net_message);
-}
-
-
-/*
-==================
-CL_FireEntityEvents
-
-==================
-*/
-void CL_FireEntityEvents (frame_t *frame)
-{
-	entity_state_t		*s1;
-	int					pnum, num;
-
-	for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
-	{
-		num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1);
-		s1 = &cl_parse_entities[num];
-		if (s1->event)
-			CL_EntityEvent (s1);
-
-		// EF_TELEPORTER acts like an event, but is not cleared each frame
-		if (s1->effects & EF_TELEPORTER)
-			CL_TeleporterParticles (s1);
-	}
-}
-
-
-/*
-================
-CL_ParseFrame
-================
-*/
-void CL_ParseFrame (void)
-{
-	int			cmd;
-	int			len;
-	frame_t		*old;
-
-	memset (&cl.frame, 0, sizeof(cl.frame));
-
-/*
-	CL_ClearProjectiles(); // clear projectiles for new frame
-*/
-
-	cl.frame.serverframe = MSG_ReadLong (&net_message);
-	cl.frame.deltaframe = MSG_ReadLong (&net_message);
-	cl.frame.servertime = cl.frame.serverframe*100;
-
-	// BIG HACK to let old demos continue to work
-	if (cls.serverProtocol != 26)
-		cl.surpressCount = MSG_ReadByte (&net_message);
-
-	if (cl_shownet->value == 3)
-		Com_Printf ("   frame:%i  delta:%i\n", cl.frame.serverframe,
-		cl.frame.deltaframe);
-
-	// If the frame is delta compressed from data that we
-	// no longer have available, we must suck up the rest of
-	// the frame, but not use it, then ask for a non-compressed
-	// message 
-	if (cl.frame.deltaframe <= 0)
-	{
-		cl.frame.valid = true;		// uncompressed frame
-		old = NULL;
-		cls.demowaiting = false;	// we can start recording now
-	}
-	else
-	{
-		old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
-		if (!old->valid)
-		{	// should never happen
-			Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
-		}
-		if (old->serverframe != cl.frame.deltaframe)
-		{	// The frame that the server did the delta from
-			// is too old, so we can't reconstruct it properly.
-			Com_Printf ("Delta frame too old.\n");
-		}
-		else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128)
-		{
-			Com_Printf ("Delta parse_entities too old.\n");
-		}
-		else
-			cl.frame.valid = true;	// valid delta parse
-	}
-
-	// clamp time 
-	if (cl.time > cl.frame.servertime)
-		cl.time = cl.frame.servertime;
-	else if (cl.time < cl.frame.servertime - 100)
-		cl.time = cl.frame.servertime - 100;
-
-	// read areabits
-	len = MSG_ReadByte (&net_message);
-	MSG_ReadData (&net_message, cl.frame.areabits, len);
-
-	// read playerinfo
-	cmd = MSG_ReadByte (&net_message);
-	SHOWNET(svc_strings[cmd]);
-	if (cmd != svc_playerinfo)
-		Com_Error (ERR_DROP, "CL_ParseFrame: not playerinfo");
-	CL_ParsePlayerstate (old, &cl.frame);
-
-	// read packet entities
-	cmd = MSG_ReadByte (&net_message);
-	SHOWNET(svc_strings[cmd]);
-	if (cmd != svc_packetentities)
-		Com_Error (ERR_DROP, "CL_ParseFrame: not packetentities");
-	CL_ParsePacketEntities (old, &cl.frame);
-
-/*
-	if (cmd == svc_packetentities2)
-		CL_ParseProjectiles();
-*/
-
-	// save the frame off in the backup array for later delta comparisons
-	cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;
-
-	if (cl.frame.valid)
-	{
-		// getting a valid frame message ends the connection process
-		if (cls.state != ca_active)
-		{
-			cls.state = ca_active;
-			cl.force_refdef = true;
-			cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
-			cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
-			cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125;
-			VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles);
-			if (cls.disable_servercount != cl.servercount
-				&& cl.refresh_prepped)
-				SCR_EndLoadingPlaque ();	// get rid of loading plaque
-		}
-		cl.sound_prepped = true;	// can start mixing ambient sounds
-	
-		// fire entity events
-		CL_FireEntityEvents (&cl.frame);
-		CL_CheckPredictionError ();
-	}
-}
-
-/*
-==========================================================================
-
-INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
-
-==========================================================================
-*/
-
-struct model_s *S_RegisterSexedModel (entity_state_t *ent, char *base)
-{
-	int				n;
-	char			*p;
-	struct model_s	*mdl;
-	char			model[MAX_QPATH];
-	char			buffer[MAX_QPATH];
-
-	// determine what model the client is using
-	model[0] = 0;
-	n = CS_PLAYERSKINS + ent->number - 1;
-	if (cl.configstrings[n][0])
-	{
-		p = strchr(cl.configstrings[n], '\\');
-		if (p)
-		{
-			p += 1;
-			strcpy(model, p);
-			p = strchr(model, '/');
-			if (p)
-				*p = 0;
-		}
-	}
-	// if we can't figure it out, they're male
-	if (!model[0])
-		strcpy(model, "male");
-
-	Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", model, base+1);
-	mdl = re.RegisterModel(buffer);
-	if (!mdl) {
-		// not found, try default weapon model
-		Com_sprintf (buffer, sizeof(buffer), "players/%s/weapon.md2", model);
-		mdl = re.RegisterModel(buffer);
-		if (!mdl) {
-			// no, revert to the male model
-			Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", "male", base+1);
-			mdl = re.RegisterModel(buffer);
-			if (!mdl) {
-				// last try, default male weapon.md2
-				Com_sprintf (buffer, sizeof(buffer), "players/male/weapon.md2");
-				mdl = re.RegisterModel(buffer);
-			}
-		} 
-	}
-
-	return mdl;
-}
-
-/*
-===============
-CL_AddPacketEntities
-
-===============
-*/
-void CL_AddPacketEntities (frame_t *frame)
-{
-	entity_t			ent;
-	entity_state_t		*s1;
-	float				autorotate;
-	int					i;
-	int					pnum;
-	centity_t			*cent;
-	int					autoanim;
-	clientinfo_t		*ci;
-	unsigned int		effects, renderfx;
-
-	// bonus items rotate at a fixed rate
-	autorotate = anglemod(cl.time/10);
-
-	// brush models can auto animate their frames
-	autoanim = 2*cl.time/1000;
-
-	memset (&ent, 0, sizeof(ent));
-
-	for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
-	{
-		s1 = &cl_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)];
-
-		cent = &cl_entities[s1->number];
-
-		effects = s1->effects;
-		renderfx = s1->renderfx;
-
-			// set frame
-		if (effects & EF_ANIM01)
-			ent.frame = autoanim & 1;
-		else if (effects & EF_ANIM23)
-			ent.frame = 2 + (autoanim & 1);
-		else if (effects & EF_ANIM_ALL)
-			ent.frame = autoanim;
-		else if (effects & EF_ANIM_ALLFAST)
-			ent.frame = cl.time / 100;
-		else
-			ent.frame = s1->frame;
-
-		// quad and pent can do different things on client
-		if (effects & EF_PENT)
-		{
-			effects &= ~EF_PENT;
-			effects |= EF_COLOR_SHELL;
-			renderfx |= RF_SHELL_RED;
-		}
-
-		if (effects & EF_QUAD)
-		{
-			effects &= ~EF_QUAD;
-			effects |= EF_COLOR_SHELL;
-			renderfx |= RF_SHELL_BLUE;
-		}
-//======
-// PMM
-		if (effects & EF_DOUBLE)
-		{
-			effects &= ~EF_DOUBLE;
-			effects |= EF_COLOR_SHELL;
-			renderfx |= RF_SHELL_DOUBLE;
-		}
-
-		if (effects & EF_HALF_DAMAGE)
-		{
-			effects &= ~EF_HALF_DAMAGE;
-			effects |= EF_COLOR_SHELL;
-			renderfx |= RF_SHELL_HALF_DAM;
-		}
-// pmm
-//======
-		ent.oldframe = cent->prev.frame;
-		ent.backlerp = 1.0 - cl.lerpfrac;
-
-		if (renderfx & (RF_FRAMELERP|RF_BEAM))
-		{	// step origin discretely, because the frames
-			// do the animation properly
-			VectorCopy (cent->current.origin, ent.origin);
-			VectorCopy (cent->current.old_origin, ent.oldorigin);
-		}
-		else
-		{	// interpolate origin
-			for (i=0 ; i<3 ; i++)
-			{
-				ent.origin[i] = ent.oldorigin[i] = cent->prev.origin[i] + cl.lerpfrac * 
-					(cent->current.origin[i] - cent->prev.origin[i]);
-			}
-		}
-
-		// create a new entity
-	
-		// tweak the color of beams
-		if ( renderfx & RF_BEAM )
-		{	// the four beam colors are encoded in 32 bits of skinnum (hack)
-			ent.alpha = 0.30;
-			ent.skinnum = (s1->skinnum >> ((rand() % 4)*8)) & 0xff;
-			ent.model = NULL;
-		}
-		else
-		{
-			// set skin
-			if (s1->modelindex == 255)
-			{	// use custom player skin
-				ent.skinnum = 0;
-				ci = &cl.clientinfo[s1->skinnum & 0xff];
-				ent.skin = ci->skin;
-				ent.model = ci->model;
-				if (!ent.skin || !ent.model)
-				{
-					ent.skin = cl.baseclientinfo.skin;
-					ent.model = cl.baseclientinfo.model;
-				}
-
-//============
-//PGM
-				if (renderfx & RF_USE_DISGUISE)
-				{
-					if(!strncmp((char *)ent.skin, "players/male", 12))
-					{
-						ent.skin = re.RegisterSkin ("players/male/disguise.pcx");
-						ent.model = re.RegisterModel ("players/male/tris.md2");
-					}
-					else if(!strncmp((char *)ent.skin, "players/female", 14))
-					{
-						ent.skin = re.RegisterSkin ("players/female/disguise.pcx");
-						ent.model = re.RegisterModel ("players/female/tris.md2");
-					}
-					else if(!strncmp((char *)ent.skin, "players/cyborg", 14))
-					{
-						ent.skin = re.RegisterSkin ("players/cyborg/disguise.pcx");
-						ent.model = re.RegisterModel ("players/cyborg/tris.md2");
-					}
-				}
-//PGM
-//============
-			}
-			else
-			{
-				ent.skinnum = s1->skinnum;
-				ent.skin = NULL;
-				ent.model = cl.model_draw[s1->modelindex];
-			}
-		}
-
-		// only used for black hole model right now, FIXME: do better
-		if (renderfx == RF_TRANSLUCENT)
-			ent.alpha = 0.70;
-
-		// render effects (fullbright, translucent, etc)
-		if ((effects & EF_COLOR_SHELL))
-			ent.flags = 0;	// renderfx go on color shell entity
-		else
-			ent.flags = renderfx;
-
-		// calculate angles
-		if (effects & EF_ROTATE)
-		{	// some bonus items auto-rotate
-			ent.angles[0] = 0;
-			ent.angles[1] = autorotate;
-			ent.angles[2] = 0;
-		}
-		// RAFAEL
-		else if (effects & EF_SPINNINGLIGHTS)
-		{
-			ent.angles[0] = 0;
-			ent.angles[1] = anglemod(cl.time/2) + s1->angles[1];
-			ent.angles[2] = 180;
-			{
-				vec3_t forward;
-				vec3_t start;
-
-				AngleVectors (ent.angles, forward, NULL, NULL);
-				VectorMA (ent.origin, 64, forward, start);
-				V_AddLight (start, 100, 1, 0, 0);
-			}
-		}
-		else
-		{	// interpolate angles
-			float	a1, a2;
-
-			for (i=0 ; i<3 ; i++)
-			{
-				a1 = cent->current.angles[i];
-				a2 = cent->prev.angles[i];
-				ent.angles[i] = LerpAngle (a2, a1, cl.lerpfrac);
-			}
-		}
-
-		if (s1->number == cl.playernum+1)
-		{
-			ent.flags |= RF_VIEWERMODEL;	// only draw from mirrors
-			// FIXME: still pass to refresh
-
-			if (effects & EF_FLAG1)
-				V_AddLight (ent.origin, 225, 1.0, 0.1, 0.1);
-			else if (effects & EF_FLAG2)
-				V_AddLight (ent.origin, 225, 0.1, 0.1, 1.0);
-			else if (effects & EF_TAGTRAIL)						//PGM
-				V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);	//PGM
-			else if (effects & EF_TRACKERTRAIL)					//PGM
-				V_AddLight (ent.origin, 225, -1.0, -1.0, -1.0);	//PGM
-
-			continue;
-		}
-
-		// if set to invisible, skip
-		if (!s1->modelindex)
-			continue;
-
-		if (effects & EF_BFG)
-		{
-			ent.flags |= RF_TRANSLUCENT;
-			ent.alpha = 0.30;
-		}
-
-		// RAFAEL
-		if (effects & EF_PLASMA)
-		{
-			ent.flags |= RF_TRANSLUCENT;
-			ent.alpha = 0.6;
-		}
-
-		if (effects & EF_SPHERETRANS)
-		{
-			ent.flags |= RF_TRANSLUCENT;
-			// PMM - *sigh*  yet more EF overloading
-			if (effects & EF_TRACKERTRAIL)
-				ent.alpha = 0.6;
-			else
-				ent.alpha = 0.3;
-		}
-//pmm
-
-		// add to refresh list
-		V_AddEntity (&ent);
-
-		// color shells generate a seperate entity for the main model
-		if (effects & EF_COLOR_SHELL)
-		{
-			ent.flags = renderfx | RF_TRANSLUCENT;
-			ent.alpha = 0.30;
-			V_AddEntity (&ent);
-		}
-
-		ent.skin = NULL;		// never use a custom skin on others
-		ent.skinnum = 0;
-		ent.flags = 0;
-		ent.alpha = 0;
-
-		// duplicate for linked models
-		if (s1->modelindex2)
-		{
-			if (s1->modelindex2 == 255)
-			{	// custom weapon
-				ci = &cl.clientinfo[s1->skinnum & 0xff];
-				i = (s1->skinnum >> 8); // 0 is default weapon model
-				if (!cl_vwep->value || i > MAX_CLIENTWEAPONMODELS - 1)
-					i = 0;
-				ent.model = ci->weaponmodel[i];
-				if (!ent.model) {
-					if (i != 0)
-						ent.model = ci->weaponmodel[0];
-					if (!ent.model)
-						ent.model = cl.baseclientinfo.weaponmodel[0];
-				}
-			}
-			//PGM - hack to allow translucent linked models (defender sphere's shell)
-			//		set the high bit 0x80 on modelindex2 to enable translucency
-			else if(s1->modelindex2 & 0x80)
-			{
-				ent.model = cl.model_draw[s1->modelindex2 & 0x7F];
-				ent.alpha = 0.32;
-				ent.flags = RF_TRANSLUCENT;
-			}
-			//PGM
-			else
-				ent.model = cl.model_draw[s1->modelindex2];
-			V_AddEntity (&ent);
-
-			//PGM - make sure these get reset.
-			ent.flags = 0;
-			ent.alpha = 0;
-			//PGM
-		}
-		if (s1->modelindex3)
-		{
-			ent.model = cl.model_draw[s1->modelindex3];
-			V_AddEntity (&ent);
-		}
-		if (s1->modelindex4)
-		{
-			ent.model = cl.model_draw[s1->modelindex4];
-			V_AddEntity (&ent);
-		}
-
-		if ( effects & EF_POWERSCREEN )
-		{
-			ent.model = cl_mod_powerscreen;
-			ent.oldframe = 0;
-			ent.frame = 0;
-			ent.flags |= (RF_TRANSLUCENT | RF_SHELL_GREEN);
-			ent.alpha = 0.30;
-			V_AddEntity (&ent);
-		}
-
-		// add automatic particle trails
-		if ( (effects&~EF_ROTATE) )
-		{
-			if (effects & EF_ROCKET)
-			{
-				CL_RocketTrail (cent->lerp_origin, ent.origin, cent);
-				V_AddLight (ent.origin, 200, 1, 1, 0);
-			}
-			// PGM - Do not reorder EF_BLASTER and EF_HYPERBLASTER. 
-			// EF_BLASTER | EF_TRACKER is a special case for EF_BLASTER2... Cheese!
-			else if (effects & EF_BLASTER)
-			{
-//				CL_BlasterTrail (cent->lerp_origin, ent.origin);
-//PGM
-				if (effects & EF_TRACKER)	// lame... problematic?
-				{
-					CL_BlasterTrail2 (cent->lerp_origin, ent.origin);
-					V_AddLight (ent.origin, 200, 0, 1, 0);		
-				}
-				else
-				{
-					CL_BlasterTrail (cent->lerp_origin, ent.origin);
-					V_AddLight (ent.origin, 200, 1, 1, 0);
-				}
-//PGM
-			}
-			else if (effects & EF_HYPERBLASTER)
-			{
-				if (effects & EF_TRACKER)						// PGM	overloaded for blaster2.
-					V_AddLight (ent.origin, 200, 0, 1, 0);		// PGM
-				else											// PGM
-					V_AddLight (ent.origin, 200, 1, 1, 0);
-			}
-			else if (effects & EF_GIB)
-			{
-				CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
-			}
-			else if (effects & EF_GRENADE)
-			{
-				CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
-			}
-			else if (effects & EF_FLIES)
-			{
-				CL_FlyEffect (cent, ent.origin);
-			}
-			else if (effects & EF_BFG)
-			{
-				static int bfg_lightramp[6] = {300, 400, 600, 300, 150, 75};
-
-				if (effects & EF_ANIM_ALLFAST)
-				{
-					CL_BfgParticles (&ent);
-					i = 200;
-				}
-				else
-				{
-					i = bfg_lightramp[s1->frame];
-				}
-				V_AddLight (ent.origin, i, 0, 1, 0);
-			}
-			// RAFAEL
-			else if (effects & EF_TRAP)
-			{
-				ent.origin[2] += 32;
-				CL_TrapParticles (&ent);
-				i = (rand()%100) + 100;
-				V_AddLight (ent.origin, i, 1, 0.8, 0.1);
-			}
-			else if (effects & EF_FLAG1)
-			{
-				CL_FlagTrail (cent->lerp_origin, ent.origin, 242);
-				V_AddLight (ent.origin, 225, 1, 0.1, 0.1);
-			}
-			else if (effects & EF_FLAG2)
-			{
-				CL_FlagTrail (cent->lerp_origin, ent.origin, 115);
-				V_AddLight (ent.origin, 225, 0.1, 0.1, 1);
-			}
-//======
-//ROGUE
-			else if (effects & EF_TAGTRAIL)
-			{
-				CL_TagTrail (cent->lerp_origin, ent.origin, 220);
-				V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);
-			}
-			else if (effects & EF_TRACKERTRAIL)
-			{
-				if (effects & EF_TRACKER)
-				{
-					float intensity;
-
-					intensity = 50 + (500 * (sin(cl.time/500.0) + 1.0));
-					// FIXME - check out this effect in rendition
-					if(vidref_val == VIDREF_GL)
-						V_AddLight (ent.origin, intensity, -1.0, -1.0, -1.0);
-					else
-						V_AddLight (ent.origin, -1.0 * intensity, 1.0, 1.0, 1.0);
-					}
-				else
-				{
-					CL_Tracker_Shell (cent->lerp_origin);
-					V_AddLight (ent.origin, 155, -1.0, -1.0, -1.0);
-				}
-			}
-			else if (effects & EF_TRACKER)
-			{
-				CL_TrackerTrail (cent->lerp_origin, ent.origin, 0);
-				// FIXME - check out this effect in rendition
-				if(vidref_val == VIDREF_GL)
-					V_AddLight (ent.origin, 200, -1, -1, -1);
-				else
-					V_AddLight (ent.origin, -200, 1, 1, 1);
-			}
-//ROGUE
-//======
-			// RAFAEL
-			else if (effects & EF_GREENGIB)
-			{
-				CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);				
-			}
-			// RAFAEL
-			else if (effects & EF_IONRIPPER)
-			{
-				CL_IonripperTrail (cent->lerp_origin, ent.origin);
-				V_AddLight (ent.origin, 100, 1, 0.5, 0.5);
-			}
-			// RAFAEL
-			else if (effects & EF_BLUEHYPERBLASTER)
-			{
-				V_AddLight (ent.origin, 200, 0, 0, 1);
-			}
-			// RAFAEL
-			else if (effects & EF_PLASMA)
-			{
-				if (effects & EF_ANIM_ALLFAST)
-				{
-					CL_BlasterTrail (cent->lerp_origin, ent.origin);
-				}
-				V_AddLight (ent.origin, 130, 1, 0.5, 0.5);
-			}
-		}
-
-		VectorCopy (ent.origin, cent->lerp_origin);
-	}
-}
-
-
-
-/*
-==============
-CL_AddViewWeapon
-==============
-*/
-void CL_AddViewWeapon (player_state_t *ps, player_state_t *ops)
-{
-	entity_t	gun;		// view model
-	int			i;
-
-	// allow the gun to be completely removed
-	if (!cl_gun->value)
-		return;
-
-	// don't draw gun if in wide angle view
-	if (ps->fov > 90)
-		return;
-
-	memset (&gun, 0, sizeof(gun));
-
-	if (gun_model)
-		gun.model = gun_model;	// development tool
-	else
-		gun.model = cl.model_draw[ps->gunindex];
-	if (!gun.model)
-		return;
-
-	// set up gun position
-	for (i=0 ; i<3 ; i++)
-	{
-		gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i]
-			+ cl.lerpfrac * (ps->gunoffset[i] - ops->gunoffset[i]);
-		gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->gunangles[i],
-			ps->gunangles[i], cl.lerpfrac);
-	}
-
-	if (gun_frame)
-	{
-		gun.frame = gun_frame;	// development tool
-		gun.oldframe = gun_frame;	// development tool
-	}
-	else
-	{
-		gun.frame = ps->gunframe;
-		if (gun.frame == 0)
-			gun.oldframe = 0;	// just changed weapons, don't lerp from old
-		else
-			gun.oldframe = ops->gunframe;
-	}
-
-	gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
-	gun.backlerp = 1.0 - cl.lerpfrac;
-	VectorCopy (gun.origin, gun.oldorigin);	// don't lerp at all
-	V_AddEntity (&gun);
-}
-
-
-/*
-===============
-CL_CalcViewValues
-
-Sets cl.refdef view values
-===============
-*/
-void CL_CalcViewValues (void)
-{
-	int			i;
-	float		lerp, backlerp;
-	frame_t		*oldframe;
-	player_state_t	*ps, *ops;
-
-	// find the previous frame to interpolate from
-	ps = &cl.frame.playerstate;
-	i = (cl.frame.serverframe - 1) & UPDATE_MASK;
-	oldframe = &cl.frames[i];
-	if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
-		oldframe = &cl.frame;		// previous frame was dropped or involid
-	ops = &oldframe->playerstate;
-
-	// see if the player entity was teleported this frame
-	if ( fabs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256*8
-		|| abs(ops->pmove.origin[1] - ps->pmove.origin[1]) > 256*8
-		|| abs(ops->pmove.origin[2] - ps->pmove.origin[2]) > 256*8)
-		ops = ps;		// don't interpolate
-
-	lerp = cl.lerpfrac;
-
-	// calculate the origin
-	if ((cl_predict->value) && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
-	{	// use predicted values
-		unsigned	delta;
-
-		backlerp = 1.0 - lerp;
-		for (i=0 ; i<3 ; i++)
-		{
-			cl.refdef.vieworg[i] = cl.predicted_origin[i] + ops->viewoffset[i] 
-				+ cl.lerpfrac * (ps->viewoffset[i] - ops->viewoffset[i])
-				- backlerp * cl.prediction_error[i];
-		}
-
-		// smooth out stair climbing
-		delta = cls.realtime - cl.predicted_step_time;
-		if (delta < 100)
-			cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01;
-	}
-	else
-	{	// just use interpolated values
-		for (i=0 ; i<3 ; i++)
-			cl.refdef.vieworg[i] = ops->pmove.origin[i]*0.125 + ops->viewoffset[i] 
-				+ lerp * (ps->pmove.origin[i]*0.125 + ps->viewoffset[i] 
-				- (ops->pmove.origin[i]*0.125 + ops->viewoffset[i]) );
-	}
-
-	// if not running a demo or on a locked frame, add the local angle movement
-	if ( cl.frame.playerstate.pmove.pm_type < PM_DEAD )
-	{	// use predicted values
-		for (i=0 ; i<3 ; i++)
-			cl.refdef.viewangles[i] = cl.predicted_angles[i];
-	}
-	else
-	{	// just use interpolated values
-		for (i=0 ; i<3 ; i++)
-			cl.refdef.viewangles[i] = LerpAngle (ops->viewangles[i], ps->viewangles[i], lerp);
-	}
-
-	for (i=0 ; i<3 ; i++)
-		cl.refdef.viewangles[i] += LerpAngle (ops->kick_angles[i], ps->kick_angles[i], lerp);
-
-	AngleVectors (cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up);
-
-	// interpolate field of view
-	cl.refdef.fov_x = ops->fov + lerp * (ps->fov - ops->fov);
-
-	// don't interpolate blend color
-	for (i=0 ; i<4 ; i++)
-		cl.refdef.blend[i] = ps->blend[i];
-
-	// add the weapon
-	CL_AddViewWeapon (ps, ops);
-}
-
-/*
-===============
-CL_AddEntities
-
-Emits all entities, particles, and lights to the refresh
-===============
-*/
-void CL_AddEntities (void)
-{
-	if (cls.state != ca_active)
-		return;
-
-	if (cl.time > cl.frame.servertime)
-	{
-		if (cl_showclamp->value)
-			Com_Printf ("high clamp %i\n", cl.time - cl.frame.servertime);
-		cl.time = cl.frame.servertime;
-		cl.lerpfrac = 1.0;
-	}
-	else if (cl.time < cl.frame.servertime - 100)
-	{
-		if (cl_showclamp->value)
-			Com_Printf ("low clamp %i\n", cl.frame.servertime-100 - cl.time);
-		cl.time = cl.frame.servertime - 100;
-		cl.lerpfrac = 0;
-	}
-	else
-		cl.lerpfrac = 1.0 - (cl.frame.servertime - cl.time) * 0.01;
-
-	if (cl_timedemo->value)
-		cl.lerpfrac = 1.0;
-
-//	CL_AddPacketEntities (&cl.frame);
-//	CL_AddTEnts ();
-//	CL_AddParticles ();
-//	CL_AddDLights ();
-//	CL_AddLightStyles ();
-
-	CL_CalcViewValues ();
-	// PMM - moved this here so the heat beam has the right values for the vieworg, and can lock the beam to the gun
-	CL_AddPacketEntities (&cl.frame);
-/*
-	CL_AddProjectiles ();
-*/
-	CL_AddTEnts ();
-	CL_AddParticles ();
-	CL_AddDLights ();
-	CL_AddLightStyles ();
-}
-
-
-
-/*
-===============
-CL_GetEntitySoundOrigin
-
-Called to get the sound spatialization origin
-===============
-*/
-void CL_GetEntitySoundOrigin (int ent, vec3_t org)
-{
-	centity_t	*old;
-
-	if (ent < 0 || ent >= MAX_EDICTS)
-		Com_Error (ERR_DROP, "CL_GetEntitySoundOrigin: bad ent");
-	old = &cl_entities[ent];
-	VectorCopy (old->lerp_origin, org);
-
-	// FIXME: bmodel issues...
-}
--- a/client/cl_fx.c
+++ /dev/null
@@ -1,2286 +1,0 @@
-// cl_fx.c -- entity effects parsing and management
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-void CL_LogoutEffect (vec3_t org, int type);
-void CL_ItemRespawnParticles (vec3_t org);
-
-static vec3_t avelocities [NUMVERTEXNORMALS];
-
-extern	struct model_s	*cl_mod_smoke;
-extern	struct model_s	*cl_mod_flash;
-
-/*
-==============================================================
-
-LIGHT STYLE MANAGEMENT
-
-==============================================================
-*/
-
-typedef struct
-{
-	int		length;
-	float	value[3];
-	float	map[MAX_QPATH];
-} clightstyle_t;
-
-clightstyle_t	cl_lightstyle[MAX_LIGHTSTYLES];
-int			lastofs;
-
-/*
-================
-CL_ClearLightStyles
-================
-*/
-void CL_ClearLightStyles (void)
-{
-	memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
-	lastofs = -1;
-}
-
-/*
-================
-CL_RunLightStyles
-================
-*/
-void CL_RunLightStyles (void)
-{
-	int		ofs;
-	int		i;
-	clightstyle_t	*ls;
-
-	ofs = cl.time / 100;
-	if (ofs == lastofs)
-		return;
-	lastofs = ofs;
-
-	for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
-	{
-		if (!ls->length)
-		{
-			ls->value[0] = ls->value[1] = ls->value[2] = 1.0;
-			continue;
-		}
-		if (ls->length == 1)
-			ls->value[0] = ls->value[1] = ls->value[2] = ls->map[0];
-		else
-			ls->value[0] = ls->value[1] = ls->value[2] = ls->map[ofs%ls->length];
-	}
-}
-
-
-void CL_SetLightstyle (int i)
-{
-	char	*s;
-	int		j, k;
-
-	s = cl.configstrings[i+CS_LIGHTS];
-
-	j = strlen (s);
-	if (j >= MAX_QPATH)
-		Com_Error (ERR_DROP, "svc_lightstyle length=%i", j);
-
-	cl_lightstyle[i].length = j;
-
-	for (k=0 ; k<j ; k++)
-		cl_lightstyle[i].map[k] = (float)(s[k]-'a')/(float)('m'-'a');
-}
-
-/*
-================
-CL_AddLightStyles
-================
-*/
-void CL_AddLightStyles (void)
-{
-	int		i;
-	clightstyle_t	*ls;
-
-	for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
-		V_AddLightStyle (i, ls->value[0], ls->value[1], ls->value[2]);
-}
-
-/*
-==============================================================
-
-DLIGHT MANAGEMENT
-
-==============================================================
-*/
-
-cdlight_t		cl_dlights[MAX_DLIGHTS];
-
-/*
-================
-CL_ClearDlights
-================
-*/
-void CL_ClearDlights (void)
-{
-	memset (cl_dlights, 0, sizeof(cl_dlights));
-}
-
-/*
-===============
-CL_AllocDlight
-
-===============
-*/
-cdlight_t *CL_AllocDlight (int key)
-{
-	int		i;
-	cdlight_t	*dl;
-
-// first look for an exact key match
-	if (key)
-	{
-		dl = cl_dlights;
-		for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
-		{
-			if (dl->key == key)
-			{
-				memset (dl, 0, sizeof(*dl));
-				dl->key = key;
-				return dl;
-			}
-		}
-	}
-
-// then look for anything else
-	dl = cl_dlights;
-	for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
-	{
-		if (dl->die < cl.time)
-		{
-			memset (dl, 0, sizeof(*dl));
-			dl->key = key;
-			return dl;
-		}
-	}
-
-	dl = &cl_dlights[0];
-	memset (dl, 0, sizeof(*dl));
-	dl->key = key;
-	return dl;
-}
-
-/*
-===============
-CL_NewDlight
-===============
-*/
-void CL_NewDlight (int key, float x, float y, float z, float radius, float time)
-{
-	cdlight_t	*dl;
-
-	dl = CL_AllocDlight (key);
-	dl->origin[0] = x;
-	dl->origin[1] = y;
-	dl->origin[2] = z;
-	dl->radius = radius;
-	dl->die = cl.time + time;
-}
-
-
-/*
-===============
-CL_RunDLights
-
-===============
-*/
-void CL_RunDLights (void)
-{
-	int			i;
-	cdlight_t	*dl;
-
-	dl = cl_dlights;
-	for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
-	{
-		if (!dl->radius)
-			continue;
-		
-		if (dl->die < cl.time)
-		{
-			dl->radius = 0;
-			return;
-		}
-		dl->radius -= cls.frametime*dl->decay;
-		if (dl->radius < 0)
-			dl->radius = 0;
-	}
-}
-
-/*
-==============
-CL_ParseMuzzleFlash
-==============
-*/
-void CL_ParseMuzzleFlash (void)
-{
-	vec3_t		fv, rv;
-	cdlight_t	*dl;
-	int			i, weapon;
-	centity_t	*pl;
-	int			silenced;
-	float		volume;
-	char		soundname[64];
-
-	i = MSG_ReadShort (&net_message);
-	if (i < 1 || i >= MAX_EDICTS)
-		Com_Error (ERR_DROP, "CL_ParseMuzzleFlash: bad entity");
-
-	weapon = MSG_ReadByte (&net_message);
-	silenced = weapon & MZ_SILENCED;
-	weapon &= ~MZ_SILENCED;
-
-	pl = &cl_entities[i];
-
-	dl = CL_AllocDlight (i);
-	VectorCopy (pl->current.origin,  dl->origin);
-	AngleVectors (pl->current.angles, fv, rv, NULL);
-	VectorMA (dl->origin, 18, fv, dl->origin);
-	VectorMA (dl->origin, 16, rv, dl->origin);
-	if (silenced)
-		dl->radius = 100 + (rand()&31);
-	else
-		dl->radius = 200 + (rand()&31);
-	dl->minlight = 32;
-	dl->die = cl.time; // + 0.1;
-
-	if (silenced)
-		volume = 0.2;
-	else
-		volume = 1;
-
-	switch (weapon)
-	{
-	case MZ_BLASTER:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
-		break;
-	case MZ_BLUEHYPERBLASTER:
-		dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
-		break;
-	case MZ_HYPERBLASTER:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
-		break;
-	case MZ_MACHINEGUN:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
-		break;
-	case MZ_SHOTGUN:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotgf1b.wav"), volume, ATTN_NORM, 0);
-		S_StartSound (NULL, i, CHAN_AUTO,   S_RegisterSound("weapons/shotgr1b.wav"), volume, ATTN_NORM, 0.1);
-		break;
-	case MZ_SSHOTGUN:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/sshotf1b.wav"), volume, ATTN_NORM, 0);
-		break;
-	case MZ_CHAINGUN1:
-		dl->radius = 200 + (rand()&31);
-		dl->color[0] = 1;dl->color[1] = 0.25;dl->color[2] = 0;
-		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
-		break;
-	case MZ_CHAINGUN2:
-		dl->radius = 225 + (rand()&31);
-		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
-		dl->die = cl.time  + 0.1;	// long delay
-		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
-		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.05);
-		break;
-	case MZ_CHAINGUN3:
-		dl->radius = 250 + (rand()&31);
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		dl->die = cl.time  + 0.1;	// long delay
-		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
-		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.033);
-		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.066);
-		break;
-	case MZ_RAILGUN:
-		dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/railgf1a.wav"), volume, ATTN_NORM, 0);
-		break;
-	case MZ_ROCKET:
-		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rocklf1a.wav"), volume, ATTN_NORM, 0);
-		S_StartSound (NULL, i, CHAN_AUTO,   S_RegisterSound("weapons/rocklr1b.wav"), volume, ATTN_NORM, 0.1);
-		break;
-	case MZ_GRENADE:
-		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0);
-		S_StartSound (NULL, i, CHAN_AUTO,   S_RegisterSound("weapons/grenlr1b.wav"), volume, ATTN_NORM, 0.1);
-		break;
-	case MZ_BFG:
-		dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0);
-		break;
-
-	case MZ_LOGIN:
-		dl->color[0] = 0;dl->color[1] = 1; dl->color[2] = 0;
-		dl->die = cl.time + 1.0;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
-		CL_LogoutEffect (pl->current.origin, weapon);
-		break;
-	case MZ_LOGOUT:
-		dl->color[0] = 1;dl->color[1] = 0; dl->color[2] = 0;
-		dl->die = cl.time + 1.0;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
-		CL_LogoutEffect (pl->current.origin, weapon);
-		break;
-	case MZ_RESPAWN:
-		dl->color[0] = 1;dl->color[1] = 1; dl->color[2] = 0;
-		dl->die = cl.time + 1.0;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
-		CL_LogoutEffect (pl->current.origin, weapon);
-		break;
-	// RAFAEL
-	case MZ_PHALANX:
-		dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/plasshot.wav"), volume, ATTN_NORM, 0);
-		break;
-	// RAFAEL
-	case MZ_IONRIPPER:	
-		dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0);
-		break;
-
-// ======================
-// PGM
-	case MZ_ETF_RIFLE:
-		dl->color[0] = 0.9;dl->color[1] = 0.7;dl->color[2] = 0;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0);
-		break;
-	case MZ_SHOTGUN2:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0);
-		break;
-	case MZ_HEATBEAM:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		dl->die = cl.time + 100;
-//		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0);
-		break;
-	case MZ_BLASTER2:
-		dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
-		// FIXME - different sound for blaster2 ??
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
-		break;
-	case MZ_TRACKER:
-		// negative flashes handled the same in gl/soft until CL_AddDLights
-		dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
-		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), volume, ATTN_NORM, 0);
-		break;		
-	case MZ_NUKE1:
-		dl->color[0] = 1;dl->color[1] = 0;dl->color[2] = 0;
-		dl->die = cl.time + 100;
-		break;
-	case MZ_NUKE2:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		dl->die = cl.time + 100;
-		break;
-	case MZ_NUKE4:
-		dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
-		dl->die = cl.time + 100;
-		break;
-	case MZ_NUKE8:
-		dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 1;
-		dl->die = cl.time + 100;
-		break;
-// PGM
-// ======================
-	}
-}
-
-
-/*
-==============
-CL_ParseMuzzleFlash2
-==============
-*/
-void CL_ParseMuzzleFlash2 (void) 
-{
-	int			ent;
-	vec3_t		origin;
-	int			flash_number;
-	cdlight_t	*dl;
-	vec3_t		forward, right;
-	char		soundname[64];
-
-	ent = MSG_ReadShort (&net_message);
-	if (ent < 1 || ent >= MAX_EDICTS)
-		Com_Error (ERR_DROP, "CL_ParseMuzzleFlash2: bad entity");
-
-	flash_number = MSG_ReadByte (&net_message);
-
-	// locate the origin
-	AngleVectors (cl_entities[ent].current.angles, forward, right, NULL);
-	origin[0] = cl_entities[ent].current.origin[0] + forward[0] * monster_flash_offset[flash_number][0] + right[0] * monster_flash_offset[flash_number][1];
-	origin[1] = cl_entities[ent].current.origin[1] + forward[1] * monster_flash_offset[flash_number][0] + right[1] * monster_flash_offset[flash_number][1];
-	origin[2] = cl_entities[ent].current.origin[2] + forward[2] * monster_flash_offset[flash_number][0] + right[2] * monster_flash_offset[flash_number][1] + monster_flash_offset[flash_number][2];
-
-	dl = CL_AllocDlight (ent);
-	VectorCopy (origin,  dl->origin);
-	dl->radius = 200 + (rand()&31);
-	dl->minlight = 32;
-	dl->die = cl.time;	// + 0.1;
-
-	switch (flash_number)
-	{
-	case MZ2_INFANTRY_MACHINEGUN_1:
-	case MZ2_INFANTRY_MACHINEGUN_2:
-	case MZ2_INFANTRY_MACHINEGUN_3:
-	case MZ2_INFANTRY_MACHINEGUN_4:
-	case MZ2_INFANTRY_MACHINEGUN_5:
-	case MZ2_INFANTRY_MACHINEGUN_6:
-	case MZ2_INFANTRY_MACHINEGUN_7:
-	case MZ2_INFANTRY_MACHINEGUN_8:
-	case MZ2_INFANTRY_MACHINEGUN_9:
-	case MZ2_INFANTRY_MACHINEGUN_10:
-	case MZ2_INFANTRY_MACHINEGUN_11:
-	case MZ2_INFANTRY_MACHINEGUN_12:
-	case MZ2_INFANTRY_MACHINEGUN_13:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		CL_ParticleEffect (origin, vec3_origin, 0, 40);
-		CL_SmokeAndFlash(origin);
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_SOLDIER_MACHINEGUN_1:
-	case MZ2_SOLDIER_MACHINEGUN_2:
-	case MZ2_SOLDIER_MACHINEGUN_3:
-	case MZ2_SOLDIER_MACHINEGUN_4:
-	case MZ2_SOLDIER_MACHINEGUN_5:
-	case MZ2_SOLDIER_MACHINEGUN_6:
-	case MZ2_SOLDIER_MACHINEGUN_7:
-	case MZ2_SOLDIER_MACHINEGUN_8:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		CL_ParticleEffect (origin, vec3_origin, 0, 40);
-		CL_SmokeAndFlash(origin);
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_GUNNER_MACHINEGUN_1:
-	case MZ2_GUNNER_MACHINEGUN_2:
-	case MZ2_GUNNER_MACHINEGUN_3:
-	case MZ2_GUNNER_MACHINEGUN_4:
-	case MZ2_GUNNER_MACHINEGUN_5:
-	case MZ2_GUNNER_MACHINEGUN_6:
-	case MZ2_GUNNER_MACHINEGUN_7:
-	case MZ2_GUNNER_MACHINEGUN_8:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		CL_ParticleEffect (origin, vec3_origin, 0, 40);
-		CL_SmokeAndFlash(origin);
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_ACTOR_MACHINEGUN_1:
-	case MZ2_SUPERTANK_MACHINEGUN_1:
-	case MZ2_SUPERTANK_MACHINEGUN_2:
-	case MZ2_SUPERTANK_MACHINEGUN_3:
-	case MZ2_SUPERTANK_MACHINEGUN_4:
-	case MZ2_SUPERTANK_MACHINEGUN_5:
-	case MZ2_SUPERTANK_MACHINEGUN_6:
-	case MZ2_TURRET_MACHINEGUN:			// PGM
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-
-		CL_ParticleEffect (origin, vec3_origin, 0, 40);
-		CL_SmokeAndFlash(origin);
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_BOSS2_MACHINEGUN_L1:
-	case MZ2_BOSS2_MACHINEGUN_L2:
-	case MZ2_BOSS2_MACHINEGUN_L3:
-	case MZ2_BOSS2_MACHINEGUN_L4:
-	case MZ2_BOSS2_MACHINEGUN_L5:
-	case MZ2_CARRIER_MACHINEGUN_L1:		// PMM
-	case MZ2_CARRIER_MACHINEGUN_L2:		// PMM
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-
-		CL_ParticleEffect (origin, vec3_origin, 0, 40);
-		CL_SmokeAndFlash(origin);
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0);
-		break;
-
-	case MZ2_SOLDIER_BLASTER_1:
-	case MZ2_SOLDIER_BLASTER_2:
-	case MZ2_SOLDIER_BLASTER_3:
-	case MZ2_SOLDIER_BLASTER_4:
-	case MZ2_SOLDIER_BLASTER_5:
-	case MZ2_SOLDIER_BLASTER_6:
-	case MZ2_SOLDIER_BLASTER_7:
-	case MZ2_SOLDIER_BLASTER_8:
-	case MZ2_TURRET_BLASTER:			// PGM
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck2.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_FLYER_BLASTER_1:
-	case MZ2_FLYER_BLASTER_2:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("flyer/flyatck3.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_MEDIC_BLASTER_1:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("medic/medatck1.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_HOVER_BLASTER_1:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("hover/hovatck1.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_FLOAT_BLASTER_1:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("floater/fltatck1.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_SOLDIER_SHOTGUN_1:
-	case MZ2_SOLDIER_SHOTGUN_2:
-	case MZ2_SOLDIER_SHOTGUN_3:
-	case MZ2_SOLDIER_SHOTGUN_4:
-	case MZ2_SOLDIER_SHOTGUN_5:
-	case MZ2_SOLDIER_SHOTGUN_6:
-	case MZ2_SOLDIER_SHOTGUN_7:
-	case MZ2_SOLDIER_SHOTGUN_8:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		CL_SmokeAndFlash(origin);
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck1.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_TANK_BLASTER_1:
-	case MZ2_TANK_BLASTER_2:
-	case MZ2_TANK_BLASTER_3:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_TANK_MACHINEGUN_1:
-	case MZ2_TANK_MACHINEGUN_2:
-	case MZ2_TANK_MACHINEGUN_3:
-	case MZ2_TANK_MACHINEGUN_4:
-	case MZ2_TANK_MACHINEGUN_5:
-	case MZ2_TANK_MACHINEGUN_6:
-	case MZ2_TANK_MACHINEGUN_7:
-	case MZ2_TANK_MACHINEGUN_8:
-	case MZ2_TANK_MACHINEGUN_9:
-	case MZ2_TANK_MACHINEGUN_10:
-	case MZ2_TANK_MACHINEGUN_11:
-	case MZ2_TANK_MACHINEGUN_12:
-	case MZ2_TANK_MACHINEGUN_13:
-	case MZ2_TANK_MACHINEGUN_14:
-	case MZ2_TANK_MACHINEGUN_15:
-	case MZ2_TANK_MACHINEGUN_16:
-	case MZ2_TANK_MACHINEGUN_17:
-	case MZ2_TANK_MACHINEGUN_18:
-	case MZ2_TANK_MACHINEGUN_19:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		CL_ParticleEffect (origin, vec3_origin, 0, 40);
-		CL_SmokeAndFlash(origin);
-		Com_sprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + rand() % 5);
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound(soundname), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_CHICK_ROCKET_1:
-	case MZ2_TURRET_ROCKET:			// PGM
-		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("chick/chkatck2.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_TANK_ROCKET_1:
-	case MZ2_TANK_ROCKET_2:
-	case MZ2_TANK_ROCKET_3:
-		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck1.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_SUPERTANK_ROCKET_1:
-	case MZ2_SUPERTANK_ROCKET_2:
-	case MZ2_SUPERTANK_ROCKET_3:
-	case MZ2_BOSS2_ROCKET_1:
-	case MZ2_BOSS2_ROCKET_2:
-	case MZ2_BOSS2_ROCKET_3:
-	case MZ2_BOSS2_ROCKET_4:
-	case MZ2_CARRIER_ROCKET_1:
-//	case MZ2_CARRIER_ROCKET_2:
-//	case MZ2_CARRIER_ROCKET_3:
-//	case MZ2_CARRIER_ROCKET_4:
-		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/rocket.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_GUNNER_GRENADE_1:
-	case MZ2_GUNNER_GRENADE_2:
-	case MZ2_GUNNER_GRENADE_3:
-	case MZ2_GUNNER_GRENADE_4:
-		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck3.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_GLADIATOR_RAILGUN_1:
-	// PMM
-	case MZ2_CARRIER_RAILGUN:
-	case MZ2_WIDOW_RAIL:
-	// pmm
-		dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
-		break;
-
-// --- Xian's shit starts ---
-	case MZ2_MAKRON_BFG:
-		dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
-		//S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_MAKRON_BLASTER_1:
-	case MZ2_MAKRON_BLASTER_2:
-	case MZ2_MAKRON_BLASTER_3:
-	case MZ2_MAKRON_BLASTER_4:
-	case MZ2_MAKRON_BLASTER_5:
-	case MZ2_MAKRON_BLASTER_6:
-	case MZ2_MAKRON_BLASTER_7:
-	case MZ2_MAKRON_BLASTER_8:
-	case MZ2_MAKRON_BLASTER_9:
-	case MZ2_MAKRON_BLASTER_10:
-	case MZ2_MAKRON_BLASTER_11:
-	case MZ2_MAKRON_BLASTER_12:
-	case MZ2_MAKRON_BLASTER_13:
-	case MZ2_MAKRON_BLASTER_14:
-	case MZ2_MAKRON_BLASTER_15:
-	case MZ2_MAKRON_BLASTER_16:
-	case MZ2_MAKRON_BLASTER_17:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/blaster.wav"), 1, ATTN_NORM, 0);
-		break;
-	
-	case MZ2_JORG_MACHINEGUN_L1:
-	case MZ2_JORG_MACHINEGUN_L2:
-	case MZ2_JORG_MACHINEGUN_L3:
-	case MZ2_JORG_MACHINEGUN_L4:
-	case MZ2_JORG_MACHINEGUN_L5:
-	case MZ2_JORG_MACHINEGUN_L6:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		CL_ParticleEffect (origin, vec3_origin, 0, 40);
-		CL_SmokeAndFlash(origin);
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("boss3/xfire.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_JORG_MACHINEGUN_R1:
-	case MZ2_JORG_MACHINEGUN_R2:
-	case MZ2_JORG_MACHINEGUN_R3:
-	case MZ2_JORG_MACHINEGUN_R4:
-	case MZ2_JORG_MACHINEGUN_R5:
-	case MZ2_JORG_MACHINEGUN_R6:
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		CL_ParticleEffect (origin, vec3_origin, 0, 40);
-		CL_SmokeAndFlash(origin);
-		break;
-
-	case MZ2_JORG_BFG_1:
-		dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
-		break;
-
-	case MZ2_BOSS2_MACHINEGUN_R1:
-	case MZ2_BOSS2_MACHINEGUN_R2:
-	case MZ2_BOSS2_MACHINEGUN_R3:
-	case MZ2_BOSS2_MACHINEGUN_R4:
-	case MZ2_BOSS2_MACHINEGUN_R5:
-	case MZ2_CARRIER_MACHINEGUN_R1:			// PMM
-	case MZ2_CARRIER_MACHINEGUN_R2:			// PMM
-
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-
-		CL_ParticleEffect (origin, vec3_origin, 0, 40);
-		CL_SmokeAndFlash(origin);
-		break;
-
-// ======
-// ROGUE
-	case MZ2_STALKER_BLASTER:
-	case MZ2_DAEDALUS_BLASTER:
-	case MZ2_MEDIC_BLASTER_2:
-	case MZ2_WIDOW_BLASTER:
-	case MZ2_WIDOW_BLASTER_SWEEP1:
-	case MZ2_WIDOW_BLASTER_SWEEP2:
-	case MZ2_WIDOW_BLASTER_SWEEP3:
-	case MZ2_WIDOW_BLASTER_SWEEP4:
-	case MZ2_WIDOW_BLASTER_SWEEP5:
-	case MZ2_WIDOW_BLASTER_SWEEP6:
-	case MZ2_WIDOW_BLASTER_SWEEP7:
-	case MZ2_WIDOW_BLASTER_SWEEP8:
-	case MZ2_WIDOW_BLASTER_SWEEP9:
-	case MZ2_WIDOW_BLASTER_100:
-	case MZ2_WIDOW_BLASTER_90:
-	case MZ2_WIDOW_BLASTER_80:
-	case MZ2_WIDOW_BLASTER_70:
-	case MZ2_WIDOW_BLASTER_60:
-	case MZ2_WIDOW_BLASTER_50:
-	case MZ2_WIDOW_BLASTER_40:
-	case MZ2_WIDOW_BLASTER_30:
-	case MZ2_WIDOW_BLASTER_20:
-	case MZ2_WIDOW_BLASTER_10:
-	case MZ2_WIDOW_BLASTER_0:
-	case MZ2_WIDOW_BLASTER_10L:
-	case MZ2_WIDOW_BLASTER_20L:
-	case MZ2_WIDOW_BLASTER_30L:
-	case MZ2_WIDOW_BLASTER_40L:
-	case MZ2_WIDOW_BLASTER_50L:
-	case MZ2_WIDOW_BLASTER_60L:
-	case MZ2_WIDOW_BLASTER_70L:
-	case MZ2_WIDOW_RUN_1:
-	case MZ2_WIDOW_RUN_2:
-	case MZ2_WIDOW_RUN_3:
-	case MZ2_WIDOW_RUN_4:
-	case MZ2_WIDOW_RUN_5:
-	case MZ2_WIDOW_RUN_6:
-	case MZ2_WIDOW_RUN_7:
-	case MZ2_WIDOW_RUN_8:
-		dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_WIDOW_DISRUPTOR:
-		dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
-		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), 1, ATTN_NORM, 0);
-		break;
-
-	case MZ2_WIDOW_PLASMABEAM:
-	case MZ2_WIDOW2_BEAMER_1:
-	case MZ2_WIDOW2_BEAMER_2:
-	case MZ2_WIDOW2_BEAMER_3:
-	case MZ2_WIDOW2_BEAMER_4:
-	case MZ2_WIDOW2_BEAMER_5:
-	case MZ2_WIDOW2_BEAM_SWEEP_1:
-	case MZ2_WIDOW2_BEAM_SWEEP_2:
-	case MZ2_WIDOW2_BEAM_SWEEP_3:
-	case MZ2_WIDOW2_BEAM_SWEEP_4:
-	case MZ2_WIDOW2_BEAM_SWEEP_5:
-	case MZ2_WIDOW2_BEAM_SWEEP_6:
-	case MZ2_WIDOW2_BEAM_SWEEP_7:
-	case MZ2_WIDOW2_BEAM_SWEEP_8:
-	case MZ2_WIDOW2_BEAM_SWEEP_9:
-	case MZ2_WIDOW2_BEAM_SWEEP_10:
-	case MZ2_WIDOW2_BEAM_SWEEP_11:
-		dl->radius = 300 + (rand()&100);
-		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-		dl->die = cl.time + 200;
-		break;
-// ROGUE
-// ======
-
-// --- Xian's shit ends ---
-
-	}
-}
-
-
-/*
-===============
-CL_AddDLights
-
-===============
-*/
-void CL_AddDLights (void)
-{
-	int			i;
-	cdlight_t	*dl;
-
-	dl = cl_dlights;
-
-//=====
-//PGM
-	if(vidref_val == VIDREF_GL)
-	{
-		for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
-		{
-			if (!dl->radius)
-				continue;
-			V_AddLight (dl->origin, dl->radius,
-				dl->color[0], dl->color[1], dl->color[2]);
-		}
-	}
-	else
-	{
-		for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
-		{
-			if (!dl->radius)
-				continue;
-
-			// negative light in software. only black allowed
-			if ((dl->color[0] < 0) || (dl->color[1] < 0) || (dl->color[2] < 0))
-			{
-				dl->radius = -(dl->radius);
-				dl->color[0] = 1;
-				dl->color[1] = 1;
-				dl->color[2] = 1;
-			}
-			V_AddLight (dl->origin, dl->radius,
-				dl->color[0], dl->color[1], dl->color[2]);
-		}
-	}
-//PGM
-//=====
-}
-
-
-
-/*
-==============================================================
-
-PARTICLE MANAGEMENT
-
-==============================================================
-*/
-
-/*
-// THIS HAS BEEN RELOCATED TO CLIENT.H
-typedef struct particle_s
-{
-	struct particle_s	*next;
-
-	float		time;
-
-	vec3_t		org;
-	vec3_t		vel;
-	vec3_t		accel;
-	float		color;
-	float		colorvel;
-	float		alpha;
-	float		alphavel;
-} cparticle_t;
-
-
-#define	PARTICLE_GRAVITY	40
-*/
-
-cparticle_t	*active_particles, *free_particles;
-
-cparticle_t	particles[MAX_PARTICLES];
-int			cl_numparticles = MAX_PARTICLES;
-
-
-/*
-===============
-CL_ClearParticles
-===============
-*/
-void CL_ClearParticles (void)
-{
-	int		i;
-	
-	free_particles = &particles[0];
-	active_particles = NULL;
-
-	for (i=0 ;i<cl_numparticles ; i++)
-		particles[i].next = &particles[i+1];
-	particles[cl_numparticles-1].next = NULL;
-}
-
-
-/*
-===============
-CL_ParticleEffect
-
-Wall impact puffs
-===============
-*/
-void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count)
-{
-	int			i, j;
-	cparticle_t	*p;
-	float		d;
-
-	for (i=0 ; i<count ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = color + (rand()&7);
-
-		d = rand()&31;
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
-			p->vel[j] = crand()*20;
-		}
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY;
-		p->alpha = 1.0;
-
-		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
-	}
-}
-
-
-/*
-===============
-CL_ParticleEffect2
-===============
-*/
-void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count)
-{
-	int			i, j;
-	cparticle_t	*p;
-	float		d;
-
-	for (i=0 ; i<count ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = color;
-
-		d = rand()&7;
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
-			p->vel[j] = crand()*20;
-		}
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY;
-		p->alpha = 1.0;
-
-		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
-	}
-}
-
-
-// RAFAEL
-/*
-===============
-CL_ParticleEffect3
-===============
-*/
-void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count)
-{
-	int			i, j;
-	cparticle_t	*p;
-	float		d;
-
-	for (i=0 ; i<count ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = color;
-
-		d = rand()&7;
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
-			p->vel[j] = crand()*20;
-		}
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = PARTICLE_GRAVITY;
-		p->alpha = 1.0;
-
-		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
-	}
-}
-
-/*
-===============
-CL_TeleporterParticles
-===============
-*/
-void CL_TeleporterParticles (entity_state_t *ent)
-{
-	int			i, j;
-	cparticle_t	*p;
-
-	for (i=0 ; i<8 ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = 0xdb;
-
-		for (j=0 ; j<2 ; j++)
-		{
-			p->org[j] = ent->origin[j] - 16 + (rand()&31);
-			p->vel[j] = crand()*14;
-		}
-
-		p->org[2] = ent->origin[2] - 8 + (rand()&7);
-		p->vel[2] = 80 + (rand()&7);
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY;
-		p->alpha = 1.0;
-
-		p->alphavel = -0.5;
-	}
-}
-
-
-/*
-===============
-CL_LogoutEffect
-
-===============
-*/
-void CL_LogoutEffect (vec3_t org, int type)
-{
-	int			i, j;
-	cparticle_t	*p;
-
-	for (i=0 ; i<500 ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-
-		if (type == MZ_LOGIN)
-			p->color = 0xd0 + (rand()&7);	// green
-		else if (type == MZ_LOGOUT)
-			p->color = 0x40 + (rand()&7);	// red
-		else
-			p->color = 0xe0 + (rand()&7);	// yellow
-
-		p->org[0] = org[0] - 16 + qfrand()*32;
-		p->org[1] = org[1] - 16 + qfrand()*32;
-		p->org[2] = org[2] - 24 + qfrand()*56;
-
-		for (j=0 ; j<3 ; j++)
-			p->vel[j] = crand()*20;
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY;
-		p->alpha = 1.0;
-
-		p->alphavel = -1.0 / (1.0 + qfrand()*0.3);
-	}
-}
-
-
-/*
-===============
-CL_ItemRespawnParticles
-
-===============
-*/
-void CL_ItemRespawnParticles (vec3_t org)
-{
-	int			i, j;
-	cparticle_t	*p;
-
-	for (i=0 ; i<64 ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-
-		p->color = 0xd4 + (rand()&3);	// green
-
-		p->org[0] = org[0] + crand()*8;
-		p->org[1] = org[1] + crand()*8;
-		p->org[2] = org[2] + crand()*8;
-
-		for (j=0 ; j<3 ; j++)
-			p->vel[j] = crand()*8;
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY*0.2;
-		p->alpha = 1.0;
-
-		p->alphavel = -1.0 / (1.0 + qfrand()*0.3);
-	}
-}
-
-
-/*
-===============
-CL_ExplosionParticles
-===============
-*/
-void CL_ExplosionParticles (vec3_t org)
-{
-	int			i, j;
-	cparticle_t	*p;
-
-	for (i=0 ; i<256 ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = 0xe0 + (rand()&7);
-
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = org[j] + ((rand()%32)-16);
-			p->vel[j] = (rand()%384)-192;
-		}
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY;
-		p->alpha = 1.0;
-
-		p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
-	}
-}
-
-
-/*
-===============
-CL_BigTeleportParticles
-===============
-*/
-void CL_BigTeleportParticles (vec3_t org)
-{
-	int			i;
-	cparticle_t	*p;
-	float		angle, dist;
-	static int colortable[4] = {2*8,13*8,21*8,18*8};
-
-	for (i=0 ; i<4096 ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-
-		p->color = colortable[rand()&3];
-
-		angle = M_PI*2*(rand()&1023)/1023.0;
-		dist = rand()&31;
-		p->org[0] = org[0] + cos(angle)*dist;
-		p->vel[0] = cos(angle)*(70+(rand()&63));
-		p->accel[0] = -cos(angle)*100;
-
-		p->org[1] = org[1] + sin(angle)*dist;
-		p->vel[1] = sin(angle)*(70+(rand()&63));
-		p->accel[1] = -sin(angle)*100;
-
-		p->org[2] = org[2] + 8 + (rand()%90);
-		p->vel[2] = -100 + (rand()&31);
-		p->accel[2] = PARTICLE_GRAVITY*4;
-		p->alpha = 1.0;
-
-		p->alphavel = -0.3 / (0.5 + qfrand()*0.3);
-	}
-}
-
-
-/*
-===============
-CL_BlasterParticles
-
-Wall impact puffs
-===============
-*/
-void CL_BlasterParticles (vec3_t org, vec3_t dir)
-{
-	int			i, j;
-	cparticle_t	*p;
-	float		d;
-	int			count;
-
-	count = 40;
-	for (i=0 ; i<count ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = 0xe0 + (rand()&7);
-
-		d = rand()&15;
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
-			p->vel[j] = dir[j] * 30 + crand()*40;
-		}
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY;
-		p->alpha = 1.0;
-
-		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
-	}
-}
-
-
-/*
-===============
-CL_BlasterTrail
-
-===============
-*/
-void CL_BlasterTrail (vec3_t start, vec3_t end)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-	int			dec;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	dec = 5;
-	VectorScale (vec, 5, vec);
-
-	// FIXME: this is a really silly way to have a loop
-	while (len > 0)
-	{
-		len -= dec;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (0.3+qfrand()*0.2);
-		p->color = 0xe0;
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j] + crand();
-			p->vel[j] = crand()*5;
-			p->accel[j] = 0;
-		}
-
-		VectorAdd (move, vec, move);
-	}
-}
-
-/*
-===============
-CL_QuadTrail
-
-===============
-*/
-void CL_QuadTrail (vec3_t start, vec3_t end)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-	int			dec;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	dec = 5;
-	VectorScale (vec, 5, vec);
-
-	while (len > 0)
-	{
-		len -= dec;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (0.8+qfrand()*0.2);
-		p->color = 115;
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j] + crand()*16;
-			p->vel[j] = crand()*5;
-			p->accel[j] = 0;
-		}
-
-		VectorAdd (move, vec, move);
-	}
-}
-
-/*
-===============
-CL_FlagTrail
-
-===============
-*/
-void CL_FlagTrail (vec3_t start, vec3_t end, float color)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-	int			dec;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	dec = 5;
-	VectorScale (vec, 5, vec);
-
-	while (len > 0)
-	{
-		len -= dec;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (0.8+qfrand()*0.2);
-		p->color = color;
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j] + crand()*16;
-			p->vel[j] = crand()*5;
-			p->accel[j] = 0;
-		}
-
-		VectorAdd (move, vec, move);
-	}
-}
-
-/*
-===============
-CL_DiminishingTrail
-
-===============
-*/
-void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-	float		dec;
-	float		orgscale;
-	float		velscale;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	dec = 0.5;
-	VectorScale (vec, dec, vec);
-
-	if (old->trailcount > 900)
-	{
-		orgscale = 4;
-		velscale = 15;
-	}
-	else if (old->trailcount > 800)
-	{
-		orgscale = 2;
-		velscale = 10;
-	}
-	else
-	{
-		orgscale = 1;
-		velscale = 5;
-	}
-
-	while (len > 0)
-	{
-		len -= dec;
-
-		if (!free_particles)
-			return;
-
-		// drop less particles as it flies
-		if ((rand()&1023) < old->trailcount)
-		{
-			p = free_particles;
-			free_particles = p->next;
-			p->next = active_particles;
-			active_particles = p;
-			VectorClear (p->accel);
-		
-			p->time = cl.time;
-
-			if (flags & EF_GIB)
-			{
-				p->alpha = 1.0;
-				p->alphavel = -1.0 / (1+qfrand()*0.4);
-				p->color = 0xe8 + (rand()&7);
-				for (j=0 ; j<3 ; j++)
-				{
-					p->org[j] = move[j] + crand()*orgscale;
-					p->vel[j] = crand()*velscale;
-					p->accel[j] = 0;
-				}
-				p->vel[2] -= PARTICLE_GRAVITY;
-			}
-			else if (flags & EF_GREENGIB)
-			{
-				p->alpha = 1.0;
-				p->alphavel = -1.0 / (1+qfrand()*0.4);
-				p->color = 0xdb + (rand()&7);
-				for (j=0; j< 3; j++)
-				{
-					p->org[j] = move[j] + crand()*orgscale;
-					p->vel[j] = crand()*velscale;
-					p->accel[j] = 0;
-				}
-				p->vel[2] -= PARTICLE_GRAVITY;
-			}
-			else
-			{
-				p->alpha = 1.0;
-				p->alphavel = -1.0 / (1+qfrand()*0.2);
-				p->color = 4 + (rand()&7);
-				for (j=0 ; j<3 ; j++)
-				{
-					p->org[j] = move[j] + crand()*orgscale;
-					p->vel[j] = crand()*velscale;
-				}
-				p->accel[2] = 20;
-			}
-		}
-
-		old->trailcount -= 5;
-		if (old->trailcount < 100)
-			old->trailcount = 100;
-		VectorAdd (move, vec, move);
-	}
-}
-
-void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up)
-{
-	float		d;
-
-	// this rotate and negat guarantees a vector
-	// not colinear with the original
-	right[1] = -forward[0];
-	right[2] = forward[1];
-	right[0] = forward[2];
-
-	d = DotProduct (right, forward);
-	VectorMA (right, -d, forward, right);
-	VectorNormalize (right);
-	CrossProduct (right, forward, up);
-}
-
-/*
-===============
-CL_RocketTrail
-
-===============
-*/
-void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-	float		dec;
-
-	// smoke
-	CL_DiminishingTrail (start, end, old, EF_ROCKET);
-
-	// fire
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	dec = 1;
-	VectorScale (vec, dec, vec);
-
-	while (len > 0)
-	{
-		len -= dec;
-
-		if (!free_particles)
-			return;
-
-		if ( (rand()&7) == 0)
-		{
-			p = free_particles;
-			free_particles = p->next;
-			p->next = active_particles;
-			active_particles = p;
-			
-			VectorClear (p->accel);
-			p->time = cl.time;
-
-			p->alpha = 1.0;
-			p->alphavel = -1.0 / (1+qfrand()*0.2);
-			p->color = 0xdc + (rand()&3);
-			for (j=0 ; j<3 ; j++)
-			{
-				p->org[j] = move[j] + crand()*5;
-				p->vel[j] = crand()*20;
-			}
-			p->accel[2] = -PARTICLE_GRAVITY;
-		}
-		VectorAdd (move, vec, move);
-	}
-}
-
-/*
-===============
-CL_RailTrail
-
-===============
-*/
-void CL_RailTrail (vec3_t start, vec3_t end)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-	float		dec;
-	vec3_t		right, up;
-	int			i;
-	float		d, c, s;
-	vec3_t		dir;
-	byte		clr = 0x74;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	MakeNormalVectors (vec, right, up);
-
-	for (i=0 ; i<len ; i++)
-	{
-		if (!free_particles)
-			return;
-
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		
-		p->time = cl.time;
-		VectorClear (p->accel);
-
-		d = i * 0.1;
-		c = cos(d);
-		s = sin(d);
-
-		VectorScale (right, c, dir);
-		VectorMA (dir, s, up, dir);
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (1+qfrand()*0.2);
-		p->color = clr + (rand()&7);
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j] + dir[j]*3;
-			p->vel[j] = dir[j]*6;
-		}
-
-		VectorAdd (move, vec, move);
-	}
-
-	dec = 0.75;
-	VectorScale (vec, dec, vec);
-	VectorCopy (start, move);
-
-	while (len > 0)
-	{
-		len -= dec;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		VectorClear (p->accel);
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (0.6+qfrand()*0.2);
-		p->color = 0x0 + rand()&15;
-
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j] + crand()*3;
-			p->vel[j] = crand()*3;
-			p->accel[j] = 0;
-		}
-
-		VectorAdd (move, vec, move);
-	}
-}
-
-// RAFAEL
-/*
-===============
-CL_IonripperTrail
-===============
-*/
-void CL_IonripperTrail (vec3_t start, vec3_t ent)
-{
-	vec3_t	move;
-	vec3_t	vec;
-	float	len;
-	int		j;
-	cparticle_t *p;
-	int		dec;
-	int     left = 0;
-
-	VectorCopy (start, move);
-	VectorSubtract (ent, start, vec);
-	len = VectorNormalize (vec);
-
-	dec = 5;
-	VectorScale (vec, 5, vec);
-
-	while (len > 0)
-	{
-		len -= dec;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-
-		p->time = cl.time;
-		p->alpha = 0.5;
-		p->alphavel = -1.0 / (0.3 + qfrand() * 0.2);
-		p->color = 0xe4 + (rand()&3);
-
-		for (j=0; j<3; j++)
-		{
-			p->org[j] = move[j];
-			p->accel[j] = 0;
-		}
-		if (left)
-		{
-			left = 0;
-			p->vel[0] = 10;
-		}
-		else 
-		{
-			left = 1;
-			p->vel[0] = -10;
-		}
-
-		p->vel[1] = 0;
-		p->vel[2] = 0;
-
-		VectorAdd (move, vec, move);
-	}
-}
-
-
-/*
-===============
-CL_BubbleTrail
-
-===============
-*/
-void CL_BubbleTrail (vec3_t start, vec3_t end)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			i, j;
-	cparticle_t	*p;
-	float		dec;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	dec = 32;
-	VectorScale (vec, dec, vec);
-
-	for (i=0 ; i<len ; i+=dec)
-	{
-		if (!free_particles)
-			return;
-
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		VectorClear (p->accel);
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (1+qfrand()*0.2);
-		p->color = 4 + (rand()&7);
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j] + crand()*2;
-			p->vel[j] = crand()*5;
-		}
-		p->vel[2] += 6;
-
-		VectorAdd (move, vec, move);
-	}
-}
-
-
-/*
-===============
-CL_FlyParticles
-===============
-*/
-
-#define	BEAMLENGTH	16
-
-void CL_FlyParticles (vec3_t origin, int count)
-{
-	int			i;
-	cparticle_t	*p;
-	float		angle;
-	float		sp, sy, cp, cy;
-	vec3_t		forward;
-	float		dist;
-	float		ltime;
-
-
-	if (count > NUMVERTEXNORMALS)
-		count = NUMVERTEXNORMALS;
-
-	if (!avelocities[0][0])
-	{
-		for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
-			avelocities[0][i] = (rand()&255) * 0.01;
-	}
-
-
-	ltime = (float)cl.time / 1000.0;
-	for (i=0 ; i<count ; i+=2)
-	{
-		angle = ltime * avelocities[i][0];
-		sy = sin(angle);
-		cy = cos(angle);
-		angle = ltime * avelocities[i][1];
-		sp = sin(angle);
-		cp = cos(angle);
-		/*
-		angle = ltime * avelocities[i][2];
-		sr = sin(angle);
-		cr = cos(angle);
-		*/
-	
-		forward[0] = cp*cy;
-		forward[1] = cp*sy;
-		forward[2] = -sp;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-
-		dist = sin(ltime + i)*64;
-		p->org[0] = origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
-		p->org[1] = origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
-		p->org[2] = origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
-
-		VectorClear (p->vel);
-		VectorClear (p->accel);
-
-		p->color = 0;
-		p->colorvel = 0;
-
-		p->alpha = 1;
-		p->alphavel = -100;
-	}
-}
-
-void CL_FlyEffect (centity_t *ent, vec3_t origin)
-{
-	int		n;
-	int		count;
-	int		starttime;
-
-	if (ent->fly_stoptime < cl.time)
-	{
-		starttime = cl.time;
-		ent->fly_stoptime = cl.time + 60000;
-	}
-	else
-	{
-		starttime = ent->fly_stoptime - 60000;
-	}
-
-	n = cl.time - starttime;
-	if (n < 20000)
-		count = n * 162 / 20000.0;
-	else
-	{
-		n = ent->fly_stoptime - cl.time;
-		if (n < 20000)
-			count = n * 162 / 20000.0;
-		else
-			count = 162;
-	}
-
-	CL_FlyParticles (origin, count);
-}
-
-
-/*
-===============
-CL_BfgParticles
-===============
-*/
-
-void CL_BfgParticles (entity_t *ent)
-{
-	int			i;
-	cparticle_t	*p;
-	float		angle;
-	float		sp, sy, cp, cy;
-	vec3_t		forward;
-	float		dist;
-	vec3_t		v;
-	float		ltime;
-	
-	if (!avelocities[0][0])
-	{
-		for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
-			avelocities[0][i] = (rand()&255) * 0.01;
-	}
-
-
-	ltime = (float)cl.time / 1000.0;
-	for (i=0 ; i<NUMVERTEXNORMALS ; i++)
-	{
-		angle = ltime * avelocities[i][0];
-		sy = sin(angle);
-		cy = cos(angle);
-		angle = ltime * avelocities[i][1];
-		sp = sin(angle);
-		cp = cos(angle);
-		/*
-		angle = ltime * avelocities[i][2];
-		sr = sin(angle);
-		cr = cos(angle);
-		*/
-	
-		forward[0] = cp*cy;
-		forward[1] = cp*sy;
-		forward[2] = -sp;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-
-		dist = sin(ltime + i)*64;
-		p->org[0] = ent->origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
-		p->org[1] = ent->origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
-		p->org[2] = ent->origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
-
-		VectorClear (p->vel);
-		VectorClear (p->accel);
-
-		VectorSubtract (p->org, ent->origin, v);
-		dist = VectorLength(v) / 90.0;
-		p->color = floor (0xd0 + dist * 7);
-		p->colorvel = 0;
-
-		p->alpha = 1.0 - dist;
-		p->alphavel = -100;
-	}
-}
-
-
-/*
-===============
-CL_TrapParticles
-===============
-*/
-// RAFAEL
-void CL_TrapParticles (entity_t *ent)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	vec3_t		start, end;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-	int			dec;
-
-	ent->origin[2]-=14;
-	VectorCopy (ent->origin, start);
-	VectorCopy (ent->origin, end);
-	end[2]+=64;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	dec = 5;
-	VectorScale (vec, 5, vec);
-
-	// FIXME: this is a really silly way to have a loop
-	while (len > 0)
-	{
-		len -= dec;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (0.3+qfrand()*0.2);
-		p->color = 0xe0;
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j] + crand();
-			p->vel[j] = crand()*15;
-			p->accel[j] = 0;
-		}
-		p->accel[2] = PARTICLE_GRAVITY;
-
-		VectorAdd (move, vec, move);
-	}
-
-	{
-
-	
-	int			i, j, k;
-	cparticle_t	*p;
-	float		vel;
-	vec3_t		dir;
-	vec3_t		org;
-
-	
-	ent->origin[2]+=14;
-	VectorCopy (ent->origin, org);
-
-
-	for (i=-2 ; i<=2 ; i+=4)
-		for (j=-2 ; j<=2 ; j+=4)
-			for (k=-2 ; k<=4 ; k+=4)
-			{
-				if (!free_particles)
-					return;
-				p = free_particles;
-				free_particles = p->next;
-				p->next = active_particles;
-				active_particles = p;
-
-				p->time = cl.time;
-				p->color = 0xe0 + (rand()&3);
-
-				p->alpha = 1.0;
-				p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
-				
-				p->org[0] = org[0] + i + ((rand()&23) * crand());
-				p->org[1] = org[1] + j + ((rand()&23) * crand());
-				p->org[2] = org[2] + k + ((rand()&23) * crand());
-	
-				dir[0] = j * 8;
-				dir[1] = i * 8;
-				dir[2] = k * 8;
-	
-				VectorNormalize (dir);						
-				vel = 50 + rand()&63;
-				VectorScale (dir, vel, p->vel);
-
-				p->accel[0] = p->accel[1] = 0;
-				p->accel[2] = -PARTICLE_GRAVITY;
-			}
-	}
-}
-
-
-/*
-===============
-CL_BFGExplosionParticles
-===============
-*/
-//FIXME combined with CL_ExplosionParticles
-void CL_BFGExplosionParticles (vec3_t org)
-{
-	int			i, j;
-	cparticle_t	*p;
-
-	for (i=0 ; i<256 ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = 0xd0 + (rand()&7);
-
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = org[j] + ((rand()%32)-16);
-			p->vel[j] = (rand()%384)-192;
-		}
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY;
-		p->alpha = 1.0;
-
-		p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
-	}
-}
-
-
-/*
-===============
-CL_TeleportParticles
-
-===============
-*/
-void CL_TeleportParticles (vec3_t org)
-{
-	int			i, j, k;
-	cparticle_t	*p;
-	float		vel;
-	vec3_t		dir;
-
-	for (i=-16 ; i<=16 ; i+=4)
-		for (j=-16 ; j<=16 ; j+=4)
-			for (k=-16 ; k<=32 ; k+=4)
-			{
-				if (!free_particles)
-					return;
-				p = free_particles;
-				free_particles = p->next;
-				p->next = active_particles;
-				active_particles = p;
-
-				p->time = cl.time;
-				p->color = 7 + (rand()&7);
-
-				p->alpha = 1.0;
-				p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
-				
-				p->org[0] = org[0] + i + (rand()&3);
-				p->org[1] = org[1] + j + (rand()&3);
-				p->org[2] = org[2] + k + (rand()&3);
-	
-				dir[0] = j*8;
-				dir[1] = i*8;
-				dir[2] = k*8;
-	
-				VectorNormalize (dir);						
-				vel = 50 + (rand()&63);
-				VectorScale (dir, vel, p->vel);
-
-				p->accel[0] = p->accel[1] = 0;
-				p->accel[2] = -PARTICLE_GRAVITY;
-			}
-}
-
-
-/*
-===============
-CL_AddParticles
-===============
-*/
-void CL_AddParticles (void)
-{
-	cparticle_t		*p, *next;
-	float			alpha;
-	float			time = 0, time2;
-	vec3_t			org;
-	int				color;
-	cparticle_t		*active, *tail;
-
-	active = NULL;
-	tail = NULL;
-
-	for (p=active_particles ; p ; p=next)
-	{
-		next = p->next;
-
-		// PMM - added INSTANT_PARTICLE handling for heat beam
-		if (p->alphavel != INSTANT_PARTICLE)
-		{
-			time = (cl.time - p->time)*0.001;
-			alpha = p->alpha + time*p->alphavel;
-			if (alpha <= 0)
-			{	// faded out
-				p->next = free_particles;
-				free_particles = p;
-				continue;
-			}
-		}
-		else
-		{
-			alpha = p->alpha;
-		}
-
-		p->next = NULL;
-		if (!tail)
-			active = tail = p;
-		else
-		{
-			tail->next = p;
-			tail = p;
-		}
-
-		if (alpha > 1.0)
-			alpha = 1;
-		color = p->color;
-
-		time2 = time*time;
-
-		org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
-		org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
-		org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
-
-		V_AddParticle (org, color, alpha);
-		// PMM
-		if (p->alphavel == INSTANT_PARTICLE)
-		{
-			p->alphavel = 0.0;
-			p->alpha = 0.0;
-		}
-	}
-
-	active_particles = active;
-}
-
-
-/*
-==============
-CL_EntityEvent
-
-An entity has just been parsed that has an event value
-
-the female events are there for backwards compatability
-==============
-*/
-extern struct sfx_s	*cl_sfx_footsteps[4];
-
-void CL_EntityEvent (entity_state_t *ent)
-{
-	switch (ent->event)
-	{
-	case EV_ITEM_RESPAWN:
-		S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("items/respawn1.wav"), 1, ATTN_IDLE, 0);
-		CL_ItemRespawnParticles (ent->origin);
-		break;
-	case EV_PLAYER_TELEPORT:
-		S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("misc/tele1.wav"), 1, ATTN_IDLE, 0);
-		CL_TeleportParticles (ent->origin);
-		break;
-	case EV_FOOTSTEP:
-		if (cl_footsteps->value)
-			S_StartSound (NULL, ent->number, CHAN_BODY, cl_sfx_footsteps[rand()&3], 1, ATTN_NORM, 0);
-		break;
-	case EV_FALLSHORT:
-		S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("player/land1.wav"), 1, ATTN_NORM, 0);
-		break;
-	case EV_FALL:
-		S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall2.wav"), 1, ATTN_NORM, 0);
-		break;
-	case EV_FALLFAR:
-		S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall1.wav"), 1, ATTN_NORM, 0);
-		break;
-	}
-}
-
-
-/*
-==============
-CL_ClearEffects
-
-==============
-*/
-void CL_ClearEffects (void)
-{
-	CL_ClearParticles ();
-	CL_ClearDlights ();
-	CL_ClearLightStyles ();
-}
--- a/client/cl_input.c
+++ /dev/null
@@ -1,525 +1,0 @@
-// cl.input.c  -- builds an intended movement command to send to the server
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-cvar_t	*cl_nodelta;
-
-unsigned	frame_msec;
-unsigned	old_sys_frame_time;
-
-/*
-===============================================================================
-
-KEY BUTTONS
-
-Continuous button event tracking is complicated by the fact that two different
-input sources (say, mouse button 1 and the control key) can both press the
-same button, but the button should only be released when both of the
-pressing key have been released.
-
-When a key event issues a button command (+forward, +attack, etc), it appends
-its key number as a parameter to the command so it can be matched up with
-the release.
-
-state bit 0 is the current state of the key
-state bit 1 is edge triggered on the up to down transition
-state bit 2 is edge triggered on the down to up transition
-
-
-Key_Event (int key, qboolean down, unsigned time);
-
-  +mlook src time
-
-===============================================================================
-*/
-
-
-kbutton_t	in_klook;
-kbutton_t	in_left, in_right, in_forward, in_back;
-kbutton_t	in_lookup, in_lookdown, in_moveleft, in_moveright;
-kbutton_t	in_strafe, in_speed, in_use, in_attack;
-kbutton_t	in_up, in_down;
-
-int			in_impulse;
-
-
-void KeyDown (kbutton_t *b)
-{
-	int		k;
-	char	*c;
-	
-	c = Cmd_Argv(1);
-	if (c[0])
-		k = atoi(c);
-	else
-		k = -1;		// typed manually at the console for continuous down
-
-	if (k == b->down[0] || k == b->down[1])
-		return;		// repeating key
-	
-	if (!b->down[0])
-		b->down[0] = k;
-	else if (!b->down[1])
-		b->down[1] = k;
-	else
-	{
-		Com_Printf ("Three keys down for a button!\n");
-		return;
-	}
-	
-	if (b->state & 1)
-		return;		// still down
-
-	// save timestamp
-	c = Cmd_Argv(2);
-	b->downtime = atoi(c);
-	if (!b->downtime)
-		b->downtime = sys_frame_time - 100;
-
-	b->state |= 1 + 2;	// down + impulse down
-}
-
-void KeyUp (kbutton_t *b)
-{
-	int		k;
-	char	*c;
-	unsigned	uptime;
-
-	c = Cmd_Argv(1);
-	if (c[0])
-		k = atoi(c);
-	else
-	{ // typed manually at the console, assume for unsticking, so clear all
-		b->down[0] = b->down[1] = 0;
-		b->state = 4;	// impulse up
-		return;
-	}
-
-	if (b->down[0] == k)
-		b->down[0] = 0;
-	else if (b->down[1] == k)
-		b->down[1] = 0;
-	else
-		return;		// key up without coresponding down (menu pass through)
-	if (b->down[0] || b->down[1])
-		return;		// some other key is still holding it down
-
-	if (!(b->state & 1))
-		return;		// still up (this should not happen)
-
-	// save timestamp
-	c = Cmd_Argv(2);
-	uptime = atoi(c);
-	if (uptime)
-		b->msec += uptime - b->downtime;
-	else
-		b->msec += 10;
-
-	b->state &= ~1;		// now up
-	b->state |= 4; 		// impulse up
-}
-
-void IN_KLookDown (void) {KeyDown(&in_klook);}
-void IN_KLookUp (void) {KeyUp(&in_klook);}
-void IN_UpDown(void) {KeyDown(&in_up);}
-void IN_UpUp(void) {KeyUp(&in_up);}
-void IN_DownDown(void) {KeyDown(&in_down);}
-void IN_DownUp(void) {KeyUp(&in_down);}
-void IN_LeftDown(void) {KeyDown(&in_left);}
-void IN_LeftUp(void) {KeyUp(&in_left);}
-void IN_RightDown(void) {KeyDown(&in_right);}
-void IN_RightUp(void) {KeyUp(&in_right);}
-void IN_ForwardDown(void) {KeyDown(&in_forward);}
-void IN_ForwardUp(void) {KeyUp(&in_forward);}
-void IN_BackDown(void) {KeyDown(&in_back);}
-void IN_BackUp(void) {KeyUp(&in_back);}
-void IN_LookupDown(void) {KeyDown(&in_lookup);}
-void IN_LookupUp(void) {KeyUp(&in_lookup);}
-void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
-void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
-void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
-void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
-void IN_MoverightDown(void) {KeyDown(&in_moveright);}
-void IN_MoverightUp(void) {KeyUp(&in_moveright);}
-
-void IN_SpeedDown(void) {KeyDown(&in_speed);}
-void IN_SpeedUp(void) {KeyUp(&in_speed);}
-void IN_StrafeDown(void) {KeyDown(&in_strafe);}
-void IN_StrafeUp(void) {KeyUp(&in_strafe);}
-
-void IN_AttackDown(void) {KeyDown(&in_attack);}
-void IN_AttackUp(void) {KeyUp(&in_attack);}
-
-void IN_UseDown (void) {KeyDown(&in_use);}
-void IN_UseUp (void) {KeyUp(&in_use);}
-
-void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
-
-/*
-===============
-CL_KeyState
-
-Returns the fraction of the frame that the key was down
-===============
-*/
-float CL_KeyState (kbutton_t *key)
-{
-	float		val;
-	int			msec;
-
-	key->state &= 1;		// clear impulses
-
-	msec = key->msec;
-	key->msec = 0;
-
-	if (key->state)
-	{	// still down
-		msec += sys_frame_time - key->downtime;
-		key->downtime = sys_frame_time;
-	}
-
-/*
-	if (msec)
-	{
-		Com_Printf ("%i ", msec);
-	}
-*/
-
-	val = (float)msec / frame_msec;
-	if (val < 0)
-		val = 0;
-	if (val > 1)
-		val = 1;
-
-	return val;
-}
-
-
-
-
-//==========================================================================
-
-cvar_t	*cl_upspeed;
-cvar_t	*cl_forwardspeed;
-cvar_t	*cl_sidespeed;
-
-cvar_t	*cl_yawspeed;
-cvar_t	*cl_pitchspeed;
-
-cvar_t	*cl_run;
-
-cvar_t	*cl_anglespeedkey;
-
-
-/*
-================
-CL_AdjustAngles
-
-Moves the local angle positions
-================
-*/
-void CL_AdjustAngles (void)
-{
-	float	speed;
-	float	up, down;
-	
-	if (in_speed.state & 1)
-		speed = cls.frametime * cl_anglespeedkey->value;
-	else
-		speed = cls.frametime;
-
-	if (!(in_strafe.state & 1))
-	{
-		cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
-		cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
-	}
-	if (in_klook.state & 1)
-	{
-		cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward);
-		cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back);
-	}
-	
-	up = CL_KeyState (&in_lookup);
-	down = CL_KeyState(&in_lookdown);
-	
-	cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * up;
-	cl.viewangles[PITCH] += speed*cl_pitchspeed->value * down;
-}
-
-/*
-================
-CL_BaseMove
-
-Send the intended movement message to the server
-================
-*/
-void CL_BaseMove (usercmd_t *cmd)
-{	
-	CL_AdjustAngles ();
-	
-	memset (cmd, 0, sizeof(*cmd));
-	
-	VectorCopy (cl.viewangles, cmd->angles);
-	if (in_strafe.state & 1)
-	{
-		cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right);
-		cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left);
-	}
-
-	cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright);
-	cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft);
-
-	cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up);
-	cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down);
-
-	if (! (in_klook.state & 1) )
-	{	
-		cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward);
-		cmd->forwardmove -= cl_forwardspeed->value * CL_KeyState (&in_back);
-	}	
-
-//
-// adjust for speed key / running
-//
-	if ( (in_speed.state & 1) ^ (int)(cl_run->value) )
-	{
-		cmd->forwardmove *= 2;
-		cmd->sidemove *= 2;
-		cmd->upmove *= 2;
-	}	
-}
-
-void CL_ClampPitch (void)
-{
-	float	pitch;
-
-	pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
-	if (pitch > 180)
-		pitch -= 360;
-	if (cl.viewangles[PITCH] + pitch > 89)
-		cl.viewangles[PITCH] = 89 - pitch;
-	if (cl.viewangles[PITCH] + pitch < -89)
-		cl.viewangles[PITCH] = -89 - pitch;
-}
-
-/*
-==============
-CL_FinishMove
-==============
-*/
-void CL_FinishMove (usercmd_t *cmd)
-{
-	int		ms;
-	int		i;
-
-//
-// figure button bits
-//	
-	if ( in_attack.state & 3 )
-		cmd->buttons |= BUTTON_ATTACK;
-	in_attack.state &= ~2;
-	
-	if (in_use.state & 3)
-		cmd->buttons |= BUTTON_USE;
-	in_use.state &= ~2;
-
-	if (anykeydown && cls.key_dest == key_game)
-		cmd->buttons |= BUTTON_ANY;
-
-	// send milliseconds of time to apply the move
-	ms = cls.frametime * 1000;
-	if (ms > 250)
-		ms = 100;		// time was unreasonable
-	cmd->msec = ms;
-
-	CL_ClampPitch ();
-	for (i=0 ; i<3 ; i++)
-		cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
-
-	cmd->impulse = in_impulse;
-	in_impulse = 0;
-
-// send the ambient light level at the player's current position
-	cmd->lightlevel = (byte)cl_lightlevel->value;
-}
-
-/*
-=================
-CL_CreateCmd
-=================
-*/
-usercmd_t CL_CreateCmd (void)
-{
-	usercmd_t	cmd;
-
-	frame_msec = sys_frame_time - old_sys_frame_time;
-	if (frame_msec < 1)
-		frame_msec = 1;
-	if (frame_msec > 200)
-		frame_msec = 200;
-	
-	// get basic movement from keyboard
-	CL_BaseMove (&cmd);
-
-	// allow mice or other external controllers to add to the move
-	IN_Move (&cmd);
-
-	CL_FinishMove (&cmd);
-
-	old_sys_frame_time = sys_frame_time;
-
-//cmd.impulse = cls.framecount;
-
-	return cmd;
-}
-
-
-void IN_CenterView (void)
-{
-	cl.viewangles[PITCH] = -SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
-}
-
-/*
-============
-CL_InitInput
-============
-*/
-void CL_InitInput (void)
-{
-	Cmd_AddCommand ("centerview",IN_CenterView);
-
-	Cmd_AddCommand ("+moveup",IN_UpDown);
-	Cmd_AddCommand ("-moveup",IN_UpUp);
-	Cmd_AddCommand ("+movedown",IN_DownDown);
-	Cmd_AddCommand ("-movedown",IN_DownUp);
-	Cmd_AddCommand ("+left",IN_LeftDown);
-	Cmd_AddCommand ("-left",IN_LeftUp);
-	Cmd_AddCommand ("+right",IN_RightDown);
-	Cmd_AddCommand ("-right",IN_RightUp);
-	Cmd_AddCommand ("+forward",IN_ForwardDown);
-	Cmd_AddCommand ("-forward",IN_ForwardUp);
-	Cmd_AddCommand ("+back",IN_BackDown);
-	Cmd_AddCommand ("-back",IN_BackUp);
-	Cmd_AddCommand ("+lookup", IN_LookupDown);
-	Cmd_AddCommand ("-lookup", IN_LookupUp);
-	Cmd_AddCommand ("+lookdown", IN_LookdownDown);
-	Cmd_AddCommand ("-lookdown", IN_LookdownUp);
-	Cmd_AddCommand ("+strafe", IN_StrafeDown);
-	Cmd_AddCommand ("-strafe", IN_StrafeUp);
-	Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
-	Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
-	Cmd_AddCommand ("+moveright", IN_MoverightDown);
-	Cmd_AddCommand ("-moveright", IN_MoverightUp);
-	Cmd_AddCommand ("+speed", IN_SpeedDown);
-	Cmd_AddCommand ("-speed", IN_SpeedUp);
-	Cmd_AddCommand ("+attack", IN_AttackDown);
-	Cmd_AddCommand ("-attack", IN_AttackUp);
-	Cmd_AddCommand ("+use", IN_UseDown);
-	Cmd_AddCommand ("-use", IN_UseUp);
-	Cmd_AddCommand ("impulse", IN_Impulse);
-	Cmd_AddCommand ("+klook", IN_KLookDown);
-	Cmd_AddCommand ("-klook", IN_KLookUp);
-
-	cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
-}
-
-
-
-/*
-=================
-CL_SendCmd
-=================
-*/
-void CL_SendCmd (void)
-{
-	sizebuf_t	buf;
-	byte		data[128];
-	int			i;
-	usercmd_t	*cmd, *oldcmd;
-	usercmd_t	nullcmd;
-	int			checksumIndex;
-
-	// build a command even if not connected
-
-	// save this command off for prediction
-	i = cls.netchan.outgoing_sequence & (CMD_BACKUP-1);
-	cmd = &cl.cmds[i];
-	cl.cmd_time[i] = cls.realtime;	// for netgraph ping calculation
-
-	*cmd = CL_CreateCmd ();
-
-	cl.cmd = *cmd;
-
-	if (cls.state == ca_disconnected || cls.state == ca_connecting)
-		return;
-
-	if ( cls.state == ca_connected)
-	{
-		if (cls.netchan.message.cursize	|| curtime - cls.netchan.last_sent > 1000 )
-			Netchan_Transmit (&cls.netchan, 0, buf.data);	
-		return;
-	}
-
-	// send a userinfo update if needed
-	if (userinfo_modified)
-	{
-		CL_FixUpGender();
-		userinfo_modified = false;
-		MSG_WriteByte (&cls.netchan.message, clc_userinfo);
-		MSG_WriteString (&cls.netchan.message, Cvar_Userinfo() );
-	}
-
-	SZ_Init (&buf, data, sizeof(data));
-
-	if (cmd->buttons && cl.cinematictime > 0 && !cl.attractloop 
-		&& cls.realtime - cl.cinematictime > 1000)
-	{	// skip the rest of the cinematic
-		SCR_FinishCinematic ();
-	}
-
-	// begin a client move command
-	MSG_WriteByte (&buf, clc_move);
-
-	// save the position for a checksum byte
-	checksumIndex = buf.cursize;
-	MSG_WriteByte (&buf, 0);
-
-	// let the server know what the last frame we
-	// got was, so the next message can be delta compressed
-	if (cl_nodelta->value || !cl.frame.valid || cls.demowaiting)
-		MSG_WriteLong (&buf, -1);	// no compression
-	else
-		MSG_WriteLong (&buf, cl.frame.serverframe);
-
-	// send this and the previous cmds in the message, so
-	// if the last packet was dropped, it can be recovered
-	i = (cls.netchan.outgoing_sequence-2) & (CMD_BACKUP-1);
-	cmd = &cl.cmds[i];
-	memset (&nullcmd, 0, sizeof(nullcmd));
-	MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd);
-	oldcmd = cmd;
-
-	i = (cls.netchan.outgoing_sequence-1) & (CMD_BACKUP-1);
-	cmd = &cl.cmds[i];
-	MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
-	oldcmd = cmd;
-
-	i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP-1);
-	cmd = &cl.cmds[i];
-	MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
-
-	// calculate a checksum over the move commands
-	buf.data[checksumIndex] = COM_BlockSequenceCRCByte(
-		buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,
-		cls.netchan.outgoing_sequence);
-
-	//
-	// deliver the message
-	//
-	Netchan_Transmit (&cls.netchan, buf.cursize, buf.data);	
-}
-
-
--- a/client/cl_inv.c
+++ /dev/null
@@ -1,126 +1,0 @@
-// cl_inv.c -- client inventory screen
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-================
-CL_ParseInventory
-================
-*/
-void CL_ParseInventory (void)
-{
-	int		i;
-
-	for (i=0 ; i<MAX_ITEMS ; i++)
-		cl.inventory[i] = MSG_ReadShort (&net_message);
-}
-
-
-/*
-================
-Inv_DrawString
-================
-*/
-void Inv_DrawString (int x, int y, char *string)
-{
-	while (*string)
-	{
-		re.DrawChar (x, y, *string);
-		x+=8;
-		string++;
-	}
-}
-
-void SetStringHighBit (char *s)
-{
-	while (*s)
-		*s++ |= 128;
-}
-
-/*
-================
-CL_DrawInventory
-================
-*/
-#define	DISPLAY_ITEMS	17
-
-void CL_DrawInventory (void)
-{
-	int		i, j;
-	int		num, selected_num, item;
-	int		index[MAX_ITEMS];
-	char	string[1024];
-	int		x, y;
-	char	binding[1024];
-	char	*bind;
-	int		selected;
-	int		top;
-
-	selected = cl.frame.playerstate.stats[STAT_SELECTED_ITEM];
-
-	num = 0;
-	selected_num = 0;
-	for (i=0 ; i<MAX_ITEMS ; i++)
-	{
-		if (i==selected)
-			selected_num = num;
-		if (cl.inventory[i])
-		{
-			index[num] = i;
-			num++;
-		}
-	}
-
-	// determine scroll point
-	top = selected_num - DISPLAY_ITEMS/2;
-	if (num - top < DISPLAY_ITEMS)
-		top = num - DISPLAY_ITEMS;
-	if (top < 0)
-		top = 0;
-
-	x = (vid.width-256)/2;
-	y = (vid.height-240)/2;
-
-	// repaint everything next frame
-	SCR_DirtyScreen ();
-
-	re.DrawPic (x, y+8, "inventory");
-
-	y += 24;
-	x += 24;
-	Inv_DrawString (x, y, "hotkey ### item");
-	Inv_DrawString (x, y+8, "------ --- ----");
-	y += 16;
-	for (i=top ; i<num && i < top+DISPLAY_ITEMS ; i++)
-	{
-		item = index[i];
-		// search for a binding
-		Com_sprintf (binding, sizeof(binding), "use %s", cl.configstrings[CS_ITEMS+item]);
-		bind = "";
-		for (j=0 ; j<256 ; j++)
-			if (keybindings[j] && !cistrcmp (keybindings[j], binding))
-			{
-				bind = Key_KeynumToString(j);
-				break;
-			}
-
-		Com_sprintf (string, sizeof(string), "%6s %3i %s", bind, cl.inventory[item],
-			cl.configstrings[CS_ITEMS+item] );
-		if (item != selected)
-			SetStringHighBit (string);
-		else	// draw a blinky cursor by the selected item
-		{
-			if ( (int)(cls.realtime*10) & 1)
-				re.DrawChar (x-8, y, 15);
-		}
-		Inv_DrawString (x, y, string);
-		y += 8;
-	}
-
-
-}
-
-
--- a/client/cl_main.c
+++ /dev/null
@@ -1,1790 +1,0 @@
-// cl_main.c  -- client main loop
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-cvar_t	*adr0;
-cvar_t	*adr1;
-cvar_t	*adr2;
-cvar_t	*adr3;
-cvar_t	*adr4;
-cvar_t	*adr5;
-cvar_t	*adr6;
-cvar_t	*adr7;
-cvar_t	*adr8;
-
-cvar_t	*cl_stereo_separation;
-cvar_t	*cl_stereo;
-
-cvar_t	*rcon_client_password;
-cvar_t	*rcon_address;
-
-cvar_t	*cl_noskins;
-cvar_t	*cl_autoskins;
-cvar_t	*cl_footsteps;
-cvar_t	*cl_timeout;
-cvar_t	*cl_predict;
-//cvar_t	*cl_minfps;
-cvar_t	*cl_maxfps;
-cvar_t	*cl_gun;
-
-cvar_t	*cl_add_particles;
-cvar_t	*cl_add_lights;
-cvar_t	*cl_add_entities;
-cvar_t	*cl_add_blend;
-
-cvar_t	*cl_shownet;
-cvar_t	*cl_showmiss;
-cvar_t	*cl_showclamp;
-
-cvar_t	*cl_paused;
-cvar_t	*cl_timedemo;
-
-cvar_t	*cl_lightlevel;
-
-//
-// userinfo
-//
-cvar_t	*info_password;
-cvar_t	*info_spectator;
-cvar_t	*name;
-cvar_t	*skin;
-cvar_t	*rate;
-cvar_t	*fov;
-cvar_t	*msg;
-cvar_t	*hand;
-cvar_t	*gender;
-cvar_t	*gender_auto;
-
-cvar_t	*cl_vwep;
-
-client_static_t	cls;
-client_state_t	cl;
-
-centity_t		cl_entities[MAX_EDICTS];
-
-entity_state_t	cl_parse_entities[MAX_PARSE_ENTITIES];
-
-extern	cvar_t *allow_download;
-extern	cvar_t *allow_download_players;
-extern	cvar_t *allow_download_models;
-extern	cvar_t *allow_download_sounds;
-extern	cvar_t *allow_download_maps;
-
-//======================================================================
-
-
-/*
-====================
-CL_WriteDemoMessage
-
-Dumps the current net message, prefixed by the length
-====================
-*/
-void CL_WriteDemoMessage (void)
-{
-	int		len, swlen;
-
-	// the first eight bytes are just packet sequencing stuff
-	len = net_message.cursize-8;
-	swlen = LittleLong(len);
-	fwrite (&swlen, 4, 1, cls.demofile);
-	fwrite (net_message.data+8,	len, 1, cls.demofile);
-}
-
-
-/*
-====================
-CL_Stop_f
-
-stop recording a demo
-====================
-*/
-void CL_Stop_f (void)
-{
-	int		len;
-
-	if (!cls.demorecording)
-	{
-		Com_Printf ("Not recording a demo.\n");
-		return;
-	}
-
-// finish up
-	len = -1;
-	fwrite (&len, 4, 1, cls.demofile);
-	fclose (cls.demofile);
-	cls.demofile = NULL;
-	cls.demorecording = false;
-	Com_Printf ("Stopped demo.\n");
-}
-
-/*
-====================
-CL_Record_f
-
-record <demoname>
-
-Begins recording a demo from the current position
-====================
-*/
-void CL_Record_f (void)
-{
-	char	name[MAX_OSPATH];
-	char	buf_data[MAX_MSGLEN];
-	sizebuf_t	buf;
-	int		i;
-	int		len;
-	entity_state_t	*ent;
-	entity_state_t	nullstate;
-
-	if (Cmd_Argc() != 2)
-	{
-		Com_Printf ("record <demoname>\n");
-		return;
-	}
-
-	if (cls.demorecording)
-	{
-		Com_Printf ("Already recording.\n");
-		return;
-	}
-
-	if (cls.state != ca_active)
-	{
-		Com_Printf ("You must be in a level to record.\n");
-		return;
-	}
-
-	//
-	// open the demo file
-	//
-	Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
-
-	Com_Printf ("recording to %s.\n", name);
-	FS_CreatePath (name);
-	cls.demofile = fopen (name, "wb");
-	if (!cls.demofile)
-	{
-		Com_Printf ("ERROR: couldn't open.\n");
-		return;
-	}
-	cls.demorecording = true;
-
-	// don't start saving messages until a non-delta compressed message is received
-	cls.demowaiting = true;
-
-	//
-	// write out messages to hold the startup information
-	//
-	SZ_Init (&buf, (uchar *)buf_data, sizeof(buf_data));
-
-	// send the serverdata
-	MSG_WriteByte (&buf, svc_serverdata);
-	MSG_WriteLong (&buf, PROTOCOL_VERSION);
-	MSG_WriteLong (&buf, 0x10000 + cl.servercount);
-	MSG_WriteByte (&buf, 1);	// demos are always attract loops
-	MSG_WriteString (&buf, cl.gamedir);
-	MSG_WriteShort (&buf, cl.playernum);
-
-	MSG_WriteString (&buf, cl.configstrings[CS_NAME]);
-
-	// configstrings
-	for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
-	{
-		if (cl.configstrings[i][0])
-		{
-			if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
-			{	// write it out
-				len = LittleLong (buf.cursize);
-				fwrite (&len, 4, 1, cls.demofile);
-				fwrite (buf.data, buf.cursize, 1, cls.demofile);
-				buf.cursize = 0;
-			}
-
-			MSG_WriteByte (&buf, svc_configstring);
-			MSG_WriteShort (&buf, i);
-			MSG_WriteString (&buf, cl.configstrings[i]);
-		}
-
-	}
-
-	// baselines
-	memset (&nullstate, 0, sizeof(nullstate));
-	for (i=0; i<MAX_EDICTS ; i++)
-	{
-		ent = &cl_entities[i].baseline;
-		if (!ent->modelindex)
-			continue;
-
-		if (buf.cursize + 64 > buf.maxsize)
-		{	// write it out
-			len = LittleLong (buf.cursize);
-			fwrite (&len, 4, 1, cls.demofile);
-			fwrite (buf.data, buf.cursize, 1, cls.demofile);
-			buf.cursize = 0;
-		}
-
-		MSG_WriteByte (&buf, svc_spawnbaseline);		
-		MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
-	}
-
-	MSG_WriteByte (&buf, svc_stufftext);
-	MSG_WriteString (&buf, "precache\n");
-
-	// write it to the demo file
-
-	len = LittleLong (buf.cursize);
-	fwrite (&len, 4, 1, cls.demofile);
-	fwrite (buf.data, buf.cursize, 1, cls.demofile);
-
-	// the rest of the demo file will be individual frames
-}
-
-//======================================================================
-
-/*
-===================
-Cmd_ForwardToServer
-
-adds the current command line as a clc_stringcmd to the client message.
-things like godmode, noclip, etc, are commands directed to the server,
-so when they are typed in at the console, they will need to be forwarded.
-===================
-*/
-void Cmd_ForwardToServer (void)
-{
-	char	*cmd;
-
-	cmd = Cmd_Argv(0);
-	if (cls.state <= ca_connected || *cmd == '-' || *cmd == '+')
-	{
-		Com_Printf ("Unknown command \"%s\"\n", cmd);
-		return;
-	}
-
-	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
-	SZ_Print (&cls.netchan.message, cmd);
-	if (Cmd_Argc() > 1)
-	{
-		SZ_Print (&cls.netchan.message, " ");
-		SZ_Print (&cls.netchan.message, Cmd_Args());
-	}
-}
-
-void
-CL_Setenv_f(void)
-{
-	int i, l = 0, argc;
-	char name[1024], val[1024], *env;
-
-	argc = Cmd_Argc();
-
-	if(argc > 2){
-		strncpy(name, Cmd_Argv(1), sizeof name);
-		for(i = 2; i < argc; i++){
-			strncpy(val+l, Cmd_Argv(i), sizeof(name) - l - 2);
-			val[sizeof(val)-2] = 0;
-			strcat(val, " ");
-			l = strlen(val);
-		}
-		putenv(name, val);
-	}else if(argc == 2){
-		env = getenv(Cmd_Argv(1));
-		if(env){
-			Com_Printf("%s=%s\n", Cmd_Argv(1), env);
-			free(env);
-		}else
-			Com_Printf("%s undefined\n", Cmd_Argv(1), env);
-	}
-}
-
-
-/*
-==================
-CL_ForwardToServer_f
-==================
-*/
-void CL_ForwardToServer_f (void)
-{
-	if (cls.state != ca_connected && cls.state != ca_active)
-	{
-		Com_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
-		return;
-	}
-	
-	// don't forward the first argument
-	if (Cmd_Argc() > 1)
-	{
-		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
-		SZ_Print (&cls.netchan.message, Cmd_Args());
-	}
-}
-
-
-/*
-==================
-CL_Pause_f
-==================
-*/
-void CL_Pause_f (void)
-{
-	// never pause in multiplayer
-	if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
-	{
-		Cvar_SetValue ("paused", 0);
-		return;
-	}
-
-	Cvar_SetValue ("paused", !cl_paused->value);
-}
-
-/*
-==================
-CL_Quit_f
-==================
-*/
-void CL_Quit_f (void)
-{
-	CL_Disconnect ();
-	Com_Quit ();
-}
-
-/*
-================
-CL_Drop
-
-Called after an ERR_DROP was thrown
-================
-*/
-void CL_Drop (void)
-{
-	if (cls.state == ca_uninitialized)
-		return;
-	if (cls.state == ca_disconnected)
-		return;
-
-	CL_Disconnect ();
-
-	// drop loading plaque unless this is the initial game start
-	if (cls.disable_servercount != -1)
-		SCR_EndLoadingPlaque ();	// get rid of loading plaque
-}
-
-
-/*
-=======================
-CL_SendConnectPacket
-
-We have gotten a challenge from the server, so try and
-connect.
-======================
-*/
-void CL_SendConnectPacket (void)
-{
-	netadr_t	adr;
-	int		port;
-
-	if (!NET_StringToAdr (cls.servername, &adr))
-	{
-		Com_Printf ("Bad server address\n");
-		cls.connect_time = 0;
-		return;
-	}
-	if (adr.port == 0)
-		adr.port = BigShort (PORT_SERVER);
-
-	port = Cvar_VariableValue ("qport");
-	userinfo_modified = false;
-
-	Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n",
-		PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );
-}
-
-/*
-=================
-CL_CheckForResend
-
-Resend a connect message if the last one has timed out
-=================
-*/
-void CL_CheckForResend (void)
-{
-	netadr_t	adr;
-
-	// if the local server is running and we aren't
-	// then connect
-	if (cls.state == ca_disconnected && Com_ServerState() )
-	{
-		cls.state = ca_connecting;
-		strncpy (cls.servername, "localhost", sizeof(cls.servername)-1);
-		// we don't need a challenge on the localhost
-		CL_SendConnectPacket ();
-		return;
-//		cls.connect_time = -99999;	// CL_CheckForResend() will fire immediately
-	}
-
-	// resend if we haven't gotten a reply yet
-	if (cls.state != ca_connecting)
-		return;
-
-	if (cls.realtime - cls.connect_time < 3000)
-		return;
-
-	if (!NET_StringToAdr (cls.servername, &adr))
-	{
-		Com_Printf ("Bad server address\n");
-		cls.state = ca_disconnected;
-		return;
-	}
-	if (adr.port == 0)
-		adr.port = BigShort (PORT_SERVER);
-
-	cls.connect_time = cls.realtime;	// for retransmit requests
-
-	Com_Printf ("Connecting to %s...\n", cls.servername);
-
-	Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
-}
-
-
-/*
-================
-CL_Connect_f
-
-================
-*/
-void CL_Connect_f (void)
-{
-	char	*server;
-
-	if (Cmd_Argc() != 2)
-	{
-		Com_Printf ("usage: connect <server>\n");
-		return;	
-	}
-	
-	if (Com_ServerState ())
-	{	// if running a local server, kill it and reissue
-		SV_Shutdown (va("Server quit\n", msg), false);
-	}
-	else
-	{
-		CL_Disconnect ();
-	}
-
-	server = Cmd_Argv (1);
-
-	NET_Config (true);		// allow remote
-
-	CL_Disconnect ();
-
-	cls.state = ca_connecting;
-	strncpy (cls.servername, server, sizeof(cls.servername)-1);
-	cls.connect_time = -99999;	// CL_CheckForResend() will fire immediately
-}
-
-
-/*
-=====================
-CL_Rcon_f
-
-  Send the rest of the command line over as
-  an unconnected command.
-=====================
-*/
-void CL_Rcon_f (void)
-{
-	char	message[1024];
-	int		i;
-	netadr_t	to;
-
-	if (!rcon_client_password->string)
-	{
-		Com_Printf ("You must set 'rcon_password' before\n"
-					"issuing an rcon command.\n");
-		return;
-	}
-
-	message[0] = (char)255;
-	message[1] = (char)255;
-	message[2] = (char)255;
-	message[3] = (char)255;
-	message[4] = 0;
-
-	NET_Config (true);		// allow remote
-
-	strcat (message, "rcon ");
-
-	strcat (message, rcon_client_password->string);
-	strcat (message, " ");
-
-	for (i=1 ; i<Cmd_Argc() ; i++)
-	{
-		strcat (message, Cmd_Argv(i));
-		strcat (message, " ");
-	}
-
-	if (cls.state >= ca_connected)
-		to = cls.netchan.remote_address;
-	else
-	{
-		if (!strlen(rcon_address->string))
-		{
-			Com_Printf ("You must either be connected,\n"
-						"or set the 'rcon_address' cvar\n"
-						"to issue rcon commands\n");
-
-			return;
-		}
-		NET_StringToAdr (rcon_address->string, &to);
-		if (to.port == 0)
-			to.port = BigShort (PORT_SERVER);
-	}
-	
-	NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
-}
-
-
-/*
-=====================
-CL_ClearState
-
-=====================
-*/
-void CL_ClearState (void)
-{
-	S_StopAllSounds ();
-	CL_ClearEffects ();
-	CL_ClearTEnts ();
-
-// wipe the entire cl structure
-	memset (&cl, 0, sizeof(cl));
-	memset (cl_entities, 0, sizeof(cl_entities));
-
-	SZ_Clear (&cls.netchan.message);
-
-}
-
-/*
-=====================
-CL_Disconnect
-
-Goes from a connected state to full screen console state
-Sends a disconnect message to the server
-This is also called on Com_Error, so it shouldn't cause any errors
-=====================
-*/
-void CL_Disconnect (void)
-{
-	byte	final[32];
-
-	if (cls.state == ca_disconnected)
-		return;
-
-	if (cl_timedemo && cl_timedemo->value)
-	{
-		int	time;
-		
-		time = Sys_Milliseconds () - cl.timedemo_start;
-		if (time > 0)
-			Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
-			time/1000.0, cl.timedemo_frames*1000.0 / time);
-	}
-
-	VectorClear (cl.refdef.blend);
-	re.CinematicSetPalette(NULL);
-
-	M_ForceMenuOff ();
-
-	cls.connect_time = 0;
-
-	SCR_StopCinematic ();
-
-	if (cls.demorecording)
-		CL_Stop_f ();
-
-	// send a disconnect message to the server
-	final[0] = clc_stringcmd;
-	strcpy ((char *)final+1, "disconnect");
-	Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
-	Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
-	Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
-
-	CL_ClearState ();
-
-	// stop download
-	if (cls.download) {
-		fclose(cls.download);
-		cls.download = NULL;
-	}
-
-	cls.state = ca_disconnected;
-}
-
-void CL_Disconnect_f (void)
-{
-	Com_Error (ERR_DROP, "Disconnected from server");
-}
-
-
-/*
-====================
-CL_Packet_f
-
-packet <destination> <contents>
-
-Contents allows \n escape character
-====================
-*/
-void CL_Packet_f (void)
-{
-	char	send[2048];
-	int		i, l;
-	char	*in, *out;
-	netadr_t	adr;
-
-	if (Cmd_Argc() != 3)
-	{
-		Com_Printf ("packet <destination> <contents>\n");
-		return;
-	}
-
-	NET_Config (true);		// allow remote
-
-	if (!NET_StringToAdr (Cmd_Argv(1), &adr))
-	{
-		Com_Printf ("Bad address\n");
-		return;
-	}
-	if (!adr.port)
-		adr.port = BigShort (PORT_SERVER);
-
-	in = Cmd_Argv(2);
-	out = send+4;
-	send[0] = send[1] = send[2] = send[3] = (char)0xff;
-
-	l = strlen (in);
-	for (i=0 ; i<l ; i++)
-	{
-		if (in[i] == '\\' && in[i+1] == 'n')
-		{
-			*out++ = '\n';
-			i++;
-		}
-		else
-			*out++ = in[i];
-	}
-	*out = 0;
-
-	NET_SendPacket (NS_CLIENT, out-send, send, adr);
-}
-
-/*
-=================
-CL_Changing_f
-
-Just sent as a hint to the client that they should
-drop to full console
-=================
-*/
-void CL_Changing_f (void)
-{
-	//ZOID
-	//if we are downloading, we don't change!  This so we don't suddenly stop downloading a map
-	if (cls.download)
-		return;
-
-	SCR_BeginLoadingPlaque ();
-	cls.state = ca_connected;	// not active anymore, but not disconnected
-	Com_Printf ("\nChanging map...\n");
-}
-
-
-/*
-=================
-CL_Reconnect_f
-
-The server is changing levels
-=================
-*/
-void CL_Reconnect_f (void)
-{
-	//ZOID
-	//if we are downloading, we don't change!  This so we don't suddenly stop downloading a map
-	if (cls.download)
-		return;
-
-	S_StopAllSounds ();
-	if (cls.state == ca_connected) {
-		Com_Printf ("reconnecting...\n");
-		cls.state = ca_connected;
-		MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
-		MSG_WriteString (&cls.netchan.message, "new");		
-		return;
-	}
-
-	if (*cls.servername) {
-		if (cls.state >= ca_connected) {
-			CL_Disconnect();
-			cls.connect_time = cls.realtime - 1500;
-		} else
-			cls.connect_time = -99999; // fire immediately
-
-		cls.state = ca_connecting;
-		Com_Printf ("reconnecting...\n");
-	}
-}
-
-/*
-=================
-CL_ParseStatusMessage
-
-Handle a reply from a ping
-=================
-*/
-void CL_ParseStatusMessage (void)
-{
-	char	*s;
-
-	s = MSG_ReadString(&net_message);
-
-	Com_Printf ("%s\n", s);
-	M_AddToServerList (net_from, s);
-}
-
-
-/*
-=================
-CL_PingServers_f
-=================
-*/
-void CL_PingServers_f (void)
-{
-	int			i;
-	netadr_t	adr;
-	char		name[32];
-	char		*adrstring;
-	cvar_t		*noudp;
-	cvar_t		*noipx;
-
-	NET_Config (true);		// allow remote
-
-	// send a broadcast packet
-	Com_Printf ("pinging broadcast...\n");
-
-	noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
-	if (!noudp->value)
-	{
-		adr.type = NA_BROADCAST;
-		adr.port = BigShort(PORT_SERVER);
-		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
-	}
-
-	noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
-	if (!noipx->value)
-	{
-		adr.type = NA_BROADCAST_IPX;
-		adr.port = BigShort(PORT_SERVER);
-		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
-	}
-
-	// send a packet to each address book entry
-	for (i=0 ; i<16 ; i++)
-	{
-		Com_sprintf (name, sizeof(name), "adr%i", i);
-		adrstring = Cvar_VariableString (name);
-		if (!adrstring || !adrstring[0])
-			continue;
-
-		Com_Printf ("pinging %s...\n", adrstring);
-		if (!NET_StringToAdr (adrstring, &adr))
-		{
-			Com_Printf ("Bad address: %s\n", adrstring);
-			continue;
-		}
-		if (!adr.port)
-			adr.port = BigShort(PORT_SERVER);
-		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
-	}
-}
-
-
-/*
-=================
-CL_Skins_f
-
-Load or download any custom player skins and models
-=================
-*/
-void CL_Skins_f (void)
-{
-	int		i;
-
-	for (i=0 ; i<MAX_CLIENTS ; i++)
-	{
-		if (!cl.configstrings[CS_PLAYERSKINS+i][0])
-			continue;
-		Com_Printf ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]); 
-		SCR_UpdateScreen ();
-		Sys_SendKeyEvents ();	// pump message loop
-		CL_ParseClientinfo (i);
-	}
-}
-
-
-/*
-=================
-CL_ConnectionlessPacket
-
-Responses to broadcasts, etc
-=================
-*/
-void CL_ConnectionlessPacket (void)
-{
-	char	*s;
-	char	*c;
-	
-	MSG_BeginReading (&net_message);
-	MSG_ReadLong (&net_message);	// skip the -1
-
-	s = MSG_ReadStringLine (&net_message);
-
-	Cmd_TokenizeString (s, false);
-
-	c = Cmd_Argv(0);
-
-	Com_Printf ("%s: %s\n", NET_AdrToString (net_from), c);
-
-	// server connection
-	if (!strcmp(c, "client_connect"))
-	{
-		if (cls.state == ca_connected)
-		{
-			Com_Printf ("Dup connect received.  Ignored.\n");
-			return;
-		}
-		Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
-		MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
-		MSG_WriteString (&cls.netchan.message, "new");	
-		cls.state = ca_connected;
-		return;
-	}
-
-	// server responding to a status broadcast
-	if (!strcmp(c, "info"))
-	{
-		CL_ParseStatusMessage ();
-		return;
-	}
-
-	// remote command from gui front end
-	if (!strcmp(c, "cmd"))
-	{
-		if (!NET_IsLocalAddress(net_from))
-		{
-			Com_Printf ("Command packet from remote host.  Ignored.\n");
-			return;
-		}
-		Sys_AppActivate ();
-		s = MSG_ReadString (&net_message);
-		Cbuf_AddText (s);
-		Cbuf_AddText ("\n");
-		return;
-	}
-	// print command from somewhere
-	if (!strcmp(c, "print"))
-	{
-		s = MSG_ReadString (&net_message);
-		Com_Printf ("%s", s);
-		return;
-	}
-
-	// ping from somewhere
-	if (!strcmp(c, "ping"))
-	{
-		Netchan_OutOfBandPrint (NS_CLIENT, net_from, "ack");
-		return;
-	}
-
-	// challenge from the server we are connecting to
-	if (!strcmp(c, "challenge"))
-	{
-		cls.challenge = atoi(Cmd_Argv(1));
-		CL_SendConnectPacket ();
-		return;
-	}
-
-	// echo request from server
-	if (!strcmp(c, "echo"))
-	{
-		Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
-		return;
-	}
-
-	Com_Printf ("Unknown command.\n");
-}
-
-
-/*
-=================
-CL_DumpPackets
-
-A vain attempt to help bad TCP stacks that cause problems
-when they overflow
-=================
-*/
-void CL_DumpPackets (void)
-{
-	while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
-	{
-		Com_Printf ("dumnping a packet\n");
-	}
-}
-
-/*
-=================
-CL_ReadPackets
-=================
-*/
-void CL_ReadPackets (void)
-{
-	while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
-	{
-//	Com_Printf ("packet\n");
-		//
-		// remote command packet
-		//
-		if (*(int *)net_message.data == -1)
-		{
-			CL_ConnectionlessPacket ();
-			continue;
-		}
-
-		if (cls.state == ca_disconnected || cls.state == ca_connecting)
-			continue;		// dump it if not connected
-
-		if (net_message.cursize < 8)
-		{
-			Com_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
-			continue;
-		}
-
-		//
-		// packet from server
-		//
-		if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
-		{
-			Com_DPrintf ("%s:sequenced packet without connection\n"
-				,NET_AdrToString(net_from));
-			continue;
-		}
-		if (!Netchan_Process(&cls.netchan, &net_message))
-			continue;		// wasn't accepted for some reason
-		CL_ParseServerMessage ();
-	}
-
-	//
-	// check timeout
-	//
-	if (cls.state >= ca_connected
-	 && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000)
-	{
-		if (++cl.timeoutcount > 5)	// timeoutcount saves debugger
-		{
-			Com_Printf ("\nServer connection timed out.\n");
-			CL_Disconnect ();
-			return;
-		}
-	}
-	else
-		cl.timeoutcount = 0;
-	
-}
-
-
-//=============================================================================
-
-/*
-==============
-CL_FixUpGender_f
-==============
-*/
-void CL_FixUpGender(void)
-{
-	char *p;
-	char sk[80];
-
-	if (gender_auto->value) {
-
-		if (gender->modified) {
-			// was set directly, don't override the user
-			gender->modified = false;
-			return;
-		}
-
-		strncpy(sk, skin->string, sizeof(sk) - 1);
-		if ((p = strchr(sk, '/')) != NULL)
-			*p = 0;
-		if (cistrcmp(sk, "male") == 0 || cistrcmp(sk, "cyborg") == 0)
-			Cvar_Set ("gender", "male");
-		else if (cistrcmp(sk, "female") == 0 || cistrcmp(sk, "crackhor") == 0)
-			Cvar_Set ("gender", "female");
-		else
-			Cvar_Set ("gender", "none");
-		gender->modified = false;
-	}
-}
-
-/*
-==============
-CL_Userinfo_f
-==============
-*/
-void CL_Userinfo_f (void)
-{
-	Com_Printf ("User info settings:\n");
-	Info_Print (Cvar_Userinfo());
-}
-
-/*
-=================
-CL_Snd_Restart_f
-
-Restart the sound subsystem so it can pick up
-new parameters and flush all sounds
-=================
-*/
-void CL_Snd_Restart_f (void)
-{
-	S_Shutdown ();
-	S_Init ();
-	CL_RegisterSounds ();
-}
-
-int precache_check; // for autodownload of precache items
-int precache_spawncount;
-int precache_tex;
-int precache_model_skin;
-
-byte *precache_model; // used for skin checking in alias models
-
-#define PLAYER_MULT 5
-
-// ENV_CNT is map load, ENV_CNT+1 is first env map
-#define ENV_CNT (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
-#define TEXTURE_CNT (ENV_CNT+13)
-
-static const char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
-
-void CL_RequestNextDownload (void)
-{
-	unsigned	map_checksum;		// for detecting cheater maps
-	char fn[MAX_OSPATH];
-	dmdl_t *pheader;
-
-	if (cls.state != ca_connected)
-		return;
-
-	if (!allow_download->value && precache_check < ENV_CNT)
-		precache_check = ENV_CNT;
-
-//ZOID
-	if (precache_check == CS_MODELS) { // confirm map
-		precache_check = CS_MODELS+2; // 0 isn't used
-		if (allow_download_maps->value)
-			if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
-				return; // started a download
-	}
-	if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS) {
-		if (allow_download_models->value) {
-			while (precache_check < CS_MODELS+MAX_MODELS &&
-				cl.configstrings[precache_check][0]) {
-				if (cl.configstrings[precache_check][0] == '*' ||
-					cl.configstrings[precache_check][0] == '#') {
-					precache_check++;
-					continue;
-				}
-				if (precache_model_skin == 0) {
-					if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
-						precache_model_skin = 1;
-						return; // started a download
-					}
-					precache_model_skin = 1;
-				}
-
-				// checking for skins in the model
-				if (!precache_model) {
-
-					FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model);
-					if (!precache_model) {
-						precache_model_skin = 0;
-						precache_check++;
-						continue; // couldn't load it
-					}
-					if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER) {
-						// not an alias model
-						FS_FreeFile(precache_model);
-						precache_model = 0;
-						precache_model_skin = 0;
-						precache_check++;
-						continue;
-					}
-					pheader = (dmdl_t *)precache_model;
-					if (LittleLong (pheader->version) != ALIAS_VERSION) {
-						precache_check++;
-						precache_model_skin = 0;
-						continue; // couldn't load it
-					}
-				}
-
-				pheader = (dmdl_t *)precache_model;
-
-				while (precache_model_skin - 1 < LittleLong(pheader->num_skins)) {
-					if (!CL_CheckOrDownloadFile((char *)precache_model +
-						LittleLong(pheader->ofs_skins) + 
-						(precache_model_skin - 1)*MAX_SKINNAME)) {
-						precache_model_skin++;
-						return; // started a download
-					}
-					precache_model_skin++;
-				}
-				if (precache_model) { 
-					FS_FreeFile(precache_model);
-					precache_model = 0;
-				}
-				precache_model_skin = 0;
-				precache_check++;
-			}
-		}
-		precache_check = CS_SOUNDS;
-	}
-	if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS) { 
-		if (allow_download_sounds->value) {
-			if (precache_check == CS_SOUNDS)
-				precache_check++; // zero is blank
-			while (precache_check < CS_SOUNDS+MAX_SOUNDS &&
-				cl.configstrings[precache_check][0]) {
-				if (cl.configstrings[precache_check][0] == '*') {
-					precache_check++;
-					continue;
-				}
-				Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]);
-				if (!CL_CheckOrDownloadFile(fn))
-					return; // started a download
-			}
-		}
-		precache_check = CS_IMAGES;
-	}
-	if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES) {
-		if (precache_check == CS_IMAGES)
-			precache_check++; // zero is blank
-		while (precache_check < CS_IMAGES+MAX_IMAGES &&
-			cl.configstrings[precache_check][0]) {
-			Com_sprintf(fn, sizeof(fn), "pics/%s.pcx", cl.configstrings[precache_check++]);
-			if (!CL_CheckOrDownloadFile(fn))
-				return; // started a download
-		}
-		precache_check = CS_PLAYERSKINS;
-	}
-	// skins are special, since a player has three things to download:
-	// model, weapon model and skin
-	// so precache_check is now *3
-	if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
-		if (allow_download_players->value) {
-			while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
-				int i, n;
-				char model[MAX_QPATH], skin[MAX_QPATH], *p;
-
-				i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
-				n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
-
-				if (!cl.configstrings[CS_PLAYERSKINS+i][0]) {
-					precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
-					continue;
-				}
-
-				if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
-					p++;
-				else
-					p = cl.configstrings[CS_PLAYERSKINS+i];
-				strcpy(model, p);
-				p = strchr(model, '/');
-				if (!p)
-					p = strchr(model, '\\');
-				if (p) {
-					*p++ = 0;
-					strcpy(skin, p);
-				} else
-					*skin = 0;
-
-				switch (n) {
-				case 0: // model
-					Com_sprintf(fn, sizeof(fn), "players/%s/tris.md2", model);
-					if (!CL_CheckOrDownloadFile(fn)) {
-						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
-						return; // started a download
-					}
-					/*FALL THROUGH*/
-
-				case 1: // weapon model
-					Com_sprintf(fn, sizeof(fn), "players/%s/weapon.md2", model);
-					if (!CL_CheckOrDownloadFile(fn)) {
-						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
-						return; // started a download
-					}
-					/*FALL THROUGH*/
-
-				case 2: // weapon skin
-					Com_sprintf(fn, sizeof(fn), "players/%s/weapon.pcx", model);
-					if (!CL_CheckOrDownloadFile(fn)) {
-						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
-						return; // started a download
-					}
-					/*FALL THROUGH*/
-
-				case 3: // skin
-					Com_sprintf(fn, sizeof(fn), "players/%s/%s.pcx", model, skin);
-					if (!CL_CheckOrDownloadFile(fn)) {
-						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
-						return; // started a download
-					}
-					/*FALL THROUGH*/
-
-				case 4: // skin_i
-					Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.pcx", model, skin);
-					if (!CL_CheckOrDownloadFile(fn)) {
-						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
-						return; // started a download
-					}
-					// move on to next model
-					precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
-				}
-			}
-		}
-		// precache phase completed
-		precache_check = ENV_CNT;
-	}
-
-	if (precache_check == ENV_CNT) {
-		precache_check = ENV_CNT + 1;
-
-		CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
-
-		if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM])) {
-			Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n",
-				map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
-			return;
-		}
-	}
-
-	if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) {
-		if (allow_download->value && allow_download_maps->value) {
-			while (precache_check < TEXTURE_CNT) {
-				int n = precache_check++ - ENV_CNT - 1;
-
-				if (n & 1)
-					Com_sprintf(fn, sizeof(fn), "env/%s%s.pcx", 
-						cl.configstrings[CS_SKY], env_suf[n/2]);
-				else
-					Com_sprintf(fn, sizeof(fn), "env/%s%s.tga", 
-						cl.configstrings[CS_SKY], env_suf[n/2]);
-				if (!CL_CheckOrDownloadFile(fn))
-					return; // started a download
-			}
-		}
-		precache_check = TEXTURE_CNT;
-	}
-
-	if (precache_check == TEXTURE_CNT) {
-		precache_check = TEXTURE_CNT+1;
-		precache_tex = 0;
-	}
-
-	// confirm existance of textures, download any that don't exist
-	if (precache_check == TEXTURE_CNT+1) {
-		// from qcommon/cmodel.c
-		extern int			numtexinfo;
-		extern mapsurface_t	map_surfaces[];
-
-		if (allow_download->value && allow_download_maps->value) {
-			while (precache_tex < numtexinfo) {
-				char fn[MAX_OSPATH];
-
-				sprintf(fn, "textures/%s.wal", map_surfaces[precache_tex++].rname);
-				if (!CL_CheckOrDownloadFile(fn))
-					return; // started a download
-			}
-		}
-		precache_check = TEXTURE_CNT+999;
-	}
-
-//ZOID
-	CL_RegisterSounds ();
-	CL_PrepRefresh ();
-
-	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
-	MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) );
-}
-
-/*
-=================
-CL_Precache_f
-
-The server will send this command right
-before allowing the client into the server
-=================
-*/
-void CL_Precache_f (void)
-{
-	//Yet another hack to let old demos work
-	//the old precache sequence
-	if (Cmd_Argc() < 2) {
-		unsigned	map_checksum;		// for detecting cheater maps
-
-		CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
-		CL_RegisterSounds ();
-		CL_PrepRefresh ();
-		return;
-	}
-
-	precache_check = CS_MODELS;
-	precache_spawncount = atoi(Cmd_Argv(1));
-	precache_model = 0;
-	precache_model_skin = 0;
-
-	CL_RequestNextDownload();
-}
-
-
-/*
-=================
-CL_InitLocal
-=================
-*/
-void CL_InitLocal (void)
-{
-	cls.state = ca_disconnected;
-	cls.realtime = Sys_Milliseconds ();
-
-	CL_InitInput ();
-
-	adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE );
-	adr1 = Cvar_Get( "adr1", "", CVAR_ARCHIVE );
-	adr2 = Cvar_Get( "adr2", "", CVAR_ARCHIVE );
-	adr3 = Cvar_Get( "adr3", "", CVAR_ARCHIVE );
-	adr4 = Cvar_Get( "adr4", "", CVAR_ARCHIVE );
-	adr5 = Cvar_Get( "adr5", "", CVAR_ARCHIVE );
-	adr6 = Cvar_Get( "adr6", "", CVAR_ARCHIVE );
-	adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE );
-	adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE );
-
-//
-// register our variables
-//
-	cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE );
-	cl_stereo = Cvar_Get( "cl_stereo", "0", 0 );
-
-	cl_add_blend = Cvar_Get ("cl_blend", "1", 0);
-	cl_add_lights = Cvar_Get ("cl_lights", "1", 0);
-	cl_add_particles = Cvar_Get ("cl_particles", "1", 0);
-	cl_add_entities = Cvar_Get ("cl_entities", "1", 0);
-	cl_gun = Cvar_Get ("cl_gun", "1", 0);
-	cl_footsteps = Cvar_Get ("cl_footsteps", "1", 0);
-	cl_noskins = Cvar_Get ("cl_noskins", "0", 0);
-	cl_autoskins = Cvar_Get ("cl_autoskins", "0", 0);
-	cl_predict = Cvar_Get ("cl_predict", "1", 0);
-//	cl_minfps = Cvar_Get ("cl_minfps", "5", 0);
-	cl_maxfps = Cvar_Get ("cl_maxfps", "90", 0);
-
-	cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0);
-	cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0);
-	cl_sidespeed = Cvar_Get ("cl_sidespeed", "200", 0);
-	cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0);
-	cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0);
-	cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
-
-	cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE);
-
-	cl_shownet = Cvar_Get ("cl_shownet", "0", 0);
-	cl_showmiss = Cvar_Get ("cl_showmiss", "0", 0);
-	cl_showclamp = Cvar_Get ("showclamp", "0", 0);
-	cl_timeout = Cvar_Get ("cl_timeout", "120", 0);
-	cl_paused = Cvar_Get ("paused", "0", 0);
-	cl_timedemo = Cvar_Get ("timedemo", "0", 0);
-
-	rcon_client_password = Cvar_Get ("rcon_password", "", 0);
-	rcon_address = Cvar_Get ("rcon_address", "", 0);
-
-	cl_lightlevel = Cvar_Get ("r_lightlevel", "0", 0);
-
-	//
-	// userinfo
-	//
-	info_password = Cvar_Get ("password", "", CVAR_USERINFO);
-	info_spectator = Cvar_Get ("spectator", "0", CVAR_USERINFO);
-	name = Cvar_Get ("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE);
-	skin = Cvar_Get ("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
-	rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE);	// FIXME
-	msg = Cvar_Get ("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
-	hand = Cvar_Get ("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
-	fov = Cvar_Get ("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE);
-	gender = Cvar_Get ("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
-	gender_auto = Cvar_Get ("gender_auto", "1", CVAR_ARCHIVE);
-	gender->modified = false; // clear this so we know when user sets it manually
-
-	cl_vwep = Cvar_Get ("cl_vwep", "1", CVAR_ARCHIVE);
-
-
-	//
-	// register our commands
-	//
-	Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
-	Cmd_AddCommand ("pause", CL_Pause_f);
-	Cmd_AddCommand ("pingservers", CL_PingServers_f);
-	Cmd_AddCommand ("skins", CL_Skins_f);
-
-	Cmd_AddCommand ("userinfo", CL_Userinfo_f);
-	Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
-
-	Cmd_AddCommand ("changing", CL_Changing_f);
-	Cmd_AddCommand ("disconnect", CL_Disconnect_f);
-	Cmd_AddCommand ("record", CL_Record_f);
-	Cmd_AddCommand ("stop", CL_Stop_f);
-
-	Cmd_AddCommand ("quit", CL_Quit_f);
-
-	Cmd_AddCommand ("connect", CL_Connect_f);
-	Cmd_AddCommand ("reconnect", CL_Reconnect_f);
-
-	Cmd_AddCommand ("rcon", CL_Rcon_f);
-
-// 	Cmd_AddCommand ("packet", CL_Packet_f); // this is dangerous to leave in
-
-	Cmd_AddCommand ("setenv", CL_Setenv_f );
-
-	Cmd_AddCommand ("precache", CL_Precache_f);
-
-	Cmd_AddCommand ("download", CL_Download_f);
-
-	//
-	// forward to server commands
-	//
-	// the only thing this does is allow command completion
-	// to work -- all unknown commands are automatically
-	// forwarded to the server
-	Cmd_AddCommand ("wave", NULL);
-	Cmd_AddCommand ("inven", NULL);
-	Cmd_AddCommand ("kill", NULL);
-	Cmd_AddCommand ("use", NULL);
-	Cmd_AddCommand ("drop", NULL);
-	Cmd_AddCommand ("say", NULL);
-	Cmd_AddCommand ("say_team", NULL);
-	Cmd_AddCommand ("info", NULL);
-	Cmd_AddCommand ("prog", NULL);
-	Cmd_AddCommand ("give", NULL);
-	Cmd_AddCommand ("god", NULL);
-	Cmd_AddCommand ("notarget", NULL);
-	Cmd_AddCommand ("noclip", NULL);
-	Cmd_AddCommand ("invuse", NULL);
-	Cmd_AddCommand ("invprev", NULL);
-	Cmd_AddCommand ("invnext", NULL);
-	Cmd_AddCommand ("invdrop", NULL);
-	Cmd_AddCommand ("weapnext", NULL);
-	Cmd_AddCommand ("weapprev", NULL);
-}
-
-
-
-/*
-===============
-CL_WriteConfiguration
-
-Writes key bindings and archived cvars to config.cfg
-===============
-*/
-void CL_WriteConfiguration (void)
-{
-	FILE	*f;
-	char	path[MAX_QPATH];
-
-	if (cls.state == ca_uninitialized)
-		return;
-
-	Com_sprintf (path, sizeof(path),"%s/config.cfg",FS_Gamedir());
-	f = fopen (path, "w");
-	if (!f)
-	{
-		Com_Printf ("Couldn't write config.cfg.\n");
-		return;
-	}
-
-	fprintf (f, "// generated by quake, do not modify\n");
-	Key_WriteBindings (f);
-	fclose (f);
-
-	Cvar_WriteVariables (path);
-}
-
-
-/*
-==================
-CL_FixCvarCheats
-
-==================
-*/
-
-typedef struct
-{
-	char	*name;
-	char	*value;
-	cvar_t	*var;
-} cheatvar_t;
-
-cheatvar_t	cheatvars[] = {
-	{"timescale", "1"},
-	{"timedemo", "0"},
-	{"r_drawworld", "1"},
-	{"cl_testlights", "0"},
-	{"r_fullbright", "0"},
-	{"r_drawflat", "0"},
-	{"paused", "0"},
-	{"fixedtime", "0"},
-	{"sw_draworder", "0"},
-	{"gl_lightmap", "0"},
-	{"gl_saturatelighting", "0"},
-	{NULL, NULL}
-};
-
-int		numcheatvars;
-
-void CL_FixCvarCheats (void)
-{
-	int			i;
-	cheatvar_t	*var;
-
-	if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1") 
-		|| !cl.configstrings[CS_MAXCLIENTS][0] )
-		return;		// single player can cheat
-
-	// find all the cvars if we haven't done it yet
-	if (!numcheatvars)
-	{
-		while (cheatvars[numcheatvars].name)
-		{
-			cheatvars[numcheatvars].var = Cvar_Get (cheatvars[numcheatvars].name,
-					cheatvars[numcheatvars].value, 0);
-			numcheatvars++;
-		}
-	}
-
-	// make sure they are all set to the proper values
-	for (i=0, var = cheatvars ; i<numcheatvars ; i++, var++)
-	{
-		if ( strcmp (var->var->string, var->value) )
-		{
-			Cvar_Set (var->name, var->value);
-		}
-	}
-}
-
-//============================================================================
-
-/*
-==================
-CL_SendCommand
-
-==================
-*/
-void CL_SendCommand (void)
-{
-	// get new key events
-	Sys_SendKeyEvents ();
-
-	// allow mice or other external controllers to add commands
-	IN_Commands ();
-
-	// process console commands
-	Cbuf_Execute ();
-
-	// fix any cheating cvars
-	CL_FixCvarCheats ();
-
-	// send intentions now
-	CL_SendCmd ();
-
-	// resend a connection request if necessary
-	CL_CheckForResend ();
-}
-
-
-/*
-==================
-CL_Frame
-
-==================
-*/
-void CL_Frame (int msec)
-{
-	static int	extratime;
-	static int  lasttimecalled;
-
-	if (dedicated->value)
-		return;
-
-	extratime += msec;
-
-	if (!cl_timedemo->value)
-	{
-		if (cls.state == ca_connected && extratime < 100)
-			return;			// don't flood packets out while connecting
-		if (extratime < 1000/cl_maxfps->value)
-			return;			// framerate is too high
-	}
-
-	// let the mouse activate or deactivate
-	IN_Frame ();
-
-	// decide the simulation time
-	cls.frametime = extratime/1000.0;
-	cl.time += extratime;
-	cls.realtime = curtime;
-
-	extratime = 0;
-/*
-	if (cls.frametime > (1.0 / cl_minfps->value))
-		cls.frametime = (1.0 / cl_minfps->value);
-*/
-	if (cls.frametime > (1.0 / 5))
-		cls.frametime = (1.0 / 5);
-
-	// if in the debugger last frame, don't timeout
-	if (msec > 5000)
-		cls.netchan.last_received = Sys_Milliseconds ();
-
-	// fetch results from server
-	CL_ReadPackets ();
-
-	// send a new command message to the server
-	CL_SendCommand ();
-
-	// predict all unacknowledged movements
-	CL_PredictMovement ();
-
-	// allow rendering DLL change
-	VID_CheckChanges ();
-	if (!cl.refresh_prepped && cls.state == ca_active)
-		CL_PrepRefresh ();
-
-	// update the screen
-	if (host_speeds->value)
-		time_before_ref = Sys_Milliseconds ();
-	SCR_UpdateScreen ();
-	if (host_speeds->value)
-		time_after_ref = Sys_Milliseconds ();
-
-	// update audio
-	S_Update (cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up);
-	
-	CDAudio_Update();
-
-	// advance local effects for next frame
-	CL_RunDLights ();
-	CL_RunLightStyles ();
-	SCR_RunCinematic ();
-	SCR_RunConsole ();
-
-	cls.framecount++;
-
-	if ( log_stats->value )
-	{
-		if ( cls.state == ca_active )
-		{
-			if ( !lasttimecalled )
-			{
-				lasttimecalled = Sys_Milliseconds();
-				if ( log_stats_file )
-					fprintf( log_stats_file, "0\n" );
-			}
-			else
-			{
-				int now = Sys_Milliseconds();
-
-				if ( log_stats_file )
-					fprintf( log_stats_file, "%d\n", now - lasttimecalled );
-				lasttimecalled = now;
-			}
-		}
-	}
-}
-
-
-//============================================================================
-
-/*
-====================
-CL_Init
-====================
-*/
-void CL_Init (void)
-{
-	IN_Init();
-
-	if(dedicated->value)
-		return;		// nothing running on the client
-
-	// all archived variables will now be loaded
-
-	Con_Init ();
-	S_Init ();	
-	VID_Init ();
-	
-	V_Init ();
-	
-	net_message.data = net_message_buffer;
-	net_message.maxsize = sizeof(net_message_buffer);
-
-	M_Init ();	
-	
-	SCR_Init ();
-	cls.disable_screen = true;	// don't draw yet
-
-	CDAudio_Init ();
-	CL_InitLocal ();
-
-//	Cbuf_AddText ("exec autoexec.cfg\n");
-	FS_ExecAutoexec ();
-	Cbuf_Execute ();
-}
-
-
-/*
-===============
-CL_Shutdown
-
-FIXME: this is a callback from Sys_Quit and Com_Error.  It would be better
-to run quit through here before the final handoff to the sys code.
-===============
-*/
-void CL_Shutdown(void)
-{
-	static qboolean isdown = false;
-	
-	if (isdown)
-	{
-		printf ("recursive shutdown\n");
-		return;
-	}
-	isdown = true;
-
-	CL_WriteConfiguration (); 
-
-	CDAudio_Shutdown ();
-	S_Shutdown();
-	IN_Shutdown ();
-	VID_Shutdown();
-}
-
-
--- a/client/cl_newfx.c
+++ /dev/null
@@ -1,1306 +1,0 @@
-// cl_newfx.c -- MORE entity effects parsing and management
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-extern cparticle_t	*active_particles, *free_particles;
-extern cparticle_t	particles[MAX_PARTICLES];
-extern int			cl_numparticles;
-
-extern void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up);
-
-
-/*
-======
-vectoangles2 - this is duplicated in the game DLL, but I need it here.
-======
-*/
-void vectoangles2 (vec3_t value1, vec3_t angles)
-{
-	float	forward;
-	float	yaw, pitch;
-	
-	if (value1[1] == 0 && value1[0] == 0)
-	{
-		yaw = 0;
-		if (value1[2] > 0)
-			pitch = 90;
-		else
-			pitch = 270;
-	}
-	else
-	{
-	// PMM - fixed to correct for pitch of 0
-		if (value1[0])
-			yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
-		else if (value1[1] > 0)
-			yaw = 90;
-		else
-			yaw = 270;
-
-		if (yaw < 0)
-			yaw += 360;
-
-		forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
-		pitch = (atan2(value1[2], forward) * 180 / M_PI);
-		if (pitch < 0)
-			pitch += 360;
-	}
-
-	angles[PITCH] = -pitch;
-	angles[YAW] = yaw;
-	angles[ROLL] = 0;
-}
-
-//=============
-//=============
-void CL_Flashlight (int ent, vec3_t pos)
-{
-	cdlight_t	*dl;
-
-	dl = CL_AllocDlight (ent);
-	VectorCopy (pos,  dl->origin);
-	dl->radius = 400;
-	dl->minlight = 250;
-	dl->die = cl.time + 100;
-	dl->color[0] = 1;
-	dl->color[1] = 1;
-	dl->color[2] = 1;
-}
-
-/*
-======
-CL_ColorFlash - flash of light
-======
-*/
-void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b)
-{
-	cdlight_t	*dl;
-
-	if((vidref_val == VIDREF_SOFT) && ((r < 0) || (g<0) || (b<0)))
-	{
-		intensity = -intensity;
-		r = -r;
-		g = -g;
-		b = -b;
-	}
-
-	dl = CL_AllocDlight (ent);
-	VectorCopy (pos,  dl->origin);
-	dl->radius = intensity;
-	dl->minlight = 250;
-	dl->die = cl.time + 100;
-	dl->color[0] = r;
-	dl->color[1] = g;
-	dl->color[2] = b;
-}
-
-
-/*
-======
-CL_DebugTrail
-======
-*/
-void CL_DebugTrail (vec3_t start, vec3_t end)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-//	int			j;
-	cparticle_t	*p;
-	float		dec;
-	vec3_t		right, up;
-//	int			i;
-//	float		d, c, s;
-//	vec3_t		dir;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	MakeNormalVectors (vec, right, up);
-
-//	VectorScale(vec, RT2_SKIP, vec);
-
-//	dec = 1.0;
-//	dec = 0.75;
-	dec = 3;
-	VectorScale (vec, dec, vec);
-	VectorCopy (start, move);
-
-	while (len > 0)
-	{
-		len -= dec;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		VectorClear (p->accel);
-		VectorClear (p->vel);
-		p->alpha = 1.0;
-		p->alphavel = -0.1;
-//		p->alphavel = 0;
-		p->color = 0x74 + (rand()&7);
-		VectorCopy (move, p->org);
-/*
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j] + crand()*2;
-			p->vel[j] = crand()*3;
-			p->accel[j] = 0;
-		}
-*/
-		VectorAdd (move, vec, move);
-	}
-
-}
-
-/*
-===============
-CL_SmokeTrail
-===============
-*/
-void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	VectorScale (vec, spacing, vec);
-
-	// FIXME: this is a really silly way to have a loop
-	while (len > 0)
-	{
-		len -= spacing;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (1+qfrand()*0.5);
-		p->color = colorStart + (rand() % colorRun);
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j] + crand()*3;
-			p->accel[j] = 0;
-		}
-		p->vel[2] = 20 + crand()*5;
-
-		VectorAdd (move, vec, move);
-	}
-}
-
-void CL_ForceWall (vec3_t start, vec3_t end, int color)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	VectorScale (vec, 4, vec);
-
-	// FIXME: this is a really silly way to have a loop
-	while (len > 0)
-	{
-		len -= 4;
-
-		if (!free_particles)
-			return;
-		
-		if (qfrand() > 0.3)
-		{
-			p = free_particles;
-			free_particles = p->next;
-			p->next = active_particles;
-			active_particles = p;
-			VectorClear (p->accel);
-			
-			p->time = cl.time;
-
-			p->alpha = 1.0;
-			p->alphavel =  -1.0 / (3.0+qfrand()*0.5);
-			p->color = color;
-			for (j=0 ; j<3 ; j++)
-			{
-				p->org[j] = move[j] + crand()*3;
-				p->accel[j] = 0;
-			}
-			p->vel[0] = 0;
-			p->vel[1] = 0;
-			p->vel[2] = -40 - (crand()*10);
-		}
-
-		VectorAdd (move, vec, move);
-	}
-}
-
-void CL_FlameEffects (centity_t */*ent*/, vec3_t origin)
-{
-	int			n, count;
-	int			j;
-	cparticle_t	*p;
-
-	count = rand() & 0xF;
-
-	for(n=0;n<count;n++)
-	{
-		if (!free_particles)
-			return;
-			
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		
-		VectorClear (p->accel);
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (1+qfrand()*0.2);
-		p->color = 226 + (rand() % 4);
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = origin[j] + crand()*5;
-			p->vel[j] = crand()*5;
-		}
-		p->vel[2] = crand() * -10;
-		p->accel[2] = -PARTICLE_GRAVITY;
-	}
-
-	count = rand() & 0x7;
-
-	for(n=0;n<count;n++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (1+qfrand()*0.5);
-		p->color = 0 + (rand() % 4);
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = origin[j] + crand()*3;
-		}
-		p->vel[2] = 20 + crand()*5;
-	}
-
-}
-
-
-/*
-===============
-CL_GenericParticleEffect
-===============
-*/
-void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel)
-{
-	int			i, j;
-	cparticle_t	*p;
-	float		d;
-
-	for (i=0 ; i<count ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		if (numcolors > 1)
-			p->color = color + (rand() & numcolors);
-		else
-			p->color = color;
-
-		d = rand() & dirspread;
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
-			p->vel[j] = crand()*20;
-		}
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY;
-//		VectorCopy (accel, p->accel);
-		p->alpha = 1.0;
-
-		p->alphavel = -1.0 / (0.5 + qfrand()*alphavel);
-//		p->alphavel = alphavel;
-	}
-}
-
-/*
-===============
-CL_BubbleTrail2 (lets you control the # of bubbles by setting the distance between the spawns)
-
-===============
-*/
-void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			i, j;
-	cparticle_t	*p;
-	float		dec;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	dec = dist;
-	VectorScale (vec, dec, vec);
-
-	for (i=0 ; i<len ; i+=dec)
-	{
-		if (!free_particles)
-			return;
-
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		VectorClear (p->accel);
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (1+qfrand()*0.1);
-		p->color = 4 + (rand()&7);
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j] + crand()*2;
-			p->vel[j] = crand()*10;
-		}
-		p->org[2] -= 4;
-//		p->vel[2] += 6;
-		p->vel[2] += 20;
-
-		VectorAdd (move, vec, move);
-	}
-}
-
-//#define CORKSCREW		1
-//#define DOUBLE_SCREW	1
-#define	RINGS		1
-//#define	SPRAY		1
-
-#ifdef CORKSCREW
-void CL_Heatbeam (vec3_t start, vec3_t end)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j,k;
-	cparticle_t	*p;
-	vec3_t		right, up;
-	int			i;
-	float		d, c, s;
-	vec3_t		dir;
-	float		ltime;
-	float		step = 5.0;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-//	MakeNormalVectors (vec, right, up);
-	VectorCopy (cl.v_right, right);
-	VectorCopy (cl.v_up, up);
-	VectorMA (move, -1, right, move);
-	VectorMA (move, -1, up, move);
-
-	VectorScale (vec, step, vec);
-	ltime = (float) cl.time/1000.0;
-
-//	for (i=0 ; i<len ; i++)
-	for (i=0 ; i<len ; i+=step)
-	{
-		d = i * 0.1 - fmod(ltime,16.0)*M_PI;
-		c = cos(d)/1.75;
-		s = sin(d)/1.75;
-#ifdef DOUBLE_SCREW		
-		for (k=-1; k<2; k+=2)
-		{
-#else
-		k=1;
-#endif
-			if (!free_particles)
-				return;
-
-			p = free_particles;
-			free_particles = p->next;
-			p->next = active_particles;
-			active_particles = p;
-			
-			p->time = cl.time;
-			VectorClear (p->accel);
-
-			p->alpha = 0.5;
-	//		p->alphavel = -1.0 / (1+qfrand()*0.2);
-			// only last one frame!
-			p->alphavel = INSTANT_PARTICLE;
-	//		p->color = 0x74 + (rand()&7);
-//			p->color = 223 - (rand()&7);
-			p->color = 223;
-//			p->color = 240;
-
-			// trim it so it looks like it's starting at the origin
-			if (i < 10)
-			{
-				VectorScale (right, c*(i/10.0)*k, dir);
-				VectorMA (dir, s*(i/10.0)*k, up, dir);
-			}
-			else
-			{
-				VectorScale (right, c*k, dir);
-				VectorMA (dir, s*k, up, dir);
-			}
-			
-			for (j=0 ; j<3 ; j++)
-			{
-				p->org[j] = move[j] + dir[j]*3;
-	//			p->vel[j] = dir[j]*6;
-				p->vel[j] = 0;
-			}
-#ifdef DOUBLE_SCREW
-		}
-#endif
-		VectorAdd (move, vec, move);
-	}
-}
-#endif
-#ifdef RINGS
-//void CL_Heatbeam (vec3_t start, vec3_t end)
-void CL_Heatbeam (vec3_t start, vec3_t forward)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-	vec3_t		right, up;
-	int			i;
-	float		c, s;
-	vec3_t		dir;
-	float		ltime;
-	float		step = 32.0, rstep;
-	float		start_pt;
-	float		rot;
-	float		variance;
-	vec3_t		end;
-
-	VectorMA (start, 4096, forward, end);
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	// FIXME - pmm - these might end up using old values?
-//	MakeNormalVectors (vec, right, up);
-	VectorCopy (cl.v_right, right);
-	VectorCopy (cl.v_up, up);
-	if (vidref_val == VIDREF_GL)
-	{ // GL mode
-		VectorMA (move, -0.5, right, move);
-		VectorMA (move, -0.5, up, move);
-	}
-	// otherwise assume SOFT
-
-	ltime = (float) cl.time/1000.0;
-	start_pt = fmod(ltime*96.0,step);
-	VectorMA (move, start_pt, vec, move);
-
-	VectorScale (vec, step, vec);
-
-//	Com_Printf ("%f\n", ltime);
-	rstep = M_PI/10.0;
-	for (i=start_pt ; i<len ; i+=step)
-	{
-		if (i>step*5) // don't bother after the 5th ring
-			break;
-
-		for (rot = 0; rot < M_PI*2; rot += rstep)
-		{
-
-			if (!free_particles)
-				return;
-
-			p = free_particles;
-			free_particles = p->next;
-			p->next = active_particles;
-			active_particles = p;
-			
-			p->time = cl.time;
-			VectorClear (p->accel);
-//			rot+= fmod(ltime, 12.0)*M_PI;
-//			c = cos(rot)/2.0;
-//			s = sin(rot)/2.0;
-//			variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2;
-			variance = 0.5;
-			c = cos(rot)*variance;
-			s = sin(rot)*variance;
-			
-			// trim it so it looks like it's starting at the origin
-			if (i < 10)
-			{
-				VectorScale (right, c*(i/10.0), dir);
-				VectorMA (dir, s*(i/10.0), up, dir);
-			}
-			else
-			{
-				VectorScale (right, c, dir);
-				VectorMA (dir, s, up, dir);
-			}
-		
-			p->alpha = 0.5;
-	//		p->alphavel = -1.0 / (1+qfrand()*0.2);
-			p->alphavel = -1000.0;
-	//		p->color = 0x74 + (rand()&7);
-			p->color = 223 - (rand()&7);
-			for (j=0 ; j<3 ; j++)
-			{
-				p->org[j] = move[j] + dir[j]*3;
-	//			p->vel[j] = dir[j]*6;
-				p->vel[j] = 0;
-			}
-		}
-		VectorAdd (move, vec, move);
-	}
-}
-#endif
-#ifdef SPRAY
-void CL_Heatbeam (vec3_t start, vec3_t end)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-	vec3_t		forward, right, up;
-	int			i;
-	float		d, c, s;
-	vec3_t		dir;
-	float		ltime;
-	float		step = 32.0, rstep;
-	float		start_pt;
-	float		rot;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-//	MakeNormalVectors (vec, right, up);
-	VectorCopy (cl.v_forward, forward);
-	VectorCopy (cl.v_right, right);
-	VectorCopy (cl.v_up, up);
-	VectorMA (move, -0.5, right, move);
-	VectorMA (move, -0.5, up, move);
-
-	for (i=0; i<8; i++)
-	{
-		if (!free_particles)
-			return;
-
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		
-		p->time = cl.time;
-		VectorClear (p->accel);
-		
-		d = crand()*M_PI;
-		c = cos(d)*30;
-		s = sin(d)*30;
-
-		p->alpha = 1.0;
-		p->alphavel = -5.0 / (1+qfrand());
-		p->color = 223 - (rand()&7);
-
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j];
-		}
-		VectorScale (vec, 450, p->vel);
-		VectorMA (p->vel, c, right, p->vel);
-		VectorMA (p->vel, s, up, p->vel);
-	}
-/*
-
-	ltime = (float) cl.time/1000.0;
-	start_pt = fmod(ltime*16.0,step);
-	VectorMA (move, start_pt, vec, move);
-
-	VectorScale (vec, step, vec);
-
-//	Com_Printf ("%f\n", ltime);
-	rstep = M_PI/12.0;
-	for (i=start_pt ; i<len ; i+=step)
-	{
-		if (i>step*5) // don't bother after the 5th ring
-			break;
-
-		for (rot = 0; rot < M_PI*2; rot += rstep)
-		{
-			if (!free_particles)
-				return;
-
-			p = free_particles;
-			free_particles = p->next;
-			p->next = active_particles;
-			active_particles = p;
-			
-			p->time = cl.time;
-			VectorClear (p->accel);
-//			rot+= fmod(ltime, 12.0)*M_PI;
-//			c = cos(rot)/2.0;
-//			s = sin(rot)/2.0;
-			c = cos(rot)/1.5;
-			s = sin(rot)/1.5;
-			
-			// trim it so it looks like it's starting at the origin
-			if (i < 10)
-			{
-				VectorScale (right, c*(i/10.0), dir);
-				VectorMA (dir, s*(i/10.0), up, dir);
-			}
-			else
-			{
-				VectorScale (right, c, dir);
-				VectorMA (dir, s, up, dir);
-			}
-		
-			p->alpha = 0.5;
-	//		p->alphavel = -1.0 / (1+qfrand()*0.2);
-			p->alphavel = -1000.0;
-	//		p->color = 0x74 + (rand()&7);
-			p->color = 223 - (rand()&7);
-			for (j=0 ; j<3 ; j++)
-			{
-				p->org[j] = move[j] + dir[j]*3;
-	//			p->vel[j] = dir[j]*6;
-				p->vel[j] = 0;
-			}
-		}
-		VectorAdd (move, vec, move);
-	}
-*/
-}
-#endif
-
-/*
-===============
-CL_ParticleSteamEffect
-
-Puffs with velocity along direction, with some randomness thrown in
-===============
-*/
-void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
-{
-	int			i, j;
-	cparticle_t	*p;
-	float		d;
-	vec3_t		r, u;
-
-//	vectoangles2 (dir, angle_dir);
-//	AngleVectors (angle_dir, f, r, u);
-
-	MakeNormalVectors (dir, r, u);
-
-	for (i=0 ; i<count ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = color + (rand()&7);
-
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = org[j] + magnitude*0.1*crand();
-//			p->vel[j] = dir[j]*magnitude;
-		}
-		VectorScale (dir, magnitude, p->vel);
-		d = crand()*magnitude/3;
-		VectorMA (p->vel, d, r, p->vel);
-		d = crand()*magnitude/3;
-		VectorMA (p->vel, d, u, p->vel);
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY/2;
-		p->alpha = 1.0;
-
-		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
-	}
-}
-
-void CL_ParticleSteamEffect2 (cl_sustain_t *self)
-//vec3_t org, vec3_t dir, int color, int count, int magnitude)
-{
-	int			i, j;
-	cparticle_t	*p;
-	float		d;
-	vec3_t		r, u;
-	vec3_t		dir;
-
-//	vectoangles2 (dir, angle_dir);
-//	AngleVectors (angle_dir, f, r, u);
-
-	VectorCopy (self->dir, dir);
-	MakeNormalVectors (dir, r, u);
-
-	for (i=0 ; i<self->count ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = self->color + (rand()&7);
-
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = self->org[j] + self->magnitude*0.1*crand();
-//			p->vel[j] = dir[j]*magnitude;
-		}
-		VectorScale (dir, self->magnitude, p->vel);
-		d = crand()*self->magnitude/3;
-		VectorMA (p->vel, d, r, p->vel);
-		d = crand()*self->magnitude/3;
-		VectorMA (p->vel, d, u, p->vel);
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY/2;
-		p->alpha = 1.0;
-
-		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
-	}
-	self->nextthink += self->thinkinterval;
-}
-
-/*
-===============
-CL_TrackerTrail
-===============
-*/
-void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	vec3_t		forward,right,up,angle_dir;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-	int			dec;
-	float		dist;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	VectorCopy(vec, forward);
-	vectoangles2 (forward, angle_dir);
-	AngleVectors (angle_dir, forward, right, up);
-
-	dec = 3;
-	VectorScale (vec, 3, vec);
-
-	// FIXME: this is a really silly way to have a loop
-	while (len > 0)
-	{
-		len -= dec;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -2.0;
-		p->color = particleColor;
-		dist = DotProduct(move, forward);
-		VectorMA(move, 8 * cos(dist), up, p->org);
-		for (j=0 ; j<3 ; j++)
-		{
-//			p->org[j] = move[j] + crand();
-			p->vel[j] = 0;
-			p->accel[j] = 0;
-		}
-		p->vel[2] = 5;
-
-		VectorAdd (move, vec, move);
-	}
-}
-
-void CL_Tracker_Shell(vec3_t origin)
-{
-	vec3_t			dir;
-	int				i;
-	cparticle_t		*p;
-
-	for(i=0;i<300;i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = INSTANT_PARTICLE;
-		p->color = 0;
-
-		dir[0] = crand();
-		dir[1] = crand();
-		dir[2] = crand();
-		VectorNormalize(dir);
-	
-		VectorMA(origin, 40, dir, p->org);
-	}
-}
-
-void CL_MonsterPlasma_Shell(vec3_t origin)
-{
-	vec3_t			dir;
-	int				i;
-	cparticle_t		*p;
-
-	for(i=0;i<40;i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = INSTANT_PARTICLE;
-		p->color = 0xe0;
-
-		dir[0] = crand();
-		dir[1] = crand();
-		dir[2] = crand();
-		VectorNormalize(dir);
-	
-		VectorMA(origin, 10, dir, p->org);
-//		VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
-	}
-}
-
-void CL_Widowbeamout (cl_sustain_t *self)
-{
-	vec3_t			dir;
-	int				i;
-	cparticle_t		*p;
-	static int colortable[4] = {2*8,13*8,21*8,18*8};
-	float			ratio;
-
-	ratio = 1.0 - (((float)self->endtime - (float)cl.time)/2100.0);
-
-	for(i=0;i<300;i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = INSTANT_PARTICLE;
-		p->color = colortable[rand()&3];
-
-		dir[0] = crand();
-		dir[1] = crand();
-		dir[2] = crand();
-		VectorNormalize(dir);
-	
-		VectorMA(self->org, (45.0 * ratio), dir, p->org);
-//		VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
-	}
-}
-
-void CL_Nukeblast (cl_sustain_t *self)
-{
-	vec3_t			dir;
-	int				i;
-	cparticle_t		*p;
-	static int colortable[4] = {110, 112, 114, 116};
-	float			ratio;
-
-	ratio = 1.0 - (((float)self->endtime - (float)cl.time)/1000.0);
-
-	for(i=0;i<700;i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = INSTANT_PARTICLE;
-		p->color = colortable[rand()&3];
-
-		dir[0] = crand();
-		dir[1] = crand();
-		dir[2] = crand();
-		VectorNormalize(dir);
-	
-		VectorMA(self->org, (200.0 * ratio), dir, p->org);
-//		VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
-	}
-}
-
-void CL_WidowSplash (vec3_t org)
-{
-	static int colortable[4] = {2*8,13*8,21*8,18*8};
-	int			i;
-	cparticle_t	*p;
-	vec3_t		dir;
-
-	for (i=0 ; i<256 ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = colortable[rand()&3];
-
-		dir[0] = crand();
-		dir[1] = crand();
-		dir[2] = crand();
-		VectorNormalize(dir);
-		VectorMA(org, 45.0, dir, p->org);
-		VectorMA(vec3_origin, 40.0, dir, p->vel);
-
-		p->accel[0] = p->accel[1] = 0;
-		p->alpha = 1.0;
-
-		p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
-	}
-
-}
-
-void CL_Tracker_Explode(vec3_t	origin)
-{
-	vec3_t			dir, backdir;
-	int				i;
-	cparticle_t		*p;
-
-	for(i=0;i<300;i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0;
-		p->color = 0;
-
-		dir[0] = crand();
-		dir[1] = crand();
-		dir[2] = crand();
-		VectorNormalize(dir);
-		VectorScale(dir, -1, backdir);
-	
-		VectorMA(origin, 64, dir, p->org);
-		VectorScale(backdir, 64, p->vel);
-	}
-	
-}
-
-/*
-===============
-CL_TagTrail
-
-===============
-*/
-void CL_TagTrail (vec3_t start, vec3_t end, float color)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-	int			dec;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	dec = 5;
-	VectorScale (vec, 5, vec);
-
-	while (len >= 0)
-	{
-		len -= dec;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (0.8+qfrand()*0.2);
-		p->color = color;
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j] + crand()*16;
-			p->vel[j] = crand()*5;
-			p->accel[j] = 0;
-		}
-
-		VectorAdd (move, vec, move);
-	}
-}
-
-/*
-===============
-CL_ColorExplosionParticles
-===============
-*/
-void CL_ColorExplosionParticles (vec3_t org, int color, int run)
-{
-	int			i, j;
-	cparticle_t	*p;
-
-	for (i=0 ; i<128 ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = color + (rand() % run);
-
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = org[j] + ((rand()%32)-16);
-			p->vel[j] = (rand()%256)-128;
-		}
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY;
-		p->alpha = 1.0;
-
-		p->alphavel = -0.4 / (0.6 + qfrand()*0.2);
-	}
-}
-
-/*
-===============
-CL_ParticleSmokeEffect - like the steam effect, but unaffected by gravity
-===============
-*/
-void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
-{
-	int			i, j;
-	cparticle_t	*p;
-	float		d;
-	vec3_t		r, u;
-
-	MakeNormalVectors (dir, r, u);
-
-	for (i=0 ; i<count ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = color + (rand()&7);
-
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = org[j] + magnitude*0.1*crand();
-//			p->vel[j] = dir[j]*magnitude;
-		}
-		VectorScale (dir, magnitude, p->vel);
-		d = crand()*magnitude/3;
-		VectorMA (p->vel, d, r, p->vel);
-		d = crand()*magnitude/3;
-		VectorMA (p->vel, d, u, p->vel);
-
-		p->accel[0] = p->accel[1] = p->accel[2] = 0;
-		p->alpha = 1.0;
-
-		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
-	}
-}
-
-/*
-===============
-CL_BlasterParticles2
-
-Wall impact puffs (Green)
-===============
-*/
-void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color)
-{
-	int			i, j;
-	cparticle_t	*p;
-	float		d;
-	int			count;
-
-	count = 40;
-	for (i=0 ; i<count ; i++)
-	{
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-
-		p->time = cl.time;
-		p->color = color + (rand()&7);
-
-		d = rand()&15;
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
-			p->vel[j] = dir[j] * 30 + crand()*40;
-		}
-
-		p->accel[0] = p->accel[1] = 0;
-		p->accel[2] = -PARTICLE_GRAVITY;
-		p->alpha = 1.0;
-
-		p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
-	}
-}
-
-/*
-===============
-CL_BlasterTrail2
-
-Green!
-===============
-*/
-void CL_BlasterTrail2 (vec3_t start, vec3_t end)
-{
-	vec3_t		move;
-	vec3_t		vec;
-	float		len;
-	int			j;
-	cparticle_t	*p;
-	int			dec;
-
-	VectorCopy (start, move);
-	VectorSubtract (end, start, vec);
-	len = VectorNormalize (vec);
-
-	dec = 5;
-	VectorScale (vec, 5, vec);
-
-	// FIXME: this is a really silly way to have a loop
-	while (len > 0)
-	{
-		len -= dec;
-
-		if (!free_particles)
-			return;
-		p = free_particles;
-		free_particles = p->next;
-		p->next = active_particles;
-		active_particles = p;
-		VectorClear (p->accel);
-		
-		p->time = cl.time;
-
-		p->alpha = 1.0;
-		p->alphavel = -1.0 / (0.3+qfrand()*0.2);
-		p->color = 0xd0;
-		for (j=0 ; j<3 ; j++)
-		{
-			p->org[j] = move[j] + crand();
-			p->vel[j] = crand()*5;
-			p->accel[j] = 0;
-		}
-
-		VectorAdd (move, vec, move);
-	}
-}
--- a/client/cl_parse.c
+++ /dev/null
@@ -1,802 +1,0 @@
-// cl_parse.c  -- parse a message received from the server
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-char *svc_strings[256] =
-{
-	"svc_bad",
-
-	"svc_muzzleflash",
-	"svc_muzzlflash2",
-	"svc_temp_entity",
-	"svc_layout",
-	"svc_inventory",
-
-	"svc_nop",
-	"svc_disconnect",
-	"svc_reconnect",
-	"svc_sound",
-	"svc_print",
-	"svc_stufftext",
-	"svc_serverdata",
-	"svc_configstring",
-	"svc_spawnbaseline",	
-	"svc_centerprint",
-	"svc_download",
-	"svc_playerinfo",
-	"svc_packetentities",
-	"svc_deltapacketentities",
-	"svc_frame"
-};
-
-//=============================================================================
-
-void CL_DownloadFileName(char *dest, int destlen, char *fn)
-{
-	if (strncmp(fn, "players", 7) == 0)
-		Com_sprintf (dest, destlen, "%s/%s", BASEDIRNAME, fn);
-	else
-		Com_sprintf (dest, destlen, "%s/%s", FS_Gamedir(), fn);
-}
-
-/*
-===============
-CL_CheckOrDownloadFile
-
-Returns true if the file exists, otherwise it attempts
-to start a download from the server.
-===============
-*/
-qboolean	CL_CheckOrDownloadFile (char *filename)
-{
-	FILE *fp;
-	char	name[MAX_OSPATH];
-
-	if (strstr (filename, ".."))
-	{
-		Com_Printf ("Refusing to download a path with ..\n");
-		return true;
-	}
-
-	if (FS_LoadFile (filename, NULL) != -1)
-	{	// it exists, no need to download
-		return true;
-	}
-
-	strcpy (cls.downloadname, filename);
-
-	// download to a temp name, and only rename
-	// to the real name when done, so if interrupted
-	// a runt file wont be left
-	COM_StripExtension (cls.downloadname, cls.downloadtempname);
-	strcat (cls.downloadtempname, ".tmp");
-
-//ZOID
-	// check to see if we already have a tmp for this file, if so, try to resume
-	// open the file if not opened yet
-	CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
-
-//	FS_CreatePath (name);
-
-	fp = fopen (name, "r+b");
-	if (fp) { // it exists
-		int len;
-		fseek(fp, 0, SEEK_END);
-		len = ftell(fp);
-
-		cls.download = fp;
-
-		// give the server an offset to start the download
-		Com_Printf ("Resuming %s\n", cls.downloadname);
-		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
-		MSG_WriteString (&cls.netchan.message,
-			va("download %s %i", cls.downloadname, len));
-	} else {
-		Com_Printf ("Downloading %s\n", cls.downloadname);
-		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
-		MSG_WriteString (&cls.netchan.message,
-			va("download %s", cls.downloadname));
-	}
-
-	cls.downloadnumber++;
-
-	return false;
-}
-
-/*
-===============
-CL_Download_f
-
-Request a download from the server
-===============
-*/
-void	CL_Download_f (void)
-{
-	char filename[MAX_OSPATH];
-
-	if (Cmd_Argc() != 2) {
-		Com_Printf("Usage: download <filename>\n");
-		return;
-	}
-
-	Com_sprintf(filename, sizeof(filename), "%s", Cmd_Argv(1));
-
-	if (strstr (filename, ".."))
-	{
-		Com_Printf ("Refusing to download a path with ..\n");
-		return;
-	}
-
-	if (FS_LoadFile (filename, NULL) != -1)
-	{	// it exists, no need to download
-		Com_Printf("File already exists.\n");
-		return;
-	}
-
-	strcpy (cls.downloadname, filename);
-	Com_Printf ("Downloading %s\n", cls.downloadname);
-
-	// download to a temp name, and only rename
-	// to the real name when done, so if interrupted
-	// a runt file wont be left
-	COM_StripExtension (cls.downloadname, cls.downloadtempname);
-	strcat (cls.downloadtempname, ".tmp");
-
-	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
-	MSG_WriteString (&cls.netchan.message,
-		va("download %s", cls.downloadname));
-
-	cls.downloadnumber++;
-}
-
-/*
-======================
-CL_RegisterSounds
-======================
-*/
-void CL_RegisterSounds (void)
-{
-	int		i;
-
-	S_BeginRegistration ();
-	CL_RegisterTEntSounds ();
-	for (i=1 ; i<MAX_SOUNDS ; i++)
-	{
-		if (!cl.configstrings[CS_SOUNDS+i][0])
-			break;
-		cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
-		Sys_SendKeyEvents ();	// pump message loop
-	}
-	S_EndRegistration ();
-}
-
-static void
-rename(char *old, char *new)
-{
-	char *p;
-	Dir d;
-
-	if((p = strrchr(new, '/')) == nil)
-		p = new;
-	else
-		p++;
-	nulldir(&d);
-	d.name = p;
-	if(dirwstat(old, &d) < 0)
-		fprint(2, "rename: %r\n");
-}
-
-/*
-=====================
-CL_ParseDownload
-
-A download message has been received from the server
-=====================
-*/
-void CL_ParseDownload (void)
-{
-	int		size, percent;
-	char	name[MAX_OSPATH];
-
-	// read the data
-	size = MSG_ReadShort (&net_message);
-	percent = MSG_ReadByte (&net_message);
-	if (size == -1)
-	{
-		Com_Printf ("Server does not have this file.\n");
-		if (cls.download)
-		{
-			// if here, we tried to resume a file but the server said no
-			fclose (cls.download);
-			cls.download = NULL;
-		}
-		CL_RequestNextDownload ();
-		return;
-	}
-
-	// open the file if not opened yet
-	if (!cls.download)
-	{
-		CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
-
-		FS_CreatePath (name);
-
-		cls.download = fopen (name, "wb");
-		if (!cls.download)
-		{
-			net_message.readcount += size;
-			Com_Printf ("Failed to open %s\n", cls.downloadtempname);
-			CL_RequestNextDownload ();
-			return;
-		}
-	}
-
-	fwrite (net_message.data + net_message.readcount, 1, size, cls.download);
-	net_message.readcount += size;
-
-	if (percent != 100)
-	{
-		// request next block
-// change display routines by zoid
-/*
-		Com_Printf (".");
-		if (10*(percent/10) != cls.downloadpercent)
-		{
-			cls.downloadpercent = 10*(percent/10);
-			Com_Printf ("%i%%", cls.downloadpercent);
-		}
-*/
-		cls.downloadpercent = percent;
-
-		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
-		SZ_Print (&cls.netchan.message, "nextdl");
-	}
-	else
-	{
-		char	oldn[MAX_OSPATH];
-		char	newn[MAX_OSPATH];
-
-//		Com_Printf ("100%%\n");
-
-		fclose (cls.download);
-
-		// rename the temp file to it's final name
-		CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
-		CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
-		rename (oldn, newn);	/* FIXME */
-
-		cls.download = NULL;
-		cls.downloadpercent = 0;
-
-		// get another file if needed
-
-		CL_RequestNextDownload ();
-	}
-}
-
-
-/*
-=====================================================================
-
-  SERVER CONNECTING MESSAGES
-
-=====================================================================
-*/
-
-/*
-==================
-CL_ParseServerData
-==================
-*/
-void CL_ParseServerData (void)
-{
-	extern cvar_t	*fs_gamedirvar;
-	char	*str;
-	int		i;
-	
-	Com_DPrintf ("Serverdata packet received.\n");
-//
-// wipe the client_state_t struct
-//
-	CL_ClearState ();
-	cls.state = ca_connected;
-
-// parse protocol version number
-	i = MSG_ReadLong (&net_message);
-	cls.serverProtocol = i;
-
-	// BIG HACK to let demos from release work with the 3.0x patch!!!
-	if (Com_ServerState() && PROTOCOL_VERSION == 34)
-	{
-	}
-	else if (i != PROTOCOL_VERSION)
-		Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
-
-	cl.servercount = MSG_ReadLong (&net_message);
-	cl.attractloop = MSG_ReadByte (&net_message);
-
-	// game directory
-	str = MSG_ReadString (&net_message);
-	strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
-
-	// set gamedir
-	if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
-		Cvar_Set("game", str);
-
-	// parse player entity number
-	cl.playernum = MSG_ReadShort (&net_message);
-
-	// get the full level name
-	str = MSG_ReadString (&net_message);
-
-	if (cl.playernum == -1)
-	{	// playing a cinematic or showing a pic, not a level
-		SCR_PlayCinematic (str);
-	}
-	else
-	{
-		// seperate the printfs so the server message can have a color
-		Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
-		Com_Printf ("%c%s\n", 2, str);
-
-		// need to prep refresh at next oportunity
-		cl.refresh_prepped = false;
-	}
-}
-
-/*
-==================
-CL_ParseBaseline
-==================
-*/
-void CL_ParseBaseline (void)
-{
-	entity_state_t	*es;
-	int				bits;
-	int				newnum;
-	entity_state_t	nullstate;
-
-	memset (&nullstate, 0, sizeof(nullstate));
-
-	newnum = CL_ParseEntityBits (&bits);
-	es = &cl_entities[newnum].baseline;
-	CL_ParseDelta (&nullstate, es, newnum, bits);
-}
-
-
-/*
-================
-CL_LoadClientinfo
-
-================
-*/
-void CL_LoadClientinfo (clientinfo_t *ci, char *s)
-{
-	int i;
-	char		*t;
-	char		model_name[MAX_QPATH];
-	char		skin_name[MAX_QPATH];
-	char		model_filename[MAX_QPATH];
-	char		skin_filename[MAX_QPATH];
-	char		weapon_filename[MAX_QPATH];
-
-	strncpy(ci->cinfo, s, sizeof(ci->cinfo));
-	ci->cinfo[sizeof(ci->cinfo)-1] = 0;
-
-	// isolate the player's name
-	strncpy(ci->name, s, sizeof(ci->name));
-	ci->name[sizeof(ci->name)-1] = 0;
-	t = strstr (s, "\\");
-	if (t)
-	{
-		ci->name[t-s] = 0;
-		s = t+1;
-	}
-
-	if (cl_noskins->value || *s == 0)
-	{
-		Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
-		Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/weapon.md2");
-		Com_sprintf (skin_filename, sizeof(skin_filename), "players/male/grunt.pcx");
-		Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/male/grunt_i.pcx");
-		ci->model = re.RegisterModel (model_filename);
-		memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
-		ci->weaponmodel[0] = re.RegisterModel (weapon_filename);
-		ci->skin = re.RegisterSkin (skin_filename);
-		ci->icon = re.RegisterPic (ci->iconname);
-	}
-	else
-	{
-		// isolate the model name
-		strcpy (model_name, s);
-		t = strstr(model_name, "/");
-		if (!t)
-			t = strstr(model_name, "\\");
-		if (!t)
-			t = model_name;
-		*t = 0;
-
-		// isolate the skin name
-		strcpy (skin_name, s + strlen(model_name) + 1);
-
-		// model file
-		Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
-		ci->model = re.RegisterModel (model_filename);
-		if (!ci->model)
-		{
-			strcpy(model_name, "male");
-			Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
-			ci->model = re.RegisterModel (model_filename);
-		}
-
-		// skin file
-		Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
-		ci->skin = re.RegisterSkin (skin_filename);
-
-		// if we don't have the skin and the model wasn't male,
-		// see if the male has it (this is for CTF's skins)
- 		if (!ci->skin && cistrcmp(model_name, "male"))
-		{
-			// change model to male
-			strcpy(model_name, "male");
-			Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
-			ci->model = re.RegisterModel (model_filename);
-
-			// see if the skin exists for the male model
-			Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
-			ci->skin = re.RegisterSkin (skin_filename);
-		}
-
-		// if we still don't have a skin, it means that the male model didn't have
-		// it, so default to grunt
-		if (!ci->skin) {
-			// see if the skin exists for the male model
-			Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/grunt.pcx", model_name, skin_name);
-			ci->skin = re.RegisterSkin (skin_filename);
-		}
-
-		// weapon file
-		for (i = 0; i < num_cl_weaponmodels; i++) {
-			Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
-			ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
-			if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
-				// try male
-				Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
-				ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
-			}
-			if (!cl_vwep->value)
-				break; // only one when vwep is off
-		}
-
-		// icon file
-		Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
-		ci->icon = re.RegisterPic (ci->iconname);
-	}
-
-	// must have loaded all data types to be valud
-	if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
-	{
-		ci->skin = NULL;
-		ci->icon = NULL;
-		ci->model = NULL;
-		ci->weaponmodel[0] = NULL;
-		return;
-	}
-}
-
-/*
-================
-CL_ParseClientinfo
-
-Load the skin, icon, and model for a client
-================
-*/
-void CL_ParseClientinfo (int player)
-{
-	char			*s;
-	clientinfo_t	*ci;
-
-	s = cl.configstrings[player+CS_PLAYERSKINS];
-
-	ci = &cl.clientinfo[player];
-
-	CL_LoadClientinfo (ci, s);
-}
-
-
-/*
-================
-CL_ParseConfigString
-================
-*/
-void CL_ParseConfigString (void)
-{
-	int		i;
-	char	*s;
-
-	i = MSG_ReadShort (&net_message);
-	if (i < 0 || i >= MAX_CONFIGSTRINGS)
-		Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
-	s = MSG_ReadString(&net_message);
-	strcpy (cl.configstrings[i], s);
-
-	// do something apropriate 
-
-	if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
-		CL_SetLightstyle (i - CS_LIGHTS);
-	else if (i == CS_CDTRACK)
-	{
-		if (cl.refresh_prepped)
-			CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
-	}
-	else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS)
-	{
-		if (cl.refresh_prepped)
-		{
-			cl.model_draw[i-CS_MODELS] = re.RegisterModel (cl.configstrings[i]);
-			if (cl.configstrings[i][0] == '*')
-				cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
-			else
-				cl.model_clip[i-CS_MODELS] = NULL;
-		}
-	}
-	else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)
-	{
-		if (cl.refresh_prepped)
-			cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
-	}
-	else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS)
-	{
-		if (cl.refresh_prepped)
-			cl.image_precache[i-CS_IMAGES] = re.RegisterPic (cl.configstrings[i]);
-	}
-	else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS)
-	{
-		if (cl.refresh_prepped)
-			CL_ParseClientinfo (i-CS_PLAYERSKINS);
-	}
-}
-
-
-/*
-=====================================================================
-
-ACTION MESSAGES
-
-=====================================================================
-*/
-
-/*
-==================
-CL_ParseStartSoundPacket
-==================
-*/
-void CL_ParseStartSoundPacket(void)
-{
-    vec3_t  pos_v;
-	float	*pos;
-    int 	channel, ent;
-    int 	sound_num;
-    float 	volume;
-    float 	attenuation;  
-	int		flags;
-	float	ofs;
-
-	flags = MSG_ReadByte (&net_message);
-	sound_num = MSG_ReadByte (&net_message);
-
-    if (flags & SND_VOLUME)
-		volume = MSG_ReadByte (&net_message) / 255.0;
-	else
-		volume = DEFAULT_SOUND_PACKET_VOLUME;
-	
-    if (flags & SND_ATTENUATION)
-		attenuation = MSG_ReadByte (&net_message) / 64.0;
-	else
-		attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;	
-
-    if (flags & SND_OFFSET)
-		ofs = MSG_ReadByte (&net_message) / 1000.0;
-	else
-		ofs = 0;
-
-	if (flags & SND_ENT)
-	{	// entity reletive
-		channel = MSG_ReadShort(&net_message); 
-		ent = channel>>3;
-		if (ent > MAX_EDICTS)
-			Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
-
-		channel &= 7;
-	}
-	else
-	{
-		ent = 0;
-		channel = 0;
-	}
-
-	if (flags & SND_POS)
-	{	// positioned in space
-		MSG_ReadPos (&net_message, pos_v);
- 
-		pos = pos_v;
-	}
-	else	// use entity number
-		pos = NULL;
-
-	if (!cl.sound_precache[sound_num])
-		return;
-
-	S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
-}       
-
-
-void SHOWNET(char *s)
-{
-	if (cl_shownet->value>=2)
-		Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
-}
-
-/*
-=====================
-CL_ParseServerMessage
-=====================
-*/
-void CL_ParseServerMessage (void)
-{
-	int			cmd;
-	char		*s;
-	int			i;
-
-//
-// if recording demos, copy the message out
-//
-	if (cl_shownet->value == 1)
-		Com_Printf ("%i ",net_message.cursize);
-	else if (cl_shownet->value >= 2)
-		Com_Printf ("------------------\n");
-
-
-//
-// parse the message
-//
-	while (1)
-	{
-		if (net_message.readcount > net_message.cursize)
-		{
-			Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
-			break;
-		}
-
-		cmd = MSG_ReadByte (&net_message);
-
-		if (cmd == -1)
-		{
-			SHOWNET("END OF MESSAGE");
-			break;
-		}
-
-		if (cl_shownet->value>=2)
-		{
-			if (!svc_strings[cmd])
-				Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
-			else
-				SHOWNET(svc_strings[cmd]);
-		}
-	
-	// other commands
-		switch (cmd)
-		{
-		default:
-			Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
-			break;
-			
-		case svc_nop:
-//			Com_Printf ("svc_nop\n");
-			break;
-			
-		case svc_disconnect:
-			Com_Error (ERR_DISCONNECT,"Server disconnected\n");
-			break;
-
-		case svc_reconnect:
-			Com_Printf ("Server disconnected, reconnecting\n");
-			if (cls.download) {
-				//ZOID, close download
-				fclose (cls.download);
-				cls.download = NULL;
-			}
-			cls.state = ca_connecting;
-			cls.connect_time = -99999;	// CL_CheckForResend() will fire immediately
-			break;
-
-		case svc_print:
-			i = MSG_ReadByte (&net_message);
-			if (i == PRINT_CHAT)
-			{
-				S_StartLocalSound ("misc/talk.wav");
-				con.ormask = 128;
-			}
-			Com_Printf ("%s", MSG_ReadString (&net_message));
-			con.ormask = 0;
-			break;
-			
-		case svc_centerprint:
-			SCR_CenterPrint (MSG_ReadString (&net_message));
-			break;
-			
-		case svc_stufftext:
-			s = MSG_ReadString (&net_message);
-			Com_DPrintf ("stufftext: %s\n", s);
-			Cbuf_AddText (s);
-			break;
-			
-		case svc_serverdata:
-			Cbuf_Execute ();		// make sure any stuffed commands are done
-			CL_ParseServerData ();
-			break;
-			
-		case svc_configstring:
-			CL_ParseConfigString ();
-			break;
-			
-		case svc_sound:
-			CL_ParseStartSoundPacket();
-			break;
-			
-		case svc_spawnbaseline:
-			CL_ParseBaseline ();
-			break;
-
-		case svc_temp_entity:
-			CL_ParseTEnt ();
-			break;
-
-		case svc_muzzleflash:
-			CL_ParseMuzzleFlash ();
-			break;
-
-		case svc_muzzleflash2:
-			CL_ParseMuzzleFlash2 ();
-			break;
-
-		case svc_download:
-			CL_ParseDownload ();
-			break;
-
-		case svc_frame:
-			CL_ParseFrame ();
-			break;
-
-		case svc_inventory:
-			CL_ParseInventory ();
-			break;
-
-		case svc_layout:
-			s = MSG_ReadString (&net_message);
-			strncpy (cl.layout, s, sizeof(cl.layout)-1);
-			break;
-
-		case svc_playerinfo:
-		case svc_packetentities:
-		case svc_deltapacketentities:
-			Com_Error (ERR_DROP, "Out of place frame data");
-			break;
-		}
-	}
-
-	CL_AddNetgraph ();
-
-	//
-	// we don't know if it is ok to save a demo message until
-	// after we have parsed the frame
-	//
-	if (cls.demorecording && !cls.demowaiting)
-		CL_WriteDemoMessage ();
-
-}
-
-
--- a/client/cl_pred.c
+++ /dev/null
@@ -1,259 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-
-/*
-===================
-CL_CheckPredictionError
-===================
-*/
-void CL_CheckPredictionError (void)
-{
-	int		frame;
-	int		delta[3];
-	int		i;
-	int		len;
-
-	if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
-		return;
-
-	// calculate the last usercmd_t we sent that the server has processed
-	frame = cls.netchan.incoming_acknowledged;
-	frame &= (CMD_BACKUP-1);
-
-	// compare what the server returned with what we had predicted it to be
-	VectorSubtract (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame], delta);
-
-	// save the prediction error for interpolation
-	len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
-	if (len > 640)	// 80 world units
-	{	// a teleport or something
-		VectorClear (cl.prediction_error);
-	}
-	else
-	{
-		if (cl_showmiss->value && (delta[0] || delta[1] || delta[2]) )
-			Com_Printf ("prediction miss on %i: %i\n", cl.frame.serverframe, 
-			delta[0] + delta[1] + delta[2]);
-
-		VectorCopy (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame]);
-
-		// save for error itnerpolation
-		for (i=0 ; i<3 ; i++)
-			cl.prediction_error[i] = delta[i]*0.125;
-	}
-}
-
-
-/*
-====================
-CL_ClipMoveToEntities
-
-====================
-*/
-void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
-{
-	int			i, x, zd, zu;
-	trace_t		trace;
-	int			headnode;
-	float		*angles;
-	entity_state_t	*ent;
-	int			num;
-	cmodel_t		*cmodel;
-	vec3_t		bmins, bmaxs;
-
-	for (i=0 ; i<cl.frame.num_entities ; i++)
-	{
-		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
-		ent = &cl_parse_entities[num];
-
-		if (!ent->solid)
-			continue;
-
-		if (ent->number == cl.playernum+1)
-			continue;
-
-		if (ent->solid == 31)
-		{	// special value for bmodel
-			cmodel = cl.model_clip[ent->modelindex];
-			if (!cmodel)
-				continue;
-			headnode = cmodel->headnode;
-			angles = ent->angles;
-		}
-		else
-		{	// encoded bbox
-			x = 8*(ent->solid & 31);
-			zd = 8*((ent->solid>>5) & 31);
-			zu = 8*((ent->solid>>10) & 63) - 32;
-
-			bmins[0] = bmins[1] = -x;
-			bmaxs[0] = bmaxs[1] = x;
-			bmins[2] = -zd;
-			bmaxs[2] = zu;
-
-			headnode = CM_HeadnodeForBox (bmins, bmaxs);
-			angles = vec3_origin;	// boxes don't rotate
-		}
-
-		if (tr->allsolid)
-			return;
-
-		trace = CM_TransformedBoxTrace (start, end,
-			mins, maxs, headnode,  MASK_PLAYERSOLID,
-			ent->origin, angles);
-
-		if (trace.allsolid || trace.startsolid ||
-		trace.fraction < tr->fraction)
-		{
-			trace.ent = (edict_t *)ent;
-		 	if (tr->startsolid)
-			{
-				*tr = trace;
-				tr->startsolid = true;
-			}
-			else
-				*tr = trace;
-		}
-		else if (trace.startsolid)
-			tr->startsolid = true;
-	}
-}
-
-
-/*
-================
-CL_PMTrace
-================
-*/
-trace_t		CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
-{
-	trace_t	t;
-
-	// check against world
-	t = CM_BoxTrace (start, end, mins, maxs, 0, MASK_PLAYERSOLID);
-	if (t.fraction < 1.0)
-		t.ent = (edict_t *)1;
-
-	// check all other solid models
-	CL_ClipMoveToEntities (start, mins, maxs, end, &t);
-
-	return t;
-}
-
-int		CL_PMpointcontents (vec3_t point)
-{
-	int			i;
-	entity_state_t	*ent;
-	int			num;
-	cmodel_t		*cmodel;
-	int			contents;
-
-	contents = CM_PointContents (point, 0);
-
-	for (i=0 ; i<cl.frame.num_entities ; i++)
-	{
-		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
-		ent = &cl_parse_entities[num];
-
-		if (ent->solid != 31) // special value for bmodel
-			continue;
-
-		cmodel = cl.model_clip[ent->modelindex];
-		if (!cmodel)
-			continue;
-
-		contents |= CM_TransformedPointContents (point, cmodel->headnode, ent->origin, ent->angles);
-	}
-
-	return contents;
-}
-
-
-/*
-=================
-CL_PredictMovement
-
-Sets cl.predicted_origin and cl.predicted_angles
-=================
-*/
-void CL_PredictMovement (void)
-{
-	int			ack, current;
-	int			frame;
-	int			oldframe;
-	usercmd_t	*cmd;
-	pmove_t		pm;
-	int			i;
-	int			step;
-	int			oldz;
-
-	if (cls.state != ca_active)
-		return;
-
-	if (cl_paused->value)
-		return;
-
-	if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
-	{	// just set angles
-		for (i=0 ; i<3 ; i++)
-		{
-			cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]);
-		}
-		return;
-	}
-
-	ack = cls.netchan.incoming_acknowledged;
-	current = cls.netchan.outgoing_sequence;
-
-	// if we are too far out of date, just freeze
-	if (current - ack >= CMD_BACKUP)
-	{
-		if (cl_showmiss->value)
-			Com_Printf ("exceeded CMD_BACKUP\n");
-		return;	
-	}
-
-	// copy current state to pmove
-	memset (&pm, 0, sizeof(pm));
-	pm.trace = CL_PMTrace;
-	pm.pointcontents = CL_PMpointcontents;
-
-	pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
-
-	pm.s = cl.frame.playerstate.pmove;
-
-//	SCR_DebugGraph (current - ack - 1, 0);
-
-	// run frames
-	while (++ack < current)
-	{
-		frame = ack & (CMD_BACKUP-1);
-		cmd = &cl.cmds[frame];
-
-		pm.cmd = *cmd;
-		Pmove (&pm);
-
-		// save for debug checking
-		VectorCopy (pm.s.origin, cl.predicted_origins[frame]);
-	}
-
-	oldframe = (ack-2) & (CMD_BACKUP-1);
-	oldz = cl.predicted_origins[oldframe][2];
-	step = pm.s.origin[2] - oldz;
-	if (step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND) )
-	{
-		cl.predicted_step = step * 0.125;
-		cl.predicted_step_time = cls.realtime - cls.frametime * 500;
-	}
-
-
-	// copy results out for rendering
-	cl.predicted_origin[0] = pm.s.origin[0]*0.125;
-	cl.predicted_origin[1] = pm.s.origin[1]*0.125;
-	cl.predicted_origin[2] = pm.s.origin[2]*0.125;
-
-	VectorCopy (pm.viewangles, cl.predicted_angles);
-}
--- a/client/cl_scrn.c
+++ /dev/null
@@ -1,1381 +1,0 @@
-// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
-
-/*
-
-  full screen console
-  put up loading plaque
-  blanked background with loading plaque
-  blanked background with menu
-  cinematics
-  full screen image for quit and victory
-
-  end of unit intermissions
-
-  */
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-float		scr_con_current;	// aproaches scr_conlines at scr_conspeed
-float		scr_conlines;		// 0.0 to 1.0 lines of console to display
-
-qboolean	scr_initialized;		// ready to draw
-
-int			scr_draw_loading;
-
-vrect_t		scr_vrect;		// position of render window on screen
-
-
-cvar_t		*scr_viewsize;
-cvar_t		*scr_conspeed;
-cvar_t		*scr_centertime;
-cvar_t		*scr_showturtle;
-cvar_t		*scr_showpause;
-cvar_t		*scr_printspeed;
-
-cvar_t		*scr_netgraph;
-cvar_t		*scr_timegraph;
-cvar_t		*scr_debuggraph;
-cvar_t		*scr_graphheight;
-cvar_t		*scr_graphscale;
-cvar_t		*scr_graphshift;
-cvar_t		*scr_drawall;
-
-typedef struct
-{
-	int		x1, y1, x2, y2;
-} dirty_t;
-
-dirty_t		scr_dirty, scr_old_dirty[2];
-
-char		crosshair_pic[MAX_QPATH];
-int			crosshair_width, crosshair_height;
-
-void SCR_TimeRefresh_f (void);
-void SCR_Loading_f (void);
-
-
-/*
-===============================================================================
-
-BAR GRAPHS
-
-===============================================================================
-*/
-
-/*
-==============
-CL_AddNetgraph
-
-A new packet was just parsed
-==============
-*/
-void CL_AddNetgraph (void)
-{
-	int		i;
-	int		in;
-	int		ping;
-
-	// if using the debuggraph for something else, don't
-	// add the net lines
-	if (scr_debuggraph->value || scr_timegraph->value)
-		return;
-
-	for (i=0 ; i<cls.netchan.dropped ; i++)
-		SCR_DebugGraph (30, 0x40);
-
-	for (i=0 ; i<cl.surpressCount ; i++)
-		SCR_DebugGraph (30, 0xdf);
-
-	// see what the latency was on this packet
-	in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
-	ping = cls.realtime - cl.cmd_time[in];
-	ping /= 30;
-	if (ping > 30)
-		ping = 30;
-	SCR_DebugGraph (ping, 0xd0);
-}
-
-
-typedef struct
-{
-	float	value;
-	int		color;
-} graphsamp_t;
-
-static	int			current;
-static	graphsamp_t	values[1024];
-
-/*
-==============
-SCR_DebugGraph
-==============
-*/
-void SCR_DebugGraph (float value, int color)
-{
-	values[current&1023].value = value;
-	values[current&1023].color = color;
-	current++;
-}
-
-/*
-==============
-SCR_DrawDebugGraph
-==============
-*/
-void SCR_DrawDebugGraph (void)
-{
-	int		a, x, y, w, i, h;
-	float	v;
-	int		color;
-
-	//
-	// draw the graph
-	//
-	w = scr_vrect.width;
-
-	x = scr_vrect.x;
-	y = scr_vrect.y+scr_vrect.height;
-	re.DrawFill (x, y-scr_graphheight->value,
-		w, scr_graphheight->value, 8);
-
-	for (a=0 ; a<w ; a++)
-	{
-		i = (current-1-a+1024) & 1023;
-		v = values[i].value;
-		color = values[i].color;
-		v = v*scr_graphscale->value + scr_graphshift->value;
-		
-		if (v < 0)
-			v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
-		h = (int)v % (int)scr_graphheight->value;
-		re.DrawFill (x+w-1-a, y - h, 1,	h, color);
-	}
-}
-
-/*
-===============================================================================
-
-CENTER PRINTING
-
-===============================================================================
-*/
-
-char		scr_centerstring[1024];
-float		scr_centertime_start;	// for slow victory printing
-float		scr_centertime_off;
-int			scr_center_lines;
-int			scr_erase_center;
-
-/*
-==============
-SCR_CenterPrint
-
-Called for important messages that should stay in the center of the screen
-for a few moments
-==============
-*/
-void SCR_CenterPrint (char *str)
-{
-	char	*s;
-	char	line[64];
-	int		i, j, l;
-
-	strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
-	scr_centertime_off = scr_centertime->value;
-	scr_centertime_start = cl.time;
-
-	// count the number of lines for centering
-	scr_center_lines = 1;
-	s = str;
-	while (*s)
-	{
-		if (*s == '\n')
-			scr_center_lines++;
-		s++;
-	}
-
-	// echo it to the console
-	Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
-
-	s = str;
-	do	
-	{
-	// scan the width of the line
-		for (l=0 ; l<40 ; l++)
-			if (s[l] == '\n' || !s[l])
-				break;
-		for (i=0 ; i<(40-l)/2 ; i++)
-			line[i] = ' ';
-
-		for (j=0 ; j<l ; j++)
-		{
-			line[i++] = s[j];
-		}
-
-		line[i] = '\n';
-		line[i+1] = 0;
-
-		Com_Printf ("%s", line);
-
-		while (*s && *s != '\n')
-			s++;
-
-		if (!*s)
-			break;
-		s++;		// skip the \n
-	} while (1);
-	Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
-	Con_ClearNotify ();
-}
-
-
-void SCR_DrawCenterString (void)
-{
-	char	*start;
-	int		l;
-	int		j;
-	int		x, y;
-	int		remaining;
-
-// the finale prints the characters one at a time
-	remaining = 9999;
-
-	scr_erase_center = 0;
-	start = scr_centerstring;
-
-	if (scr_center_lines <= 4)
-		y = vid.height*0.35;
-	else
-		y = 48;
-
-	do	
-	{
-	// scan the width of the line
-		for (l=0 ; l<40 ; l++)
-			if (start[l] == '\n' || !start[l])
-				break;
-		x = (vid.width - l*8)/2;
-		SCR_AddDirtyPoint (x, y);
-		for (j=0 ; j<l ; j++, x+=8)
-		{
-			re.DrawChar (x, y, start[j]);	
-			if (!remaining--)
-				return;
-		}
-		SCR_AddDirtyPoint (x, y+8);
-			
-		y += 8;
-
-		while (*start && *start != '\n')
-			start++;
-
-		if (!*start)
-			break;
-		start++;		// skip the \n
-	} while (1);
-}
-
-void SCR_CheckDrawCenterString (void)
-{
-	scr_centertime_off -= cls.frametime;
-	
-	if (scr_centertime_off <= 0)
-		return;
-
-	SCR_DrawCenterString ();
-}
-
-//=============================================================================
-
-/*
-=================
-SCR_CalcVrect
-
-Sets scr_vrect, the coordinates of the rendered window
-=================
-*/
-static void SCR_CalcVrect (void)
-{
-	int		size;
-
-	// bound viewsize
-	if (scr_viewsize->value < 40)
-		Cvar_Set ("viewsize","40");
-	if (scr_viewsize->value > 100)
-		Cvar_Set ("viewsize","100");
-
-	size = scr_viewsize->value;
-
-	scr_vrect.width = vid.width*size/100;
-	scr_vrect.width &= ~7;
-
-	scr_vrect.height = vid.height*size/100;
-	scr_vrect.height &= ~1;
-
-	scr_vrect.x = (vid.width - scr_vrect.width)/2;
-	scr_vrect.y = (vid.height - scr_vrect.height)/2;
-}
-
-
-/*
-=================
-SCR_SizeUp_f
-
-Keybinding command
-=================
-*/
-void SCR_SizeUp_f (void)
-{
-	Cvar_SetValue ("viewsize",scr_viewsize->value+10);
-}
-
-
-/*
-=================
-SCR_SizeDown_f
-
-Keybinding command
-=================
-*/
-void SCR_SizeDown_f (void)
-{
-	Cvar_SetValue ("viewsize",scr_viewsize->value-10);
-}
-
-/*
-=================
-SCR_Sky_f
-
-Set a specific sky and rotation speed
-=================
-*/
-void SCR_Sky_f (void)
-{
-	float	rotate;
-	vec3_t	axis;
-
-	if (Cmd_Argc() < 2)
-	{
-		Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
-		return;
-	}
-	if (Cmd_Argc() > 2)
-		rotate = atof(Cmd_Argv(2));
-	else
-		rotate = 0;
-	if (Cmd_Argc() == 6)
-	{
-		axis[0] = atof(Cmd_Argv(3));
-		axis[1] = atof(Cmd_Argv(4));
-		axis[2] = atof(Cmd_Argv(5));
-	}
-	else
-	{
-		axis[0] = 0;
-		axis[1] = 0;
-		axis[2] = 1;
-	}
-
-	re.SetSky (Cmd_Argv(1), rotate, axis);
-}
-
-//============================================================================
-
-/*
-==================
-SCR_Init
-==================
-*/
-void SCR_Init (void)
-{
-	scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
-	scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
-	scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
-	scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
-	scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
-	scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
-	scr_netgraph = Cvar_Get ("netgraph", "0", 0);
-	scr_timegraph = Cvar_Get ("timegraph", "0", 0);
-	scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
-	scr_graphheight = Cvar_Get ("graphheight", "32", 0);
-	scr_graphscale = Cvar_Get ("graphscale", "1", 0);
-	scr_graphshift = Cvar_Get ("graphshift", "0", 0);
-	scr_drawall = Cvar_Get ("scr_drawall", "0", 0);
-
-//
-// register our commands
-//
-	Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
-	Cmd_AddCommand ("loading",SCR_Loading_f);
-	Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
-	Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
-	Cmd_AddCommand ("sky",SCR_Sky_f);
-
-	scr_initialized = true;
-}
-
-
-/*
-==============
-SCR_DrawNet
-==============
-*/
-void SCR_DrawNet (void)
-{
-	if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged 
-		< CMD_BACKUP-1)
-		return;
-
-	re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");
-}
-
-/*
-==============
-SCR_DrawPause
-==============
-*/
-void SCR_DrawPause (void)
-{
-	int		w, h;
-
-	if (!scr_showpause->value)		// turn off for screenshots
-		return;
-
-	if (!cl_paused->value)
-		return;
-
-	re.DrawGetPicSize (&w, &h, "pause");
-	re.DrawPic ((vid.width-w)/2, vid.height/2 + 8, "pause");
-}
-
-/*
-==============
-SCR_DrawLoading
-==============
-*/
-void SCR_DrawLoading (void)
-{
-	int		w, h;
-		
-	if (!scr_draw_loading)
-		return;
-
-	scr_draw_loading = false;
-	re.DrawGetPicSize (&w, &h, "loading");
-	re.DrawPic ((vid.width-w)/2, (vid.height-h)/2, "loading");
-}
-
-//=============================================================================
-
-/*
-==================
-SCR_RunConsole
-
-Scroll it up or down
-==================
-*/
-void SCR_RunConsole (void)
-{
-// decide on the height of the console
-	if (cls.key_dest == key_console)
-		scr_conlines = 0.5;		// half screen
-	else
-		scr_conlines = 0;				// none visible
-	
-	if (scr_conlines < scr_con_current)
-	{
-		scr_con_current -= scr_conspeed->value*cls.frametime;
-		if (scr_conlines > scr_con_current)
-			scr_con_current = scr_conlines;
-
-	}
-	else if (scr_conlines > scr_con_current)
-	{
-		scr_con_current += scr_conspeed->value*cls.frametime;
-		if (scr_conlines < scr_con_current)
-			scr_con_current = scr_conlines;
-	}
-
-}
-
-/*
-==================
-SCR_DrawConsole
-==================
-*/
-void SCR_DrawConsole (void)
-{
-	Con_CheckResize ();
-	
-	if (cls.state == ca_disconnected || cls.state == ca_connecting)
-	{	// forced full screen console
-		Con_DrawConsole (1.0);
-		return;
-	}
-
-	if (cls.state != ca_active || !cl.refresh_prepped)
-	{	// connected, but can't render
-		Con_DrawConsole (0.5);
-		re.DrawFill (0, vid.height/2, vid.width, vid.height/2, 0);
-		return;
-	}
-
-	if (scr_con_current)
-	{
-		Con_DrawConsole (scr_con_current);
-	}
-	else
-	{
-		if (cls.key_dest == key_game || cls.key_dest == key_message)
-			Con_DrawNotify ();	// only draw notify in game
-	}
-}
-
-//=============================================================================
-
-/*
-================
-SCR_BeginLoadingPlaque
-================
-*/
-void SCR_BeginLoadingPlaque (void)
-{
-	S_StopAllSounds ();
-	cl.sound_prepped = false;		// don't play ambients
-	CDAudio_Stop ();
-	if (cls.disable_screen)
-		return;
-	if (developer->value)
-		return;
-	if (cls.state == ca_disconnected)
-		return;	// if at console, don't bring up the plaque
-	if (cls.key_dest == key_console)
-		return;
-	if (cl.cinematictime > 0)
-		scr_draw_loading = 2;	// clear to balack first
-	else
-		scr_draw_loading = 1;
-	SCR_UpdateScreen ();
-	cls.disable_screen = Sys_Milliseconds ();
-	cls.disable_servercount = cl.servercount;
-}
-
-/*
-================
-SCR_EndLoadingPlaque
-================
-*/
-void SCR_EndLoadingPlaque (void)
-{
-	cls.disable_screen = 0;
-	Con_ClearNotify ();
-}
-
-/*
-================
-SCR_Loading_f
-================
-*/
-void SCR_Loading_f (void)
-{
-	SCR_BeginLoadingPlaque ();
-}
-
-/*
-================
-SCR_TimeRefresh_f
-================
-*/
-int entitycmpfnc( const entity_t *a, const entity_t *b )
-{
-	/*
-	** all other models are sorted by model then skin
-	*/
-	if ( a->model == b->model )
-	{
-		return (uintptr)a->skin - (uintptr)b->skin;
-	}
-	else
-	{
-		return (uintptr)a->model - (uintptr)b->model;
-	}
-}
-
-void SCR_TimeRefresh_f (void)
-{
-	int		i;
-	int		start, stop;
-	float	time;
-
-	if ( cls.state != ca_active )
-		return;
-
-	start = Sys_Milliseconds ();
-
-	if (Cmd_Argc() == 2)
-	{	// run without page flipping
-		re.BeginFrame( 0 );
-		for (i=0 ; i<128 ; i++)
-		{
-			cl.refdef.viewangles[1] = i/128.0*360.0;
-			re.RenderFrame (&cl.refdef);
-		}
-		re.EndFrame();
-	}
-	else
-	{
-		for (i=0 ; i<128 ; i++)
-		{
-			cl.refdef.viewangles[1] = i/128.0*360.0;
-
-			re.BeginFrame( 0 );
-			re.RenderFrame (&cl.refdef);
-			re.EndFrame();
-		}
-	}
-
-	stop = Sys_Milliseconds ();
-	time = (stop-start)/1000.0;
-	Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
-}
-
-/*
-=================
-SCR_AddDirtyPoint
-=================
-*/
-void SCR_AddDirtyPoint (int x, int y)
-{
-	if (x < scr_dirty.x1)
-		scr_dirty.x1 = x;
-	if (x > scr_dirty.x2)
-		scr_dirty.x2 = x;
-	if (y < scr_dirty.y1)
-		scr_dirty.y1 = y;
-	if (y > scr_dirty.y2)
-		scr_dirty.y2 = y;
-}
-
-void SCR_DirtyScreen (void)
-{
-	SCR_AddDirtyPoint (0, 0);
-	SCR_AddDirtyPoint (vid.width-1, vid.height-1);
-}
-
-/*
-==============
-SCR_TileClear
-
-Clear any parts of the tiled background that were drawn on last frame
-==============
-*/
-void SCR_TileClear (void)
-{
-	int		i;
-	int		top, bottom, left, right;
-	dirty_t	clear;
-
-	if (scr_drawall->value)
-		SCR_DirtyScreen ();	// for power vr or broken page flippers...
-
-	if (scr_con_current == 1.0)
-		return;		// full screen console
-	if (scr_viewsize->value == 100)
-		return;		// full screen rendering
-	if (cl.cinematictime > 0)
-		return;		// full screen cinematic
-
-	// erase rect will be the union of the past three frames
-	// so tripple buffering works properly
-	clear = scr_dirty;
-	for (i=0 ; i<2 ; i++)
-	{
-		if (scr_old_dirty[i].x1 < clear.x1)
-			clear.x1 = scr_old_dirty[i].x1;
-		if (scr_old_dirty[i].x2 > clear.x2)
-			clear.x2 = scr_old_dirty[i].x2;
-		if (scr_old_dirty[i].y1 < clear.y1)
-			clear.y1 = scr_old_dirty[i].y1;
-		if (scr_old_dirty[i].y2 > clear.y2)
-			clear.y2 = scr_old_dirty[i].y2;
-	}
-
-	scr_old_dirty[1] = scr_old_dirty[0];
-	scr_old_dirty[0] = scr_dirty;
-
-	scr_dirty.x1 = 9999;
-	scr_dirty.x2 = -9999;
-	scr_dirty.y1 = 9999;
-	scr_dirty.y2 = -9999;
-
-	// don't bother with anything convered by the console)
-	top = scr_con_current*vid.height;
-	if (top >= clear.y1)
-		clear.y1 = top;
-
-	if (clear.y2 <= clear.y1)
-		return;		// nothing disturbed
-
-	top = scr_vrect.y;
-	bottom = top + scr_vrect.height-1;
-	left = scr_vrect.x;
-	right = left + scr_vrect.width-1;
-
-	if (clear.y1 < top)
-	{	// clear above view screen
-		i = clear.y2 < top-1 ? clear.y2 : top-1;
-		re.DrawTileClear (clear.x1 , clear.y1,
-			clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
-		clear.y1 = top;
-	}
-	if (clear.y2 > bottom)
-	{	// clear below view screen
-		i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
-		re.DrawTileClear (clear.x1, i,
-			clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
-		clear.y2 = bottom;
-	}
-	if (clear.x1 < left)
-	{	// clear left of view screen
-		i = clear.x2 < left-1 ? clear.x2 : left-1;
-		re.DrawTileClear (clear.x1, clear.y1,
-			i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
-		clear.x1 = left;
-	}
-	if (clear.x2 > right)
-	{	// clear left of view screen
-		i = clear.x1 > right+1 ? clear.x1 : right+1;
-		re.DrawTileClear (i, clear.y1,
-			clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
-		clear.x2 = right;
-	}
-
-}
-
-
-//===============================================================
-
-
-#define STAT_MINUS		10	// num frame for '-' stats digit
-char		*sb_nums[2][11] = 
-{
-	{"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
-	"num_6", "num_7", "num_8", "num_9", "num_minus"},
-	{"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
-	"anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
-};
-
-#define	ICON_WIDTH	24
-#define	ICON_HEIGHT	24
-#define	CHAR_WIDTH	16
-#define	ICON_SPACE	8
-
-
-
-/*
-================
-SizeHUDString
-
-Allow embedded \n in the string
-================
-*/
-void SizeHUDString (char *string, int *w, int *h)
-{
-	int		lines, width, current;
-
-	lines = 1;
-	width = 0;
-
-	current = 0;
-	while (*string)
-	{
-		if (*string == '\n')
-		{
-			lines++;
-			current = 0;
-		}
-		else
-		{
-			current++;
-			if (current > width)
-				width = current;
-		}
-		string++;
-	}
-
-	*w = width * 8;
-	*h = lines * 8;
-}
-
-void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)
-{
-	int		margin;
-	char	line[1024];
-	int		width;
-	int		i;
-
-	margin = x;
-
-	while (*string)
-	{
-		// scan out one line of text from the string
-		width = 0;
-		while (*string && *string != '\n')
-			line[width++] = *string++;
-		line[width] = 0;
-
-		if (centerwidth)
-			x = margin + (centerwidth - width*8)/2;
-		else
-			x = margin;
-		for (i=0 ; i<width ; i++)
-		{
-			re.DrawChar (x, y, line[i]^xor);
-			x += 8;
-		}
-		if (*string)
-		{
-			string++;	// skip the \n
-			y += 8;
-		}
-	}
-}
-
-
-/*
-==============
-SCR_DrawField
-==============
-*/
-void SCR_DrawField (int x, int y, int color, int width, int value)
-{
-	char	num[16], *ptr;
-	int		l;
-	int		frame;
-
-	if (width < 1)
-		return;
-
-	// draw number string
-	if (width > 5)
-		width = 5;
-
-	SCR_AddDirtyPoint (x, y);
-	SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);
-
-	Com_sprintf (num, sizeof(num), "%i", value);
-	l = strlen(num);
-	if (l > width)
-		l = width;
-	x += 2 + CHAR_WIDTH*(width - l);
-
-	ptr = num;
-	while (*ptr && l)
-	{
-		if (*ptr == '-')
-			frame = STAT_MINUS;
-		else
-			frame = *ptr -'0';
-
-		re.DrawPic (x,y,sb_nums[color][frame]);
-		x += CHAR_WIDTH;
-		ptr++;
-		l--;
-	}
-}
-
-
-/*
-===============
-SCR_TouchPics
-
-Allows rendering code to cache all needed sbar graphics
-===============
-*/
-void SCR_TouchPics (void)
-{
-	int		i, j;
-
-	for (i=0 ; i<2 ; i++)
-		for (j=0 ; j<11 ; j++)
-			re.RegisterPic (sb_nums[i][j]);
-
-	if (crosshair->value)
-	{
-		if (crosshair->value > 3 || crosshair->value < 0)
-			crosshair->value = 3;
-
-		Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));
-		re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
-		if (!crosshair_width)
-			crosshair_pic[0] = 0;
-	}
-}
-
-/*
-================
-SCR_ExecuteLayoutString 
-
-================
-*/
-void SCR_ExecuteLayoutString (char *s)
-{
-	int		x, y;
-	int		value;
-	char	*token;
-	int		width;
-	int		index;
-	clientinfo_t	*ci;
-
-	if (cls.state != ca_active || !cl.refresh_prepped)
-		return;
-
-	if (!s[0])
-		return;
-
-	x = 0;
-	y = 0;
-
-	while (s)
-	{
-		token = COM_Parse (&s);
-		if (!strcmp(token, "xl"))
-		{
-			token = COM_Parse (&s);
-			x = atoi(token);
-			continue;
-		}
-		if (!strcmp(token, "xr"))
-		{
-			token = COM_Parse (&s);
-			x = vid.width + atoi(token);
-			continue;
-		}
-		if (!strcmp(token, "xv"))
-		{
-			token = COM_Parse (&s);
-			x = vid.width/2 - 160 + atoi(token);
-			continue;
-		}
-
-		if (!strcmp(token, "yt"))
-		{
-			token = COM_Parse (&s);
-			y = atoi(token);
-			continue;
-		}
-		if (!strcmp(token, "yb"))
-		{
-			token = COM_Parse (&s);
-			y = vid.height + atoi(token);
-			continue;
-		}
-		if (!strcmp(token, "yv"))
-		{
-			token = COM_Parse (&s);
-			y = vid.height/2 - 120 + atoi(token);
-			continue;
-		}
-
-		if (!strcmp(token, "pic"))
-		{	// draw a pic from a stat number
-			token = COM_Parse (&s);
-			value = cl.frame.playerstate.stats[atoi(token)];
-			if (value >= MAX_IMAGES)
-				Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
-			if (cl.configstrings[CS_IMAGES+value])
-			{
-				SCR_AddDirtyPoint (x, y);
-				SCR_AddDirtyPoint (x+23, y+23);
-				re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
-			}
-			continue;
-		}
-
-		if (!strcmp(token, "client"))
-		{	// draw a deathmatch client block
-			int		score, ping, time;
-
-			token = COM_Parse (&s);
-			x = vid.width/2 - 160 + atoi(token);
-			token = COM_Parse (&s);
-			y = vid.height/2 - 120 + atoi(token);
-			SCR_AddDirtyPoint (x, y);
-			SCR_AddDirtyPoint (x+159, y+31);
-
-			token = COM_Parse (&s);
-			value = atoi(token);
-			if (value >= MAX_CLIENTS || value < 0)
-				Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
-			ci = &cl.clientinfo[value];
-
-			token = COM_Parse (&s);
-			score = atoi(token);
-
-			token = COM_Parse (&s);
-			ping = atoi(token);
-
-			token = COM_Parse (&s);
-			time = atoi(token);
-
-			DrawAltString (x+32, y, ci->name);
-			DrawString (x+32, y+8,  "Score: ");
-			DrawAltString (x+32+7*8, y+8,  va("%i", score));
-			DrawString (x+32, y+16, va("Ping:  %i", ping));
-			DrawString (x+32, y+24, va("Time:  %i", time));
-
-			if (!ci->icon)
-				ci = &cl.baseclientinfo;
-			re.DrawPic (x, y, ci->iconname);
-			continue;
-		}
-
-		if (!strcmp(token, "ctf"))
-		{	// draw a ctf client block
-			int		score, ping;
-			char	block[80];
-
-			token = COM_Parse (&s);
-			x = vid.width/2 - 160 + atoi(token);
-			token = COM_Parse (&s);
-			y = vid.height/2 - 120 + atoi(token);
-			SCR_AddDirtyPoint (x, y);
-			SCR_AddDirtyPoint (x+159, y+31);
-
-			token = COM_Parse (&s);
-			value = atoi(token);
-			if (value >= MAX_CLIENTS || value < 0)
-				Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
-			ci = &cl.clientinfo[value];
-
-			token = COM_Parse (&s);
-			score = atoi(token);
-
-			token = COM_Parse (&s);
-			ping = atoi(token);
-			if (ping > 999)
-				ping = 999;
-
-			sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
-
-			if (value == cl.playernum)
-				DrawAltString (x, y, block);
-			else
-				DrawString (x, y, block);
-			continue;
-		}
-
-		if (!strcmp(token, "picn"))
-		{	// draw a pic from a name
-			token = COM_Parse (&s);
-			SCR_AddDirtyPoint (x, y);
-			SCR_AddDirtyPoint (x+23, y+23);
-			re.DrawPic (x, y, token);
-			continue;
-		}
-
-		if (!strcmp(token, "num"))
-		{	// draw a number
-			token = COM_Parse (&s);
-			width = atoi(token);
-			token = COM_Parse (&s);
-			value = cl.frame.playerstate.stats[atoi(token)];
-			SCR_DrawField (x, y, 0, width, value);
-			continue;
-		}
-
-		if (!strcmp(token, "hnum"))
-		{	// health number
-			int		color;
-
-			width = 3;
-			value = cl.frame.playerstate.stats[STAT_HEALTH];
-			if (value > 25)
-				color = 0;	// green
-			else if (value > 0)
-				color = (cl.frame.serverframe>>2) & 1;		// flash
-			else
-				color = 1;
-
-			if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)
-				re.DrawPic (x, y, "field_3");
-
-			SCR_DrawField (x, y, color, width, value);
-			continue;
-		}
-
-		if (!strcmp(token, "anum"))
-		{	// ammo number
-			int		color;
-
-			width = 3;
-			value = cl.frame.playerstate.stats[STAT_AMMO];
-			if (value > 5)
-				color = 0;	// green
-			else if (value >= 0)
-				color = (cl.frame.serverframe>>2) & 1;		// flash
-			else
-				continue;	// negative number = don't show
-
-			if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)
-				re.DrawPic (x, y, "field_3");
-
-			SCR_DrawField (x, y, color, width, value);
-			continue;
-		}
-
-		if (!strcmp(token, "rnum"))
-		{	// armor number
-			int		color;
-
-			width = 3;
-			value = cl.frame.playerstate.stats[STAT_ARMOR];
-			if (value < 1)
-				continue;
-
-			color = 0;	// green
-
-			if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)
-				re.DrawPic (x, y, "field_3");
-
-			SCR_DrawField (x, y, color, width, value);
-			continue;
-		}
-
-
-		if (!strcmp(token, "stat_string"))
-		{
-			token = COM_Parse (&s);
-			index = atoi(token);
-			if (index < 0 || index >= MAX_CONFIGSTRINGS)
-				Com_Error (ERR_DROP, "Bad stat_string index");
-			index = cl.frame.playerstate.stats[index];
-			if (index < 0 || index >= MAX_CONFIGSTRINGS)
-				Com_Error (ERR_DROP, "Bad stat_string index");
-			DrawString (x, y, cl.configstrings[index]);
-			continue;
-		}
-
-		if (!strcmp(token, "cstring"))
-		{
-			token = COM_Parse (&s);
-			DrawHUDString (token, x, y, 320, 0);
-			continue;
-		}
-
-		if (!strcmp(token, "string"))
-		{
-			token = COM_Parse (&s);
-			DrawString (x, y, token);
-			continue;
-		}
-
-		if (!strcmp(token, "cstring2"))
-		{
-			token = COM_Parse (&s);
-			DrawHUDString (token, x, y, 320,0x80);
-			continue;
-		}
-
-		if (!strcmp(token, "string2"))
-		{
-			token = COM_Parse (&s);
-			DrawAltString (x, y, token);
-			continue;
-		}
-
-		if (!strcmp(token, "if"))
-		{	// draw a number
-			token = COM_Parse (&s);
-			value = cl.frame.playerstate.stats[atoi(token)];
-			if (!value)
-			{	// skip to endif
-				while (s && strcmp(token, "endif") )
-				{
-					token = COM_Parse (&s);
-				}
-			}
-
-			continue;
-		}
-
-
-	}
-}
-
-
-/*
-================
-SCR_DrawStats
-
-The status bar is a small layout program that
-is based on the stats array
-================
-*/
-void SCR_DrawStats (void)
-{
-	SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
-}
-
-
-/*
-================
-SCR_DrawLayout
-
-================
-*/
-void SCR_DrawLayout (void)
-{
-	if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
-		return;
-	SCR_ExecuteLayoutString (cl.layout);
-}
-
-//=======================================================
-
-/*
-==================
-SCR_UpdateScreen
-
-This is called every frame, and can also be called explicitly to flush
-text to the screen.
-==================
-*/
-void SCR_UpdateScreen (void)
-{
-	int numframes;
-	int i;
-	float separation[2] = { 0, 0 };
-
-	// if the screen is disabled (loading plaque is up, or vid mode changing)
-	// do nothing at all
-	if (cls.disable_screen)
-	{
-		if (Sys_Milliseconds() - cls.disable_screen > 120000)
-		{
-			cls.disable_screen = 0;
-			Com_Printf ("Loading plaque timed out.\n");
-		}
-		return;
-	}
-
-	if (!scr_initialized || !con.initialized)
-		return;				// not initialized yet
-
-	/*
-	** range check cl_camera_separation so we don't inadvertently fry someone's
-	** brain
-	*/
-	if ( cl_stereo_separation->value > 1.0 )
-		Cvar_SetValue( "cl_stereo_separation", 1.0 );
-	else if ( cl_stereo_separation->value < 0 )
-		Cvar_SetValue( "cl_stereo_separation", 0.0 );
-
-	if ( cl_stereo->value )
-	{
-		numframes = 2;
-		separation[0] = -cl_stereo_separation->value / 2;
-		separation[1] =  cl_stereo_separation->value / 2;
-	}		
-	else
-	{
-		separation[0] = 0;
-		separation[1] = 0;
-		numframes = 1;
-	}
-
-	for ( i = 0; i < numframes; i++ )
-	{
-		re.BeginFrame( separation[i] );
-
-		if (scr_draw_loading == 2)
-		{	//  loading plaque over black screen
-			int		w, h;
-
-			re.CinematicSetPalette(NULL);
-			scr_draw_loading = false;
-			re.DrawGetPicSize (&w, &h, "loading");
-			re.DrawPic ((vid.width-w)/2, (vid.height-h)/2, "loading");
-//			re.EndFrame();
-//			return;
-		} 
-		// if a cinematic is supposed to be running, handle menus
-		// and console specially
-		else if (cl.cinematictime > 0)
-		{
-			if (cls.key_dest == key_menu)
-			{
-				if (cl.cinematicpalette_active)
-				{
-					re.CinematicSetPalette(NULL);
-					cl.cinematicpalette_active = false;
-				}
-				M_Draw ();
-//				re.EndFrame();
-//				return;
-			}
-			else if (cls.key_dest == key_console)
-			{
-				if (cl.cinematicpalette_active)
-				{
-					re.CinematicSetPalette(NULL);
-					cl.cinematicpalette_active = false;
-				}
-				SCR_DrawConsole ();
-//				re.EndFrame();
-//				return;
-			}
-			else
-			{
-				SCR_DrawCinematic();
-//				re.EndFrame();
-//				return;
-			}
-		}
-		else 
-		{
-
-			// make sure the game palette is active
-			if (cl.cinematicpalette_active)
-			{
-				re.CinematicSetPalette(NULL);
-				cl.cinematicpalette_active = false;
-			}
-
-			// do 3D refresh drawing, and then update the screen
-			SCR_CalcVrect ();
-
-			// clear any dirty part of the background
-			SCR_TileClear ();
-
-			V_RenderView ( separation[i] );
-
-			SCR_DrawStats ();
-			if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
-				SCR_DrawLayout ();
-			if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
-				CL_DrawInventory ();
-
-			SCR_DrawNet ();
-			SCR_CheckDrawCenterString ();
-
-			if (scr_timegraph->value)
-				SCR_DebugGraph (cls.frametime*300, 0);
-
-			if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
-				SCR_DrawDebugGraph ();
-
-			SCR_DrawPause ();
-
-			SCR_DrawConsole ();
-
-			M_Draw ();
-
-			SCR_DrawLoading ();
-		}
-	}
-	re.EndFrame();
-}
--- a/client/cl_tent.c
+++ /dev/null
@@ -1,1729 +1,0 @@
-// cl_tent.c -- client side temporary entities
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-typedef enum
-{
-	ex_free, ex_explosion, ex_misc, ex_flash, ex_mflash, ex_poly, ex_poly2
-} exptype_t;
-
-typedef struct
-{
-	exptype_t	type;
-	entity_t	ent;
-
-	int			frames;
-	float		light;
-	vec3_t		lightcolor;
-	float		start;
-	int			baseframe;
-} explosion_t;
-
-
-
-#define	MAX_EXPLOSIONS	32
-explosion_t	cl_explosions[MAX_EXPLOSIONS];
-
-
-#define	MAX_BEAMS	32
-typedef struct
-{
-	int		entity;
-	int		dest_entity;
-	struct model_s	*model;
-	int		endtime;
-	vec3_t	offset;
-	vec3_t	start, end;
-} beam_t;
-beam_t		cl_beams[MAX_BEAMS];
-//PMM - added this for player-linked beams.  Currently only used by the plasma beam
-beam_t		cl_playerbeams[MAX_BEAMS];
-
-
-#define	MAX_LASERS	32
-typedef struct
-{
-	entity_t	ent;
-	int			endtime;
-} laser_t;
-laser_t		cl_lasers[MAX_LASERS];
-
-//ROGUE
-cl_sustain_t	cl_sustains[MAX_SUSTAINS];
-//ROGUE
-
-//PGM
-extern void CL_TeleportParticles (vec3_t org);
-//PGM
-
-void CL_BlasterParticles (vec3_t org, vec3_t dir);
-void CL_ExplosionParticles (vec3_t org);
-void CL_BFGExplosionParticles (vec3_t org);
-// RAFAEL
-void CL_BlueBlasterParticles (vec3_t org, vec3_t dir);
-
-struct sfx_s	*cl_sfx_ric1;
-struct sfx_s	*cl_sfx_ric2;
-struct sfx_s	*cl_sfx_ric3;
-struct sfx_s	*cl_sfx_lashit;
-struct sfx_s	*cl_sfx_spark5;
-struct sfx_s	*cl_sfx_spark6;
-struct sfx_s	*cl_sfx_spark7;
-struct sfx_s	*cl_sfx_railg;
-struct sfx_s	*cl_sfx_rockexp;
-struct sfx_s	*cl_sfx_grenexp;
-struct sfx_s	*cl_sfx_watrexp;
-// RAFAEL
-struct sfx_s	*cl_sfx_plasexp;
-struct sfx_s	*cl_sfx_footsteps[4];
-
-struct model_s	*cl_mod_explode;
-struct model_s	*cl_mod_smoke;
-struct model_s	*cl_mod_flash;
-struct model_s	*cl_mod_parasite_segment;
-struct model_s	*cl_mod_grapple_cable;
-struct model_s	*cl_mod_parasite_tip;
-struct model_s	*cl_mod_explo4;
-struct model_s	*cl_mod_bfg_explo;
-struct model_s	*cl_mod_powerscreen;
-// RAFAEL
-struct model_s	*cl_mod_plasmaexplo;
-
-//ROGUE
-struct sfx_s	*cl_sfx_lightning;
-struct sfx_s	*cl_sfx_disrexp;
-struct model_s	*cl_mod_lightning;
-struct model_s	*cl_mod_heatbeam;
-struct model_s	*cl_mod_monster_heatbeam;
-struct model_s	*cl_mod_explo4_big;
-
-//ROGUE
-/*
-=================
-CL_RegisterTEntSounds
-=================
-*/
-void CL_RegisterTEntSounds (void)
-{
-	int		i;
-	char	name[MAX_QPATH];
-
-	// PMM - version stuff
-//	Com_Printf ("%s\n", ROGUE_VERSION_STRING);
-	// PMM
-	cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav");
-	cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav");
-	cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav");
-	cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav");
-	cl_sfx_spark5 = S_RegisterSound ("world/spark5.wav");
-	cl_sfx_spark6 = S_RegisterSound ("world/spark6.wav");
-	cl_sfx_spark7 = S_RegisterSound ("world/spark7.wav");
-	cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav");
-	cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav");
-	cl_sfx_grenexp = S_RegisterSound ("weapons/grenlx1a.wav");
-	cl_sfx_watrexp = S_RegisterSound ("weapons/xpld_wat.wav");
-	// RAFAEL
-	// cl_sfx_plasexp = S_RegisterSound ("weapons/plasexpl.wav");
-	S_RegisterSound ("player/land1.wav");
-
-	S_RegisterSound ("player/fall2.wav");
-	S_RegisterSound ("player/fall1.wav");
-
-	for (i=0 ; i<4 ; i++)
-	{
-		Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
-		cl_sfx_footsteps[i] = S_RegisterSound (name);
-	}
-
-//PGM
-	cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav");
-	cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav");
-	// version stuff
-	sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID);
-	if (name[0] == 'w')
-		name[0] = 'W';
-//PGM
-}	
-
-/*
-=================
-CL_RegisterTEntModels
-=================
-*/
-void CL_RegisterTEntModels (void)
-{
-	cl_mod_explode = re.RegisterModel ("models/objects/explode/tris.md2");
-	cl_mod_smoke = re.RegisterModel ("models/objects/smoke/tris.md2");
-	cl_mod_flash = re.RegisterModel ("models/objects/flash/tris.md2");
-	cl_mod_parasite_segment = re.RegisterModel ("models/monsters/parasite/segment/tris.md2");
-	cl_mod_grapple_cable = re.RegisterModel ("models/ctf/segment/tris.md2");
-	cl_mod_parasite_tip = re.RegisterModel ("models/monsters/parasite/tip/tris.md2");
-	cl_mod_explo4 = re.RegisterModel ("models/objects/r_explode/tris.md2");
-	cl_mod_bfg_explo = re.RegisterModel ("sprites/s_bfg2.sp2");
-	cl_mod_powerscreen = re.RegisterModel ("models/items/armor/effect/tris.md2");
-
-re.RegisterModel ("models/objects/laser/tris.md2");
-re.RegisterModel ("models/objects/grenade2/tris.md2");
-re.RegisterModel ("models/weapons/v_machn/tris.md2");
-re.RegisterModel ("models/weapons/v_handgr/tris.md2");
-re.RegisterModel ("models/weapons/v_shotg2/tris.md2");
-re.RegisterModel ("models/objects/gibs/bone/tris.md2");
-re.RegisterModel ("models/objects/gibs/sm_meat/tris.md2");
-re.RegisterModel ("models/objects/gibs/bone2/tris.md2");
-// RAFAEL
-// re.RegisterModel ("models/objects/blaser/tris.md2");
-
-re.RegisterPic ("w_machinegun");
-re.RegisterPic ("a_bullets");
-re.RegisterPic ("i_health");
-re.RegisterPic ("a_grenades");
-
-//ROGUE
-	cl_mod_explo4_big = re.RegisterModel ("models/objects/r_explode2/tris.md2");
-	cl_mod_lightning = re.RegisterModel ("models/proj/lightning/tris.md2");
-	cl_mod_heatbeam = re.RegisterModel ("models/proj/beam/tris.md2");
-	cl_mod_monster_heatbeam = re.RegisterModel ("models/proj/widowbeam/tris.md2");
-//ROGUE
-}	
-
-/*
-=================
-CL_ClearTEnts
-=================
-*/
-void CL_ClearTEnts (void)
-{
-	memset (cl_beams, 0, sizeof(cl_beams));
-	memset (cl_explosions, 0, sizeof(cl_explosions));
-	memset (cl_lasers, 0, sizeof(cl_lasers));
-
-//ROGUE
-	memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
-	memset (cl_sustains, 0, sizeof(cl_sustains));
-//ROGUE
-}
-
-/*
-=================
-CL_AllocExplosion
-=================
-*/
-explosion_t *CL_AllocExplosion (void)
-{
-	int		i;
-	int		time;
-	int		index;
-	
-	for (i=0 ; i<MAX_EXPLOSIONS ; i++)
-	{
-		if (cl_explosions[i].type == ex_free)
-		{
-			memset (&cl_explosions[i], 0, sizeof (cl_explosions[i]));
-			return &cl_explosions[i];
-		}
-	}
-// find the oldest explosion
-	time = cl.time;
-	index = 0;
-
-	for (i=0 ; i<MAX_EXPLOSIONS ; i++)
-		if (cl_explosions[i].start < time)
-		{
-			time = cl_explosions[i].start;
-			index = i;
-		}
-	memset (&cl_explosions[index], 0, sizeof (cl_explosions[index]));
-	return &cl_explosions[index];
-}
-
-/*
-=================
-CL_SmokeAndFlash
-=================
-*/
-void CL_SmokeAndFlash(vec3_t origin)
-{
-	explosion_t	*ex;
-
-	ex = CL_AllocExplosion ();
-	VectorCopy (origin, ex->ent.origin);
-	ex->type = ex_misc;
-	ex->frames = 4;
-	ex->ent.flags = RF_TRANSLUCENT;
-	ex->start = cl.frame.servertime - 100;
-	ex->ent.model = cl_mod_smoke;
-
-	ex = CL_AllocExplosion ();
-	VectorCopy (origin, ex->ent.origin);
-	ex->type = ex_flash;
-	ex->ent.flags = RF_FULLBRIGHT;
-	ex->frames = 2;
-	ex->start = cl.frame.servertime - 100;
-	ex->ent.model = cl_mod_flash;
-}
-
-/*
-=================
-CL_ParseParticles
-=================
-*/
-void CL_ParseParticles (void)
-{
-	int		color, count;
-	vec3_t	pos, dir;
-
-	MSG_ReadPos (&net_message, pos);
-	MSG_ReadDir (&net_message, dir);
-
-	color = MSG_ReadByte (&net_message);
-
-	count = MSG_ReadByte (&net_message);
-
-	CL_ParticleEffect (pos, dir, color, count);
-}
-
-/*
-=================
-CL_ParseBeam
-=================
-*/
-int CL_ParseBeam (struct model_s *model)
-{
-	int		ent;
-	vec3_t	start, end;
-	beam_t	*b;
-	int		i;
-	
-	ent = MSG_ReadShort (&net_message);
-	
-	MSG_ReadPos (&net_message, start);
-	MSG_ReadPos (&net_message, end);
-
-// override any beam with the same entity
-	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
-		if (b->entity == ent)
-		{
-			b->entity = ent;
-			b->model = model;
-			b->endtime = cl.time + 200;
-			VectorCopy (start, b->start);
-			VectorCopy (end, b->end);
-			VectorClear (b->offset);
-			return ent;
-		}
-
-// find a free beam
-	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
-	{
-		if (!b->model || b->endtime < cl.time)
-		{
-			b->entity = ent;
-			b->model = model;
-			b->endtime = cl.time + 200;
-			VectorCopy (start, b->start);
-			VectorCopy (end, b->end);
-			VectorClear (b->offset);
-			return ent;
-		}
-	}
-	Com_Printf ("beam list overflow!\n");	
-	return ent;
-}
-
-/*
-=================
-CL_ParseBeam2
-=================
-*/
-int CL_ParseBeam2 (struct model_s *model)
-{
-	int		ent;
-	vec3_t	start, end, offset;
-	beam_t	*b;
-	int		i;
-	
-	ent = MSG_ReadShort (&net_message);
-	
-	MSG_ReadPos (&net_message, start);
-	MSG_ReadPos (&net_message, end);
-	MSG_ReadPos (&net_message, offset);
-
-//	Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
-
-// override any beam with the same entity
-
-	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
-		if (b->entity == ent)
-		{
-			b->entity = ent;
-			b->model = model;
-			b->endtime = cl.time + 200;
-			VectorCopy (start, b->start);
-			VectorCopy (end, b->end);
-			VectorCopy (offset, b->offset);
-			return ent;
-		}
-
-// find a free beam
-	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
-	{
-		if (!b->model || b->endtime < cl.time)
-		{
-			b->entity = ent;
-			b->model = model;
-			b->endtime = cl.time + 200;	
-			VectorCopy (start, b->start);
-			VectorCopy (end, b->end);
-			VectorCopy (offset, b->offset);
-			return ent;
-		}
-	}
-	Com_Printf ("beam list overflow!\n");	
-	return ent;
-}
-
-// ROGUE
-/*
-=================
-CL_ParsePlayerBeam
-  - adds to the cl_playerbeam array instead of the cl_beams array
-=================
-*/
-int CL_ParsePlayerBeam (struct model_s *model)
-{
-	int		ent;
-	vec3_t	start, end, offset;
-	beam_t	*b;
-	int		i;
-	
-	ent = MSG_ReadShort (&net_message);
-	
-	MSG_ReadPos (&net_message, start);
-	MSG_ReadPos (&net_message, end);
-	// PMM - network optimization
-	if (model == cl_mod_heatbeam)
-		VectorSet(offset, 2, 7, -3);
-	else if (model == cl_mod_monster_heatbeam)
-	{
-		model = cl_mod_heatbeam;
-		VectorSet(offset, 0, 0, 0);
-	}
-	else
-		MSG_ReadPos (&net_message, offset);
-
-//	Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
-
-// override any beam with the same entity
-// PMM - For player beams, we only want one per player (entity) so..
-	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
-	{
-		if (b->entity == ent)
-		{
-			b->entity = ent;
-			b->model = model;
-			b->endtime = cl.time + 200;
-			VectorCopy (start, b->start);
-			VectorCopy (end, b->end);
-			VectorCopy (offset, b->offset);
-			return ent;
-		}
-	}
-
-// find a free beam
-	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
-	{
-		if (!b->model || b->endtime < cl.time)
-		{
-			b->entity = ent;
-			b->model = model;
-			b->endtime = cl.time + 100;		// PMM - this needs to be 100 to prevent multiple heatbeams
-			VectorCopy (start, b->start);
-			VectorCopy (end, b->end);
-			VectorCopy (offset, b->offset);
-			return ent;
-		}
-	}
-	Com_Printf ("beam list overflow!\n");	
-	return ent;
-}
-//rogue
-
-/*
-=================
-CL_ParseLightning
-=================
-*/
-int CL_ParseLightning (struct model_s *model)
-{
-	int		srcEnt, destEnt;
-	vec3_t	start, end;
-	beam_t	*b;
-	int		i;
-	
-	srcEnt = MSG_ReadShort (&net_message);
-	destEnt = MSG_ReadShort (&net_message);
-
-	MSG_ReadPos (&net_message, start);
-	MSG_ReadPos (&net_message, end);
-
-// override any beam with the same source AND destination entities
-	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
-		if (b->entity == srcEnt && b->dest_entity == destEnt)
-		{
-//			Com_Printf("%d: OVERRIDE  %d -> %d\n", cl.time, srcEnt, destEnt);
-			b->entity = srcEnt;
-			b->dest_entity = destEnt;
-			b->model = model;
-			b->endtime = cl.time + 200;
-			VectorCopy (start, b->start);
-			VectorCopy (end, b->end);
-			VectorClear (b->offset);
-			return srcEnt;
-		}
-
-// find a free beam
-	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
-	{
-		if (!b->model || b->endtime < cl.time)
-		{
-//			Com_Printf("%d: NORMAL  %d -> %d\n", cl.time, srcEnt, destEnt);
-			b->entity = srcEnt;
-			b->dest_entity = destEnt;
-			b->model = model;
-			b->endtime = cl.time + 200;
-			VectorCopy (start, b->start);
-			VectorCopy (end, b->end);
-			VectorClear (b->offset);
-			return srcEnt;
-		}
-	}
-	Com_Printf ("beam list overflow!\n");	
-	return srcEnt;
-}
-
-/*
-=================
-CL_ParseLaser
-=================
-*/
-void CL_ParseLaser (int colors)
-{
-	vec3_t	start;
-	vec3_t	end;
-	laser_t	*l;
-	int		i;
-
-	MSG_ReadPos (&net_message, start);
-	MSG_ReadPos (&net_message, end);
-
-	for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
-	{
-		if (l->endtime < cl.time)
-		{
-			l->ent.flags = RF_TRANSLUCENT | RF_BEAM;
-			VectorCopy (start, l->ent.origin);
-			VectorCopy (end, l->ent.oldorigin);
-			l->ent.alpha = 0.30;
-			l->ent.skinnum = (colors >> ((rand() % 4)*8)) & 0xff;
-			l->ent.model = NULL;
-			l->ent.frame = 4;
-			l->endtime = cl.time + 100;
-			return;
-		}
-	}
-}
-
-//=============
-//ROGUE
-void CL_ParseSteam (void)
-{
-	vec3_t	pos, dir;
-	int		id, i;
-	int		r;
-	int		cnt;
-	int		color;
-	int		magnitude;
-	cl_sustain_t	*s, *free_sustain;
-
-	id = MSG_ReadShort (&net_message);		// an id of -1 is an instant effect
-	if (id != -1) // sustains
-	{
-//			Com_Printf ("Sustain effect id %d\n", id);
-		free_sustain = NULL;
-		for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
-		{
-			if (s->id == 0)
-			{
-				free_sustain = s;
-				break;
-			}
-		}
-		if (free_sustain)
-		{
-			s->id = id;
-			s->count = MSG_ReadByte (&net_message);
-			MSG_ReadPos (&net_message, s->org);
-			MSG_ReadDir (&net_message, s->dir);
-			r = MSG_ReadByte (&net_message);
-			s->color = r & 0xff;
-			s->magnitude = MSG_ReadShort (&net_message);
-			s->endtime = cl.time + MSG_ReadLong (&net_message);
-			s->think = CL_ParticleSteamEffect2;
-			s->thinkinterval = 100;
-			s->nextthink = cl.time;
-		}
-		else
-		{
-//				Com_Printf ("No free sustains!\n");
-			// FIXME - read the stuff anyway	/* and toss the results */
-			MSG_ReadByte (&net_message);
-			MSG_ReadPos (&net_message, pos);
-			MSG_ReadDir (&net_message, dir);
-			MSG_ReadByte (&net_message);
-			MSG_ReadShort (&net_message);
-			MSG_ReadLong (&net_message); // really interval
-		}
-	}
-	else // instant
-	{
-		cnt = MSG_ReadByte (&net_message);
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		r = MSG_ReadByte (&net_message);
-		magnitude = MSG_ReadShort (&net_message);
-		color = r & 0xff;
-		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
-//		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
-	}
-}
-
-void CL_ParseWidow (void)
-{
-	vec3_t	pos;
-	int		id, i;
-	cl_sustain_t	*s, *free_sustain;
-
-	id = MSG_ReadShort (&net_message);
-
-	free_sustain = NULL;
-	for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
-	{
-		if (s->id == 0)
-		{
-			free_sustain = s;
-			break;
-		}
-	}
-	if (free_sustain)
-	{
-		s->id = id;
-		MSG_ReadPos (&net_message, s->org);
-		s->endtime = cl.time + 2100;
-		s->think = CL_Widowbeamout;
-		s->thinkinterval = 1;
-		s->nextthink = cl.time;
-	}
-	else // no free sustains
-	{
-		// FIXME - read the stuff anyway
-		MSG_ReadPos (&net_message, pos);
-	}
-}
-
-void CL_ParseNuke (void)
-{
-	vec3_t	pos;
-	int		i;
-	cl_sustain_t	*s, *free_sustain;
-
-	free_sustain = NULL;
-	for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
-	{
-		if (s->id == 0)
-		{
-			free_sustain = s;
-			break;
-		}
-	}
-	if (free_sustain)
-	{
-		s->id = 21000;
-		MSG_ReadPos (&net_message, s->org);
-		s->endtime = cl.time + 1000;
-		s->think = CL_Nukeblast;
-		s->thinkinterval = 1;
-		s->nextthink = cl.time;
-	}
-	else // no free sustains
-	{
-		// FIXME - read the stuff anyway
-		MSG_ReadPos (&net_message, pos);
-	}
-}
-
-//ROGUE
-//=============
-
-
-/*
-=================
-CL_ParseTEnt
-=================
-*/
-static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
-
-void CL_ParseTEnt (void)
-{
-	int		type;
-	vec3_t	pos, pos2, dir;
-	explosion_t	*ex;
-	int		cnt;
-	int		color;
-	int		r;
-	int		ent;
-	int		magnitude;
-
-	type = MSG_ReadByte (&net_message);
-
-	switch (type)
-	{
-	case TE_BLOOD:			// bullet hitting flesh
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		CL_ParticleEffect (pos, dir, 0xe8, 60);
-		break;
-
-	case TE_GUNSHOT:			// bullet hitting wall
-	case TE_SPARKS:
-	case TE_BULLET_SPARKS:
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		if (type == TE_GUNSHOT)
-			CL_ParticleEffect (pos, dir, 0, 40);
-		else
-			CL_ParticleEffect (pos, dir, 0xe0, 6);
-
-		if (type != TE_SPARKS)
-		{
-			CL_SmokeAndFlash(pos);
-			
-			// impact sound
-			cnt = rand()&15;
-			if (cnt == 1)
-				S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
-			else if (cnt == 2)
-				S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
-			else if (cnt == 3)
-				S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
-		}
-
-		break;
-		
-	case TE_SCREEN_SPARKS:
-	case TE_SHIELD_SPARKS:
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		if (type == TE_SCREEN_SPARKS)
-			CL_ParticleEffect (pos, dir, 0xd0, 40);
-		else
-			CL_ParticleEffect (pos, dir, 0xb0, 40);
-		//FIXME : replace or remove this sound
-		S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
-		break;
-		
-	case TE_SHOTGUN:			// bullet hitting wall
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		CL_ParticleEffect (pos, dir, 0, 20);
-		CL_SmokeAndFlash(pos);
-		break;
-
-	case TE_SPLASH:			// bullet hitting water
-		cnt = MSG_ReadByte (&net_message);
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		r = MSG_ReadByte (&net_message);
-		if (r > 6)
-			color = 0x00;
-		else
-			color = splash_color[r];
-		CL_ParticleEffect (pos, dir, color, cnt);
-
-		if (r == SPLASH_SPARKS)
-		{
-			r = rand() & 3;
-			if (r == 0)
-				S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
-			else if (r == 1)
-				S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
-			else
-				S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
-		}
-		break;
-
-	case TE_LASER_SPARKS:
-		cnt = MSG_ReadByte (&net_message);
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		color = MSG_ReadByte (&net_message);
-		CL_ParticleEffect2 (pos, dir, color, cnt);
-		break;
-
-	// RAFAEL
-	case TE_BLUEHYPERBLASTER:
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadPos (&net_message, dir);
-		CL_BlasterParticles (pos, dir);
-		break;
-
-	case TE_BLASTER:			// blaster hitting wall
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		CL_BlasterParticles (pos, dir);
-
-		ex = CL_AllocExplosion ();
-		VectorCopy (pos, ex->ent.origin);
-		ex->ent.angles[0] = acos(dir[2])/M_PI*180;
-	// PMM - fixed to correct for pitch of 0
-		if (dir[0])
-			ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
-		else if (dir[1] > 0)
-			ex->ent.angles[1] = 90;
-		else if (dir[1] < 0)
-			ex->ent.angles[1] = 270;
-		else
-			ex->ent.angles[1] = 0;
-
-		ex->type = ex_misc;
-		ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
-		ex->start = cl.frame.servertime - 100;
-		ex->light = 150;
-		ex->lightcolor[0] = 1;
-		ex->lightcolor[1] = 1;
-		ex->ent.model = cl_mod_explode;
-		ex->frames = 4;
-		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
-		break;
-		
-	case TE_RAILTRAIL:			// railgun effect
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadPos (&net_message, pos2);
-		CL_RailTrail (pos, pos2);
-		S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
-		break;
-
-	case TE_EXPLOSION2:
-	case TE_GRENADE_EXPLOSION:
-	case TE_GRENADE_EXPLOSION_WATER:
-		MSG_ReadPos (&net_message, pos);
-
-		ex = CL_AllocExplosion ();
-		VectorCopy (pos, ex->ent.origin);
-		ex->type = ex_poly;
-		ex->ent.flags = RF_FULLBRIGHT;
-		ex->start = cl.frame.servertime - 100;
-		ex->light = 350;
-		ex->lightcolor[0] = 1.0;
-		ex->lightcolor[1] = 0.5;
-		ex->lightcolor[2] = 0.5;
-		ex->ent.model = cl_mod_explo4;
-		ex->frames = 19;
-		ex->baseframe = 30;
-		ex->ent.angles[1] = rand() % 360;
-		CL_ExplosionParticles (pos);
-		if (type == TE_GRENADE_EXPLOSION_WATER)
-			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
-		else
-			S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
-		break;
-
-	// RAFAEL
-	case TE_PLASMA_EXPLOSION:
-		MSG_ReadPos (&net_message, pos);
-		ex = CL_AllocExplosion ();
-		VectorCopy (pos, ex->ent.origin);
-		ex->type = ex_poly;
-		ex->ent.flags = RF_FULLBRIGHT;
-		ex->start = cl.frame.servertime - 100;
-		ex->light = 350;
-		ex->lightcolor[0] = 1.0; 
-		ex->lightcolor[1] = 0.5;
-		ex->lightcolor[2] = 0.5;
-		ex->ent.angles[1] = rand() % 360;
-		ex->ent.model = cl_mod_explo4;
-		if (qfrand() < 0.5)
-			ex->baseframe = 15;
-		ex->frames = 15;
-		CL_ExplosionParticles (pos);
-		S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
-		break;
-	
-	case TE_EXPLOSION1:
-	case TE_EXPLOSION1_BIG:						// PMM
-	case TE_ROCKET_EXPLOSION:
-	case TE_ROCKET_EXPLOSION_WATER:
-	case TE_EXPLOSION1_NP:						// PMM
-		MSG_ReadPos (&net_message, pos);
-
-		ex = CL_AllocExplosion ();
-		VectorCopy (pos, ex->ent.origin);
-		ex->type = ex_poly;
-		ex->ent.flags = RF_FULLBRIGHT;
-		ex->start = cl.frame.servertime - 100;
-		ex->light = 350;
-		ex->lightcolor[0] = 1.0;
-		ex->lightcolor[1] = 0.5;
-		ex->lightcolor[2] = 0.5;
-		ex->ent.angles[1] = rand() % 360;
-		if (type != TE_EXPLOSION1_BIG)				// PMM
-			ex->ent.model = cl_mod_explo4;			// PMM
-		else
-			ex->ent.model = cl_mod_explo4_big;
-		if (qfrand() < 0.5)
-			ex->baseframe = 15;
-		ex->frames = 15;
-		if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP))		// PMM
-			CL_ExplosionParticles (pos);									// PMM
-		if (type == TE_ROCKET_EXPLOSION_WATER)
-			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
-		else
-			S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
-		break;
-
-	case TE_BFG_EXPLOSION:
-		MSG_ReadPos (&net_message, pos);
-		ex = CL_AllocExplosion ();
-		VectorCopy (pos, ex->ent.origin);
-		ex->type = ex_poly;
-		ex->ent.flags = RF_FULLBRIGHT;
-		ex->start = cl.frame.servertime - 100;
-		ex->light = 350;
-		ex->lightcolor[0] = 0.0;
-		ex->lightcolor[1] = 1.0;
-		ex->lightcolor[2] = 0.0;
-		ex->ent.model = cl_mod_bfg_explo;
-		ex->ent.flags |= RF_TRANSLUCENT;
-		ex->ent.alpha = 0.30;
-		ex->frames = 4;
-		break;
-
-	case TE_BFG_BIGEXPLOSION:
-		MSG_ReadPos (&net_message, pos);
-		CL_BFGExplosionParticles (pos);
-		break;
-
-	case TE_BFG_LASER:
-		CL_ParseLaser (0xd0d1d2d3);
-		break;
-
-	case TE_BUBBLETRAIL:
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadPos (&net_message, pos2);
-		CL_BubbleTrail (pos, pos2);
-		break;
-
-	case TE_PARASITE_ATTACK:
-	case TE_MEDIC_CABLE_ATTACK:
-		CL_ParseBeam (cl_mod_parasite_segment);		/* toss result */
-		break;
-
-	case TE_BOSSTPORT:			// boss teleporting to station
-		MSG_ReadPos (&net_message, pos);
-		CL_BigTeleportParticles (pos);
-		S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0);
-		break;
-
-	case TE_GRAPPLE_CABLE:
-		CL_ParseBeam2 (cl_mod_grapple_cable);		/* toss result */
-		break;
-
-	// RAFAEL
-	case TE_WELDING_SPARKS:
-		cnt = MSG_ReadByte (&net_message);
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		color = MSG_ReadByte (&net_message);
-		CL_ParticleEffect2 (pos, dir, color, cnt);
-
-		ex = CL_AllocExplosion ();
-		VectorCopy (pos, ex->ent.origin);
-		ex->type = ex_flash;
-		// note to self
-		// we need a better no draw flag
-		ex->ent.flags = RF_BEAM;
-		ex->start = cl.frame.servertime - 0.1;
-		ex->light = 100 + (rand()%75);
-		ex->lightcolor[0] = 1.0;
-		ex->lightcolor[1] = 1.0;
-		ex->lightcolor[2] = 0.3;
-		ex->ent.model = cl_mod_flash;
-		ex->frames = 2;
-		break;
-
-	case TE_GREENBLOOD:
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		CL_ParticleEffect2 (pos, dir, 0xdf, 30);
-		break;
-
-	// RAFAEL
-	case TE_TUNNEL_SPARKS:
-		cnt = MSG_ReadByte (&net_message);
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		color = MSG_ReadByte (&net_message);
-		CL_ParticleEffect3 (pos, dir, color, cnt);
-		break;
-
-//=============
-//PGM
-		// PMM -following code integrated for flechette (different color)
-	case TE_BLASTER2:			// green blaster hitting wall
-	case TE_FLECHETTE:			// flechette
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		
-		// PMM
-		if (type == TE_BLASTER2)
-			CL_BlasterParticles2 (pos, dir, 0xd0);
-		else
-			CL_BlasterParticles2 (pos, dir, 0x6f); // 75
-
-		ex = CL_AllocExplosion ();
-		VectorCopy (pos, ex->ent.origin);
-		ex->ent.angles[0] = acos(dir[2])/M_PI*180;
-	// PMM - fixed to correct for pitch of 0
-		if (dir[0])
-			ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
-		else if (dir[1] > 0)
-			ex->ent.angles[1] = 90;
-		else if (dir[1] < 0)
-			ex->ent.angles[1] = 270;
-		else
-			ex->ent.angles[1] = 0;
-
-		ex->type = ex_misc;
-		ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
-
-		// PMM
-		if (type == TE_BLASTER2)
-			ex->ent.skinnum = 1;
-		else // flechette
-			ex->ent.skinnum = 2;
-
-		ex->start = cl.frame.servertime - 100;
-		ex->light = 150;
-		// PMM
-		if (type == TE_BLASTER2)
-			ex->lightcolor[1] = 1;
-		else // flechette
-		{
-			ex->lightcolor[0] = 0.19;
-			ex->lightcolor[1] = 0.41;
-			ex->lightcolor[2] = 0.75;
-		}
-		ex->ent.model = cl_mod_explode;
-		ex->frames = 4;
-		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
-		break;
-
-
-	case TE_LIGHTNING:
-		ent = CL_ParseLightning (cl_mod_lightning);
-		S_StartSound (NULL, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0);
-		break;
-
-	case TE_DEBUGTRAIL:
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadPos (&net_message, pos2);
-		CL_DebugTrail (pos, pos2);
-		break;
-
-	case TE_PLAIN_EXPLOSION:
-		MSG_ReadPos (&net_message, pos);
-
-		ex = CL_AllocExplosion ();
-		VectorCopy (pos, ex->ent.origin);
-		ex->type = ex_poly;
-		ex->ent.flags = RF_FULLBRIGHT;
-		ex->start = cl.frame.servertime - 100;
-		ex->light = 350;
-		ex->lightcolor[0] = 1.0;
-		ex->lightcolor[1] = 0.5;
-		ex->lightcolor[2] = 0.5;
-		ex->ent.angles[1] = rand() % 360;
-		ex->ent.model = cl_mod_explo4;
-		if (qfrand() < 0.5)
-			ex->baseframe = 15;
-		ex->frames = 15;
-		if (type == TE_ROCKET_EXPLOSION_WATER)
-			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
-		else
-			S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
-		break;
-
-	case TE_FLASHLIGHT:
-		MSG_ReadPos(&net_message, pos);
-		ent = MSG_ReadShort(&net_message);
-		CL_Flashlight(ent, pos);
-		break;
-
-	case TE_FORCEWALL:
-		MSG_ReadPos(&net_message, pos);
-		MSG_ReadPos(&net_message, pos2);
-		color = MSG_ReadByte (&net_message);
-		CL_ForceWall(pos, pos2, color);
-		break;
-
-	case TE_HEATBEAM:
-		CL_ParsePlayerBeam (cl_mod_heatbeam);		/* toss result */
-		break;
-
-	case TE_MONSTER_HEATBEAM:
-		CL_ParsePlayerBeam (cl_mod_monster_heatbeam);	/* toss result */
-		break;
-
-	case TE_HEATBEAM_SPARKS:
-//		cnt = MSG_ReadByte (&net_message);
-		cnt = 50;
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-//		r = MSG_ReadByte (&net_message);
-//		magnitude = MSG_ReadShort (&net_message);
-		r = 8;
-		magnitude = 60;
-		color = r & 0xff;
-		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
-		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
-		break;
-	
-	case TE_HEATBEAM_STEAM:
-//		cnt = MSG_ReadByte (&net_message);
-		cnt = 20;
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-//		r = MSG_ReadByte (&net_message);
-//		magnitude = MSG_ReadShort (&net_message);
-//		color = r & 0xff;
-		color = 0xe0;
-		magnitude = 60;
-		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
-		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
-		break;
-
-	case TE_STEAM:
-		CL_ParseSteam();
-		break;
-
-	case TE_BUBBLETRAIL2:
-//		cnt = MSG_ReadByte (&net_message);
-		cnt = 8;
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadPos (&net_message, pos2);
-		CL_BubbleTrail2 (pos, pos2, cnt);
-		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
-		break;
-
-	case TE_MOREBLOOD:
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-		CL_ParticleEffect (pos, dir, 0xe8, 250);
-		break;
-
-	case TE_CHAINFIST_SMOKE:
-		dir[0]=0; dir[1]=0; dir[2]=1;
-		MSG_ReadPos(&net_message, pos);
-		CL_ParticleSmokeEffect (pos, dir, 0, 20, 20);
-		break;
-
-	case TE_ELECTRIC_SPARKS:
-		MSG_ReadPos (&net_message, pos);
-		MSG_ReadDir (&net_message, dir);
-//		CL_ParticleEffect (pos, dir, 109, 40);
-		CL_ParticleEffect (pos, dir, 0x75, 40);
-		//FIXME : replace or remove this sound
-		S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
-		break;
-
-	case TE_TRACKER_EXPLOSION:
-		MSG_ReadPos (&net_message, pos);
-		CL_ColorFlash (pos, 0, 150, -1, -1, -1);
-		CL_ColorExplosionParticles (pos, 0, 1);
-//		CL_Tracker_Explode (pos);
-		S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
-		break;
-
-	case TE_TELEPORT_EFFECT:
-	case TE_DBALL_GOAL:
-		MSG_ReadPos (&net_message, pos);
-		CL_TeleportParticles (pos);
-		break;
-
-	case TE_WIDOWBEAMOUT:
-		CL_ParseWidow ();
-		break;
-
-	case TE_NUKEBLAST:
-		CL_ParseNuke ();
-		break;
-
-	case TE_WIDOWSPLASH:
-		MSG_ReadPos (&net_message, pos);
-		CL_WidowSplash (pos);
-		break;
-//PGM
-//==============
-
-	default:
-		Com_Error (ERR_DROP, "CL_ParseTEnt: bad type");
-	}
-}
-
-/*
-=================
-CL_AddBeams
-=================
-*/
-void CL_AddBeams (void)
-{
-	int			i,j;
-	beam_t		*b;
-	vec3_t		dist, org;
-	float		d;
-	entity_t	ent;
-	float		yaw, pitch;
-	float		forward;
-	float		len, steps;
-	float		model_length;
-	
-// update beams
-	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
-	{
-		if (!b->model || b->endtime < cl.time)
-			continue;
-
-		// if coming from the player, update the start position
-		if (b->entity == cl.playernum+1)	// entity 0 is the world
-		{
-			VectorCopy (cl.refdef.vieworg, b->start);
-			b->start[2] -= 22;	// adjust for view height
-		}
-		VectorAdd (b->start, b->offset, org);
-
-	// calculate pitch and yaw
-		VectorSubtract (b->end, org, dist);
-
-		if (dist[1] == 0 && dist[0] == 0)
-		{
-			yaw = 0;
-			if (dist[2] > 0)
-				pitch = 90;
-			else
-				pitch = 270;
-		}
-		else
-		{
-	// PMM - fixed to correct for pitch of 0
-			if (dist[0])
-				yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
-			else if (dist[1] > 0)
-				yaw = 90;
-			else
-				yaw = 270;
-			if (yaw < 0)
-				yaw += 360;
-	
-			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
-			pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
-			if (pitch < 0)
-				pitch += 360.0;
-		}
-
-	// add new entities for the beams
-		d = VectorNormalize(dist);
-
-		memset (&ent, 0, sizeof(ent));
-		if (b->model == cl_mod_lightning)
-		{
-			model_length = 35.0;
-			d-= 20.0;  // correction so it doesn't end in middle of tesla
-		}
-		else
-		{
-			model_length = 30.0;
-		}
-		steps = ceil(d/model_length);
-		len = (d-model_length)/(steps-1);
-
-		// PMM - special case for lightning model .. if the real length is shorter than the model,
-		// flip it around & draw it from the end to the start.  This prevents the model from going
-		// through the tesla mine (instead it goes through the target)
-		if ((b->model == cl_mod_lightning) && (d <= model_length))
-		{
-//			Com_Printf ("special case\n");
-			VectorCopy (b->end, ent.origin);
-			// offset to push beam outside of tesla model (negative because dist is from end to start
-			// for this beam)
-//			for (j=0 ; j<3 ; j++)
-//				ent.origin[j] -= dist[j]*10.0;
-			ent.model = b->model;
-			ent.flags = RF_FULLBRIGHT;
-			ent.angles[0] = pitch;
-			ent.angles[1] = yaw;
-			ent.angles[2] = rand()%360;
-			V_AddEntity (&ent);			
-			return;
-		}
-		while (d > 0)
-		{
-			VectorCopy (org, ent.origin);
-			ent.model = b->model;
-			if (b->model == cl_mod_lightning)
-			{
-				ent.flags = RF_FULLBRIGHT;
-				ent.angles[0] = -pitch;
-				ent.angles[1] = yaw + 180.0;
-				ent.angles[2] = rand()%360;
-			}
-			else
-			{
-				ent.angles[0] = pitch;
-				ent.angles[1] = yaw;
-				ent.angles[2] = rand()%360;
-			}
-			
-//			Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
-			V_AddEntity (&ent);
-
-			for (j=0 ; j<3 ; j++)
-				org[j] += dist[j]*len;
-			d -= model_length;
-		}
-	}
-}
-
-
-/*
-//				Com_Printf ("Endpoint:  %f %f %f\n", b->end[0], b->end[1], b->end[2]);
-//				Com_Printf ("Pred View Angles:  %f %f %f\n", cl.predicted_angles[0], cl.predicted_angles[1], cl.predicted_angles[2]);
-//				Com_Printf ("Act View Angles: %f %f %f\n", cl.refdef.viewangles[0], cl.refdef.viewangles[1], cl.refdef.viewangles[2]);
-//				VectorCopy (cl.predicted_origin, b->start);
-//				b->start[2] += 22;	// adjust for view height
-//				if (fabs(cl.refdef.vieworg[2] - b->start[2]) >= 10) {
-//					b->start[2] = cl.refdef.vieworg[2];
-//				}
-
-//				Com_Printf ("Time:  %d %d %f\n", cl.time, cls.realtime, cls.frametime);
-*/
-
-extern cvar_t *hand;
-
-/*
-=================
-ROGUE - draw player locked beams
-CL_AddPlayerBeams
-=================
-*/
-void CL_AddPlayerBeams (void)
-{
-	int			i,j;
-	beam_t		*b;
-	vec3_t		dist, org;
-	float		d;
-	entity_t	ent;
-	float		yaw, pitch;
-	float		forward;
-	float		len, steps;
-	int			framenum = 0;
-	float		model_length;
-	
-	float		hand_multiplier;
-	frame_t		*oldframe;
-	player_state_t	*ps, *ops;
-
-//PMM
-	if (hand)
-	{
-		if (hand->value == 2)
-			hand_multiplier = 0;
-		else if (hand->value == 1)
-			hand_multiplier = -1;
-		else
-			hand_multiplier = 1;
-	}
-	else 
-	{
-		hand_multiplier = 1;
-	}
-//PMM
-
-// update beams
-	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
-	{
-		vec3_t		f,r,u;
-		if (!b->model || b->endtime < cl.time)
-			continue;
-
-		if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
-		{
-
-			// if coming from the player, update the start position
-			if (b->entity == cl.playernum+1)	// entity 0 is the world
-			{	
-				// set up gun position
-				// code straight out of CL_AddViewWeapon
-				ps = &cl.frame.playerstate;
-				j = (cl.frame.serverframe - 1) & UPDATE_MASK;
-				oldframe = &cl.frames[j];
-				if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
-					oldframe = &cl.frame;		// previous frame was dropped or involid
-				ops = &oldframe->playerstate;
-				for (j=0 ; j<3 ; j++)
-				{
-					b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j]
-						+ cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]);
-				}
-				VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org);
-				VectorMA (     org, b->offset[1], cl.v_forward, org);
-				VectorMA (     org, b->offset[2], cl.v_up, org);
-				if ((hand) && (hand->value == 2)) {
-					VectorMA (org, -1, cl.v_up, org);
-				}
-				// FIXME - take these out when final
-				VectorCopy (cl.v_right, r);
-				VectorCopy (cl.v_forward, f);
-				VectorCopy (cl.v_up, u);
-
-			}
-			else
-				VectorCopy (b->start, org);
-		}
-		else
-		{
-			// if coming from the player, update the start position
-			if (b->entity == cl.playernum+1)	// entity 0 is the world
-			{
-				VectorCopy (cl.refdef.vieworg, b->start);
-				b->start[2] -= 22;	// adjust for view height
-			}
-			VectorAdd (b->start, b->offset, org);
-		}
-
-	// calculate pitch and yaw
-		VectorSubtract (b->end, org, dist);
-
-//PMM
-		if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1))
-		{
-			vec_t len;
-
-			len = VectorLength (dist);
-			VectorScale (f, len, dist);
-			VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist);
-			VectorMA (dist, b->offset[1], f, dist);
-			VectorMA (dist, b->offset[2], u, dist);
-			if ((hand) && (hand->value == 2)) {
-				VectorMA (org, -1, cl.v_up, org);
-			}
-		}
-//PMM
-
-		if (dist[1] == 0 && dist[0] == 0)
-		{
-			yaw = 0;
-			if (dist[2] > 0)
-				pitch = 90;
-			else
-				pitch = 270;
-		}
-		else
-		{
-	// PMM - fixed to correct for pitch of 0
-			if (dist[0])
-				yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
-			else if (dist[1] > 0)
-				yaw = 90;
-			else
-				yaw = 270;
-			if (yaw < 0)
-				yaw += 360;
-	
-			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
-			pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
-			if (pitch < 0)
-				pitch += 360.0;
-		}
-		
-		if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
-		{
-			if (b->entity != cl.playernum+1)
-			{
-				framenum = 2;
-//				Com_Printf ("Third person\n");
-				ent.angles[0] = -pitch;
-				ent.angles[1] = yaw + 180.0;
-				ent.angles[2] = 0;
-//				Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b->offset[0], b->offset[1], b->offset[2]);
-				AngleVectors(ent.angles, f, r, u);
-					
-				// if it's a non-origin offset, it's a player, so use the hardcoded player offset
-				if (!VectorCompare (b->offset, vec3_origin))
-				{
-					VectorMA (org, -(b->offset[0])+1, r, org);
-					VectorMA (org, -(b->offset[1]), f, org);
-					VectorMA (org, -(b->offset[2])-10, u, org);
-				}
-				else
-				{
-					// if it's a monster, do the particle effect
-					CL_MonsterPlasma_Shell(b->start);
-				}
-			}
-			else
-			{
-				framenum = 1;
-			}
-		}
-
-		// if it's the heatbeam, draw the particle effect
-		if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1)))
-		{
-			CL_Heatbeam (org, dist);
-		}
-
-	// add new entities for the beams
-		d = VectorNormalize(dist);
-
-		memset (&ent, 0, sizeof(ent));
-		if (b->model == cl_mod_heatbeam)
-		{
-			model_length = 32.0;
-		}
-		else if (b->model == cl_mod_lightning)
-		{
-			model_length = 35.0;
-			d-= 20.0;  // correction so it doesn't end in middle of tesla
-		}
-		else
-		{
-			model_length = 30.0;
-		}
-		steps = ceil(d/model_length);
-		len = (d-model_length)/(steps-1);
-
-		// PMM - special case for lightning model .. if the real length is shorter than the model,
-		// flip it around & draw it from the end to the start.  This prevents the model from going
-		// through the tesla mine (instead it goes through the target)
-		if ((b->model == cl_mod_lightning) && (d <= model_length))
-		{
-//			Com_Printf ("special case\n");
-			VectorCopy (b->end, ent.origin);
-			// offset to push beam outside of tesla model (negative because dist is from end to start
-			// for this beam)
-//			for (j=0 ; j<3 ; j++)
-//				ent.origin[j] -= dist[j]*10.0;
-			ent.model = b->model;
-			ent.flags = RF_FULLBRIGHT;
-			ent.angles[0] = pitch;
-			ent.angles[1] = yaw;
-			ent.angles[2] = rand()%360;
-			V_AddEntity (&ent);			
-			return;
-		}
-		while (d > 0)
-		{
-			VectorCopy (org, ent.origin);
-			ent.model = b->model;
-			if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
-			{
-//				ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
-//				ent.alpha = 0.3;
-				ent.flags = RF_FULLBRIGHT;
-				ent.angles[0] = -pitch;
-				ent.angles[1] = yaw + 180.0;
-				ent.angles[2] = (cl.time) % 360;
-//				ent.angles[2] = rand()%360;
-				ent.frame = framenum;
-			}
-			else if (b->model == cl_mod_lightning)
-			{
-				ent.flags = RF_FULLBRIGHT;
-				ent.angles[0] = -pitch;
-				ent.angles[1] = yaw + 180.0;
-				ent.angles[2] = rand()%360;
-			}
-			else
-			{
-				ent.angles[0] = pitch;
-				ent.angles[1] = yaw;
-				ent.angles[2] = rand()%360;
-			}
-			
-//			Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
-			V_AddEntity (&ent);
-
-			for (j=0 ; j<3 ; j++)
-				org[j] += dist[j]*len;
-			d -= model_length;
-		}
-	}
-}
-
-/*
-=================
-CL_AddExplosions
-=================
-*/
-void CL_AddExplosions (void)
-{
-	entity_t	*ent;
-	int			i;
-	explosion_t	*ex;
-	float		frac;
-	int			f;
-
-	memset (&ent, 0, sizeof(ent));
-
-	for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++)
-	{
-		if (ex->type == ex_free)
-			continue;
-		frac = (cl.time - ex->start)/100.0;
-		f = floor(frac);
-
-		ent = &ex->ent;
-
-		switch (ex->type)
-		{
-		case ex_mflash:
-			if (f >= ex->frames-1)
-				ex->type = ex_free;
-			break;
-		case ex_misc:
-			if (f >= ex->frames-1)
-			{
-				ex->type = ex_free;
-				break;
-			}
-			ent->alpha = 1.0 - frac/(ex->frames-1);
-			break;
-		case ex_flash:
-			if (f >= 1)
-			{
-				ex->type = ex_free;
-				break;
-			}
-			ent->alpha = 1.0;
-			break;
-		case ex_poly:
-			if (f >= ex->frames-1)
-			{
-				ex->type = ex_free;
-				break;
-			}
-
-			ent->alpha = (16.0 - (float)f)/16.0;
-
-			if (f < 10)
-			{
-				ent->skinnum = (f>>1);
-				if (ent->skinnum < 0)
-					ent->skinnum = 0;
-			}
-			else
-			{
-				ent->flags |= RF_TRANSLUCENT;
-				if (f < 13)
-					ent->skinnum = 5;
-				else
-					ent->skinnum = 6;
-			}
-			break;
-		case ex_poly2:
-			if (f >= ex->frames-1)
-			{
-				ex->type = ex_free;
-				break;
-			}
-
-			ent->alpha = (5.0 - (float)f)/5.0;
-			ent->skinnum = 0;
-			ent->flags |= RF_TRANSLUCENT;
-			break;
-		}
-
-		if (ex->type == ex_free)
-			continue;
-		if (ex->light)
-		{
-			V_AddLight (ent->origin, ex->light*ent->alpha,
-				ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]);
-		}
-
-		VectorCopy (ent->origin, ent->oldorigin);
-
-		if (f < 0)
-			f = 0;
-		ent->frame = ex->baseframe + f + 1;
-		ent->oldframe = ex->baseframe + f;
-		ent->backlerp = 1.0 - cl.lerpfrac;
-
-		V_AddEntity (ent);
-	}
-}
-
-
-/*
-=================
-CL_AddLasers
-=================
-*/
-void CL_AddLasers (void)
-{
-	laser_t		*l;
-	int			i;
-
-	for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
-	{
-		if (l->endtime >= cl.time)
-			V_AddEntity (&l->ent);
-	}
-}
-
-/* PMM - CL_Sustains */
-void CL_ProcessSustain (void)
-{
-	cl_sustain_t	*s;
-	int				i;
-
-	for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++)
-	{
-		if (s->id)
-			if ((s->endtime >= cl.time) && (cl.time >= s->nextthink))
-			{
-//				Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval);
-				s->think (s);
-			}
-			else if (s->endtime < cl.time)
-				s->id = 0;
-	}
-}
-
-/*
-=================
-CL_AddTEnts
-=================
-*/
-void CL_AddTEnts (void)
-{
-	CL_AddBeams ();
-	// PMM - draw plasma beams
-	CL_AddPlayerBeams ();
-	CL_AddExplosions ();
-	CL_AddLasers ();
-	// PMM - set up sustain
-	CL_ProcessSustain();
-}
--- a/client/cl_view.c
+++ /dev/null
@@ -1,568 +1,0 @@
-// cl_view.c -- player rendering positioning
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-//=============
-//
-// development tools for weapons
-//
-int			gun_frame;
-struct model_s	*gun_model;
-
-//=============
-
-cvar_t		*crosshair;
-cvar_t		*cl_testparticles;
-cvar_t		*cl_testentities;
-cvar_t		*cl_testlights;
-cvar_t		*cl_testblend;
-
-cvar_t		*cl_stats;
-
-
-int			r_numdlights;
-dlight_t	r_dlights[MAX_DLIGHTS];
-
-int			r_numentities;
-entity_t	r_entities[MAX_ENTITIES];
-
-int			r_numparticles;
-particle_t	r_particles[MAX_PARTICLES];
-
-lightstyle_t	r_lightstyles[MAX_LIGHTSTYLES];
-
-char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
-int num_cl_weaponmodels;
-
-/*
-====================
-V_ClearScene
-
-Specifies the model that will be used as the world
-====================
-*/
-void V_ClearScene (void)
-{
-	r_numdlights = 0;
-	r_numentities = 0;
-	r_numparticles = 0;
-}
-
-
-/*
-=====================
-V_AddEntity
-
-=====================
-*/
-void V_AddEntity (entity_t *ent)
-{
-	if (r_numentities >= MAX_ENTITIES)
-		return;
-	r_entities[r_numentities++] = *ent;
-}
-
-
-/*
-=====================
-V_AddParticle
-
-=====================
-*/
-void V_AddParticle (vec3_t org, int color, float alpha)
-{
-	particle_t	*p;
-
-	if (r_numparticles >= MAX_PARTICLES)
-		return;
-	p = &r_particles[r_numparticles++];
-	VectorCopy (org, p->origin);
-	p->color = color;
-	p->alpha = alpha;
-}
-
-/*
-=====================
-V_AddLight
-
-=====================
-*/
-void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
-{
-	dlight_t	*dl;
-
-	if (r_numdlights >= MAX_DLIGHTS)
-		return;
-	dl = &r_dlights[r_numdlights++];
-	VectorCopy (org, dl->origin);
-	dl->intensity = intensity;
-	dl->color[0] = r;
-	dl->color[1] = g;
-	dl->color[2] = b;
-}
-
-
-/*
-=====================
-V_AddLightStyle
-
-=====================
-*/
-void V_AddLightStyle (int style, float r, float g, float b)
-{
-	lightstyle_t	*ls;
-
-	if (style < 0 || style > MAX_LIGHTSTYLES)
-		Com_Error (ERR_DROP, "Bad light style %i", style);
-	ls = &r_lightstyles[style];
-
-	ls->white = r+g+b;
-	ls->rgb[0] = r;
-	ls->rgb[1] = g;
-	ls->rgb[2] = b;
-}
-
-/*
-================
-V_TestParticles
-
-If cl_testparticles is set, create 4096 particles in the view
-================
-*/
-void V_TestParticles (void)
-{
-	particle_t	*p;
-	int			i, j;
-	float		d, r, u;
-
-	r_numparticles = MAX_PARTICLES;
-	for (i=0 ; i<r_numparticles ; i++)
-	{
-		d = i*0.25;
-		r = 4*((i&7)-3.5);
-		u = 4*(((i>>3)&7)-3.5);
-		p = &r_particles[i];
-
-		for (j=0 ; j<3 ; j++)
-			p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*d +
-			cl.v_right[j]*r + cl.v_up[j]*u;
-
-		p->color = 8;
-		p->alpha = cl_testparticles->value;
-	}
-}
-
-/*
-================
-V_TestEntities
-
-If cl_testentities is set, create 32 player models
-================
-*/
-void V_TestEntities (void)
-{
-	int			i, j;
-	float		f, r;
-	entity_t	*ent;
-
-	r_numentities = 32;
-	memset (r_entities, 0, sizeof(r_entities));
-
-	for (i=0 ; i<r_numentities ; i++)
-	{
-		ent = &r_entities[i];
-
-		r = 64 * ( (i%4) - 1.5 );
-		f = 64 * (i/4) + 128;
-
-		for (j=0 ; j<3 ; j++)
-			ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
-			cl.v_right[j]*r;
-
-		ent->model = cl.baseclientinfo.model;
-		ent->skin = cl.baseclientinfo.skin;
-	}
-}
-
-/*
-================
-V_TestLights
-
-If cl_testlights is set, create 32 lights models
-================
-*/
-void V_TestLights (void)
-{
-	int			i, j;
-	float		f, r;
-	dlight_t	*dl;
-
-	r_numdlights = 32;
-	memset (r_dlights, 0, sizeof(r_dlights));
-
-	for (i=0 ; i<r_numdlights ; i++)
-	{
-		dl = &r_dlights[i];
-
-		r = 64 * ( (i%4) - 1.5 );
-		f = 64 * (i/4) + 128;
-
-		for (j=0 ; j<3 ; j++)
-			dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
-			cl.v_right[j]*r;
-		dl->color[0] = ((i%6)+1) & 1;
-		dl->color[1] = (((i%6)+1) & 2)>>1;
-		dl->color[2] = (((i%6)+1) & 4)>>2;
-		dl->intensity = 200;
-	}
-}
-
-//===================================================================
-
-/*
-=================
-CL_PrepRefresh
-
-Call before entering a new level, or after changing dlls
-=================
-*/
-void CL_PrepRefresh (void)
-{
-	char		mapname[32];
-	int			i;
-	char		name[MAX_QPATH];
-	float		rotate;
-	vec3_t		axis;
-
-	if (!cl.configstrings[CS_MODELS+1][0])
-		return;		// no map loaded
-
-	SCR_AddDirtyPoint (0, 0);
-	SCR_AddDirtyPoint (vid.width-1, vid.height-1);
-
-	// let the render dll load the map
-	strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5);	// skip "maps/"
-	mapname[strlen(mapname)-4] = 0;		// cut off ".bsp"
-
-	// register models, pics, and skins
-	Com_Printf ("Map: %s\r", mapname); 
-	SCR_UpdateScreen ();
-	re.BeginRegistration (mapname);
-	Com_Printf ("                                     \r");
-
-	// precache status bar pics
-	Com_Printf ("pics\r"); 
-	SCR_UpdateScreen ();
-	SCR_TouchPics ();
-	Com_Printf ("                                     \r");
-
-	CL_RegisterTEntModels ();
-
-	num_cl_weaponmodels = 1;
-	strcpy(cl_weaponmodels[0], "weapon.md2");
-
-	for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
-	{
-		strcpy (name, cl.configstrings[CS_MODELS+i]);
-		name[37] = 0;	// never go beyond one line
-		if (name[0] != '*')
-			Com_Printf ("%s\r", name); 
-		SCR_UpdateScreen ();
-		Sys_SendKeyEvents ();	// pump message loop
-		if (name[0] == '#')
-		{
-			// special player weapon model
-			if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
-			{
-				strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
-					sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
-				num_cl_weaponmodels++;
-			}
-		} 
-		else
-		{
-			cl.model_draw[i] = re.RegisterModel (cl.configstrings[CS_MODELS+i]);
-			if (name[0] == '*')
-				cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
-			else
-				cl.model_clip[i] = NULL;
-		}
-		if (name[0] != '*')
-			Com_Printf ("                                     \r");
-	}
-
-	Com_Printf ("images\r", i); 
-	SCR_UpdateScreen ();
-	for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
-	{
-		cl.image_precache[i] = re.RegisterPic (cl.configstrings[CS_IMAGES+i]);
-		Sys_SendKeyEvents ();	// pump message loop
-	}
-	
-	Com_Printf ("                                     \r");
-	for (i=0 ; i<MAX_CLIENTS ; i++)
-	{
-		if (!cl.configstrings[CS_PLAYERSKINS+i][0])
-			continue;
-		Com_Printf ("client %i\r", i); 
-		SCR_UpdateScreen ();
-		Sys_SendKeyEvents ();	// pump message loop
-		CL_ParseClientinfo (i);
-		Com_Printf ("                                     \r");
-	}
-
-	CL_LoadClientinfo (&cl.baseclientinfo, "unnamed\\male/grunt");
-
-	// set sky textures and speed
-	Com_Printf ("sky\r", i); 
-	SCR_UpdateScreen ();
-	rotate = atof (cl.configstrings[CS_SKYROTATE]);
-	sscanf (cl.configstrings[CS_SKYAXIS], "%f %f %f", 
-		&axis[0], &axis[1], &axis[2]);
-	re.SetSky (cl.configstrings[CS_SKY], rotate, axis);
-	Com_Printf ("                                     \r");
-
-	// the renderer can now free unneeded stuff
-	re.EndRegistration ();
-
-	// clear any lines of console text
-	Con_ClearNotify ();
-
-	SCR_UpdateScreen ();
-	cl.refresh_prepped = true;
-	cl.force_refdef = true;	// make sure we have a valid refdef
-
-	// start the cd track
-	CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
-}
-
-/*
-====================
-CalcFov
-====================
-*/
-float CalcFov (float fov_x, float width, float height)
-{
-	float	a;
-	float	x;
-
-	if (fov_x < 1 || fov_x > 179)
-		Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
-
-	x = width/tan(fov_x/360*M_PI);
-
-	a = atan (height/x);
-
-	a = a*360/M_PI;
-
-	return a;
-}
-
-//============================================================================
-
-// gun frame debugging functions
-void V_Gun_Next_f (void)
-{
-	gun_frame++;
-	Com_Printf ("frame %i\n", gun_frame);
-}
-
-void V_Gun_Prev_f (void)
-{
-	gun_frame--;
-	if (gun_frame < 0)
-		gun_frame = 0;
-	Com_Printf ("frame %i\n", gun_frame);
-}
-
-void V_Gun_Model_f (void)
-{
-	char	name[MAX_QPATH];
-
-	if (Cmd_Argc() != 2)
-	{
-		gun_model = NULL;
-		return;
-	}
-	Com_sprintf (name, sizeof(name), "models/%s/tris.md2", Cmd_Argv(1));
-	gun_model = re.RegisterModel (name);
-}
-
-//============================================================================
-
-
-/*
-=================
-SCR_DrawCrosshair
-=================
-*/
-void SCR_DrawCrosshair (void)
-{
-	if (!crosshair->value)
-		return;
-
-	if (crosshair->modified)
-	{
-		crosshair->modified = false;
-		SCR_TouchPics ();
-	}
-
-	if (!crosshair_pic[0])
-		return;
-
-	re.DrawPic (scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1)
-	, scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1), crosshair_pic);
-}
-
-/*
-==================
-V_RenderView
-
-==================
-*/
-void V_RenderView( float stereo_separation )
-{
-	extern int entitycmpfnc( const entity_t *, const entity_t * );
-
-	if (cls.state != ca_active)
-		return;
-
-	if (!cl.refresh_prepped)
-		return;			// still loading
-
-	if (cl_timedemo->value)
-	{
-		if (!cl.timedemo_start)
-			cl.timedemo_start = Sys_Milliseconds ();
-		cl.timedemo_frames++;
-	}
-
-	// an invalid frame will just use the exact previous refdef
-	// we can't use the old frame if the video mode has changed, though...
-	if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
-	{
-		cl.force_refdef = false;
-
-		V_ClearScene ();
-
-		// build a refresh entity list and calc cl.sim*
-		// this also calls CL_CalcViewValues which loads
-		// v_forward, etc.
-		CL_AddEntities ();
-
-		if (cl_testparticles->value)
-			V_TestParticles ();
-		if (cl_testentities->value)
-			V_TestEntities ();
-		if (cl_testlights->value)
-			V_TestLights ();
-		if (cl_testblend->value)
-		{
-			cl.refdef.blend[0] = 1;
-			cl.refdef.blend[1] = 0.5;
-			cl.refdef.blend[2] = 0.25;
-			cl.refdef.blend[3] = 0.5;
-		}
-
-		// offset vieworg appropriately if we're doing stereo separation
-		if ( stereo_separation != 0 )
-		{
-			vec3_t tmp;
-
-			VectorScale( cl.v_right, stereo_separation, tmp );
-			VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
-		}
-
-		// never let it sit exactly on a node line, because a water plane can
-		// dissapear when viewed with the eye exactly on it.
-		// the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
-		cl.refdef.vieworg[0] += 1.0/16;
-		cl.refdef.vieworg[1] += 1.0/16;
-		cl.refdef.vieworg[2] += 1.0/16;
-
-		cl.refdef.x = scr_vrect.x;
-		cl.refdef.y = scr_vrect.y;
-		cl.refdef.width = scr_vrect.width;
-		cl.refdef.height = scr_vrect.height;
-		cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
-		cl.refdef.time = cl.time*0.001;
-
-		cl.refdef.areabits = cl.frame.areabits;
-
-		if (!cl_add_entities->value)
-			r_numentities = 0;
-		if (!cl_add_particles->value)
-			r_numparticles = 0;
-		if (!cl_add_lights->value)
-			r_numdlights = 0;
-		if (!cl_add_blend->value)
-		{
-			VectorClear (cl.refdef.blend);
-		}
-
-		cl.refdef.num_entities = r_numentities;
-		cl.refdef.entities = r_entities;
-		cl.refdef.num_particles = r_numparticles;
-		cl.refdef.particles = r_particles;
-		cl.refdef.num_dlights = r_numdlights;
-		cl.refdef.dlights = r_dlights;
-		cl.refdef.lightstyles = r_lightstyles;
-
-		cl.refdef.rdflags = cl.frame.playerstate.rdflags;
-
-		// sort entities for better cache locality
-        qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(const void *, const void *))entitycmpfnc );
-	}
-
-	re.RenderFrame (&cl.refdef);
-	if (cl_stats->value)
-		Com_Printf ("ent:%i  lt:%i  part:%i\n", r_numentities, r_numdlights, r_numparticles);
-	if ( log_stats->value && ( log_stats_file != 0 ) )
-		fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
-
-
-	SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y);
-	SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1,
-		scr_vrect.y+scr_vrect.height-1);
-
-	SCR_DrawCrosshair ();
-}
-
-
-/*
-=============
-V_Viewpos_f
-=============
-*/
-void V_Viewpos_f (void)
-{
-	Com_Printf ("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
-		(int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2], 
-		(int)cl.refdef.viewangles[YAW]);
-}
-
-/*
-=============
-V_Init
-=============
-*/
-void V_Init (void)
-{
-	Cmd_AddCommand ("gun_next", V_Gun_Next_f);
-	Cmd_AddCommand ("gun_prev", V_Gun_Prev_f);
-	Cmd_AddCommand ("gun_model", V_Gun_Model_f);
-
-	Cmd_AddCommand ("viewpos", V_Viewpos_f);
-
-	crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
-
-	cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
-	cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
-	cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
-	cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
-
-	cl_stats = Cvar_Get ("cl_stats", "0", 0);
-}
--- a/client/client.h
+++ /dev/null
@@ -1,536 +1,0 @@
-// client.h -- primary header for client
-
-//#define	PARANOID			// speed sapping error checking
-
-//=============================================================================
-typedef struct
-{
-	qboolean		valid;			// cleared if delta parsing was invalid
-	int				serverframe;
-	int				servertime;		// server time the message is valid for (in msec)
-	int				deltaframe;
-	byte			areabits[MAX_MAP_AREAS/8];		// portalarea visibility bits
-	player_state_t	playerstate;
-	int				num_entities;
-	int				parse_entities;	// non-masked index into cl_parse_entities array
-} frame_t;
-
-typedef struct
-{
-	entity_state_t	baseline;		// delta from this if not from a previous frame
-	entity_state_t	current;
-	entity_state_t	prev;			// will always be valid, but might just be a copy of current
-
-	int			serverframe;		// if not current, this ent isn't in the frame
-
-	int			trailcount;			// for diminishing grenade trails
-	vec3_t		lerp_origin;		// for trails (variable hz)
-
-	int			fly_stoptime;
-} centity_t;
-
-#define MAX_CLIENTWEAPONMODELS		20		// PGM -- upped from 16 to fit the chainfist vwep
-
-typedef struct
-{
-	char	name[MAX_QPATH];
-	char	cinfo[MAX_QPATH];
-	struct image_s	*skin;
-	struct image_s	*icon;
-	char	iconname[MAX_QPATH];
-	struct model_s	*model;
-	struct model_s	*weaponmodel[MAX_CLIENTWEAPONMODELS];
-} clientinfo_t;
-
-extern char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
-extern int num_cl_weaponmodels;
-
-#define	CMD_BACKUP		64	// allow a lot of command backups for very fast systems
-
-//
-// the client_state_t structure is wiped completely at every
-// server map change
-//
-typedef struct
-{
-	int			timeoutcount;
-
-	int			timedemo_frames;
-	int			timedemo_start;
-
-	qboolean	refresh_prepped;	// false if on new level or new ref dll
-	qboolean	sound_prepped;		// ambient sounds can start
-	qboolean	force_refdef;		// vid has changed, so we can't use a paused refdef
-
-	int			parse_entities;		// index (not anded off) into cl_parse_entities[]
-
-	usercmd_t	cmd;
-	usercmd_t	cmds[CMD_BACKUP];	// each mesage will send several old cmds
-	int			cmd_time[CMD_BACKUP];	// time sent, for calculating pings
-	short		predicted_origins[CMD_BACKUP][3];	// for debug comparing against server
-
-	float		predicted_step;				// for stair up smoothing
-	unsigned	predicted_step_time;
-
-	vec3_t		predicted_origin;	// generated by CL_PredictMovement
-	vec3_t		predicted_angles;
-	vec3_t		prediction_error;
-
-	frame_t		frame;				// received from server
-	int			surpressCount;		// number of messages rate supressed
-	frame_t		frames[UPDATE_BACKUP];
-
-	// the client maintains its own idea of view angles, which are
-	// sent to the server each frame.  It is cleared to 0 upon entering each level.
-	// the server sends a delta each frame which is added to the locally
-	// tracked view angles to account for standing on rotating objects,
-	// and teleport direction changes
-	vec3_t		viewangles;
-
-	int			time;			// this is the time value that the client
-								// is rendering at.  always <= cls.realtime
-	float		lerpfrac;		// between oldframe and frame
-
-	refdef_t	refdef;
-
-	vec3_t		v_forward, v_right, v_up;	// set when refdef.angles is set
-
-	//
-	// transient data from server
-	//
-	char		layout[1024];		// general 2D overlay
-	int			inventory[MAX_ITEMS];
-
-	//
-	// non-gameserver infornamtion
-	// FIXME: move this cinematic stuff into the cin_t structure
-	FILE		*cinematic_file;
-	int			cinematictime;		// cls.realtime for first cinematic frame
-	int			cinematicframe;
-	char		cinematicpalette[768];
-	qboolean	cinematicpalette_active;
-
-	//
-	// server state information
-	//
-	qboolean	attractloop;		// running the attract loop, any key will menu
-	int			servercount;	// server identification for prespawns
-	char		gamedir[MAX_QPATH];
-	int			playernum;
-
-	char		configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
-
-	//
-	// locally derived information from server state
-	//
-	struct model_s	*model_draw[MAX_MODELS];
-	struct cmodel_s	*model_clip[MAX_MODELS];
-
-	struct sfx_s	*sound_precache[MAX_SOUNDS];
-	struct image_s	*image_precache[MAX_IMAGES];
-
-	clientinfo_t	clientinfo[MAX_CLIENTS];
-	clientinfo_t	baseclientinfo;
-} client_state_t;
-
-extern	client_state_t	cl;
-/*
-==================================================================
-
-the client_static_t structure is persistant through an arbitrary number
-of server connections
-
-==================================================================
-*/
-
-typedef enum {
-	ca_uninitialized,
-	ca_disconnected, 	// not talking to a server
-	ca_connecting,		// sending request packets to the server
-	ca_connected,		// netchan_t established, waiting for svc_serverdata
-	ca_active			// game views should be displayed
-} connstate_t;
-
-typedef enum {
-	dl_none,
-	dl_model,
-	dl_sound,
-	dl_skin,
-	dl_single
-} dltype_t;		// download type
-
-typedef enum {key_game, key_console, key_message, key_menu} keydest_t;
-
-typedef struct
-{
-	connstate_t	state;
-	keydest_t	key_dest;
-
-	int			framecount;
-	int			realtime;			// always increasing, no clamping, etc
-	float		frametime;			// seconds since last frame
-
-// screen rendering information
-	float		disable_screen;		// showing loading plaque between levels
-									// or changing rendering dlls
-									// if time gets > 30 seconds ahead, break it
-	int			disable_servercount;	// when we receive a frame and cl.servercount
-									// > cls.disable_servercount, clear disable_screen
-
-// connection information
-	char		servername[MAX_OSPATH];	// name of server from original connect
-	float		connect_time;		// for connection retransmits
-
-	int			quakePort;			// a 16 bit value that allows quake servers
-									// to work around address translating routers
-	netchan_t	netchan;
-	int			serverProtocol;		// in case we are doing some kind of version hack
-
-	int			challenge;			// from the server to use for connecting
-
-	FILE		*download;			// file transfer from server
-	char		downloadtempname[MAX_OSPATH];
-	char		downloadname[MAX_OSPATH];
-	int			downloadnumber;
-	dltype_t	downloadtype;
-	int			downloadpercent;
-
-// demo recording info must be here, so it isn't cleared on level change
-	qboolean	demorecording;
-	qboolean	demowaiting;	// don't record until a non-delta message is received
-	FILE		*demofile;
-} client_static_t;
-
-extern client_static_t	cls;
-
-//=============================================================================
-
-//
-// cvars
-//
-extern	cvar_t	*cl_stereo_separation;
-extern	cvar_t	*cl_stereo;
-
-extern	cvar_t	*cl_gun;
-extern	cvar_t	*cl_add_blend;
-extern	cvar_t	*cl_add_lights;
-extern	cvar_t	*cl_add_particles;
-extern	cvar_t	*cl_add_entities;
-extern	cvar_t	*cl_predict;
-extern	cvar_t	*cl_footsteps;
-extern	cvar_t	*cl_noskins;
-extern	cvar_t	*cl_autoskins;
-
-extern	cvar_t	*cl_upspeed;
-extern	cvar_t	*cl_forwardspeed;
-extern	cvar_t	*cl_sidespeed;
-
-extern	cvar_t	*cl_yawspeed;
-extern	cvar_t	*cl_pitchspeed;
-
-extern	cvar_t	*cl_run;
-
-extern	cvar_t	*cl_anglespeedkey;
-
-extern	cvar_t	*cl_shownet;
-extern	cvar_t	*cl_showmiss;
-extern	cvar_t	*cl_showclamp;
-
-extern	cvar_t	*cl_lightlevel;	// FIXME HACK
-
-extern	cvar_t	*cl_paused;
-extern	cvar_t	*cl_timedemo;
-
-extern	cvar_t	*cl_vwep;
-
-typedef struct
-{
-	int		key;				// so entities can reuse same entry
-	vec3_t	color;
-	vec3_t	origin;
-	float	radius;
-	float	die;				// stop lighting after this time
-	float	decay;				// drop this each second
-	float	minlight;			// don't add when contributing less
-} cdlight_t;
-
-extern	centity_t	cl_entities[MAX_EDICTS];
-extern	cdlight_t	cl_dlights[MAX_DLIGHTS];
-
-// the cl_parse_entities must be large enough to hold UPDATE_BACKUP frames of
-// entities, so that when a delta compressed message arives from the server
-// it can be un-deltad from the original 
-#define	MAX_PARSE_ENTITIES	1024
-extern	entity_state_t	cl_parse_entities[MAX_PARSE_ENTITIES];
-
-//=============================================================================
-
-extern	netadr_t	net_from;
-extern	sizebuf_t	net_message;
-
-void DrawString (int x, int y, char *s);
-void DrawAltString (int x, int y, char *s);	// toggle high bit
-qboolean	CL_CheckOrDownloadFile (char *filename);
-
-void CL_AddNetgraph (void);
-
-//ROGUE
-typedef struct cl_sustain
-{
-	int			id;
-	int			type;
-	int			endtime;
-	int			nextthink;
-	int			thinkinterval;
-	vec3_t		org;
-	vec3_t		dir;
-	int			color;
-	int			count;
-	int			magnitude;
-	void		(*think)(struct cl_sustain *self);
-} cl_sustain_t;
-
-#define MAX_SUSTAINS		32
-void CL_ParticleSteamEffect2(cl_sustain_t *self);
-
-void CL_TeleporterParticles (entity_state_t *ent);
-void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count);
-void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count);
-
-// RAFAEL
-void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count);
-
-
-//=================================================
-
-// ========
-// PGM
-typedef struct particle_s
-{
-	struct particle_s	*next;
-
-	float		time;
-
-	vec3_t		org;
-	vec3_t		vel;
-	vec3_t		accel;
-	float		color;
-	float		colorvel;
-	float		alpha;
-	float		alphavel;
-} cparticle_t;
-
-
-#define	PARTICLE_GRAVITY	40
-#define BLASTER_PARTICLE_COLOR		0xe0
-// PMM
-#define INSTANT_PARTICLE	-10000.0
-// PGM
-// ========
-
-void CL_ClearEffects (void);
-void CL_ClearTEnts (void);
-void CL_BlasterTrail (vec3_t start, vec3_t end);
-void CL_QuadTrail (vec3_t start, vec3_t end);
-void CL_RailTrail (vec3_t start, vec3_t end);
-void CL_BubbleTrail (vec3_t start, vec3_t end);
-void CL_FlagTrail (vec3_t start, vec3_t end, float color);
-
-// RAFAEL
-void CL_IonripperTrail (vec3_t start, vec3_t end);
-
-// ========
-// PGM
-void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color);
-void CL_BlasterTrail2 (vec3_t start, vec3_t end);
-void CL_DebugTrail (vec3_t start, vec3_t end);
-void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing);
-void CL_Flashlight (int ent, vec3_t pos);
-void CL_ForceWall (vec3_t start, vec3_t end, int color);
-void CL_FlameEffects (centity_t *ent, vec3_t origin);
-void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel);
-void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist);
-void CL_Heatbeam (vec3_t start, vec3_t end);
-void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude);
-void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor);
-void CL_Tracker_Explode(vec3_t origin);
-void CL_TagTrail (vec3_t start, vec3_t end, float color);
-void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b);
-void CL_Tracker_Shell(vec3_t origin);
-void CL_MonsterPlasma_Shell(vec3_t origin);
-void CL_ColorExplosionParticles (vec3_t org, int color, int run);
-void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude);
-void CL_Widowbeamout (cl_sustain_t *self);
-void CL_Nukeblast (cl_sustain_t *self);
-void CL_WidowSplash (vec3_t org);
-// PGM
-// ========
-
-int CL_ParseEntityBits (int *bits);
-void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits);
-void CL_ParseFrame (void);
-
-void CL_ParseTEnt (void);
-void CL_ParseConfigString (void);
-void CL_ParseMuzzleFlash (void);
-void CL_ParseMuzzleFlash2 (void);
-void SmokeAndFlash(vec3_t origin);
-
-void CL_SetLightstyle (int i);
-
-void CL_RunParticles (void);
-void CL_RunDLights (void);
-void CL_RunLightStyles (void);
-
-void CL_AddEntities (void);
-void CL_AddDLights (void);
-void CL_AddTEnts (void);
-void CL_AddLightStyles (void);
-
-//=================================================
-
-void CL_PrepRefresh (void);
-void CL_RegisterSounds (void);
-
-void CL_Quit_f (void);
-
-void IN_Accumulate (void);
-
-void CL_ParseLayout (void);
-
-
-//
-// cl_main
-//
-extern	refexport_t	re;		// interface to refresh .dll
-
-void CL_Init (void);
-
-void CL_FixUpGender(void);
-void CL_Disconnect (void);
-void CL_Disconnect_f (void);
-void CL_GetChallengePacket (void);
-void CL_PingServers_f (void);
-void CL_Snd_Restart_f (void);
-void CL_RequestNextDownload (void);
-
-//
-// cl_input
-//
-typedef struct
-{
-	int			down[2];		// key nums holding it down
-	unsigned	downtime;		// msec timestamp
-	unsigned	msec;			// msec down this frame
-	int			state;
-} kbutton_t;
-
-extern	kbutton_t	in_mlook, in_klook;
-extern 	kbutton_t 	in_strafe;
-extern 	kbutton_t 	in_speed;
-
-void CL_InitInput (void);
-void CL_SendCmd (void);
-void CL_SendMove (usercmd_t *cmd);
-
-void CL_ClearState (void);
-
-void CL_ReadPackets (void);
-
-int  CL_ReadFromServer (void);
-void CL_WriteToServer (usercmd_t *cmd);
-void CL_BaseMove (usercmd_t *cmd);
-
-void IN_CenterView (void);
-
-float CL_KeyState (kbutton_t *key);
-char *Key_KeynumToString (int keynum);
-
-//
-// cl_demo.c
-//
-void CL_WriteDemoMessage (void);
-void CL_Stop_f (void);
-void CL_Record_f (void);
-
-//
-// cl_parse.c
-//
-extern	char *svc_strings[256];
-
-void CL_ParseServerMessage (void);
-void CL_LoadClientinfo (clientinfo_t *ci, char *s);
-void SHOWNET(char *s);
-void CL_ParseClientinfo (int player);
-void CL_Download_f (void);
-
-//
-// cl_view.c
-//
-extern	int			gun_frame;
-extern	struct model_s	*gun_model;
-
-void V_Init (void);
-void V_RenderView( float stereo_separation );
-void V_AddEntity (entity_t *ent);
-void V_AddParticle (vec3_t org, int color, float alpha);
-void V_AddLight (vec3_t org, float intensity, float r, float g, float b);
-void V_AddLightStyle (int style, float r, float g, float b);
-
-//
-// cl_tent.c
-//
-void CL_RegisterTEntSounds (void);
-void CL_RegisterTEntModels (void);
-void CL_SmokeAndFlash(vec3_t origin);
-
-
-//
-// cl_pred.c
-//
-void CL_InitPrediction (void);
-void CL_PredictMove (void);
-void CL_CheckPredictionError (void);
-
-//
-// cl_fx.c
-//
-cdlight_t *CL_AllocDlight (int key);
-void CL_BigTeleportParticles (vec3_t org);
-void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old);
-void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags);
-void CL_FlyEffect (centity_t *ent, vec3_t origin);
-void CL_BfgParticles (entity_t *ent);
-void CL_AddParticles (void);
-void CL_EntityEvent (entity_state_t *ent);
-// RAFAEL
-void CL_TrapParticles (entity_t *ent);
-
-//
-// menus
-//
-void M_Init (void);
-void M_Keydown (int key);
-void M_Draw (void);
-void M_Menu_Main_f (void);
-void M_ForceMenuOff (void);
-void M_AddToServerList (netadr_t adr, char *info);
-
-//
-// cl_inv.c
-//
-void CL_ParseInventory (void);
-void CL_KeyInventory (int key);
-void CL_DrawInventory (void);
-
-//
-// cl_pred.c
-//
-void CL_PredictMovement (void);
-
-#ifdef id386
-void x86_TimerStart( void );
-void x86_TimerStop( void );
-void x86_TimerInit( unsigned long smallest, unsigned longest );
-unsigned long *x86_TimerGetHistogram( void );
-#endif
--- a/client/console.c
+++ /dev/null
@@ -1,660 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-console_t	con;
-
-cvar_t		*con_notifytime;
-
-
-#define		MAXCMDLINE	256
-extern	char	key_lines[32][MAXCMDLINE];
-extern	int		edit_line;
-extern	int		key_linepos;
-		
-
-void DrawString (int x, int y, char *s)
-{
-	while (*s)
-	{
-		re.DrawChar (x, y, *s);
-		x+=8;
-		s++;
-	}
-}
-
-void DrawAltString (int x, int y, char *s)
-{
-	while (*s)
-	{
-		re.DrawChar (x, y, *s ^ 0x80);
-		x+=8;
-		s++;
-	}
-}
-
-
-void Key_ClearTyping (void)
-{
-	key_lines[edit_line][1] = 0;	// clear any typing
-	key_linepos = 1;
-}
-
-/*
-================
-Con_ToggleConsole_f
-================
-*/
-void Con_ToggleConsole_f (void)
-{
-	SCR_EndLoadingPlaque ();	// get rid of loading plaque
-
-	if (cl.attractloop)
-	{
-		Cbuf_AddText ("killserver\n");
-		return;
-	}
-
-	if (cls.state == ca_disconnected)
-	{	// start the demo loop again
-		Cbuf_AddText ("d1\n");
-		return;
-	}
-
-	Key_ClearTyping ();
-	Con_ClearNotify ();
-
-	if (cls.key_dest == key_console)
-	{
-		M_ForceMenuOff ();
-		Cvar_Set ("paused", "0");
-		IN_Grabm (1);
-	}
-	else
-	{
-		M_ForceMenuOff ();
-		cls.key_dest = key_console;	
-
-		if (Cvar_VariableValue ("maxclients") == 1 
-			&& Com_ServerState ())
-			Cvar_Set ("paused", "1");
-		IN_Grabm (0);
-	}
-}
-
-/*
-================
-Con_ToggleChat_f
-================
-*/
-void Con_ToggleChat_f (void)
-{
-	Key_ClearTyping ();
-
-	if (cls.key_dest == key_console)
-	{
-		if (cls.state == ca_active)
-		{
-			M_ForceMenuOff ();
-			cls.key_dest = key_game;
-		}
-	}
-	else
-		cls.key_dest = key_console;
-	
-	Con_ClearNotify ();
-}
-
-/*
-================
-Con_Clear_f
-================
-*/
-void Con_Clear_f (void)
-{
-	memset (con.text, ' ', CON_TEXTSIZE);
-}
-
-						
-/*
-================
-Con_Dump_f
-
-Save the console contents out to a file
-================
-*/
-void Con_Dump_f (void)
-{
-	int		l, x;
-	char	*line;
-	FILE	*f;
-	char	buffer[1024];
-	char	name[MAX_OSPATH];
-
-	if (Cmd_Argc() != 2)
-	{
-		Com_Printf ("usage: condump <filename>\n");
-		return;
-	}
-
-	Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1));
-
-	Com_Printf ("Dumped console text to %s.\n", name);
-	FS_CreatePath (name);
-	f = fopen (name, "w");
-	if (!f)
-	{
-		Com_Printf ("ERROR: couldn't open.\n");
-		return;
-	}
-
-	// skip empty lines
-	for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
-	{
-		line = con.text + (l%con.totallines)*con.linewidth;
-		for (x=0 ; x<con.linewidth ; x++)
-			if (line[x] != ' ')
-				break;
-		if (x != con.linewidth)
-			break;
-	}
-
-	// write the remaining lines
-	buffer[con.linewidth] = 0;
-	for ( ; l <= con.current ; l++)
-	{
-		line = con.text + (l%con.totallines)*con.linewidth;
-		strncpy (buffer, line, con.linewidth);
-		for (x=con.linewidth-1 ; x>=0 ; x--)
-		{
-			if (buffer[x] == ' ')
-				buffer[x] = 0;
-			else
-				break;
-		}
-		for (x=0; buffer[x]; x++)
-			buffer[x] &= 0x7f;
-
-		fprintf (f, "%s\n", buffer);
-	}
-
-	fclose (f);
-}
-
-						
-/*
-================
-Con_ClearNotify
-================
-*/
-void Con_ClearNotify (void)
-{
-	int		i;
-	
-	for (i=0 ; i<NUM_CON_TIMES ; i++)
-		con.times[i] = 0;
-}
-
-						
-/*
-================
-Con_MessageMode_f
-================
-*/
-void Con_MessageMode_f (void)
-{
-	chat_team = false;
-	cls.key_dest = key_message;
-}
-
-/*
-================
-Con_MessageMode2_f
-================
-*/
-void Con_MessageMode2_f (void)
-{
-	chat_team = true;
-	cls.key_dest = key_message;
-}
-
-/*
-================
-Con_CheckResize
-
-If the line width has changed, reformat the buffer.
-================
-*/
-void Con_CheckResize (void)
-{
-	int		i, j, width, oldwidth, oldtotallines, numlines, numchars;
-	char	tbuf[CON_TEXTSIZE];
-
-	width = (vid.width >> 3) - 2;
-
-	if (width == con.linewidth)
-		return;
-
-	if (width < 1)			// video hasn't been initialized yet
-	{
-		width = 38;
-		con.linewidth = width;
-		con.totallines = CON_TEXTSIZE / con.linewidth;
-		memset (con.text, ' ', CON_TEXTSIZE);
-	}
-	else
-	{
-		oldwidth = con.linewidth;
-		con.linewidth = width;
-		oldtotallines = con.totallines;
-		con.totallines = CON_TEXTSIZE / con.linewidth;
-		numlines = oldtotallines;
-
-		if (con.totallines < numlines)
-			numlines = con.totallines;
-
-		numchars = oldwidth;
-	
-		if (con.linewidth < numchars)
-			numchars = con.linewidth;
-
-		memcpy (tbuf, con.text, CON_TEXTSIZE);
-		memset (con.text, ' ', CON_TEXTSIZE);
-
-		for (i=0 ; i<numlines ; i++)
-		{
-			for (j=0 ; j<numchars ; j++)
-			{
-				con.text[(con.totallines - 1 - i) * con.linewidth + j] =
-						tbuf[((con.current - i + oldtotallines) %
-							  oldtotallines) * oldwidth + j];
-			}
-		}
-
-		Con_ClearNotify ();
-	}
-
-	con.current = con.totallines - 1;
-	con.display = con.current;
-}
-
-
-/*
-================
-Con_Init
-================
-*/
-void Con_Init (void)
-{
-	con.linewidth = -1;
-
-	Con_CheckResize ();
-	
-	Com_Printf ("Console initialized.\n");
-
-//
-// register our commands
-//
-	con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
-
-	Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
-	Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
-	Cmd_AddCommand ("messagemode", Con_MessageMode_f);
-	Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
-	Cmd_AddCommand ("clear", Con_Clear_f);
-	Cmd_AddCommand ("condump", Con_Dump_f);
-	con.initialized = true;
-}
-
-
-/*
-===============
-Con_Linefeed
-===============
-*/
-void Con_Linefeed (void)
-{
-	con.x = 0;
-	if (con.display == con.current)
-		con.display++;
-	con.current++;
-	memset (&con.text[(con.current%con.totallines)*con.linewidth]
-	, ' ', con.linewidth);
-}
-
-/*
-================
-Con_Print
-
-Handles cursor positioning, line wrapping, etc
-All console printing must go through this in order to be logged to disk
-If no console is visible, the text will appear at the top of the game window
-================
-*/
-void Con_Print (char *txt)
-{
-	int		y;
-	int		c, l;
-	static int	cr;
-	int		mask;
-
-	if (!con.initialized)
-		return;
-
-	if (txt[0] == 1 || txt[0] == 2)
-	{
-		mask = 128;		// go to colored text
-		txt++;
-	}
-	else
-		mask = 0;
-
-
-	while ( (c = *txt) )
-	{
-	// count word length
-		for (l=0 ; l< con.linewidth ; l++)
-			if ( txt[l] <= ' ')
-				break;
-
-	// word wrap
-		if (l != con.linewidth && (con.x + l > con.linewidth) )
-			con.x = 0;
-
-		txt++;
-
-		if (cr)
-		{
-			con.current--;
-			cr = false;
-		}
-
-		
-		if (!con.x)
-		{
-			Con_Linefeed ();
-		// mark time for transparent overlay
-			if (con.current >= 0)
-				con.times[con.current % NUM_CON_TIMES] = cls.realtime;
-		}
-
-		switch (c)
-		{
-		case '\n':
-			con.x = 0;
-			break;
-
-		case '\r':
-			con.x = 0;
-			cr = 1;
-			break;
-
-		default:	// display character and advance
-			y = con.current % con.totallines;
-			con.text[y*con.linewidth+con.x] = c | mask | con.ormask;
-			con.x++;
-			if (con.x >= con.linewidth)
-				con.x = 0;
-			break;
-		}
-		
-	}
-}
-
-
-/*
-==============
-Con_CenteredPrint
-==============
-*/
-void Con_CenteredPrint (char *text)
-{
-	int		l;
-	char	buffer[1024];
-
-	l = strlen(text);
-	l = (con.linewidth-l)/2;
-	if (l < 0)
-		l = 0;
-	memset (buffer, ' ', l);
-	strcpy (buffer+l, text);
-	strcat (buffer, "\n");
-	Con_Print (buffer);
-}
-
-/*
-==============================================================================
-
-DRAWING
-
-==============================================================================
-*/
-
-
-/*
-================
-Con_DrawInput
-
-The input line scrolls horizontally if typing goes beyond the right edge
-================
-*/
-void Con_DrawInput (void)
-{
-	int		i;
-	char	*text;
-
-	if (cls.key_dest == key_menu)
-		return;
-	if (cls.key_dest != key_console && cls.state == ca_active)
-		return;		// don't draw anything (always draw if not active)
-
-	text = key_lines[edit_line];
-	
-// add the cursor frame
-	text[key_linepos] = 10+((int)(cls.realtime>>8)&1);
-	
-// fill out remainder with spaces
-	for (i=key_linepos+1 ; i< con.linewidth ; i++)
-		text[i] = ' ';
-		
-//	prestep if horizontally scrolling
-	if (key_linepos >= con.linewidth)
-		text += 1 + key_linepos - con.linewidth;
-		
-// draw it
-	for (i=0 ; i<con.linewidth ; i++)
-		re.DrawChar ( (i+1)<<3, con.vislines - 22, text[i]);
-
-// remove cursor
-	key_lines[edit_line][key_linepos] = 0;
-}
-
-
-/*
-================
-Con_DrawNotify
-
-Draws the last few lines of output transparently over the game top
-================
-*/
-void Con_DrawNotify (void)
-{
-	int		x, v;
-	char	*text;
-	int		i;
-	int		time;
-	char	*s;
-	int		skip;
-
-	v = 0;
-	for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
-	{
-		if (i < 0)
-			continue;
-		time = con.times[i % NUM_CON_TIMES];
-		if (time == 0)
-			continue;
-		time = cls.realtime - time;
-		if (time > con_notifytime->value*1000)
-			continue;
-		text = con.text + (i % con.totallines)*con.linewidth;
-		
-		for (x = 0 ; x < con.linewidth ; x++)
-			re.DrawChar ( (x+1)<<3, v, text[x]);
-
-		v += 8;
-	}
-
-
-	if (cls.key_dest == key_message)
-	{
-		if (chat_team)
-		{
-			DrawString (8, v, "say_team:");
-			skip = 11;
-		}
-		else
-		{
-			DrawString (8, v, "say:");
-			skip = 5;
-		}
-
-		s = chat_buffer;
-		if (chat_bufferlen > (vid.width>>3)-(skip+1))
-			s += chat_bufferlen - ((vid.width>>3)-(skip+1));
-		x = 0;
-		while(s[x])
-		{
-			re.DrawChar ( (x+skip)<<3, v, s[x]);
-			x++;
-		}
-		re.DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1));
-		v += 8;
-	}
-	
-	if (v)
-	{
-		SCR_AddDirtyPoint (0,0);
-		SCR_AddDirtyPoint (vid.width-1, v);
-	}
-}
-
-/*
-================
-Con_DrawConsole
-
-Draws the console with the solid background
-================
-*/
-void Con_DrawConsole (float frac)
-{
-	int				i, j, x, y, n;
-	int				rows;
-	char			*text;
-	int				row;
-	int				lines;
-	char			version[64];
-	char			dlbar[1024];
-
-	lines = vid.height * frac;
-	if (lines <= 0)
-		return;
-
-	if (lines > vid.height)
-		lines = vid.height;
-
-// draw the background
-	re.DrawStretchPic (0, -vid.height+lines, vid.width, vid.height, "conback");
-	SCR_AddDirtyPoint (0,0);
-	SCR_AddDirtyPoint (vid.width-1,lines-1);
-
-	Com_sprintf (version, sizeof(version), "v%4.2f", VERSION);
-	for (x=0 ; x<5 ; x++)
-		re.DrawChar (vid.width-44+x*8, lines-12, 128 + version[x] );
-
-// draw the text
-	con.vislines = lines;
-	
-/*
-	rows = (lines-8)>>3;		// rows of text to draw
-
-	y = lines - 24;
-*/
-	rows = (lines-22)>>3;		// rows of text to draw
-
-	y = lines - 30;
-
-// draw from the bottom up
-	if (con.display != con.current)
-	{
-	// draw arrows to show the buffer is backscrolled
-		for (x=0 ; x<con.linewidth ; x+=4)
-			re.DrawChar ( (x+1)<<3, y, '^');
-	
-		y -= 8;
-		rows--;
-	}
-	
-	row = con.display;
-	for (i=0 ; i<rows ; i++, y-=8, row--)
-	{
-		if (row < 0)
-			break;
-		if (con.current - row >= con.totallines)
-			break;		// past scrollback wrap point
-			
-		text = con.text + (row % con.totallines)*con.linewidth;
-
-		for (x=0 ; x<con.linewidth ; x++)
-			re.DrawChar ( (x+1)<<3, y, text[x]);
-	}
-
-//ZOID
-	// draw the download bar
-	// figure out width
-	if (cls.download) {
-		if ((text = strrchr(cls.downloadname, '/')) != NULL)
-			text++;
-		else
-			text = cls.downloadname;
-
-		x = con.linewidth - ((con.linewidth * 7) / 40);
-		y = x - strlen(text) - 8;
-		i = con.linewidth/3;
-		if (strlen(text) > i) {
-			y = x - i - 11;
-			strncpy(dlbar, text, i);
-			dlbar[i] = 0;
-			strcat(dlbar, "...");
-		} else
-			strcpy(dlbar, text);
-		strcat(dlbar, ": ");
-		i = strlen(dlbar);
-		dlbar[i++] = 0x80;
-		// where's the dot go?
-		if (cls.downloadpercent == 0)
-			n = 0;
-		else
-			n = y * cls.downloadpercent / 100;
-			
-		for (j = 0; j < y; j++)
-			if (j == n)
-				dlbar[i++] = 0x83;
-			else
-				dlbar[i++] = 0x81;
-		dlbar[i++] = 0x82;
-		dlbar[i] = 0;
-
-		sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
-
-		// draw it
-		y = con.vislines-12;
-		for (i = 0; i < strlen(dlbar); i++)
-			re.DrawChar ( (i+1)<<3, y, dlbar[i]);
-	}
-//ZOID
-
-// draw the input prompt, user text, and cursor if desired
-	Con_DrawInput ();
-}
--- a/client/console.h
+++ /dev/null
@@ -1,38 +1,0 @@
-#define	NUM_CON_TIMES 4
-
-#define		CON_TEXTSIZE	32768
-typedef struct
-{
-	qboolean	initialized;
-
-	char	text[CON_TEXTSIZE];
-	int		current;		// line where next message will be printed
-	int		x;				// offset in current line for next print
-	int		display;		// bottom of console displays this line
-
-	int		ormask;			// high bit mask for colored characters
-
-	int 	linewidth;		// characters across screen
-	int		totallines;		// total lines in console scrollback
-
-	float	cursorspeed;
-
-	int		vislines;
-
-	float	times[NUM_CON_TIMES];	// cls.realtime time the line was generated
-								// for transparent notify lines
-} console_t;
-
-extern	console_t	con;
-
-void Con_DrawCharacter (int cx, int line, int num);
-
-void Con_CheckResize (void);
-void Con_Init (void);
-void Con_DrawConsole (float frac);
-void Con_Print (char *txt);
-void Con_CenteredPrint (char *text);
-void Con_Clear_f (void);
-void Con_DrawNotify (void);
-void Con_ClearNotify (void);
-void Con_ToggleConsole_f (void);
--- a/client/input.h
+++ /dev/null
@@ -1,24 +1,0 @@
-// input.h -- external (non-keyboard) input devices
-
-extern cvar_t *in_joystick;
-extern cvar_t *lookspring;
-extern cvar_t *lookstrafe;
-extern cvar_t *sensitivity;
-extern cvar_t *freelook;
-extern cvar_t *m_pitch;
-
-void IN_Init (void);
-
-void IN_Shutdown (void);
-
-void IN_Commands (void);
-// oportunity for devices to stick commands on the script buffer
-
-void IN_Frame (void);
-
-void IN_Move (usercmd_t *cmd);
-// add additional movement on top of the keyboard move cmd
-
-void IN_Activate (qboolean active);
-
-void IN_Grabm(int on);
--- a/client/keys.c
+++ /dev/null
@@ -1,927 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-
-key up events are sent even if in console mode
-
-*/
-
-
-#define		MAXCMDLINE	256
-char	key_lines[32][MAXCMDLINE];
-int		key_linepos;
-int		shift_down=false;
-int	anykeydown;
-
-int		edit_line=0;
-int		history_line=0;
-
-int		key_waiting;
-char	*keybindings[256];
-qboolean	consolekeys[256];	// if true, can't be rebound while in console
-qboolean	menubound[256];	// if true, can't be rebound while in menu
-int		keyshift[256];		// key to map to if shift held down in console
-int		key_repeats[256];	// if > 1, it is autorepeating
-qboolean	keydown[256];
-
-typedef struct
-{
-	char	*name;
-	int		keynum;
-} keyname_t;
-
-keyname_t keynames[] =
-{
-	{"TAB", K_TAB},
-	{"ENTER", K_ENTER},
-	{"ESCAPE", K_ESCAPE},
-	{"SPACE", K_SPACE},
-	{"BACKSPACE", K_BACKSPACE},
-	{"UPARROW", K_UPARROW},
-	{"DOWNARROW", K_DOWNARROW},
-	{"LEFTARROW", K_LEFTARROW},
-	{"RIGHTARROW", K_RIGHTARROW},
-
-	{"ALT", K_ALT},
-	{"CTRL", K_CTRL},
-	{"SHIFT", K_SHIFT},
-	
-	{"F1", K_F1},
-	{"F2", K_F2},
-	{"F3", K_F3},
-	{"F4", K_F4},
-	{"F5", K_F5},
-	{"F6", K_F6},
-	{"F7", K_F7},
-	{"F8", K_F8},
-	{"F9", K_F9},
-	{"F10", K_F10},
-	{"F11", K_F11},
-	{"F12", K_F12},
-
-	{"INS", K_INS},
-	{"DEL", K_DEL},
-	{"PGDN", K_PGDN},
-	{"PGUP", K_PGUP},
-	{"HOME", K_HOME},
-	{"END", K_END},
-
-	{"MOUSE1", K_MOUSE1},
-	{"MOUSE2", K_MOUSE2},
-	{"MOUSE3", K_MOUSE3},
-
-	{"JOY1", K_JOY1},
-	{"JOY2", K_JOY2},
-	{"JOY3", K_JOY3},
-	{"JOY4", K_JOY4},
-
-	{"AUX1", K_AUX1},
-	{"AUX2", K_AUX2},
-	{"AUX3", K_AUX3},
-	{"AUX4", K_AUX4},
-	{"AUX5", K_AUX5},
-	{"AUX6", K_AUX6},
-	{"AUX7", K_AUX7},
-	{"AUX8", K_AUX8},
-	{"AUX9", K_AUX9},
-	{"AUX10", K_AUX10},
-	{"AUX11", K_AUX11},
-	{"AUX12", K_AUX12},
-	{"AUX13", K_AUX13},
-	{"AUX14", K_AUX14},
-	{"AUX15", K_AUX15},
-	{"AUX16", K_AUX16},
-	{"AUX17", K_AUX17},
-	{"AUX18", K_AUX18},
-	{"AUX19", K_AUX19},
-	{"AUX20", K_AUX20},
-	{"AUX21", K_AUX21},
-	{"AUX22", K_AUX22},
-	{"AUX23", K_AUX23},
-	{"AUX24", K_AUX24},
-	{"AUX25", K_AUX25},
-	{"AUX26", K_AUX26},
-	{"AUX27", K_AUX27},
-	{"AUX28", K_AUX28},
-	{"AUX29", K_AUX29},
-	{"AUX30", K_AUX30},
-	{"AUX31", K_AUX31},
-	{"AUX32", K_AUX32},
-
-	{"KP_HOME",			K_KP_HOME },
-	{"KP_UPARROW",		K_KP_UPARROW },
-	{"KP_PGUP",			K_KP_PGUP },
-	{"KP_LEFTARROW",	K_KP_LEFTARROW },
-	{"KP_5",			K_KP_5 },
-	{"KP_RIGHTARROW",	K_KP_RIGHTARROW },
-	{"KP_END",			K_KP_END },
-	{"KP_DOWNARROW",	K_KP_DOWNARROW },
-	{"KP_PGDN",			K_KP_PGDN },
-	{"KP_ENTER",		K_KP_ENTER },
-	{"KP_INS",			K_KP_INS },
-	{"KP_DEL",			K_KP_DEL },
-	{"KP_SLASH",		K_KP_SLASH },
-	{"KP_MINUS",		K_KP_MINUS },
-	{"KP_PLUS",			K_KP_PLUS },
-
-	{"MWHEELUP", K_MWHEELUP },
-	{"MWHEELDOWN", K_MWHEELDOWN },
-
-	{"PAUSE", K_PAUSE},
-
-	{"SEMICOLON", ';'},	// because a raw semicolon seperates commands
-
-	{NULL,0}
-};
-
-/*
-==============================================================================
-
-			LINE TYPING INTO THE CONSOLE
-
-==============================================================================
-*/
-
-void CompleteCommand (void)
-{
-	char	*cmd, *s;
-
-	s = key_lines[edit_line]+1;
-	if (*s == '\\' || *s == '/')
-		s++;
-
-	cmd = Cmd_CompleteCommand (s);
-	if (!cmd)
-		cmd = Cvar_CompleteVariable (s);
-	if (cmd)
-	{
-		key_lines[edit_line][1] = '/';
-		strcpy (key_lines[edit_line]+2, cmd);
-		key_linepos = strlen(cmd)+2;
-		key_lines[edit_line][key_linepos] = ' ';
-		key_linepos++;
-		key_lines[edit_line][key_linepos] = 0;
-		return;
-	}
-}
-
-/*
-====================
-Key_Console
-
-Interactive line editing and console scrollback
-====================
-*/
-void Key_Console (int key)
-{
-
-	switch ( key )
-	{
-	case K_KP_SLASH:
-		key = '/';
-		break;
-	case K_KP_MINUS:
-		key = '-';
-		break;
-	case K_KP_PLUS:
-		key = '+';
-		break;
-	case K_KP_HOME:
-		key = '7';
-		break;
-	case K_KP_UPARROW:
-		key = '8';
-		break;
-	case K_KP_PGUP:
-		key = '9';
-		break;
-	case K_KP_LEFTARROW:
-		key = '4';
-		break;
-	case K_KP_5:
-		key = '5';
-		break;
-	case K_KP_RIGHTARROW:
-		key = '6';
-		break;
-	case K_KP_END:
-		key = '1';
-		break;
-	case K_KP_DOWNARROW:
-		key = '2';
-		break;
-	case K_KP_PGDN:
-		key = '3';
-		break;
-	case K_KP_INS:
-		key = '0';
-		break;
-	case K_KP_DEL:
-		key = '.';
-		break;
-	}
-
-	if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
-		 ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
-	{
-		char *cbd;
-		
-		if ( ( cbd = Sys_GetClipboardData() ) != 0 )
-		{
-			int i;
-
-			strtok( cbd, "\n\r\b" );
-
-			i = strlen( cbd );
-			if ( i + key_linepos >= MAXCMDLINE)
-				i= MAXCMDLINE - key_linepos;
-
-			if ( i > 0 )
-			{
-				cbd[i]=0;
-				strcat( key_lines[edit_line], cbd );
-				key_linepos += i;
-			}
-			free( cbd );
-		}
-
-		return;
-	}
-
-	if ( key == 'l' ) 
-	{
-		if ( keydown[K_CTRL] )
-		{
-			Cbuf_AddText ("clear\n");
-			return;
-		}
-	}
-
-	if ( key == K_ENTER || key == K_KP_ENTER )
-	{	// backslash text are commands, else chat
-		if (key_lines[edit_line][1] == '\\' || key_lines[edit_line][1] == '/')
-			Cbuf_AddText (key_lines[edit_line]+2);	// skip the >
-		else
-			Cbuf_AddText (key_lines[edit_line]+1);	// valid command
-
-		Cbuf_AddText ("\n");
-		Com_Printf ("%s\n",key_lines[edit_line]);
-		edit_line = (edit_line + 1) & 31;
-		history_line = edit_line;
-		key_lines[edit_line][0] = ']';
-		key_linepos = 1;
-		if (cls.state == ca_disconnected)
-			SCR_UpdateScreen ();	// force an update, because the command
-									// may take some time
-		return;
-	}
-
-	if (key == K_TAB)
-	{	// command completion
-		CompleteCommand ();
-		return;
-	}
-	
-	if ( ( key == K_BACKSPACE ) || ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) || ( ( key == 'h' ) && ( keydown[K_CTRL] ) ) )
-	{
-		if (key_linepos > 1)
-			key_linepos--;
-		return;
-	}
-
-	if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
-		 ( ( key == 'p' ) && keydown[K_CTRL] ) )
-	{
-		do
-		{
-			history_line = (history_line - 1) & 31;
-		} while (history_line != edit_line
-				&& !key_lines[history_line][1]);
-		if (history_line == edit_line)
-			history_line = (edit_line+1)&31;
-		strcpy(key_lines[edit_line], key_lines[history_line]);
-		key_linepos = strlen(key_lines[edit_line]);
-		return;
-	}
-
-	if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
-		 ( ( key == 'n' ) && keydown[K_CTRL] ) )
-	{
-		if (history_line == edit_line) return;
-		do
-		{
-			history_line = (history_line + 1) & 31;
-		}
-		while (history_line != edit_line
-			&& !key_lines[history_line][1]);
-		if (history_line == edit_line)
-		{
-			key_lines[edit_line][0] = ']';
-			key_linepos = 1;
-		}
-		else
-		{
-			strcpy(key_lines[edit_line], key_lines[history_line]);
-			key_linepos = strlen(key_lines[edit_line]);
-		}
-		return;
-	}
-
-	if (key == K_PGUP || key == K_KP_PGUP )
-	{
-		con.display -= 2;
-		return;
-	}
-
-	if (key == K_PGDN || key == K_KP_PGDN ) 
-	{
-		con.display += 2;
-		if (con.display > con.current)
-			con.display = con.current;
-		return;
-	}
-
-	if (key == K_HOME || key == K_KP_HOME )
-	{
-		con.display = con.current - con.totallines + 10;
-		return;
-	}
-
-	if (key == K_END || key == K_KP_END )
-	{
-		con.display = con.current;
-		return;
-	}
-	
-	if (key < 32 || key > 127)
-		return;	// non printable
-		
-	if (key_linepos < MAXCMDLINE-1)
-	{
-		key_lines[edit_line][key_linepos] = key;
-		key_linepos++;
-		key_lines[edit_line][key_linepos] = 0;
-	}
-
-}
-
-//============================================================================
-
-qboolean	chat_team;
-char		chat_buffer[MAXCMDLINE];
-int			chat_bufferlen = 0;
-
-void Key_Message (int key)
-{
-
-	if ( key == K_ENTER || key == K_KP_ENTER )
-	{
-		if (chat_team)
-			Cbuf_AddText ("say_team \"");
-		else
-			Cbuf_AddText ("say \"");
-		Cbuf_AddText(chat_buffer);
-		Cbuf_AddText("\"\n");
-
-		cls.key_dest = key_game;
-		chat_bufferlen = 0;
-		chat_buffer[0] = 0;
-		return;
-	}
-
-	if (key == K_ESCAPE)
-	{
-		cls.key_dest = key_game;
-		chat_bufferlen = 0;
-		chat_buffer[0] = 0;
-		return;
-	}
-
-	if (key < 32 || key > 127)
-		return;	// non printable
-
-	if (key == K_BACKSPACE)
-	{
-		if (chat_bufferlen)
-		{
-			chat_bufferlen--;
-			chat_buffer[chat_bufferlen] = 0;
-		}
-		return;
-	}
-
-	if (chat_bufferlen == sizeof(chat_buffer)-1)
-		return; // all full
-
-	chat_buffer[chat_bufferlen++] = key;
-	chat_buffer[chat_bufferlen] = 0;
-}
-
-//============================================================================
-
-
-/*
-===================
-Key_StringToKeynum
-
-Returns a key number to be used to index keybindings[] by looking at
-the given string.  Single ascii characters return themselves, while
-the K_* names are matched up.
-===================
-*/
-int Key_StringToKeynum (char *str)
-{
-	keyname_t	*kn;
-	
-	if (!str || !str[0])
-		return -1;
-	if (!str[1])
-		return str[0];
-
-	for (kn=keynames ; kn->name ; kn++)
-	{
-		if (!cistrcmp(str,kn->name))
-			return kn->keynum;
-	}
-	return -1;
-}
-
-/*
-===================
-Key_KeynumToString
-
-Returns a string (either a single ascii char, or a K_* name) for the
-given keynum.
-FIXME: handle quote special (general escape sequence?)
-===================
-*/
-char *Key_KeynumToString (int keynum)
-{
-	keyname_t	*kn;	
-	static	char	tinystr[2];
-	
-	if (keynum == -1)
-		return "<KEY NOT FOUND>";
-	if (keynum > 32 && keynum < 127)
-	{	// printable ascii
-		tinystr[0] = keynum;
-		tinystr[1] = 0;
-		return tinystr;
-	}
-	
-	for (kn=keynames ; kn->name ; kn++)
-		if (keynum == kn->keynum)
-			return kn->name;
-
-	return "<UNKNOWN KEYNUM>";
-}
-
-
-/*
-===================
-Key_SetBinding
-===================
-*/
-void Key_SetBinding (int keynum, char *binding)
-{
-	char	*new;
-	int		l;
-			
-	if (keynum == -1)
-		return;
-
-// free old bindings
-	if (keybindings[keynum])
-	{
-		Z_Free (keybindings[keynum]);
-		keybindings[keynum] = NULL;
-	}
-			
-// allocate memory for new binding
-	l = strlen (binding);	
-	new = Z_Malloc (l+1);
-	strcpy (new, binding);
-	new[l] = 0;
-	keybindings[keynum] = new;	
-}
-
-/*
-===================
-Key_Unbind_f
-===================
-*/
-void Key_Unbind_f (void)
-{
-	int		b;
-
-	if (Cmd_Argc() != 2)
-	{
-		Com_Printf ("unbind <key> : remove commands from a key\n");
-		return;
-	}
-	
-	b = Key_StringToKeynum (Cmd_Argv(1));
-	if (b==-1)
-	{
-		Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
-		return;
-	}
-
-	Key_SetBinding (b, "");
-}
-
-void Key_Unbindall_f (void)
-{
-	int		i;
-	
-	for (i=0 ; i<256 ; i++)
-		if (keybindings[i])
-			Key_SetBinding (i, "");
-}
-
-
-/*
-===================
-Key_Bind_f
-===================
-*/
-void Key_Bind_f (void)
-{
-	int			i, c, b;
-	char		cmd[1024];
-	
-	c = Cmd_Argc();
-
-	if (c < 2)
-	{
-		Com_Printf ("bind <key> [command] : attach a command to a key\n");
-		return;
-	}
-	b = Key_StringToKeynum (Cmd_Argv(1));
-	if (b==-1)
-	{
-		Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
-		return;
-	}
-
-	if (c == 2)
-	{
-		if (keybindings[b])
-			Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
-		else
-			Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
-		return;
-	}
-	
-// copy the rest of the command line
-	cmd[0] = 0;		// start out with a null string
-	for (i=2 ; i< c ; i++)
-	{
-		strcat (cmd, Cmd_Argv(i));
-		if (i != (c-1))
-			strcat (cmd, " ");
-	}
-
-	Key_SetBinding (b, cmd);
-}
-
-/*
-============
-Key_WriteBindings
-
-Writes lines containing "bind key value"
-============
-*/
-void Key_WriteBindings (FILE *f)
-{
-	int		i;
-
-	for (i=0 ; i<256 ; i++)
-		if (keybindings[i] && keybindings[i][0])
-			fprintf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
-}
-
-
-/*
-============
-Key_Bindlist_f
-
-============
-*/
-void Key_Bindlist_f (void)
-{
-	int		i;
-
-	for (i=0 ; i<256 ; i++)
-		if (keybindings[i] && keybindings[i][0])
-			Com_Printf ("%s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
-}
-
-
-/*
-===================
-Key_Init
-===================
-*/
-void Key_Init (void)
-{
-	int		i;
-
-	for (i=0 ; i<32 ; i++)
-	{
-		key_lines[i][0] = ']';
-		key_lines[i][1] = 0;
-	}
-	key_linepos = 1;
-	
-//
-// init ascii characters in console mode
-//
-	for (i=32 ; i<128 ; i++)
-		consolekeys[i] = true;
-	consolekeys[K_ENTER] = true;
-	consolekeys[K_KP_ENTER] = true;
-	consolekeys[K_TAB] = true;
-	consolekeys[K_LEFTARROW] = true;
-	consolekeys[K_KP_LEFTARROW] = true;
-	consolekeys[K_RIGHTARROW] = true;
-	consolekeys[K_KP_RIGHTARROW] = true;
-	consolekeys[K_UPARROW] = true;
-	consolekeys[K_KP_UPARROW] = true;
-	consolekeys[K_DOWNARROW] = true;
-	consolekeys[K_KP_DOWNARROW] = true;
-	consolekeys[K_BACKSPACE] = true;
-	consolekeys[K_HOME] = true;
-	consolekeys[K_KP_HOME] = true;
-	consolekeys[K_END] = true;
-	consolekeys[K_KP_END] = true;
-	consolekeys[K_PGUP] = true;
-	consolekeys[K_KP_PGUP] = true;
-	consolekeys[K_PGDN] = true;
-	consolekeys[K_KP_PGDN] = true;
-	consolekeys[K_SHIFT] = true;
-	consolekeys[K_INS] = true;
-	consolekeys[K_KP_INS] = true;
-	consolekeys[K_KP_DEL] = true;
-	consolekeys[K_KP_SLASH] = true;
-	consolekeys[K_KP_PLUS] = true;
-	consolekeys[K_KP_MINUS] = true;
-	consolekeys[K_KP_5] = true;
-
-	consolekeys['`'] = false;
-	consolekeys['~'] = false;
-
-	for (i=0 ; i<256 ; i++)
-		keyshift[i] = i;
-	for (i='a' ; i<='z' ; i++)
-		keyshift[i] = i - 'a' + 'A';
-	keyshift['1'] = '!';
-	keyshift['2'] = '@';
-	keyshift['3'] = '#';
-	keyshift['4'] = '$';
-	keyshift['5'] = '%';
-	keyshift['6'] = '^';
-	keyshift['7'] = '&';
-	keyshift['8'] = '*';
-	keyshift['9'] = '(';
-	keyshift['0'] = ')';
-	keyshift['-'] = '_';
-	keyshift['='] = '+';
-	keyshift[','] = '<';
-	keyshift['.'] = '>';
-	keyshift['/'] = '?';
-	keyshift[';'] = ':';
-	keyshift['\''] = '"';
-	keyshift['['] = '{';
-	keyshift[']'] = '}';
-	keyshift['`'] = '~';
-	keyshift['\\'] = '|';
-
-	menubound[K_ESCAPE] = true;
-	for (i=0 ; i<12 ; i++)
-		menubound[K_F1+i] = true;
-
-//
-// register our functions
-//
-	Cmd_AddCommand ("bind",Key_Bind_f);
-	Cmd_AddCommand ("unbind",Key_Unbind_f);
-	Cmd_AddCommand ("unbindall",Key_Unbindall_f);
-	Cmd_AddCommand ("bindlist",Key_Bindlist_f);
-}
-
-/*
-===================
-Key_Event
-
-Called by the system between frames for both key up and key down events
-Should NOT be called during an interrupt!
-===================
-*/
-void Key_Event (int key, qboolean down, unsigned time)
-{
-	char	*kb;
-	char	cmd[1024];
-
-	// hack for modal presses
-	if (key_waiting == -1)
-	{
-		if (down)
-			key_waiting = key;
-		return;
-	}
-
-	// update auto-repeat status
-	if (down)
-	{
-		key_repeats[key]++;
-		if (key != K_BACKSPACE 
-			&& key != K_PAUSE 
-			&& key != K_PGUP 
-			&& key != K_KP_PGUP 
-			&& key != K_PGDN
-			&& key != K_KP_PGDN
-			&& key_repeats[key] > 1)
-			return;	// ignore most autorepeats
-			
-		if (key >= 200 && !keybindings[key])
-			Com_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
-	}
-	else
-	{
-		key_repeats[key] = 0;
-	}
-
-	if (key == K_SHIFT)
-		shift_down = down;
-
-	// console key is hardcoded, so the user can never unbind it
-	if (key == '`' || key == '~')
-	{
-		if (!down)
-			return;
-		Con_ToggleConsole_f ();
-		return;
-	}
-
-	// any key during the attract mode will bring up the menu
-	if (cl.attractloop && cls.key_dest != key_menu)
-		key = K_ESCAPE;
-
-	// menu key is hardcoded, so the user can never unbind it
-	if (key == K_ESCAPE)
-	{
-		if (!down)
-			return;
-
-		if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
-		{	// put away help computer / inventory
-			Cbuf_AddText ("cmd putaway\n");
-			return;
-		}
-		switch (cls.key_dest)
-		{
-		case key_message:
-			Key_Message (key);
-			break;
-		case key_menu:
-			M_Keydown (key);
-			break;
-		case key_game:
-		case key_console:
-			M_Menu_Main_f ();
-			break;
-		default:
-			Com_Error (ERR_FATAL, "Bad cls.key_dest");
-		}
-		return;
-	}
-
-	// track if any key is down for BUTTON_ANY
-	keydown[key] = down;
-	if (down)
-	{
-		if (key_repeats[key] == 1)
-			anykeydown++;
-	}
-	else
-	{
-		anykeydown--;
-		if (anykeydown < 0)
-			anykeydown = 0;
-	}
-
-//
-// key up events only generate commands if the game key binding is
-// a button command (leading + sign).  These will occur even in console mode,
-// to keep the character from continuing an action started before a console
-// switch.  Button commands include the kenum as a parameter, so multiple
-// downs can be matched with ups
-//
-	if (!down)
-	{
-		kb = keybindings[key];
-		if (kb && kb[0] == '+')
-		{
-			Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
-			Cbuf_AddText (cmd);
-		}
-		if (keyshift[key] != key)
-		{
-			kb = keybindings[keyshift[key]];
-			if (kb && kb[0] == '+')
-			{
-				Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
-				Cbuf_AddText (cmd);
-			}
-		}
-		return;
-	}
-
-//
-// if not a consolekey, send to the interpreter no matter what mode is
-//
-	if ( (cls.key_dest == key_menu && menubound[key])
-	|| (cls.key_dest == key_console && !consolekeys[key])
-	|| (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
-	{
-		kb = keybindings[key];
-		if (kb)
-		{
-			if (kb[0] == '+')
-			{	// button commands add keynum and time as a parm
-				Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
-				Cbuf_AddText (cmd);
-			}
-			else
-			{
-				Cbuf_AddText (kb);
-				Cbuf_AddText ("\n");
-			}
-		}
-		return;
-	}
-
-	if (!down)
-		return;		// other systems only care about key down events
-
-	if (shift_down)
-		key = keyshift[key];
-
-	switch (cls.key_dest)
-	{
-	case key_message:
-		Key_Message (key);
-		break;
-	case key_menu:
-		M_Keydown (key);
-		break;
-
-	case key_game:
-	case key_console:
-		Key_Console (key);
-		break;
-	default:
-		Com_Error (ERR_FATAL, "Bad cls.key_dest");
-	}
-}
-
-/*
-===================
-Key_ClearStates
-===================
-*/
-void Key_ClearStates (void)
-{
-	int		i;
-
-	anykeydown = false;
-
-	for (i=0 ; i<256 ; i++)
-	{
-		if ( keydown[i] || key_repeats[i] )
-			Key_Event( i, false, 0 );
-		keydown[i] = 0;
-		key_repeats[i] = 0;
-	}
-}
-
-
-/*
-===================
-Key_GetKey
-===================
-*/
-int Key_GetKey (void)
-{
-	key_waiting = -1;
-
-	while (key_waiting == -1)
-		Sys_SendKeyEvents ();
-
-	return key_waiting;
-}
-
--- a/client/keys.h
+++ /dev/null
@@ -1,125 +1,0 @@
-//
-// these are the key numbers that should be passed to Key_Event
-//
-#define	K_TAB			9
-#define	K_ENTER			13
-#define	K_ESCAPE		27
-#define	K_SPACE			32
-
-// normal keys should be passed as lowercased ascii
-
-#define	K_BACKSPACE		127
-#define	K_UPARROW		128
-#define	K_DOWNARROW		129
-#define	K_LEFTARROW		130
-#define	K_RIGHTARROW	131
-
-#define	K_ALT			132
-#define	K_CTRL			133
-#define	K_SHIFT			134
-#define	K_F1			135
-#define	K_F2			136
-#define	K_F3			137
-#define	K_F4			138
-#define	K_F5			139
-#define	K_F6			140
-#define	K_F7			141
-#define	K_F8			142
-#define	K_F9			143
-#define	K_F10			144
-#define	K_F11			145
-#define	K_F12			146
-#define	K_INS			147
-#define	K_DEL			148
-#define	K_PGDN			149
-#define	K_PGUP			150
-#define	K_HOME			151
-#define	K_END			152
-
-#define K_KP_HOME		160
-#define K_KP_UPARROW	161
-#define K_KP_PGUP		162
-#define	K_KP_LEFTARROW	163
-#define K_KP_5			164
-#define K_KP_RIGHTARROW	165
-#define K_KP_END		166
-#define K_KP_DOWNARROW	167
-#define K_KP_PGDN		168
-#define	K_KP_ENTER		169
-#define K_KP_INS   		170
-#define	K_KP_DEL		171
-#define K_KP_SLASH		172
-#define K_KP_MINUS		173
-#define K_KP_PLUS		174
-
-//
-// mouse buttons generate virtual keys
-//
-#define	K_MOUSE1		200
-#define	K_MOUSE3		201
-#define	K_MOUSE2		202
-#define K_MWHEELUP		203
-#define K_MWHEELDOWN		204
-
-//
-// joystick buttons
-//
-#define	K_JOY1			205
-#define	K_JOY2			206
-#define	K_JOY3			207
-#define	K_JOY4			208
-
-//
-// aux keys are for multi-buttoned joysticks to generate so they can use
-// the normal binding process
-//
-#define	K_AUX1			209
-#define	K_AUX2			210
-#define	K_AUX3			211
-#define	K_AUX4			212
-#define	K_AUX5			213
-#define	K_AUX6			214
-#define	K_AUX7			215
-#define	K_AUX8			216
-#define	K_AUX9			217
-#define	K_AUX10			218
-#define	K_AUX11			219
-#define	K_AUX12			220
-#define	K_AUX13			221
-#define	K_AUX14			222
-#define	K_AUX15			223
-#define	K_AUX16			224
-#define	K_AUX17			225
-#define	K_AUX18			226
-#define	K_AUX19			227
-#define	K_AUX20			228
-#define	K_AUX21			229
-#define	K_AUX22			230
-#define	K_AUX23			231
-#define	K_AUX24			232
-#define	K_AUX25			233
-#define	K_AUX26			234
-#define	K_AUX27			235
-#define	K_AUX28			236
-#define	K_AUX29			237
-#define	K_AUX30			238
-#define	K_AUX31			239
-#define	K_AUX32			240
-
-#define K_PAUSE			255
-
-extern char		*keybindings[256];
-extern	int		key_repeats[256];
-
-extern	int	anykeydown;
-extern char chat_buffer[];
-extern	int chat_bufferlen;
-extern	qboolean	chat_team;
-
-void Key_Event (int key, qboolean down, unsigned time);
-void Key_Init (void);
-void Key_WriteBindings (FILE *f);
-void Key_SetBinding (int keynum, char *binding);
-void Key_ClearStates (void);
-int Key_GetKey (void);
-
--- a/client/menu.c
+++ /dev/null
@@ -1,3997 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <ctype.h>
-#include "../q_shared.h"
-
-static int	m_main_cursor;
-
-#define NUM_CURSOR_FRAMES 15
-
-static char *menu_in_sound		= "misc/menu1.wav";
-static char *menu_move_sound	= "misc/menu2.wav";
-static char *menu_out_sound		= "misc/menu3.wav";
-
-void M_Menu_Main_f (void);
-	void M_Menu_Game_f (void);
-		void M_Menu_LoadGame_f (void);
-		void M_Menu_SaveGame_f (void);
-		void M_Menu_PlayerConfig_f (void);
-			void M_Menu_DownloadOptions_f (void);
-		void M_Menu_Credits_f( void );
-	void M_Menu_Multiplayer_f( void );
-		void M_Menu_JoinServer_f (void);
-			void M_Menu_AddressBook_f( void );
-		void M_Menu_StartServer_f (void);
-			void M_Menu_DMOptions_f (void);
-	void M_Menu_Video_f (void);
-	void M_Menu_Options_f (void);
-		void M_Menu_Keys_f (void);
-	void M_Menu_Quit_f (void);
-
-	void M_Menu_Credits( void );
-
-qboolean	m_entersound;		// play after drawing a frame, so caching
-								// won't disrupt the sound
-
-void	(*m_drawfunc) (void);
-const char *(*m_keyfunc) (int key);
-
-//=============================================================================
-/* Support Routines */
-
-#define	MAX_MENU_DEPTH	8
-
-
-typedef struct
-{
-	void	(*draw) (void);
-	const char *(*key) (int k);
-} menulayer_t;
-
-menulayer_t	m_layers[MAX_MENU_DEPTH];
-int		m_menudepth;
-
-static void M_Banner( char *name )
-{
-	int w, h;
-
-	re.DrawGetPicSize (&w, &h, name );
-	re.DrawPic( vid.width / 2 - w / 2, vid.height / 2 - 110, name );
-}
-
-void M_PushMenu ( void (*draw) (void), const char *(*key) (int k) )
-{
-	int		i;
-
-	if (Cvar_VariableValue ("maxclients") == 1 
-		&& Com_ServerState ())
-		Cvar_Set ("paused", "1");
-
-	// if this menu is already present, drop back to that level
-	// to avoid stacking menus by hotkeys
-	for (i=0 ; i<m_menudepth ; i++)
-		if (m_layers[i].draw == draw &&
-			m_layers[i].key == key)
-		{
-			m_menudepth = i;
-		}
-
-	if (i == m_menudepth)
-	{
-		if (m_menudepth >= MAX_MENU_DEPTH)
-			Com_Error (ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH");
-		m_layers[m_menudepth].draw = m_drawfunc;
-		m_layers[m_menudepth].key = m_keyfunc;
-		m_menudepth++;
-	}
-
-	m_drawfunc = draw;
-	m_keyfunc = key;
-
-	m_entersound = true;
-
-	cls.key_dest = key_menu;
-}
-
-void M_ForceMenuOff (void)
-{
-	m_drawfunc = 0;
-	m_keyfunc = 0;
-	cls.key_dest = key_game;
-	m_menudepth = 0;
-	Key_ClearStates ();
-	Cvar_Set ("paused", "0");
-	IN_Grabm (1);
-}
-
-void M_PopMenu (void)
-{
-	S_StartLocalSound( menu_out_sound );
-	if (m_menudepth < 1)
-		Com_Error (ERR_FATAL, "M_PopMenu: depth < 1");
-	m_menudepth--;
-
-	m_drawfunc = m_layers[m_menudepth].draw;
-	m_keyfunc = m_layers[m_menudepth].key;
-
-	if (!m_menudepth)
-		M_ForceMenuOff ();
-}
-
-
-const char *Default_MenuKey( menuframework_s *m, int key )
-{
-	const char *sound = NULL;
-	menucommon_s *item;
-
-	if ( m )
-	{
-		if ( ( item = Menu_ItemAtCursor( m ) ) != 0 )
-		{
-			if ( item->type == MTYPE_FIELD )
-			{
-				if ( Field_Key( ( menufield_s * ) item, key ) )
-					return NULL;
-			}
-		}
-	}
-
-	switch ( key )
-	{
-	case K_ESCAPE:
-		M_PopMenu();
-		return menu_out_sound;
-	case K_KP_UPARROW:
-	case K_UPARROW:
-		if ( m )
-		{
-			m->cursor--;
-			Menu_AdjustCursor( m, -1 );
-			sound = menu_move_sound;
-		}
-		break;
-	case K_TAB:
-		if ( m )
-		{
-			m->cursor++;
-			Menu_AdjustCursor( m, 1 );
-			sound = menu_move_sound;
-		}
-		break;
-	case K_KP_DOWNARROW:
-	case K_DOWNARROW:
-		if ( m )
-		{
-			m->cursor++;
-			Menu_AdjustCursor( m, 1 );
-			sound = menu_move_sound;
-		}
-		break;
-	case K_KP_LEFTARROW:
-	case K_LEFTARROW:
-		if ( m )
-		{
-			Menu_SlideItem( m, -1 );
-			sound = menu_move_sound;
-		}
-		break;
-	case K_KP_RIGHTARROW:
-	case K_RIGHTARROW:
-		if ( m )
-		{
-			Menu_SlideItem( m, 1 );
-			sound = menu_move_sound;
-		}
-		break;
-
-	case K_MOUSE1:
-	case K_MOUSE2:
-	case K_MOUSE3:
-	case K_JOY1:
-	case K_JOY2:
-	case K_JOY3:
-	case K_JOY4:
-	case K_AUX1:
-	case K_AUX2:
-	case K_AUX3:
-	case K_AUX4:
-	case K_AUX5:
-	case K_AUX6:
-	case K_AUX7:
-	case K_AUX8:
-	case K_AUX9:
-	case K_AUX10:
-	case K_AUX11:
-	case K_AUX12:
-	case K_AUX13:
-	case K_AUX14:
-	case K_AUX15:
-	case K_AUX16:
-	case K_AUX17:
-	case K_AUX18:
-	case K_AUX19:
-	case K_AUX20:
-	case K_AUX21:
-	case K_AUX22:
-	case K_AUX23:
-	case K_AUX24:
-	case K_AUX25:
-	case K_AUX26:
-	case K_AUX27:
-	case K_AUX28:
-	case K_AUX29:
-	case K_AUX30:
-	case K_AUX31:
-	case K_AUX32:
-		
-	case K_KP_ENTER:
-	case K_ENTER:
-		if ( m )
-			Menu_SelectItem( m );
-		sound = menu_move_sound;
-		break;
-	}
-
-	return sound;
-}
-
-//=============================================================================
-
-/*
-================
-M_DrawCharacter
-
-Draws one solid graphics character
-cx and cy are in 320*240 coordinates, and will be centered on
-higher res screens.
-================
-*/
-void M_DrawCharacter (int cx, int cy, int num)
-{
-	re.DrawChar ( cx + ((vid.width - 320)>>1), cy + ((vid.height - 240)>>1), num);
-}
-
-void M_Print (int cx, int cy, char *str)
-{
-	while (*str)
-	{
-		M_DrawCharacter (cx, cy, (*str)+128);
-		str++;
-		cx += 8;
-	}
-}
-
-void M_PrintWhite (int cx, int cy, char *str)
-{
-	while (*str)
-	{
-		M_DrawCharacter (cx, cy, *str);
-		str++;
-		cx += 8;
-	}
-}
-
-void M_DrawPic (int x, int y, char *pic)
-{
-	re.DrawPic (x + ((vid.width - 320)>>1), y + ((vid.height - 240)>>1), pic);
-}
-
-
-/*
-=============
-M_DrawCursor
-
-Draws an animating cursor with the point at
-x,y.  The pic will extend to the left of x,
-and both above and below y.
-=============
-*/
-void M_DrawCursor( int x, int y, int f )
-{
-	char	cursorname[80];
-	static qboolean cached;
-
-	if ( !cached )
-	{
-		int i;
-
-		for ( i = 0; i < NUM_CURSOR_FRAMES; i++ )
-		{
-			Com_sprintf( cursorname, sizeof( cursorname ), "m_cursor%d", i );
-
-			re.RegisterPic( cursorname );
-		}
-		cached = true;
-	}
-
-	Com_sprintf( cursorname, sizeof(cursorname), "m_cursor%d", f );
-	re.DrawPic( x, y, cursorname );
-}
-
-void M_DrawTextBox (int x, int y, int width, int lines)
-{
-	int		cx, cy;
-	int		n;
-
-	// draw left side
-	cx = x;
-	cy = y;
-	M_DrawCharacter (cx, cy, 1);
-	for (n = 0; n < lines; n++)
-	{
-		cy += 8;
-		M_DrawCharacter (cx, cy, 4);
-	}
-	M_DrawCharacter (cx, cy+8, 7);
-
-	// draw middle
-	cx += 8;
-	while (width > 0)
-	{
-		cy = y;
-		M_DrawCharacter (cx, cy, 2);
-		for (n = 0; n < lines; n++)
-		{
-			cy += 8;
-			M_DrawCharacter (cx, cy, 5);
-		}
-		M_DrawCharacter (cx, cy+8, 8);
-		width -= 1;
-		cx += 8;
-	}
-
-	// draw right side
-	cy = y;
-	M_DrawCharacter (cx, cy, 3);
-	for (n = 0; n < lines; n++)
-	{
-		cy += 8;
-		M_DrawCharacter (cx, cy, 6);
-	}
-	M_DrawCharacter (cx, cy+8, 9);
-}
-
-		
-/*
-=======================================================================
-
-MAIN MENU
-
-=======================================================================
-*/
-#define	MAIN_ITEMS	5
-
-
-void M_Main_Draw (void)
-{
-	int i;
-	int w, h;
-	int ystart;
-	int	xoffset;
-	int widest = -1;
-	int totalheight = 0;
-	char litname[80];
-	char *names[] =
-	{
-		"m_main_game",
-		"m_main_multiplayer",
-		"m_main_options",
-		"m_main_video",
-		"m_main_quit",
-		0
-	};
-
-	for ( i = 0; names[i] != 0; i++ )
-	{
-		re.DrawGetPicSize( &w, &h, names[i] );
-
-		if ( w > widest )
-			widest = w;
-		totalheight += ( h + 12 );
-	}
-
-	ystart = ( vid.height / 2 - 110 );
-	xoffset = ( vid.width - widest + 70 ) / 2;
-
-	for ( i = 0; names[i] != 0; i++ )
-	{
-		if ( i != m_main_cursor )
-			re.DrawPic( xoffset, ystart + i * 40 + 13, names[i] );
-	}
-	strcpy( litname, names[m_main_cursor] );
-	strcat( litname, "_sel" );
-	re.DrawPic( xoffset, ystart + m_main_cursor * 40 + 13, litname );
-
-	M_DrawCursor( xoffset - 25, ystart + m_main_cursor * 40 + 11, (int)(cls.realtime / 100)%NUM_CURSOR_FRAMES );
-
-	re.DrawGetPicSize( &w, &h, "m_main_plaque" );
-	re.DrawPic( xoffset - 30 - w, ystart, "m_main_plaque" );
-
-	re.DrawPic( xoffset - 30 - w, ystart + h + 5, "m_main_logo" );
-}
-
-
-const char *M_Main_Key (int key)
-{
-	const char *sound = menu_move_sound;
-
-	switch (key)
-	{
-	case K_ESCAPE:
-		M_PopMenu ();
-		break;
-
-	case K_KP_DOWNARROW:
-	case K_DOWNARROW:
-		if (++m_main_cursor >= MAIN_ITEMS)
-			m_main_cursor = 0;
-		return sound;
-
-	case K_KP_UPARROW:
-	case K_UPARROW:
-		if (--m_main_cursor < 0)
-			m_main_cursor = MAIN_ITEMS - 1;
-		return sound;
-
-	case K_KP_ENTER:
-	case K_ENTER:
-		m_entersound = true;
-
-		switch (m_main_cursor)
-		{
-		case 0:
-			M_Menu_Game_f ();
-			break;
-
-		case 1:
-			M_Menu_Multiplayer_f();
-			break;
-
-		case 2:
-			M_Menu_Options_f ();
-			break;
-
-		case 3:
-			M_Menu_Video_f ();
-			break;
-
-		case 4:
-			M_Menu_Quit_f ();
-			break;
-		}
-	}
-
-	return NULL;
-}
-
-
-void M_Menu_Main_f (void)
-{
-	IN_Grabm (0);
-	M_PushMenu (M_Main_Draw, M_Main_Key);
-}
-
-/*
-=======================================================================
-
-MULTIPLAYER MENU
-
-=======================================================================
-*/
-static menuframework_s	s_multiplayer_menu;
-static menuaction_s		s_join_network_server_action;
-static menuaction_s		s_start_network_server_action;
-static menuaction_s		s_player_setup_action;
-
-static void Multiplayer_MenuDraw (void)
-{
-	M_Banner( "m_banner_multiplayer" );
-
-	Menu_AdjustCursor( &s_multiplayer_menu, 1 );
-	Menu_Draw( &s_multiplayer_menu );
-}
-
-static void PlayerSetupFunc( void * )
-{
-	M_Menu_PlayerConfig_f();
-}
-
-static void JoinNetworkServerFunc( void * )
-{
-	M_Menu_JoinServer_f();
-}
-
-static void StartNetworkServerFunc( void * )
-{
-	M_Menu_StartServer_f ();
-}
-
-void Multiplayer_MenuInit( void )
-{
-	s_multiplayer_menu.x = vid.width * 0.50 - 64;
-	s_multiplayer_menu.nitems = 0;
-
-	s_join_network_server_action.generic.type	= MTYPE_ACTION;
-	s_join_network_server_action.generic.flags  = QMF_LEFT_JUSTIFY;
-	s_join_network_server_action.generic.x		= 0;
-	s_join_network_server_action.generic.y		= 0;
-	s_join_network_server_action.generic.name	= " join network server";
-	s_join_network_server_action.generic.callback = JoinNetworkServerFunc;
-
-	s_start_network_server_action.generic.type	= MTYPE_ACTION;
-	s_start_network_server_action.generic.flags  = QMF_LEFT_JUSTIFY;
-	s_start_network_server_action.generic.x		= 0;
-	s_start_network_server_action.generic.y		= 10;
-	s_start_network_server_action.generic.name	= " start network server";
-	s_start_network_server_action.generic.callback = StartNetworkServerFunc;
-
-	s_player_setup_action.generic.type	= MTYPE_ACTION;
-	s_player_setup_action.generic.flags  = QMF_LEFT_JUSTIFY;
-	s_player_setup_action.generic.x		= 0;
-	s_player_setup_action.generic.y		= 20;
-	s_player_setup_action.generic.name	= " player setup";
-	s_player_setup_action.generic.callback = PlayerSetupFunc;
-
-	Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_join_network_server_action );
-	Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_start_network_server_action );
-	Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_player_setup_action );
-
-	Menu_SetStatusBar( &s_multiplayer_menu, NULL );
-
-	Menu_Center( &s_multiplayer_menu );
-}
-
-const char *Multiplayer_MenuKey( int key )
-{
-	return Default_MenuKey( &s_multiplayer_menu, key );
-}
-
-void M_Menu_Multiplayer_f( void )
-{
-	Multiplayer_MenuInit();
-	M_PushMenu( Multiplayer_MenuDraw, Multiplayer_MenuKey );
-}
-
-/*
-=======================================================================
-
-KEYS MENU
-
-=======================================================================
-*/
-char *bindnames[][2] =
-{
-{"+attack", 		"attack"},
-{"weapnext", 		"next weapon"},
-{"+forward", 		"walk forward"},
-{"+back", 			"backpedal"},
-{"+left", 			"turn left"},
-{"+right", 			"turn right"},
-{"+speed", 			"run"},
-{"+moveleft", 		"step left"},
-{"+moveright", 		"step right"},
-{"+strafe", 		"sidestep"},
-{"+lookup", 		"look up"},
-{"+lookdown", 		"look down"},
-{"centerview", 		"center view"},
-{"+mlook", 			"mouse look"},
-{"+klook", 			"keyboard look"},
-{"+moveup",			"up / jump"},
-{"+movedown",		"down / crouch"},
-
-{"inven",			"inventory"},
-{"invuse",			"use item"},
-{"invdrop",			"drop item"},
-{"invprev",			"prev item"},
-{"invnext",			"next item"},
-
-{"cmd help", 		"help computer" }, 
-{ 0, 0 }
-};
-
-int				keys_cursor;
-static int		bind_grab;
-
-static menuframework_s	s_keys_menu;
-static menuaction_s		s_keys_attack_action;
-static menuaction_s		s_keys_change_weapon_action;
-static menuaction_s		s_keys_walk_forward_action;
-static menuaction_s		s_keys_backpedal_action;
-static menuaction_s		s_keys_turn_left_action;
-static menuaction_s		s_keys_turn_right_action;
-static menuaction_s		s_keys_run_action;
-static menuaction_s		s_keys_step_left_action;
-static menuaction_s		s_keys_step_right_action;
-static menuaction_s		s_keys_sidestep_action;
-static menuaction_s		s_keys_look_up_action;
-static menuaction_s		s_keys_look_down_action;
-static menuaction_s		s_keys_center_view_action;
-static menuaction_s		s_keys_mouse_look_action;
-static menuaction_s		s_keys_keyboard_look_action;
-static menuaction_s		s_keys_move_up_action;
-static menuaction_s		s_keys_move_down_action;
-static menuaction_s		s_keys_inventory_action;
-static menuaction_s		s_keys_inv_use_action;
-static menuaction_s		s_keys_inv_drop_action;
-static menuaction_s		s_keys_inv_prev_action;
-static menuaction_s		s_keys_inv_next_action;
-
-static menuaction_s		s_keys_help_computer_action;
-
-static void M_UnbindCommand (char *command)
-{
-	int		j;
-	int		l;
-	char	*b;
-
-	l = strlen(command);
-
-	for (j=0 ; j<256 ; j++)
-	{
-		b = keybindings[j];
-		if (!b)
-			continue;
-		if (!strncmp (b, command, l) )
-			Key_SetBinding (j, "");
-	}
-}
-
-static void M_FindKeysForCommand (char *command, int *twokeys)
-{
-	int		count;
-	int		j;
-	int		l;
-	char	*b;
-
-	twokeys[0] = twokeys[1] = -1;
-	l = strlen(command);
-	count = 0;
-
-	for (j=0 ; j<256 ; j++)
-	{
-		b = keybindings[j];
-		if (!b)
-			continue;
-		if (!strncmp (b, command, l) )
-		{
-			twokeys[count] = j;
-			count++;
-			if (count == 2)
-				break;
-		}
-	}
-}
-
-static void KeyCursorDrawFunc( menuframework_s *menu )
-{
-	if ( bind_grab )
-		re.DrawChar( menu->x, menu->y + menu->cursor * 9, '=' );
-	else
-		re.DrawChar( menu->x, menu->y + menu->cursor * 9, 12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ) );
-}
-
-static void DrawKeyBindingFunc( void *self )
-{
-	int keys[2];
-	menuaction_s *a = ( menuaction_s * ) self;
-
-	M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys);
-		
-	if (keys[0] == -1)
-	{
-		Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, "???" );
-	}
-	else
-	{
-		int x;
-		const char *name;
-
-		name = Key_KeynumToString (keys[0]);
-
-		Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, name );
-
-		x = strlen(name) * 8;
-
-		if (keys[1] != -1)
-		{
-			Menu_DrawString( a->generic.x + a->generic.parent->x + 24 + x, a->generic.y + a->generic.parent->y, "or" );
-			Menu_DrawString( a->generic.x + a->generic.parent->x + 48 + x, a->generic.y + a->generic.parent->y, Key_KeynumToString (keys[1]) );
-		}
-	}
-}
-
-static void KeyBindingFunc( void *self )
-{
-	menuaction_s *a = ( menuaction_s * ) self;
-	int keys[2];
-
-	M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys );
-
-	if (keys[1] != -1)
-		M_UnbindCommand( bindnames[a->generic.localdata[0]][0]);
-
-	bind_grab = true;
-
-	Menu_SetStatusBar( &s_keys_menu, "press a key or button for this action" );
-}
-
-static void Keys_MenuInit( void )
-{
-	int y = 0;
-	int i = 0;
-
-	s_keys_menu.x = vid.width * 0.50;
-	s_keys_menu.nitems = 0;
-	s_keys_menu.cursordraw = KeyCursorDrawFunc;
-
-	s_keys_attack_action.generic.type	= MTYPE_ACTION;
-	s_keys_attack_action.generic.flags  = QMF_GRAYED;
-	s_keys_attack_action.generic.x		= 0;
-	s_keys_attack_action.generic.y		= y;
-	s_keys_attack_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_attack_action.generic.localdata[0] = i;
-	s_keys_attack_action.generic.name	= bindnames[s_keys_attack_action.generic.localdata[0]][1];
-
-	s_keys_change_weapon_action.generic.type	= MTYPE_ACTION;
-	s_keys_change_weapon_action.generic.flags  = QMF_GRAYED;
-	s_keys_change_weapon_action.generic.x		= 0;
-	s_keys_change_weapon_action.generic.y		= y += 9;
-	s_keys_change_weapon_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_change_weapon_action.generic.localdata[0] = ++i;
-	s_keys_change_weapon_action.generic.name	= bindnames[s_keys_change_weapon_action.generic.localdata[0]][1];
-
-	s_keys_walk_forward_action.generic.type	= MTYPE_ACTION;
-	s_keys_walk_forward_action.generic.flags  = QMF_GRAYED;
-	s_keys_walk_forward_action.generic.x		= 0;
-	s_keys_walk_forward_action.generic.y		= y += 9;
-	s_keys_walk_forward_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_walk_forward_action.generic.localdata[0] = ++i;
-	s_keys_walk_forward_action.generic.name	= bindnames[s_keys_walk_forward_action.generic.localdata[0]][1];
-
-	s_keys_backpedal_action.generic.type	= MTYPE_ACTION;
-	s_keys_backpedal_action.generic.flags  = QMF_GRAYED;
-	s_keys_backpedal_action.generic.x		= 0;
-	s_keys_backpedal_action.generic.y		= y += 9;
-	s_keys_backpedal_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_backpedal_action.generic.localdata[0] = ++i;
-	s_keys_backpedal_action.generic.name	= bindnames[s_keys_backpedal_action.generic.localdata[0]][1];
-
-	s_keys_turn_left_action.generic.type	= MTYPE_ACTION;
-	s_keys_turn_left_action.generic.flags  = QMF_GRAYED;
-	s_keys_turn_left_action.generic.x		= 0;
-	s_keys_turn_left_action.generic.y		= y += 9;
-	s_keys_turn_left_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_turn_left_action.generic.localdata[0] = ++i;
-	s_keys_turn_left_action.generic.name	= bindnames[s_keys_turn_left_action.generic.localdata[0]][1];
-
-	s_keys_turn_right_action.generic.type	= MTYPE_ACTION;
-	s_keys_turn_right_action.generic.flags  = QMF_GRAYED;
-	s_keys_turn_right_action.generic.x		= 0;
-	s_keys_turn_right_action.generic.y		= y += 9;
-	s_keys_turn_right_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_turn_right_action.generic.localdata[0] = ++i;
-	s_keys_turn_right_action.generic.name	= bindnames[s_keys_turn_right_action.generic.localdata[0]][1];
-
-	s_keys_run_action.generic.type	= MTYPE_ACTION;
-	s_keys_run_action.generic.flags  = QMF_GRAYED;
-	s_keys_run_action.generic.x		= 0;
-	s_keys_run_action.generic.y		= y += 9;
-	s_keys_run_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_run_action.generic.localdata[0] = ++i;
-	s_keys_run_action.generic.name	= bindnames[s_keys_run_action.generic.localdata[0]][1];
-
-	s_keys_step_left_action.generic.type	= MTYPE_ACTION;
-	s_keys_step_left_action.generic.flags  = QMF_GRAYED;
-	s_keys_step_left_action.generic.x		= 0;
-	s_keys_step_left_action.generic.y		= y += 9;
-	s_keys_step_left_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_step_left_action.generic.localdata[0] = ++i;
-	s_keys_step_left_action.generic.name	= bindnames[s_keys_step_left_action.generic.localdata[0]][1];
-
-	s_keys_step_right_action.generic.type	= MTYPE_ACTION;
-	s_keys_step_right_action.generic.flags  = QMF_GRAYED;
-	s_keys_step_right_action.generic.x		= 0;
-	s_keys_step_right_action.generic.y		= y += 9;
-	s_keys_step_right_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_step_right_action.generic.localdata[0] = ++i;
-	s_keys_step_right_action.generic.name	= bindnames[s_keys_step_right_action.generic.localdata[0]][1];
-
-	s_keys_sidestep_action.generic.type	= MTYPE_ACTION;
-	s_keys_sidestep_action.generic.flags  = QMF_GRAYED;
-	s_keys_sidestep_action.generic.x		= 0;
-	s_keys_sidestep_action.generic.y		= y += 9;
-	s_keys_sidestep_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_sidestep_action.generic.localdata[0] = ++i;
-	s_keys_sidestep_action.generic.name	= bindnames[s_keys_sidestep_action.generic.localdata[0]][1];
-
-	s_keys_look_up_action.generic.type	= MTYPE_ACTION;
-	s_keys_look_up_action.generic.flags  = QMF_GRAYED;
-	s_keys_look_up_action.generic.x		= 0;
-	s_keys_look_up_action.generic.y		= y += 9;
-	s_keys_look_up_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_look_up_action.generic.localdata[0] = ++i;
-	s_keys_look_up_action.generic.name	= bindnames[s_keys_look_up_action.generic.localdata[0]][1];
-
-	s_keys_look_down_action.generic.type	= MTYPE_ACTION;
-	s_keys_look_down_action.generic.flags  = QMF_GRAYED;
-	s_keys_look_down_action.generic.x		= 0;
-	s_keys_look_down_action.generic.y		= y += 9;
-	s_keys_look_down_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_look_down_action.generic.localdata[0] = ++i;
-	s_keys_look_down_action.generic.name	= bindnames[s_keys_look_down_action.generic.localdata[0]][1];
-
-	s_keys_center_view_action.generic.type	= MTYPE_ACTION;
-	s_keys_center_view_action.generic.flags  = QMF_GRAYED;
-	s_keys_center_view_action.generic.x		= 0;
-	s_keys_center_view_action.generic.y		= y += 9;
-	s_keys_center_view_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_center_view_action.generic.localdata[0] = ++i;
-	s_keys_center_view_action.generic.name	= bindnames[s_keys_center_view_action.generic.localdata[0]][1];
-
-	s_keys_mouse_look_action.generic.type	= MTYPE_ACTION;
-	s_keys_mouse_look_action.generic.flags  = QMF_GRAYED;
-	s_keys_mouse_look_action.generic.x		= 0;
-	s_keys_mouse_look_action.generic.y		= y += 9;
-	s_keys_mouse_look_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_mouse_look_action.generic.localdata[0] = ++i;
-	s_keys_mouse_look_action.generic.name	= bindnames[s_keys_mouse_look_action.generic.localdata[0]][1];
-
-	s_keys_keyboard_look_action.generic.type	= MTYPE_ACTION;
-	s_keys_keyboard_look_action.generic.flags  = QMF_GRAYED;
-	s_keys_keyboard_look_action.generic.x		= 0;
-	s_keys_keyboard_look_action.generic.y		= y += 9;
-	s_keys_keyboard_look_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_keyboard_look_action.generic.localdata[0] = ++i;
-	s_keys_keyboard_look_action.generic.name	= bindnames[s_keys_keyboard_look_action.generic.localdata[0]][1];
-
-	s_keys_move_up_action.generic.type	= MTYPE_ACTION;
-	s_keys_move_up_action.generic.flags  = QMF_GRAYED;
-	s_keys_move_up_action.generic.x		= 0;
-	s_keys_move_up_action.generic.y		= y += 9;
-	s_keys_move_up_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_move_up_action.generic.localdata[0] = ++i;
-	s_keys_move_up_action.generic.name	= bindnames[s_keys_move_up_action.generic.localdata[0]][1];
-
-	s_keys_move_down_action.generic.type	= MTYPE_ACTION;
-	s_keys_move_down_action.generic.flags  = QMF_GRAYED;
-	s_keys_move_down_action.generic.x		= 0;
-	s_keys_move_down_action.generic.y		= y += 9;
-	s_keys_move_down_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_move_down_action.generic.localdata[0] = ++i;
-	s_keys_move_down_action.generic.name	= bindnames[s_keys_move_down_action.generic.localdata[0]][1];
-
-	s_keys_inventory_action.generic.type	= MTYPE_ACTION;
-	s_keys_inventory_action.generic.flags  = QMF_GRAYED;
-	s_keys_inventory_action.generic.x		= 0;
-	s_keys_inventory_action.generic.y		= y += 9;
-	s_keys_inventory_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_inventory_action.generic.localdata[0] = ++i;
-	s_keys_inventory_action.generic.name	= bindnames[s_keys_inventory_action.generic.localdata[0]][1];
-
-	s_keys_inv_use_action.generic.type	= MTYPE_ACTION;
-	s_keys_inv_use_action.generic.flags  = QMF_GRAYED;
-	s_keys_inv_use_action.generic.x		= 0;
-	s_keys_inv_use_action.generic.y		= y += 9;
-	s_keys_inv_use_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_inv_use_action.generic.localdata[0] = ++i;
-	s_keys_inv_use_action.generic.name	= bindnames[s_keys_inv_use_action.generic.localdata[0]][1];
-
-	s_keys_inv_drop_action.generic.type	= MTYPE_ACTION;
-	s_keys_inv_drop_action.generic.flags  = QMF_GRAYED;
-	s_keys_inv_drop_action.generic.x		= 0;
-	s_keys_inv_drop_action.generic.y		= y += 9;
-	s_keys_inv_drop_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_inv_drop_action.generic.localdata[0] = ++i;
-	s_keys_inv_drop_action.generic.name	= bindnames[s_keys_inv_drop_action.generic.localdata[0]][1];
-
-	s_keys_inv_prev_action.generic.type	= MTYPE_ACTION;
-	s_keys_inv_prev_action.generic.flags  = QMF_GRAYED;
-	s_keys_inv_prev_action.generic.x		= 0;
-	s_keys_inv_prev_action.generic.y		= y += 9;
-	s_keys_inv_prev_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_inv_prev_action.generic.localdata[0] = ++i;
-	s_keys_inv_prev_action.generic.name	= bindnames[s_keys_inv_prev_action.generic.localdata[0]][1];
-
-	s_keys_inv_next_action.generic.type	= MTYPE_ACTION;
-	s_keys_inv_next_action.generic.flags  = QMF_GRAYED;
-	s_keys_inv_next_action.generic.x		= 0;
-	s_keys_inv_next_action.generic.y		= y += 9;
-	s_keys_inv_next_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_inv_next_action.generic.localdata[0] = ++i;
-	s_keys_inv_next_action.generic.name	= bindnames[s_keys_inv_next_action.generic.localdata[0]][1];
-
-	s_keys_help_computer_action.generic.type	= MTYPE_ACTION;
-	s_keys_help_computer_action.generic.flags  = QMF_GRAYED;
-	s_keys_help_computer_action.generic.x		= 0;
-	s_keys_help_computer_action.generic.y		= y += 9;
-	s_keys_help_computer_action.generic.ownerdraw = DrawKeyBindingFunc;
-	s_keys_help_computer_action.generic.localdata[0] = ++i;
-	s_keys_help_computer_action.generic.name	= bindnames[s_keys_help_computer_action.generic.localdata[0]][1];
-
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_attack_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_change_weapon_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_walk_forward_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_backpedal_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_left_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_right_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_run_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_left_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_right_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_sidestep_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_up_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_down_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_center_view_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_mouse_look_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_keyboard_look_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_up_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_down_action );
-
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inventory_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_use_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_drop_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_prev_action );
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_next_action );
-
-	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_help_computer_action );
-	
-	Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
-	Menu_Center( &s_keys_menu );
-}
-
-static void Keys_MenuDraw (void)
-{
-	Menu_AdjustCursor( &s_keys_menu, 1 );
-	Menu_Draw( &s_keys_menu );
-}
-
-static const char *Keys_MenuKey( int key )
-{
-	menuaction_s *item = ( menuaction_s * ) Menu_ItemAtCursor( &s_keys_menu );
-
-	if ( bind_grab )
-	{	
-		if ( key != K_ESCAPE && key != '`' )
-		{
-			char cmd[1024];
-
-			Com_sprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item->generic.localdata[0]][0]);
-			Cbuf_InsertText (cmd);
-		}
-		
-		Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
-		bind_grab = false;
-		return menu_out_sound;
-	}
-
-	switch ( key )
-	{
-	case K_KP_ENTER:
-	case K_ENTER:
-		KeyBindingFunc( item );
-		return menu_in_sound;
-	case K_BACKSPACE:		// delete bindings
-	case K_DEL:				// delete bindings
-	case K_KP_DEL:
-		M_UnbindCommand( bindnames[item->generic.localdata[0]][0] );
-		return menu_out_sound;
-	default:
-		return Default_MenuKey( &s_keys_menu, key );
-	}
-}
-
-void M_Menu_Keys_f (void)
-{
-	Keys_MenuInit();
-	M_PushMenu( Keys_MenuDraw, Keys_MenuKey );
-}
-
-
-/*
-=======================================================================
-
-CONTROLS MENU
-
-=======================================================================
-*/
-static cvar_t *win_noalttab;
-
-static menuframework_s	s_options_menu;
-static menuaction_s		s_options_defaults_action;
-static menuaction_s		s_options_customize_options_action;
-static menuslider_s		s_options_sensitivity_slider;
-static menulist_s		s_options_freelook_box;
-static menulist_s		s_options_noalttab_box;
-static menulist_s		s_options_alwaysrun_box;
-static menulist_s		s_options_invertmouse_box;
-static menulist_s		s_options_lookspring_box;
-static menulist_s		s_options_lookstrafe_box;
-static menulist_s		s_options_crosshair_box;
-static menuslider_s		s_options_sfxvolume_slider;
-static menulist_s		s_options_joystick_box;
-static menulist_s		s_options_cdvolume_box;
-static menulist_s		s_options_quality_list;
-static menulist_s		s_options_compatibility_list;
-static menulist_s		s_options_console_action;
-
-static void CrosshairFunc( void * )
-{
-	Cvar_SetValue( "crosshair", s_options_crosshair_box.curvalue );
-}
-
-static void JoystickFunc( void * )
-{
-	Cvar_SetValue( "in_joystick", s_options_joystick_box.curvalue );
-}
-
-static void CustomizeControlsFunc( void * )
-{
-	M_Menu_Keys_f();
-}
-
-static void AlwaysRunFunc( void * )
-{
-	Cvar_SetValue( "cl_run", s_options_alwaysrun_box.curvalue );
-}
-
-static void FreeLookFunc( void * )
-{
-	Cvar_SetValue( "freelook", s_options_freelook_box.curvalue );
-}
-
-static void MouseSpeedFunc( void * )
-{
-	Cvar_SetValue( "sensitivity", s_options_sensitivity_slider.curvalue / 2.0F );
-}
-
-static void NoAltTabFunc( void * )
-{
-	Cvar_SetValue( "win_noalttab", s_options_noalttab_box.curvalue );
-}
-
-static float ClampCvar( float min, float max, float value )
-{
-	if ( value < min ) return min;
-	if ( value > max ) return max;
-	return value;
-}
-
-static void ControlsSetMenuItemValues( void )
-{
-	s_options_sfxvolume_slider.curvalue		= Cvar_VariableValue( "s_volume" ) * 10;
-	s_options_cdvolume_box.curvalue 		= !Cvar_VariableValue("cd_nocd");
-	s_options_quality_list.curvalue			= !Cvar_VariableValue( "s_loadas8bit" );
-	s_options_sensitivity_slider.curvalue	= ( sensitivity->value ) * 2;
-
-	Cvar_SetValue( "cl_run", ClampCvar( 0, 1, cl_run->value ) );
-	s_options_alwaysrun_box.curvalue		= cl_run->value;
-
-	s_options_invertmouse_box.curvalue		= m_pitch->value < 0;
-
-	Cvar_SetValue( "lookspring", ClampCvar( 0, 1, lookspring->value ) );
-	s_options_lookspring_box.curvalue		= lookspring->value;
-
-	Cvar_SetValue( "lookstrafe", ClampCvar( 0, 1, lookstrafe->value ) );
-	s_options_lookstrafe_box.curvalue		= lookstrafe->value;
-
-	Cvar_SetValue( "freelook", ClampCvar( 0, 1, freelook->value ) );
-	s_options_freelook_box.curvalue			= freelook->value;
-
-	Cvar_SetValue( "crosshair", ClampCvar( 0, 3, crosshair->value ) );
-	s_options_crosshair_box.curvalue		= crosshair->value;
-
-	Cvar_SetValue( "in_joystick", ClampCvar( 0, 1, in_joystick->value ) );
-	s_options_joystick_box.curvalue		= in_joystick->value;
-
-	s_options_noalttab_box.curvalue			= win_noalttab->value;
-}
-
-static void ControlsResetDefaultsFunc( void * )
-{
-	Cbuf_AddText ("exec default.cfg\n");
-	Cbuf_Execute();
-
-	ControlsSetMenuItemValues();
-}
-
-static void InvertMouseFunc( void * )
-{
-	if ( s_options_invertmouse_box.curvalue == 0 )
-	{
-		Cvar_SetValue( "m_pitch", fabs( m_pitch->value ) );
-	}
-	else
-	{
-		Cvar_SetValue( "m_pitch", -fabs( m_pitch->value ) );
-	}
-}
-
-static void LookspringFunc( void * )
-{
-	Cvar_SetValue( "lookspring", s_options_lookspring_box.curvalue );
-}
-
-static void LookstrafeFunc( void * )
-{
-	Cvar_SetValue( "lookstrafe", s_options_lookstrafe_box.curvalue );
-}
-
-static void UpdateVolumeFunc( void * )
-{
-	Cvar_SetValue( "s_volume", s_options_sfxvolume_slider.curvalue / 10 );
-}
-
-static void UpdateCDVolumeFunc( void * )
-{
-	Cvar_SetValue( "cd_nocd", !s_options_cdvolume_box.curvalue );
-}
-
-static void ConsoleFunc( void * )
-{
-	/*
-	** the proper way to do this is probably to have ToggleConsole_f accept a parameter
-	*/
-	extern void Key_ClearTyping( void );
-
-	if ( cl.attractloop )
-	{
-		Cbuf_AddText ("killserver\n");
-		return;
-	}
-
-	Key_ClearTyping ();
-	Con_ClearNotify ();
-
-	M_ForceMenuOff ();
-	cls.key_dest = key_console;
-}
-
-static void UpdateSoundQualityFunc( void * )
-{
-	if ( s_options_quality_list.curvalue )
-	{
-		Cvar_SetValue( "s_khz", 22 );
-		Cvar_SetValue( "s_loadas8bit", false );
-	}
-	else
-	{
-		Cvar_SetValue( "s_khz", 11 );
-		Cvar_SetValue( "s_loadas8bit", true );
-	}
-	
-	Cvar_SetValue( "s_primary", s_options_compatibility_list.curvalue );
-
-	M_DrawTextBox( 8, 120 - 48, 36, 3 );
-	M_Print( 16 + 16, 120 - 48 + 8,  "Restarting the sound system. This" );
-	M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
-	M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
-
-	// the text box won't show up unless we do a buffer swap
-	re.EndFrame();
-
-	CL_Snd_Restart_f();
-}
-
-void Options_MenuInit( void )
-{
-	static const char *cd_music_items[] =
-	{
-		"disabled",
-		"enabled",
-		0
-	};
-	static const char *quality_items[] =
-	{
-		"low", "high", 0
-	};
-
-	static const char *compatibility_items[] =
-	{
-		"max compatibility", "max performance", 0
-	};
-
-	static const char *yesno_names[] =
-	{
-		"no",
-		"yes",
-		0
-	};
-
-	static const char *crosshair_names[] =
-	{
-		"none",
-		"cross",
-		"dot",
-		"angle",
-		0
-	};
-
-	win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
-
-	/*
-	** configure controls menu and menu items
-	*/
-	s_options_menu.x = vid.width / 2;
-	s_options_menu.y = vid.height / 2 - 58;
-	s_options_menu.nitems = 0;
-
-	s_options_sfxvolume_slider.generic.type	= MTYPE_SLIDER;
-	s_options_sfxvolume_slider.generic.x	= 0;
-	s_options_sfxvolume_slider.generic.y	= 0;
-	s_options_sfxvolume_slider.generic.name	= "effects volume";
-	s_options_sfxvolume_slider.generic.callback	= UpdateVolumeFunc;
-	s_options_sfxvolume_slider.minvalue		= 0;
-	s_options_sfxvolume_slider.maxvalue		= 10;
-	s_options_sfxvolume_slider.curvalue		= Cvar_VariableValue( "s_volume" ) * 10;
-
-	s_options_cdvolume_box.generic.type	= MTYPE_SPINCONTROL;
-	s_options_cdvolume_box.generic.x		= 0;
-	s_options_cdvolume_box.generic.y		= 10;
-	s_options_cdvolume_box.generic.name	= "CD music";
-	s_options_cdvolume_box.generic.callback	= UpdateCDVolumeFunc;
-	s_options_cdvolume_box.itemnames		= cd_music_items;
-	s_options_cdvolume_box.curvalue 		= !Cvar_VariableValue("cd_nocd");
-
-	s_options_quality_list.generic.type	= MTYPE_SPINCONTROL;
-	s_options_quality_list.generic.x		= 0;
-	s_options_quality_list.generic.y		= 20;;
-	s_options_quality_list.generic.name		= "sound quality";
-	s_options_quality_list.generic.callback = UpdateSoundQualityFunc;
-	s_options_quality_list.itemnames		= quality_items;
-	s_options_quality_list.curvalue			= !Cvar_VariableValue( "s_loadas8bit" );
-
-	s_options_compatibility_list.generic.type	= MTYPE_SPINCONTROL;
-	s_options_compatibility_list.generic.x		= 0;
-	s_options_compatibility_list.generic.y		= 30;
-	s_options_compatibility_list.generic.name	= "sound compatibility";
-	s_options_compatibility_list.generic.callback = UpdateSoundQualityFunc;
-	s_options_compatibility_list.itemnames		= compatibility_items;
-	s_options_compatibility_list.curvalue		= Cvar_VariableValue( "s_primary" );
-
-	s_options_sensitivity_slider.generic.type	= MTYPE_SLIDER;
-	s_options_sensitivity_slider.generic.x		= 0;
-	s_options_sensitivity_slider.generic.y		= 50;
-	s_options_sensitivity_slider.generic.name	= "mouse speed";
-	s_options_sensitivity_slider.generic.callback = MouseSpeedFunc;
-	s_options_sensitivity_slider.minvalue		= 2;
-	s_options_sensitivity_slider.maxvalue		= 22;
-
-	s_options_alwaysrun_box.generic.type = MTYPE_SPINCONTROL;
-	s_options_alwaysrun_box.generic.x	= 0;
-	s_options_alwaysrun_box.generic.y	= 60;
-	s_options_alwaysrun_box.generic.name	= "always run";
-	s_options_alwaysrun_box.generic.callback = AlwaysRunFunc;
-	s_options_alwaysrun_box.itemnames = yesno_names;
-
-	s_options_invertmouse_box.generic.type = MTYPE_SPINCONTROL;
-	s_options_invertmouse_box.generic.x	= 0;
-	s_options_invertmouse_box.generic.y	= 70;
-	s_options_invertmouse_box.generic.name	= "invert mouse";
-	s_options_invertmouse_box.generic.callback = InvertMouseFunc;
-	s_options_invertmouse_box.itemnames = yesno_names;
-
-	s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL;
-	s_options_lookspring_box.generic.x	= 0;
-	s_options_lookspring_box.generic.y	= 80;
-	s_options_lookspring_box.generic.name	= "lookspring";
-	s_options_lookspring_box.generic.callback = LookspringFunc;
-	s_options_lookspring_box.itemnames = yesno_names;
-
-	s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL;
-	s_options_lookstrafe_box.generic.x	= 0;
-	s_options_lookstrafe_box.generic.y	= 90;
-	s_options_lookstrafe_box.generic.name	= "lookstrafe";
-	s_options_lookstrafe_box.generic.callback = LookstrafeFunc;
-	s_options_lookstrafe_box.itemnames = yesno_names;
-
-	s_options_freelook_box.generic.type = MTYPE_SPINCONTROL;
-	s_options_freelook_box.generic.x	= 0;
-	s_options_freelook_box.generic.y	= 100;
-	s_options_freelook_box.generic.name	= "free look";
-	s_options_freelook_box.generic.callback = FreeLookFunc;
-	s_options_freelook_box.itemnames = yesno_names;
-
-	s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL;
-	s_options_crosshair_box.generic.x	= 0;
-	s_options_crosshair_box.generic.y	= 110;
-	s_options_crosshair_box.generic.name	= "crosshair";
-	s_options_crosshair_box.generic.callback = CrosshairFunc;
-	s_options_crosshair_box.itemnames = crosshair_names;
-/*
-	s_options_noalttab_box.generic.type = MTYPE_SPINCONTROL;
-	s_options_noalttab_box.generic.x	= 0;
-	s_options_noalttab_box.generic.y	= 110;
-	s_options_noalttab_box.generic.name	= "disable alt-tab";
-	s_options_noalttab_box.generic.callback = NoAltTabFunc;
-	s_options_noalttab_box.itemnames = yesno_names;
-*/
-	s_options_joystick_box.generic.type = MTYPE_SPINCONTROL;
-	s_options_joystick_box.generic.x	= 0;
-	s_options_joystick_box.generic.y	= 120;
-	s_options_joystick_box.generic.name	= "use joystick";
-	s_options_joystick_box.generic.callback = JoystickFunc;
-	s_options_joystick_box.itemnames = yesno_names;
-
-	s_options_customize_options_action.generic.type	= MTYPE_ACTION;
-	s_options_customize_options_action.generic.x		= 0;
-	s_options_customize_options_action.generic.y		= 140;
-	s_options_customize_options_action.generic.name	= "customize controls";
-	s_options_customize_options_action.generic.callback = CustomizeControlsFunc;
-
-	s_options_defaults_action.generic.type	= MTYPE_ACTION;
-	s_options_defaults_action.generic.x		= 0;
-	s_options_defaults_action.generic.y		= 150;
-	s_options_defaults_action.generic.name	= "reset defaults";
-	s_options_defaults_action.generic.callback = ControlsResetDefaultsFunc;
-
-	s_options_console_action.generic.type	= MTYPE_ACTION;
-	s_options_console_action.generic.x		= 0;
-	s_options_console_action.generic.y		= 160;
-	s_options_console_action.generic.name	= "go to console";
-	s_options_console_action.generic.callback = ConsoleFunc;
-
-	ControlsSetMenuItemValues();
-
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_sfxvolume_slider );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_cdvolume_box );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_quality_list );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_compatibility_list );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_sensitivity_slider );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_alwaysrun_box );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_invertmouse_box );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookspring_box );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookstrafe_box );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_freelook_box );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_crosshair_box );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_joystick_box );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_customize_options_action );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_defaults_action );
-	Menu_AddItem( &s_options_menu, ( void * ) &s_options_console_action );
-}
-
-void Options_MenuDraw (void)
-{
-	M_Banner( "m_banner_options" );
-	Menu_AdjustCursor( &s_options_menu, 1 );
-	Menu_Draw( &s_options_menu );
-}
-
-const char *Options_MenuKey( int key )
-{
-	return Default_MenuKey( &s_options_menu, key );
-}
-
-void M_Menu_Options_f (void)
-{
-	Options_MenuInit();
-	M_PushMenu ( Options_MenuDraw, Options_MenuKey );
-}
-
-/*
-=======================================================================
-
-VIDEO MENU
-
-=======================================================================
-*/
-
-void M_Menu_Video_f (void)
-{
-	VID_MenuInit();
-	M_PushMenu( VID_MenuDraw, VID_MenuKey );
-}
-
-/*
-=============================================================================
-
-END GAME MENU
-
-=============================================================================
-*/
-static int credits_start_time;
-static const char **credits;
-static char *creditsIndex[256];
-static char *creditsBuffer;
-static const char *idcredits[] =
-{
-	"+QUAKE II BY ID SOFTWARE",
-	"",
-	"+PROGRAMMING",
-	"John Carmack",
-	"John Cash",
-	"Brian Hook",
-	"",
-	"+ART",
-	"Adrian Carmack",
-	"Kevin Cloud",
-	"Paul Steed",
-	"",
-	"+LEVEL DESIGN",
-	"Tim Willits",
-	"American McGee",
-	"Christian Antkow",
-	"Paul Jaquays",
-	"Brandon James",
-	"",
-	"+BIZ",
-	"Todd Hollenshead",
-	"Barrett (Bear) Alexander",
-	"Donna Jackson",
-	"",
-	"",
-	"+SPECIAL THANKS",
-	"Ben Donges for beta testing",
-	"",
-	"",
-	"",
-	"",
-	"",
-	"",
-	"+ADDITIONAL SUPPORT",
-	"",
-	"+LINUX PORT AND CTF",
-	"Dave \"Zoid\" Kirsch",
-	"",
-	"+CINEMATIC SEQUENCES",
-	"Ending Cinematic by Blur Studio - ",
-	"Venice, CA",
-	"",
-	"Environment models for Introduction",
-	"Cinematic by Karl Dolgener",
-	"",
-	"Assistance with environment design",
-	"by Cliff Iwai",
-	"",
-	"+SOUND EFFECTS AND MUSIC",
-	"Sound Design by Soundelux Media Labs.",
-	"Music Composed and Produced by",
-	"Soundelux Media Labs.  Special thanks",
-	"to Bill Brown, Tom Ozanich, Brian",
-	"Celano, Jeff Eisner, and The Soundelux",
-	"Players.",
-	"",
-	"\"Level Music\" by Sonic Mayhem",
-	"www.sonicmayhem.com",
-	"",
-	"\"Quake II Theme Song\"",
-	"(C) 1997 Rob Zombie. All Rights",
-	"Reserved.",
-	"",
-	"Track 10 (\"Climb\") by Jer Sypult",
-	"",
-	"Voice of computers by",
-	"Carly Staehlin-Taylor",
-	"",
-	"+THANKS TO ACTIVISION",
-	"+IN PARTICULAR:",
-	"",
-	"John Tam",
-	"Steve Rosenthal",
-	"Marty Stratton",
-	"Henk Hartong",
-	"",
-	"Quake II(tm) (C)1997 Id Software, Inc.",
-	"All Rights Reserved.  Distributed by",
-	"Activision, Inc. under license.",
-	"Quake II(tm), the Id Software name,",
-	"the \"Q II\"(tm) logo and id(tm)",
-	"logo are trademarks of Id Software,",
-	"Inc. Activision(R) is a registered",
-	"trademark of Activision, Inc. All",
-	"other trademarks and trade names are",
-	"properties of their respective owners.",
-	0
-};
-
-static const char *xatcredits[] =
-{
-	"+QUAKE II MISSION PACK: THE RECKONING",
-	"+BY",
-	"+XATRIX ENTERTAINMENT, INC.",
-	"",
-	"+DESIGN AND DIRECTION",
-	"Drew Markham",
-	"",
-	"+PRODUCED BY",
-	"Greg Goodrich",
-	"",
-	"+PROGRAMMING",
-	"Rafael Paiz",
-	"",
-	"+LEVEL DESIGN / ADDITIONAL GAME DESIGN",
-	"Alex Mayberry",
-	"",
-	"+LEVEL DESIGN",
-	"Mal Blackwell",
-	"Dan Koppel",
-	"",
-	"+ART DIRECTION",
-	"Michael \"Maxx\" Kaufman",
-	"",
-	"+COMPUTER GRAPHICS SUPERVISOR AND",
-	"+CHARACTER ANIMATION DIRECTION",
-	"Barry Dempsey",
-	"",
-	"+SENIOR ANIMATOR AND MODELER",
-	"Jason Hoover",
-	"",
-	"+CHARACTER ANIMATION AND",
-	"+MOTION CAPTURE SPECIALIST",
-	"Amit Doron",
-	"",
-	"+ART",
-	"Claire Praderie-Markham",
-	"Viktor Antonov",
-	"Corky Lehmkuhl",
-	"",
-	"+INTRODUCTION ANIMATION",
-	"Dominique Drozdz",
-	"",
-	"+ADDITIONAL LEVEL DESIGN",
-	"Aaron Barber",
-	"Rhett Baldwin",
-	"",
-	"+3D CHARACTER ANIMATION TOOLS",
-	"Gerry Tyra, SA Technology",
-	"",
-	"+ADDITIONAL EDITOR TOOL PROGRAMMING",
-	"Robert Duffy",
-	"",
-	"+ADDITIONAL PROGRAMMING",
-	"Ryan Feltrin",
-	"",
-	"+PRODUCTION COORDINATOR",
-	"Victoria Sylvester",
-	"",
-	"+SOUND DESIGN",
-	"Gary Bradfield",
-	"",
-	"+MUSIC BY",
-	"Sonic Mayhem",
-	"",
-	"",
-	"",
-	"+SPECIAL THANKS",
-	"+TO",
-	"+OUR FRIENDS AT ID SOFTWARE",
-	"",
-	"John Carmack",
-	"John Cash",
-	"Brian Hook",
-	"Adrian Carmack",
-	"Kevin Cloud",
-	"Paul Steed",
-	"Tim Willits",
-	"Christian Antkow",
-	"Paul Jaquays",
-	"Brandon James",
-	"Todd Hollenshead",
-	"Barrett (Bear) Alexander",
-	"Dave \"Zoid\" Kirsch",
-	"Donna Jackson",
-	"",
-	"",
-	"",
-	"+THANKS TO ACTIVISION",
-	"+IN PARTICULAR:",
-	"",
-	"Marty Stratton",
-	"Henk \"The Original Ripper\" Hartong",
-	"Kevin Kraff",
-	"Jamey Gottlieb",
-	"Chris Hepburn",
-	"",
-	"+AND THE GAME TESTERS",
-	"",
-	"Tim Vanlaw",
-	"Doug Jacobs",
-	"Steven Rosenthal",
-	"David Baker",
-	"Chris Campbell",
-	"Aaron Casillas",
-	"Steve Elwell",
-	"Derek Johnstone",
-	"Igor Krinitskiy",
-	"Samantha Lee",
-	"Michael Spann",
-	"Chris Toft",
-	"Juan Valdes",
-	"",
-	"+THANKS TO INTERGRAPH COMPUTER SYTEMS",
-	"+IN PARTICULAR:",
-	"",
-	"Michael T. Nicolaou",
-	"",
-	"",
-	"Quake II Mission Pack: The Reckoning",
-	"(tm) (C)1998 Id Software, Inc. All",
-	"Rights Reserved. Developed by Xatrix",
-	"Entertainment, Inc. for Id Software,",
-	"Inc. Distributed by Activision Inc.",
-	"under license. Quake(R) is a",
-	"registered trademark of Id Software,",
-	"Inc. Quake II Mission Pack: The",
-	"Reckoning(tm), Quake II(tm), the Id",
-	"Software name, the \"Q II\"(tm) logo",
-	"and id(tm) logo are trademarks of Id",
-	"Software, Inc. Activision(R) is a",
-	"registered trademark of Activision,",
-	"Inc. Xatrix(R) is a registered",
-	"trademark of Xatrix Entertainment,",
-	"Inc. All other trademarks and trade",
-	"names are properties of their",
-	"respective owners.",
-	0
-};
-
-static const char *roguecredits[] =
-{
-	"+QUAKE II MISSION PACK 2: GROUND ZERO",
-	"+BY",
-	"+ROGUE ENTERTAINMENT, INC.",
-	"",
-	"+PRODUCED BY",
-	"Jim Molinets",
-	"",
-	"+PROGRAMMING",
-	"Peter Mack",
-	"Patrick Magruder",
-	"",
-	"+LEVEL DESIGN",
-	"Jim Molinets",
-	"Cameron Lamprecht",
-	"Berenger Fish",
-	"Robert Selitto",
-	"Steve Tietze",
-	"Steve Thoms",
-	"",
-	"+ART DIRECTION",
-	"Rich Fleider",
-	"",
-	"+ART",
-	"Rich Fleider",
-	"Steve Maines",
-	"Won Choi",
-	"",
-	"+ANIMATION SEQUENCES",
-	"Creat Studios",
-	"Steve Maines",
-	"",
-	"+ADDITIONAL LEVEL DESIGN",
-	"Rich Fleider",
-	"Steve Maines",
-	"Peter Mack",
-	"",
-	"+SOUND",
-	"James Grunke",
-	"",
-	"+GROUND ZERO THEME",
-	"+AND",
-	"+MUSIC BY",
-	"Sonic Mayhem",
-	"",
-	"+VWEP MODELS",
-	"Brent \"Hentai\" Dill",
-	"",
-	"",
-	"",
-	"+SPECIAL THANKS",
-	"+TO",
-	"+OUR FRIENDS AT ID SOFTWARE",
-	"",
-	"John Carmack",
-	"John Cash",
-	"Brian Hook",
-	"Adrian Carmack",
-	"Kevin Cloud",
-	"Paul Steed",
-	"Tim Willits",
-	"Christian Antkow",
-	"Paul Jaquays",
-	"Brandon James",
-	"Todd Hollenshead",
-	"Barrett (Bear) Alexander",
-	"Katherine Anna Kang",
-	"Donna Jackson",
-	"Dave \"Zoid\" Kirsch",
-	"",
-	"",
-	"",
-	"+THANKS TO ACTIVISION",
-	"+IN PARTICULAR:",
-	"",
-	"Marty Stratton",
-	"Henk Hartong",
-	"Mitch Lasky",
-	"Steve Rosenthal",
-	"Steve Elwell",
-	"",
-	"+AND THE GAME TESTERS",
-	"",
-	"The Ranger Clan",
-	"Dave \"Zoid\" Kirsch",
-	"Nihilistic Software",
-	"Robert Duffy",
-	"",
-	"And Countless Others",
-	"",
-	"",
-	"",
-	"Quake II Mission Pack 2: Ground Zero",
-	"(tm) (C)1998 Id Software, Inc. All",
-	"Rights Reserved. Developed by Rogue",
-	"Entertainment, Inc. for Id Software,",
-	"Inc. Distributed by Activision Inc.",
-	"under license. Quake(R) is a",
-	"registered trademark of Id Software,",
-	"Inc. Quake II Mission Pack 2: Ground",
-	"Zero(tm), Quake II(tm), the Id",
-	"Software name, the \"Q II\"(tm) logo",
-	"and id(tm) logo are trademarks of Id",
-	"Software, Inc. Activision(R) is a",
-	"registered trademark of Activision,",
-	"Inc. Rogue(R) is a registered",
-	"trademark of Rogue Entertainment,",
-	"Inc. All other trademarks and trade",
-	"names are properties of their",
-	"respective owners.",
-	0
-};
-
-
-void M_Credits_MenuDraw( void )
-{
-	int i, y;
-
-	/*
-	** draw the credits
-	*/
-	for ( i = 0, y = vid.height - ( ( cls.realtime - credits_start_time ) / 40.0F ); credits[i] && y < vid.height; y += 10, i++ )
-	{
-		int j, stringoffset;
-		int bold;
-
-		if ( y <= -8 )
-			continue;
-
-		if ( credits[i][0] == '+' )
-		{
-			bold = true;
-			stringoffset = 1;
-		}
-		else
-		{
-			bold = false;
-			stringoffset = 0;
-		}
-
-		for ( j = 0; credits[i][j+stringoffset]; j++ )
-		{
-			int x;
-
-			x = ( vid.width - strlen( credits[i] ) * 8 - stringoffset * 8 ) / 2 + ( j + stringoffset ) * 8;
-
-			if ( bold )
-				re.DrawChar( x, y, credits[i][j+stringoffset] + 128 );
-			else
-				re.DrawChar( x, y, credits[i][j+stringoffset] );
-		}
-	}
-
-	if ( y < 0 )
-		credits_start_time = cls.realtime;
-}
-
-const char *M_Credits_Key( int key )
-{
-	switch (key)
-	{
-	case K_ESCAPE:
-		if (creditsBuffer)
-			FS_FreeFile (creditsBuffer);
-		M_PopMenu ();
-		break;
-	}
-
-	return menu_out_sound;
-
-}
-
-extern int Developer_searchpath (int who);
-
-void M_Menu_Credits_f( void )
-{
-	int		n;
-	int		count;
-	char	*p;
-	int		isdeveloper;
-
-	creditsBuffer = NULL;
-	count = FS_LoadFile ("credits", &creditsBuffer);
-	if (count != -1)
-	{
-		p = creditsBuffer;
-		for (n = 0; n < 255; n++)
-		{
-			creditsIndex[n] = p;
-			while (*p != '\r' && *p != '\n')
-			{
-				p++;
-				if (--count == 0)
-					break;
-			}
-			if (*p == '\r')
-			{
-				*p++ = 0;
-				if (--count == 0)
-					break;
-			}
-			*p++ = 0;
-			if (--count == 0)
-				break;
-		}
-		creditsIndex[++n] = 0;
-		credits = creditsIndex;
-	}
-	else
-	{
-		isdeveloper = Developer_searchpath (1);
-		
-		if (isdeveloper == 1)			// xatrix
-			credits = xatcredits;
-		else if (isdeveloper == 2)		// ROGUE
-			credits = roguecredits;
-		else
-		{
-			credits = idcredits;	
-		}
-
-	}
-
-	credits_start_time = cls.realtime;
-	M_PushMenu( M_Credits_MenuDraw, M_Credits_Key);
-}
-
-/*
-=============================================================================
-
-GAME MENU
-
-=============================================================================
-*/
-
-static int		m_game_cursor;
-
-static menuframework_s	s_game_menu;
-static menuaction_s		s_easy_game_action;
-static menuaction_s		s_medium_game_action;
-static menuaction_s		s_hard_game_action;
-static menuaction_s		s_load_game_action;
-static menuaction_s		s_save_game_action;
-static menuaction_s		s_credits_action;
-static menuseparator_s	s_blankline;
-
-static void StartGame( void )
-{
-	// disable updates and start the cinematic going
-	cl.servercount = -1;
-	M_ForceMenuOff ();
-	Cvar_SetValue( "deathmatch", 0 );
-	Cvar_SetValue( "coop", 0 );
-
-	Cvar_SetValue( "gamerules", 0 );		//PGM
-
-	Cbuf_AddText ("loading ; killserver ; wait ; newgame\n");
-	cls.key_dest = key_game;
-}
-
-static void EasyGameFunc( void * )
-{
-	Cvar_ForceSet( "skill", "0" );
-	StartGame();
-}
-
-static void MediumGameFunc( void * )
-{
-	Cvar_ForceSet( "skill", "1" );
-	StartGame();
-}
-
-static void HardGameFunc( void * )
-{
-	Cvar_ForceSet( "skill", "2" );
-	StartGame();
-}
-
-static void LoadGameFunc( void * )
-{
-	M_Menu_LoadGame_f ();
-}
-
-static void SaveGameFunc( void * )
-{
-	M_Menu_SaveGame_f();
-}
-
-static void CreditsFunc( void * )
-{
-	M_Menu_Credits_f();
-}
-
-void Game_MenuInit( void )
-{
-	static const char *difficulty_names[] =
-	{
-		"easy",
-		"medium",
-		"hard",
-		0
-	};
-
-	s_game_menu.x = vid.width * 0.50;
-	s_game_menu.nitems = 0;
-
-	s_easy_game_action.generic.type	= MTYPE_ACTION;
-	s_easy_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
-	s_easy_game_action.generic.x		= 0;
-	s_easy_game_action.generic.y		= 0;
-	s_easy_game_action.generic.name	= "easy";
-	s_easy_game_action.generic.callback = EasyGameFunc;
-
-	s_medium_game_action.generic.type	= MTYPE_ACTION;
-	s_medium_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
-	s_medium_game_action.generic.x		= 0;
-	s_medium_game_action.generic.y		= 10;
-	s_medium_game_action.generic.name	= "medium";
-	s_medium_game_action.generic.callback = MediumGameFunc;
-
-	s_hard_game_action.generic.type	= MTYPE_ACTION;
-	s_hard_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
-	s_hard_game_action.generic.x		= 0;
-	s_hard_game_action.generic.y		= 20;
-	s_hard_game_action.generic.name	= "hard";
-	s_hard_game_action.generic.callback = HardGameFunc;
-
-	s_blankline.generic.type = MTYPE_SEPARATOR;
-
-	s_load_game_action.generic.type	= MTYPE_ACTION;
-	s_load_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
-	s_load_game_action.generic.x		= 0;
-	s_load_game_action.generic.y		= 40;
-	s_load_game_action.generic.name	= "load game";
-	s_load_game_action.generic.callback = LoadGameFunc;
-
-	s_save_game_action.generic.type	= MTYPE_ACTION;
-	s_save_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
-	s_save_game_action.generic.x		= 0;
-	s_save_game_action.generic.y		= 50;
-	s_save_game_action.generic.name	= "save game";
-	s_save_game_action.generic.callback = SaveGameFunc;
-
-	s_credits_action.generic.type	= MTYPE_ACTION;
-	s_credits_action.generic.flags  = QMF_LEFT_JUSTIFY;
-	s_credits_action.generic.x		= 0;
-	s_credits_action.generic.y		= 60;
-	s_credits_action.generic.name	= "credits";
-	s_credits_action.generic.callback = CreditsFunc;
-
-	Menu_AddItem( &s_game_menu, ( void * ) &s_easy_game_action );
-	Menu_AddItem( &s_game_menu, ( void * ) &s_medium_game_action );
-	Menu_AddItem( &s_game_menu, ( void * ) &s_hard_game_action );
-	Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
-	Menu_AddItem( &s_game_menu, ( void * ) &s_load_game_action );
-	Menu_AddItem( &s_game_menu, ( void * ) &s_save_game_action );
-	Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
-	Menu_AddItem( &s_game_menu, ( void * ) &s_credits_action );
-
-	Menu_Center( &s_game_menu );
-}
-
-void Game_MenuDraw( void )
-{
-	M_Banner( "m_banner_game" );
-	Menu_AdjustCursor( &s_game_menu, 1 );
-	Menu_Draw( &s_game_menu );
-}
-
-const char *Game_MenuKey( int key )
-{
-	return Default_MenuKey( &s_game_menu, key );
-}
-
-void M_Menu_Game_f (void)
-{
-	Game_MenuInit();
-	M_PushMenu( Game_MenuDraw, Game_MenuKey );
-	m_game_cursor = 1;
-}
-
-/*
-=============================================================================
-
-LOADGAME MENU
-
-=============================================================================
-*/
-
-#define	MAX_SAVEGAMES	15
-
-static menuframework_s	s_savegame_menu;
-
-static menuframework_s	s_loadgame_menu;
-static menuaction_s		s_loadgame_actions[MAX_SAVEGAMES];
-
-char		m_savestrings[MAX_SAVEGAMES][32];
-qboolean	m_savevalid[MAX_SAVEGAMES];
-
-void Create_Savestrings (void)
-{
-	int		i;
-	FILE	*f;
-	char	name[MAX_OSPATH];
-
-	for (i=0 ; i<MAX_SAVEGAMES ; i++)
-	{
-		Com_sprintf (name, sizeof(name), "%s/save/save%i/server.ssv", FS_Gamedir(), i);
-		f = fopen (name, "rb");
-		if (!f)
-		{
-			strcpy (m_savestrings[i], "<EMPTY>");
-			m_savevalid[i] = false;
-		}
-		else
-		{
-			FS_Read (m_savestrings[i], sizeof(m_savestrings[i]), f);
-			fclose (f);
-			m_savevalid[i] = true;
-		}
-	}
-}
-
-void LoadGameCallback( void *self )
-{
-	menuaction_s *a = ( menuaction_s * ) self;
-
-	if ( m_savevalid[ a->generic.localdata[0] ] )
-		Cbuf_AddText (va("load save%i\n",  a->generic.localdata[0] ) );
-	M_ForceMenuOff ();
-}
-
-void LoadGame_MenuInit( void )
-{
-	int i;
-
-	s_loadgame_menu.x = vid.width / 2 - 120;
-	s_loadgame_menu.y = vid.height / 2 - 58;
-	s_loadgame_menu.nitems = 0;
-
-	Create_Savestrings();
-
-	for ( i = 0; i < MAX_SAVEGAMES; i++ )
-	{
-		s_loadgame_actions[i].generic.name			= m_savestrings[i];
-		s_loadgame_actions[i].generic.flags			= QMF_LEFT_JUSTIFY;
-		s_loadgame_actions[i].generic.localdata[0]	= i;
-		s_loadgame_actions[i].generic.callback		= LoadGameCallback;
-
-		s_loadgame_actions[i].generic.x = 0;
-		s_loadgame_actions[i].generic.y = ( i ) * 10;
-		if (i>0)	// separate from autosave
-			s_loadgame_actions[i].generic.y += 10;
-
-		s_loadgame_actions[i].generic.type = MTYPE_ACTION;
-
-		Menu_AddItem( &s_loadgame_menu, &s_loadgame_actions[i] );
-	}
-}
-
-void LoadGame_MenuDraw( void )
-{
-	M_Banner( "m_banner_load_game" );
-//	Menu_AdjustCursor( &s_loadgame_menu, 1 );
-	Menu_Draw( &s_loadgame_menu );
-}
-
-const char *LoadGame_MenuKey( int key )
-{
-	if ( key == K_ESCAPE || key == K_ENTER )
-	{
-		s_savegame_menu.cursor = s_loadgame_menu.cursor - 1;
-		if ( s_savegame_menu.cursor < 0 )
-			s_savegame_menu.cursor = 0;
-	}
-	return Default_MenuKey( &s_loadgame_menu, key );
-}
-
-void M_Menu_LoadGame_f (void)
-{
-	LoadGame_MenuInit();
-	M_PushMenu( LoadGame_MenuDraw, LoadGame_MenuKey );
-}
-
-
-/*
-=============================================================================
-
-SAVEGAME MENU
-
-=============================================================================
-*/
-static menuframework_s	s_savegame_menu;
-static menuaction_s		s_savegame_actions[MAX_SAVEGAMES];
-
-void SaveGameCallback( void *self )
-{
-	menuaction_s *a = ( menuaction_s * ) self;
-
-	Cbuf_AddText (va("save save%i\n", a->generic.localdata[0] ));
-	M_ForceMenuOff ();
-}
-
-void SaveGame_MenuDraw( void )
-{
-	M_Banner( "m_banner_save_game" );
-	Menu_AdjustCursor( &s_savegame_menu, 1 );
-	Menu_Draw( &s_savegame_menu );
-}
-
-void SaveGame_MenuInit( void )
-{
-	int i;
-
-	s_savegame_menu.x = vid.width / 2 - 120;
-	s_savegame_menu.y = vid.height / 2 - 58;
-	s_savegame_menu.nitems = 0;
-
-	Create_Savestrings();
-
-	// don't include the autosave slot
-	for ( i = 0; i < MAX_SAVEGAMES-1; i++ )
-	{
-		s_savegame_actions[i].generic.name = m_savestrings[i+1];
-		s_savegame_actions[i].generic.localdata[0] = i+1;
-		s_savegame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
-		s_savegame_actions[i].generic.callback = SaveGameCallback;
-
-		s_savegame_actions[i].generic.x = 0;
-		s_savegame_actions[i].generic.y = ( i ) * 10;
-
-		s_savegame_actions[i].generic.type = MTYPE_ACTION;
-
-		Menu_AddItem( &s_savegame_menu, &s_savegame_actions[i] );
-	}
-}
-
-const char *SaveGame_MenuKey( int key )
-{
-	if ( key == K_ENTER || key == K_ESCAPE )
-	{
-		s_loadgame_menu.cursor = s_savegame_menu.cursor - 1;
-		if ( s_loadgame_menu.cursor < 0 )
-			s_loadgame_menu.cursor = 0;
-	}
-	return Default_MenuKey( &s_savegame_menu, key );
-}
-
-void M_Menu_SaveGame_f (void)
-{
-	if (!Com_ServerState())
-		return;		// not playing a game
-
-	SaveGame_MenuInit();
-	M_PushMenu( SaveGame_MenuDraw, SaveGame_MenuKey );
-	Create_Savestrings ();
-}
-
-
-/*
-=============================================================================
-
-JOIN SERVER MENU
-
-=============================================================================
-*/
-#define MAX_LOCAL_SERVERS 8
-
-static menuframework_s	s_joinserver_menu;
-static menuseparator_s	s_joinserver_server_title;
-static menuaction_s		s_joinserver_search_action;
-static menuaction_s		s_joinserver_address_book_action;
-static menuaction_s		s_joinserver_server_actions[MAX_LOCAL_SERVERS];
-
-int		m_num_servers;
-#define	NO_SERVER_STRING	"<no server>"
-
-// user readable information
-static char local_server_names[MAX_LOCAL_SERVERS][80];
-
-// network address
-static netadr_t local_server_netadr[MAX_LOCAL_SERVERS];
-
-void M_AddToServerList (netadr_t adr, char *info)
-{
-	int		i;
-
-	if (m_num_servers == MAX_LOCAL_SERVERS)
-		return;
-	while ( *info == ' ' )
-		info++;
-
-	// ignore if duplicated
-	for (i=0 ; i<m_num_servers ; i++)
-		if (!strcmp(info, local_server_names[i]))
-			return;
-
-	local_server_netadr[m_num_servers] = adr;
-	strncpy (local_server_names[m_num_servers], info, sizeof(local_server_names[0])-1);
-	m_num_servers++;
-}
-
-
-void JoinServerFunc( void *self )
-{
-	char	buffer[128];
-	int		index;
-
-	index = ( menuaction_s * ) self - s_joinserver_server_actions;
-
-	if ( cistrcmp( local_server_names[index], NO_SERVER_STRING ) == 0 )
-		return;
-
-	if (index >= m_num_servers)
-		return;
-
-	Com_sprintf (buffer, sizeof(buffer), "connect %s\n", NET_AdrToString (local_server_netadr[index]));
-	Cbuf_AddText (buffer);
-	M_ForceMenuOff ();
-}
-
-void AddressBookFunc( void * )
-{
-	M_Menu_AddressBook_f();
-}
-
-void NullCursorDraw( void * )
-{
-}
-
-void SearchLocalGames( void )
-{
-	int		i;
-
-	m_num_servers = 0;
-	for (i=0 ; i<MAX_LOCAL_SERVERS ; i++)
-		strcpy (local_server_names[i], NO_SERVER_STRING);
-
-	M_DrawTextBox( 8, 120 - 48, 36, 3 );
-	M_Print( 16 + 16, 120 - 48 + 8,  "Searching for local servers, this" );
-	M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
-	M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
-
-	// the text box won't show up unless we do a buffer swap
-	re.EndFrame();
-
-	// send out info packets
-	CL_PingServers_f();
-}
-
-void SearchLocalGamesFunc( void * )
-{
-	SearchLocalGames();
-}
-
-void JoinServer_MenuInit( void )
-{
-	int i;
-
-	s_joinserver_menu.x = vid.width * 0.50 - 120;
-	s_joinserver_menu.nitems = 0;
-
-	s_joinserver_address_book_action.generic.type	= MTYPE_ACTION;
-	s_joinserver_address_book_action.generic.name	= "address book";
-	s_joinserver_address_book_action.generic.flags	= QMF_LEFT_JUSTIFY;
-	s_joinserver_address_book_action.generic.x		= 0;
-	s_joinserver_address_book_action.generic.y		= 0;
-	s_joinserver_address_book_action.generic.callback = AddressBookFunc;
-
-	s_joinserver_search_action.generic.type = MTYPE_ACTION;
-	s_joinserver_search_action.generic.name	= "refresh server list";
-	s_joinserver_search_action.generic.flags	= QMF_LEFT_JUSTIFY;
-	s_joinserver_search_action.generic.x	= 0;
-	s_joinserver_search_action.generic.y	= 10;
-	s_joinserver_search_action.generic.callback = SearchLocalGamesFunc;
-	s_joinserver_search_action.generic.statusbar = "search for servers";
-
-	s_joinserver_server_title.generic.type = MTYPE_SEPARATOR;
-	s_joinserver_server_title.generic.name = "connect to...";
-	s_joinserver_server_title.generic.x    = 80;
-	s_joinserver_server_title.generic.y	   = 30;
-
-	for ( i = 0; i < MAX_LOCAL_SERVERS; i++ )
-	{
-		s_joinserver_server_actions[i].generic.type	= MTYPE_ACTION;
-		strcpy (local_server_names[i], NO_SERVER_STRING);
-		s_joinserver_server_actions[i].generic.name	= local_server_names[i];
-		s_joinserver_server_actions[i].generic.flags	= QMF_LEFT_JUSTIFY;
-		s_joinserver_server_actions[i].generic.x		= 0;
-		s_joinserver_server_actions[i].generic.y		= 40 + i*10;
-		s_joinserver_server_actions[i].generic.callback = JoinServerFunc;
-		s_joinserver_server_actions[i].generic.statusbar = "press ENTER to connect";
-	}
-
-	Menu_AddItem( &s_joinserver_menu, &s_joinserver_address_book_action );
-	Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_title );
-	Menu_AddItem( &s_joinserver_menu, &s_joinserver_search_action );
-
-	for ( i = 0; i < 8; i++ )
-		Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_actions[i] );
-
-	Menu_Center( &s_joinserver_menu );
-
-	SearchLocalGames();
-}
-
-void JoinServer_MenuDraw(void)
-{
-	M_Banner( "m_banner_join_server" );
-	Menu_Draw( &s_joinserver_menu );
-}
-
-
-const char *JoinServer_MenuKey( int key )
-{
-	return Default_MenuKey( &s_joinserver_menu, key );
-}
-
-void M_Menu_JoinServer_f (void)
-{
-	JoinServer_MenuInit();
-	M_PushMenu( JoinServer_MenuDraw, JoinServer_MenuKey );
-}
-
-
-/*
-=============================================================================
-
-START SERVER MENU
-
-=============================================================================
-*/
-static menuframework_s s_startserver_menu;
-static char **mapnames;
-static int	  nummaps;
-
-static menuaction_s	s_startserver_start_action;
-static menuaction_s	s_startserver_dmoptions_action;
-static menufield_s	s_timelimit_field;
-static menufield_s	s_fraglimit_field;
-static menufield_s	s_maxclients_field;
-static menufield_s	s_hostname_field;
-static menulist_s	s_startmap_list;
-static menulist_s	s_rules_box;
-
-void DMOptionsFunc( void * )
-{
-	if (s_rules_box.curvalue == 1)
-		return;
-	M_Menu_DMOptions_f();
-}
-
-void RulesChangeFunc ( void * )
-{
-	// DM
-	if (s_rules_box.curvalue == 0)
-	{
-		s_maxclients_field.generic.statusbar = NULL;
-		s_startserver_dmoptions_action.generic.statusbar = NULL;
-	}
-	else if(s_rules_box.curvalue == 1)		// coop				// PGM
-	{
-		s_maxclients_field.generic.statusbar = "4 maximum for cooperative";
-		if (atoi(s_maxclients_field.buffer) > 4)
-			strcpy( s_maxclients_field.buffer, "4" );
-		s_startserver_dmoptions_action.generic.statusbar = "N/A for cooperative";
-	}
-//=====
-//PGM
-	// ROGUE GAMES
-	else if(Developer_searchpath(2) == 2)
-	{
-		if (s_rules_box.curvalue == 2)			// tag	
-		{
-			s_maxclients_field.generic.statusbar = NULL;
-			s_startserver_dmoptions_action.generic.statusbar = NULL;
-		}
-/*
-		else if(s_rules_box.curvalue == 3)		// deathball
-		{
-			s_maxclients_field.generic.statusbar = NULL;
-			s_startserver_dmoptions_action.generic.statusbar = NULL;
-		}
-*/
-	}
-//PGM
-//=====
-}
-
-void StartServerActionFunc( void * )
-{
-	char	startmap[1024];
-	int		timelimit;
-	int		fraglimit;
-	int		maxclients;
-	char	*spot;
-
-	strcpy( startmap, strchr( mapnames[s_startmap_list.curvalue], '\n' ) + 1 );
-
-	maxclients  = atoi( s_maxclients_field.buffer );
-	timelimit	= atoi( s_timelimit_field.buffer );
-	fraglimit	= atoi( s_fraglimit_field.buffer );
-
-	Cvar_SetValue( "maxclients", ClampCvar( 0, maxclients, maxclients ) );
-	Cvar_SetValue ("timelimit", ClampCvar( 0, timelimit, timelimit ) );
-	Cvar_SetValue ("fraglimit", ClampCvar( 0, fraglimit, fraglimit ) );
-	Cvar_Set("hostname", s_hostname_field.buffer );
-//	Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
-//	Cvar_SetValue ("coop", s_rules_box.curvalue );
-
-//PGM
-	if((s_rules_box.curvalue < 2) || (Developer_searchpath(2) != 2))
-	{
-		Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
-		Cvar_SetValue ("coop", s_rules_box.curvalue );
-		Cvar_SetValue ("gamerules", 0 );
-	}
-	else
-	{
-		Cvar_SetValue ("deathmatch", 1 );	// deathmatch is always true for rogue games, right?
-		Cvar_SetValue ("coop", 0 );			// FIXME - this might need to depend on which game we're running
-		Cvar_SetValue ("gamerules", s_rules_box.curvalue );
-	}
-//PGM
-
-	spot = NULL;
-	if (s_rules_box.curvalue == 1)		// PGM
-	{
- 		if(cistrcmp(startmap, "bunk1") == 0)
-  			spot = "start";
- 		else if(cistrcmp(startmap, "mintro") == 0)
-  			spot = "start";
- 		else if(cistrcmp(startmap, "fact1") == 0)
-  			spot = "start";
- 		else if(cistrcmp(startmap, "power1") == 0)
-  			spot = "pstart";
- 		else if(cistrcmp(startmap, "biggun") == 0)
-  			spot = "bstart";
- 		else if(cistrcmp(startmap, "hangar1") == 0)
-  			spot = "unitstart";
- 		else if(cistrcmp(startmap, "city1") == 0)
-  			spot = "unitstart";
- 		else if(cistrcmp(startmap, "boss1") == 0)
-			spot = "bosstart";
-	}
-
-	if (spot)
-	{
-		if (Com_ServerState())
-			Cbuf_AddText ("disconnect\n");
-		Cbuf_AddText (va("gamemap \"*%s$%s\"\n", startmap, spot));
-	}
-	else
-	{
-		Cbuf_AddText (va("map %s\n", startmap));
-	}
-
-	M_ForceMenuOff ();
-}
-
-void StartServer_MenuInit( void )
-{
-	static const char *dm_coop_names[] =
-	{
-		"deathmatch",
-		"cooperative",
-		0
-	};
-//=======
-//PGM
-	static const char *dm_coop_names_rogue[] =
-	{
-		"deathmatch",
-		"cooperative",
-		"tag",
-//		"deathball",
-		0
-	};
-//PGM
-//=======
-	char *buffer;
-	char  mapsname[1024];
-	char *s;
-	int length;
-	int i;
-	FILE *fp;
-
-	/*
-	** load the list of map names
-	*/
-	Com_sprintf( mapsname, sizeof( mapsname ), "%s/maps.lst", FS_Gamedir() );
-	if ( ( fp = fopen( mapsname, "rb" ) ) == 0 )
-	{
-		if ( ( length = FS_LoadFile( "maps.lst", ( void ** ) &buffer ) ) == -1 )
-			Com_Error( ERR_DROP, "couldn't find maps.lst\n" );
-	}
-	else
-	{
-#ifdef _WIN32
-		length = filelength( fileno( fp  ) );
-#else
-		fseek(fp, 0, SEEK_END);
-		length = ftell(fp);
-		fseek(fp, 0, SEEK_SET);
-#endif
-		buffer = malloc( length );
-		fread( buffer, length, 1, fp );
-	}
-
-	s = buffer;
-
-	i = 0;
-	while ( i < length )
-	{
-		if ( s[i] == '\r' )
-			nummaps++;
-		i++;
-	}
-
-	if ( nummaps == 0 )
-		Com_Error( ERR_DROP, "no maps in maps.lst\n" );
-
-	mapnames = malloc( sizeof( char * ) * ( nummaps + 1 ) );
-	memset( mapnames, 0, sizeof( char * ) * ( nummaps + 1 ) );
-
-	s = buffer;
-
-	for ( i = 0; i < nummaps; i++ )
-	{
-    char  shortname[MAX_TOKEN_CHARS];
-    char  longname[MAX_TOKEN_CHARS];
-		char  scratch[200];
-		int		j, l;
-
-		strcpy( shortname, COM_Parse( &s ) );
-		l = strlen(shortname);
-		for (j=0 ; j<l ; j++)
-			shortname[j] = toupper(shortname[j]);
-		strcpy( longname, COM_Parse( &s ) );
-		Com_sprintf( scratch, sizeof( scratch ), "%s\n%s", longname, shortname );
-
-		mapnames[i] = malloc( strlen( scratch ) + 1 );
-		strcpy( mapnames[i], scratch );
-	}
-	mapnames[nummaps] = 0;
-
-	if ( fp != 0 )
-	{
-		free( buffer );
-	}
-	else
-	{
-		FS_FreeFile( buffer );
-	}
-
-	/*
-	** initialize the menu stuff
-	*/
-	s_startserver_menu.x = vid.width * 0.50;
-	s_startserver_menu.nitems = 0;
-
-	s_startmap_list.generic.type = MTYPE_SPINCONTROL;
-	s_startmap_list.generic.x	= 0;
-	s_startmap_list.generic.y	= 0;
-	s_startmap_list.generic.name	= "initial map";
-	s_startmap_list.itemnames = mapnames;
-
-	s_rules_box.generic.type = MTYPE_SPINCONTROL;
-	s_rules_box.generic.x	= 0;
-	s_rules_box.generic.y	= 20;
-	s_rules_box.generic.name	= "rules";
-	
-//PGM - rogue games only available with rogue DLL.
-	if(Developer_searchpath(2) == 2)
-		s_rules_box.itemnames = dm_coop_names_rogue;
-	else
-		s_rules_box.itemnames = dm_coop_names;
-//PGM
-
-	if (Cvar_VariableValue("coop"))
-		s_rules_box.curvalue = 1;
-	else
-		s_rules_box.curvalue = 0;
-	s_rules_box.generic.callback = RulesChangeFunc;
-
-	s_timelimit_field.generic.type = MTYPE_FIELD;
-	s_timelimit_field.generic.name = "time limit";
-	s_timelimit_field.generic.flags = QMF_NUMBERSONLY;
-	s_timelimit_field.generic.x	= 0;
-	s_timelimit_field.generic.y	= 36;
-	s_timelimit_field.generic.statusbar = "0 = no limit";
-	s_timelimit_field.length = 3;
-	s_timelimit_field.visible_length = 3;
-	strcpy( s_timelimit_field.buffer, Cvar_VariableString("timelimit") );
-
-	s_fraglimit_field.generic.type = MTYPE_FIELD;
-	s_fraglimit_field.generic.name = "frag limit";
-	s_fraglimit_field.generic.flags = QMF_NUMBERSONLY;
-	s_fraglimit_field.generic.x	= 0;
-	s_fraglimit_field.generic.y	= 54;
-	s_fraglimit_field.generic.statusbar = "0 = no limit";
-	s_fraglimit_field.length = 3;
-	s_fraglimit_field.visible_length = 3;
-	strcpy( s_fraglimit_field.buffer, Cvar_VariableString("fraglimit") );
-
-	/*
-	** maxclients determines the maximum number of players that can join
-	** the game.  If maxclients is only "1" then we should default the menu
-	** option to 8 players, otherwise use whatever its current value is. 
-	** Clamping will be done when the server is actually started.
-	*/
-	s_maxclients_field.generic.type = MTYPE_FIELD;
-	s_maxclients_field.generic.name = "max players";
-	s_maxclients_field.generic.flags = QMF_NUMBERSONLY;
-	s_maxclients_field.generic.x	= 0;
-	s_maxclients_field.generic.y	= 72;
-	s_maxclients_field.generic.statusbar = NULL;
-	s_maxclients_field.length = 3;
-	s_maxclients_field.visible_length = 3;
-	if ( Cvar_VariableValue( "maxclients" ) == 1 )
-		strcpy( s_maxclients_field.buffer, "8" );
-	else 
-		strcpy( s_maxclients_field.buffer, Cvar_VariableString("maxclients") );
-
-	s_hostname_field.generic.type = MTYPE_FIELD;
-	s_hostname_field.generic.name = "hostname";
-	s_hostname_field.generic.flags = 0;
-	s_hostname_field.generic.x	= 0;
-	s_hostname_field.generic.y	= 90;
-	s_hostname_field.generic.statusbar = NULL;
-	s_hostname_field.length = 12;
-	s_hostname_field.visible_length = 12;
-	strcpy( s_hostname_field.buffer, Cvar_VariableString("hostname") );
-
-	s_startserver_dmoptions_action.generic.type = MTYPE_ACTION;
-	s_startserver_dmoptions_action.generic.name	= " deathmatch flags";
-	s_startserver_dmoptions_action.generic.flags= QMF_LEFT_JUSTIFY;
-	s_startserver_dmoptions_action.generic.x	= 24;
-	s_startserver_dmoptions_action.generic.y	= 108;
-	s_startserver_dmoptions_action.generic.statusbar = NULL;
-	s_startserver_dmoptions_action.generic.callback = DMOptionsFunc;
-
-	s_startserver_start_action.generic.type = MTYPE_ACTION;
-	s_startserver_start_action.generic.name	= " begin";
-	s_startserver_start_action.generic.flags= QMF_LEFT_JUSTIFY;
-	s_startserver_start_action.generic.x	= 24;
-	s_startserver_start_action.generic.y	= 128;
-	s_startserver_start_action.generic.callback = StartServerActionFunc;
-
-	Menu_AddItem( &s_startserver_menu, &s_startmap_list );
-	Menu_AddItem( &s_startserver_menu, &s_rules_box );
-	Menu_AddItem( &s_startserver_menu, &s_timelimit_field );
-	Menu_AddItem( &s_startserver_menu, &s_fraglimit_field );
-	Menu_AddItem( &s_startserver_menu, &s_maxclients_field );
-	Menu_AddItem( &s_startserver_menu, &s_hostname_field );
-	Menu_AddItem( &s_startserver_menu, &s_startserver_dmoptions_action );
-	Menu_AddItem( &s_startserver_menu, &s_startserver_start_action );
-
-	Menu_Center( &s_startserver_menu );
-
-	// call this now to set proper inital state
-	RulesChangeFunc ( NULL );
-}
-
-void StartServer_MenuDraw(void)
-{
-	Menu_Draw( &s_startserver_menu );
-}
-
-const char *StartServer_MenuKey( int key )
-{
-	if ( key == K_ESCAPE )
-	{
-		if ( mapnames )
-		{
-			int i;
-
-			for ( i = 0; i < nummaps; i++ )
-				free( mapnames[i] );
-			free( mapnames );
-		}
-		mapnames = 0;
-		nummaps = 0;
-	}
-
-	return Default_MenuKey( &s_startserver_menu, key );
-}
-
-void M_Menu_StartServer_f (void)
-{
-	StartServer_MenuInit();
-	M_PushMenu( StartServer_MenuDraw, StartServer_MenuKey );
-}
-
-/*
-=============================================================================
-
-DMOPTIONS BOOK MENU
-
-=============================================================================
-*/
-static char dmoptions_statusbar[128];
-
-static menuframework_s s_dmoptions_menu;
-
-static menulist_s	s_friendlyfire_box;
-static menulist_s	s_falls_box;
-static menulist_s	s_weapons_stay_box;
-static menulist_s	s_instant_powerups_box;
-static menulist_s	s_powerups_box;
-static menulist_s	s_health_box;
-static menulist_s	s_spawn_farthest_box;
-static menulist_s	s_teamplay_box;
-static menulist_s	s_samelevel_box;
-static menulist_s	s_force_respawn_box;
-static menulist_s	s_armor_box;
-static menulist_s	s_allow_exit_box;
-static menulist_s	s_infinite_ammo_box;
-static menulist_s	s_fixed_fov_box;
-static menulist_s	s_quad_drop_box;
-
-//ROGUE
-static menulist_s	s_no_mines_box;
-static menulist_s	s_no_nukes_box;
-static menulist_s	s_stack_double_box;
-static menulist_s	s_no_spheres_box;
-//ROGUE
-
-static void DMFlagCallback( void *self )
-{
-	menulist_s *f = ( menulist_s * ) self;
-	int flags;
-	int bit = 0;
-
-	flags = Cvar_VariableValue( "dmflags" );
-
-	if ( f == &s_friendlyfire_box )
-	{
-		if ( f->curvalue )
-			flags &= ~DF_NO_FRIENDLY_FIRE;
-		else
-			flags |= DF_NO_FRIENDLY_FIRE;
-		goto setvalue;
-	}
-	else if ( f == &s_falls_box )
-	{
-		if ( f->curvalue )
-			flags &= ~DF_NO_FALLING;
-		else
-			flags |= DF_NO_FALLING;
-		goto setvalue;
-	}
-	else if ( f == &s_weapons_stay_box ) 
-	{
-		bit = DF_WEAPONS_STAY;
-	}
-	else if ( f == &s_instant_powerups_box )
-	{
-		bit = DF_INSTANT_ITEMS;
-	}
-	else if ( f == &s_allow_exit_box )
-	{
-		bit = DF_ALLOW_EXIT;
-	}
-	else if ( f == &s_powerups_box )
-	{
-		if ( f->curvalue )
-			flags &= ~DF_NO_ITEMS;
-		else
-			flags |= DF_NO_ITEMS;
-		goto setvalue;
-	}
-	else if ( f == &s_health_box )
-	{
-		if ( f->curvalue )
-			flags &= ~DF_NO_HEALTH;
-		else
-			flags |= DF_NO_HEALTH;
-		goto setvalue;
-	}
-	else if ( f == &s_spawn_farthest_box )
-	{
-		bit = DF_SPAWN_FARTHEST;
-	}
-	else if ( f == &s_teamplay_box )
-	{
-		if ( f->curvalue == 1 )
-		{
-			flags |=  DF_SKINTEAMS;
-			flags &= ~DF_MODELTEAMS;
-		}
-		else if ( f->curvalue == 2 )
-		{
-			flags |=  DF_MODELTEAMS;
-			flags &= ~DF_SKINTEAMS;
-		}
-		else
-		{
-			flags &= ~( DF_MODELTEAMS | DF_SKINTEAMS );
-		}
-
-		goto setvalue;
-	}
-	else if ( f == &s_samelevel_box )
-	{
-		bit = DF_SAME_LEVEL;
-	}
-	else if ( f == &s_force_respawn_box )
-	{
-		bit = DF_FORCE_RESPAWN;
-	}
-	else if ( f == &s_armor_box )
-	{
-		if ( f->curvalue )
-			flags &= ~DF_NO_ARMOR;
-		else
-			flags |= DF_NO_ARMOR;
-		goto setvalue;
-	}
-	else if ( f == &s_infinite_ammo_box )
-	{
-		bit = DF_INFINITE_AMMO;
-	}
-	else if ( f == &s_fixed_fov_box )
-	{
-		bit = DF_FIXED_FOV;
-	}
-	else if ( f == &s_quad_drop_box )
-	{
-		bit = DF_QUAD_DROP;
-	}
-
-//=======
-//ROGUE
-	else if (Developer_searchpath(2) == 2)
-	{
-		if ( f == &s_no_mines_box)
-		{
-			bit = DF_NO_MINES;
-		}
-		else if ( f == &s_no_nukes_box)
-		{
-			bit = DF_NO_NUKES;
-		}
-		else if ( f == &s_stack_double_box)
-		{
-			bit = DF_NO_STACK_DOUBLE;
-		}
-		else if ( f == &s_no_spheres_box)
-		{
-			bit = DF_NO_SPHERES;
-		}
-	}
-//ROGUE
-//=======
-
-	if ( f )
-	{
-		if ( f->curvalue == 0 )
-			flags &= ~bit;
-		else
-			flags |= bit;
-	}
-
-setvalue:
-	Cvar_SetValue ("dmflags", flags);
-
-	Com_sprintf( dmoptions_statusbar, sizeof( dmoptions_statusbar ), "dmflags = %d", flags );
-
-}
-
-void DMOptions_MenuInit( void )
-{
-	static const char *yes_no_names[] =
-	{
-		"no", "yes", 0
-	};
-	static const char *teamplay_names[] = 
-	{
-		"disabled", "by skin", "by model", 0
-	};
-	int dmflags = Cvar_VariableValue( "dmflags" );
-	int y = 0;
-
-	s_dmoptions_menu.x = vid.width * 0.50;
-	s_dmoptions_menu.nitems = 0;
-
-	s_falls_box.generic.type = MTYPE_SPINCONTROL;
-	s_falls_box.generic.x	= 0;
-	s_falls_box.generic.y	= y;
-	s_falls_box.generic.name	= "falling damage";
-	s_falls_box.generic.callback = DMFlagCallback;
-	s_falls_box.itemnames = yes_no_names;
-	s_falls_box.curvalue = ( dmflags & DF_NO_FALLING ) == 0;
-
-	s_weapons_stay_box.generic.type = MTYPE_SPINCONTROL;
-	s_weapons_stay_box.generic.x	= 0;
-	s_weapons_stay_box.generic.y	= y += 10;
-	s_weapons_stay_box.generic.name	= "weapons stay";
-	s_weapons_stay_box.generic.callback = DMFlagCallback;
-	s_weapons_stay_box.itemnames = yes_no_names;
-	s_weapons_stay_box.curvalue = ( dmflags & DF_WEAPONS_STAY ) != 0;
-
-	s_instant_powerups_box.generic.type = MTYPE_SPINCONTROL;
-	s_instant_powerups_box.generic.x	= 0;
-	s_instant_powerups_box.generic.y	= y += 10;
-	s_instant_powerups_box.generic.name	= "instant powerups";
-	s_instant_powerups_box.generic.callback = DMFlagCallback;
-	s_instant_powerups_box.itemnames = yes_no_names;
-	s_instant_powerups_box.curvalue = ( dmflags & DF_INSTANT_ITEMS ) != 0;
-
-	s_powerups_box.generic.type = MTYPE_SPINCONTROL;
-	s_powerups_box.generic.x	= 0;
-	s_powerups_box.generic.y	= y += 10;
-	s_powerups_box.generic.name	= "allow powerups";
-	s_powerups_box.generic.callback = DMFlagCallback;
-	s_powerups_box.itemnames = yes_no_names;
-	s_powerups_box.curvalue = ( dmflags & DF_NO_ITEMS ) == 0;
-
-	s_health_box.generic.type = MTYPE_SPINCONTROL;
-	s_health_box.generic.x	= 0;
-	s_health_box.generic.y	= y += 10;
-	s_health_box.generic.callback = DMFlagCallback;
-	s_health_box.generic.name	= "allow health";
-	s_health_box.itemnames = yes_no_names;
-	s_health_box.curvalue = ( dmflags & DF_NO_HEALTH ) == 0;
-
-	s_armor_box.generic.type = MTYPE_SPINCONTROL;
-	s_armor_box.generic.x	= 0;
-	s_armor_box.generic.y	= y += 10;
-	s_armor_box.generic.name	= "allow armor";
-	s_armor_box.generic.callback = DMFlagCallback;
-	s_armor_box.itemnames = yes_no_names;
-	s_armor_box.curvalue = ( dmflags & DF_NO_ARMOR ) == 0;
-
-	s_spawn_farthest_box.generic.type = MTYPE_SPINCONTROL;
-	s_spawn_farthest_box.generic.x	= 0;
-	s_spawn_farthest_box.generic.y	= y += 10;
-	s_spawn_farthest_box.generic.name	= "spawn farthest";
-	s_spawn_farthest_box.generic.callback = DMFlagCallback;
-	s_spawn_farthest_box.itemnames = yes_no_names;
-	s_spawn_farthest_box.curvalue = ( dmflags & DF_SPAWN_FARTHEST ) != 0;
-
-	s_samelevel_box.generic.type = MTYPE_SPINCONTROL;
-	s_samelevel_box.generic.x	= 0;
-	s_samelevel_box.generic.y	= y += 10;
-	s_samelevel_box.generic.name	= "same map";
-	s_samelevel_box.generic.callback = DMFlagCallback;
-	s_samelevel_box.itemnames = yes_no_names;
-	s_samelevel_box.curvalue = ( dmflags & DF_SAME_LEVEL ) != 0;
-
-	s_force_respawn_box.generic.type = MTYPE_SPINCONTROL;
-	s_force_respawn_box.generic.x	= 0;
-	s_force_respawn_box.generic.y	= y += 10;
-	s_force_respawn_box.generic.name	= "force respawn";
-	s_force_respawn_box.generic.callback = DMFlagCallback;
-	s_force_respawn_box.itemnames = yes_no_names;
-	s_force_respawn_box.curvalue = ( dmflags & DF_FORCE_RESPAWN ) != 0;
-
-	s_teamplay_box.generic.type = MTYPE_SPINCONTROL;
-	s_teamplay_box.generic.x	= 0;
-	s_teamplay_box.generic.y	= y += 10;
-	s_teamplay_box.generic.name	= "teamplay";
-	s_teamplay_box.generic.callback = DMFlagCallback;
-	s_teamplay_box.itemnames = teamplay_names;
-
-	s_allow_exit_box.generic.type = MTYPE_SPINCONTROL;
-	s_allow_exit_box.generic.x	= 0;
-	s_allow_exit_box.generic.y	= y += 10;
-	s_allow_exit_box.generic.name	= "allow exit";
-	s_allow_exit_box.generic.callback = DMFlagCallback;
-	s_allow_exit_box.itemnames = yes_no_names;
-	s_allow_exit_box.curvalue = ( dmflags & DF_ALLOW_EXIT ) != 0;
-
-	s_infinite_ammo_box.generic.type = MTYPE_SPINCONTROL;
-	s_infinite_ammo_box.generic.x	= 0;
-	s_infinite_ammo_box.generic.y	= y += 10;
-	s_infinite_ammo_box.generic.name	= "infinite ammo";
-	s_infinite_ammo_box.generic.callback = DMFlagCallback;
-	s_infinite_ammo_box.itemnames = yes_no_names;
-	s_infinite_ammo_box.curvalue = ( dmflags & DF_INFINITE_AMMO ) != 0;
-
-	s_fixed_fov_box.generic.type = MTYPE_SPINCONTROL;
-	s_fixed_fov_box.generic.x	= 0;
-	s_fixed_fov_box.generic.y	= y += 10;
-	s_fixed_fov_box.generic.name	= "fixed FOV";
-	s_fixed_fov_box.generic.callback = DMFlagCallback;
-	s_fixed_fov_box.itemnames = yes_no_names;
-	s_fixed_fov_box.curvalue = ( dmflags & DF_FIXED_FOV ) != 0;
-
-	s_quad_drop_box.generic.type = MTYPE_SPINCONTROL;
-	s_quad_drop_box.generic.x	= 0;
-	s_quad_drop_box.generic.y	= y += 10;
-	s_quad_drop_box.generic.name	= "quad drop";
-	s_quad_drop_box.generic.callback = DMFlagCallback;
-	s_quad_drop_box.itemnames = yes_no_names;
-	s_quad_drop_box.curvalue = ( dmflags & DF_QUAD_DROP ) != 0;
-
-	s_friendlyfire_box.generic.type = MTYPE_SPINCONTROL;
-	s_friendlyfire_box.generic.x	= 0;
-	s_friendlyfire_box.generic.y	= y += 10;
-	s_friendlyfire_box.generic.name	= "friendly fire";
-	s_friendlyfire_box.generic.callback = DMFlagCallback;
-	s_friendlyfire_box.itemnames = yes_no_names;
-	s_friendlyfire_box.curvalue = ( dmflags & DF_NO_FRIENDLY_FIRE ) == 0;
-
-//============
-//ROGUE
-	if(Developer_searchpath(2) == 2)
-	{
-		s_no_mines_box.generic.type = MTYPE_SPINCONTROL;
-		s_no_mines_box.generic.x	= 0;
-		s_no_mines_box.generic.y	= y += 10;
-		s_no_mines_box.generic.name	= "remove mines";
-		s_no_mines_box.generic.callback = DMFlagCallback;
-		s_no_mines_box.itemnames = yes_no_names;
-		s_no_mines_box.curvalue = ( dmflags & DF_NO_MINES ) != 0;
-
-		s_no_nukes_box.generic.type = MTYPE_SPINCONTROL;
-		s_no_nukes_box.generic.x	= 0;
-		s_no_nukes_box.generic.y	= y += 10;
-		s_no_nukes_box.generic.name	= "remove nukes";
-		s_no_nukes_box.generic.callback = DMFlagCallback;
-		s_no_nukes_box.itemnames = yes_no_names;
-		s_no_nukes_box.curvalue = ( dmflags & DF_NO_NUKES ) != 0;
-
-		s_stack_double_box.generic.type = MTYPE_SPINCONTROL;
-		s_stack_double_box.generic.x	= 0;
-		s_stack_double_box.generic.y	= y += 10;
-		s_stack_double_box.generic.name	= "2x/4x stacking off";
-		s_stack_double_box.generic.callback = DMFlagCallback;
-		s_stack_double_box.itemnames = yes_no_names;
-		s_stack_double_box.curvalue = ( dmflags & DF_NO_STACK_DOUBLE ) != 0;
-
-		s_no_spheres_box.generic.type = MTYPE_SPINCONTROL;
-		s_no_spheres_box.generic.x	= 0;
-		s_no_spheres_box.generic.y	= y += 10;
-		s_no_spheres_box.generic.name	= "remove spheres";
-		s_no_spheres_box.generic.callback = DMFlagCallback;
-		s_no_spheres_box.itemnames = yes_no_names;
-		s_no_spheres_box.curvalue = ( dmflags & DF_NO_SPHERES ) != 0;
-
-	}
-//ROGUE
-//============
-
-	Menu_AddItem( &s_dmoptions_menu, &s_falls_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_weapons_stay_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_instant_powerups_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_powerups_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_health_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_armor_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_spawn_farthest_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_samelevel_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_force_respawn_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_teamplay_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_allow_exit_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_infinite_ammo_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_fixed_fov_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_quad_drop_box );
-	Menu_AddItem( &s_dmoptions_menu, &s_friendlyfire_box );
-
-//=======
-//ROGUE
-	if(Developer_searchpath(2) == 2)
-	{
-		Menu_AddItem( &s_dmoptions_menu, &s_no_mines_box );
-		Menu_AddItem( &s_dmoptions_menu, &s_no_nukes_box );
-		Menu_AddItem( &s_dmoptions_menu, &s_stack_double_box );
-		Menu_AddItem( &s_dmoptions_menu, &s_no_spheres_box );
-	}
-//ROGUE
-//=======
-
-	Menu_Center( &s_dmoptions_menu );
-
-	// set the original dmflags statusbar
-	DMFlagCallback( 0 );
-	Menu_SetStatusBar( &s_dmoptions_menu, dmoptions_statusbar );
-}
-
-void DMOptions_MenuDraw(void)
-{
-	Menu_Draw( &s_dmoptions_menu );
-}
-
-const char *DMOptions_MenuKey( int key )
-{
-	return Default_MenuKey( &s_dmoptions_menu, key );
-}
-
-void M_Menu_DMOptions_f (void)
-{
-	DMOptions_MenuInit();
-	M_PushMenu( DMOptions_MenuDraw, DMOptions_MenuKey );
-}
-
-/*
-=============================================================================
-
-DOWNLOADOPTIONS BOOK MENU
-
-=============================================================================
-*/
-static menuframework_s s_downloadoptions_menu;
-
-static menuseparator_s	s_download_title;
-static menulist_s	s_allow_download_box;
-static menulist_s	s_allow_download_maps_box;
-static menulist_s	s_allow_download_models_box;
-static menulist_s	s_allow_download_players_box;
-static menulist_s	s_allow_download_sounds_box;
-
-static void DownloadCallback( void *self )
-{
-	menulist_s *f = ( menulist_s * ) self;
-
-	if (f == &s_allow_download_box)
-	{
-		Cvar_SetValue("allow_download", f->curvalue);
-	}
-
-	else if (f == &s_allow_download_maps_box)
-	{
-		Cvar_SetValue("allow_download_maps", f->curvalue);
-	}
-
-	else if (f == &s_allow_download_models_box)
-	{
-		Cvar_SetValue("allow_download_models", f->curvalue);
-	}
-
-	else if (f == &s_allow_download_players_box)
-	{
-		Cvar_SetValue("allow_download_players", f->curvalue);
-	}
-
-	else if (f == &s_allow_download_sounds_box)
-	{
-		Cvar_SetValue("allow_download_sounds", f->curvalue);
-	}
-}
-
-void DownloadOptions_MenuInit( void )
-{
-	static const char *yes_no_names[] =
-	{
-		"no", "yes", 0
-	};
-	int y = 0;
-
-	s_downloadoptions_menu.x = vid.width * 0.50;
-	s_downloadoptions_menu.nitems = 0;
-
-	s_download_title.generic.type = MTYPE_SEPARATOR;
-	s_download_title.generic.name = "Download Options";
-	s_download_title.generic.x    = 48;
-	s_download_title.generic.y	 = y;
-
-	s_allow_download_box.generic.type = MTYPE_SPINCONTROL;
-	s_allow_download_box.generic.x	= 0;
-	s_allow_download_box.generic.y	= y += 20;
-	s_allow_download_box.generic.name	= "allow downloading";
-	s_allow_download_box.generic.callback = DownloadCallback;
-	s_allow_download_box.itemnames = yes_no_names;
-	s_allow_download_box.curvalue = (Cvar_VariableValue("allow_download") != 0);
-
-	s_allow_download_maps_box.generic.type = MTYPE_SPINCONTROL;
-	s_allow_download_maps_box.generic.x	= 0;
-	s_allow_download_maps_box.generic.y	= y += 20;
-	s_allow_download_maps_box.generic.name	= "maps";
-	s_allow_download_maps_box.generic.callback = DownloadCallback;
-	s_allow_download_maps_box.itemnames = yes_no_names;
-	s_allow_download_maps_box.curvalue = (Cvar_VariableValue("allow_download_maps") != 0);
-
-	s_allow_download_players_box.generic.type = MTYPE_SPINCONTROL;
-	s_allow_download_players_box.generic.x	= 0;
-	s_allow_download_players_box.generic.y	= y += 10;
-	s_allow_download_players_box.generic.name	= "player models/skins";
-	s_allow_download_players_box.generic.callback = DownloadCallback;
-	s_allow_download_players_box.itemnames = yes_no_names;
-	s_allow_download_players_box.curvalue = (Cvar_VariableValue("allow_download_players") != 0);
-
-	s_allow_download_models_box.generic.type = MTYPE_SPINCONTROL;
-	s_allow_download_models_box.generic.x	= 0;
-	s_allow_download_models_box.generic.y	= y += 10;
-	s_allow_download_models_box.generic.name	= "models";
-	s_allow_download_models_box.generic.callback = DownloadCallback;
-	s_allow_download_models_box.itemnames = yes_no_names;
-	s_allow_download_models_box.curvalue = (Cvar_VariableValue("allow_download_models") != 0);
-
-	s_allow_download_sounds_box.generic.type = MTYPE_SPINCONTROL;
-	s_allow_download_sounds_box.generic.x	= 0;
-	s_allow_download_sounds_box.generic.y	= y += 10;
-	s_allow_download_sounds_box.generic.name	= "sounds";
-	s_allow_download_sounds_box.generic.callback = DownloadCallback;
-	s_allow_download_sounds_box.itemnames = yes_no_names;
-	s_allow_download_sounds_box.curvalue = (Cvar_VariableValue("allow_download_sounds") != 0);
-
-	Menu_AddItem( &s_downloadoptions_menu, &s_download_title );
-	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_box );
-	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_maps_box );
-	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_players_box );
-	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_models_box );
-	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_sounds_box );
-
-	Menu_Center( &s_downloadoptions_menu );
-
-	// skip over title
-	if (s_downloadoptions_menu.cursor == 0)
-		s_downloadoptions_menu.cursor = 1;
-}
-
-void DownloadOptions_MenuDraw(void)
-{
-	Menu_Draw( &s_downloadoptions_menu );
-}
-
-const char *DownloadOptions_MenuKey( int key )
-{
-	return Default_MenuKey( &s_downloadoptions_menu, key );
-}
-
-void M_Menu_DownloadOptions_f (void)
-{
-	DownloadOptions_MenuInit();
-	M_PushMenu( DownloadOptions_MenuDraw, DownloadOptions_MenuKey );
-}
-/*
-=============================================================================
-
-ADDRESS BOOK MENU
-
-=============================================================================
-*/
-#define NUM_ADDRESSBOOK_ENTRIES 9
-
-static menuframework_s	s_addressbook_menu;
-static menufield_s		s_addressbook_fields[NUM_ADDRESSBOOK_ENTRIES];
-
-void AddressBook_MenuInit( void )
-{
-	int i;
-
-	s_addressbook_menu.x = vid.width / 2 - 142;
-	s_addressbook_menu.y = vid.height / 2 - 58;
-	s_addressbook_menu.nitems = 0;
-
-	for ( i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++ )
-	{
-		cvar_t *adr;
-		char buffer[20];
-
-		Com_sprintf( buffer, sizeof( buffer ), "adr%d", i );
-
-		adr = Cvar_Get( buffer, "", CVAR_ARCHIVE );
-
-		s_addressbook_fields[i].generic.type = MTYPE_FIELD;
-		s_addressbook_fields[i].generic.name = 0;
-		s_addressbook_fields[i].generic.callback = 0;
-		s_addressbook_fields[i].generic.x		= 0;
-		s_addressbook_fields[i].generic.y		= i * 18 + 0;
-		s_addressbook_fields[i].generic.localdata[0] = i;
-		s_addressbook_fields[i].cursor			= 0;
-		s_addressbook_fields[i].length			= 60;
-		s_addressbook_fields[i].visible_length	= 30;
-
-		strcpy( s_addressbook_fields[i].buffer, adr->string );
-
-		Menu_AddItem( &s_addressbook_menu, &s_addressbook_fields[i] );
-	}
-}
-
-const char *AddressBook_MenuKey( int key )
-{
-	if ( key == K_ESCAPE )
-	{
-		int index;
-		char buffer[20];
-
-		for ( index = 0; index < NUM_ADDRESSBOOK_ENTRIES; index++ )
-		{
-			Com_sprintf( buffer, sizeof( buffer ), "adr%d", index );
-			Cvar_Set( buffer, s_addressbook_fields[index].buffer );
-		}
-	}
-	return Default_MenuKey( &s_addressbook_menu, key );
-}
-
-void AddressBook_MenuDraw(void)
-{
-	M_Banner( "m_banner_addressbook" );
-	Menu_Draw( &s_addressbook_menu );
-}
-
-void M_Menu_AddressBook_f(void)
-{
-	AddressBook_MenuInit();
-	M_PushMenu( AddressBook_MenuDraw, AddressBook_MenuKey );
-}
-
-/*
-=============================================================================
-
-PLAYER CONFIG MENU
-
-=============================================================================
-*/
-static menuframework_s	s_player_config_menu;
-static menufield_s		s_player_name_field;
-static menulist_s		s_player_model_box;
-static menulist_s		s_player_skin_box;
-static menulist_s		s_player_handedness_box;
-static menulist_s		s_player_rate_box;
-static menuseparator_s	s_player_skin_title;
-static menuseparator_s	s_player_model_title;
-static menuseparator_s	s_player_hand_title;
-static menuseparator_s	s_player_rate_title;
-static menuaction_s		s_player_download_action;
-
-#define MAX_DISPLAYNAME 16
-#define MAX_PLAYERMODELS 1024
-
-typedef struct
-{
-	int		nskins;
-	char	**skindisplaynames;
-	char	displayname[MAX_DISPLAYNAME];
-	char	directory[MAX_QPATH];
-} playermodelinfo_s;
-
-static playermodelinfo_s s_pmi[MAX_PLAYERMODELS];
-static char *s_pmnames[MAX_PLAYERMODELS];
-static int s_numplayermodels;
-
-static int rate_tbl[] = { 2500, 3200, 5000, 10000, 25000, 0 };
-static const char *rate_names[] = { "28.8 Modem", "33.6 Modem", "Single ISDN",
-	"Dual ISDN/Cable", "T1/LAN", "User defined", 0 };
-
-void DownloadOptionsFunc( void * )
-{
-	M_Menu_DownloadOptions_f();
-}
-
-static void HandednessCallback( void * )
-{
-	Cvar_SetValue( "hand", s_player_handedness_box.curvalue );
-}
-
-static void RateCallback( void * )
-{
-	if (s_player_rate_box.curvalue != sizeof(rate_tbl) / sizeof(*rate_tbl) - 1)
-		Cvar_SetValue( "rate", rate_tbl[s_player_rate_box.curvalue] );
-}
-
-static void ModelCallback( void * )
-{
-	s_player_skin_box.itemnames = s_pmi[s_player_model_box.curvalue].skindisplaynames;
-	s_player_skin_box.curvalue = 0;
-}
-
-static void FreeFileList( char **list, int n )
-{
-	int i;
-
-	for ( i = 0; i < n; i++ )
-	{
-		if ( list[i] )
-		{
-			free( list[i] );
-			list[i] = 0;
-		}
-	}
-	free( list );
-}
-
-static qboolean IconOfSkinExists( char *skin, char **pcxfiles, int npcxfiles )
-{
-	int i;
-	char scratch[1024];
-
-	strcpy( scratch, skin );
-	*strrchr( scratch, '.' ) = 0;
-	strcat( scratch, "_i.pcx" );
-
-	for ( i = 0; i < npcxfiles; i++ )
-	{
-		if ( strcmp( pcxfiles[i], scratch ) == 0 )
-			return true;
-	}
-
-	return false;
-}
-
-static qboolean PlayerConfig_ScanDirectories( void )
-{
-	char findname[1024];
-	char scratch[1024];
-	int ndirs = 0, npms;
-	char **dirnames = NULL;
-	char *path = NULL;
-	int i;
-
-	extern char **FS_ListFiles( char *, int *, unsigned, unsigned );
-
-	s_numplayermodels = 0;
-
-	/*
-	** get a list of directories
-	*/
-	do 
-	{
-		if ( ( path = FS_NextPath( path ) ) == NULL)
-			break;
-		Com_sprintf( findname, sizeof(findname), "%s/players/*.*", path );
-
-		if ( ( dirnames = FS_ListFiles( findname, &ndirs, SFF_SUBDIR, 0 ) ) != 0 )
-			break;
-	} while ( path );
-
-	if ( !dirnames )
-		return false;
-
-	/*
-	** go through the subdirectories
-	*/
-	npms = ndirs;
-	if ( npms > MAX_PLAYERMODELS )
-		npms = MAX_PLAYERMODELS;
-
-	for ( i = 0; i < npms; i++ )
-	{
-		int k, s;
-		char *a, *b, *c;
-		char **pcxnames;
-		char **skinnames;
-		int npcxfiles;
-		int nskins = 0;
-
-		if ( dirnames[i] == 0 )
-			continue;
-
-		// verify the existence of tris.md2
-		strcpy( scratch, dirnames[i] );
-		strcat( scratch, "/tris.md2" );
-		if ( !Sys_FindFirst( scratch, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM ) )
-		{
-			free( dirnames[i] );
-			dirnames[i] = 0;
-			Sys_FindClose();
-			continue;
-		}
-		Sys_FindClose();
-
-		// verify the existence of at least one pcx skin
-		strcpy( scratch, dirnames[i] );
-		strcat( scratch, "/*.pcx" );
-		pcxnames = FS_ListFiles( scratch, &npcxfiles, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM );
-
-		if ( !pcxnames )
-		{
-			free( dirnames[i] );
-			dirnames[i] = 0;
-			continue;
-		}
-
-		// count valid skins, which consist of a skin with a matching "_i" icon
-		for ( k = 0; k < npcxfiles-1; k++ )
-		{
-			if ( !strstr( pcxnames[k], "_i.pcx" ) )
-			{
-				if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
-				{
-					nskins++;
-				}
-			}
-		}
-		if ( !nskins )
-			continue;
-
-		skinnames = malloc( sizeof( char * ) * ( nskins + 1 ) );
-		memset( skinnames, 0, sizeof( char * ) * ( nskins + 1 ) );
-
-		// copy the valid skins
-		for ( s = 0, k = 0; k < npcxfiles-1; k++ )
-		{
-			char *a, *b, *c;
-
-			if ( !strstr( pcxnames[k], "_i.pcx" ) )
-			{
-				if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
-				{
-					a = strrchr( pcxnames[k], '/' );
-					b = strrchr( pcxnames[k], '\\' );
-
-					if ( a > b )
-						c = a;
-					else
-						c = b;
-
-					strcpy( scratch, c + 1 );
-
-					if ( strrchr( scratch, '.' ) )
-						*strrchr( scratch, '.' ) = 0;
-
-					skinnames[s] = strdup( scratch );
-					s++;
-				}
-			}
-		}
-
-		// at this point we have a valid player model
-		s_pmi[s_numplayermodels].nskins = nskins;
-		s_pmi[s_numplayermodels].skindisplaynames = skinnames;
-
-		// make short name for the model
-		a = strrchr( dirnames[i], '/' );
-		b = strrchr( dirnames[i], '\\' );
-
-		if ( a > b )
-			c = a;
-		else
-			c = b;
-
-		strncpy( s_pmi[s_numplayermodels].displayname, c + 1, MAX_DISPLAYNAME-1 );
-		strcpy( s_pmi[s_numplayermodels].directory, c + 1 );
-
-		FreeFileList( pcxnames, npcxfiles );
-
-		s_numplayermodels++;
-	}
-	if ( dirnames )
-		FreeFileList( dirnames, ndirs );
-	return true;
-}
-
-static int pmicmpfnc( const void *_a, const void *_b )
-{
-	const playermodelinfo_s *a = ( const playermodelinfo_s * ) _a;
-	const playermodelinfo_s *b = ( const playermodelinfo_s * ) _b;
-
-	/*
-	** sort by male, female, then alphabetical
-	*/
-	if ( strcmp( a->directory, "male" ) == 0 )
-		return -1;
-	else if ( strcmp( b->directory, "male" ) == 0 )
-		return 1;
-
-	if ( strcmp( a->directory, "female" ) == 0 )
-		return -1;
-	else if ( strcmp( b->directory, "female" ) == 0 )
-		return 1;
-
-	return strcmp( a->directory, b->directory );
-}
-
-
-qboolean PlayerConfig_MenuInit( void )
-{
-	extern cvar_t *name;
-	extern cvar_t *team;
-	extern cvar_t *skin;
-	char currentdirectory[1024];
-	char currentskin[1024];
-	int i;
-
-	int currentdirectoryindex = 0;
-	int currentskinindex = 0;
-
-	cvar_t *hand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
-
-	static const char *handedness[] = { "right", "left", "center", 0 };
-
-	PlayerConfig_ScanDirectories();
-
-	if (s_numplayermodels == 0)
-		return false;
-
-	if ( hand->value < 0 || hand->value > 2 )
-		Cvar_SetValue( "hand", 0 );
-
-	strcpy( currentdirectory, skin->string );
-
-	if ( strchr( currentdirectory, '/' ) )
-	{
-		strcpy( currentskin, strchr( currentdirectory, '/' ) + 1 );
-		*strchr( currentdirectory, '/' ) = 0;
-	}
-	else if ( strchr( currentdirectory, '\\' ) )
-	{
-		strcpy( currentskin, strchr( currentdirectory, '\\' ) + 1 );
-		*strchr( currentdirectory, '\\' ) = 0;
-	}
-	else
-	{
-		strcpy( currentdirectory, "male" );
-		strcpy( currentskin, "grunt" );
-	}
-
-	qsort( s_pmi, s_numplayermodels, sizeof( s_pmi[0] ), pmicmpfnc );
-
-	memset( s_pmnames, 0, sizeof( s_pmnames ) );
-	for ( i = 0; i < s_numplayermodels; i++ )
-	{
-		s_pmnames[i] = s_pmi[i].displayname;
-		if ( cistrcmp( s_pmi[i].directory, currentdirectory ) == 0 )
-		{
-			int j;
-
-			currentdirectoryindex = i;
-
-			for ( j = 0; j < s_pmi[i].nskins; j++ )
-			{
-				if ( cistrcmp( s_pmi[i].skindisplaynames[j], currentskin ) == 0 )
-				{
-					currentskinindex = j;
-					break;
-				}
-			}
-		}
-	}
-
-	s_player_config_menu.x = vid.width / 2 - 95; 
-	s_player_config_menu.y = vid.height / 2 - 97;
-	s_player_config_menu.nitems = 0;
-
-	s_player_name_field.generic.type = MTYPE_FIELD;
-	s_player_name_field.generic.name = "name";
-	s_player_name_field.generic.callback = 0;
-	s_player_name_field.generic.x		= 0;
-	s_player_name_field.generic.y		= 0;
-	s_player_name_field.length	= 20;
-	s_player_name_field.visible_length = 20;
-	strcpy( s_player_name_field.buffer, name->string );
-	s_player_name_field.cursor = strlen( name->string );
-
-	s_player_model_title.generic.type = MTYPE_SEPARATOR;
-	s_player_model_title.generic.name = "model";
-	s_player_model_title.generic.x    = -8;
-	s_player_model_title.generic.y	 = 60;
-
-	s_player_model_box.generic.type = MTYPE_SPINCONTROL;
-	s_player_model_box.generic.x	= -56;
-	s_player_model_box.generic.y	= 70;
-	s_player_model_box.generic.callback = ModelCallback;
-	s_player_model_box.generic.cursor_offset = -48;
-	s_player_model_box.curvalue = currentdirectoryindex;
-	s_player_model_box.itemnames = s_pmnames;
-
-	s_player_skin_title.generic.type = MTYPE_SEPARATOR;
-	s_player_skin_title.generic.name = "skin";
-	s_player_skin_title.generic.x    = -16;
-	s_player_skin_title.generic.y	 = 84;
-
-	s_player_skin_box.generic.type = MTYPE_SPINCONTROL;
-	s_player_skin_box.generic.x	= -56;
-	s_player_skin_box.generic.y	= 94;
-	s_player_skin_box.generic.name	= 0;
-	s_player_skin_box.generic.callback = 0;
-	s_player_skin_box.generic.cursor_offset = -48;
-	s_player_skin_box.curvalue = currentskinindex;
-	s_player_skin_box.itemnames = s_pmi[currentdirectoryindex].skindisplaynames;
-
-	s_player_hand_title.generic.type = MTYPE_SEPARATOR;
-	s_player_hand_title.generic.name = "handedness";
-	s_player_hand_title.generic.x    = 32;
-	s_player_hand_title.generic.y	 = 108;
-
-	s_player_handedness_box.generic.type = MTYPE_SPINCONTROL;
-	s_player_handedness_box.generic.x	= -56;
-	s_player_handedness_box.generic.y	= 118;
-	s_player_handedness_box.generic.name	= 0;
-	s_player_handedness_box.generic.cursor_offset = -48;
-	s_player_handedness_box.generic.callback = HandednessCallback;
-	s_player_handedness_box.curvalue = Cvar_VariableValue( "hand" );
-	s_player_handedness_box.itemnames = handedness;
-
-	for (i = 0; i < sizeof(rate_tbl) / sizeof(*rate_tbl) - 1; i++)
-		if (Cvar_VariableValue("rate") == rate_tbl[i])
-			break;
-
-	s_player_rate_title.generic.type = MTYPE_SEPARATOR;
-	s_player_rate_title.generic.name = "connect speed";
-	s_player_rate_title.generic.x    = 56;
-	s_player_rate_title.generic.y	 = 156;
-
-	s_player_rate_box.generic.type = MTYPE_SPINCONTROL;
-	s_player_rate_box.generic.x	= -56;
-	s_player_rate_box.generic.y	= 166;
-	s_player_rate_box.generic.name	= 0;
-	s_player_rate_box.generic.cursor_offset = -48;
-	s_player_rate_box.generic.callback = RateCallback;
-	s_player_rate_box.curvalue = i;
-	s_player_rate_box.itemnames = rate_names;
-
-	s_player_download_action.generic.type = MTYPE_ACTION;
-	s_player_download_action.generic.name	= "download options";
-	s_player_download_action.generic.flags= QMF_LEFT_JUSTIFY;
-	s_player_download_action.generic.x	= -24;
-	s_player_download_action.generic.y	= 186;
-	s_player_download_action.generic.statusbar = NULL;
-	s_player_download_action.generic.callback = DownloadOptionsFunc;
-
-	Menu_AddItem( &s_player_config_menu, &s_player_name_field );
-	Menu_AddItem( &s_player_config_menu, &s_player_model_title );
-	Menu_AddItem( &s_player_config_menu, &s_player_model_box );
-	if ( s_player_skin_box.itemnames )
-	{
-		Menu_AddItem( &s_player_config_menu, &s_player_skin_title );
-		Menu_AddItem( &s_player_config_menu, &s_player_skin_box );
-	}
-	Menu_AddItem( &s_player_config_menu, &s_player_hand_title );
-	Menu_AddItem( &s_player_config_menu, &s_player_handedness_box );
-	Menu_AddItem( &s_player_config_menu, &s_player_rate_title );
-	Menu_AddItem( &s_player_config_menu, &s_player_rate_box );
-	Menu_AddItem( &s_player_config_menu, &s_player_download_action );
-
-	return true;
-}
-
-void PlayerConfig_MenuDraw( void )
-{
-	extern float CalcFov( float fov_x, float w, float h );
-	refdef_t refdef;
-	char scratch[MAX_QPATH];
-
-	memset( &refdef, 0, sizeof( refdef ) );
-
-	refdef.x = vid.width / 2;
-	refdef.y = vid.height / 2 - 72;
-	refdef.width = 144;
-	refdef.height = 168;
-	refdef.fov_x = 40;
-	refdef.fov_y = CalcFov( refdef.fov_x, refdef.width, refdef.height );
-	refdef.time = cls.realtime*0.001;
-
-	if ( s_pmi[s_player_model_box.curvalue].skindisplaynames )
-	{
-		static int yaw;
-		entity_t entity;
-
-		memset( &entity, 0, sizeof( entity ) );
-
-		Com_sprintf( scratch, sizeof( scratch ), "players/%s/tris.md2", s_pmi[s_player_model_box.curvalue].directory );
-		entity.model = re.RegisterModel( scratch );
-		Com_sprintf( scratch, sizeof( scratch ), "players/%s/%s.pcx", s_pmi[s_player_model_box.curvalue].directory, s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
-		entity.skin = re.RegisterSkin( scratch );
-		entity.flags = RF_FULLBRIGHT;
-		entity.origin[0] = 80;
-		entity.origin[1] = 0;
-		entity.origin[2] = 0;
-		VectorCopy( entity.origin, entity.oldorigin );
-		entity.frame = 0;
-		entity.oldframe = 0;
-		entity.backlerp = 0.0;
-		entity.angles[1] = yaw++;
-		if ( ++yaw > 360 )
-			yaw -= 360;
-
-		refdef.areabits = 0;
-		refdef.num_entities = 1;
-		refdef.entities = &entity;
-		refdef.lightstyles = 0;
-		refdef.rdflags = RDF_NOWORLDMODEL;
-
-		Menu_Draw( &s_player_config_menu );
-
-		M_DrawTextBox( ( refdef.x ) * ( 320.0F / vid.width ) - 8, ( vid.height / 2 ) * ( 240.0F / vid.height) - 77, refdef.width / 8, refdef.height / 8 );
-		refdef.height += 4;
-
-		re.RenderFrame( &refdef );
-
-		Com_sprintf( scratch, sizeof( scratch ), "/players/%s/%s_i.pcx", 
-			s_pmi[s_player_model_box.curvalue].directory,
-			s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
-		re.DrawPic( s_player_config_menu.x - 40, refdef.y, scratch );
-	}
-}
-
-const char *PlayerConfig_MenuKey (int key)
-{
-	int i;
-
-	if ( key == K_ESCAPE )
-	{
-		char scratch[1024];
-
-		Cvar_Set( "name", s_player_name_field.buffer );
-
-		Com_sprintf( scratch, sizeof( scratch ), "%s/%s", 
-			s_pmi[s_player_model_box.curvalue].directory, 
-			s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
-
-		Cvar_Set( "skin", scratch );
-
-		for ( i = 0; i < s_numplayermodels; i++ )
-		{
-			int j;
-
-			for ( j = 0; j < s_pmi[i].nskins; j++ )
-			{
-				if ( s_pmi[i].skindisplaynames[j] )
-					free( s_pmi[i].skindisplaynames[j] );
-				s_pmi[i].skindisplaynames[j] = 0;
-			}
-			free( s_pmi[i].skindisplaynames );
-			s_pmi[i].skindisplaynames = 0;
-			s_pmi[i].nskins = 0;
-		}
-	}
-	return Default_MenuKey( &s_player_config_menu, key );
-}
-
-
-void M_Menu_PlayerConfig_f (void)
-{
-	if (!PlayerConfig_MenuInit())
-	{
-		Menu_SetStatusBar( &s_multiplayer_menu, "No valid player models found" );
-		return;
-	}
-	Menu_SetStatusBar( &s_multiplayer_menu, NULL );
-	M_PushMenu( PlayerConfig_MenuDraw, PlayerConfig_MenuKey );
-}
-
-
-/*
-=======================================================================
-
-GALLERY MENU
-
-=======================================================================
-*/
-/* commented out in release
-void M_Menu_Gallery_f( void )
-{
-	extern void Gallery_MenuDraw( void );
-	extern const char *Gallery_MenuKey( int key );
-
-	M_PushMenu( Gallery_MenuDraw, Gallery_MenuKey );
-}
-*/
-
-/*
-=======================================================================
-
-QUIT MENU
-
-=======================================================================
-*/
-
-const char *M_Quit_Key (int key)
-{
-	switch (key)
-	{
-	case K_ESCAPE:
-	case 'n':
-	case 'N':
-		M_PopMenu ();
-		break;
-
-	case 'Y':
-	case 'y':
-		cls.key_dest = key_console;
-		CL_Quit_f ();
-		break;
-
-	default:
-		break;
-	}
-
-	return NULL;
-
-}
-
-
-void M_Quit_Draw (void)
-{
-	int		w, h;
-
-	re.DrawGetPicSize (&w, &h, "quit");
-	re.DrawPic ( (vid.width-w)/2, (vid.height-h)/2, "quit");
-}
-
-
-void M_Menu_Quit_f (void)
-{
-	M_PushMenu (M_Quit_Draw, M_Quit_Key);
-}
-
-
-
-//=============================================================================
-/* Menu Subsystem */
-
-
-/*
-=================
-M_Init
-=================
-*/
-void M_Init (void)
-{
-	Cmd_AddCommand ("menu_main", M_Menu_Main_f);
-	Cmd_AddCommand ("menu_game", M_Menu_Game_f);
-		Cmd_AddCommand ("menu_loadgame", M_Menu_LoadGame_f);
-		Cmd_AddCommand ("menu_savegame", M_Menu_SaveGame_f);
-		Cmd_AddCommand ("menu_joinserver", M_Menu_JoinServer_f);
-			Cmd_AddCommand ("menu_addressbook", M_Menu_AddressBook_f);
-		Cmd_AddCommand ("menu_startserver", M_Menu_StartServer_f);
-			Cmd_AddCommand ("menu_dmoptions", M_Menu_DMOptions_f);
-		Cmd_AddCommand ("menu_playerconfig", M_Menu_PlayerConfig_f);
-			Cmd_AddCommand ("menu_downloadoptions", M_Menu_DownloadOptions_f);
-		Cmd_AddCommand ("menu_credits", M_Menu_Credits_f );
-	Cmd_AddCommand ("menu_multiplayer", M_Menu_Multiplayer_f );
-	Cmd_AddCommand ("menu_video", M_Menu_Video_f);
-	Cmd_AddCommand ("menu_options", M_Menu_Options_f);
-		Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
-	Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
-}
-
-
-/*
-=================
-M_Draw
-=================
-*/
-void M_Draw (void)
-{
-	if (cls.key_dest != key_menu)
-		return;
-
-	// repaint everything next frame
-	SCR_DirtyScreen ();
-
-	// dim everything behind it down
-	if (cl.cinematictime > 0)
-		re.DrawFill (0,0,vid.width, vid.height, 0);
-	else
-		re.DrawFadeScreen ();
-
-	m_drawfunc ();
-
-	// delay playing the enter sound until after the
-	// menu has been drawn, to avoid delay while
-	// caching images
-	if (m_entersound)
-	{
-		S_StartLocalSound( menu_in_sound );
-		m_entersound = false;
-	}
-}
-
-
-/*
-=================
-M_Keydown
-=================
-*/
-void M_Keydown (int key)
-{
-	const char *s;
-
-	if (m_keyfunc)
-		if ( ( s = m_keyfunc( key ) ) != 0 )
-			S_StartLocalSound( ( char * ) s );
-}
-
-
--- a/client/qmenu.c
+++ /dev/null
@@ -1,651 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <ctype.h>
-#include "../q_shared.h"
-
-void	 Action_DoEnter( menuaction_s *a );
-void	 Action_Draw( menuaction_s *a );
-void  Menu_DrawStatusBar( const char *string );
-void	 Menulist_DoEnter( menulist_s *l );
-void	 MenuList_Draw( menulist_s *l );
-void	 Separator_Draw( menuseparator_s *s );
-void	 Slider_DoSlide( menuslider_s *s, int dir );
-void	 Slider_Draw( menuslider_s *s );
-void	 SpinControl_DoEnter( menulist_s *s );
-void	 SpinControl_Draw( menulist_s *s );
-void	 SpinControl_DoSlide( menulist_s *s, int dir );
-
-#define RCOLUMN_OFFSET  16
-#define LCOLUMN_OFFSET -16
-
-extern refexport_t re;
-
-#define Draw_Char re.DrawChar
-#define Draw_Fill re.DrawFill
-
-void Action_DoEnter( menuaction_s *a )
-{
-	if ( a->generic.callback )
-		a->generic.callback( a );
-}
-
-void Action_Draw( menuaction_s *a )
-{
-	if ( a->generic.flags & QMF_LEFT_JUSTIFY )
-	{
-		if ( a->generic.flags & QMF_GRAYED )
-			Menu_DrawStringDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
-		else
-			Menu_DrawString( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
-	}
-	else
-	{
-		if ( a->generic.flags & QMF_GRAYED )
-			Menu_DrawStringR2LDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
-		else
-			Menu_DrawStringR2L( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
-	}
-	if ( a->generic.ownerdraw )
-		a->generic.ownerdraw( a );
-}
-
-qboolean Field_DoEnter( menufield_s *f )
-{
-	if ( f->generic.callback )
-	{
-		f->generic.callback( f );
-		return true;
-	}
-	return false;
-}
-
-void Field_Draw( menufield_s *f )
-{
-	int i;
-	char tempbuffer[128]="";
-
-	if ( f->generic.name )
-		Menu_DrawStringR2LDark( f->generic.x + f->generic.parent->x + LCOLUMN_OFFSET, f->generic.y + f->generic.parent->y, f->generic.name );
-
-	strncpy( tempbuffer, f->buffer + f->visible_offset, f->visible_length );
-
-	Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y - 4, 18 );
-	Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y + 4, 24 );
-
-	Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y - 4, 20 );
-	Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y + 4, 26 );
-
-	for ( i = 0; i < f->visible_length; i++ )
-	{
-		Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y - 4, 19 );
-		Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y + 4, 25 );
-	}
-
-	Menu_DrawString( f->generic.x + f->generic.parent->x + 24, f->generic.y + f->generic.parent->y, tempbuffer );
-
-	if ( Menu_ItemAtCursor( f->generic.parent ) == f )
-	{
-		int offset;
-
-		if ( f->visible_offset )
-			offset = f->visible_length;
-		else
-			offset = f->cursor;
-
-		if ( ( ( int ) ( Sys_Milliseconds() / 250 ) ) & 1 )
-		{
-			Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8,
-					   f->generic.y + f->generic.parent->y,
-					   11 );
-		}
-		else
-		{
-			Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8,
-					   f->generic.y + f->generic.parent->y,
-					   ' ' );
-		}
-	}
-}
-
-qboolean Field_Key( menufield_s *f, int key )
-{
-	extern int keydown[];
-
-	switch ( key )
-	{
-	case K_KP_SLASH:
-		key = '/';
-		break;
-	case K_KP_MINUS:
-		key = '-';
-		break;
-	case K_KP_PLUS:
-		key = '+';
-		break;
-	case K_KP_HOME:
-		key = '7';
-		break;
-	case K_KP_UPARROW:
-		key = '8';
-		break;
-	case K_KP_PGUP:
-		key = '9';
-		break;
-	case K_KP_LEFTARROW:
-		key = '4';
-		break;
-	case K_KP_5:
-		key = '5';
-		break;
-	case K_KP_RIGHTARROW:
-		key = '6';
-		break;
-	case K_KP_END:
-		key = '1';
-		break;
-	case K_KP_DOWNARROW:
-		key = '2';
-		break;
-	case K_KP_PGDN:
-		key = '3';
-		break;
-	case K_KP_INS:
-		key = '0';
-		break;
-	case K_KP_DEL:
-		key = '.';
-		break;
-	}
-
-	if ( key > 127 )
-	{
-		switch ( key )
-		{
-		case K_DEL:
-		default:
-			return false;
-		}
-	}
-
-	/*
-	** support pasting from the clipboard
-	*/
-	if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
-		 ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
-	{
-		char *cbd;
-		
-		if ( ( cbd = Sys_GetClipboardData() ) != 0 )
-		{
-			strtok( cbd, "\n\r\b" );
-
-			strncpy( f->buffer, cbd, f->length - 1 );
-			f->cursor = strlen( f->buffer );
-			f->visible_offset = f->cursor - f->visible_length;
-			if ( f->visible_offset < 0 )
-				f->visible_offset = 0;
-
-			free( cbd );
-		}
-		return true;
-	}
-
-	switch ( key )
-	{
-	case K_KP_LEFTARROW:
-	case K_LEFTARROW:
-	case K_BACKSPACE:
-		if ( f->cursor > 0 )
-		{
-			memmove( &f->buffer[f->cursor-1], &f->buffer[f->cursor], strlen( &f->buffer[f->cursor] ) + 1 );
-			f->cursor--;
-
-			if ( f->visible_offset )
-			{
-				f->visible_offset--;
-			}
-		}
-		break;
-
-	case K_KP_DEL:
-	case K_DEL:
-		memmove( &f->buffer[f->cursor], &f->buffer[f->cursor+1], strlen( &f->buffer[f->cursor+1] ) + 1 );
-		break;
-
-	case K_KP_ENTER:
-	case K_ENTER:
-	case K_ESCAPE:
-	case K_TAB:
-		return false;
-
-	case K_SPACE:
-	default:
-		if ( !isdigit( key ) && ( f->generic.flags & QMF_NUMBERSONLY ) )
-			return false;
-
-		if ( f->cursor < f->length )
-		{
-			f->buffer[f->cursor++] = key;
-			f->buffer[f->cursor] = 0;
-
-			if ( f->cursor > f->visible_length )
-			{
-				f->visible_offset++;
-			}
-		}
-	}
-
-	return true;
-}
-
-void Menu_AddItem( menuframework_s *menu, void *item )
-{
-	if ( menu->nitems == 0 )
-		menu->nslots = 0;
-
-	if ( menu->nitems < MAXMENUITEMS )
-	{
-		menu->items[menu->nitems] = item;
-		( ( menucommon_s * ) menu->items[menu->nitems] )->parent = menu;
-		menu->nitems++;
-	}
-
-	menu->nslots = Menu_TallySlots( menu );
-}
-
-/*
-** Menu_AdjustCursor
-**
-** This function takes the given menu, the direction, and attempts
-** to adjust the menu's cursor so that it's at the next available
-** slot.
-*/
-void Menu_AdjustCursor( menuframework_s *m, int dir )
-{
-	menucommon_s *citem;
-
-	/*
-	** see if it's in a valid spot
-	*/
-	if ( m->cursor >= 0 && m->cursor < m->nitems )
-	{
-		if ( ( citem = Menu_ItemAtCursor( m ) ) != 0 )
-		{
-			if ( citem->type != MTYPE_SEPARATOR )
-				return;
-		}
-	}
-
-	/*
-	** it's not in a valid spot, so crawl in the direction indicated until we
-	** find a valid spot
-	*/
-	if ( dir == 1 )
-	{
-		while ( 1 )
-		{
-			citem = Menu_ItemAtCursor( m );
-			if ( citem )
-				if ( citem->type != MTYPE_SEPARATOR )
-					break;
-			m->cursor += dir;
-			if ( m->cursor >= m->nitems )
-				m->cursor = 0;
-		}
-	}
-	else
-	{
-		while ( 1 )
-		{
-			citem = Menu_ItemAtCursor( m );
-			if ( citem )
-				if ( citem->type != MTYPE_SEPARATOR )
-					break;
-			m->cursor += dir;
-			if ( m->cursor < 0 )
-				m->cursor = m->nitems - 1;
-		}
-	}
-}
-
-void Menu_Center( menuframework_s *menu )
-{
-	int height;
-
-	height = ( ( menucommon_s * ) menu->items[menu->nitems-1])->y;
-	height += 10;
-
-	menu->y = ( vid.height - height ) / 2;
-}
-
-void Menu_Draw( menuframework_s *menu )
-{
-	int i;
-	menucommon_s *item;
-
-	/*
-	** draw contents
-	*/
-	for ( i = 0; i < menu->nitems; i++ )
-	{
-		switch ( ( ( menucommon_s * ) menu->items[i] )->type )
-		{
-		case MTYPE_FIELD:
-			Field_Draw( ( menufield_s * ) menu->items[i] );
-			break;
-		case MTYPE_SLIDER:
-			Slider_Draw( ( menuslider_s * ) menu->items[i] );
-			break;
-		case MTYPE_LIST:
-			MenuList_Draw( ( menulist_s * ) menu->items[i] );
-			break;
-		case MTYPE_SPINCONTROL:
-			SpinControl_Draw( ( menulist_s * ) menu->items[i] );
-			break;
-		case MTYPE_ACTION:
-			Action_Draw( ( menuaction_s * ) menu->items[i] );
-			break;
-		case MTYPE_SEPARATOR:
-			Separator_Draw( ( menuseparator_s * ) menu->items[i] );
-			break;
-		}
-	}
-
-	item = Menu_ItemAtCursor( menu );
-
-	if ( item && item->cursordraw )
-	{
-		item->cursordraw( item );
-	}
-	else if ( menu->cursordraw )
-	{
-		menu->cursordraw( menu );
-	}
-	else if ( item && item->type != MTYPE_FIELD )
-	{
-		if ( item->flags & QMF_LEFT_JUSTIFY )
-		{
-			Draw_Char( menu->x + item->x - 24 + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) );
-		}
-		else
-		{
-			Draw_Char( menu->x + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) );
-		}
-	}
-
-	if ( item )
-	{
-		if ( item->statusbarfunc )
-			item->statusbarfunc( ( void * ) item );
-		else if ( item->statusbar )
-			Menu_DrawStatusBar( item->statusbar );
-		else
-			Menu_DrawStatusBar( menu->statusbar );
-
-	}
-	else
-	{
-		Menu_DrawStatusBar( menu->statusbar );
-	}
-}
-
-void Menu_DrawStatusBar( const char *string )
-{
-	if ( string )
-	{
-		int l = strlen( string );
-		//int maxrow = vid.height / 8;
-		int maxcol = vid.width / 8;
-		int col = maxcol / 2 - l / 2;
-
-		Draw_Fill( 0, vid.height-8, vid.width, 8, 4 );
-		Menu_DrawString( col*8, vid.height - 8, string );
-	}
-	else
-	{
-		Draw_Fill( 0, vid.height-8, vid.width, 8, 0 );
-	}
-}
-
-void Menu_DrawString( int x, int y, const char *string )
-{
-	unsigned i;
-
-	for ( i = 0; i < strlen( string ); i++ )
-	{
-		Draw_Char( ( x + i*8 ), y, string[i] );
-	}
-}
-
-void Menu_DrawStringDark( int x, int y, const char *string )
-{
-	unsigned i;
-
-	for ( i = 0; i < strlen( string ); i++ )
-	{
-		Draw_Char( ( x + i*8 ), y, string[i] + 128 );
-	}
-}
-
-void Menu_DrawStringR2L( int x, int y, const char *string )
-{
-	unsigned i;
-
-	for ( i = 0; i < strlen( string ); i++ )
-	{
-		Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1] );
-	}
-}
-
-void Menu_DrawStringR2LDark( int x, int y, const char *string )
-{
-	unsigned i;
-
-	for ( i = 0; i < strlen( string ); i++ )
-	{
-		Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1]+128 );
-	}
-}
-
-void *Menu_ItemAtCursor( menuframework_s *m )
-{
-	if ( m->cursor < 0 || m->cursor >= m->nitems )
-		return 0;
-
-	return m->items[m->cursor];
-}
-
-qboolean Menu_SelectItem( menuframework_s *s )
-{
-	menucommon_s *item = ( menucommon_s * ) Menu_ItemAtCursor( s );
-
-	if ( item )
-	{
-		switch ( item->type )
-		{
-		case MTYPE_FIELD:
-			return Field_DoEnter( ( menufield_s * ) item ) ;
-		case MTYPE_ACTION:
-			Action_DoEnter( ( menuaction_s * ) item );
-			return true;
-		case MTYPE_LIST:
-//			Menulist_DoEnter( ( menulist_s * ) item );
-			return false;
-		case MTYPE_SPINCONTROL:
-//			SpinControl_DoEnter( ( menulist_s * ) item );
-			return false;
-		}
-	}
-	return false;
-}
-
-void Menu_SetStatusBar( menuframework_s *m, const char *string )
-{
-	m->statusbar = string;
-}
-
-void Menu_SlideItem( menuframework_s *s, int dir )
-{
-	menucommon_s *item = ( menucommon_s * ) Menu_ItemAtCursor( s );
-
-	if ( item )
-	{
-		switch ( item->type )
-		{
-		case MTYPE_SLIDER:
-			Slider_DoSlide( ( menuslider_s * ) item, dir );
-			break;
-		case MTYPE_SPINCONTROL:
-			SpinControl_DoSlide( ( menulist_s * ) item, dir );
-			break;
-		}
-	}
-}
-
-int Menu_TallySlots( menuframework_s *menu )
-{
-	int i;
-	int total = 0;
-
-	for ( i = 0; i < menu->nitems; i++ )
-	{
-		if ( ( ( menucommon_s * ) menu->items[i] )->type == MTYPE_LIST )
-		{
-			int nitems = 0;
-			const char **n = ( ( menulist_s * ) menu->items[i] )->itemnames;
-
-			while (*n)
-				nitems++, n++;
-
-			total += nitems;
-		}
-		else
-		{
-			total++;
-		}
-	}
-
-	return total;
-}
-
-void Menulist_DoEnter( menulist_s *l )
-{
-	int start;
-
-	start = l->generic.y / 10 + 1;
-
-	l->curvalue = l->generic.parent->cursor - start;
-
-	if ( l->generic.callback )
-		l->generic.callback( l );
-}
-
-void MenuList_Draw( menulist_s *l )
-{
-	const char **n;
-	int y = 0;
-
-	Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y, l->generic.name );
-
-	n = l->itemnames;
-
-  	Draw_Fill( l->generic.x - 112 + l->generic.parent->x, l->generic.parent->y + l->generic.y + l->curvalue*10 + 10, 128, 10, 16 );
-	while ( *n )
-	{
-		Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y + y + 10, *n );
-
-		n++;
-		y += 10;
-	}
-}
-
-void Separator_Draw( menuseparator_s *s )
-{
-	if ( s->generic.name )
-		Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->generic.name );
-}
-
-void Slider_DoSlide( menuslider_s *s, int dir )
-{
-	s->curvalue += dir;
-
-	if ( s->curvalue > s->maxvalue )
-		s->curvalue = s->maxvalue;
-	else if ( s->curvalue < s->minvalue )
-		s->curvalue = s->minvalue;
-
-	if ( s->generic.callback )
-		s->generic.callback( s );
-}
-
-#define SLIDER_RANGE 10
-
-void Slider_Draw( menuslider_s *s )
-{
-	int	i;
-
-	Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET,
-		                s->generic.y + s->generic.parent->y, 
-						s->generic.name );
-
-	s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
-
-	if ( s->range < 0)
-		s->range = 0;
-	if ( s->range > 1)
-		s->range = 1;
-	Draw_Char( s->generic.x + s->generic.parent->x + RCOLUMN_OFFSET, s->generic.y + s->generic.parent->y, 128);
-	for ( i = 0; i < SLIDER_RANGE; i++ )
-		Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 129);
-	Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 130);
-	Draw_Char( ( int ) ( 8 + RCOLUMN_OFFSET + s->generic.parent->x + s->generic.x + (SLIDER_RANGE-1)*8 * s->range ), s->generic.y + s->generic.parent->y, 131);
-}
-
-void SpinControl_DoEnter( menulist_s *s )
-{
-	s->curvalue++;
-	if ( s->itemnames[s->curvalue] == 0 )
-		s->curvalue = 0;
-
-	if ( s->generic.callback )
-		s->generic.callback( s );
-}
-
-void SpinControl_DoSlide( menulist_s *s, int dir )
-{
-	s->curvalue += dir;
-
-	if ( s->curvalue < 0 )
-		s->curvalue = 0;
-	else if ( s->itemnames[s->curvalue] == 0 )
-		s->curvalue--;
-
-	if ( s->generic.callback )
-		s->generic.callback( s );
-}
-
-void SpinControl_Draw( menulist_s *s )
-{
-	char buffer[100];
-
-	if ( s->generic.name )
-	{
-		Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET, 
-							s->generic.y + s->generic.parent->y, 
-							s->generic.name );
-	}
-	if ( !strchr( s->itemnames[s->curvalue], '\n' ) )
-	{
-		Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->itemnames[s->curvalue] );
-	}
-	else
-	{
-		strcpy( buffer, s->itemnames[s->curvalue] );
-		*strchr( buffer, '\n' ) = 0;
-		Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, buffer );
-		strcpy( buffer, strchr( s->itemnames[s->curvalue], '\n' ) + 1 );
-		Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y + 10, buffer );
-	}
-}
-
--- a/client/qmenu.h
+++ /dev/null
@@ -1,108 +1,0 @@
-#ifndef __QMENU_H__
-#define __QMENU_H__
-
-#define MAXMENUITEMS	64
-
-#define MTYPE_SLIDER		0
-#define MTYPE_LIST			1
-#define MTYPE_ACTION		2
-#define MTYPE_SPINCONTROL	3
-#define MTYPE_SEPARATOR  	4
-#define MTYPE_FIELD			5
-
-#define QMF_LEFT_JUSTIFY	0x00000001
-#define QMF_GRAYED			0x00000002
-#define QMF_NUMBERSONLY		0x00000004
-
-typedef struct _tag_menuframework
-{
-	int x, y;
-	int	cursor;
-
-	int	nitems;
-	int nslots;
-	void *items[64];
-
-	const char *statusbar;
-
-	void (*cursordraw)( struct _tag_menuframework *m );
-	
-} menuframework_s;
-
-typedef struct
-{
-	int type;
-	const char *name;
-	int x, y;
-	menuframework_s *parent;
-	int cursor_offset;
-	int	localdata[4];
-	unsigned flags;
-
-	const char *statusbar;
-
-	void (*callback)( void *self );
-	void (*statusbarfunc)( void *self );
-	void (*ownerdraw)( void *self );
-	void (*cursordraw)( void *self );
-} menucommon_s;
-
-typedef struct
-{
-	menucommon_s generic;
-
-	char		buffer[80];
-	int			cursor;
-	int			length;
-	int			visible_length;
-	int			visible_offset;
-} menufield_s;
-
-typedef struct 
-{
-	menucommon_s generic;
-
-	float minvalue;
-	float maxvalue;
-	float curvalue;
-
-	float range;
-} menuslider_s;
-
-typedef struct
-{
-	menucommon_s generic;
-
-	int curvalue;
-
-	const char **itemnames;
-} menulist_s;
-
-typedef struct
-{
-	menucommon_s generic;
-} menuaction_s;
-
-typedef struct
-{
-	menucommon_s generic;
-} menuseparator_s;
-
-qboolean Field_Key( menufield_s *field, int key );
-
-void	Menu_AddItem( menuframework_s *menu, void *item );
-void	Menu_AdjustCursor( menuframework_s *menu, int dir );
-void	Menu_Center( menuframework_s *menu );
-void	Menu_Draw( menuframework_s *menu );
-void	*Menu_ItemAtCursor( menuframework_s *m );
-qboolean Menu_SelectItem( menuframework_s *s );
-void	Menu_SetStatusBar( menuframework_s *s, const char *string );
-void	Menu_SlideItem( menuframework_s *s, int dir );
-int		Menu_TallySlots( menuframework_s *menu );
-
-void	 Menu_DrawString( int, int, const char * );
-void	 Menu_DrawStringDark( int, int, const char * );
-void	 Menu_DrawStringR2L( int, int, const char * );
-void	 Menu_DrawStringR2LDark( int, int, const char * );
-
-#endif
--- a/client/ref.h
+++ /dev/null
@@ -1,205 +1,0 @@
-#define	MAX_DLIGHTS		32
-#define	MAX_ENTITIES	128
-#define	MAX_PARTICLES	4096
-//#define	MAX_LIGHTSTYLES	256	/* macro redifinition */
-
-#define POWERSUIT_SCALE		4.0F
-
-#define SHELL_RED_COLOR		0xF2
-#define SHELL_GREEN_COLOR	0xD0
-#define SHELL_BLUE_COLOR	0xF3
-
-#define SHELL_RG_COLOR		0xDC
-//#define SHELL_RB_COLOR		0x86
-#define SHELL_RB_COLOR		0x68
-#define SHELL_BG_COLOR		0x78
-
-//ROGUE
-#define SHELL_DOUBLE_COLOR	0xDF // 223
-#define	SHELL_HALF_DAM_COLOR	0x90
-#define SHELL_CYAN_COLOR	0x72
-//ROGUE
-
-#define SHELL_WHITE_COLOR	0xD7
-
-typedef struct entity_s
-{
-	struct model_s		*model;			// opaque type outside refresh
-	float				angles[3];
-
-	/*
-	** most recent data
-	*/
-	float				origin[3];		// also used as RF_BEAM's "from"
-	int					frame;			// also used as RF_BEAM's diameter
-
-	/*
-	** previous data for lerping
-	*/
-	float				oldorigin[3];	// also used as RF_BEAM's "to"
-	int					oldframe;
-
-	/*
-	** misc
-	*/
-	float	backlerp;				// 0.0 = current, 1.0 = old
-	int		skinnum;				// also used as RF_BEAM's palette index
-
-	int		lightstyle;				// for flashing entities
-	float	alpha;					// ignore if RF_TRANSLUCENT isn't set
-
-	struct image_s	*skin;			// NULL for inline skin
-	int		flags;
-
-} entity_t;
-
-#define ENTITY_FLAGS  68
-
-typedef struct
-{
-	vec3_t	origin;
-	vec3_t	color;
-	float	intensity;
-} dlight_t;
-
-typedef struct
-{
-	vec3_t	origin;
-	int		color;
-	float	alpha;
-} particle_t;
-
-typedef struct
-{
-	float		rgb[3];			// 0.0 - 2.0
-	float		white;			// highest of rgb
-} lightstyle_t;
-
-typedef struct
-{
-	int			x, y, width, height;// in virtual screen coordinates
-	float		fov_x, fov_y;
-	float		vieworg[3];
-	float		viewangles[3];
-	float		blend[4];			// rgba 0-1 full screen blend
-	float		time;				// time is uesed to auto animate
-	int			rdflags;			// RDF_UNDERWATER, etc
-
-	byte		*areabits;			// if not NULL, only areas with set bits will be drawn
-
-	lightstyle_t	*lightstyles;	// [MAX_LIGHTSTYLES]
-
-	int			num_entities;
-	entity_t	*entities;
-
-	int			num_dlights;
-	dlight_t	*dlights;
-
-	int			num_particles;
-	particle_t	*particles;
-} refdef_t;
-
-
-
-#define	API_VERSION		3
-
-//
-// these are the functions exported by the refresh module
-//
-typedef struct
-{
-	// if api_version is different, the dll cannot be used
-	int		api_version;
-
-	// called when the library is loaded
-	qboolean	(*Init) ( void *hinstance, void *wndproc );
-
-	// called before the library is unloaded
-	void	(*Shutdown) (void);
-
-	// All data that will be used in a level should be
-	// registered before rendering any frames to prevent disk hits,
-	// but they can still be registered at a later time
-	// if necessary.
-	//
-	// EndRegistration will free any remaining data that wasn't registered.
-	// Any model_s or skin_s pointers from before the BeginRegistration
-	// are no longer valid after EndRegistration.
-	//
-	// Skins and images need to be differentiated, because skins
-	// are flood filled to eliminate mip map edge errors, and pics have
-	// an implicit "pics/" prepended to the name. (a pic name that starts with a
-	// slash will not use the "pics/" prefix or the ".pcx" postfix)
-	void	(*BeginRegistration) (char *map);
-	struct model_s *(*RegisterModel) (char *name);
-	struct image_s *(*RegisterSkin) (char *name);
-	struct image_s *(*RegisterPic) (char *name);
-	void	(*SetSky) (char *name, float rotate, vec3_t axis);
-	void	(*EndRegistration) (void);
-
-	void	(*RenderFrame) (refdef_t *fd);
-
-	void	(*DrawGetPicSize) (int *w, int *h, char *name);	// will return 0 0 if not found
-	void	(*DrawPic) (int x, int y, char *name);
-	void	(*DrawStretchPic) (int x, int y, int w, int h, char *name);
-	void	(*DrawChar) (int x, int y, int c);
-	void	(*DrawTileClear) (int x, int y, int w, int h, char *name);
-	void	(*DrawFill) (int x, int y, int w, int h, int c);
-	void	(*DrawFadeScreen) (void);
-
-	// Draw images for cinematic rendering (which can have a different palette). Note that calls
-	void	(*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, byte *data);
-
-	/*
-	** video mode and refresh state management entry points
-	*/
-	void	(*CinematicSetPalette)( const unsigned char *palette);	// NULL = game palette
-	void	(*BeginFrame)( float camera_separation );
-	void	(*EndFrame) (void);
-
-	void	(*AppActivate)( qboolean activate );
-
-} refexport_t;
-
-//
-// these are the functions imported by the refresh module
-//
-typedef struct
-{
-	void	(*Sys_Error) (int err_level, char *str, ...);
-
-	void	(*Cmd_AddCommand) (char *name, void(*cmd)(void));
-	void	(*Cmd_RemoveCommand) (char *name);
-	int		(*Cmd_Argc) (void);
-	char	*(*Cmd_Argv) (int i);
-	void	(*Cmd_ExecuteText) (int exec_when, char *text);
-
-	void	(*Con_Printf) (int print_level, char *str, ...);
-
-	// files will be memory mapped read only
-	// the returned buffer may be part of a larger pak file,
-	// or a discrete file from anywhere in the quake search path
-	// a -1 return means the file does not exist
-	// NULL can be passed for buf to just determine existance
-	int		(*FS_LoadFile) (char *name, void **buf);
-	void	(*FS_FreeFile) (void *buf);
-
-	// gamedir will be the current directory that generated
-	// files should be stored to, ie: "f:\quake\id1"
-	char	*(*FS_Gamedir) (void);
-
-	cvar_t	*(*Cvar_Get) (char *name, char *value, int flags);
-	cvar_t	*(*Cvar_Set)( char *name, char *value );
-	void	 (*Cvar_SetValue)( char *name, float value );
-
-	qboolean	(*Vid_GetModeInfo)( int *width, int *height, int mode );
-	void		(*Vid_MenuInit)( void );
-	void		(*Vid_NewWindow)( int width, int height );
-} refimport_t;
-
-
-// this is the only function actually exported at the linker level
-typedef	refexport_t	(*GetRefAPI_t) (refimport_t);
-
-extern cvar_t *vid_fullscreen;
-extern cvar_t *vid_gamma;
--- a/client/screen.h
+++ /dev/null
@@ -1,41 +1,0 @@
-void	SCR_Init (void);
-
-void	SCR_UpdateScreen (void);
-
-void	SCR_SizeUp (void);
-void	SCR_SizeDown (void);
-void	SCR_CenterPrint (char *str);
-void	SCR_BeginLoadingPlaque (void);
-void	SCR_EndLoadingPlaque (void);
-
-void	SCR_DebugGraph (float value, int color);
-
-void	SCR_TouchPics (void);
-
-void	SCR_RunConsole (void);
-
-extern	float		scr_con_current;
-extern	float		scr_conlines;		// lines of console to display
-
-extern	int			sb_lines;
-
-extern	cvar_t		*scr_viewsize;
-extern	cvar_t		*crosshair;
-
-extern	vrect_t		scr_vrect;		// position of render window
-
-extern	char		crosshair_pic[MAX_QPATH];
-extern	int			crosshair_width, crosshair_height;
-
-void SCR_AddDirtyPoint (int x, int y);
-void SCR_DirtyScreen (void);
-
-//
-// scr_cin.c
-//
-void SCR_PlayCinematic (char *name);
-qboolean SCR_DrawCinematic (void);
-void SCR_RunCinematic (void);
-void SCR_StopCinematic (void);
-void SCR_FinishCinematic (void);
-
--- a/client/snd_dma.c
+++ /dev/null
@@ -1,1194 +1,0 @@
-// snd_dma.c -- main control for any streaming sound output device
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-void S_Play(void);
-void S_SoundList(void);
-void S_Update_(void);
-void S_StopAllSounds(void);
-
-
-// =======================================================================
-// Internal sound data & structures
-// =======================================================================
-
-// only begin attenuating sound volumes when outside the FULLVOLUME range
-#define		SOUND_FULLVOLUME	80
-
-#define		SOUND_LOOPATTENUATE	0.003
-
-int			s_registration_sequence;
-
-channel_t   channels[MAX_CHANNELS];
-
-qboolean	snd_initialized = false;
-int			sound_started=0;
-
-dma_t		dma;
-
-vec3_t		listener_origin;
-vec3_t		listener_forward;
-vec3_t		listener_right;
-vec3_t		listener_up;
-
-qboolean	s_registering;
-
-int			soundtime;		// sample PAIRS
-int   		paintedtime; 	// sample PAIRS
-
-// during registration it is possible to have more sounds
-// than could actually be referenced during gameplay,
-// because we don't want to free anything until we are
-// sure we won't need it.
-#define		MAX_SFX		(MAX_SOUNDS*2)
-sfx_t		known_sfx[MAX_SFX];
-int			num_sfx;
-
-#define		MAX_PLAYSOUNDS	128
-playsound_t	s_playsounds[MAX_PLAYSOUNDS];
-playsound_t	s_freeplays;
-playsound_t	s_pendingplays;
-
-int			s_beginofs;
-
-cvar_t		*s_volume;
-cvar_t		*s_testsound;
-cvar_t		*s_loadas8bit;
-cvar_t		*s_khz;
-cvar_t		*s_show;
-cvar_t		*s_mixahead;
-cvar_t		*s_primary;
-
-
-int		s_rawend;
-portable_samplepair_t	s_rawsamples[MAX_RAW_SAMPLES];
-
-
-// ====================================================================
-// User-setable variables
-// ====================================================================
-
-
-void S_SoundInfo_f(void)
-{
-	if (!sound_started)
-	{
-		Com_Printf ("sound system not started\n");
-		return;
-	}
-	
-    Com_Printf("%5d stereo\n", dma.channels - 1);
-    Com_Printf("%5d samples\n", dma.samples);
-    Com_Printf("%5d samplepos\n", dma.samplepos);
-    Com_Printf("%5d samplebits\n", dma.samplebits);
-    Com_Printf("%5d submission_chunk\n", dma.submission_chunk);
-    Com_Printf("%5d speed\n", dma.speed);
-    Com_Printf("0x%x dma buffer\n", dma.buffer);
-}
-
-
-
-/*
-================
-S_Init
-================
-*/
-void S_Init (void)
-{
-	cvar_t	*cv;
-
-	Com_Printf("\n------- sound initialization -------\n");
-
-	cv = Cvar_Get ("s_initsound", "1", 0);
-	if (!cv->value)
-		Com_Printf ("not initializing.\n");
-	else
-	{
-		s_volume = Cvar_Get ("s_volume", "0.7", CVAR_ARCHIVE);
-		s_khz = Cvar_Get ("s_khz", "11", CVAR_ARCHIVE);
-		s_loadas8bit = Cvar_Get ("s_loadas8bit", "1", CVAR_ARCHIVE);
-		s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
-		s_show = Cvar_Get ("s_show", "0", 0);
-		s_testsound = Cvar_Get ("s_testsound", "0", 0);
-		s_primary = Cvar_Get ("s_primary", "0", CVAR_ARCHIVE);	// win32 specific
-
-		Cmd_AddCommand("play", S_Play);
-		Cmd_AddCommand("stopsound", S_StopAllSounds);
-		Cmd_AddCommand("soundlist", S_SoundList);
-		Cmd_AddCommand("soundinfo", S_SoundInfo_f);
-
-		if (!SNDDMA_Init())
-			return;
-
-		S_InitScaletable ();
-
-		sound_started = 1;
-		num_sfx = 0;
-
-		soundtime = 0;
-		paintedtime = 0;
-
-		Com_Printf ("sound sampling rate: %i\n", dma.speed);
-
-		S_StopAllSounds ();
-	}
-
-	Com_Printf("------------------------------------\n");
-}
-
-
-// =======================================================================
-// Shutdown sound engine
-// =======================================================================
-
-void S_Shutdown(void)
-{
-	int		i;
-	sfx_t	*sfx;
-
-	if (!sound_started)
-		return;
-
-	SNDDMA_Shutdown();
-
-	sound_started = 0;
-
-	Cmd_RemoveCommand("play");
-	Cmd_RemoveCommand("stopsound");
-	Cmd_RemoveCommand("soundlist");
-	Cmd_RemoveCommand("soundinfo");
-
-	// free all sounds
-	for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
-	{
-		if (!sfx->name[0])
-			continue;
-		if (sfx->cache)
-			Z_Free (sfx->cache);
-		memset (sfx, 0, sizeof(*sfx));
-	}
-
-	num_sfx = 0;
-}
-
-
-// =======================================================================
-// Load a sound
-// =======================================================================
-
-/*
-==================
-S_FindName
-
-==================
-*/
-sfx_t *S_FindName (char *name, qboolean create)
-{
-	int		i;
-	sfx_t	*sfx;
-
-	if (!name)
-		Com_Error (ERR_FATAL, "S_FindName: NULL\n");
-	if (!name[0])
-		Com_Error (ERR_FATAL, "S_FindName: empty name\n");
-
-	if (strlen(name) >= MAX_QPATH)
-		Com_Error (ERR_FATAL, "Sound name too long: %s", name);
-
-	// see if already loaded
-	for (i=0 ; i < num_sfx ; i++)
-		if (!strcmp(known_sfx[i].name, name))
-		{
-			return &known_sfx[i];
-		}
-
-	if (!create)
-		return NULL;
-
-	// find a free sfx
-	for (i=0 ; i < num_sfx ; i++)
-		if (!known_sfx[i].name[0])
-//			registration_sequence < s_registration_sequence)
-			break;
-
-	if (i == num_sfx)
-	{
-		if (num_sfx == MAX_SFX)
-			Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
-		num_sfx++;
-	}
-	
-	sfx = &known_sfx[i];
-	memset (sfx, 0, sizeof(*sfx));
-	strcpy (sfx->name, name);
-	sfx->registration_sequence = s_registration_sequence;
-	
-	return sfx;
-}
-
-
-/*
-==================
-S_AliasName
-
-==================
-*/
-sfx_t *S_AliasName (char *aliasname, char *truename)
-{
-	sfx_t	*sfx;
-	char	*s;
-	int		i;
-
-	s = Z_Malloc (MAX_QPATH);
-	strcpy (s, truename);
-
-	// find a free sfx
-	for (i=0 ; i < num_sfx ; i++)
-		if (!known_sfx[i].name[0])
-			break;
-
-	if (i == num_sfx)
-	{
-		if (num_sfx == MAX_SFX)
-			Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
-		num_sfx++;
-	}
-	
-	sfx = &known_sfx[i];
-	memset (sfx, 0, sizeof(*sfx));
-	strcpy (sfx->name, aliasname);
-	sfx->registration_sequence = s_registration_sequence;
-	sfx->truename = s;
-
-	return sfx;
-}
-
-
-/*
-=====================
-S_BeginRegistration
-
-=====================
-*/
-void S_BeginRegistration (void)
-{
-	s_registration_sequence++;
-	s_registering = true;
-}
-
-/*
-==================
-S_RegisterSound
-
-==================
-*/
-sfx_t *S_RegisterSound (char *name)
-{
-	sfx_t	*sfx;
-
-	if (!sound_started)
-		return NULL;
-
-	sfx = S_FindName (name, true);
-	sfx->registration_sequence = s_registration_sequence;
-
-	if (!s_registering)
-		S_LoadSound (sfx);
-
-	return sfx;
-}
-
-
-/*
-=====================
-S_EndRegistration
-
-=====================
-*/
-void S_EndRegistration (void)
-{
-	int		i;
-	sfx_t	*sfx;
-	int		size;
-
-	// free any sounds not from this registration sequence
-	for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
-	{
-		if (!sfx->name[0])
-			continue;
-		if (sfx->registration_sequence != s_registration_sequence)
-		{	// don't need this sound
-			if (sfx->cache)	// it is possible to have a leftover
-				Z_Free (sfx->cache);	// from a server that didn't finish loading
-			memset (sfx, 0, sizeof(*sfx));
-		}
-		else
-		{	// make sure it is paged in
-			if (sfx->cache)
-			{
-				size = sfx->cache->length*sfx->cache->width;
-				Com_PageInMemory ((byte *)sfx->cache, size);
-			}
-		}
-
-	}
-
-	// load everything in
-	for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
-	{
-		if (!sfx->name[0])
-			continue;
-		S_LoadSound (sfx);
-	}
-
-	s_registering = false;
-}
-
-
-//=============================================================================
-
-/*
-=================
-S_PickChannel
-=================
-*/
-channel_t *S_PickChannel(int entnum, int entchannel)
-{
-    int			ch_idx;
-    int			first_to_die;
-    int			life_left;
-	channel_t	*ch;
-
-	if (entchannel<0)
-		Com_Error (ERR_DROP, "S_PickChannel: entchannel<0");
-
-// Check for replacement sound, or find the best one to replace
-    first_to_die = -1;
-    life_left = 0x7fffffff;
-    for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++)
-    {
-		if (entchannel != 0		// channel 0 never overrides
-		&& channels[ch_idx].entnum == entnum
-		&& channels[ch_idx].entchannel == entchannel)
-		{	// always override sound from same entity
-			first_to_die = ch_idx;
-			break;
-		}
-
-		// don't let monster sounds override player sounds
-		if (channels[ch_idx].entnum == cl.playernum+1 && entnum != cl.playernum+1 && channels[ch_idx].sfx)
-			continue;
-
-		if (channels[ch_idx].end - paintedtime < life_left)
-		{
-			life_left = channels[ch_idx].end - paintedtime;
-			first_to_die = ch_idx;
-		}
-   }
-
-	if (first_to_die == -1)
-		return NULL;
-
-	ch = &channels[first_to_die];
-	memset (ch, 0, sizeof(*ch));
-
-    return ch;
-}       
-
-/*
-=================
-S_SpatializeOrigin
-
-Used for spatializing channels and autosounds
-=================
-*/
-void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
-{
-    vec_t		dot;
-    vec_t		dist;
-    vec_t		lscale, rscale, scale;
-    vec3_t		source_vec;
-
-	if (cls.state != ca_active)
-	{
-		*left_vol = *right_vol = 255;
-		return;
-	}
-
-// calculate stereo seperation and distance attenuation
-	VectorSubtract(origin, listener_origin, source_vec);
-
-	dist = VectorNormalize(source_vec);
-	dist -= SOUND_FULLVOLUME;
-	if (dist < 0)
-		dist = 0;			// close enough to be at full volume
-	dist *= dist_mult;		// different attenuation levels
-	
-	dot = DotProduct(listener_right, source_vec);
-
-	if (dma.channels == 1 || !dist_mult)
-	{ // no attenuation = no spatialization
-		rscale = 1.0;
-		lscale = 1.0;
-	}
-	else
-	{
-		rscale = 0.5 * (1.0 + dot);
-		lscale = 0.5*(1.0 - dot);
-	}
-
-	// add in distance effect
-	scale = (1.0 - dist) * rscale;
-	*right_vol = (int) (master_vol * scale);
-	if (*right_vol < 0)
-		*right_vol = 0;
-
-	scale = (1.0 - dist) * lscale;
-	*left_vol = (int) (master_vol * scale);
-	if (*left_vol < 0)
-		*left_vol = 0;
-}
-
-/*
-=================
-S_Spatialize
-=================
-*/
-void S_Spatialize(channel_t *ch)
-{
-	vec3_t		origin;
-
-	// anything coming from the view entity will always be full volume
-	if (ch->entnum == cl.playernum+1)
-	{
-		ch->leftvol = ch->master_vol;
-		ch->rightvol = ch->master_vol;
-		return;
-	}
-
-	if (ch->fixed_origin)
-	{
-		VectorCopy (ch->origin, origin);
-	}
-	else
-		CL_GetEntitySoundOrigin (ch->entnum, origin);
-
-	S_SpatializeOrigin (origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol);
-}           
-
-
-/*
-=================
-S_AllocPlaysound
-=================
-*/
-playsound_t *S_AllocPlaysound (void)
-{
-	playsound_t	*ps;
-
-	ps = s_freeplays.next;
-	if (ps == &s_freeplays)
-		return NULL;		// no free playsounds
-
-	// unlink from freelist
-	ps->prev->next = ps->next;
-	ps->next->prev = ps->prev;
-	
-	return ps;
-}
-
-
-/*
-=================
-S_FreePlaysound
-=================
-*/
-void S_FreePlaysound (playsound_t *ps)
-{
-	// unlink from channel
-	ps->prev->next = ps->next;
-	ps->next->prev = ps->prev;
-
-	// add to free list
-	ps->next = s_freeplays.next;
-	s_freeplays.next->prev = ps;
-	ps->prev = &s_freeplays;
-	s_freeplays.next = ps;
-}
-
-
-
-/*
-===============
-S_IssuePlaysound
-
-Take the next playsound and begin it on the channel
-This is never called directly by S_Play*, but only
-by the update loop.
-===============
-*/
-void S_IssuePlaysound (playsound_t *ps)
-{
-	channel_t	*ch;
-	sfxcache_t	*sc;
-
-	if (s_show->value)
-		Com_Printf ("Issue %i\n", ps->begin);
-	// pick a channel to play on
-	ch = S_PickChannel(ps->entnum, ps->entchannel);
-	if (!ch)
-	{
-		S_FreePlaysound (ps);
-		return;
-	}
-
-	// spatialize
-	if (ps->attenuation == ATTN_STATIC)
-		ch->dist_mult = ps->attenuation * 0.001;
-	else
-		ch->dist_mult = ps->attenuation * 0.0005;
-	ch->master_vol = ps->volume;
-	ch->entnum = ps->entnum;
-	ch->entchannel = ps->entchannel;
-	ch->sfx = ps->sfx;
-	VectorCopy (ps->origin, ch->origin);
-	ch->fixed_origin = ps->fixed_origin;
-
-	S_Spatialize(ch);
-
-	ch->pos = 0;
-	sc = S_LoadSound (ch->sfx);
-    ch->end = paintedtime + sc->length;
-
-	// free the playsound
-	S_FreePlaysound (ps);
-}
-
-struct sfx_s *S_RegisterSexedSound (entity_state_t *ent, char *base)
-{
-	int				n;
-	char			*p;
-	struct sfx_s	*sfx;
-	FILE			*f;
-	char			model[MAX_QPATH];
-	char			sexedFilename[MAX_QPATH];
-	char			maleFilename[MAX_QPATH];
-
-	// determine what model the client is using
-	model[0] = 0;
-	n = CS_PLAYERSKINS + ent->number - 1;
-	if (cl.configstrings[n][0])
-	{
-		p = strchr(cl.configstrings[n], '\\');
-		if (p)
-		{
-			p += 1;
-			strcpy(model, p);
-			p = strchr(model, '/');
-			if (p)
-				*p = 0;
-		}
-	}
-	// if we can't figure it out, they're male
-	if (!model[0])
-		strcpy(model, "male");
-
-	// see if we already know of the model specific sound
-	Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
-	sfx = S_FindName (sexedFilename, false);
-
-	if (!sfx)
-	{
-		// no, so see if it exists
-		FS_FOpenFile (&sexedFilename[1], &f);
-		if (f)
-		{
-			// yes, close the file and register it
-			FS_FCloseFile (f);
-			sfx = S_RegisterSound (sexedFilename);
-		}
-		else
-		{
-			// no, revert to the male sound in the pak0.pak
-			Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1);
-			sfx = S_AliasName (sexedFilename, maleFilename);
-		}
-	}
-
-	return sfx;
-}
-
-
-// =======================================================================
-// Start a sound effect
-// =======================================================================
-
-/*
-====================
-S_StartSound
-
-Validates the parms and ques the sound up
-if pos is NULL, the sound will be dynamically sourced from the entity
-Entchannel 0 will never override a playing sound
-====================
-*/
-void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
-{
-	sfxcache_t	*sc;
-	int			vol;
-	playsound_t	*ps, *sort;
-	int			start;
-
-	if (!sound_started)
-		return;
-
-	if (!sfx)
-		return;
-
-	if (sfx->name[0] == '*')
-		sfx = S_RegisterSexedSound(&cl_entities[entnum].current, sfx->name);
-
-	// make sure the sound is loaded
-	sc = S_LoadSound (sfx);
-	if (!sc)
-		return;		// couldn't load the sound's data
-
-	vol = fvol*255;
-
-	// make the playsound_t
-	ps = S_AllocPlaysound ();
-	if (!ps)
-		return;
-
-	if (origin)
-	{
-		VectorCopy (origin, ps->origin);
-		ps->fixed_origin = true;
-	}
-	else
-		ps->fixed_origin = false;
-
-	ps->entnum = entnum;
-	ps->entchannel = entchannel;
-	ps->attenuation = attenuation;
-	ps->volume = vol;
-	ps->sfx = sfx;
-
-	// drift s_beginofs
-	start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs;
-	if (start < paintedtime)
-	{
-		start = paintedtime;
-		s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
-	}
-	else if (start > paintedtime + 0.3 * dma.speed)
-	{
-		start = paintedtime + 0.1 * dma.speed;
-		s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
-	}
-	else
-	{
-		s_beginofs-=10;
-	}
-
-	if (!timeofs)
-		ps->begin = paintedtime;
-	else
-		ps->begin = start + timeofs * dma.speed;
-
-	// sort into the pending sound list
-	for (sort = s_pendingplays.next ; 
-		sort != &s_pendingplays && sort->begin < ps->begin ;
-		sort = sort->next)
-			;
-
-	ps->next = sort;
-	ps->prev = sort->prev;
-
-	ps->next->prev = ps;
-	ps->prev->next = ps;
-}
-
-
-/*
-==================
-S_StartLocalSound
-==================
-*/
-void S_StartLocalSound (char *sound)
-{
-	sfx_t	*sfx;
-
-	if (!sound_started)
-		return;
-		
-	sfx = S_RegisterSound (sound);
-	if (!sfx)
-	{
-		Com_Printf ("S_StartLocalSound: can't cache %s\n", sound);
-		return;
-	}
-	S_StartSound (NULL, cl.playernum+1, 0, sfx, 1, 1, 0);
-}
-
-
-/*
-==================
-S_ClearBuffer
-==================
-*/
-void S_ClearBuffer (void)
-{
-	int		clear;
-		
-	if (!sound_started)
-		return;
-
-	s_rawend = 0;
-
-	if (dma.samplebits == 8)
-		clear = 0x80;
-	else
-		clear = 0;
-
-	SNDDMA_BeginPainting ();
-	if (dma.buffer)
-		memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
-	SNDDMA_Submit ();
-}
-
-/*
-==================
-S_StopAllSounds
-==================
-*/
-void S_StopAllSounds(void)
-{
-	int		i;
-
-	if (!sound_started)
-		return;
-
-	// clear all the playsounds
-	memset(s_playsounds, 0, sizeof(s_playsounds));
-	s_freeplays.next = s_freeplays.prev = &s_freeplays;
-	s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
-
-	for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
-	{
-		s_playsounds[i].prev = &s_freeplays;
-		s_playsounds[i].next = s_freeplays.next;
-		s_playsounds[i].prev->next = &s_playsounds[i];
-		s_playsounds[i].next->prev = &s_playsounds[i];
-	}
-
-	// clear all the channels
-	memset(channels, 0, sizeof(channels));
-
-	S_ClearBuffer ();
-}
-
-/*
-==================
-S_AddLoopSounds
-
-Entities with a ->sound field will generated looped sounds
-that are automatically started, stopped, and merged together
-as the entities are sent to the client
-==================
-*/
-void S_AddLoopSounds (void)
-{
-	int			i, j;
-	int			sounds[MAX_EDICTS];
-	int			left, right, left_total, right_total;
-	channel_t	*ch;
-	sfx_t		*sfx;
-	sfxcache_t	*sc;
-	int			num;
-	entity_state_t	*ent;
-
-	if (cl_paused->value)
-		return;
-
-	if (cls.state != ca_active)
-		return;
-
-	if (!cl.sound_prepped)
-		return;
-
-	for (i=0 ; i<cl.frame.num_entities ; i++)
-	{
-		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
-		ent = &cl_parse_entities[num];
-		sounds[i] = ent->sound;
-	}
-
-	for (i=0 ; i<cl.frame.num_entities ; i++)
-	{
-		if (!sounds[i])
-			continue;
-
-		sfx = cl.sound_precache[sounds[i]];
-		if (!sfx)
-			continue;		// bad sound effect
-		sc = sfx->cache;
-		if (!sc)
-			continue;
-
-		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
-		ent = &cl_parse_entities[num];
-
-		// find the total contribution of all sounds of this type
-		S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
-			&left_total, &right_total);
-		for (j=i+1 ; j<cl.frame.num_entities ; j++)
-		{
-			if (sounds[j] != sounds[i])
-				continue;
-			sounds[j] = 0;	// don't check this again later
-
-			num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1);
-			ent = &cl_parse_entities[num];
-
-			S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE, 
-				&left, &right);
-			left_total += left;
-			right_total += right;
-		}
-
-		if (left_total == 0 && right_total == 0)
-			continue;		// not audible
-
-		// allocate a channel
-		ch = S_PickChannel(0, 0);
-		if (!ch)
-			return;
-
-		if (left_total > 255)
-			left_total = 255;
-		if (right_total > 255)
-			right_total = 255;
-		ch->leftvol = left_total;
-		ch->rightvol = right_total;
-		ch->autosound = true;	// remove next frame
-		ch->sfx = sfx;
-		ch->pos = paintedtime % sc->length;
-		ch->end = paintedtime + sc->length - ch->pos;
-	}
-}
-
-//=============================================================================
-
-/*
-============
-S_RawSamples
-
-Cinematic streaming and voice over network
-============
-*/
-void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
-{
-	int		i;
-	int		src, dst;
-	float	scale;
-
-	if (!sound_started)
-		return;
-
-	if (s_rawend < paintedtime)
-		s_rawend = paintedtime;
-	scale = (float)rate / dma.speed;
-
-//Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
-	if (channels == 2 && width == 2)
-	{
-		if (scale == 1.0)
-		{	// optimized case
-			for (i=0 ; i<samples ; i++)
-			{
-				dst = s_rawend&(MAX_RAW_SAMPLES-1);
-				s_rawend++;
-				s_rawsamples[dst].left =
-				    LittleShort(((short *)data)[i*2]) << 8;
-				s_rawsamples[dst].right =
-				    LittleShort(((short *)data)[i*2+1]) << 8;
-			}
-		}
-		else
-		{
-			for (i=0 ; ; i++)
-			{
-				src = i*scale;
-				if (src >= samples)
-					break;
-				dst = s_rawend&(MAX_RAW_SAMPLES-1);
-				s_rawend++;
-				s_rawsamples[dst].left =
-				    LittleShort(((short *)data)[src*2]) << 8;
-				s_rawsamples[dst].right =
-				    LittleShort(((short *)data)[src*2+1]) << 8;
-			}
-		}
-	}
-	else if (channels == 1 && width == 2)
-	{
-		for (i=0 ; ; i++)
-		{
-			src = i*scale;
-			if (src >= samples)
-				break;
-			dst = s_rawend&(MAX_RAW_SAMPLES-1);
-			s_rawend++;
-			s_rawsamples[dst].left =
-			    LittleShort(((short *)data)[src]) << 8;
-			s_rawsamples[dst].right =
-			    LittleShort(((short *)data)[src]) << 8;
-		}
-	}
-	else if (channels == 2 && width == 1)
-	{
-		for (i=0 ; ; i++)
-		{
-			src = i*scale;
-			if (src >= samples)
-				break;
-			dst = s_rawend&(MAX_RAW_SAMPLES-1);
-			s_rawend++;
-			s_rawsamples[dst].left =
-			    ((char *)data)[src*2] << 16;
-			s_rawsamples[dst].right =
-			    ((char *)data)[src*2+1] << 16;
-		}
-	}
-	else if (channels == 1 && width == 1)
-	{
-		for (i=0 ; ; i++)
-		{
-			src = i*scale;
-			if (src >= samples)
-				break;
-			dst = s_rawend&(MAX_RAW_SAMPLES-1);
-			s_rawend++;
-			s_rawsamples[dst].left =
-			    (((byte *)data)[src]-128) << 16;
-			s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
-		}
-	}
-}
-
-//=============================================================================
-
-/*
-============
-S_Update
-
-Called once each time through the main loop
-============
-*/
-void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
-{
-	int			i;
-	int			total;
-	channel_t	*ch;
-
-	if (!sound_started)
-		return;
-
-	// if the laoding plaque is up, clear everything
-	// out to make sure we aren't looping a dirty
-	// dma buffer while loading
-	if (cls.disable_screen)
-	{
-		S_ClearBuffer ();
-		return;
-	}
-
-	// rebuild scale tables if volume is modified
-	if (s_volume->modified)
-		S_InitScaletable ();
-
-	VectorCopy(origin, listener_origin);
-	VectorCopy(forward, listener_forward);
-	VectorCopy(right, listener_right);
-	VectorCopy(up, listener_up);
-
-	// update spatialization for dynamic sounds	
-	ch = channels;
-	for (i=0 ; i<MAX_CHANNELS; i++, ch++)
-	{
-		if (!ch->sfx)
-			continue;
-		if (ch->autosound)
-		{	// autosounds are regenerated fresh each frame
-			memset (ch, 0, sizeof(*ch));
-			continue;
-		}
-		S_Spatialize(ch);         // respatialize channel
-		if (!ch->leftvol && !ch->rightvol)
-		{
-			memset (ch, 0, sizeof(*ch));
-			continue;
-		}
-	}
-
-	// add loopsounds
-	S_AddLoopSounds ();
-
-	//
-	// debugging output
-	//
-	if (s_show->value)
-	{
-		total = 0;
-		ch = channels;
-		for (i=0 ; i<MAX_CHANNELS; i++, ch++)
-			if (ch->sfx && (ch->leftvol || ch->rightvol) )
-			{
-				Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
-				total++;
-			}
-		
-		Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime);
-	}
-
-// mix some sound
-	S_Update_();
-}
-
-void GetSoundtime(void)
-{
-	int		samplepos;
-	static	int		buffers;
-	static	int		oldsamplepos;
-	int		fullsamples;
-	
-	fullsamples = dma.samples / dma.channels;
-
-// it is possible to miscount buffers if it has wrapped twice between
-// calls to S_Update.  Oh well.
-	samplepos = SNDDMA_GetDMAPos();
-
-	if (samplepos < oldsamplepos)
-	{
-		buffers++;					// buffer wrapped
-		
-		if (paintedtime > 0x40000000)
-		{	// time to chop things off to avoid 32 bit limits
-			buffers = 0;
-			paintedtime = fullsamples;
-			S_StopAllSounds ();
-		}
-	}
-	oldsamplepos = samplepos;
-
-	soundtime = buffers*fullsamples + samplepos/dma.channels;
-}
-
-
-void S_Update_(void)
-{
-	unsigned        endtime;
-	int				samps;
-
-	if (!sound_started)
-		return;
-
-	SNDDMA_BeginPainting ();
-
-	if (!dma.buffer)
-		return;
-
-// Updates DMA time
-	GetSoundtime();
-
-// check to make sure that we haven't overshot
-	if (paintedtime < soundtime)
-	{
-		Com_DPrintf ("S_Update_ : overflow\n");
-		paintedtime = soundtime;
-	}
-
-// mix ahead of current position
-	endtime = soundtime + s_mixahead->value * dma.speed;
-//endtime = (soundtime + 4096) & ~4095;
-
-	// mix to an even submission block size
-	endtime = (endtime + dma.submission_chunk-1)
-		& ~(dma.submission_chunk-1);
-	samps = dma.samples >> (dma.channels-1);
-	if (endtime - soundtime > samps)
-		endtime = soundtime + samps;
-
-	S_PaintChannels (endtime);
-
-	SNDDMA_Submit ();
-}
-
-/*
-===============================================================================
-
-console functions
-
-===============================================================================
-*/
-
-void S_Play(void)
-{
-	int 	i;
-	char name[256];
-	sfx_t	*sfx;
-	
-	i = 1;
-	while (i<Cmd_Argc())
-	{
-		if (!strrchr(Cmd_Argv(i), '.'))
-		{
-			strcpy(name, Cmd_Argv(i));
-			strcat(name, ".wav");
-		}
-		else
-			strcpy(name, Cmd_Argv(i));
-		sfx = S_RegisterSound(name);
-		S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
-		i++;
-	}
-}
-
-void S_SoundList(void)
-{
-	int		i;
-	sfx_t	*sfx;
-	sfxcache_t	*sc;
-	int		size, total;
-
-	total = 0;
-	for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
-	{
-		if (!sfx->registration_sequence)
-			continue;
-		sc = sfx->cache;
-		if (sc)
-		{
-			size = sc->length*sc->width*(sc->stereo+1);
-			total += size;
-			if (sc->loopstart >= 0)
-				Com_Printf ("L");
-			else
-				Com_Printf (" ");
-			Com_Printf("(%2db) %6i : %s\n",sc->width*8,  size, sfx->name);
-		}
-		else
-		{
-			if (sfx->name[0] == '*')
-				Com_Printf("  placeholder : %s\n", sfx->name);
-			else
-				Com_Printf("  not loaded  : %s\n", sfx->name);
-		}
-	}
-	Com_Printf ("Total resident: %i\n", total);
-}
-
--- a/client/snd_loc.h
+++ /dev/null
@@ -1,144 +1,0 @@
-// snd_loc.h -- private sound functions
-
-// !!! if this is changed, the asm code must change !!!
-typedef struct
-{
-	int			left;
-	int			right;
-} portable_samplepair_t;
-
-typedef struct
-{
-	int 		length;
-	int 		loopstart;
-	int 		speed;			// not needed, because converted on load?
-	int 		width;
-	int 		stereo;
-	byte		data[1];		// variable sized
-} sfxcache_t;
-
-typedef struct sfx_s
-{
-	char 		name[MAX_QPATH];
-	int			registration_sequence;
-	sfxcache_t	*cache;
-	char 		*truename;
-} sfx_t;
-
-// a playsound_t will be generated by each call to S_StartSound,
-// when the mixer reaches playsound->begin, the playsound will
-// be assigned to a channel
-typedef struct playsound_s
-{
-	struct playsound_s	*prev, *next;
-	sfx_t		*sfx;
-	float		volume;
-	float		attenuation;
-	int			entnum;
-	int			entchannel;
-	qboolean	fixed_origin;	// use origin field instead of entnum's origin
-	vec3_t		origin;
-	unsigned	begin;			// begin on this sample
-} playsound_t;
-
-typedef struct
-{
-	int			channels;
-	int			samples;				// mono samples in buffer
-	int			submission_chunk;		// don't mix less than this #
-	int			samplepos;				// in mono samples
-	int			samplebits;
-	int			speed;
-	byte		*buffer;
-} dma_t;
-
-// !!! if this is changed, the asm code must change !!!
-typedef struct
-{
-	sfx_t		*sfx;			// sfx number
-	int			leftvol;		// 0-255 volume
-	int			rightvol;		// 0-255 volume
-	int			end;			// end time in global paintsamples
-	int 		pos;			// sample position in sfx
-	int			looping;		// where to loop, -1 = no looping OBSOLETE?
-	int			entnum;			// to allow overriding a specific sound
-	int			entchannel;		//
-	vec3_t		origin;			// only use if fixed_origin is set
-	vec_t		dist_mult;		// distance multiplier (attenuation/clipK)
-	int			master_vol;		// 0-255 master volume
-	qboolean	fixed_origin;	// use origin instead of fetching entnum's origin
-	qboolean	autosound;		// from an entity->sound, cleared each frame
-} channel_t;
-
-typedef struct
-{
-	int			rate;
-	int			width;
-	int			channels;
-	int			loopstart;
-	int			samples;
-	int			dataofs;		// chunk starts this many bytes from file start
-} wavinfo_t;
-
-
-/*
-====================================================================
-
-  SYSTEM SPECIFIC FUNCTIONS
-
-====================================================================
-*/
-
-// initializes cycling through a DMA buffer and returns information on it
-qboolean SNDDMA_Init(void);
-
-// gets the current DMA position
-int		SNDDMA_GetDMAPos(void);
-
-// shutdown the DMA xfer.
-void	SNDDMA_Shutdown(void);
-
-void	SNDDMA_BeginPainting (void);
-
-void	SNDDMA_Submit(void);
-
-//====================================================================
-
-#define	MAX_CHANNELS			32
-extern	channel_t   channels[MAX_CHANNELS];
-
-extern	int		paintedtime;
-extern	int		s_rawend;
-extern	vec3_t	listener_origin;
-extern	vec3_t	listener_forward;
-extern	vec3_t	listener_right;
-extern	vec3_t	listener_up;
-extern	dma_t	dma;
-extern	playsound_t	s_pendingplays;
-
-#define	MAX_RAW_SAMPLES	8192
-extern	portable_samplepair_t	s_rawsamples[MAX_RAW_SAMPLES];
-
-extern cvar_t	*s_volume;
-extern cvar_t	*s_loadas8bit;
-extern cvar_t	*s_khz;
-extern cvar_t	*s_show;
-extern cvar_t	*s_mixahead;
-extern cvar_t	*s_testsound;
-extern cvar_t	*s_primary;
-
-wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength);
-
-void S_InitScaletable (void);
-
-sfxcache_t *S_LoadSound (sfx_t *s);
-
-void S_IssuePlaysound (playsound_t *ps);
-
-void S_PaintChannels(int endtime);
-
-// picks a channel based on priorities, empty slots, number of channels
-channel_t *S_PickChannel(int entnum, int entchannel);
-
-// spatializes a channel
-void S_Spatialize(channel_t *ch);
--- a/client/snd_mem.c
+++ /dev/null
@@ -1,341 +1,0 @@
-// snd_mem.c: sound caching
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-int			cache_full_cycle;
-
-byte *S_Alloc (int size);
-
-/*
-================
-ResampleSfx
-================
-*/
-void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
-{
-	int		outcount;
-	int		srcsample;
-	float	stepscale;
-	int		i;
-	int		sample, samplefrac, fracstep;
-	sfxcache_t	*sc;
-	
-	sc = sfx->cache;
-	if (!sc)
-		return;
-
-	stepscale = (float)inrate / dma.speed;	// this is usually 0.5, 1, or 2
-
-	outcount = sc->length / stepscale;
-	sc->length = outcount;
-	if (sc->loopstart != -1)
-		sc->loopstart = sc->loopstart / stepscale;
-
-	sc->speed = dma.speed;
-	if (s_loadas8bit->value)
-		sc->width = 1;
-	else
-		sc->width = inwidth;
-	sc->stereo = 0;
-
-// resample / decimate to the current source rate
-
-	if (stepscale == 1 && inwidth == 1 && sc->width == 1)
-	{
-// fast special case
-		for (i=0 ; i<outcount ; i++)
-			((signed char *)sc->data)[i]
-			= (int)( (unsigned char)(data[i]) - 128);
-	}
-	else
-	{
-// general case
-		samplefrac = 0;
-		fracstep = stepscale*256;
-		for (i=0 ; i<outcount ; i++)
-		{
-			srcsample = samplefrac >> 8;
-			samplefrac += fracstep;
-			if (inwidth == 2)
-				sample = LittleShort ( ((short *)data)[srcsample] );
-			else
-				sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
-			if (sc->width == 2)
-				((short *)sc->data)[i] = sample;
-			else
-				((signed char *)sc->data)[i] = sample >> 8;
-		}
-	}
-}
-
-//=============================================================================
-
-/*
-==============
-S_LoadSound
-==============
-*/
-sfxcache_t *S_LoadSound (sfx_t *s)
-{
-    char	namebuffer[MAX_QPATH];
-	byte	*data;
-	wavinfo_t	info;
-	int		len;
-	float	stepscale;
-	sfxcache_t	*sc;
-	int		size;
-	char	*name;
-
-	if (s->name[0] == '*')
-		return NULL;
-
-// see if still in memory
-	sc = s->cache;
-	if (sc)
-		return sc;
-
-//Com_Printf ("S_LoadSound: %x\n", (int)stackbuf);
-// load it in
-	if (s->truename)
-		name = s->truename;
-	else
-		name = s->name;
-
-	if (name[0] == '#')
-		strcpy(namebuffer, &name[1]);
-	else
-		Com_sprintf (namebuffer, sizeof(namebuffer), "sound/%s", name);
-
-//	Com_Printf ("loading %s\n",namebuffer);
-
-	size = FS_LoadFile (namebuffer, (void **)&data);
-
-	if (!data)
-	{
-		Com_DPrintf ("Couldn't load %s\n", namebuffer);
-		return NULL;
-	}
-
-	info = GetWavinfo (s->name, data, size);
-	if (info.channels != 1)
-	{
-		Com_Printf ("%s is a stereo sample\n",s->name);
-		FS_FreeFile (data);
-		return NULL;
-	}
-
-	stepscale = (float)info.rate / dma.speed;	
-	len = info.samples / stepscale;
-
-	len = len * info.width * info.channels;
-
-	sc = s->cache = Z_Malloc (len + sizeof(sfxcache_t));
-	if (!sc)
-	{
-		FS_FreeFile (data);
-		return NULL;
-	}
-	
-	sc->length = info.samples;
-	sc->loopstart = info.loopstart;
-	sc->speed = info.rate;
-	sc->width = info.width;
-	sc->stereo = info.channels;
-
-	ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
-
-	FS_FreeFile (data);
-
-	return sc;
-}
-
-
-
-/*
-===============================================================================
-
-WAV loading
-
-===============================================================================
-*/
-
-
-byte	*data_p;
-byte 	*iff_end;
-byte 	*last_chunk;
-byte 	*iff_data;
-int 	iff_chunk_len;
-
-
-short GetLittleShort(void)
-{
-	short val;
-	val = *data_p;
-	val = val + (*(data_p+1)<<8);
-	data_p += 2;
-	return val;
-}
-
-int GetLittleLong(void)
-{
-	int val;
-	val = *data_p;
-	val = val + (*(data_p+1)<<8);
-	val = val + (*(data_p+2)<<16);
-	val = val + (*(data_p+3)<<24);
-	data_p += 4;
-	return val;
-}
-
-void FindNextChunk(char *name)
-{
-	while (1)
-	{
-		data_p=last_chunk;
-
-		if (data_p >= iff_end)
-		{	// didn't find the chunk
-			data_p = NULL;
-			return;
-		}
-		
-		data_p += 4;
-		iff_chunk_len = GetLittleLong();
-		if (iff_chunk_len < 0)
-		{
-			data_p = NULL;
-			return;
-		}
-//		if (iff_chunk_len > 1024*1024)
-//			Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
-		data_p -= 8;
-		last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
-		if (!strncmp((char *)data_p, name, 4))
-			return;
-	}
-}
-
-void FindChunk(char *name)
-{
-	last_chunk = iff_data;
-	FindNextChunk (name);
-}
-
-
-void DumpChunks(void)
-{
-	char	str[5];
-	
-	str[4] = 0;
-	data_p=iff_data;
-	do
-	{
-		memcpy (str, data_p, 4);
-		data_p += 4;
-		iff_chunk_len = GetLittleLong();
-		Com_Printf ("0x%x : %s (%p)\n", (uintptr)(data_p - 4), str, iff_chunk_len);
-		data_p += (iff_chunk_len + 1) & ~1;
-	} while (data_p < iff_end);
-}
-
-/*
-============
-GetWavinfo
-============
-*/
-wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
-{
-	wavinfo_t	info;
-	int     i;
-	int     format;
-	int		samples;
-
-	memset (&info, 0, sizeof(info));
-
-	if (!wav)
-		return info;
-		
-	iff_data = wav;
-	iff_end = wav + wavlength;
-
-// find "RIFF" chunk
-	FindChunk("RIFF");
-	if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4)))
-	{
-		Com_Printf("Missing RIFF/WAVE chunks\n");
-		return info;
-	}
-
-// get "fmt " chunk
-	iff_data = data_p + 12;
-// DumpChunks ();
-
-	FindChunk("fmt ");
-	if (!data_p)
-	{
-		Com_Printf("Missing fmt chunk\n");
-		return info;
-	}
-	data_p += 8;
-	format = GetLittleShort();
-	if (format != 1)
-	{
-		Com_Printf("Microsoft PCM format only\n");
-		return info;
-	}
-
-	info.channels = GetLittleShort();
-	info.rate = GetLittleLong();
-	data_p += 4+2;
-	info.width = GetLittleShort() / 8;
-
-// get cue chunk
-	FindChunk("cue ");
-	if (data_p)
-	{
-		data_p += 32;
-		info.loopstart = GetLittleLong();
-//		Com_Printf("loopstart=%d\n", sfx->loopstart);
-
-	// if the next chunk is a LIST chunk, look for a cue length marker
-		FindNextChunk ("LIST");
-		if (data_p)
-		{
-			if (!strncmp ((char *)data_p + 28, "mark", 4))
-			{	// this is not a proper parse, but it works with cooledit...
-				data_p += 24;
-				i = GetLittleLong ();	// samples in loop
-				info.samples = info.loopstart + i;
-//				Com_Printf("looped length: %i\n", i);
-			}
-		}
-	}
-	else
-		info.loopstart = -1;
-
-// find data chunk
-	FindChunk("data");
-	if (!data_p)
-	{
-		Com_Printf("Missing data chunk\n");
-		return info;
-	}
-
-	data_p += 4;
-	samples = GetLittleLong () / info.width;
-
-	if (info.samples)
-	{
-		if (samples < info.samples)
-			Com_Error (ERR_DROP, "Sound %s has a bad loop length", name);
-	}
-	else
-		info.samples = samples;
-
-	info.dataofs = data_p - wav;
-	
-	return info;
-}
-
--- a/client/snd_mix.c
+++ /dev/null
@@ -1,349 +1,0 @@
-// snd_mix.c -- portable code to mix sounds for snd_dma.c
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-#define	PAINTBUFFER_SIZE	2048
-portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
-int		snd_scaletable[32][256];
-int 	*snd_p, snd_linear_count, snd_vol;
-short	*snd_out;
-
-
-void S_WriteLinearBlastStereo16 (void)
-{
-	int		i;
-	int		val;
-
-	for (i=0 ; i<snd_linear_count ; i+=2)
-	{
-		val = snd_p[i]>>8;
-		if (val > 0x7fff)
-			snd_out[i] = 0x7fff;
-		else if (val < (short)0x8000)
-			snd_out[i] = (short)0x8000;
-		else
-			snd_out[i] = val;
-
-		val = snd_p[i+1]>>8;
-		if (val > 0x7fff)
-			snd_out[i+1] = 0x7fff;
-		else if (val < (short)0x8000)
-			snd_out[i+1] = (short)0x8000;
-		else
-			snd_out[i+1] = val;
-	}
-}
-
-void S_TransferStereo16 (unsigned long *pbuf, int endtime)
-{
-	int		lpos;
-	int		lpaintedtime;
-	
-	snd_p = (int *) paintbuffer;
-	lpaintedtime = paintedtime;
-
-	while (lpaintedtime < endtime)
-	{
-	// handle recirculating buffer issues
-		lpos = lpaintedtime & ((dma.samples>>1)-1);
-
-		snd_out = (short *) pbuf + (lpos<<1);
-
-		snd_linear_count = (dma.samples>>1) - lpos;
-		if (lpaintedtime + snd_linear_count > endtime)
-			snd_linear_count = endtime - lpaintedtime;
-
-		snd_linear_count <<= 1;
-
-	// write a linear blast of samples
-		S_WriteLinearBlastStereo16 ();
-
-		snd_p += snd_linear_count;
-		lpaintedtime += (snd_linear_count>>1);
-	}
-}
-
-/*
-===================
-S_TransferPaintBuffer
-
-===================
-*/
-void S_TransferPaintBuffer(int endtime)
-{
-	int 	out_idx;
-	int 	count;
-	int 	out_mask;
-	int 	*p;
-	int 	step;
-	int		val;
-	unsigned long *pbuf;
-
-	pbuf = (unsigned long *)dma.buffer;
-
-	if (s_testsound->value)
-	{
-		int		i;
-		int		count;
-
-		// write a fixed sine wave
-		count = (endtime - paintedtime);
-		for (i=0 ; i<count ; i++)
-			paintbuffer[i].left = paintbuffer[i].right = sin((paintedtime+i)*0.1)*20000*256;
-	}
-
-
-	if (dma.samplebits == 16 && dma.channels == 2)
-	{	// optimized case
-		S_TransferStereo16 (pbuf, endtime);
-	}
-	else
-	{	// general case
-		p = (int *) paintbuffer;
-		count = (endtime - paintedtime) * dma.channels;
-		out_mask = dma.samples - 1; 
-		out_idx = paintedtime * dma.channels & out_mask;
-		step = 3 - dma.channels;
-
-		if (dma.samplebits == 16)
-		{
-			short *out = (short *) pbuf;
-			while (count--)
-			{
-				val = *p >> 8;
-				p+= step;
-				if (val > 0x7fff)
-					val = 0x7fff;
-				else if (val < (short)0x8000)
-					val = (short)0x8000;
-				out[out_idx] = val;
-				out_idx = (out_idx + 1) & out_mask;
-			}
-		}
-		else if (dma.samplebits == 8)
-		{
-			unsigned char *out = (unsigned char *) pbuf;
-			while (count--)
-			{
-				val = *p >> 8;
-				p+= step;
-				if (val > 0x7fff)
-					val = 0x7fff;
-				else if (val < (short)0x8000)
-					val = (short)0x8000;
-				out[out_idx] = (val>>8) + 128;
-				out_idx = (out_idx + 1) & out_mask;
-			}
-		}
-	}
-}
-
-
-/*
-===============================================================================
-
-CHANNEL MIXING
-
-===============================================================================
-*/
-
-void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
-void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
-
-void S_PaintChannels(int endtime)
-{
-	int 	i;
-	int 	end;
-	channel_t *ch;
-	sfxcache_t	*sc;
-	int		ltime, count;
-	playsound_t	*ps;
-
-	snd_vol = s_volume->value*256;
-
-//Com_Printf ("%i to %i\n", paintedtime, endtime);
-	while (paintedtime < endtime)
-	{
-	// if paintbuffer is smaller than DMA buffer
-		end = endtime;
-		if (endtime - paintedtime > PAINTBUFFER_SIZE)
-			end = paintedtime + PAINTBUFFER_SIZE;
-
-		// start any playsounds
-		while (1)
-		{
-			ps = s_pendingplays.next;
-			if (ps == &s_pendingplays)
-				break;	// no more pending sounds
-			if (ps->begin <= paintedtime)
-			{
-				S_IssuePlaysound (ps);
-				continue;
-			}
-
-			if (ps->begin < end)
-				end = ps->begin;		// stop here
-			break;
-		}
-
-	// clear the paint buffer
-		if (s_rawend < paintedtime)
-		{
-//			Com_Printf ("clear\n");
-			memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
-		}
-		else
-		{	// copy from the streaming sound source
-			int		s;
-			int		stop;
-
-			stop = (end < s_rawend) ? end : s_rawend;
-
-			for (i=paintedtime ; i<stop ; i++)
-			{
-				s = i&(MAX_RAW_SAMPLES-1);
-				paintbuffer[i-paintedtime] = s_rawsamples[s];
-			}
-//		if (i != end)
-//			Com_Printf ("partial stream\n");
-//		else
-//			Com_Printf ("full stream\n");
-			for ( ; i<end ; i++)
-			{
-				paintbuffer[i-paintedtime].left =
-				paintbuffer[i-paintedtime].right = 0;
-			}
-		}
-
-
-	// paint in the channels.
-		ch = channels;
-		for (i=0; i<MAX_CHANNELS ; i++, ch++)
-		{
-			ltime = paintedtime;
-		
-			while (ltime < end)
-			{
-				if (!ch->sfx || (!ch->leftvol && !ch->rightvol) )
-					break;
-
-				// max painting is to the end of the buffer
-				count = end - ltime;
-
-				// might be stopped by running out of data
-				if (ch->end - ltime < count)
-					count = ch->end - ltime;
-		
-				sc = S_LoadSound (ch->sfx);
-				if (!sc)
-					break;
-
-				if (count > 0 && ch->sfx)
-				{	
-					if (sc->width == 1)// FIXME; 8 bit asm is wrong now
-						S_PaintChannelFrom8(ch, sc, count,  ltime - paintedtime);
-					else
-						S_PaintChannelFrom16(ch, sc, count, ltime - paintedtime);
-	
-					ltime += count;
-				}
-
-			// if at end of loop, restart
-				if (ltime >= ch->end)
-				{
-					if (ch->autosound)
-					{	// autolooping sounds always go back to start
-						ch->pos = 0;
-						ch->end = ltime + sc->length;
-					}
-					else if (sc->loopstart >= 0)
-					{
-						ch->pos = sc->loopstart;
-						ch->end = ltime + sc->length - ch->pos;
-					}
-					else				
-					{	// channel just stopped
-						ch->sfx = NULL;
-					}
-				}
-			}
-															  
-		}
-
-	// transfer out according to DMA format
-		S_TransferPaintBuffer(end);
-		paintedtime = end;
-	}
-}
-
-void S_InitScaletable (void)
-{
-	int		i, j;
-	int		scale;
-
-	s_volume->modified = false;
-	for (i=0 ; i<32 ; i++)
-	{
-		scale = i * 8 * 256 * s_volume->value;
-		for (j=0 ; j<256 ; j++)
-			snd_scaletable[i][j] = ((signed char)j) * scale;
-	}
-}
-
-void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
-{
-	int 	data;
-	int		*lscale, *rscale;
-	unsigned char *sfx;
-	int		i;
-	portable_samplepair_t	*samp;
-
-	if (ch->leftvol > 255)
-		ch->leftvol = 255;
-	if (ch->rightvol > 255)
-		ch->rightvol = 255;
-		
-	lscale = snd_scaletable[ ch->leftvol >> 11];
-	rscale = snd_scaletable[ ch->rightvol >> 11];
-	sfx = (uchar *)sc->data + ch->pos;
-
-	samp = &paintbuffer[offset];
-
-	for (i=0 ; i<count ; i++, samp++)
-	{
-		data = sfx[i];
-		samp->left += lscale[data];
-		samp->right += rscale[data];
-	}
-	
-	ch->pos += count;
-}
-
-void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count, int offset)
-{
-	int data;
-	int left, right;
-	int leftvol, rightvol;
-	signed short *sfx;
-	int	i;
-	portable_samplepair_t	*samp;
-
-	leftvol = ch->leftvol*snd_vol;
-	rightvol = ch->rightvol*snd_vol;
-	sfx = (signed short *)sc->data + ch->pos;
-
-	samp = &paintbuffer[offset];
-	for (i=0 ; i<count ; i++, samp++)
-	{
-		data = sfx[i];
-		left = (data * leftvol)>>8;
-		right = (data * rightvol)>>8;
-		samp->left += left;
-		samp->right += right;
-	}
-
-	ch->pos += count;
-}
--- a/client/sound.h
+++ /dev/null
@@ -1,21 +1,0 @@
-void S_Init (void);
-void S_Shutdown (void);
-
-// if origin is NULL, the sound will be dynamically sourced from the entity
-void S_StartSound (vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol,  float attenuation, float timeofs);
-void S_StartLocalSound (char *s);
-
-void S_RawSamples (int samples, int rate, int width, int channels, byte *data);
-
-void S_StopAllSounds(void);
-void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up);
-
-void S_Activate (qboolean active);
-
-void S_BeginRegistration (void);
-sfx_t *S_RegisterSound (char *sample);
-void S_EndRegistration (void);
-
-// the sound code makes callbacks to the client for entitiy position
-// information, so entities can be dynamically re-spatialized
-void CL_GetEntitySoundOrigin (int ent, vec3_t org);
--- a/client/vid.h
+++ /dev/null
@@ -1,33 +1,0 @@
-// vid.h -- video driver defs
-
-typedef uchar pixel_t;
-
-typedef struct vrect_t vrect_t;
-typedef struct viddef_t viddef_t;
-
-struct vrect_t
-{
-	int	x, y, width, height;
-	vrect_t	*pnext;
-};
-
-struct viddef_t
-{
-	int	width;          
-	int	height;
-	pixel_t	*buffer;                // invisible buffer
-	pixel_t	*colormap;              // 256 * VID_GRADES size
-	pixel_t	*alphamap;              // 256 * 256 translucency map
-	int	rowbytes;               // may be > width if displayed in a window
-					// can be negative for stupid dibs
-};
-extern viddef_t vid;
-
-// Video module initialisation etc
-void	VID_Init (void);
-void	VID_Shutdown (void);
-void	VID_CheckChanges (void);
-
-void	VID_MenuInit( void );
-void	VID_MenuDraw( void );
-const char *VID_MenuKey( int );
--- /dev/null
+++ b/cmd.c
@@ -1,0 +1,633 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/* Command text buffering and command execution
+ *
+ * Any number of commands can be added in a frame, from several different
+ * sources. Most commands come from either keybindings or console line input,
+ * but remote servers can also send across commands and entire text files can
+ * be execed. The '+' command line options are also added to the command buffer.
+ * The game starts with a Cbuf_AddText("exec quake.rc\n"); Cbuf_Execute();.
+ * Command execution takes a null terminated string, breaks it into tokens,
+ * then searches for a command or variable that matches the first token. */
+
+typedef struct cmdalias_t cmdalias_t;
+typedef struct cmd_function_t cmd_function_t;
+
+enum{
+	MAX_ALIAS_NAME = 32,
+	ALIAS_LOOP_COUNT = 16
+};
+struct cmdalias_t{
+	cmdalias_t *next;
+	char name[MAX_ALIAS_NAME];
+	char *value;
+};
+cmdalias_t *cmd_alias;
+int alias_count;	// for detecting runaway loops
+
+qboolean cmd_wait;
+
+sizebuf_t cmd_text;
+uchar cmd_text_buf[8192];
+uchar defer_text_buf[8192];
+
+static int cmd_argc;
+static char *cmd_argv[MAX_STRING_TOKENS];
+static char *cmd_null_string = "";
+static char cmd_args[MAX_STRING_CHARS];
+
+struct cmd_function_t{
+	cmd_function_t *next;
+	char *name;
+	xcommand_t function;
+};
+static cmd_function_t *cmd_functions;	// possible commands to execute
+
+
+/* Causes execution of the remainder of the command buffer to be delayed until
+ * next frame. This allows commands like:
+ * bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2" */
+void
+Cmd_Wait_f(void)
+{
+	cmd_wait = true;
+}
+
+/* allocates an initial text buffer that will grow as needed */
+void
+Cbuf_Init(void)
+{
+	SZ_Init(&cmd_text, cmd_text_buf, sizeof cmd_text_buf);
+}
+
+/* adds command text at the end of the buffer */
+void
+Cbuf_AddText(char *text)
+{
+	int l;
+
+	l = strlen(text);
+
+	if(cmd_text.cursize + l >= cmd_text.maxsize){
+		Com_Printf("Cbuf_AddText: overflow\n");
+		return;
+	}
+	SZ_Write(&cmd_text, text, l);
+}
+
+// FIXME: actually change the command buffer to do less copying
+/* Adds command text immediately after the current command and '\n' to the text */
+void
+Cbuf_InsertText(char *text)
+{
+	char *temp = nil;
+	int templen;
+
+	/* copy off any commands still remaining in the exec buffer */
+	templen = cmd_text.cursize;
+	if(templen){
+		temp = Z_Malloc(templen);
+		memcpy(temp, cmd_text.data, templen);
+		SZ_Clear(&cmd_text);
+	}
+
+	Cbuf_AddText(text);
+	if(templen){
+		SZ_Write(&cmd_text, temp, templen);
+		Z_Free(temp);
+	}
+}
+
+void
+Cbuf_CopyToDefer(void)
+{
+	memcpy(defer_text_buf, cmd_text_buf, cmd_text.cursize);
+	defer_text_buf[cmd_text.cursize] = 0;
+	cmd_text.cursize = 0;
+}
+
+void
+Cbuf_InsertFromDefer(void)
+{
+	Cbuf_InsertText((char *)defer_text_buf);
+	defer_text_buf[0] = 0;
+}
+
+void
+Cbuf_ExecuteText(int exec_when, char *text)
+{
+	switch(exec_when){
+	case EXEC_NOW:
+		Cmd_ExecuteString(text);
+		break;
+	case EXEC_INSERT:
+		Cbuf_InsertText(text);
+		break;
+	case EXEC_APPEND:
+		Cbuf_AddText(text);
+		break;
+	default:
+		Com_Error(ERR_FATAL, "Cbuf_ExecuteText: bad exec_when");
+	}
+}
+
+/* normally called once per frame, but may be explicitly invoked.
+ * do not call inside a command function! */
+void
+Cbuf_Execute(void)
+{
+	int i, quotes;
+	char *text, line[1024];
+
+	alias_count = 0;	// don't allow infinite alias loops
+
+	while(cmd_text.cursize){
+		text = (char *)cmd_text.data;
+
+		/* find a \n or ; line break */
+		quotes = 0;
+		for(i=0; i<cmd_text.cursize; i++){
+			if(text[i] == '"')
+				quotes++;
+			if(~quotes & 1 && text[i] == ';')
+				break;	// don't break if inside a quoted string
+			if(text[i] == '\n')
+				break;
+		}	
+		memcpy(line, text, i);
+		line[i] = 0;
+
+		/* delete the text from the command buffer and move remaining
+		 * commands down. this is necessary because commands (exec,
+		 * alias) can insert data at the beginning of the text buffer */
+		if(i == cmd_text.cursize)
+			cmd_text.cursize = 0;
+		else{
+			i++;
+			cmd_text.cursize -= i;
+			memmove(text, text+i, cmd_text.cursize);
+		}
+
+		Cmd_ExecuteString(line);
+
+		/* skip out while text still remains in buffer, leaving it for
+		 * next frame */
+		if(cmd_wait){
+			cmd_wait = false;
+			break;
+		}
+	}
+}
+
+/* Adds command line parameters as script statements. Commands lead with a '+',
+ * and continue until another '+'. Set commands are added early, so they are
+ * guaranteed to be set before the client and server initialize for the first
+ * time. Other commands are added late, after all initialization is complete. */
+void
+Cbuf_AddEarlyCommands(qboolean clear)
+{
+	int i;
+	char *s;
+
+	for(i=0; i<COM_Argc(); i++){
+		s = COM_Argv(i);
+		if(strcmp(s, "+set"))
+			continue;
+		Cbuf_AddText(va("set %s %s\n", COM_Argv(i+1), COM_Argv(i+2)));
+		if(clear){
+			COM_ClearArgv(i);
+			COM_ClearArgv(i+1);
+			COM_ClearArgv(i+2);
+		}
+		i += 2;
+	}
+}
+
+/* Adds command line parameters as script statements. Commands lead with a '+'
+ * and continue until another '+' or '-'. Returns true if any late commands
+ * were added, which will keep the demoloop from immediately starting. */
+qboolean
+Cbuf_AddLateCommands(void)
+{
+	int i, j, s, argc;
+	char *text, *build, c;
+	qboolean ret;
+
+	/* build the combined string to parse from */
+	s = 0;
+	argc = COM_Argc();
+	for(i=1; i<argc; i++)
+		s += strlen(COM_Argv(i)) + 1;
+	if(!s)
+		return false;
+		
+	text = Z_Malloc(s+1);
+	text[0] = 0;
+	for(i=1; i<argc; i++){
+		strcat(text, COM_Argv(i));
+		if(i != argc-1)
+			strcat(text, " ");
+	}
+
+	/* pull out the commands */
+	build = Z_Malloc(s+1);
+	build[0] = 0;
+	for(i=0; i<s-1; i++)
+		if(text[i] == '+'){
+			i++;
+			for(j=i; text[j] != '+' && text[j] != '-' && text[j] != 0 ; j++)
+				;
+			c = text[j];
+			text[j] = 0;
+			strcat(build, text+i);
+			strcat(build, "\n");
+			text[j] = c;
+			i = j-1;
+		}
+
+	ret = build[0] != 0;
+	if(ret)
+		Cbuf_AddText(build);
+	Z_Free(text);
+	Z_Free(build);
+	return ret;
+}
+
+void
+Cmd_Exec_f(void)
+{
+	char *f, *f2;
+	int len;
+
+	if(Cmd_Argc() != 2){
+		Com_Printf("exec <filename> : execute a script file\n");
+		return;
+	}
+
+	len = FS_LoadFile(Cmd_Argv(1), (void **)&f);
+	if(!f){
+		Com_Printf("couldn't exec %s\n", Cmd_Argv(1));
+		return;
+	}
+	Com_Printf("execing %s\n", Cmd_Argv(1));
+
+	/* the file doesn't have a trailing 0, so we need to copy it off */
+	f2 = Z_Malloc(len+1);
+	memcpy(f2, f, len);
+	f2[len] = 0;
+	Cbuf_InsertText(f2);
+	Z_Free(f2);
+	FS_FreeFile(f);
+}
+
+/* just prints the rest of the line to the console */
+void
+Cmd_Echo_f(void)
+{
+	int i;
+	
+	for(i=1; i<Cmd_Argc(); i++)
+		Com_Printf("%s ", Cmd_Argv(i));
+	Com_Printf("\n");
+}
+
+/* Creates a new command that executes a command string (possibly ; seperated) */
+void
+Cmd_Alias_f(void)
+{
+	int i, c;
+	char cmd[1024], *s;
+	cmdalias_t *p;
+
+	if(Cmd_Argc() == 1){
+		Com_Printf("Current alias commands:\n");
+		for(p = cmd_alias; p != nil; p = p->next)
+			Com_Printf("%s : %s\n", p->name, p->value);
+		return;
+	}
+
+	s = Cmd_Argv(1);
+	if(strlen(s) >= MAX_ALIAS_NAME){
+		Com_Printf("Alias name is too long\n");
+		return;
+	}
+
+	/* if the alias already exists, reuse it */
+	for(p = cmd_alias; p != nil; p = p->next)
+		if(!strcmp(s, p->name)){
+			Z_Free(p->value);
+			break;
+		}
+
+	if(p == nil){
+		p = Z_Malloc(sizeof *p);
+		p->next = cmd_alias;
+		cmd_alias = p;
+	}
+	strcpy(p->name, s);	
+
+	/* copy the rest of the command line */
+	cmd[0] = 0;	// start out with a null string
+	c = Cmd_Argc();
+	for(i=2; i<c; i++){
+		strcat(cmd, Cmd_Argv(i));
+		if(i != c-1)
+			strcat(cmd, " ");
+	}
+	strcat(cmd, "\n");
+	p->value = CopyString(cmd);
+}
+
+int
+Cmd_Argc(void)
+{
+	return cmd_argc;
+}
+
+char *
+Cmd_Argv(int arg)
+{
+	if((unsigned)arg >= cmd_argc)
+		return cmd_null_string;
+	return cmd_argv[arg];	
+}
+
+/* returns a single string containing argv(1) to argv(argc()-1) */
+char *
+Cmd_Args(void)
+{
+	return cmd_args;
+}
+
+char *
+Cmd_MacroExpandString(char *text)
+{
+	int i, j, count, len;
+	qboolean inquote;
+	char *scan, *token, *start;
+	char temporary[MAX_STRING_CHARS];
+	static char expanded[MAX_STRING_CHARS];
+
+	inquote = false;
+	scan = text;
+	len = strlen (scan);
+	if(len >= MAX_STRING_CHARS){
+		Com_Printf("Line exceeded %d chars, discarded.\n", MAX_STRING_CHARS);
+		return nil;
+	}
+
+	count = 0;
+	for(i=0; i<len ; i++){
+		if(scan[i] == '"')
+			inquote ^= 1;
+		if(inquote)
+			continue;	// don't expand inside quotes
+		if(scan[i] != '$')
+			continue;
+
+		/* scan out the complete macro */
+		start = scan+i+1;
+		token = COM_Parse(&start);
+		if(!start)
+			continue;
+
+		token = Cvar_VariableString(token);
+		j = strlen(token);
+		len += j;
+		if(len >= MAX_STRING_CHARS){
+			Com_Printf("Expanded line exceeded %d chars, discarded.\n", MAX_STRING_CHARS);
+			return nil;
+		}
+
+		strncpy(temporary, scan, i);
+		strcpy(temporary+i, token);
+		strcpy(temporary+i+j, start);
+		strcpy(expanded, temporary);
+		scan = expanded;
+		i--;
+
+		if(++count == 100){
+			Com_Printf("Macro expansion loop, discarded.\n");
+			return nil;
+		}
+	}
+
+	if(inquote){
+		Com_Printf("Line has unmatched quote, discarded.\n");
+		return nil;
+	}
+	return scan;
+}
+
+/* Parses the given string into command line tokens. $Cvars will be expanded
+ * unless they are in a quoted token */
+void
+Cmd_TokenizeString(char *text, qboolean macroExpand)
+{
+	int i, l;
+	char *com_token;
+
+	/* clear the args from the last string */
+	for(i=0; i<cmd_argc; i++)
+		Z_Free(cmd_argv[i]);
+	cmd_argc = 0;
+	cmd_args[0] = 0;
+
+	/* macro expand the text */
+	if(macroExpand)
+		text = Cmd_MacroExpandString(text);
+	if(text == nil)
+		return;
+
+	for(;;){
+		while(*text && *text <= ' ' && *text != '\n')
+			text++;
+		
+		/* a newline separates commands in the buffer */
+		if(*text == '\n'){
+			text++;
+			break;
+		}
+
+		if(!*text)
+			return;
+
+		// set cmd_args to everything after the first arg
+		if(cmd_argc == 1){
+			strcpy(cmd_args, text);
+			/* strip off any trailing whitespace */
+			for(l = strlen(cmd_args) - 1; l >= 0 ; l--)
+				if(cmd_args[l] <= ' ')
+					cmd_args[l] = 0;
+				else
+					break;
+		}
+
+		com_token = COM_Parse(&text);
+		if(text == nil)
+			return;
+
+		if(cmd_argc < MAX_STRING_TOKENS){
+			cmd_argv[cmd_argc] = Z_Malloc(strlen(com_token)+1);
+			strcpy(cmd_argv[cmd_argc], com_token);
+			cmd_argc++;
+		}
+	}
+}
+
+/* called by the init functions of other parts of the program to register
+ * commands and functions to call for them. rhe cmd_name is referenced later,
+ * so it should not be in temp memory  if function is nil, the command will be
+ * forwarded to the server as a clc_stringcmd instead of executed locally */
+void
+Cmd_AddCommand(char *name, xcommand_t function)
+{
+	cmd_function_t *p;
+	
+	/* fail if the command is a variable name */
+	if(Cvar_VariableString(name)[0]){
+		Com_Printf("Cmd_AddCommand: %s already defined as a var\n", name);
+		return;
+	}
+
+	/* fail if the command already exists */
+	for(p = cmd_functions; p != nil; p = p->next)
+		if(!strcmp(name, p->name)){
+			Com_Printf("Cmd_AddCommand: %s already defined\n", name);
+			return;
+		}
+
+	p = Z_Malloc(sizeof *p);
+	p->name = name;
+	p->function = function;
+	p->next = cmd_functions;
+	cmd_functions = p;
+}
+
+void
+Cmd_RemoveCommand(char *name)
+{
+	cmd_function_t *p, **back;
+
+	back = &cmd_functions;
+	for(;;){
+		p = *back;
+		if(p == nil){
+			Com_Printf("Cmd_RemoveCommand: %s not added\n", name);
+			return;
+		}
+		if(!strcmp(name, p->name)){
+			*back = p->next;
+			Z_Free(p);
+			return;
+		}
+		back = &p->next;
+	}
+}
+
+/* used by the cvar code to check for cvar / command name overlap */
+qboolean
+Cmd_Exists(char *name)
+{
+	cmd_function_t *p;
+
+	for(p = cmd_functions; p != nil; p = p->next)
+		if(!strcmp(name, p->name))
+			return true;
+	return false;
+}
+
+/* attempts to match a partial command for automatic command line completion */
+char *
+Cmd_CompleteCommand(char *partial)
+{
+	cmd_function_t *p;
+	int len;
+	cmdalias_t *a;
+	
+	len = strlen(partial);
+	if(!len)
+		return nil;
+
+	/* check for exact match */
+	for(p = cmd_functions; p != nil; p = p->next)
+		if(!strcmp(partial, p->name))
+			return p->name;
+	for(a = cmd_alias; a != nil; a = a->next)
+		if(!strcmp(partial, a->name))
+			return a->name;
+
+	/* check for partial match */
+	for(p = cmd_functions; p != nil; p = p->next)
+		if(!strncmp(partial, p->name, len))
+			return p->name;
+	for(a = cmd_alias; a != nil; a = a->next)
+		if(!strncmp(partial, a->name, len))
+			return a->name;
+	return nil;
+}
+
+// FIXME: lookupnoadd the token to speed search?
+/* Parses a single line of text into arguments and tries to execute it as if it
+ * was typed at the console */
+void
+Cmd_ExecuteString(char *text)
+{	
+	cmd_function_t *p;
+	cmdalias_t *a;
+
+	Cmd_TokenizeString(text, true);
+	if(!Cmd_Argc())
+		return;	// no tokens
+
+	/* check functions */
+	for(p = cmd_functions; p != nil; p = p->next)
+		if(!cistrcmp(cmd_argv[0], p->name)){
+			if(!p->function)	// forward to server command
+				Cmd_ExecuteString(va("cmd %s", text));
+			else
+				p->function();
+			return;
+		}
+	/* check alias */
+	for(a = cmd_alias; a != nil; a = a->next)
+		if(!cistrcmp(cmd_argv[0], a->name)){
+			if(++alias_count == ALIAS_LOOP_COUNT){
+				Com_Printf("ALIAS_LOOP_COUNT\n");
+				return;
+			}
+			Cbuf_InsertText(a->value);
+			return;
+		}
+	/* check cvars */
+	if(Cvar_Command())
+		return;
+
+	/* send it as a server command if we are connected */
+	Cmd_ForwardToServer();
+}
+
+void
+Cmd_List_f(void)
+{
+	cmd_function_t *p;
+	int i;
+
+	for(p = cmd_functions, i = 0; p != nil; p = p->next, i++)
+		Com_Printf("%s\n", p->name);
+	Com_Printf("%d commands\n", i);
+}
+
+void
+Cmd_Init(void)
+{
+	Cmd_AddCommand("cmdlist", Cmd_List_f);
+	Cmd_AddCommand("exec", Cmd_Exec_f);
+	Cmd_AddCommand("echo", Cmd_Echo_f);
+	Cmd_AddCommand("alias", Cmd_Alias_f);
+	Cmd_AddCommand("wait", Cmd_Wait_f);
+}
--- /dev/null
+++ b/cmodel.c
@@ -1,0 +1,1750 @@
+// cmodel.c -- model loading
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef struct
+{
+	cplane_t	*plane;
+	int			children[2];		// negative numbers are leafs
+} cnode_t;
+
+typedef struct
+{
+	cplane_t	*plane;
+	mapsurface_t	*surface;
+} cbrushside_t;
+
+typedef struct
+{
+	int			contents;
+	int			cluster;
+	int			area;
+	unsigned short	firstleafbrush;
+	unsigned short	numleafbrushes;
+} cleaf_t;
+
+typedef struct
+{
+	int			contents;
+	int			numsides;
+	int			firstbrushside;
+	int			checkcount;		// to avoid repeated testings
+} cbrush_t;
+
+typedef struct
+{
+	int		numareaportals;
+	int		firstareaportal;
+	int		floodnum;			// if two areas have equal floodnums, they are connected
+	int		floodvalid;
+} carea_t;
+
+int			checkcount;
+
+char		map_name[MAX_QPATH];
+
+int			numbrushsides;
+cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES];
+
+int			numtexinfo;
+mapsurface_t	map_surfaces[MAX_MAP_TEXINFO];
+
+int			numplanes;
+cplane_t	map_planes[MAX_MAP_PLANES+6];		// extra for box hull
+
+int			numnodes;
+cnode_t		map_nodes[MAX_MAP_NODES+6];		// extra for box hull
+
+int			numleafs = 1;	// allow leaf funcs to be called without a map
+cleaf_t		map_leafs[MAX_MAP_LEAFS];
+int			emptyleaf, solidleaf;
+
+int			numleafbrushes;
+unsigned short	map_leafbrushes[MAX_MAP_LEAFBRUSHES];
+
+int			numcmodels;
+cmodel_t	map_cmodels[MAX_MAP_MODELS];
+
+int			numbrushes;
+cbrush_t	map_brushes[MAX_MAP_BRUSHES];
+
+int			numvisibility;
+byte		map_visibility[MAX_MAP_VISIBILITY];
+dvis_t		*map_vis = (dvis_t *)map_visibility;
+
+int			numentitychars;
+char		map_entitystring[MAX_MAP_ENTSTRING];
+
+int			numareas = 1;
+carea_t		map_areas[MAX_MAP_AREAS];
+
+int			numareaportals;
+dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS];
+
+int			numclusters = 1;
+
+mapsurface_t	nullsurface;
+
+int			floodvalid;
+
+qboolean	portalopen[MAX_MAP_AREAPORTALS];
+
+
+cvar_t		*map_noareas;
+
+void	CM_InitBoxHull (void);
+void	FloodAreaConnections (void);
+
+
+int		c_pointcontents;
+int		c_traces, c_brush_traces;
+
+
+/*
+===============================================================================
+
+					MAP LOADING
+
+===============================================================================
+*/
+
+byte	*cmod_base;
+
+/*
+=================
+CMod_LoadSubmodels
+=================
+*/
+void CMod_LoadSubmodels (lump_t *l)
+{
+	dmodel_t	*in;
+	cmodel_t	*out;
+	int			i, j, count;
+
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count < 1)
+		Com_Error (ERR_DROP, "Map with no models");
+	if (count > MAX_MAP_MODELS)
+		Com_Error (ERR_DROP, "Map has too many models");
+
+	numcmodels = count;
+
+	for ( i=0 ; i<count ; i++, in++)
+	{
+		out = &map_cmodels[i];
+
+		for (j=0 ; j<3 ; j++)
+		{	// spread the mins / maxs by a pixel
+			out->mins[j] = LittleFloat (in->mins[j]) - 1;
+			out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
+			out->origin[j] = LittleFloat (in->origin[j]);
+		}
+		out->headnode = LittleLong (in->headnode);
+	}
+}
+
+
+/*
+=================
+CMod_LoadSurfaces
+=================
+*/
+void CMod_LoadSurfaces (lump_t *l)
+{
+	texinfo_t	*in;
+	mapsurface_t	*out;
+	int			i, count;
+
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+	if (count < 1)
+		Com_Error (ERR_DROP, "Map with no surfaces");
+	if (count > MAX_MAP_TEXINFO)
+		Com_Error (ERR_DROP, "Map has too many surfaces");
+
+	numtexinfo = count;
+	out = map_surfaces;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		strncpy (out->c.name, in->texture, sizeof(out->c.name)-1);
+		strncpy (out->rname, in->texture, sizeof(out->rname)-1);
+		out->c.flags = LittleLong (in->flags);
+		out->c.value = LittleLong (in->value);
+	}
+}
+
+
+/*
+=================
+CMod_LoadNodes
+
+=================
+*/
+void CMod_LoadNodes (lump_t *l)
+{
+	dnode_t		*in;
+	int			child;
+	cnode_t		*out;
+	int			i, j, count;
+	
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count < 1)
+		Com_Error (ERR_DROP, "Map has no nodes");
+	if (count > MAX_MAP_NODES)
+		Com_Error (ERR_DROP, "Map has too many nodes");
+
+	out = map_nodes;
+
+	numnodes = count;
+
+	for (i=0 ; i<count ; i++, out++, in++)
+	{
+		out->plane = map_planes + LittleLong(in->planenum);
+		for (j=0 ; j<2 ; j++)
+		{
+			child = LittleLong (in->children[j]);
+			out->children[j] = child;
+		}
+	}
+
+}
+
+/*
+=================
+CMod_LoadBrushes
+
+=================
+*/
+void CMod_LoadBrushes (lump_t *l)
+{
+	dbrush_t	*in;
+	cbrush_t	*out;
+	int			i, count;
+	
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count > MAX_MAP_BRUSHES)
+		Com_Error (ERR_DROP, "Map has too many brushes");
+
+	out = map_brushes;
+
+	numbrushes = count;
+
+	for (i=0 ; i<count ; i++, out++, in++)
+	{
+		out->firstbrushside = LittleLong(in->firstside);
+		out->numsides = LittleLong(in->numsides);
+		out->contents = LittleLong(in->contents);
+	}
+
+}
+
+/*
+=================
+CMod_LoadLeafs
+=================
+*/
+void CMod_LoadLeafs (lump_t *l)
+{
+	int			i;
+	cleaf_t		*out;
+	dleaf_t 	*in;
+	int			count;
+	
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count < 1)
+		Com_Error (ERR_DROP, "Map with no leafs");
+	// need to save space for box planes
+	if (count > MAX_MAP_PLANES)
+		Com_Error (ERR_DROP, "Map has too many planes");
+
+	out = map_leafs;	
+	numleafs = count;
+	numclusters = 0;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		out->contents = LittleLong (in->contents);
+		out->cluster = LittleShort (in->cluster);
+		out->area = LittleShort (in->area);
+		out->firstleafbrush = LittleShort (in->firstleafbrush);
+		out->numleafbrushes = LittleShort (in->numleafbrushes);
+
+		if (out->cluster >= numclusters)
+			numclusters = out->cluster + 1;
+	}
+
+	if (map_leafs[0].contents != CONTENTS_SOLID)
+		Com_Error (ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID");
+	solidleaf = 0;
+	emptyleaf = -1;
+	for (i=1 ; i<numleafs ; i++)
+	{
+		if (!map_leafs[i].contents)
+		{
+			emptyleaf = i;
+			break;
+		}
+	}
+	if (emptyleaf == -1)
+		Com_Error (ERR_DROP, "Map does not have an empty leaf");
+}
+
+/*
+=================
+CMod_LoadPlanes
+=================
+*/
+void CMod_LoadPlanes (lump_t *l)
+{
+	int			i, j;
+	cplane_t	*out;
+	dplane_t 	*in;
+	int			count;
+	int			bits;
+	
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count < 1)
+		Com_Error (ERR_DROP, "Map with no planes");
+	// need to save space for box planes
+	if (count > MAX_MAP_PLANES)
+		Com_Error (ERR_DROP, "Map has too many planes");
+
+	out = map_planes;	
+	numplanes = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		bits = 0;
+		for (j=0 ; j<3 ; j++)
+		{
+			out->normal[j] = LittleFloat (in->normal[j]);
+			if (out->normal[j] < 0)
+				bits |= 1<<j;
+		}
+
+		out->dist = LittleFloat (in->dist);
+		out->type = LittleLong (in->type);
+		out->signbits = bits;
+	}
+}
+
+/*
+=================
+CMod_LoadLeafBrushes
+=================
+*/
+void CMod_LoadLeafBrushes (lump_t *l)
+{
+	int			i;
+	unsigned short	*out;
+	unsigned short 	*in;
+	int			count;
+	
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count < 1)
+		Com_Error (ERR_DROP, "Map with no planes");
+	// need to save space for box planes
+	if (count > MAX_MAP_LEAFBRUSHES)
+		Com_Error (ERR_DROP, "Map has too many leafbrushes");
+
+	out = map_leafbrushes;
+	numleafbrushes = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+		*out = LittleShort (*in);
+}
+
+/*
+=================
+CMod_LoadBrushSides
+=================
+*/
+void CMod_LoadBrushSides (lump_t *l)
+{
+	int			i, j;
+	cbrushside_t	*out;
+	dbrushside_t 	*in;
+	int			count;
+	int			num;
+
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	// need to save space for box planes
+	if (count > MAX_MAP_BRUSHSIDES)
+		Com_Error (ERR_DROP, "Map has too many planes");
+
+	out = map_brushsides;	
+	numbrushsides = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		num = LittleShort (in->planenum);
+		out->plane = &map_planes[num];
+		j = LittleShort (in->texinfo);
+		if (j >= numtexinfo)
+			Com_Error (ERR_DROP, "Bad brushside texinfo");
+		out->surface = &map_surfaces[j];
+	}
+}
+
+/*
+=================
+CMod_LoadAreas
+=================
+*/
+void CMod_LoadAreas (lump_t *l)
+{
+	int			i;
+	carea_t		*out;
+	darea_t 	*in;
+	int			count;
+
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count > MAX_MAP_AREAS)
+		Com_Error (ERR_DROP, "Map has too many areas");
+
+	out = map_areas;
+	numareas = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		out->numareaportals = LittleLong (in->numareaportals);
+		out->firstareaportal = LittleLong (in->firstareaportal);
+		out->floodvalid = 0;
+		out->floodnum = 0;
+	}
+}
+
+/*
+=================
+CMod_LoadAreaPortals
+=================
+*/
+void CMod_LoadAreaPortals (lump_t *l)
+{
+	int			i;
+	dareaportal_t		*out;
+	dareaportal_t 	*in;
+	int			count;
+
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count > MAX_MAP_AREAS)
+		Com_Error (ERR_DROP, "Map has too many areas");
+
+	out = map_areaportals;
+	numareaportals = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		out->portalnum = LittleLong (in->portalnum);
+		out->otherarea = LittleLong (in->otherarea);
+	}
+}
+
+/*
+=================
+CMod_LoadVisibility
+=================
+*/
+void CMod_LoadVisibility (lump_t *l)
+{
+	int		i;
+
+	numvisibility = l->filelen;
+	if (l->filelen > MAX_MAP_VISIBILITY)
+		Com_Error (ERR_DROP, "Map has too large visibility lump");
+
+	memcpy (map_visibility, cmod_base + l->fileofs, l->filelen);
+
+	map_vis->numclusters = LittleLong (map_vis->numclusters);
+	for (i=0 ; i<map_vis->numclusters ; i++)
+	{
+		map_vis->bitofs[i][0] = LittleLong (map_vis->bitofs[i][0]);
+		map_vis->bitofs[i][1] = LittleLong (map_vis->bitofs[i][1]);
+	}
+}
+
+
+/*
+=================
+CMod_LoadEntityString
+=================
+*/
+void CMod_LoadEntityString (lump_t *l)
+{
+	numentitychars = l->filelen;
+	if (l->filelen > MAX_MAP_ENTSTRING)
+		Com_Error (ERR_DROP, "Map has too large entity lump");
+
+	memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen);
+}
+
+
+
+/*
+==================
+CM_LoadMap
+
+Loads in the map and all submodels
+==================
+*/
+cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum)
+{
+	unsigned		*buf;
+	int				i;
+	dheader_t		header;
+	int				length;
+	static unsigned	last_checksum;
+
+	map_noareas = Cvar_Get ("map_noareas", "0", 0);
+
+	if (  !strcmp (map_name, name) && (clientload || !Cvar_VariableValue ("flushmap")) )
+	{
+		*checksum = last_checksum;
+		if (!clientload)
+		{
+			memset (portalopen, 0, sizeof(portalopen));
+			FloodAreaConnections ();
+		}
+		return &map_cmodels[0];		// still have the right version
+	}
+
+	// free old stuff
+	numplanes = 0;
+	numnodes = 0;
+	numleafs = 0;
+	numcmodels = 0;
+	numvisibility = 0;
+	numentitychars = 0;
+	map_entitystring[0] = 0;
+	map_name[0] = 0;
+
+	if (!name || !name[0])
+	{
+		numleafs = 1;
+		numclusters = 1;
+		numareas = 1;
+		*checksum = 0;
+		return &map_cmodels[0];			// cinematic servers won't have anything at all
+	}
+
+	//
+	// load the file
+	//
+	length = FS_LoadFile (name, (void **)&buf);
+	if (!buf)
+		Com_Error (ERR_DROP, "Couldn't load %s", name);
+
+	last_checksum = LittleLong (Com_BlockChecksum (buf, length));
+	*checksum = last_checksum;
+
+	header = *(dheader_t *)buf;
+	for (i=0 ; i<sizeof(dheader_t)/sizeof(int) ; i++)
+		((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
+
+	if (header.version != BSPVERSION)
+		Com_Error (ERR_DROP, "CMod_LoadBrushModel: %s has wrong version number (%i should be %i)"
+		, name, header.version, BSPVERSION);
+
+	cmod_base = (byte *)buf;
+
+	// load into heap
+	CMod_LoadSurfaces (&header.lumps[LUMP_TEXINFO]);
+	CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);
+	CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);
+	CMod_LoadPlanes (&header.lumps[LUMP_PLANES]);
+	CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);
+	CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);
+	CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);
+	CMod_LoadNodes (&header.lumps[LUMP_NODES]);
+	CMod_LoadAreas (&header.lumps[LUMP_AREAS]);
+	CMod_LoadAreaPortals (&header.lumps[LUMP_AREAPORTALS]);
+	CMod_LoadVisibility (&header.lumps[LUMP_VISIBILITY]);
+	CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);
+
+	FS_FreeFile (buf);
+
+	CM_InitBoxHull ();
+
+	memset (portalopen, 0, sizeof(portalopen));
+	FloodAreaConnections ();
+
+	strcpy (map_name, name);
+
+	return &map_cmodels[0];
+}
+
+/*
+==================
+CM_InlineModel
+==================
+*/
+cmodel_t	*CM_InlineModel (char *name)
+{
+	int		num;
+
+	if (!name || name[0] != '*')
+		Com_Error (ERR_DROP, "CM_InlineModel: bad name");
+	num = atoi (name+1);
+	if (num < 1 || num >= numcmodels)
+		Com_Error (ERR_DROP, "CM_InlineModel: bad number");
+
+	return &map_cmodels[num];
+}
+
+int		CM_NumClusters (void)
+{
+	return numclusters;
+}
+
+int		CM_NumInlineModels (void)
+{
+	return numcmodels;
+}
+
+char	*CM_EntityString (void)
+{
+	return map_entitystring;
+}
+
+int		CM_LeafContents (int leafnum)
+{
+	if (leafnum < 0 || leafnum >= numleafs)
+		Com_Error (ERR_DROP, "CM_LeafContents: bad number");
+	return map_leafs[leafnum].contents;
+}
+
+int		CM_LeafCluster (int leafnum)
+{
+	if (leafnum < 0 || leafnum >= numleafs)
+		Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
+	return map_leafs[leafnum].cluster;
+}
+
+int		CM_LeafArea (int leafnum)
+{
+	if (leafnum < 0 || leafnum >= numleafs)
+		Com_Error (ERR_DROP, "CM_LeafArea: bad number");
+	return map_leafs[leafnum].area;
+}
+
+//=======================================================================
+
+
+cplane_t	*box_planes;
+int			box_headnode;
+cbrush_t	*box_brush;
+cleaf_t		*box_leaf;
+
+/*
+===================
+CM_InitBoxHull
+
+Set up the planes and nodes so that the six floats of a bounding box
+can just be stored out and get a proper clipping hull structure.
+===================
+*/
+void CM_InitBoxHull (void)
+{
+	int			i;
+	int			side;
+	cnode_t		*c;
+	cplane_t	*p;
+	cbrushside_t	*s;
+
+	box_headnode = numnodes;
+	box_planes = &map_planes[numplanes];
+	if (numnodes+6 > MAX_MAP_NODES
+		|| numbrushes+1 > MAX_MAP_BRUSHES
+		|| numleafbrushes+1 > MAX_MAP_LEAFBRUSHES
+		|| numbrushsides+6 > MAX_MAP_BRUSHSIDES
+		|| numplanes+12 > MAX_MAP_PLANES)
+		Com_Error (ERR_DROP, "Not enough room for box tree");
+
+	box_brush = &map_brushes[numbrushes];
+	box_brush->numsides = 6;
+	box_brush->firstbrushside = numbrushsides;
+	box_brush->contents = CONTENTS_MONSTER;
+
+	box_leaf = &map_leafs[numleafs];
+	box_leaf->contents = CONTENTS_MONSTER;
+	box_leaf->firstleafbrush = numleafbrushes;
+	box_leaf->numleafbrushes = 1;
+
+	map_leafbrushes[numleafbrushes] = numbrushes;
+
+	for (i=0 ; i<6 ; i++)
+	{
+		side = i&1;
+
+		// brush sides
+		s = &map_brushsides[numbrushsides+i];
+		s->plane = 	map_planes + (numplanes+i*2+side);
+		s->surface = &nullsurface;
+
+		// nodes
+		c = &map_nodes[box_headnode+i];
+		c->plane = map_planes + (numplanes+i*2);
+		c->children[side] = -1 - emptyleaf;
+		if (i != 5)
+			c->children[side^1] = box_headnode+i + 1;
+		else
+			c->children[side^1] = -1 - numleafs;
+
+		// planes
+		p = &box_planes[i*2];
+		p->type = i>>1;
+		p->signbits = 0;
+		VectorClear (p->normal);
+		p->normal[i>>1] = 1;
+
+		p = &box_planes[i*2+1];
+		p->type = 3 + (i>>1);
+		p->signbits = 0;
+		VectorClear (p->normal);
+		p->normal[i>>1] = -1;
+	}	
+}
+
+
+/*
+===================
+CM_HeadnodeForBox
+
+Creates a clipping hull for an arbitrary box
+
+To keep everything totally uniform, bounding boxes are turned into small
+BSP trees instead of being compared directly.
+===================
+*/
+int	CM_HeadnodeForBox (vec3_t mins, vec3_t maxs)
+{
+	box_planes[0].dist = maxs[0];
+	box_planes[1].dist = -maxs[0];
+	box_planes[2].dist = mins[0];
+	box_planes[3].dist = -mins[0];
+	box_planes[4].dist = maxs[1];
+	box_planes[5].dist = -maxs[1];
+	box_planes[6].dist = mins[1];
+	box_planes[7].dist = -mins[1];
+	box_planes[8].dist = maxs[2];
+	box_planes[9].dist = -maxs[2];
+	box_planes[10].dist = mins[2];
+	box_planes[11].dist = -mins[2];
+
+	return box_headnode;
+}
+
+
+/*
+==================
+CM_PointLeafnum_r
+
+==================
+*/
+int CM_PointLeafnum_r (vec3_t p, int num)
+{
+	float		d;
+	cnode_t		*node;
+	cplane_t	*plane;
+
+	while (num >= 0)
+	{
+		node = map_nodes + num;
+		plane = node->plane;
+		
+		if (plane->type < 3)
+			d = p[plane->type] - plane->dist;
+		else
+			d = DotProduct (plane->normal, p) - plane->dist;
+		if (d < 0)
+			num = node->children[1];
+		else
+			num = node->children[0];
+	}
+
+	c_pointcontents++;		// optimize counter
+
+	return -1 - num;
+}
+
+/* call with topnode set to the headnode, returns with topnode set to the first
+ * node that splits the box */
+int CM_PointLeafnum (vec3_t p)
+{
+	if (!numplanes)
+		return 0;		// sound may call this without map loaded
+	return CM_PointLeafnum_r (p, 0);
+}
+
+
+
+/*
+=============
+CM_BoxLeafnums
+
+Fills in a list of all the leafs touched
+=============
+*/
+int		leaf_count, leaf_maxcount;
+int		*leaf_list;
+float	*leaf_mins, *leaf_maxs;
+int		leaf_topnode;
+
+void CM_BoxLeafnums_r (int nodenum)
+{
+	cplane_t	*plane;
+	cnode_t		*node;
+	int		s;
+
+	while (1)
+	{
+		if (nodenum < 0)
+		{
+			if (leaf_count >= leaf_maxcount)
+			{
+//				Com_Printf ("CM_BoxLeafnums_r: overflow\n");
+				return;
+			}
+			leaf_list[leaf_count++] = -1 - nodenum;
+			return;
+		}
+	
+		node = &map_nodes[nodenum];
+		plane = node->plane;
+//		s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane);
+		s = BOX_ON_PLANE_SIDE(leaf_mins, leaf_maxs, plane);
+		if (s == 1)
+			nodenum = node->children[0];
+		else if (s == 2)
+			nodenum = node->children[1];
+		else
+		{	// go down both
+			if (leaf_topnode == -1)
+				leaf_topnode = nodenum;
+			CM_BoxLeafnums_r (node->children[0]);
+			nodenum = node->children[1];
+		}
+
+	}
+}
+
+int	CM_BoxLeafnums_headnode (vec3_t mins, vec3_t maxs, int *list, int listsize, int headnode, int *topnode)
+{
+	leaf_list = list;
+	leaf_count = 0;
+	leaf_maxcount = listsize;
+	leaf_mins = mins;
+	leaf_maxs = maxs;
+
+	leaf_topnode = -1;
+
+	CM_BoxLeafnums_r (headnode);
+
+	if (topnode)
+		*topnode = leaf_topnode;
+
+	return leaf_count;
+}
+
+int	CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode)
+{
+	return CM_BoxLeafnums_headnode (mins, maxs, list,
+		listsize, map_cmodels[0].headnode, topnode);
+}
+
+
+
+/*
+==================
+CM_PointContents
+
+==================
+*/
+int CM_PointContents (vec3_t p, int headnode)
+{
+	int		l;
+
+	if (!numnodes)	// map not loaded
+		return 0;
+
+	l = CM_PointLeafnum_r (p, headnode);
+
+	return map_leafs[l].contents;
+}
+
+/*
+==================
+CM_TransformedPointContents
+
+Handles offseting and rotation of the end points for moving and
+rotating entities
+==================
+*/
+int	CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles)
+{
+	vec3_t		p_l;
+	vec3_t		temp;
+	vec3_t		forward, right, up;
+	int			l;
+
+	// subtract origin offset
+	VectorSubtract (p, origin, p_l);
+
+	// rotate start and end into the models frame of reference
+	if (headnode != box_headnode && 
+	(angles[0] || angles[1] || angles[2]) )
+	{
+		AngleVectors (angles, forward, right, up);
+
+		VectorCopy (p_l, temp);
+		p_l[0] = DotProduct (temp, forward);
+		p_l[1] = -DotProduct (temp, right);
+		p_l[2] = DotProduct (temp, up);
+	}
+
+	l = CM_PointLeafnum_r (p_l, headnode);
+
+	return map_leafs[l].contents;
+}
+
+
+/*
+===============================================================================
+
+BOX TRACING
+
+===============================================================================
+*/
+
+// 1/32 epsilon to keep floating point happy
+#define	DIST_EPSILON	(0.03125)
+
+vec3_t	trace_start, trace_end;
+vec3_t	trace_mins, trace_maxs;
+vec3_t	trace_extents;
+
+trace_t	trace_trace;
+int		trace_contents;
+qboolean	trace_ispoint;		// optimized case
+
+/*
+================
+CM_ClipBoxToBrush
+================
+*/
+void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
+					  trace_t *trace, cbrush_t *brush)
+{
+	int			i, j;
+	cplane_t	*plane, *clipplane;
+	float		dist;
+	float		enterfrac, leavefrac;
+	vec3_t		ofs;
+	float		d1, d2;
+	qboolean	getout, startout;
+	float		f;
+	cbrushside_t	*side, *leadside;
+
+	enterfrac = -1;
+	leavefrac = 1;
+	clipplane = NULL;
+
+	if (!brush->numsides)
+		return;
+
+	c_brush_traces++;
+
+	getout = false;
+	startout = false;
+	leadside = NULL;
+
+	for (i=0 ; i<brush->numsides ; i++)
+	{
+		side = &map_brushsides[brush->firstbrushside+i];
+		plane = side->plane;
+
+		// FIXME: special case for axial
+
+		if (!trace_ispoint)
+		{	// general box case
+
+			// push the plane out apropriately for mins/maxs
+
+			// FIXME: use signbits into 8 way lookup for each mins/maxs
+			for (j=0 ; j<3 ; j++)
+			{
+				if (plane->normal[j] < 0)
+					ofs[j] = maxs[j];
+				else
+					ofs[j] = mins[j];
+			}
+			dist = DotProduct (ofs, plane->normal);
+			dist = plane->dist - dist;
+		}
+		else
+		{	// special point case
+			dist = plane->dist;
+		}
+
+		d1 = DotProduct (p1, plane->normal) - dist;
+		d2 = DotProduct (p2, plane->normal) - dist;
+
+		if (d2 > 0)
+			getout = true;	// endpoint is not in solid
+		if (d1 > 0)
+			startout = true;
+
+		// if completely in front of face, no intersection
+		if (d1 > 0 && d2 >= d1)
+			return;
+
+		if (d1 <= 0 && d2 <= 0)
+			continue;
+
+		// crosses face
+		if (d1 > d2)
+		{	// enter
+			f = (d1-DIST_EPSILON) / (d1-d2);
+			if (f > enterfrac)
+			{
+				enterfrac = f;
+				clipplane = plane;
+				leadside = side;
+			}
+		}
+		else
+		{	// leave
+			f = (d1+DIST_EPSILON) / (d1-d2);
+			if (f < leavefrac)
+				leavefrac = f;
+		}
+	}
+
+	if (!startout)
+	{	// original point was inside brush
+		trace->startsolid = true;
+		if (!getout)
+			trace->allsolid = true;
+		return;
+	}
+	if (enterfrac < leavefrac)
+	{
+		if (enterfrac > -1 && enterfrac < trace->fraction)
+		{
+			if (enterfrac < 0)
+				enterfrac = 0;
+			trace->fraction = enterfrac;
+			trace->plane = *clipplane;
+			trace->surface = &(leadside->surface->c);
+			trace->contents = brush->contents;
+		}
+	}
+}
+
+/*
+================
+CM_TestBoxInBrush
+================
+*/
+void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1,
+					  trace_t *trace, cbrush_t *brush)
+{
+	int			i, j;
+	cplane_t	*plane;
+	float		dist;
+	vec3_t		ofs;
+	float		d1;
+	cbrushside_t	*side;
+
+	if (!brush->numsides)
+		return;
+
+	for (i=0 ; i<brush->numsides ; i++)
+	{
+		side = &map_brushsides[brush->firstbrushside+i];
+		plane = side->plane;
+
+		// FIXME: special case for axial
+
+		// general box case
+
+		// push the plane out apropriately for mins/maxs
+
+		// FIXME: use signbits into 8 way lookup for each mins/maxs
+		for (j=0 ; j<3 ; j++)
+		{
+			if (plane->normal[j] < 0)
+				ofs[j] = maxs[j];
+			else
+				ofs[j] = mins[j];
+		}
+		dist = DotProduct (ofs, plane->normal);
+		dist = plane->dist - dist;
+
+		d1 = DotProduct (p1, plane->normal) - dist;
+
+		// if completely in front of face, no intersection
+		if (d1 > 0)
+			return;
+
+	}
+
+	// inside this brush
+	trace->startsolid = trace->allsolid = true;
+	trace->fraction = 0;
+	trace->contents = brush->contents;
+}
+
+
+/*
+================
+CM_TraceToLeaf
+================
+*/
+void CM_TraceToLeaf (int leafnum)
+{
+	int			k;
+	int			brushnum;
+	cleaf_t		*leaf;
+	cbrush_t	*b;
+
+	leaf = &map_leafs[leafnum];
+	if ( !(leaf->contents & trace_contents))
+		return;
+	// trace line against all brushes in the leaf
+	for (k=0 ; k<leaf->numleafbrushes ; k++)
+	{
+		brushnum = map_leafbrushes[leaf->firstleafbrush+k];
+		b = &map_brushes[brushnum];
+		if (b->checkcount == checkcount)
+			continue;	// already checked this brush in another leaf
+		b->checkcount = checkcount;
+
+		if ( !(b->contents & trace_contents))
+			continue;
+		CM_ClipBoxToBrush (trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, b);
+		if (!trace_trace.fraction)
+			return;
+	}
+
+}
+
+
+/*
+================
+CM_TestInLeaf
+================
+*/
+void CM_TestInLeaf (int leafnum)
+{
+	int			k;
+	int			brushnum;
+	cleaf_t		*leaf;
+	cbrush_t	*b;
+
+	leaf = &map_leafs[leafnum];
+	if ( !(leaf->contents & trace_contents))
+		return;
+	// trace line against all brushes in the leaf
+	for (k=0 ; k<leaf->numleafbrushes ; k++)
+	{
+		brushnum = map_leafbrushes[leaf->firstleafbrush+k];
+		b = &map_brushes[brushnum];
+		if (b->checkcount == checkcount)
+			continue;	// already checked this brush in another leaf
+		b->checkcount = checkcount;
+
+		if ( !(b->contents & trace_contents))
+			continue;
+		CM_TestBoxInBrush (trace_mins, trace_maxs, trace_start, &trace_trace, b);
+		if (!trace_trace.fraction)
+			return;
+	}
+
+}
+
+
+/*
+==================
+CM_RecursiveHullCheck
+
+==================
+*/
+void CM_RecursiveHullCheck (int num, float p1f, float p2f, vec3_t p1, vec3_t p2)
+{
+	cnode_t		*node;
+	cplane_t	*plane;
+	float		t1, t2, offset;
+	float		frac, frac2;
+	float		idist;
+	int			i;
+	vec3_t		mid;
+	int			side;
+	float		midf;
+
+	if (trace_trace.fraction <= p1f)
+		return;		// already hit something nearer
+
+	// if < 0, we are in a leaf node
+	if (num < 0)
+	{
+		CM_TraceToLeaf (-1-num);
+		return;
+	}
+
+	//
+	// find the point distances to the seperating plane
+	// and the offset for the size of the box
+	//
+	node = map_nodes + num;
+	plane = node->plane;
+
+	if (plane->type < 3)
+	{
+		t1 = p1[plane->type] - plane->dist;
+		t2 = p2[plane->type] - plane->dist;
+		offset = trace_extents[plane->type];
+	}
+	else
+	{
+		t1 = DotProduct (plane->normal, p1) - plane->dist;
+		t2 = DotProduct (plane->normal, p2) - plane->dist;
+		if (trace_ispoint)
+			offset = 0;
+		else
+			offset = fabs(trace_extents[0]*plane->normal[0]) +
+				fabs(trace_extents[1]*plane->normal[1]) +
+				fabs(trace_extents[2]*plane->normal[2]);
+	}
+
+
+	/*
+	CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
+	CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
+	return;
+	*/
+
+	// see which sides we need to consider
+	if (t1 >= offset && t2 >= offset)
+	{
+		CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
+		return;
+	}
+	if (t1 < -offset && t2 < -offset)
+	{
+		CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
+		return;
+	}
+
+	// put the crosspoint DIST_EPSILON pixels on the near side
+	if (t1 < t2)
+	{
+		idist = 1.0/(t1-t2);
+		side = 1;
+		frac2 = (t1 + offset + DIST_EPSILON)*idist;
+		frac = (t1 - offset + DIST_EPSILON)*idist;
+	}
+	else if (t1 > t2)
+	{
+		idist = 1.0/(t1-t2);
+		side = 0;
+		frac2 = (t1 - offset - DIST_EPSILON)*idist;
+		frac = (t1 + offset + DIST_EPSILON)*idist;
+	}
+	else
+	{
+		side = 0;
+		frac = 1;
+		frac2 = 0;
+	}
+
+	// move up to the node
+	if (frac < 0)
+		frac = 0;
+	if (frac > 1)
+		frac = 1;
+		
+	midf = p1f + (p2f - p1f)*frac;
+	for (i=0 ; i<3 ; i++)
+		mid[i] = p1[i] + frac*(p2[i] - p1[i]);
+
+	CM_RecursiveHullCheck (node->children[side], p1f, midf, p1, mid);
+
+
+	// go past the node
+	if (frac2 < 0)
+		frac2 = 0;
+	if (frac2 > 1)
+		frac2 = 1;
+		
+	midf = p1f + (p2f - p1f)*frac2;
+	for (i=0 ; i<3 ; i++)
+		mid[i] = p1[i] + frac2*(p2[i] - p1[i]);
+
+	CM_RecursiveHullCheck (node->children[side^1], midf, p2f, mid, p2);
+}
+
+
+
+//======================================================================
+
+/*
+==================
+CM_BoxTrace
+==================
+*/
+trace_t		CM_BoxTrace (vec3_t start, vec3_t end,
+						  vec3_t mins, vec3_t maxs,
+						  int headnode, int brushmask)
+{
+	int		i;
+
+	checkcount++;		// for multi-check avoidance
+
+	c_traces++;			// for statistics, may be zeroed
+
+	// fill in a default trace
+	memset (&trace_trace, 0, sizeof(trace_trace));
+	trace_trace.fraction = 1;
+	trace_trace.surface = &(nullsurface.c);
+
+	if (!numnodes)	// map not loaded
+		return trace_trace;
+
+	trace_contents = brushmask;
+	VectorCopy (start, trace_start);
+	VectorCopy (end, trace_end);
+	VectorCopy (mins, trace_mins);
+	VectorCopy (maxs, trace_maxs);
+
+	//
+	// check for position test special case
+	//
+	if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2])
+	{
+		int		leafs[1024];
+		int		i, numleafs;
+		vec3_t	c1, c2;
+		int		topnode;
+
+		VectorAdd (start, mins, c1);
+		VectorAdd (start, maxs, c2);
+		for (i=0 ; i<3 ; i++)
+		{
+			c1[i] -= 1;
+			c2[i] += 1;
+		}
+
+		numleafs = CM_BoxLeafnums_headnode (c1, c2, leafs, 1024, headnode, &topnode);
+		for (i=0 ; i<numleafs ; i++)
+		{
+			CM_TestInLeaf (leafs[i]);
+			if (trace_trace.allsolid)
+				break;
+		}
+		VectorCopy (start, trace_trace.endpos);
+		return trace_trace;
+	}
+
+	//
+	// check for point special case
+	//
+	if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0
+		&& maxs[0] == 0 && maxs[1] == 0 && maxs[2] == 0)
+	{
+		trace_ispoint = true;
+		VectorClear (trace_extents);
+	}
+	else
+	{
+		trace_ispoint = false;
+		trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0];
+		trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1];
+		trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2];
+	}
+
+	//
+	// general sweeping through world
+	//
+	CM_RecursiveHullCheck (headnode, 0, 1, start, end);
+
+	if (trace_trace.fraction == 1)
+	{
+		VectorCopy (end, trace_trace.endpos);
+	}
+	else
+	{
+		for (i=0 ; i<3 ; i++)
+			trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]);
+	}
+	return trace_trace;
+}
+
+
+/*
+==================
+CM_TransformedBoxTrace
+
+Handles offseting and rotation of the end points for moving and
+rotating entities
+==================
+*/
+
+
+trace_t		CM_TransformedBoxTrace (vec3_t start, vec3_t end,
+						  vec3_t mins, vec3_t maxs,
+						  int headnode, int brushmask,
+						  vec3_t origin, vec3_t angles)
+{
+	trace_t		trace;
+	vec3_t		start_l, end_l;
+	vec3_t		a;
+	vec3_t		forward, right, up;
+	vec3_t		temp;
+	qboolean	rotated;
+
+	// subtract origin offset
+	VectorSubtract (start, origin, start_l);
+	VectorSubtract (end, origin, end_l);
+
+	// rotate start and end into the models frame of reference
+	if (headnode != box_headnode && 
+	(angles[0] || angles[1] || angles[2]) )
+		rotated = true;
+	else
+		rotated = false;
+
+	if (rotated)
+	{
+		AngleVectors (angles, forward, right, up);
+
+		VectorCopy (start_l, temp);
+		start_l[0] = DotProduct (temp, forward);
+		start_l[1] = -DotProduct (temp, right);
+		start_l[2] = DotProduct (temp, up);
+
+		VectorCopy (end_l, temp);
+		end_l[0] = DotProduct (temp, forward);
+		end_l[1] = -DotProduct (temp, right);
+		end_l[2] = DotProduct (temp, up);
+	}
+
+	// sweep the box through the model
+	trace = CM_BoxTrace (start_l, end_l, mins, maxs, headnode, brushmask);
+
+	if (rotated && trace.fraction != 1.0)
+	{
+		// FIXME: figure out how to do this with existing angles
+		VectorNegate (angles, a);
+		AngleVectors (a, forward, right, up);
+
+		VectorCopy (trace.plane.normal, temp);
+		trace.plane.normal[0] = DotProduct (temp, forward);
+		trace.plane.normal[1] = -DotProduct (temp, right);
+		trace.plane.normal[2] = DotProduct (temp, up);
+	}
+
+	trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
+	trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
+	trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
+
+	return trace;
+}
+
+/*
+===============================================================================
+
+PVS / PHS
+
+===============================================================================
+*/
+
+/*
+===================
+CM_DecompressVis
+===================
+*/
+void CM_DecompressVis (byte *in, byte *out)
+{
+	int		c;
+	byte	*out_p;
+	int		row;
+
+	row = (numclusters+7)>>3;	
+	out_p = out;
+
+	if (!in || !numvisibility)
+	{	// no vis info, so make all visible
+		while (row)
+		{
+			*out_p++ = 0xff;
+			row--;
+		}
+		return;		
+	}
+
+	do
+	{
+		if (*in)
+		{
+			*out_p++ = *in++;
+			continue;
+		}
+	
+		c = in[1];
+		in += 2;
+		if ((out_p - out) + c > row)
+		{
+			c = row - (out_p - out);
+			Com_DPrintf ("warning: Vis decompression overrun\n");
+		}
+		while (c)
+		{
+			*out_p++ = 0;
+			c--;
+		}
+	} while (out_p - out < row);
+}
+
+byte	pvsrow[MAX_MAP_LEAFS/8];
+byte	phsrow[MAX_MAP_LEAFS/8];
+
+byte	*CM_ClusterPVS (int cluster)
+{
+	if (cluster == -1)
+		memset (pvsrow, 0, (numclusters+7)>>3);
+	else
+		CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PVS], pvsrow);
+	return pvsrow;
+}
+
+byte	*CM_ClusterPHS (int cluster)
+{
+	if (cluster == -1)
+		memset (phsrow, 0, (numclusters+7)>>3);
+	else
+		CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PHS], phsrow);
+	return phsrow;
+}
+
+
+/*
+===============================================================================
+
+AREAPORTALS
+
+===============================================================================
+*/
+
+void FloodArea_r (carea_t *area, int floodnum)
+{
+	int		i;
+	dareaportal_t	*p;
+
+	if (area->floodvalid == floodvalid)
+	{
+		if (area->floodnum == floodnum)
+			return;
+		Com_Error (ERR_DROP, "FloodArea_r: reflooded");
+	}
+
+	area->floodnum = floodnum;
+	area->floodvalid = floodvalid;
+	p = &map_areaportals[area->firstareaportal];
+	for (i=0 ; i<area->numareaportals ; i++, p++)
+	{
+		if (portalopen[p->portalnum])
+			FloodArea_r (&map_areas[p->otherarea], floodnum);
+	}
+}
+
+/*
+====================
+FloodAreaConnections
+
+
+====================
+*/
+void	FloodAreaConnections (void)
+{
+	int		i;
+	carea_t	*area;
+	int		floodnum;
+
+	// all current floods are now invalid
+	floodvalid++;
+	floodnum = 0;
+
+	// area 0 is not used
+	for (i=1 ; i<numareas ; i++)
+	{
+		area = &map_areas[i];
+		if (area->floodvalid == floodvalid)
+			continue;		// already flooded into
+		floodnum++;
+		FloodArea_r (area, floodnum);
+	}
+
+}
+
+void	CM_SetAreaPortalState (int portalnum, qboolean open)
+{
+	if (portalnum > numareaportals)
+		Com_Error (ERR_DROP, "areaportal > numareaportals");
+
+	portalopen[portalnum] = open;
+	FloodAreaConnections ();
+}
+
+qboolean	CM_AreasConnected (int area1, int area2)
+{
+	if (map_noareas->value)
+		return true;
+
+	if (area1 > numareas || area2 > numareas)
+		Com_Error (ERR_DROP, "area > numareas");
+
+	if (map_areas[area1].floodnum == map_areas[area2].floodnum)
+		return true;
+	return false;
+}
+
+
+/*
+=================
+CM_WriteAreaBits
+
+Writes a length byte followed by a bit vector of all the areas
+that area in the same flood as the area parameter
+
+This is used by the client refreshes to cull visibility
+=================
+*/
+int CM_WriteAreaBits (byte *buffer, int area)
+{
+	int		i;
+	int		floodnum;
+	int		bytes;
+
+	bytes = (numareas+7)>>3;
+
+	if (map_noareas->value)
+	{	// for debugging, send everything
+		memset (buffer, 255, bytes);
+	}
+	else
+	{
+		memset (buffer, 0, bytes);
+
+		floodnum = map_areas[area].floodnum;
+		for (i=0 ; i<numareas ; i++)
+		{
+			if (map_areas[i].floodnum == floodnum || !area)
+				buffer[i>>3] |= 1<<(i&7);
+		}
+	}
+
+	return bytes;
+}
+
+
+/*
+===================
+CM_WritePortalState
+
+Writes the portal state to a savegame file
+===================
+*/
+void	CM_WritePortalState (FILE *f)
+{
+	fwrite (portalopen, sizeof(portalopen), 1, f);
+}
+
+/*
+===================
+CM_ReadPortalState
+
+Reads the portal state from a savegame file
+and recalculates the area connections
+===================
+*/
+void	CM_ReadPortalState (FILE *f)
+{
+	FS_Read (portalopen, sizeof(portalopen), f);
+	FloodAreaConnections ();
+}
+
+/*
+=============
+CM_HeadnodeVisible
+
+Returns true if any leaf under headnode has a cluster that
+is potentially visible
+=============
+*/
+qboolean CM_HeadnodeVisible (int nodenum, byte *visbits)
+{
+	int		leafnum;
+	int		cluster;
+	cnode_t	*node;
+
+	if (nodenum < 0)
+	{
+		leafnum = -1-nodenum;
+		cluster = map_leafs[leafnum].cluster;
+		if (cluster == -1)
+			return false;
+		if (visbits[cluster>>3] & (1<<(cluster&7)))
+			return true;
+		return false;
+	}
+
+	node = &map_nodes[nodenum];
+	if (CM_HeadnodeVisible(node->children[0], visbits))
+		return true;
+	return CM_HeadnodeVisible(node->children[1], visbits);
+}
+
--- /dev/null
+++ b/common.c
@@ -1,0 +1,1570 @@
+// common.c -- misc functions used in client and server
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+#define	MAXPRINTMSG	4096
+
+#define MAX_NUM_ARGVS	50
+
+
+int		com_argc;
+char	*com_argv[MAX_NUM_ARGVS+1];
+
+int		realtime;
+
+jmp_buf abortframe;		// an ERR_DROP occured, exit the entire frame
+
+
+FILE	*log_stats_file;
+
+cvar_t	*host_speeds;
+cvar_t	*log_stats;
+cvar_t	*developer;
+cvar_t	*timescale;
+cvar_t	*fixedtime;
+cvar_t	*logfile_active;	// 1 = buffer log, 2 = flush after each print
+cvar_t	*showtrace;
+cvar_t	*dedicated;
+
+FILE	*logfile;
+
+int			server_state;
+
+// host_speeds times
+int		time_before_game;
+int		time_after_game;
+int		time_before_ref;
+int		time_after_ref;
+
+
+
+/*
+============================================================================
+
+CLIENT / SERVER interactions
+
+============================================================================
+*/
+
+static int	rd_target;
+static char	*rd_buffer;
+static int	rd_buffersize;
+static void	(*rd_flush)(int target, char *buffer);
+
+void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush))
+{
+	if (!target || !buffer || !buffersize || !flush)
+		return;
+	rd_target = target;
+	rd_buffer = buffer;
+	rd_buffersize = buffersize;
+	rd_flush = flush;
+
+	*rd_buffer = 0;
+}
+
+void Com_EndRedirect (void)
+{
+	rd_flush(rd_target, rd_buffer);
+
+	rd_target = 0;
+	rd_buffer = NULL;
+	rd_buffersize = 0;
+	rd_flush = NULL;
+}
+
+/*
+=============
+Com_Printf
+
+Both client and server can use this, and it will output
+to the apropriate place.
+=============
+*/
+void Com_Printf (char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[MAXPRINTMSG];
+
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+
+	if (rd_target)
+	{
+		if ((strlen (msg) + strlen(rd_buffer)) > (rd_buffersize - 1))
+		{
+			rd_flush(rd_target, rd_buffer);
+			*rd_buffer = 0;
+		}
+		strcat (rd_buffer, msg);
+		return;
+	}
+
+	Con_Print (msg);
+		
+	// also echo to debugging console
+	Sys_ConsoleOutput (msg);
+
+	// logfile
+	if (logfile_active && logfile_active->value)
+	{
+		char	name[MAX_QPATH];
+		
+		if (!logfile)
+		{
+			Com_sprintf (name, sizeof(name), "%s/qconsole.log", FS_Gamedir ());
+			logfile = fopen (name, "w");
+		}
+		if (logfile)
+			fprintf (logfile, "%s", msg);
+		if (logfile_active->value > 1)
+			fflush (logfile);		// force it to save every time
+	}
+}
+
+
+/*
+================
+Com_DPrintf
+
+A Com_Printf that only shows up if the "developer" cvar is set
+================
+*/
+void Com_DPrintf (char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[MAXPRINTMSG];
+		
+	if (!developer || !developer->value)
+		return;			// don't confuse non-developers with techie stuff...
+
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+	
+	Com_Printf ("%s", msg);
+}
+
+
+/*
+=============
+Com_Error
+
+Both client and server can use this, and it will
+do the apropriate things.
+=============
+*/
+void Com_Error (int code, char *fmt, ...)
+{
+	va_list		argptr;
+	static char		msg[MAXPRINTMSG];
+	static	qboolean	recursive;
+
+	if (recursive)
+		Sys_Error ("recursive error after: %s", msg);
+	recursive = true;
+
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+	
+	if (code == ERR_DISCONNECT)
+	{
+		CL_Drop ();
+		recursive = false;
+		longjmp (abortframe, -1);
+	}
+	else if (code == ERR_DROP)
+	{
+		Com_Printf ("********************\nERROR: %s\n********************\n", msg);
+		SV_Shutdown (va("Server crashed: %s\n", msg), false);
+		CL_Drop ();
+		recursive = false;
+		longjmp (abortframe, -1);
+	}
+	else
+	{
+		SV_Shutdown (va("Server fatal crashed: %s\n", msg), false);
+		CL_Shutdown ();
+	}
+
+	if (logfile)
+	{
+		fclose (logfile);
+		logfile = NULL;
+	}
+
+	Sys_Error ("%s", msg);
+}
+
+
+/*
+=============
+Com_Quit
+
+Both client and server can use this, and it will
+do the apropriate things.
+=============
+*/
+void Com_Quit (void)
+{
+	SV_Shutdown ("Server quit\n", false);
+	CL_Shutdown ();
+
+	if (logfile)
+	{
+		fclose (logfile);
+		logfile = NULL;
+	}
+
+	Sys_Quit ();
+}
+
+
+/*
+==================
+Com_ServerState
+==================
+*/
+// this should've just been a cvar...
+int Com_ServerState (void)
+{
+	return server_state;
+}
+
+/*
+==================
+Com_SetServerState
+==================
+*/
+void Com_SetServerState (int state)
+{
+	server_state = state;
+}
+
+
+/*
+==============================================================================
+
+			MESSAGE IO FUNCTIONS
+
+Handles byte ordering and avoids alignment errors
+==============================================================================
+*/
+
+vec3_t	bytedirs[NUMVERTEXNORMALS] =
+{
+#include "anorms.h"
+};
+
+//
+// writing functions
+//
+
+void MSG_WriteChar (sizebuf_t *sb, int c)
+{
+	byte	*buf;
+	
+#ifdef PARANOID
+	if (c < -128 || c > 127)
+		Com_Error (ERR_FATAL, "MSG_WriteChar: range error");
+#endif
+
+	buf = SZ_GetSpace (sb, 1);
+	buf[0] = c;
+}
+
+void MSG_WriteByte (sizebuf_t *sb, int c)
+{
+	byte	*buf;
+	
+#ifdef PARANOID
+	if (c < 0 || c > 255)
+		Com_Error (ERR_FATAL, "MSG_WriteByte: range error");
+#endif
+
+	buf = SZ_GetSpace (sb, 1);
+	buf[0] = c;
+}
+
+void MSG_WriteShort (sizebuf_t *sb, int c)
+{
+	byte	*buf;
+	
+#ifdef PARANOID
+	if (c < ((short)0x8000) || c > (short)0x7fff)
+		Com_Error (ERR_FATAL, "MSG_WriteShort: range error");
+#endif
+
+	buf = SZ_GetSpace (sb, 2);
+	buf[0] = c&0xff;
+	buf[1] = c>>8;
+}
+
+void MSG_WriteLong (sizebuf_t *sb, int c)
+{
+	byte	*buf;
+	
+	buf = SZ_GetSpace (sb, 4);
+	buf[0] = c&0xff;
+	buf[1] = (c>>8)&0xff;
+	buf[2] = (c>>16)&0xff;
+	buf[3] = c>>24;
+}
+
+void MSG_WriteFloat (sizebuf_t *sb, float f)
+{
+	union
+	{
+		float	f;
+		int	l;
+	} dat;
+	
+	
+	dat.f = f;
+	dat.l = LittleLong (dat.l);
+	
+	SZ_Write (sb, &dat.l, 4);
+}
+
+void MSG_WriteString (sizebuf_t *sb, char *s)
+{
+	if (!s)
+		SZ_Write (sb, "", 1);
+	else
+		SZ_Write (sb, s, strlen(s)+1);
+}
+
+void MSG_WriteCoord (sizebuf_t *sb, float f)
+{
+	MSG_WriteShort (sb, (int)(f*8));
+}
+
+void MSG_WritePos (sizebuf_t *sb, vec3_t pos)
+{
+	MSG_WriteShort (sb, (int)(pos[0]*8));
+	MSG_WriteShort (sb, (int)(pos[1]*8));
+	MSG_WriteShort (sb, (int)(pos[2]*8));
+}
+
+void MSG_WriteAngle (sizebuf_t *sb, float f)
+{
+	MSG_WriteByte (sb, (int)(f*256/360) & 255);
+}
+
+void MSG_WriteAngle16 (sizebuf_t *sb, float f)
+{
+	MSG_WriteShort (sb, ANGLE2SHORT(f));
+}
+
+
+void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd)
+{
+	int		bits;
+
+//
+// send the movement message
+//
+	bits = 0;
+	if (cmd->angles[0] != from->angles[0])
+		bits |= CM_ANGLE1;
+	if (cmd->angles[1] != from->angles[1])
+		bits |= CM_ANGLE2;
+	if (cmd->angles[2] != from->angles[2])
+		bits |= CM_ANGLE3;
+	if (cmd->forwardmove != from->forwardmove)
+		bits |= CM_FORWARD;
+	if (cmd->sidemove != from->sidemove)
+		bits |= CM_SIDE;
+	if (cmd->upmove != from->upmove)
+		bits |= CM_UP;
+	if (cmd->buttons != from->buttons)
+		bits |= CM_BUTTONS;
+	if (cmd->impulse != from->impulse)
+		bits |= CM_IMPULSE;
+
+    MSG_WriteByte (buf, bits);
+
+	if (bits & CM_ANGLE1)
+		MSG_WriteShort (buf, cmd->angles[0]);
+	if (bits & CM_ANGLE2)
+		MSG_WriteShort (buf, cmd->angles[1]);
+	if (bits & CM_ANGLE3)
+		MSG_WriteShort (buf, cmd->angles[2]);
+	
+	if (bits & CM_FORWARD)
+		MSG_WriteShort (buf, cmd->forwardmove);
+	if (bits & CM_SIDE)
+	  	MSG_WriteShort (buf, cmd->sidemove);
+	if (bits & CM_UP)
+		MSG_WriteShort (buf, cmd->upmove);
+
+ 	if (bits & CM_BUTTONS)
+	  	MSG_WriteByte (buf, cmd->buttons);
+ 	if (bits & CM_IMPULSE)
+	    MSG_WriteByte (buf, cmd->impulse);
+
+    MSG_WriteByte (buf, cmd->msec);
+	MSG_WriteByte (buf, cmd->lightlevel);
+}
+
+
+void MSG_WriteDir (sizebuf_t *sb, vec3_t dir)
+{
+	int		i, best;
+	float	d, bestd;
+	
+	if (!dir)
+	{
+		MSG_WriteByte (sb, 0);
+		return;
+	}
+
+	bestd = 0;
+	best = 0;
+	for (i=0 ; i<NUMVERTEXNORMALS ; i++)
+	{
+		d = DotProduct (dir, bytedirs[i]);
+		if (d > bestd)
+		{
+			bestd = d;
+			best = i;
+		}
+	}
+	MSG_WriteByte (sb, best);
+}
+
+
+void MSG_ReadDir (sizebuf_t *sb, vec3_t dir)
+{
+	int		b;
+
+	b = MSG_ReadByte (sb);
+	if (b >= NUMVERTEXNORMALS)
+		Com_Error (ERR_DROP, "MSF_ReadDir: out of range");
+	VectorCopy (bytedirs[b], dir);
+}
+
+
+/*
+==================
+MSG_WriteDeltaEntity
+
+Writes part of a packetentities message.
+Can delta from either a baseline or a previous packet_entity
+==================
+*/
+void MSG_WriteDeltaEntity (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean newentity)
+{
+	int		bits;
+
+	if (!to->number)
+		Com_Error (ERR_FATAL, "Unset entity number");
+	if (to->number >= MAX_EDICTS)
+		Com_Error (ERR_FATAL, "Entity number >= MAX_EDICTS");
+
+// send an update
+	bits = 0;
+
+	if (to->number >= 256)
+		bits |= U_NUMBER16;		// number8 is implicit otherwise
+
+	if (to->origin[0] != from->origin[0])
+		bits |= U_ORIGIN1;
+	if (to->origin[1] != from->origin[1])
+		bits |= U_ORIGIN2;
+	if (to->origin[2] != from->origin[2])
+		bits |= U_ORIGIN3;
+
+	if ( to->angles[0] != from->angles[0] )
+		bits |= U_ANGLE1;		
+	if ( to->angles[1] != from->angles[1] )
+		bits |= U_ANGLE2;
+	if ( to->angles[2] != from->angles[2] )
+		bits |= U_ANGLE3;
+		
+	if ( to->skinnum != from->skinnum )
+	{
+		if ((unsigned)to->skinnum < 256)
+			bits |= U_SKIN8;
+		else if ((unsigned)to->skinnum < 0x10000)
+			bits |= U_SKIN16;
+		else
+			bits |= (U_SKIN8|U_SKIN16);
+	}
+		
+	if ( to->frame != from->frame )
+	{
+		if (to->frame < 256)
+			bits |= U_FRAME8;
+		else
+			bits |= U_FRAME16;
+	}
+
+	if ( to->effects != from->effects )
+	{
+		if (to->effects < 256)
+			bits |= U_EFFECTS8;
+		else if (to->effects < 0x8000)
+			bits |= U_EFFECTS16;
+		else
+			bits |= U_EFFECTS8|U_EFFECTS16;
+	}
+	
+	if ( to->renderfx != from->renderfx )
+	{
+		if (to->renderfx < 256)
+			bits |= U_RENDERFX8;
+		else if (to->renderfx < 0x8000)
+			bits |= U_RENDERFX16;
+		else
+			bits |= U_RENDERFX8|U_RENDERFX16;
+	}
+	
+	if ( to->solid != from->solid )
+		bits |= U_SOLID;
+
+	// event is not delta compressed, just 0 compressed
+	if ( to->event  )
+		bits |= U_EVENT;
+	
+	if ( to->modelindex != from->modelindex )
+		bits |= U_MODEL;
+	if ( to->modelindex2 != from->modelindex2 )
+		bits |= U_MODEL2;
+	if ( to->modelindex3 != from->modelindex3 )
+		bits |= U_MODEL3;
+	if ( to->modelindex4 != from->modelindex4 )
+		bits |= U_MODEL4;
+
+	if ( to->sound != from->sound )
+		bits |= U_SOUND;
+
+	if (newentity || (to->renderfx & RF_BEAM))
+		bits |= U_OLDORIGIN;
+
+	//
+	// write the message
+	//
+	if (!bits && !force)
+		return;		// nothing to send!
+
+	//----------
+
+	if (bits & 0xff000000)
+		bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1;
+	else if (bits & 0x00ff0000)
+		bits |= U_MOREBITS2 | U_MOREBITS1;
+	else if (bits & 0x0000ff00)
+		bits |= U_MOREBITS1;
+
+	MSG_WriteByte (msg,	bits&255 );
+
+	if (bits & 0xff000000)
+	{
+		MSG_WriteByte (msg,	(bits>>8)&255 );
+		MSG_WriteByte (msg,	(bits>>16)&255 );
+		MSG_WriteByte (msg,	(bits>>24)&255 );
+	}
+	else if (bits & 0x00ff0000)
+	{
+		MSG_WriteByte (msg,	(bits>>8)&255 );
+		MSG_WriteByte (msg,	(bits>>16)&255 );
+	}
+	else if (bits & 0x0000ff00)
+	{
+		MSG_WriteByte (msg,	(bits>>8)&255 );
+	}
+
+	//----------
+
+	if (bits & U_NUMBER16)
+		MSG_WriteShort (msg, to->number);
+	else
+		MSG_WriteByte (msg,	to->number);
+
+	if (bits & U_MODEL)
+		MSG_WriteByte (msg,	to->modelindex);
+	if (bits & U_MODEL2)
+		MSG_WriteByte (msg,	to->modelindex2);
+	if (bits & U_MODEL3)
+		MSG_WriteByte (msg,	to->modelindex3);
+	if (bits & U_MODEL4)
+		MSG_WriteByte (msg,	to->modelindex4);
+
+	if (bits & U_FRAME8)
+		MSG_WriteByte (msg, to->frame);
+	if (bits & U_FRAME16)
+		MSG_WriteShort (msg, to->frame);
+
+	if ((bits & U_SKIN8) && (bits & U_SKIN16))		//used for laser colors
+		MSG_WriteLong (msg, to->skinnum);
+	else if (bits & U_SKIN8)
+		MSG_WriteByte (msg, to->skinnum);
+	else if (bits & U_SKIN16)
+		MSG_WriteShort (msg, to->skinnum);
+
+
+	if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
+		MSG_WriteLong (msg, to->effects);
+	else if (bits & U_EFFECTS8)
+		MSG_WriteByte (msg, to->effects);
+	else if (bits & U_EFFECTS16)
+		MSG_WriteShort (msg, to->effects);
+
+	if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
+		MSG_WriteLong (msg, to->renderfx);
+	else if (bits & U_RENDERFX8)
+		MSG_WriteByte (msg, to->renderfx);
+	else if (bits & U_RENDERFX16)
+		MSG_WriteShort (msg, to->renderfx);
+
+	if (bits & U_ORIGIN1)
+		MSG_WriteCoord (msg, to->origin[0]);		
+	if (bits & U_ORIGIN2)
+		MSG_WriteCoord (msg, to->origin[1]);
+	if (bits & U_ORIGIN3)
+		MSG_WriteCoord (msg, to->origin[2]);
+
+	if (bits & U_ANGLE1)
+		MSG_WriteAngle(msg, to->angles[0]);
+	if (bits & U_ANGLE2)
+		MSG_WriteAngle(msg, to->angles[1]);
+	if (bits & U_ANGLE3)
+		MSG_WriteAngle(msg, to->angles[2]);
+
+	if (bits & U_OLDORIGIN)
+	{
+		MSG_WriteCoord (msg, to->old_origin[0]);
+		MSG_WriteCoord (msg, to->old_origin[1]);
+		MSG_WriteCoord (msg, to->old_origin[2]);
+	}
+
+	if (bits & U_SOUND)
+		MSG_WriteByte (msg, to->sound);
+	if (bits & U_EVENT)
+		MSG_WriteByte (msg, to->event);
+	if (bits & U_SOLID)
+		MSG_WriteShort (msg, to->solid);
+}
+
+
+//============================================================
+
+//
+// reading functions
+//
+
+void MSG_BeginReading (sizebuf_t *msg)
+{
+	msg->readcount = 0;
+}
+
+// returns -1 if no more characters are available
+int MSG_ReadChar (sizebuf_t *msg_read)
+{
+	int	c;
+	
+	if (msg_read->readcount+1 > msg_read->cursize)
+		c = -1;
+	else
+		c = (signed char)msg_read->data[msg_read->readcount];
+	msg_read->readcount++;
+	
+	return c;
+}
+
+int MSG_ReadByte (sizebuf_t *msg_read)
+{
+	int	c;
+	
+	if (msg_read->readcount+1 > msg_read->cursize)
+		c = -1;
+	else
+		c = (unsigned char)msg_read->data[msg_read->readcount];
+	msg_read->readcount++;
+	
+	return c;
+}
+
+int MSG_ReadShort (sizebuf_t *msg_read)
+{
+	int	c;
+	
+	if (msg_read->readcount+2 > msg_read->cursize)
+		c = -1;
+	else		
+		c = (short)(msg_read->data[msg_read->readcount]
+		+ (msg_read->data[msg_read->readcount+1]<<8));
+	
+	msg_read->readcount += 2;
+	
+	return c;
+}
+
+int MSG_ReadLong (sizebuf_t *msg_read)
+{
+	int	c;
+	
+	if (msg_read->readcount+4 > msg_read->cursize)
+		c = -1;
+	else
+		c = msg_read->data[msg_read->readcount]
+		+ (msg_read->data[msg_read->readcount+1]<<8)
+		+ (msg_read->data[msg_read->readcount+2]<<16)
+		+ (msg_read->data[msg_read->readcount+3]<<24);
+	
+	msg_read->readcount += 4;
+	
+	return c;
+}
+
+float MSG_ReadFloat (sizebuf_t *msg_read)
+{
+	union
+	{
+		byte	b[4];
+		float	f;
+		int	l;
+	} dat;
+	
+	if (msg_read->readcount+4 > msg_read->cursize)
+		dat.f = -1;
+	else
+	{
+		dat.b[0] =	msg_read->data[msg_read->readcount];
+		dat.b[1] =	msg_read->data[msg_read->readcount+1];
+		dat.b[2] =	msg_read->data[msg_read->readcount+2];
+		dat.b[3] =	msg_read->data[msg_read->readcount+3];
+	}
+	msg_read->readcount += 4;
+	
+	dat.l = LittleLong (dat.l);
+
+	return dat.f;	
+}
+
+char *MSG_ReadString (sizebuf_t *msg_read)
+{
+	static char	string[2048];
+	int		l,c;
+	
+	l = 0;
+	do
+	{
+		c = MSG_ReadChar (msg_read);
+		if (c == -1 || c == 0)
+			break;
+		string[l] = c;
+		l++;
+	} while (l < sizeof(string)-1);
+	
+	string[l] = 0;
+	
+	return string;
+}
+
+char *MSG_ReadStringLine (sizebuf_t *msg_read)
+{
+	static char	string[2048];
+	int		l,c;
+	
+	l = 0;
+	do
+	{
+		c = MSG_ReadChar (msg_read);
+		if (c == -1 || c == 0 || c == '\n')
+			break;
+		string[l] = c;
+		l++;
+	} while (l < sizeof(string)-1);
+	
+	string[l] = 0;
+	
+	return string;
+}
+
+float MSG_ReadCoord (sizebuf_t *msg_read)
+{
+	return MSG_ReadShort(msg_read) * (1.0/8);
+}
+
+void MSG_ReadPos (sizebuf_t *msg_read, vec3_t pos)
+{
+	pos[0] = MSG_ReadShort(msg_read) * (1.0/8);
+	pos[1] = MSG_ReadShort(msg_read) * (1.0/8);
+	pos[2] = MSG_ReadShort(msg_read) * (1.0/8);
+}
+
+float MSG_ReadAngle (sizebuf_t *msg_read)
+{
+	return MSG_ReadChar(msg_read) * (360.0/256);
+}
+
+float MSG_ReadAngle16 (sizebuf_t *msg_read)
+{
+	return SHORT2ANGLE(MSG_ReadShort(msg_read));
+}
+
+void MSG_ReadDeltaUsercmd (sizebuf_t *msg_read, usercmd_t *from, usercmd_t *move)
+{
+	int bits;
+
+	memcpy (move, from, sizeof(*move));
+
+	bits = MSG_ReadByte (msg_read);
+		
+// read current angles
+	if (bits & CM_ANGLE1)
+		move->angles[0] = MSG_ReadShort (msg_read);
+	if (bits & CM_ANGLE2)
+		move->angles[1] = MSG_ReadShort (msg_read);
+	if (bits & CM_ANGLE3)
+		move->angles[2] = MSG_ReadShort (msg_read);
+		
+// read movement
+	if (bits & CM_FORWARD)
+		move->forwardmove = MSG_ReadShort (msg_read);
+	if (bits & CM_SIDE)
+		move->sidemove = MSG_ReadShort (msg_read);
+	if (bits & CM_UP)
+		move->upmove = MSG_ReadShort (msg_read);
+	
+// read buttons
+	if (bits & CM_BUTTONS)
+		move->buttons = MSG_ReadByte (msg_read);
+
+	if (bits & CM_IMPULSE)
+		move->impulse = MSG_ReadByte (msg_read);
+
+// read time to run command
+	move->msec = MSG_ReadByte (msg_read);
+
+// read the light level
+	move->lightlevel = MSG_ReadByte (msg_read);
+}
+
+
+void MSG_ReadData (sizebuf_t *msg_read, void *data, int len)
+{
+	int		i;
+
+	for (i=0 ; i<len ; i++)
+		((byte *)data)[i] = MSG_ReadByte (msg_read);
+}
+
+
+//===========================================================================
+
+void SZ_Init (sizebuf_t *buf, byte *data, int length)
+{
+	memset (buf, 0, sizeof(*buf));
+	buf->data = data;
+	buf->maxsize = length;
+}
+
+void SZ_Clear (sizebuf_t *buf)
+{
+	buf->cursize = 0;
+	buf->overflowed = false;
+}
+
+void *SZ_GetSpace (sizebuf_t *buf, int length)
+{
+	void	*data;
+	
+	if (buf->cursize + length > buf->maxsize)
+	{
+		if (!buf->allowoverflow)
+			Com_Error (ERR_FATAL, "SZ_GetSpace: overflow without allowoverflow set");
+		
+		if (length > buf->maxsize)
+			Com_Error (ERR_FATAL, "SZ_GetSpace: %i is > full buffer size", length);
+			
+		Com_Printf ("SZ_GetSpace: overflow\n");
+		SZ_Clear (buf); 
+		buf->overflowed = true;
+	}
+
+	data = buf->data + buf->cursize;
+	buf->cursize += length;
+	
+	return data;
+}
+
+void SZ_Write (sizebuf_t *buf, void *data, int length)
+{
+	memcpy (SZ_GetSpace(buf,length),data,length);		
+}
+
+void SZ_Print (sizebuf_t *buf, char *data)
+{
+	int		len;
+	
+	len = strlen(data)+1;
+
+	if (buf->cursize)
+	{
+		if (buf->data[buf->cursize-1])
+			memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
+		else
+			memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
+	}
+	else
+		memcpy ((byte *)SZ_GetSpace(buf, len),data,len);
+}
+
+
+//============================================================================
+
+
+/*
+================
+COM_CheckParm
+
+Returns the position (1 to argc-1) in the program's argument list
+where the given parameter apears, or 0 if not present
+================
+*/
+int COM_CheckParm (char *parm)
+{
+	int		i;
+	
+	for (i=1 ; i<com_argc ; i++)
+	{
+		if (!strcmp (parm,com_argv[i]))
+			return i;
+	}
+		
+	return 0;
+}
+
+int COM_Argc (void)
+{
+	return com_argc;
+}
+
+char *COM_Argv (int arg)
+{
+	if (arg < 0 || arg >= com_argc || !com_argv[arg])
+		return "";
+	return com_argv[arg];
+}
+
+void COM_ClearArgv (int arg)
+{
+	if (arg < 0 || arg >= com_argc || !com_argv[arg])
+		return;
+	com_argv[arg] = "";
+}
+
+
+/*
+================
+COM_InitArgv
+================
+*/
+void COM_InitArgv (int argc, char **argv)
+{
+	int		i;
+
+	if (argc > MAX_NUM_ARGVS)
+		Com_Error (ERR_FATAL, "argc > MAX_NUM_ARGVS");
+	com_argc = argc;
+	for (i=0 ; i<argc ; i++)
+	{
+		if (!argv[i] || strlen(argv[i]) >= MAX_TOKEN_CHARS )
+			com_argv[i] = "";
+		else
+			com_argv[i] = argv[i];
+	}
+}
+
+/*
+================
+COM_AddParm
+
+Adds the given string at the end of the current argument list
+================
+*/
+void COM_AddParm (char *parm)
+{
+	if (com_argc == MAX_NUM_ARGVS)
+		Com_Error (ERR_FATAL, "COM_AddParm: MAX_NUM)ARGS");
+	com_argv[com_argc++] = parm;
+}
+
+
+
+
+/// just for debugging
+int	memsearch (byte *start, int count, int search)
+{
+	int		i;
+	
+	for (i=0 ; i<count ; i++)
+		if (start[i] == search)
+			return i;
+	return -1;
+}
+
+
+char *CopyString (char *in)
+{
+	char	*out;
+	
+	out = Z_Malloc (strlen(in)+1);
+	strcpy (out, in);
+	return out;
+}
+
+
+
+void Info_Print (char *s)
+{
+	char	key[512];
+	char	value[512];
+	char	*o;
+	int		l;
+
+	if (*s == '\\')
+		s++;
+	while (*s)
+	{
+		o = key;
+		while (*s && *s != '\\')
+			*o++ = *s++;
+
+		l = o - key;
+		if (l < 20)
+		{
+			memset (o, ' ', 20-l);
+			key[20] = 0;
+		}
+		else
+			*o = 0;
+		Com_Printf ("%s", key);
+
+		if (!*s)
+		{
+			Com_Printf ("MISSING VALUE\n");
+			return;
+		}
+
+		o = value;
+		s++;
+		while (*s && *s != '\\')
+			*o++ = *s++;
+		*o = 0;
+
+		if (*s)
+			s++;
+		Com_Printf ("%s\n", value);
+	}
+}
+
+
+/*
+==============================================================================
+
+						ZONE MEMORY ALLOCATION
+
+just cleared malloc with counters now...
+
+==============================================================================
+*/
+
+#define	Z_MAGIC	0x1d1d
+
+typedef struct zhead_t zhead_t;
+struct zhead_t{
+	zhead_t	*prev;
+	zhead_t *next;
+	short magic;
+	short tag;	// for group free
+	int size;
+};
+zhead_t z_chain;
+int z_count;
+int z_bytes;
+
+
+/*
+========================
+Z_Free
+========================
+*/
+void Z_Free (void *ptr)
+{
+	zhead_t	*z;
+
+	z = ((zhead_t *)ptr) - 1;
+
+	if (z->magic != Z_MAGIC)
+		Com_Error (ERR_FATAL, "Z_Free: bad magic");
+
+	z->prev->next = z->next;
+	z->next->prev = z->prev;
+
+	z_count--;
+	z_bytes -= z->size;
+	free (z);
+}
+
+
+/*
+========================
+Z_Stats_f
+========================
+*/
+void Z_Stats_f (void)
+{
+	Com_Printf ("%i bytes in %i blocks\n", z_bytes, z_count);
+}
+
+/*
+========================
+Z_FreeTags
+========================
+*/
+void Z_FreeTags (int tag)
+{
+	zhead_t	*z, *next;
+
+	for (z=z_chain.next ; z != &z_chain ; z=next)
+	{
+		next = z->next;
+		if (z->tag == tag)
+			Z_Free ((void *)(z+1));
+	}
+}
+
+/*
+========================
+Z_TagMalloc
+========================
+*/
+void *Z_TagMalloc (int size, int tag)
+{
+	zhead_t	*z;
+	
+	size = size + sizeof(*z);
+	z = malloc(size);
+	if (!z)
+		Com_Error (ERR_FATAL, "Z_Malloc: failed on allocation of %i bytes",size);
+	memset (z, 0, size);
+	z_count++;
+	z_bytes += size;
+	z->magic = Z_MAGIC;
+	z->tag = tag;
+	z->size = size;
+
+	z->next = z_chain.next;
+	z->prev = &z_chain;
+	z_chain.next->prev = z;
+	z_chain.next = z;
+
+	return (void *)(z+1);
+}
+
+/*
+========================
+Z_Malloc
+========================
+*/
+void *Z_Malloc (int size)
+{
+	return Z_TagMalloc (size, 0);
+}
+
+
+//============================================================================
+
+
+/*
+====================
+COM_BlockSequenceCheckByte
+
+For proxy protecting
+
+// THIS IS MASSIVELY BROKEN!  CHALLENGE MAY BE NEGATIVE
+// DON'T USE THIS FUNCTION!!!!!
+
+====================
+*/
+byte	COM_BlockSequenceCheckByte (byte */*base*/, int /*length*/, int /*sequence*/, int /*challenge*/)
+{
+	Sys_Error("COM_BlockSequenceCheckByte called\n");
+
+/*
+	int		checksum;
+	byte	buf[68];
+	byte	*p;
+	float temp;
+	byte c;
+
+	temp = bytedirs[(sequence/3) % NUMVERTEXNORMALS][sequence % 3];
+	temp = LittleFloat(temp);
+	p = ((byte *)&temp);
+
+	if (length > 60)
+		length = 60;
+	memcpy (buf, base, length);
+
+	buf[length] = (sequence & 0xff) ^ p[0];
+	buf[length+1] = p[1];
+	buf[length+2] = ((sequence>>8) & 0xff) ^ p[2];
+	buf[length+3] = p[3];
+
+	temp = bytedirs[((sequence+challenge)/3) % NUMVERTEXNORMALS][(sequence+challenge) % 3];
+	temp = LittleFloat(temp);
+	p = ((byte *)&temp);
+
+	buf[length+4] = (sequence & 0xff) ^ p[3];
+	buf[length+5] = (challenge & 0xff) ^ p[2];
+	buf[length+6] = ((sequence>>8) & 0xff) ^ p[1];
+	buf[length+7] = ((challenge >> 7) & 0xff) ^ p[0];
+
+	length += 8;
+
+	checksum = LittleLong(Com_BlockChecksum (buf, length));
+
+	checksum &= 0xff;
+
+	return checksum;
+*/
+	return 0;
+}
+
+static byte chktbl[1024] = {
+0x84, 0x47, 0x51, 0xc1, 0x93, 0x22, 0x21, 0x24, 0x2f, 0x66, 0x60, 0x4d, 0xb0, 0x7c, 0xda,
+0x88, 0x54, 0x15, 0x2b, 0xc6, 0x6c, 0x89, 0xc5, 0x9d, 0x48, 0xee, 0xe6, 0x8a, 0xb5, 0xf4,
+0xcb, 0xfb, 0xf1, 0x0c, 0x2e, 0xa0, 0xd7, 0xc9, 0x1f, 0xd6, 0x06, 0x9a, 0x09, 0x41, 0x54,
+0x67, 0x46, 0xc7, 0x74, 0xe3, 0xc8, 0xb6, 0x5d, 0xa6, 0x36, 0xc4, 0xab, 0x2c, 0x7e, 0x85,
+0xa8, 0xa4, 0xa6, 0x4d, 0x96, 0x19, 0x19, 0x9a, 0xcc, 0xd8, 0xac, 0x39, 0x5e, 0x3c, 0xf2,
+0xf5, 0x5a, 0x72, 0xe5, 0xa9, 0xd1, 0xb3, 0x23, 0x82, 0x6f, 0x29, 0xcb, 0xd1, 0xcc, 0x71,
+0xfb, 0xea, 0x92, 0xeb, 0x1c, 0xca, 0x4c, 0x70, 0xfe, 0x4d, 0xc9, 0x67, 0x43, 0x47, 0x94,
+0xb9, 0x47, 0xbc, 0x3f, 0x01, 0xab, 0x7b, 0xa6, 0xe2, 0x76, 0xef, 0x5a, 0x7a, 0x29, 0x0b,
+0x51, 0x54, 0x67, 0xd8, 0x1c, 0x14, 0x3e, 0x29, 0xec, 0xe9, 0x2d, 0x48, 0x67, 0xff, 0xed,
+0x54, 0x4f, 0x48, 0xc0, 0xaa, 0x61, 0xf7, 0x78, 0x12, 0x03, 0x7a, 0x9e, 0x8b, 0xcf, 0x83,
+0x7b, 0xae, 0xca, 0x7b, 0xd9, 0xe9, 0x53, 0x2a, 0xeb, 0xd2, 0xd8, 0xcd, 0xa3, 0x10, 0x25,
+0x78, 0x5a, 0xb5, 0x23, 0x06, 0x93, 0xb7, 0x84, 0xd2, 0xbd, 0x96, 0x75, 0xa5, 0x5e, 0xcf,
+0x4e, 0xe9, 0x50, 0xa1, 0xe6, 0x9d, 0xb1, 0xe3, 0x85, 0x66, 0x28, 0x4e, 0x43, 0xdc, 0x6e,
+0xbb, 0x33, 0x9e, 0xf3, 0x0d, 0x00, 0xc1, 0xcf, 0x67, 0x34, 0x06, 0x7c, 0x71, 0xe3, 0x63,
+0xb7, 0xb7, 0xdf, 0x92, 0xc4, 0xc2, 0x25, 0x5c, 0xff, 0xc3, 0x6e, 0xfc, 0xaa, 0x1e, 0x2a,
+0x48, 0x11, 0x1c, 0x36, 0x68, 0x78, 0x86, 0x79, 0x30, 0xc3, 0xd6, 0xde, 0xbc, 0x3a, 0x2a,
+0x6d, 0x1e, 0x46, 0xdd, 0xe0, 0x80, 0x1e, 0x44, 0x3b, 0x6f, 0xaf, 0x31, 0xda, 0xa2, 0xbd,
+0x77, 0x06, 0x56, 0xc0, 0xb7, 0x92, 0x4b, 0x37, 0xc0, 0xfc, 0xc2, 0xd5, 0xfb, 0xa8, 0xda,
+0xf5, 0x57, 0xa8, 0x18, 0xc0, 0xdf, 0xe7, 0xaa, 0x2a, 0xe0, 0x7c, 0x6f, 0x77, 0xb1, 0x26,
+0xba, 0xf9, 0x2e, 0x1d, 0x16, 0xcb, 0xb8, 0xa2, 0x44, 0xd5, 0x2f, 0x1a, 0x79, 0x74, 0x87,
+0x4b, 0x00, 0xc9, 0x4a, 0x3a, 0x65, 0x8f, 0xe6, 0x5d, 0xe5, 0x0a, 0x77, 0xd8, 0x1a, 0x14,
+0x41, 0x75, 0xb1, 0xe2, 0x50, 0x2c, 0x93, 0x38, 0x2b, 0x6d, 0xf3, 0xf6, 0xdb, 0x1f, 0xcd,
+0xff, 0x14, 0x70, 0xe7, 0x16, 0xe8, 0x3d, 0xf0, 0xe3, 0xbc, 0x5e, 0xb6, 0x3f, 0xcc, 0x81,
+0x24, 0x67, 0xf3, 0x97, 0x3b, 0xfe, 0x3a, 0x96, 0x85, 0xdf, 0xe4, 0x6e, 0x3c, 0x85, 0x05,
+0x0e, 0xa3, 0x2b, 0x07, 0xc8, 0xbf, 0xe5, 0x13, 0x82, 0x62, 0x08, 0x61, 0x69, 0x4b, 0x47,
+0x62, 0x73, 0x44, 0x64, 0x8e, 0xe2, 0x91, 0xa6, 0x9a, 0xb7, 0xe9, 0x04, 0xb6, 0x54, 0x0c,
+0xc5, 0xa9, 0x47, 0xa6, 0xc9, 0x08, 0xfe, 0x4e, 0xa6, 0xcc, 0x8a, 0x5b, 0x90, 0x6f, 0x2b,
+0x3f, 0xb6, 0x0a, 0x96, 0xc0, 0x78, 0x58, 0x3c, 0x76, 0x6d, 0x94, 0x1a, 0xe4, 0x4e, 0xb8,
+0x38, 0xbb, 0xf5, 0xeb, 0x29, 0xd8, 0xb0, 0xf3, 0x15, 0x1e, 0x99, 0x96, 0x3c, 0x5d, 0x63,
+0xd5, 0xb1, 0xad, 0x52, 0xb8, 0x55, 0x70, 0x75, 0x3e, 0x1a, 0xd5, 0xda, 0xf6, 0x7a, 0x48,
+0x7d, 0x44, 0x41, 0xf9, 0x11, 0xce, 0xd7, 0xca, 0xa5, 0x3d, 0x7a, 0x79, 0x7e, 0x7d, 0x25,
+0x1b, 0x77, 0xbc, 0xf7, 0xc7, 0x0f, 0x84, 0x95, 0x10, 0x92, 0x67, 0x15, 0x11, 0x5a, 0x5e,
+0x41, 0x66, 0x0f, 0x38, 0x03, 0xb2, 0xf1, 0x5d, 0xf8, 0xab, 0xc0, 0x02, 0x76, 0x84, 0x28,
+0xf4, 0x9d, 0x56, 0x46, 0x60, 0x20, 0xdb, 0x68, 0xa7, 0xbb, 0xee, 0xac, 0x15, 0x01, 0x2f,
+0x20, 0x09, 0xdb, 0xc0, 0x16, 0xa1, 0x89, 0xf9, 0x94, 0x59, 0x00, 0xc1, 0x76, 0xbf, 0xc1,
+0x4d, 0x5d, 0x2d, 0xa9, 0x85, 0x2c, 0xd6, 0xd3, 0x14, 0xcc, 0x02, 0xc3, 0xc2, 0xfa, 0x6b,
+0xb7, 0xa6, 0xef, 0xdd, 0x12, 0x26, 0xa4, 0x63, 0xe3, 0x62, 0xbd, 0x56, 0x8a, 0x52, 0x2b,
+0xb9, 0xdf, 0x09, 0xbc, 0x0e, 0x97, 0xa9, 0xb0, 0x82, 0x46, 0x08, 0xd5, 0x1a, 0x8e, 0x1b,
+0xa7, 0x90, 0x98, 0xb9, 0xbb, 0x3c, 0x17, 0x9a, 0xf2, 0x82, 0xba, 0x64, 0x0a, 0x7f, 0xca,
+0x5a, 0x8c, 0x7c, 0xd3, 0x79, 0x09, 0x5b, 0x26, 0xbb, 0xbd, 0x25, 0xdf, 0x3d, 0x6f, 0x9a,
+0x8f, 0xee, 0x21, 0x66, 0xb0, 0x8d, 0x84, 0x4c, 0x91, 0x45, 0xd4, 0x77, 0x4f, 0xb3, 0x8c,
+0xbc, 0xa8, 0x99, 0xaa, 0x19, 0x53, 0x7c, 0x02, 0x87, 0xbb, 0x0b, 0x7c, 0x1a, 0x2d, 0xdf,
+0x48, 0x44, 0x06, 0xd6, 0x7d, 0x0c, 0x2d, 0x35, 0x76, 0xae, 0xc4, 0x5f, 0x71, 0x85, 0x97,
+0xc4, 0x3d, 0xef, 0x52, 0xbe, 0x00, 0xe4, 0xcd, 0x49, 0xd1, 0xd1, 0x1c, 0x3c, 0xd0, 0x1c,
+0x42, 0xaf, 0xd4, 0xbd, 0x58, 0x34, 0x07, 0x32, 0xee, 0xb9, 0xb5, 0xea, 0xff, 0xd7, 0x8c,
+0x0d, 0x2e, 0x2f, 0xaf, 0x87, 0xbb, 0xe6, 0x52, 0x71, 0x22, 0xf5, 0x25, 0x17, 0xa1, 0x82,
+0x04, 0xc2, 0x4a, 0xbd, 0x57, 0xc6, 0xab, 0xc8, 0x35, 0x0c, 0x3c, 0xd9, 0xc2, 0x43, 0xdb,
+0x27, 0x92, 0xcf, 0xb8, 0x25, 0x60, 0xfa, 0x21, 0x3b, 0x04, 0x52, 0xc8, 0x96, 0xba, 0x74,
+0xe3, 0x67, 0x3e, 0x8e, 0x8d, 0x61, 0x90, 0x92, 0x59, 0xb6, 0x1a, 0x1c, 0x5e, 0x21, 0xc1,
+0x65, 0xe5, 0xa6, 0x34, 0x05, 0x6f, 0xc5, 0x60, 0xb1, 0x83, 0xc1, 0xd5, 0xd5, 0xed, 0xd9,
+0xc7, 0x11, 0x7b, 0x49, 0x7a, 0xf9, 0xf9, 0x84, 0x47, 0x9b, 0xe2, 0xa5, 0x82, 0xe0, 0xc2,
+0x88, 0xd0, 0xb2, 0x58, 0x88, 0x7f, 0x45, 0x09, 0x67, 0x74, 0x61, 0xbf, 0xe6, 0x40, 0xe2,
+0x9d, 0xc2, 0x47, 0x05, 0x89, 0xed, 0xcb, 0xbb, 0xb7, 0x27, 0xe7, 0xdc, 0x7a, 0xfd, 0xbf,
+0xa8, 0xd0, 0xaa, 0x10, 0x39, 0x3c, 0x20, 0xf0, 0xd3, 0x6e, 0xb1, 0x72, 0xf8, 0xe6, 0x0f,
+0xef, 0x37, 0xe5, 0x09, 0x33, 0x5a, 0x83, 0x43, 0x80, 0x4f, 0x65, 0x2f, 0x7c, 0x8c, 0x6a,
+0xa0, 0x82, 0x0c, 0xd4, 0xd4, 0xfa, 0x81, 0x60, 0x3d, 0xdf, 0x06, 0xf1, 0x5f, 0x08, 0x0d,
+0x6d, 0x43, 0xf2, 0xe3, 0x11, 0x7d, 0x80, 0x32, 0xc5, 0xfb, 0xc5, 0xd9, 0x27, 0xec, 0xc6,
+0x4e, 0x65, 0x27, 0x76, 0x87, 0xa6, 0xee, 0xee, 0xd7, 0x8b, 0xd1, 0xa0, 0x5c, 0xb0, 0x42,
+0x13, 0x0e, 0x95, 0x4a, 0xf2, 0x06, 0xc6, 0x43, 0x33, 0xf4, 0xc7, 0xf8, 0xe7, 0x1f, 0xdd,
+0xe4, 0x46, 0x4a, 0x70, 0x39, 0x6c, 0xd0, 0xed, 0xca, 0xbe, 0x60, 0x3b, 0xd1, 0x7b, 0x57,
+0x48, 0xe5, 0x3a, 0x79, 0xc1, 0x69, 0x33, 0x53, 0x1b, 0x80, 0xb8, 0x91, 0x7d, 0xb4, 0xf6,
+0x17, 0x1a, 0x1d, 0x5a, 0x32, 0xd6, 0xcc, 0x71, 0x29, 0x3f, 0x28, 0xbb, 0xf3, 0x5e, 0x71,
+0xb8, 0x43, 0xaf, 0xf8, 0xb9, 0x64, 0xef, 0xc4, 0xa5, 0x6c, 0x08, 0x53, 0xc7, 0x00, 0x10,
+0x39, 0x4f, 0xdd, 0xe4, 0xb6, 0x19, 0x27, 0xfb, 0xb8, 0xf5, 0x32, 0x73, 0xe5, 0xcb, 0x32
+};
+
+/*
+====================
+COM_BlockSequenceCRCByte
+
+For proxy protecting
+====================
+*/
+byte	COM_BlockSequenceCRCByte (byte *base, int length, int sequence)
+{
+	int		n;
+	byte	*p;
+	int		x;
+	byte chkb[60 + 4];
+	unsigned short crc;
+
+
+	if (sequence < 0)
+		Sys_Error("sequence < 0, this shouldn't happen\n");
+
+	p = chktbl + (sequence % (sizeof(chktbl) - 4));
+
+	if (length > 60)
+		length = 60;
+	memcpy (chkb, base, length);
+
+	chkb[length] = p[0];
+	chkb[length+1] = p[1];
+	chkb[length+2] = p[2];
+	chkb[length+3] = p[3];
+
+	length += 4;
+
+	crc = CRC_Block(chkb, length);
+
+	for (x=0, n=0; n<length; n++)
+		x += chkb[n];
+
+	crc = (crc ^ x) & 0xff;
+
+	return crc;
+}
+
+//========================================================
+
+/* 0 to 1 */
+float	qfrand(void)
+{
+	return (rand()&32767)* (1.0/32767);
+}
+
+/* -1 to 1 */
+float	crand(void)
+{
+	return (rand()&32767)* (2.0/32767) - 1;
+}
+
+void Key_Init (void);
+void SCR_EndLoadingPlaque (void);
+
+/*
+=============
+Com_Error_f
+
+Just throw a fatal error to
+test error shutdown procedures
+=============
+*/
+void Com_Error_f (void)
+{
+	Com_Error (ERR_FATAL, "%s", Cmd_Argv(1));
+}
+
+
+/*
+=================
+Qcommon_Init
+=================
+*/
+void Qcommon_Init (int argc, char **argv)
+{
+	char	*s;
+
+	if (setjmp (abortframe) )
+		Sys_Error ("Error during initialization");
+
+	z_chain.next = z_chain.prev = &z_chain;
+
+	// prepare enough of the subsystems to handle
+	// cvar and command buffer management
+	COM_InitArgv (argc, argv);
+
+	Swap_Init ();
+	Cbuf_Init ();
+
+	Cmd_Init ();
+	Cvar_Init ();
+
+	Key_Init ();
+
+	// we need to add the early commands twice, because
+	// a basedir or cddir needs to be set before execing
+	// config files, but we want other parms to override
+	// the settings of the config files
+	Cbuf_AddEarlyCommands (false);
+	Cbuf_Execute ();
+
+	FS_InitFilesystem ();
+
+	Cbuf_AddText ("exec default.cfg\n");
+	Cbuf_AddText ("exec config.cfg\n");
+
+	Cbuf_AddEarlyCommands (true);
+	Cbuf_Execute ();
+
+	//
+	// init commands and vars
+	//
+    Cmd_AddCommand ("z_stats", Z_Stats_f);
+    Cmd_AddCommand ("error", Com_Error_f);
+
+	host_speeds = Cvar_Get ("host_speeds", "0", 0);
+	log_stats = Cvar_Get ("log_stats", "0", 0);
+	developer = Cvar_Get ("developer", "0", 0);
+	timescale = Cvar_Get ("timescale", "1", 0);
+	fixedtime = Cvar_Get ("fixedtime", "0", 0);
+	logfile_active = Cvar_Get ("logfile", "0", 0);
+	showtrace = Cvar_Get ("showtrace", "0", 0);
+#ifdef DEDICATED_ONLY
+	dedicated = Cvar_Get ("dedicated", "1", CVAR_NOSET);
+#else
+	dedicated = Cvar_Get ("dedicated", "0", CVAR_NOSET);
+#endif
+
+	s = va("%4.2f 9front Nov 30 1997 9front", VERSION);
+	Cvar_Get ("version", s, CVAR_SERVERINFO|CVAR_NOSET);
+
+
+	if (dedicated->value)
+		Cmd_AddCommand ("quit", Com_Quit);
+
+	Sys_Init ();
+
+	NET_Init ();
+	Netchan_Init ();
+
+	SV_Init ();
+	CL_Init ();
+
+	// add + commands from command line
+	if (!Cbuf_AddLateCommands ())
+	{	// if the user didn't give any commands, run default action
+		if (!dedicated->value)
+			Cbuf_AddText ("d1\n");
+		else
+			Cbuf_AddText ("dedicated_start\n");
+		Cbuf_Execute ();
+	}
+	else
+	{	// the user asked for something explicit
+		// so drop the loading plaque
+		SCR_EndLoadingPlaque ();
+	}
+
+	Com_Printf ("====== Quake2 Initialized ======\n\n");	
+}
+
+/*
+=================
+Qcommon_Frame
+=================
+*/
+void Qcommon_Frame (int msec)
+{
+	char	*s;
+	int		time_before = 0, time_between = 0, time_after = 0;
+
+	if (setjmp (abortframe) )
+		return;			// an ERR_DROP was thrown
+
+	if ( log_stats->modified )
+	{
+		log_stats->modified = false;
+		if ( log_stats->value )
+		{
+			if ( log_stats_file )
+			{
+				fclose( log_stats_file );
+				log_stats_file = 0;
+			}
+			log_stats_file = fopen( "stats.log", "w" );
+			if ( log_stats_file )
+				fprintf( log_stats_file, "entities,dlights,parts,frame time\n" );
+		}
+		else
+		{
+			if ( log_stats_file )
+			{
+				fclose( log_stats_file );
+				log_stats_file = 0;
+			}
+		}
+	}
+
+	if (fixedtime->value)
+		msec = fixedtime->value;
+	else if (timescale->value)
+	{
+		msec *= timescale->value;
+		if (msec < 1)
+			msec = 1;
+	}
+
+	if (showtrace->value)
+	{
+		extern	int c_traces, c_brush_traces;
+		extern	int	c_pointcontents;
+
+		Com_Printf ("%4i traces  %4i points\n", c_traces, c_pointcontents);
+		c_traces = 0;
+		c_brush_traces = 0;
+		c_pointcontents = 0;
+	}
+
+	do
+	{
+		s = Sys_ConsoleInput ();
+		if (s)
+			Cbuf_AddText (va("%s\n",s));
+	} while (s);
+	Cbuf_Execute ();
+
+	if (host_speeds->value)
+		time_before = Sys_Milliseconds ();
+
+	SV_Frame (msec);
+
+	if (host_speeds->value)
+		time_between = Sys_Milliseconds ();		
+
+	CL_Frame (msec);
+
+	if (host_speeds->value)
+		time_after = Sys_Milliseconds ();		
+
+
+	if (host_speeds->value)
+	{
+		int			all, sv, gm, cl, rf;
+
+		all = time_after - time_before;
+		sv = time_between - time_before;
+		cl = time_after - time_between;
+		gm = time_after_game - time_before_game;
+		rf = time_after_ref - time_before_ref;
+		sv -= gm;
+		cl -= rf;
+		Com_Printf ("all:%3i sv:%3i gm:%3i cl:%3i rf:%3i\n",
+			all, sv, gm, cl, rf);
+	}	
+}
--- /dev/null
+++ b/console.c
@@ -1,0 +1,661 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+console_t	con;
+
+cvar_t		*con_notifytime;
+
+
+#define		MAXCMDLINE	256
+extern	char	key_lines[32][MAXCMDLINE];
+extern	int		edit_line;
+extern	int		key_linepos;
+		
+
+void DrawString (int x, int y, char *s)
+{
+	while (*s)
+	{
+		re.DrawChar (x, y, *s);
+		x+=8;
+		s++;
+	}
+}
+
+void DrawAltString (int x, int y, char *s)
+{
+	while (*s)
+	{
+		re.DrawChar (x, y, *s ^ 0x80);
+		x+=8;
+		s++;
+	}
+}
+
+
+void Key_ClearTyping (void)
+{
+	key_lines[edit_line][1] = 0;	// clear any typing
+	key_linepos = 1;
+}
+
+/*
+================
+Con_ToggleConsole_f
+================
+*/
+void Con_ToggleConsole_f (void)
+{
+	SCR_EndLoadingPlaque ();	// get rid of loading plaque
+
+	if (cl.attractloop)
+	{
+		Cbuf_AddText ("killserver\n");
+		return;
+	}
+
+	if (cls.state == ca_disconnected)
+	{	// start the demo loop again
+		Cbuf_AddText ("d1\n");
+		return;
+	}
+
+	Key_ClearTyping ();
+	Con_ClearNotify ();
+
+	if (cls.key_dest == key_console)
+	{
+		M_ForceMenuOff ();
+		Cvar_Set ("paused", "0");
+		IN_Grabm (1);
+	}
+	else
+	{
+		M_ForceMenuOff ();
+		cls.key_dest = key_console;	
+
+		if (Cvar_VariableValue ("maxclients") == 1 
+			&& Com_ServerState ())
+			Cvar_Set ("paused", "1");
+		IN_Grabm (0);
+	}
+}
+
+/*
+================
+Con_ToggleChat_f
+================
+*/
+void Con_ToggleChat_f (void)
+{
+	Key_ClearTyping ();
+
+	if (cls.key_dest == key_console)
+	{
+		if (cls.state == ca_active)
+		{
+			M_ForceMenuOff ();
+			cls.key_dest = key_game;
+		}
+	}
+	else
+		cls.key_dest = key_console;
+	
+	Con_ClearNotify ();
+}
+
+/*
+================
+Con_Clear_f
+================
+*/
+void Con_Clear_f (void)
+{
+	memset (con.text, ' ', CON_TEXTSIZE);
+}
+
+						
+/*
+================
+Con_Dump_f
+
+Save the console contents out to a file
+================
+*/
+void Con_Dump_f (void)
+{
+	int		l, x;
+	char	*line;
+	FILE	*f;
+	char	buffer[1024];
+	char	name[MAX_OSPATH];
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("usage: condump <filename>\n");
+		return;
+	}
+
+	Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1));
+
+	Com_Printf ("Dumped console text to %s.\n", name);
+	FS_CreatePath (name);
+	f = fopen (name, "w");
+	if (!f)
+	{
+		Com_Printf ("ERROR: couldn't open.\n");
+		return;
+	}
+
+	// skip empty lines
+	for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
+	{
+		line = con.text + (l%con.totallines)*con.linewidth;
+		for (x=0 ; x<con.linewidth ; x++)
+			if (line[x] != ' ')
+				break;
+		if (x != con.linewidth)
+			break;
+	}
+
+	// write the remaining lines
+	buffer[con.linewidth] = 0;
+	for ( ; l <= con.current ; l++)
+	{
+		line = con.text + (l%con.totallines)*con.linewidth;
+		strncpy (buffer, line, con.linewidth);
+		for (x=con.linewidth-1 ; x>=0 ; x--)
+		{
+			if (buffer[x] == ' ')
+				buffer[x] = 0;
+			else
+				break;
+		}
+		for (x=0; buffer[x]; x++)
+			buffer[x] &= 0x7f;
+
+		fprintf (f, "%s\n", buffer);
+	}
+
+	fclose (f);
+}
+
+						
+/*
+================
+Con_ClearNotify
+================
+*/
+void Con_ClearNotify (void)
+{
+	int		i;
+	
+	for (i=0 ; i<NUM_CON_TIMES ; i++)
+		con.times[i] = 0;
+}
+
+						
+/*
+================
+Con_MessageMode_f
+================
+*/
+void Con_MessageMode_f (void)
+{
+	chat_team = false;
+	cls.key_dest = key_message;
+}
+
+/*
+================
+Con_MessageMode2_f
+================
+*/
+void Con_MessageMode2_f (void)
+{
+	chat_team = true;
+	cls.key_dest = key_message;
+}
+
+/*
+================
+Con_CheckResize
+
+If the line width has changed, reformat the buffer.
+================
+*/
+void Con_CheckResize (void)
+{
+	int		i, j, width, oldwidth, oldtotallines, numlines, numchars;
+	char	tbuf[CON_TEXTSIZE];
+
+	width = (vid.width >> 3) - 2;
+
+	if (width == con.linewidth)
+		return;
+
+	if (width < 1)			// video hasn't been initialized yet
+	{
+		width = 38;
+		con.linewidth = width;
+		con.totallines = CON_TEXTSIZE / con.linewidth;
+		memset (con.text, ' ', CON_TEXTSIZE);
+	}
+	else
+	{
+		oldwidth = con.linewidth;
+		con.linewidth = width;
+		oldtotallines = con.totallines;
+		con.totallines = CON_TEXTSIZE / con.linewidth;
+		numlines = oldtotallines;
+
+		if (con.totallines < numlines)
+			numlines = con.totallines;
+
+		numchars = oldwidth;
+	
+		if (con.linewidth < numchars)
+			numchars = con.linewidth;
+
+		memcpy (tbuf, con.text, CON_TEXTSIZE);
+		memset (con.text, ' ', CON_TEXTSIZE);
+
+		for (i=0 ; i<numlines ; i++)
+		{
+			for (j=0 ; j<numchars ; j++)
+			{
+				con.text[(con.totallines - 1 - i) * con.linewidth + j] =
+						tbuf[((con.current - i + oldtotallines) %
+							  oldtotallines) * oldwidth + j];
+			}
+		}
+
+		Con_ClearNotify ();
+	}
+
+	con.current = con.totallines - 1;
+	con.display = con.current;
+}
+
+
+/*
+================
+Con_Init
+================
+*/
+void Con_Init (void)
+{
+	con.linewidth = -1;
+
+	Con_CheckResize ();
+	
+	Com_Printf ("Console initialized.\n");
+
+//
+// register our commands
+//
+	con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
+
+	Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
+	Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
+	Cmd_AddCommand ("messagemode", Con_MessageMode_f);
+	Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
+	Cmd_AddCommand ("clear", Con_Clear_f);
+	Cmd_AddCommand ("condump", Con_Dump_f);
+	con.initialized = true;
+}
+
+
+/*
+===============
+Con_Linefeed
+===============
+*/
+void Con_Linefeed (void)
+{
+	con.x = 0;
+	if (con.display == con.current)
+		con.display++;
+	con.current++;
+	memset (&con.text[(con.current%con.totallines)*con.linewidth]
+	, ' ', con.linewidth);
+}
+
+/*
+================
+Con_Print
+
+Handles cursor positioning, line wrapping, etc
+All console printing must go through this in order to be logged to disk
+If no console is visible, the text will appear at the top of the game window
+================
+*/
+void Con_Print (char *txt)
+{
+	int		y;
+	int		c, l;
+	static int	cr;
+	int		mask;
+
+	if (!con.initialized)
+		return;
+
+	if (txt[0] == 1 || txt[0] == 2)
+	{
+		mask = 128;		// go to colored text
+		txt++;
+	}
+	else
+		mask = 0;
+
+
+	while ( (c = *txt) )
+	{
+	// count word length
+		for (l=0 ; l< con.linewidth ; l++)
+			if ( txt[l] <= ' ')
+				break;
+
+	// word wrap
+		if (l != con.linewidth && (con.x + l > con.linewidth) )
+			con.x = 0;
+
+		txt++;
+
+		if (cr)
+		{
+			con.current--;
+			cr = false;
+		}
+
+		
+		if (!con.x)
+		{
+			Con_Linefeed ();
+		// mark time for transparent overlay
+			if (con.current >= 0)
+				con.times[con.current % NUM_CON_TIMES] = cls.realtime;
+		}
+
+		switch (c)
+		{
+		case '\n':
+			con.x = 0;
+			break;
+
+		case '\r':
+			con.x = 0;
+			cr = 1;
+			break;
+
+		default:	// display character and advance
+			y = con.current % con.totallines;
+			con.text[y*con.linewidth+con.x] = c | mask | con.ormask;
+			con.x++;
+			if (con.x >= con.linewidth)
+				con.x = 0;
+			break;
+		}
+		
+	}
+}
+
+
+/*
+==============
+Con_CenteredPrint
+==============
+*/
+void Con_CenteredPrint (char *text)
+{
+	int		l;
+	char	buffer[1024];
+
+	l = strlen(text);
+	l = (con.linewidth-l)/2;
+	if (l < 0)
+		l = 0;
+	memset (buffer, ' ', l);
+	strcpy (buffer+l, text);
+	strcat (buffer, "\n");
+	Con_Print (buffer);
+}
+
+/*
+==============================================================================
+
+DRAWING
+
+==============================================================================
+*/
+
+
+/*
+================
+Con_DrawInput
+
+The input line scrolls horizontally if typing goes beyond the right edge
+================
+*/
+void Con_DrawInput (void)
+{
+	int		i;
+	char	*text;
+
+	if (cls.key_dest == key_menu)
+		return;
+	if (cls.key_dest != key_console && cls.state == ca_active)
+		return;		// don't draw anything (always draw if not active)
+
+	text = key_lines[edit_line];
+	
+// add the cursor frame
+	text[key_linepos] = 10+((int)(cls.realtime>>8)&1);
+	
+// fill out remainder with spaces
+	for (i=key_linepos+1 ; i< con.linewidth ; i++)
+		text[i] = ' ';
+		
+//	prestep if horizontally scrolling
+	if (key_linepos >= con.linewidth)
+		text += 1 + key_linepos - con.linewidth;
+		
+// draw it
+	for (i=0 ; i<con.linewidth ; i++)
+		re.DrawChar ( (i+1)<<3, con.vislines - 22, text[i]);
+
+// remove cursor
+	key_lines[edit_line][key_linepos] = 0;
+}
+
+
+/*
+================
+Con_DrawNotify
+
+Draws the last few lines of output transparently over the game top
+================
+*/
+void Con_DrawNotify (void)
+{
+	int		x, v;
+	char	*text;
+	int		i;
+	int		time;
+	char	*s;
+	int		skip;
+
+	v = 0;
+	for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
+	{
+		if (i < 0)
+			continue;
+		time = con.times[i % NUM_CON_TIMES];
+		if (time == 0)
+			continue;
+		time = cls.realtime - time;
+		if (time > con_notifytime->value*1000)
+			continue;
+		text = con.text + (i % con.totallines)*con.linewidth;
+		
+		for (x = 0 ; x < con.linewidth ; x++)
+			re.DrawChar ( (x+1)<<3, v, text[x]);
+
+		v += 8;
+	}
+
+
+	if (cls.key_dest == key_message)
+	{
+		if (chat_team)
+		{
+			DrawString (8, v, "say_team:");
+			skip = 11;
+		}
+		else
+		{
+			DrawString (8, v, "say:");
+			skip = 5;
+		}
+
+		s = chat_buffer;
+		if (chat_bufferlen > (vid.width>>3)-(skip+1))
+			s += chat_bufferlen - ((vid.width>>3)-(skip+1));
+		x = 0;
+		while(s[x])
+		{
+			re.DrawChar ( (x+skip)<<3, v, s[x]);
+			x++;
+		}
+		re.DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1));
+		v += 8;
+	}
+	
+	if (v)
+	{
+		SCR_AddDirtyPoint (0,0);
+		SCR_AddDirtyPoint (vid.width-1, v);
+	}
+}
+
+/*
+================
+Con_DrawConsole
+
+Draws the console with the solid background
+================
+*/
+void Con_DrawConsole (float frac)
+{
+	int				i, j, x, y, n;
+	int				rows;
+	char			*text;
+	int				row;
+	int				lines;
+	char			version[64];
+	char			dlbar[1024];
+
+	lines = vid.height * frac;
+	if (lines <= 0)
+		return;
+
+	if (lines > vid.height)
+		lines = vid.height;
+
+// draw the background
+	re.DrawStretchPic (0, -vid.height+lines, vid.width, vid.height, "conback");
+	SCR_AddDirtyPoint (0,0);
+	SCR_AddDirtyPoint (vid.width-1,lines-1);
+
+	Com_sprintf (version, sizeof(version), "v%4.2f", VERSION);
+	for (x=0 ; x<5 ; x++)
+		re.DrawChar (vid.width-44+x*8, lines-12, 128 + version[x] );
+
+// draw the text
+	con.vislines = lines;
+	
+/*
+	rows = (lines-8)>>3;		// rows of text to draw
+
+	y = lines - 24;
+*/
+	rows = (lines-22)>>3;		// rows of text to draw
+
+	y = lines - 30;
+
+// draw from the bottom up
+	if (con.display != con.current)
+	{
+	// draw arrows to show the buffer is backscrolled
+		for (x=0 ; x<con.linewidth ; x+=4)
+			re.DrawChar ( (x+1)<<3, y, '^');
+	
+		y -= 8;
+		rows--;
+	}
+	
+	row = con.display;
+	for (i=0 ; i<rows ; i++, y-=8, row--)
+	{
+		if (row < 0)
+			break;
+		if (con.current - row >= con.totallines)
+			break;		// past scrollback wrap point
+			
+		text = con.text + (row % con.totallines)*con.linewidth;
+
+		for (x=0 ; x<con.linewidth ; x++)
+			re.DrawChar ( (x+1)<<3, y, text[x]);
+	}
+
+//ZOID
+	// draw the download bar
+	// figure out width
+	if (cls.download) {
+		if ((text = strrchr(cls.downloadname, '/')) != NULL)
+			text++;
+		else
+			text = cls.downloadname;
+
+		x = con.linewidth - ((con.linewidth * 7) / 40);
+		y = x - strlen(text) - 8;
+		i = con.linewidth/3;
+		if (strlen(text) > i) {
+			y = x - i - 11;
+			strncpy(dlbar, text, i);
+			dlbar[i] = 0;
+			strcat(dlbar, "...");
+		} else
+			strcpy(dlbar, text);
+		strcat(dlbar, ": ");
+		i = strlen(dlbar);
+		dlbar[i++] = 0x80;
+		// where's the dot go?
+		if (cls.downloadpercent == 0)
+			n = 0;
+		else
+			n = y * cls.downloadpercent / 100;
+			
+		for (j = 0; j < y; j++)
+			if (j == n)
+				dlbar[i++] = 0x83;
+			else
+				dlbar[i++] = 0x81;
+		dlbar[i++] = 0x82;
+		dlbar[i] = 0;
+
+		sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
+
+		// draw it
+		y = con.vislines-12;
+		for (i = 0; i < strlen(dlbar); i++)
+			re.DrawChar ( (i+1)<<3, y, dlbar[i]);
+	}
+//ZOID
+
+// draw the input prompt, user text, and cursor if desired
+	Con_DrawInput ();
+}
--- /dev/null
+++ b/crc.c
@@ -1,0 +1,75 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
+// and the initial and final xor values shown below...  in other words, the
+// CCITT standard CRC used by XMODEM
+
+#define CRC_INIT_VALUE	0xffff
+#define CRC_XOR_VALUE	0x0000
+
+static unsigned short crctable[256] =
+{
+	0x0000,	0x1021,	0x2042,	0x3063,	0x4084,	0x50a5,	0x60c6,	0x70e7,
+	0x8108,	0x9129,	0xa14a,	0xb16b,	0xc18c,	0xd1ad,	0xe1ce,	0xf1ef,
+	0x1231,	0x0210,	0x3273,	0x2252,	0x52b5,	0x4294,	0x72f7,	0x62d6,
+	0x9339,	0x8318,	0xb37b,	0xa35a,	0xd3bd,	0xc39c,	0xf3ff,	0xe3de,
+	0x2462,	0x3443,	0x0420,	0x1401,	0x64e6,	0x74c7,	0x44a4,	0x5485,
+	0xa56a,	0xb54b,	0x8528,	0x9509,	0xe5ee,	0xf5cf,	0xc5ac,	0xd58d,
+	0x3653,	0x2672,	0x1611,	0x0630,	0x76d7,	0x66f6,	0x5695,	0x46b4,
+	0xb75b,	0xa77a,	0x9719,	0x8738,	0xf7df,	0xe7fe,	0xd79d,	0xc7bc,
+	0x48c4,	0x58e5,	0x6886,	0x78a7,	0x0840,	0x1861,	0x2802,	0x3823,
+	0xc9cc,	0xd9ed,	0xe98e,	0xf9af,	0x8948,	0x9969,	0xa90a,	0xb92b,
+	0x5af5,	0x4ad4,	0x7ab7,	0x6a96,	0x1a71,	0x0a50,	0x3a33,	0x2a12,
+	0xdbfd,	0xcbdc,	0xfbbf,	0xeb9e,	0x9b79,	0x8b58,	0xbb3b,	0xab1a,
+	0x6ca6,	0x7c87,	0x4ce4,	0x5cc5,	0x2c22,	0x3c03,	0x0c60,	0x1c41,
+	0xedae,	0xfd8f,	0xcdec,	0xddcd,	0xad2a,	0xbd0b,	0x8d68,	0x9d49,
+	0x7e97,	0x6eb6,	0x5ed5,	0x4ef4,	0x3e13,	0x2e32,	0x1e51,	0x0e70,
+	0xff9f,	0xefbe,	0xdfdd,	0xcffc,	0xbf1b,	0xaf3a,	0x9f59,	0x8f78,
+	0x9188,	0x81a9,	0xb1ca,	0xa1eb,	0xd10c,	0xc12d,	0xf14e,	0xe16f,
+	0x1080,	0x00a1,	0x30c2,	0x20e3,	0x5004,	0x4025,	0x7046,	0x6067,
+	0x83b9,	0x9398,	0xa3fb,	0xb3da,	0xc33d,	0xd31c,	0xe37f,	0xf35e,
+	0x02b1,	0x1290,	0x22f3,	0x32d2,	0x4235,	0x5214,	0x6277,	0x7256,
+	0xb5ea,	0xa5cb,	0x95a8,	0x8589,	0xf56e,	0xe54f,	0xd52c,	0xc50d,
+	0x34e2,	0x24c3,	0x14a0,	0x0481,	0x7466,	0x6447,	0x5424,	0x4405,
+	0xa7db,	0xb7fa,	0x8799,	0x97b8,	0xe75f,	0xf77e,	0xc71d,	0xd73c,
+	0x26d3,	0x36f2,	0x0691,	0x16b0,	0x6657,	0x7676,	0x4615,	0x5634,
+	0xd94c,	0xc96d,	0xf90e,	0xe92f,	0x99c8,	0x89e9,	0xb98a,	0xa9ab,
+	0x5844,	0x4865,	0x7806,	0x6827,	0x18c0,	0x08e1,	0x3882,	0x28a3,
+	0xcb7d,	0xdb5c,	0xeb3f,	0xfb1e,	0x8bf9,	0x9bd8,	0xabbb,	0xbb9a,
+	0x4a75,	0x5a54,	0x6a37,	0x7a16,	0x0af1,	0x1ad0,	0x2ab3,	0x3a92,
+	0xfd2e,	0xed0f,	0xdd6c,	0xcd4d,	0xbdaa,	0xad8b,	0x9de8,	0x8dc9,
+	0x7c26,	0x6c07,	0x5c64,	0x4c45,	0x3ca2,	0x2c83,	0x1ce0,	0x0cc1,
+	0xef1f,	0xff3e,	0xcf5d,	0xdf7c,	0xaf9b,	0xbfba,	0x8fd9,	0x9ff8,
+	0x6e17,	0x7e36,	0x4e55,	0x5e74,	0x2e93,	0x3eb2,	0x0ed1,	0x1ef0
+};
+
+void CRC_Init(unsigned short *crcvalue)
+{
+	*crcvalue = CRC_INIT_VALUE;
+}
+
+void CRC_ProcessByte(unsigned short *crcvalue, byte data)
+{
+	*crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
+}
+
+unsigned short CRC_Value(unsigned short crcvalue)
+{
+	return crcvalue ^ CRC_XOR_VALUE;
+}
+
+unsigned short CRC_Block (byte *start, int count)
+{
+	unsigned short	crc;
+
+	CRC_Init (&crc);
+	while (count--)
+		crc = (crc << 8) ^ crctable[(crc >> 8) ^ *start++];
+
+	return crc;
+}
+
--- a/ctf/g_ai.c
+++ b/ctf/g_ai.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 qboolean FindTarget (edict_t *self);
 extern cvar_t	*maxclients;
--- a/ctf/g_chase.c
+++ b/ctf/g_chase.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 
 void UpdateChaseCam(edict_t *ent)
--- a/ctf/g_cmds.c
+++ b/ctf/g_cmds.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 #include "m_player.h"
 
 
--- a/ctf/g_combat.c
+++ b/ctf/g_combat.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 /*
 ============
--- a/ctf/g_ctf.c
+++ b/ctf/g_ctf.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 #include "m_player.h"
 
 typedef enum match_s {
--- a/ctf/g_func.c
+++ b/ctf/g_func.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 /*
 =========================================================
--- a/ctf/g_items.c
+++ b/ctf/g_items.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 
 qboolean	Pickup_Weapon (edict_t *ent, edict_t *other);
--- a/ctf/g_main.c
+++ b/ctf/g_main.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 game_locals_t	game;
 level_locals_t	level;
--- a/ctf/g_misc.c
+++ b/ctf/g_misc.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 
 /*QUAKED func_group (0 0 0) ?
--- a/ctf/g_monster.c
+++ b/ctf/g_monster.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 
 //
--- a/ctf/g_phys.c
+++ b/ctf/g_phys.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 /*
 
--- a/ctf/g_save.c
+++ b/ctf/g_save.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 field_t fields[] = {
 	{"classname", FOFS(classname), F_LSTRING},
--- a/ctf/g_spawn.c
+++ b/ctf/g_spawn.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 typedef struct
 {
--- a/ctf/g_svcmds.c
+++ b/ctf/g_svcmds.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 
 void	Svcmd_Test_f (void)
--- a/ctf/g_target.c
+++ b/ctf/g_target.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 /*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8)
 Fire an origin based temp entity event to the clients.
--- a/ctf/g_trigger.c
+++ b/ctf/g_trigger.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 
 void InitTrigger (edict_t *self)
--- a/ctf/g_utils.c
+++ b/ctf/g_utils.c
@@ -1,8 +1,9 @@
+#include <u.h>
+#include <libc.h>
 // g_utils.c -- misc utility functions for game module
 
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 
 void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
--- a/ctf/g_weapon.c
+++ b/ctf/g_weapon.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 
 /*
--- a/ctf/m_move.c
+++ b/ctf/m_move.c
@@ -1,8 +1,9 @@
+#include <u.h>
+#include <libc.h>
 // m_move.c -- monster movement
 
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 #define	STEPSIZE	18
 
--- a/ctf/p_client.c
+++ b/ctf/p_client.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 #include "m_player.h"
 
 void ClientUserinfoChanged (edict_t *ent, char *userinfo);
--- a/ctf/p_hud.c
+++ b/ctf/p_hud.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 
 
--- a/ctf/p_menu.c
+++ b/ctf/p_menu.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 // Note that the pmenu entries are duplicated
 // this is so that a static set of pmenu entries can be used
--- a/ctf/p_trail.c
+++ b/ctf/p_trail.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 
 
 /*
--- a/ctf/p_view.c
+++ b/ctf/p_view.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 #include "m_player.h"
 
 
--- a/ctf/p_weapon.c
+++ b/ctf/p_weapon.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
-#include "g_local.h"
 #include "m_player.h"
 
 
--- a/ctf/q_shared.c
+++ b/ctf/q_shared.c
@@ -1,3 +1,5 @@
+#include <u.h>
+#include <libc.h>
 #include "../dat.h"
 #include "../fns.h"
 
@@ -249,7 +251,7 @@
 
 
 // this is the slow, general version
-int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, cplane_t *p)
 {
 	int		i;
 	float	dist1, dist2;
@@ -287,7 +289,7 @@
 Returns 1, 2, or 1 + 2
 ==================
 */
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, cplane_t *p)
 {
 	float	dist1, dist2;
 	int		sides;
--- /dev/null
+++ b/cvar.c
@@ -1,0 +1,387 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/* Dynamic variable tracking
+ *
+ * cvar_t variables are used to hold scalar or string variables that can be
+ * changed or displayed at the console or prog code as well as accessed
+ * directly in C code. The user can access cvars from the console in three ways:
+ * r_draworder		prints the current value
+ * r_draworder 0	sets the current value to 0
+ * set r_draworder 0	as above, but creates the cvar if not present
+ * Cvars are restricted from having the same names as commands to keep this
+ * interface from being ambiguous. */
+
+cvar_t *cvar_vars;
+
+/* if set, each time a CVAR_USERINFO var is changed, the client will send it
+ * to the server */
+qboolean userinfo_modified;
+
+
+static qboolean
+Cvar_InfoValidate(char *s)
+{
+	if(strstr(s, "\\"))
+		return false;
+	if(strstr(s, "\""))
+		return false;
+	if(strstr(s, ";"))
+		return false;
+	return true;
+}
+
+static cvar_t *
+Cvar_FindVar(char *name)
+{
+	cvar_t *p;
+
+	for(p = cvar_vars; p != nil; p = p->next)
+		if(!strcmp(name, p->name))
+			return p;
+	return nil;
+}
+
+float
+Cvar_VariableValue(char *name)
+{
+	cvar_t *p;
+	
+	if((p = Cvar_FindVar(name)) == nil)
+		return 0;
+	return atof(p->string);
+}
+
+char *
+Cvar_VariableString(char *name)
+{
+	cvar_t *p;
+
+	if((p = Cvar_FindVar(name)) == nil)
+		return "";
+	return p->string;
+}
+
+char *
+Cvar_CompleteVariable(char *partial)
+{
+	cvar_t *p;
+	int len;
+
+	len = strlen(partial);
+	if(!len)
+		return nil;
+
+	/* check exact match */
+	for(p = cvar_vars; p != nil; p = p->next)
+		if(!strcmp(partial, p->name))
+			return p->name;
+	/* check partial match */
+	for(p = cvar_vars; p != nil; p = p->next)
+		if(!strncmp(partial, p->name, len))
+			return p->name;
+	return nil;
+}
+
+/* If the variable already exists, the value will not be set. The flags will be
+ * or'ed in if the variable exists. */
+cvar_t *
+Cvar_Get(char *var_name, char *var_value, int flags)
+{
+	cvar_t *p;
+	
+	if(flags & (CVAR_USERINFO|CVAR_SERVERINFO)){
+		if(!Cvar_InfoValidate(var_name)){
+			Com_Printf("invalid info cvar name\n");
+			return nil;
+		}
+	}
+
+	if((p = Cvar_FindVar(var_name)) != nil){
+		p->flags |= flags;
+		return p;
+	}
+
+	if(!var_value)
+		return nil;
+
+	if(flags & (CVAR_USERINFO|CVAR_SERVERINFO)){
+		if(!Cvar_InfoValidate(var_value)){
+			Com_Printf("invalid info cvar value\n");
+			return nil;
+		}
+	}
+
+	p = Z_Malloc(sizeof(*p));
+	p->name = CopyString(var_name);
+	p->string = CopyString(var_value);
+	p->modified = true;
+	p->value = atof(p->string);
+	p->next = cvar_vars;
+	cvar_vars = p;
+	p->flags = flags;
+	return p;
+}
+
+cvar_t *
+Cvar_Set2(char *var_name, char *value, qboolean force)
+{
+	cvar_t *var;
+
+	var = Cvar_FindVar(var_name);
+	if(!var)
+		return Cvar_Get(var_name, value, 0);	// create it
+
+	if(var->flags & (CVAR_USERINFO|CVAR_SERVERINFO)){
+		if(!Cvar_InfoValidate(value)){
+			Com_Printf("invalid info cvar value\n");
+			return var;
+		}
+	}
+	if(!force){
+		if(var->flags & CVAR_NOSET){
+			Com_Printf("%s is write protected.\n", var_name);
+			return var;
+		}
+		if(var->flags & CVAR_LATCH){
+			if(var->latched_string){
+				if(!strcmp(value, var->latched_string))
+					return var;
+				Z_Free(var->latched_string);
+			}else if(!strcmp(value, var->string))
+					return var;
+
+			if(Com_ServerState()){
+				Com_Printf("%s will be changed for next game.\n", var_name);
+				var->latched_string = CopyString(value);
+			}else{
+				var->string = CopyString(value);
+				var->value = atof(var->string);
+				if(!strcmp(var->name, "game")){
+					FS_SetGamedir(var->string);
+					FS_ExecAutoexec();
+				}
+			}
+			return var;
+		}
+	}else{
+		if(var->latched_string){
+			Z_Free(var->latched_string);
+			var->latched_string = nil;
+		}
+	}
+
+	if(!strcmp(value, var->string))
+		return var;	// not changed
+
+	var->modified = true;
+
+	if(var->flags & CVAR_USERINFO)
+		userinfo_modified = true;	// transmit at next oportunity
+	
+	Z_Free(var->string);	// free the old value string
+	var->string = CopyString(value);
+	var->value = atof(var->string);
+	return var;
+}
+
+/* set the variable even if NOSET or LATCH */
+cvar_t *
+Cvar_ForceSet(char *var_name, char *value)
+{
+	return Cvar_Set2(var_name, value, true);
+}
+
+cvar_t *
+Cvar_Set(char *var_name, char *value)
+{
+	return Cvar_Set2(var_name, value, false);
+}
+
+cvar_t *
+Cvar_FullSet(char *var_name, char *value, int flags)
+{
+	cvar_t *var;
+	
+	var = Cvar_FindVar(var_name);
+	if(!var)
+		return Cvar_Get(var_name, value, flags);	// create it
+
+	var->modified = true;
+
+	if(var->flags & CVAR_USERINFO)
+		userinfo_modified = true;	// transmit at next oportunity
+
+	Z_Free(var->string);	// free the old value string
+	var->string = CopyString(value);
+	var->value = atof(var->string);
+	var->flags = flags;
+	return var;
+}
+
+void
+Cvar_SetValue(char *var_name, float value)
+{
+	char val[32];
+
+	if(value == (int)value)
+		Com_sprintf(val, sizeof val, "%d", (int)value);
+	else
+		Com_sprintf(val, sizeof val, "%f", value);
+	Cvar_Set(var_name, val);
+}
+
+/* Any variables with latched values will now be updated */
+void
+Cvar_GetLatchedVars(void)
+{
+	cvar_t *p;
+
+	for(p = cvar_vars; p != nil; p = p->next){
+		if(!p->latched_string)
+			continue;
+		Z_Free(p->string);
+		p->string = p->latched_string;
+		p->latched_string = nil;
+		p->value = atof(p->string);
+		if(!strcmp(p->name, "game")){
+			FS_SetGamedir(p->string);
+			FS_ExecAutoexec();
+		}
+	}
+}
+
+/* called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known command.
+ * Returns true if the command was a variable reference that was handled (print
+ * or change). */
+qboolean
+Cvar_Command(void)
+{
+	cvar_t *p;
+
+	/* check variables */
+	if((p = Cvar_FindVar(Cmd_Argv(0))) == nil)
+		return false;
+
+	/* perform a variable print or set */
+	if(Cmd_Argc() == 1){
+		Com_Printf("\"%s\" is \"%s\"\n", p->name, p->string);
+		return true;
+	}
+
+	Cvar_Set(p->name, Cmd_Argv(1));
+	return true;
+}
+
+/* Allows setting and defining of arbitrary cvars from console */
+void
+Cvar_Set_f(void)
+{
+	int c;
+	int flags;
+
+	c = Cmd_Argc();
+	if(c != 3 && c != 4){
+		Com_Printf("usage: set <variable> <value> [u / s]\n");
+		return;
+	}
+	if(c == 4){
+		if(!strcmp(Cmd_Argv(3), "u"))
+			flags = CVAR_USERINFO;
+		else if(!strcmp(Cmd_Argv(3), "s"))
+			flags = CVAR_SERVERINFO;
+		else{
+			Com_Printf("flags can only be 'u' or 's'\n");
+			return;
+		}
+		Cvar_FullSet(Cmd_Argv(1), Cmd_Argv(2), flags);
+	}else
+		Cvar_Set(Cmd_Argv(1), Cmd_Argv(2));
+}
+
+/* Appends lines containing "set variable value" for all variables with the
+ * archive flag set to true. */
+void
+Cvar_WriteVariables(char *path)
+{
+	int fd;
+	cvar_t *p;
+
+	if((fd = open(path, OWRITE)) < 0){
+		fprint(2, "Cvar_WriteVariables:open: %r\n");
+		return;
+	}
+	seek(fd, 0, 2);
+	for(p = cvar_vars; p != nil; p = p->next)
+		if(p->flags & CVAR_ARCHIVE)
+			if(fprint(fd, "set %s \"%s\"\n", p->name, p->string) < 0)
+				sysfatal("Cvar_WriteVariables:fprint: %r");
+	close(fd);
+}
+
+void
+Cvar_List_f(void)
+{
+	cvar_t *p;
+	int i;
+
+	for(p = cvar_vars, i = 0; p != nil; p = p->next, i++){
+		if(p->flags & CVAR_ARCHIVE)
+			Com_Printf("*");
+		else
+			Com_Printf(" ");
+		if(p->flags & CVAR_USERINFO)
+			Com_Printf("U");
+		else
+			Com_Printf(" ");
+		if(p->flags & CVAR_SERVERINFO)
+			Com_Printf("S");
+		else
+			Com_Printf(" ");
+		if(p->flags & CVAR_NOSET)
+			Com_Printf("-");
+		else if(p->flags & CVAR_LATCH)
+			Com_Printf("L");
+		else
+			Com_Printf(" ");
+		Com_Printf(" %s \"%s\"\n", p->name, p->string);
+	}
+	Com_Printf("%d cvars\n", i);
+}
+
+char *
+Cvar_BitInfo(int bit)
+{
+	static char info[MAX_INFO_STRING];
+	cvar_t *p;
+
+	info[0] = 0;
+	for(p = cvar_vars; p != nil; p = p->next)
+		if(p->flags & bit)
+			Info_SetValueForKey(info, p->name, p->string);
+	return info;
+}
+
+/* returns an info string containing all the CVAR_USERINFO cvars */
+char *
+Cvar_Userinfo(void)
+{
+	return Cvar_BitInfo(CVAR_USERINFO);
+}
+
+/* returns an info string containing all the CVAR_SERVERINFO cvars */
+char *
+Cvar_Serverinfo(void)
+{
+	return Cvar_BitInfo(CVAR_SERVERINFO);
+}
+
+void
+Cvar_Init(void)
+{
+	Cmd_AddCommand("set", Cvar_Set_f);
+	Cmd_AddCommand("cvarlist", Cvar_List_f);
+}
--- /dev/null
+++ b/dat.h
@@ -1,0 +1,2931 @@
+//#define PARANOID	// speed sapping error checking
+//#define SMALL_FINALVERT
+
+typedef uchar byte;
+typedef float vec_t;
+typedef vec_t vec3_t[3];
+typedef vec_t vec5_t[5];
+typedef	int fixed4_t;
+typedef	int fixed8_t;
+typedef	int fixed16_t;
+typedef uchar pixel_t;
+
+typedef enum qboolean {false, true} qboolean;
+
+typedef struct edict_t edict_t;
+typedef struct cvar_t cvar_t;
+typedef struct cplane_t cplane_t;
+typedef struct cmodel_t cmodel_t;
+typedef struct csurface_t csurface_t;
+typedef struct mapsurface_t mapsurface_t;
+typedef struct trace_t trace_t;
+typedef struct pmove_state_t pmove_state_t;
+typedef struct usercmd_t usercmd_t;
+typedef struct pmove_t pmove_t;
+typedef struct entity_state_t entity_state_t;
+typedef struct player_state_t player_state_t;
+typedef struct sizebuf_t sizebuf_t;
+typedef struct netadr_t netadr_t;
+typedef struct netchan_t netchan_t;
+typedef struct dpackfile_t dpackfile_t;
+typedef struct dpackheader_t dpackheader_t;
+typedef struct pcx_t pcx_t;
+typedef struct dstvert_t dstvert_t;
+typedef struct dtriangle_t dtriangle_t;
+typedef struct dtrivertx_t dtrivertx_t;
+typedef struct daliasframe_t daliasframe_t;
+typedef struct dmdl_t dmdl_t;
+typedef struct dsprframe_t dsprframe_t;
+typedef struct dsprite_t dsprite_t;
+typedef struct miptex_t miptex_t;
+typedef struct lump_t lump_t;
+typedef struct dheader_t dheader_t;
+typedef struct dmodel_t dmodel_t;
+typedef struct dvertex_t dvertex_t;
+typedef struct dplane_t dplane_t;
+typedef struct dnode_t dnode_t;
+typedef struct texinfo_t texinfo_t;
+typedef struct dedge_t dedge_t;
+typedef struct dface_t dface_t;
+typedef struct dleaf_t dleaf_t;
+typedef struct dbrushside_t dbrushside_t;
+typedef struct dbrush_t dbrush_t;
+typedef struct dvis_t dvis_t;
+typedef struct dareaportal_t dareaportal_t;
+typedef struct darea_t darea_t;
+typedef struct vrect_t vrect_t;
+typedef struct viddef_t viddef_t;
+typedef struct image_t image_t;
+typedef struct oldrefdef_t oldrefdef_t;
+typedef struct mvertex_t mvertex_t;
+typedef struct mplane_t mplane_t;
+typedef struct medge_t medge_t;
+typedef struct mtexinfo_t mtexinfo_t;
+typedef struct msurface_t msurface_t;
+typedef struct mnode_t mnode_t;
+typedef struct mleaf_t mleaf_t;
+typedef struct model_t model_t;
+typedef struct emitpoint_t emitpoint_t;
+typedef struct finalvert_t finalvert_t;
+typedef struct affinetridesc_t affinetridesc_t;
+typedef struct drawsurf_t drawsurf_t;
+typedef struct alight_t alight_t;
+typedef struct bedge_t bedge_t;
+typedef struct clipplane_t clipplane_t;
+typedef struct surfcache_t surfcache_t;
+typedef struct espan_t espan_t;
+typedef struct polydesc_t polydesc_t;
+typedef struct surf_t surf_t;
+typedef struct edge_t edge_t;
+typedef struct aliastriangleparms_t aliastriangleparms_t;
+typedef struct swstate_t swstate_t;
+typedef struct entity_t entity_t;
+typedef struct dlight_t dlight_t;
+typedef struct particle_t particle_t;
+typedef struct lightstyle_t lightstyle_t;
+typedef struct refdef_t refdef_t;
+typedef struct refexport_t refexport_t;
+typedef struct refimport_t refimport_t;
+typedef struct portable_samplepair_t portable_samplepair_t;
+typedef struct sfxcache_t sfxcache_t;
+typedef struct sfx_t sfx_t;
+typedef struct playsound_t playsound_t;
+typedef struct dma_t dma_t;
+typedef struct channel_t channel_t;
+typedef struct wavinfo_t wavinfo_t;
+typedef struct console_t console_t;
+typedef struct frame_t frame_t;
+typedef struct centity_t centity_t;
+typedef struct clientinfo_t clientinfo_t;
+typedef struct client_state_t client_state_t;
+typedef struct client_static_t client_static_t;
+typedef struct cdlight_t cdlight_t;
+typedef struct cl_sustain_t cl_sustain_t;
+typedef struct cparticle_t cparticle_t;
+typedef struct kbutton_t kbutton_t;
+typedef struct menuframework_t menuframework_t;
+typedef struct menucommon_t menucommon_t;
+typedef struct menufield_t menufield_t;
+typedef struct menuslider_t menuslider_t;
+typedef struct menulist_t menulist_t;
+typedef struct menuaction_t menuaction_t;
+typedef struct menuseparator_t menuseparator_t;
+typedef struct server_t server_t;
+typedef struct client_frame_t client_frame_t;
+typedef struct client_t client_t;
+typedef struct challenge_t challenge_t;
+typedef struct server_static_t server_static_t;
+
+typedef void	(*xcommand_t)(void);
+typedef	refexport_t	(*GetRefAPI_t)(refimport_t);
+
+enum{
+	/* angle indexes */
+	PITCH = 0,
+	YAW = 1,
+	ROLL = 2,
+
+	MAX_STRING_CHARS = 1024,	// char* passed to Cmd_TokenizeString, max strlen
+	MAX_STRING_TOKENS = 80,	// max tokens resulting from Cmd_TokenizeString
+	MAX_TOKEN_CHARS = 128,	// max length of an individual token
+
+	/* max length of quake game and fs pathname */
+	MAX_QPATH = 64,
+	MAX_OSPATH = 128,
+
+	/* per-level limits */
+	MAX_CLIENTS = 256,	// absolute limit
+	MAX_EDICTS = 1024,	// must change protocol to increase more
+	MAX_LIGHTSTYLES = 256,
+
+	/* these are sent over the net as bytes so they cannot be blindly increased */
+	MAX_MODELS = 256,
+	MAX_SOUNDS = 256,
+	MAX_IMAGES = 256,
+	MAX_ITEMS = 256,
+
+	MAX_GENERAL = MAX_CLIENTS*2,	// general config strings
+
+	/* game print flags */
+	PRINT_LOW = 0,		// pickup messages
+	PRINT_MEDIUM = 1,	// death messages
+	PRINT_HIGH = 2,		// critical messages
+	PRINT_CHAT = 3,		// chat messages
+
+	/* key / value info strings */
+	MAX_INFO_KEY = 64,
+	MAX_INFO_VALUE = 64,
+	MAX_INFO_STRING = 512,
+
+	MAX_PARSE_ENTITIES = 1024,
+};
+
+/* destination class for gi.multicast() */
+typedef enum multicast_t{
+	MULTICAST_ALL,
+	MULTICAST_PHS,
+	MULTICAST_PVS,
+	MULTICAST_ALL_R,
+	MULTICAST_PHS_R,
+	MULTICAST_PVS_R
+}multicast_t;
+
+#define M_PI		3.14159265358979323846	// matches value in gcc v2 math.h
+
+extern vec3_t vec3_origin;
+
+#define DotProduct(x,y)	(x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
+#define VectorSubtract(a,b,c)	(c[0]=a[0]-b[0],c[1]=a[1]-b[1],c[2]=a[2]-b[2])
+#define VectorAdd(a,b,c)	(c[0]=a[0]+b[0],c[1]=a[1]+b[1],c[2]=a[2]+b[2])
+#define VectorCopy(a,b)	(b[0]=a[0],b[1]=a[1],b[2]=a[2])
+#define VectorClear(a)	(a[0]=a[1]=a[2]=0)
+#define VectorNegate(a,b)	(b[0]=-a[0],b[1]=-a[1],b[2]=-a[2])
+#define VectorSet(v, x, y, z)	(v[0]=(x), v[1]=(y), v[2]=(z))
+#define BOX_ON_PLANE_SIDE(emins, emaxs, p)	\
+	(((p)->type < 3)?						\
+	(										\
+		((p)->dist <= (emins)[(p)->type])?	\
+			1								\
+		:									\
+		(									\
+			((p)->dist >= (emaxs)[(p)->type])?\
+				2							\
+			:								\
+				3							\
+		)									\
+	)										\
+	:										\
+		BoxOnPlaneSide( (emins), (emaxs), (p)))
+
+extern int curtime;	// current time in ms, from Sys_Milliseconds()
+
+enum{
+	SFF_SUBDIR = 1<<3
+};
+
+enum{
+	CVAR_ARCHIVE = 1<<0,	// save to vars.rc
+	CVAR_USERINFO = 1<<1,	// add to userinfo on change
+	CVAR_SERVERINFO = 1<<2,	// add to serverinfo on change
+	CVAR_NOSET = 1<<3,	// only allow setting from commandline
+	CVAR_LATCH= 1<<4	// save changes until server restart
+};
+/* nothing outside the Cvar_*() functions should modify these fields! */
+struct cvar_t{
+	char *name;
+	char *string;
+	char *latched_string;	// for CVAR_LATCH vars
+	int flags;
+	qboolean modified;	// set each time the cvar is changed
+	float value;
+	cvar_t *next;
+};
+extern cvar_t *cvar_vars;
+extern qboolean userinfo_modified;
+
+enum{
+	/* contents flags are separate bits. a given brush can contribute
+	 * multiple content bits. multiple brushes can be in a single leaf
+	 * lower bits are stronger, and will eat weaker brushes completely */
+	CONTENTS_SOLID = 1<<0,	// an eye is never valid in a solid
+	CONTENTS_WINDOW = 1<<1,	// translucent, but not watery
+	CONTENTS_AUX = 1<<2,
+	CONTENTS_LAVA = 1<<3,
+	CONTENTS_SLIME = 1<<4,
+	CONTENTS_WATER = 1<<5,
+	CONTENTS_MIST = 1<<6,
+	LAST_VISIBLE_CONTENTS = 1<<6,
+	/* remaining contents are non-visible, and don't eat brushes */
+	CONTENTS_AREAPORTAL = 1<<15,
+	CONTENTS_PLAYERCLIP = 1<<16,
+	CONTENTS_MONSTERCLIP = 1<<17,
+	/* currents can be added to any other contents, and may be mixed */
+	CONTENTS_CURRENT_0 = 1<<18,
+	CONTENTS_CURRENT_90 = 1<<19,
+	CONTENTS_CURRENT_180 = 1<<20,
+	CONTENTS_CURRENT_270 = 1<<21,
+	CONTENTS_CURRENT_UP = 1<<22,
+	CONTENTS_CURRENT_DOWN = 1<<23,
+	CONTENTS_ORIGIN = 1<<24,	// removed before bsping an entity
+	CONTENTS_MONSTER = 1<<25,	// should never be on a brush, only in game
+	CONTENTS_DEADMONSTER = 1<<26,
+	CONTENTS_DETAIL = 1<<27,	// brushes to be added after vis leafs
+	CONTENTS_TRANSLUCENT = 1<<28,	// auto set if any surface has trans
+	CONTENTS_LADDER = 1<<29,
+
+	SURF_LIGHT = 1<<0,	// value will hold the light strength
+	SURF_SLICK = 1<<1,	// effects game physics
+	SURF_SKY = 1<<2,	// don't draw, but add to skybox
+	SURF_WARP = 1<<3,	// turbulent water warp
+	SURF_TRANS33 = 1<<4,
+	SURF_TRANS66 = 1<<5,
+	SURF_FLOWING = 1<<6,	// scroll towards angle
+	SURF_NODRAW = 1<<7,	// don't bother referencing the texture
+
+	/* content masks */
+	MASK_ALL = -1,
+	MASK_SOLID = CONTENTS_SOLID|CONTENTS_WINDOW,
+	MASK_PLAYERSOLID = CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER,
+	MASK_DEADSOLID = CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW,
+	MASK_MONSTERSOLID = CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER,
+	MASK_WATER = CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME,
+	MASK_OPAQUE = CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA,
+	MASK_SHOT = CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEADMONSTER,
+	MASK_CURRENT = CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN,
+
+	// FIXME: eliminate AREA_ distinction?
+	/* SV_AreaEdicts() can return a list of either solid or trigger entities */
+	AREA_SOLID = 1<<0,
+	AREA_TRIGGERS = 1<<1
+};
+
+/* !!! if this is changed, it must be changed in asm code too !!! */
+struct cplane_t{
+	vec3_t normal;
+	float dist;
+	uchar type;	// for fast side tests
+	uchar signbits;	// signx + (signy<<1) + (signz<<1)
+	uchar pad[2];
+};
+struct cmodel_t{
+	vec3_t mins;
+	vec3_t maxs;
+	vec3_t origin;	// for sounds or lights
+	int headnode;
+};
+struct csurface_t{
+	char name[16];
+	int flags;
+	int value;
+};
+/* used internally due to name len probs */
+struct mapsurface_t{
+	csurface_t c;
+	char rname[32];
+};
+/* a trace is returned when a box is swept through the world */
+struct trace_t{
+	qboolean allsolid;	// if true, plane is not valid
+	qboolean startsolid;	// if true, the initial point was in a solid area
+	float fraction;	// time completed, 1.0 = didn't hit anything
+	vec3_t endpos;	// final position
+	cplane_t plane;	// surface normal at impact
+	csurface_t *surface;	// surface hit
+	int contents;	// contents on other side of surface hit
+	edict_t	*ent;	// not set by CM_*() functions
+};
+
+/* information necessary for client side movement prediction */
+typedef enum pmtype_t{
+	/* can accelerate and turn */
+	PM_NORMAL,
+	PM_SPECTATOR,
+	/* no acceleration or turning */
+	PM_DEAD,
+	PM_GIB,	// different bounding box
+	PM_FREEZE
+}pmtype_t;
+
+enum{
+	PMF_DUCKED = 1<<0,
+	PMF_JUMP_HELD = 1<<1,
+	PMF_ON_GROUND = 1<<2,
+	PMF_TIME_WATERJUMP = 1<<3,	// pm_time is waterjump
+	PMF_TIME_LAND = 1<<4,	// pm_time is time before rejump
+	PMF_TIME_TELEPORT = 1<<5,	// pm_time is non-moving time
+	/* temporarily disables prediction (used for grappling hook) */
+	PMF_NO_PREDICTION = 1<<6,
+};
+/* this structure needs to be communicated bit-accurate from the server to the
+ * client to guarantee that prediction stays in sync, so no floats are used.
+ * if any part of the game code modifies this struct, it will result in a
+ * prediction error of some degree. */
+struct pmove_state_t{
+	pmtype_t pm_type;
+	short origin[3];	// 12.3
+	short velocity[3];	// 12.3
+	uchar pm_flags;	// ducked, jump_held, etc
+	uchar pm_time;	// each unit = 8 ms
+	short gravity;
+	/* add to command angles to get view direction changed by spawns,
+	 * rotating objects and teleporters */
+	short delta_angles[3];
+};
+
+enum{
+	BUTTON_ATTACK = 1<<0,
+	BUTTON_USE = 1<<1,
+	BUTTON_ANY = 1<<7,	// any key whatsoever
+
+	MAXTOUCH = 32
+};
+/* sent to the server each client frame */
+struct usercmd_t{
+	uchar msec;
+	uchar buttons;
+	short angles[3];
+	short forwardmove;
+	short sidemove;
+	short upmove;
+	uchar impulse;	// remove?
+	uchar lightlevel;	// light level the player is standing on
+};
+struct pmove_t{
+	pmove_state_t s;	// state (in / out)
+	/* command (in) */
+	usercmd_t cmd;
+	qboolean snapinitial;	// if s has been changed outside pmove
+	/* results (out) */
+	int numtouch;
+	edict_t	*touchents[MAXTOUCH];
+
+	vec3_t viewangles;	// clamped
+	float viewheight;
+	vec3_t mins;	// bounding box size
+	vec3_t maxs;
+	edict_t	*groundentity;
+	int watertype;
+	int waterlevel;
+	/* callbacks to test the world */
+	trace_t	(*trace)(vec3_t, vec3_t, vec3_t, vec3_t);
+	int	(*pointcontents)(vec3_t);
+};
+
+enum{
+	/* entity_state_t->effects
+	 * Effects are things handled on the client side (lights, particles, frame
+	 * animations) that happen constantly on the given entity. An entity that has
+	 * effects will be sent to the client even if it has a zero index model. */
+	EF_ROTATE = 1<<0,	// rotate (bonus items)
+	EF_GIB = 1<<1,	// leave a trail
+	EF_BLASTER = 1<<3,	// redlight + trail
+	EF_ROCKET = 1<<4,	// redlight + trail
+	EF_GRENADE = 1<<5,
+	EF_HYPERBLASTER = 1<<6,
+	EF_BFG = 1<<7,
+	EF_COLOR_SHELL = 1<<8,
+	EF_POWERSCREEN = 1<<9,
+	EF_ANIM01 = 1<<10,	// automatically cycle between frames 0 and 1 at 2 hz
+	EF_ANIM23 = 1<<11,	// automatically cycle between frames 2 and 3 at 2 hz
+	EF_ANIM_ALL = 1<<12,	// automatically cycle through all frames at 2hz
+	EF_ANIM_ALLFAST = 1<<13,	// automatically cycle through all frames at 10hz
+	EF_FLIES = 1<<14,
+	EF_QUAD = 1<<15,
+	EF_PENT = 1<<16,
+	EF_TELEPORTER = 1<<17,	// particle fountain
+	EF_FLAG1 = 1<<18,
+	EF_FLAG2 = 1<<19,
+	EF_IONRIPPER = 1<<20,
+	EF_GREENGIB = 1<<21,
+	EF_BLUEHYPERBLASTER = 1<<22,
+	EF_SPINNINGLIGHTS = 1<<23,
+	EF_PLASMA = 1<<24,
+	EF_TRAP = 1<<25,
+	/* ROGUE */
+	EF_TRACKER = 1<<26,
+	EF_DOUBLE = 1<<27,
+	EF_SPHERETRANS = 1<<28,
+	EF_TAGTRAIL = 1<<29,
+	EF_HALF_DAMAGE = 1<<30,
+	EF_TRACKERTRAIL = 1<<31,
+
+	/* entity_state_t->renderfx */
+	RF_MINLIGHT = 1<<0,	// allways have some light (viewmodel)
+	RF_VIEWERMODEL = 1<<1,	// don't draw through eyes, only mirrors
+	RF_WEAPONMODEL = 1<<2,	// only draw through eyes
+	RF_FULLBRIGHT = 1<<3,	// allways draw full intensity
+	RF_DEPTHHACK = 1<<4,	// for view weapon Z crunching
+	RF_TRANSLUCENT = 1<<5,
+	RF_FRAMELERP = 1<<6,
+	RF_BEAM = 1<<7,
+	RF_CUSTOMSKIN = 1<<8,	// skin is an index in image_precache
+	RF_GLOW = 1<<9,		// pulse lighting for bonus items
+	RF_SHELL_RED = 1<<10,
+	RF_SHELL_GREEN = 1<<11,
+	RF_SHELL_BLUE = 1<<12,
+	/* ROGUE */
+	RF_IR_VISIBLE = 1<<15,
+	RF_SHELL_DOUBLE = 1<<16,
+	RF_SHELL_HALF_DAM = 1<<17,
+	RF_USE_DISGUISE = 1<<18,
+
+	/* player_state_t->refdef */
+	RDF_UNDERWATER = 1<<0,	// warp the screen as apropriate
+	RDF_NOWORLDMODEL = 1<<1,	// used for player configuration screen
+	/* ROGUE */
+	RDF_IRGOGGLES = 1<<2,
+	RDF_UVGOGGLES = 1<<3,
+
+	/* muzzle flashes, player effects */
+	MZ_BLASTER = 0,
+	MZ_MACHINEGUN = 1,
+	MZ_SHOTGUN = 2,
+	MZ_CHAINGUN1 = 3,
+	MZ_CHAINGUN2 = 4,
+	MZ_CHAINGUN3 = 5,
+	MZ_RAILGUN = 6,
+	MZ_ROCKET = 7,
+	MZ_GRENADE = 8,
+	MZ_LOGIN = 9,
+	MZ_LOGOUT = 10,
+	MZ_RESPAWN = 11,
+	MZ_BFG = 12,
+	MZ_SSHOTGUN = 13,
+	MZ_HYPERBLASTER = 14,
+	MZ_ITEMRESPAWN = 15,
+	MZ_IONRIPPER = 16,
+	MZ_BLUEHYPERBLASTER = 17,
+	MZ_PHALANX = 18,
+	MZ_SILENCED = 128,	// bit flag ORed with one of the above numbers
+	/* ROGUE */
+	MZ_ETF_RIFLE = 30,
+	MZ_UNUSED = 31,
+	MZ_SHOTGUN2 = 32,
+	MZ_HEATBEAM = 33,
+	MZ_BLASTER2 = 34,
+	MZ_TRACKER = 35,
+	MZ_NUKE1 = 36,
+	MZ_NUKE2 = 37,
+	MZ_NUKE4 = 38,
+	MZ_NUKE8 = 39,
+
+	/* monster muzzle flashes */
+	MZ2_TANK_BLASTER_1 = 1,
+	MZ2_TANK_BLASTER_2 = 2,
+	MZ2_TANK_BLASTER_3 = 3,
+	MZ2_TANK_MACHINEGUN_1 = 4,
+	MZ2_TANK_MACHINEGUN_2 = 5,
+	MZ2_TANK_MACHINEGUN_3 = 6,
+	MZ2_TANK_MACHINEGUN_4 = 7,
+	MZ2_TANK_MACHINEGUN_5 = 8,
+	MZ2_TANK_MACHINEGUN_6 = 9,
+	MZ2_TANK_MACHINEGUN_7 = 10,
+	MZ2_TANK_MACHINEGUN_8 = 11,
+	MZ2_TANK_MACHINEGUN_9 = 12,
+	MZ2_TANK_MACHINEGUN_10 = 13,
+	MZ2_TANK_MACHINEGUN_11 = 14,
+	MZ2_TANK_MACHINEGUN_12 = 15,
+	MZ2_TANK_MACHINEGUN_13 = 16,
+	MZ2_TANK_MACHINEGUN_14 = 17,
+	MZ2_TANK_MACHINEGUN_15 = 18,
+	MZ2_TANK_MACHINEGUN_16 = 19,
+	MZ2_TANK_MACHINEGUN_17 = 20,
+	MZ2_TANK_MACHINEGUN_18 = 21,
+	MZ2_TANK_MACHINEGUN_19 = 22,
+	MZ2_TANK_ROCKET_1 = 23,
+	MZ2_TANK_ROCKET_2 = 24,
+	MZ2_TANK_ROCKET_3 = 25,
+	MZ2_INFANTRY_MACHINEGUN_1 = 26,
+	MZ2_INFANTRY_MACHINEGUN_2 = 27,
+	MZ2_INFANTRY_MACHINEGUN_3 = 28,
+	MZ2_INFANTRY_MACHINEGUN_4 = 29,
+	MZ2_INFANTRY_MACHINEGUN_5 = 30,
+	MZ2_INFANTRY_MACHINEGUN_6 = 31,
+	MZ2_INFANTRY_MACHINEGUN_7 = 32,
+	MZ2_INFANTRY_MACHINEGUN_8 = 33,
+	MZ2_INFANTRY_MACHINEGUN_9 = 34,
+	MZ2_INFANTRY_MACHINEGUN_10 = 35,
+	MZ2_INFANTRY_MACHINEGUN_11 = 36,
+	MZ2_INFANTRY_MACHINEGUN_12 = 37,
+	MZ2_INFANTRY_MACHINEGUN_13 = 38,
+	MZ2_SOLDIER_BLASTER_1 = 39,
+	MZ2_SOLDIER_BLASTER_2 = 40,
+	MZ2_SOLDIER_SHOTGUN_1 = 41,
+	MZ2_SOLDIER_SHOTGUN_2 = 42,
+	MZ2_SOLDIER_MACHINEGUN_1 = 43,
+	MZ2_SOLDIER_MACHINEGUN_2 = 44,
+	MZ2_GUNNER_MACHINEGUN_1 = 45,
+	MZ2_GUNNER_MACHINEGUN_2 = 46,
+	MZ2_GUNNER_MACHINEGUN_3 = 47,
+	MZ2_GUNNER_MACHINEGUN_4 = 48,
+	MZ2_GUNNER_MACHINEGUN_5 = 49,
+	MZ2_GUNNER_MACHINEGUN_6 = 50,
+	MZ2_GUNNER_MACHINEGUN_7 = 51,
+	MZ2_GUNNER_MACHINEGUN_8 = 52,
+	MZ2_GUNNER_GRENADE_1 = 53,
+	MZ2_GUNNER_GRENADE_2 = 54,
+	MZ2_GUNNER_GRENADE_3 = 55,
+	MZ2_GUNNER_GRENADE_4 = 56,
+	MZ2_CHICK_ROCKET_1 = 57,
+	MZ2_FLYER_BLASTER_1 = 58,
+	MZ2_FLYER_BLASTER_2 = 59,
+	MZ2_MEDIC_BLASTER_1 = 60,
+	MZ2_GLADIATOR_RAILGUN_1 = 61,
+	MZ2_HOVER_BLASTER_1 = 62,
+	MZ2_ACTOR_MACHINEGUN_1 = 63,
+	MZ2_SUPERTANK_MACHINEGUN_1 = 64,
+	MZ2_SUPERTANK_MACHINEGUN_2 = 65,
+	MZ2_SUPERTANK_MACHINEGUN_3 = 66,
+	MZ2_SUPERTANK_MACHINEGUN_4 = 67,
+	MZ2_SUPERTANK_MACHINEGUN_5 = 68,
+	MZ2_SUPERTANK_MACHINEGUN_6 = 69,
+	MZ2_SUPERTANK_ROCKET_1 = 70,
+	MZ2_SUPERTANK_ROCKET_2 = 71,
+	MZ2_SUPERTANK_ROCKET_3 = 72,
+	MZ2_BOSS2_MACHINEGUN_L1 = 73,
+	MZ2_BOSS2_MACHINEGUN_L2 = 74,
+	MZ2_BOSS2_MACHINEGUN_L3 = 75,
+	MZ2_BOSS2_MACHINEGUN_L4 = 76,
+	MZ2_BOSS2_MACHINEGUN_L5 = 77,
+	MZ2_BOSS2_ROCKET_1 = 78,
+	MZ2_BOSS2_ROCKET_2 = 79,
+	MZ2_BOSS2_ROCKET_3 = 80,
+	MZ2_BOSS2_ROCKET_4 = 81,
+	MZ2_FLOAT_BLASTER_1 = 82,
+	MZ2_SOLDIER_BLASTER_3 = 83,
+	MZ2_SOLDIER_SHOTGUN_3 = 84,
+	MZ2_SOLDIER_MACHINEGUN_3 = 85,
+	MZ2_SOLDIER_BLASTER_4 = 86,
+	MZ2_SOLDIER_SHOTGUN_4 = 87,
+	MZ2_SOLDIER_MACHINEGUN_4 = 88,
+	MZ2_SOLDIER_BLASTER_5 = 89,
+	MZ2_SOLDIER_SHOTGUN_5 = 90,
+	MZ2_SOLDIER_MACHINEGUN_5 = 91,
+	MZ2_SOLDIER_BLASTER_6 = 92,
+	MZ2_SOLDIER_SHOTGUN_6 = 93,
+	MZ2_SOLDIER_MACHINEGUN_6 = 94,
+	MZ2_SOLDIER_BLASTER_7 = 95,
+	MZ2_SOLDIER_SHOTGUN_7 = 96,
+	MZ2_SOLDIER_MACHINEGUN_7 = 97,
+	MZ2_SOLDIER_BLASTER_8 = 98,
+	MZ2_SOLDIER_SHOTGUN_8 = 99,
+	MZ2_SOLDIER_MACHINEGUN_8 = 100,
+	/* --- Xian shit below --- */
+	MZ2_MAKRON_BFG = 101,
+	MZ2_MAKRON_BLASTER_1 = 102,
+	MZ2_MAKRON_BLASTER_2 = 103,
+	MZ2_MAKRON_BLASTER_3 = 104,
+	MZ2_MAKRON_BLASTER_4 = 105,
+	MZ2_MAKRON_BLASTER_5 = 106,
+	MZ2_MAKRON_BLASTER_6 = 107,
+	MZ2_MAKRON_BLASTER_7 = 108,
+	MZ2_MAKRON_BLASTER_8 = 109,
+	MZ2_MAKRON_BLASTER_9 = 110,
+	MZ2_MAKRON_BLASTER_10 = 111,
+	MZ2_MAKRON_BLASTER_11 = 112,
+	MZ2_MAKRON_BLASTER_12 = 113,
+	MZ2_MAKRON_BLASTER_13 = 114,
+	MZ2_MAKRON_BLASTER_14 = 115,
+	MZ2_MAKRON_BLASTER_15 = 116,
+	MZ2_MAKRON_BLASTER_16 = 117,
+	MZ2_MAKRON_BLASTER_17 = 118,
+	MZ2_MAKRON_RAILGUN_1 = 119,
+	MZ2_JORG_MACHINEGUN_L1 = 120,
+	MZ2_JORG_MACHINEGUN_L2 = 121,
+	MZ2_JORG_MACHINEGUN_L3 = 122,
+	MZ2_JORG_MACHINEGUN_L4 = 123,
+	MZ2_JORG_MACHINEGUN_L5 = 124,
+	MZ2_JORG_MACHINEGUN_L6 = 125,
+	MZ2_JORG_MACHINEGUN_R1 = 126,
+	MZ2_JORG_MACHINEGUN_R2 = 127,
+	MZ2_JORG_MACHINEGUN_R3 = 128,
+	MZ2_JORG_MACHINEGUN_R4 = 129,
+	MZ2_JORG_MACHINEGUN_R5 = 130,
+	MZ2_JORG_MACHINEGUN_R6 = 131,
+	MZ2_JORG_BFG_1 = 132,
+	MZ2_BOSS2_MACHINEGUN_R1 = 133,
+	MZ2_BOSS2_MACHINEGUN_R2 = 134,
+	MZ2_BOSS2_MACHINEGUN_R3 = 135,
+	MZ2_BOSS2_MACHINEGUN_R4 = 136,
+	MZ2_BOSS2_MACHINEGUN_R5 = 137,
+	/* ROGUE */
+	MZ2_CARRIER_MACHINEGUN_L1 = 138,
+	MZ2_CARRIER_MACHINEGUN_R1 = 139,
+	MZ2_CARRIER_GRENADE = 140,
+	MZ2_TURRET_MACHINEGUN = 141,
+	MZ2_TURRET_ROCKET = 142,
+	MZ2_TURRET_BLASTER = 143,
+	MZ2_STALKER_BLASTER = 144,
+	MZ2_DAEDALUS_BLASTER = 145,
+	MZ2_MEDIC_BLASTER_2 = 146,
+	MZ2_CARRIER_RAILGUN = 147,
+	MZ2_WIDOW_DISRUPTOR = 148,
+	MZ2_WIDOW_BLASTER = 149,
+	MZ2_WIDOW_RAIL = 150,
+	MZ2_WIDOW_PLASMABEAM = 151,	// PMM - not used
+	MZ2_CARRIER_MACHINEGUN_L2 = 152,
+	MZ2_CARRIER_MACHINEGUN_R2 = 153,
+	MZ2_WIDOW_RAIL_LEFT = 154,
+	MZ2_WIDOW_RAIL_RIGHT = 155,
+	MZ2_WIDOW_BLASTER_SWEEP1 = 156,
+	MZ2_WIDOW_BLASTER_SWEEP2 = 157,
+	MZ2_WIDOW_BLASTER_SWEEP3 = 158,
+	MZ2_WIDOW_BLASTER_SWEEP4 = 159,
+	MZ2_WIDOW_BLASTER_SWEEP5 = 160,
+	MZ2_WIDOW_BLASTER_SWEEP6 = 161,
+	MZ2_WIDOW_BLASTER_SWEEP7 = 162,
+	MZ2_WIDOW_BLASTER_SWEEP8 = 163,
+	MZ2_WIDOW_BLASTER_SWEEP9 = 164,
+	MZ2_WIDOW_BLASTER_100 = 165,
+	MZ2_WIDOW_BLASTER_90 = 166,
+	MZ2_WIDOW_BLASTER_80 = 167,
+	MZ2_WIDOW_BLASTER_70 = 168,
+	MZ2_WIDOW_BLASTER_60 = 169,
+	MZ2_WIDOW_BLASTER_50 = 170,
+	MZ2_WIDOW_BLASTER_40 = 171,
+	MZ2_WIDOW_BLASTER_30 = 172,
+	MZ2_WIDOW_BLASTER_20 = 173,
+	MZ2_WIDOW_BLASTER_10 = 174,
+	MZ2_WIDOW_BLASTER_0 = 175,
+	MZ2_WIDOW_BLASTER_10L = 176,
+	MZ2_WIDOW_BLASTER_20L = 177,
+	MZ2_WIDOW_BLASTER_30L = 178,
+	MZ2_WIDOW_BLASTER_40L = 179,
+	MZ2_WIDOW_BLASTER_50L = 180,
+	MZ2_WIDOW_BLASTER_60L = 181,
+	MZ2_WIDOW_BLASTER_70L = 182,
+	MZ2_WIDOW_RUN_1 = 183,
+	MZ2_WIDOW_RUN_2 = 184,
+	MZ2_WIDOW_RUN_3 = 185,
+	MZ2_WIDOW_RUN_4 = 186,
+	MZ2_WIDOW_RUN_5 = 187,
+	MZ2_WIDOW_RUN_6 = 188,
+	MZ2_WIDOW_RUN_7 = 189,
+	MZ2_WIDOW_RUN_8 = 190,
+	MZ2_CARRIER_ROCKET_1 = 191,
+	MZ2_CARRIER_ROCKET_2 = 192,
+	MZ2_CARRIER_ROCKET_3 = 193,
+	MZ2_CARRIER_ROCKET_4 = 194,
+	MZ2_WIDOW2_BEAMER_1 = 195,
+	MZ2_WIDOW2_BEAMER_2 = 196,
+	MZ2_WIDOW2_BEAMER_3 = 197,
+	MZ2_WIDOW2_BEAMER_4 = 198,
+	MZ2_WIDOW2_BEAMER_5 = 199,
+	MZ2_WIDOW2_BEAM_SWEEP_1 = 200,
+	MZ2_WIDOW2_BEAM_SWEEP_2 = 201,
+	MZ2_WIDOW2_BEAM_SWEEP_3 = 202,
+	MZ2_WIDOW2_BEAM_SWEEP_4 = 203,
+	MZ2_WIDOW2_BEAM_SWEEP_5 = 204,
+	MZ2_WIDOW2_BEAM_SWEEP_6 = 205,
+	MZ2_WIDOW2_BEAM_SWEEP_7 = 206,
+	MZ2_WIDOW2_BEAM_SWEEP_8 = 207,
+	MZ2_WIDOW2_BEAM_SWEEP_9 = 208,
+	MZ2_WIDOW2_BEAM_SWEEP_10 = 209,
+	MZ2_WIDOW2_BEAM_SWEEP_11 = 210
+};
+
+extern vec3_t monster_flash_offset[];
+
+/* Temp entity events are for things that happen at a location seperate from
+ * any existing entity. Temporary entity messages are explicitly constructed
+ * and broadcast. */
+typedef enum temp_event_t{
+	TE_GUNSHOT,
+	TE_BLOOD,
+	TE_BLASTER,
+	TE_RAILTRAIL,
+	TE_SHOTGUN,
+	TE_EXPLOSION1,
+	TE_EXPLOSION2,
+	TE_ROCKET_EXPLOSION,
+	TE_GRENADE_EXPLOSION,
+	TE_SPARKS,
+	TE_SPLASH,
+	TE_BUBBLETRAIL,
+	TE_SCREEN_SPARKS,
+	TE_SHIELD_SPARKS,
+	TE_BULLET_SPARKS,
+	TE_LASER_SPARKS,
+	TE_PARASITE_ATTACK,
+	TE_ROCKET_EXPLOSION_WATER,
+	TE_GRENADE_EXPLOSION_WATER,
+	TE_MEDIC_CABLE_ATTACK,
+	TE_BFG_EXPLOSION,
+	TE_BFG_BIGEXPLOSION,
+	TE_BOSSTPORT,	// used as '22' in a map, so DON'T RENUMBER!!!
+	TE_BFG_LASER,
+	TE_GRAPPLE_CABLE,
+	TE_WELDING_SPARKS,
+	TE_GREENBLOOD,
+	TE_BLUEHYPERBLASTER,
+	TE_PLASMA_EXPLOSION,
+	TE_TUNNEL_SPARKS,
+	/* ROGUE */
+	TE_BLASTER2,
+	TE_RAILTRAIL2,
+	TE_FLAME,
+	TE_LIGHTNING,
+	TE_DEBUGTRAIL,
+	TE_PLAIN_EXPLOSION,
+	TE_FLASHLIGHT,
+	TE_FORCEWALL,
+	TE_HEATBEAM,
+	TE_MONSTER_HEATBEAM,
+	TE_STEAM,
+	TE_BUBBLETRAIL2,
+	TE_MOREBLOOD,
+	TE_HEATBEAM_SPARKS,
+	TE_HEATBEAM_STEAM,
+	TE_CHAINFIST_SMOKE,
+	TE_ELECTRIC_SPARKS,
+	TE_TRACKER_EXPLOSION,
+	TE_TELEPORT_EFFECT,
+	TE_DBALL_GOAL,
+	TE_WIDOWBEAMOUT,
+	TE_NUKEBLAST,
+	TE_WIDOWSPLASH,
+	TE_EXPLOSION1_BIG,
+	TE_EXPLOSION1_NP,
+	TE_FLECHETTE
+}temp_event_t;
+
+enum{
+	SPLASH_UNKNOWN = 0,
+	SPLASH_SPARKS = 1,
+	SPLASH_BLUE_WATER = 2,
+	SPLASH_BROWN_WATER = 3,
+	SPLASH_SLIME = 4,
+	SPLASH_LAVA = 5,
+	SPLASH_BLOOD = 6,
+
+	/* sound channels
+	 * channel 0 never willingly overrides
+	 * other channels (1-7) allways override a playing sound on that channel */
+	CHAN_AUTO = 0,
+	CHAN_WEAPON = 1,
+	CHAN_VOICE = 2,
+	CHAN_ITEM = 3,
+	CHAN_BODY = 4,
+	/* modifier flags */
+	CHAN_NO_PHS_ADD = 1<<3,	// send to all clients, not just ones in PHS (ATTN 0 will also do this)
+	CHAN_RELIABLE = 1<<4,	// send by reliable message, not datagram
+
+	/* sound attenuation values */
+	ATTN_NONE = 0,	// full volume the entire level
+	ATTN_NORM = 1,
+	ATTN_IDLE = 2,
+	ATTN_STATIC = 3,	// diminish very rapidly with distance
+
+	/* player_state->stats[] */
+	STAT_HEALTH_ICON = 0,
+	STAT_HEALTH = 1,
+	STAT_AMMO_ICON = 2,
+	STAT_AMMO = 3,
+	STAT_ARMOR_ICON = 4,
+	STAT_ARMOR = 5,
+	STAT_SELECTED_ICON = 6,
+	STAT_PICKUP_ICON = 7,
+	STAT_PICKUP_STRING = 8,
+	STAT_TIMER_ICON = 9,
+	STAT_TIMER = 10,
+	STAT_HELPICON = 11,
+	STAT_SELECTED_ITEM = 12,
+	STAT_LAYOUTS = 13,
+	STAT_FRAGS = 14,
+	STAT_FLASHES = 15,	// cleared each frame, 1 = health, 2 = armor
+	STAT_CHASE = 16,
+	STAT_SPECTATOR = 17,
+	MAX_STATS = 32,
+
+	/* dmflags->value */
+	DF_NO_HEALTH = 1<<0,
+	DF_NO_ITEMS = 1<<1,
+	DF_WEAPONS_STAY = 1<<2,
+	DF_NO_FALLING = 1<<3,
+	DF_INSTANT_ITEMS = 1<<4,
+	DF_SAME_LEVEL = 1<<5,
+	DF_SKINTEAMS = 1<<6,
+	DF_MODELTEAMS = 1<<7,
+	DF_NO_FRIENDLY_FIRE = 1<<8,
+	DF_SPAWN_FARTHEST = 1<<9,
+	DF_FORCE_RESPAWN = 1<<10,
+	DF_NO_ARMOR = 1<<11,
+	DF_ALLOW_EXIT = 1<<12,
+	DF_INFINITE_AMMO = 1<<13,
+	DF_QUAD_DROP = 1<<14,
+	DF_FIXED_FOV = 1<<15,
+	DF_QUADFIRE_DROP = 1<<16,
+	/* ROGUE */
+	DF_NO_MINES = 1<<17,
+	DF_NO_STACK_DOUBLE = 1<<18,
+	DF_NO_NUKES = 1<<19,
+	DF_NO_SPHERES = 1<<20,
+
+	ROGUE_VERSION_ID = 1278	// probably bs
+};
+
+/* communicated accross the net */
+
+#define	ANGLE2SHORT(x)	((int)((x)*65536/360) & 65535)
+#define	SHORT2ANGLE(x)	((x)*(360.0/65536))
+
+enum{
+	/* config strings are a general means of communication from the server
+	 * to all connected clients. each config string can be at most
+	 * MAX_QPATH characters. */
+	CS_NAME = 0,
+	CS_CDTRACK = 1,
+	CS_SKY = 2,
+	CS_SKYAXIS = 3,	// %f %f %f format
+	CS_SKYROTATE = 4,
+	CS_STATUSBAR = 5,	// display program string
+	CS_AIRACCEL = 29,	// air acceleration control
+	CS_MAXCLIENTS = 30,
+	CS_MAPCHECKSUM = 31,	// for catching cheater maps
+	CS_MODELS = 32,
+	CS_SOUNDS = CS_MODELS+MAX_MODELS,
+	CS_IMAGES = CS_SOUNDS+MAX_SOUNDS,
+	CS_LIGHTS = CS_IMAGES+MAX_IMAGES,
+	CS_ITEMS = CS_LIGHTS+MAX_LIGHTSTYLES,
+	CS_PLAYERSKINS = CS_ITEMS+MAX_ITEMS,
+	CS_GENERAL = CS_PLAYERSKINS+MAX_CLIENTS,
+	MAX_CONFIGSTRINGS = CS_GENERAL+MAX_GENERAL
+};
+
+/* entity events are for effects that take place relative to an existing
+ * entitiy origin. Very network efficient. All muzzle flashes really should be
+ * converted to events... */
+typedef enum entity_event_t{
+	EV_NONE,
+	EV_ITEM_RESPAWN,
+	EV_FOOTSTEP,
+	EV_FALLSHORT,
+	EV_FALL,
+	EV_FALLFAR,
+	EV_PLAYER_TELEPORT,
+	EV_OTHER_TELEPORT
+}entity_event_t;
+
+/* information conveyed from the server in an update message about entities
+ * that the client will need to render in some way */
+struct entity_state_t{
+	int number;			// edict index
+	vec3_t origin;
+	vec3_t angles;
+	vec3_t old_origin;		// for lerping
+	int modelindex;
+	int modelindex2;	// weapons, CTF flags, etc
+	int modelindex3;
+	int modelindex4;
+	int frame;
+	int skinnum;
+	uint effects;	// PGM - we're filling it, so it needs to be unsigned
+	int renderfx;
+	/* for client side prediction; SV_LinkEdict() sets .solid properly:
+	 * 8*(bits 0-4) is x/y radius
+	 * 8*(bits 5-9) is z down distance
+	 * 8(bits10-15) is z up */
+	int solid;
+	int sound;	// for looping sounds, to guarantee shutoff
+	/* impulse events: muzzle flashes, footsteps, etc.
+	 * events only go out for a single frame, they are automatically
+	 * cleared each frame */
+	int event;
+};
+/* the cl_parse_entities must be large enough to hold UPDATE_BACKUP frames of
+ * entities, so that when a delta compressed message arives from the server it
+ * can be un-deltad from the original */
+extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
+
+/* information needed in addition to pmove_state_t to render a view. There will
+ * only be 10 player_state_t sent each second, but the number of pmove_state_t
+ * changes will be reletive to client frame rates */
+struct player_state_t{
+	pmove_state_t pmove;	// for prediction
+	/* these fields do not need to be communicated bit-precise */
+	vec3_t viewangles;	// for fixed views
+	vec3_t viewoffset;	// add to pmovestate->origin
+	/* set by weapon kicks, pain effects, etc. */
+	vec3_t kick_angles;	// add to view direction to get render angles
+	vec3_t gunangles;
+	vec3_t gunoffset;
+	int gunindex;
+	int gunframe;
+	float blend[4];	// rgba full screen effect
+	float fov;	// horizontal field of view
+	int rdflags;	// refdef flags
+	short stats[MAX_STATS];	// fast status bar updates
+};
+
+enum{
+	VIDREF_GL = 1,
+	VIDREF_SOFT = 2
+};
+extern int vidref_val;
+
+
+#include "game/game.h"	// ugh
+extern game_export_t *ge;
+
+
+#define	VERSION 3.19
+#define	BASEDIRNAME "baseq2"
+
+struct sizebuf_t{
+	qboolean allowoverflow;	// if false, do a Com_Error
+	qboolean overflowed;	// set to true if the buffer size failed
+	uchar *data;
+	int maxsize;
+	int cursize;
+	int readcount;
+};
+extern sizebuf_t net_message;
+
+#define DEFAULT_SOUND_PACKET_VOLUME	1.0
+#define DEFAULT_SOUND_PACKET_ATTENUATION	1.0
+enum{
+	PROTOCOL_VERSION = 34,
+	PORT_MASTER = 27900,
+	PORT_CLIENT = 27901,
+	PORT_SERVER = 27910,
+	UPDATE_BACKUP = 16,	// buffered copies of entity_state_t; must be power of two
+	UPDATE_MASK = UPDATE_BACKUP-1,
+
+	/* server to client: protocol bytes that can be directly added to
+	 * messages; the svc_strings[] array in cl_parse.c should mirror this */
+	svc_bad = 0,
+	/* these ops are known to the game dll */
+	svc_muzzleflash,
+	svc_muzzleflash2,
+	svc_temp_entity,
+	svc_layout,
+	svc_inventory,
+	/* the rest are private to the client and server */
+	svc_nop,
+	svc_disconnect,
+	svc_reconnect,
+	svc_sound,
+	svc_print,	// [byte] id [string] null terminated string
+	svc_stufftext,	// [string] stuffed into client's console buffer, should be \n terminated
+	svc_serverdata,	// [long] protocol ...
+	svc_configstring,	// [short] [string]
+	svc_spawnbaseline,		
+	svc_centerprint,	// [string] to put in center of the screen
+	svc_download,	// [short] size [size bytes]
+	svc_playerinfo,	// variable
+	svc_packetentities,	// [...]
+	svc_deltapacketentities,	// [...]
+	svc_frame,
+
+	/* client to server */
+	clc_bad = 0,
+	clc_nop, 		
+	clc_move,	// [[usercmd_t]
+	clc_userinfo,	// [[userinfo string]
+	clc_stringcmd,	// [string] message
+
+	/* player_state_t communication */
+	PS_M_TYPE = 1<<0,
+	PS_M_ORIGIN = 1<<1,
+	PS_M_VELOCITY = 1<<2,
+	PS_M_TIME = 1<<3,
+	PS_M_FLAGS = 1<<4,
+	PS_M_GRAVITY = 1<<5,
+	PS_M_DELTA_ANGLES = 1<<6,
+	PS_VIEWOFFSET = 1<<7,
+	PS_VIEWANGLES = 1<<8,
+	PS_KICKANGLES = 1<<9,
+	PS_BLEND = 1<<10,
+	PS_FOV = 1<<11,
+	PS_WEAPONINDEX = 1<<12,
+	PS_WEAPONFRAME = 1<<13,
+	PS_RDFLAGS = 1<<14,
+
+	/* user_cmd_t communication: ms and light always sent, the others are
+	 * optional */
+	CM_ANGLE1 = 1<<0,
+	CM_ANGLE2 = 1<<1,
+	CM_ANGLE3 = 1<<2,
+	CM_FORWARD = 1<<3,
+	CM_SIDE = 1<<4,
+	CM_UP = 1<<5,
+	CM_BUTTONS = 1<<6,
+	CM_IMPULSE = 1<<7,
+
+	/* a sound without an ent or pos will be a local only sound */
+	SND_VOLUME = 1<<0,	// a byte
+	SND_ATTENUATION = 1<<1,	// a byte
+	SND_POS = 1<<2,	// three coordinates
+	SND_ENT = 1<<3,	// a short 0-2: channel, 3-12: entity
+	SND_OFFSET = 1<<4,	// a byte, msec offset from frame start
+
+	/* entity_state_t communication */
+	/* try to pack the common update flags into the first byte */
+	U_ORIGIN1 = 1<<0,
+	U_ORIGIN2 = 1<<1,
+	U_ANGLE2 = 1<<2,
+	U_ANGLE3 = 1<<3,
+	U_FRAME8 = 1<<4,	// frame is a byte
+	U_EVENT = 1<<5,
+	U_REMOVE = 1<<6,	// REMOVE this entity, don't add it
+	U_MOREBITS1 = 1<<7,	// read one additional byte
+	U_NUMBER16 = 1<<8,	// NUMBER8 is implicit if not set
+	U_ORIGIN3 = 1<<9,
+	U_ANGLE1 = 1<<10,
+	U_MODEL = 1<<11,
+	U_RENDERFX8 = 1<<12,	// fullbright, etc
+	U_EFFECTS8 = 1<<14,	// autorotate, trails, etc
+	U_MOREBITS2 = 1<<15,	// read one additional byte
+	U_SKIN8 = 1<<16,
+	U_FRAME16 = 1<<17,	// frame is a short
+	U_RENDERFX16 = 1<<18,	// 8 + 16 = 32
+	U_EFFECTS16 = 1<<19,	// 8 + 16 = 32
+	U_MODEL2 = 1<<20,	// weapons, flags, etc
+	U_MODEL3 = 1<<21,
+	U_MODEL4 = 1<<22,
+	U_MOREBITS3 = 1<<23,	// read one additional byte
+	U_OLDORIGIN = 1<<24,	// FIXME: get rid of this
+	U_SKIN16 = 1<<25,
+	U_SOUND = 1<<26,
+	U_SOLID = 1<<27,
+};
+extern char *svc_strings[256];
+
+typedef enum netsrc_t{
+	NS_CLIENT,
+	NS_SERVER
+}netsrc_t;
+typedef enum netadrtype_t{
+	NA_LOOPBACK,
+	NA_BROADCAST,
+	NA_IP,
+	NA_IPX,
+	NA_BROADCAST_IPX
+}netadrtype_t;
+
+#define	OLD_AVG	0.99	// total = oldtotal*OLD_AVG + new*(1-OLD_AVG)
+enum{
+	PORT_ANY = -1,
+	MAX_MSGLEN = 1400,	// max length of a message
+	PACKET_HEADER = 10,	// two ints and a short
+	MAX_LATENT = 32,
+	MAX_MASTERS = 8	// max recipients for heartbeat packets
+};
+struct netadr_t{
+	netadrtype_t type;
+	uchar ip[4];
+	uchar ipx[10];
+	ushort port;
+};
+extern netadr_t net_from;
+extern netadr_t master_adr[MAX_MASTERS];	// address of the master server
+
+struct netchan_t{
+	qboolean fatal_error;
+	netsrc_t sock;
+	int dropped;	// between last packet and previous
+	int last_received;	// for timeouts
+	int last_sent;	// for retransmits
+	netadr_t remote_address;
+	int qport;	// qport value to write when transmitting
+	/* sequencing variables */
+	int incoming_sequence;
+	int incoming_acknowledged;
+	int incoming_reliable_acknowledged;	// single bit
+	int incoming_reliable_sequence;	// single bit, maintained local
+	int outgoing_sequence;
+	int reliable_sequence;	// single bit
+	int last_reliable_sequence;	// sequence number of last send
+	/* reliable staging and holding areas */
+	sizebuf_t message;	// writing buffer to send to server
+	uchar message_buf[MAX_MSGLEN-16];	// leave space for header
+	/* message is copied to this buffer when it is first transfered */
+	int reliable_length;
+	uchar reliable_buf[MAX_MSGLEN-16];	// unacked reliable message
+};
+extern uchar net_message_buffer[MAX_MSGLEN];
+
+extern float pm_airaccelerate;
+
+extern cvar_t *developer;
+extern cvar_t *dedicated;
+extern cvar_t *host_speeds;
+extern cvar_t *log_stats;
+
+enum{
+	ERR_FATAL = 0,	// exit the entire game with a popup window
+	ERR_DROP = 1,	// print to console and disconnect from game
+	ERR_QUIT = 2,	// not an error, just a normal exit
+	ERR_DISCONNECT = 2,	// don't kill server
+	EXEC_NOW = 0,	// don't return until completed
+	EXEC_INSERT = 1,	// insert at current position, but don't run yet
+	EXEC_APPEND = 2,	// add to end of the command buffer
+	PRINT_ALL = 0,
+	PRINT_DEVELOPER = 1,	// only print when "developer 1"
+
+	NUMVERTEXNORMALS = 162,
+
+	/* thread groups */
+	THin = 1,
+	THsnd = 2,
+	THnet = 3
+};
+
+extern FILE *log_stats_file;
+/* host_speeds times */
+extern int time_before_game;
+extern int time_after_game;
+extern int time_before_ref;
+extern int time_after_ref;
+
+extern vec3_t bytedirs[NUMVERTEXNORMALS];
+
+extern uint sys_frame_time;
+
+#pragma pack on
+
+/* .pak files are just a linear collapse of a directory tree */
+enum{
+	IDPAKHEADER = ('K'<<24)+('C'<<16)+('A'<<8)+'P',
+	MAX_FILES_IN_PACK = 4096
+};
+struct dpackfile_t{
+	char name[56];
+	int filepos;
+	int filelen;
+};
+struct dpackheader_t{
+	int ident;	// == IDPAKHEADER
+	int dirofs;
+	int dirlen;
+};
+
+/* PCX images */
+struct pcx_t{
+	char manufacturer;
+	char version;
+	char encoding;
+	char bits_per_pixel;
+	ushort xmin;
+	ushort ymin;
+	ushort xmax;
+	ushort ymax;
+	ushort hres;
+	ushort vres;
+	uchar palette[48];
+	char reserved;
+	char color_planes;
+	ushort bytes_per_line;
+	ushort palette_type;
+	char filler[58];
+	uchar data;	// unbounded
+};
+
+/* .md2 triangle model file format */
+enum{
+	IDALIASHEADER = ('2'<<24)+('P'<<16)+('D'<<8)+'I',
+	ALIAS_VERSION = 8,
+	MAX_TRIANGLES = 4096,
+	MAX_VERTS = 2048,
+	MAX_FRAMES = 512,
+	MAX_MD2SKINS = 32,
+	MAX_SKINNAME = 64
+};
+struct dstvert_t{
+	short s;
+	short t;
+};
+struct dtriangle_t{
+	short index_xyz[3];
+	short index_st[3];
+};
+struct dtrivertx_t{
+	uchar v[3];	// scaled byte to fit in frame mins/maxs
+	uchar lightnormalindex;
+};
+struct daliasframe_t{
+	float scale[3];	// multiply byte verts by this
+	float translate[3];	// then add this
+	char name[16];	// frame name from grabbing
+	dtrivertx_t verts[1];	// variable sized
+};
+
+/* glcmd format
+ * a positive integer starts a tristrip command, followed by that many vertex
+ * structures. a negative integer starts a trifan command, followed by -x
+ * vertexes a zero indicates the end of the command list. a vertex consists of
+ * a floating point s, a floating point t, and an integer vertex index. */
+struct dmdl_t{
+	int ident;
+	int version;
+	int skinwidth;
+	int skinheight;
+	int framesize;	// byte size of each frame
+	int num_skins;
+	int num_xyz;
+	int num_st;	// greater than num_xyz for seams
+	int num_tris;
+	int num_glcmds;	// dwords in strip/fan command lis
+	int num_frames;
+	int ofs_skins;	// each skin is a MAX_SKINNAME string
+	int ofs_st;	// byte offset from start for stverts
+	int ofs_tris;	// offset for dtriangles
+	int ofs_frames;	// offset for first frame
+	int ofs_glcmds;
+	int ofs_end;	// end of file
+};
+
+/* .sp2 sprite file format */
+enum{
+	IDSPRITEHEADER = ('2'<<24)+('S'<<16)+('D'<<8)+'I',
+	SPRITE_VERSION = 2
+};
+struct dsprframe_t{
+	int width;
+	int height;
+	int origin_x;
+	int origin_y;	// raster coordinates inside pic
+	char name[MAX_SKINNAME];	// name of pcx file
+};
+struct dsprite_t{
+	int ident;
+	int version;
+	int numframes;
+	dsprframe_t frames[1]; // variable sized
+};
+
+/* .wal texture file format */
+enum{
+	MIPLEVELS = 4
+};
+struct miptex_t{
+	char name[32];
+	uint width;
+	uint height;
+	uint offsets[MIPLEVELS];	// four mip maps stored
+	char animname[32];	// next frame in animation chain
+	int flags;
+	int contents;
+	int value;
+};
+
+/* .bsp file format */
+enum{
+	IDBSPHEADER = ('P'<<24)+('S'<<16)+('B'<<8)+'I',
+	BSPVERSION = 38,
+
+	/* upper design bounds; leaffaces, leafbrushes, planes, and verts are
+	 * still bounded by 16 bit short limits */
+	MAX_MAP_MODELS = 1024,
+	MAX_MAP_BRUSHES = 8192,
+	MAX_MAP_ENTITIES = 2048,
+	MAX_MAP_ENTSTRING = 0x40000,
+	MAX_MAP_TEXINFO = 8192,
+	MAX_MAP_AREAS = 256,
+	MAX_MAP_AREAPORTALS = 1024,
+	MAX_MAP_PLANES = 65536,
+	MAX_MAP_NODES = 65536,
+	MAX_MAP_BRUSHSIDES = 65536,
+	MAX_MAP_LEAFS = 65536,
+	MAX_MAP_VERTS = 65536,
+	MAX_MAP_FACES = 65536,
+	MAX_MAP_LEAFFACES = 65536,
+	MAX_MAP_LEAFBRUSHES = 65536,
+	MAX_MAP_PORTALS = 65536,
+	MAX_MAP_EDGES = 128000,
+	MAX_MAP_SURFEDGES = 256000,
+	MAX_MAP_LIGHTING = 0x200000,
+	MAX_MAP_VISIBILITY = 0x100000,
+
+	/* key / value pair sizes */
+	MAX_KEY = 32,
+	MAX_VALUE = 1024,
+
+	LUMP_ENTITIES = 0,
+	LUMP_PLANES = 1,
+	LUMP_VERTEXES = 2,
+	LUMP_VISIBILITY = 3,
+	LUMP_NODES = 4,
+	LUMP_TEXINFO = 5,
+	LUMP_FACES = 6,
+	LUMP_LIGHTING = 7,
+	LUMP_LEAFS = 8,
+	LUMP_LEAFFACES = 9,
+	LUMP_LEAFBRUSHES = 10,
+	LUMP_EDGES = 11,
+	LUMP_SURFEDGES = 12,
+	LUMP_MODELS = 13,
+	LUMP_BRUSHES = 14,
+	LUMP_BRUSHSIDES = 15,
+	LUMP_POP = 16,
+	LUMP_AREAS = 17,
+	LUMP_AREAPORTALS = 18,
+	HEADER_LUMPS = 19,
+
+	/* 0-2 are axial planes */
+	PLANE_X = 0,
+	PLANE_Y = 1,
+	PLANE_Z = 2,
+	/* 3-5 are non-axial planes snapped to the nearest */
+	PLANE_ANYX = 3,
+	PLANE_ANYY = 4,
+	PLANE_ANYZ = 5
+	/* planes (x&~1) and (x&~1)+1 are always opposites */
+};
+struct lump_t{
+	int fileofs;
+	int filelen;
+};
+struct dheader_t{
+	int ident;
+	int version;	
+	lump_t lumps[HEADER_LUMPS];
+};
+
+struct dmodel_t{
+	float mins[3];
+	float maxs[3];
+	float origin[3];	// for sounds or lights
+	int headnode;
+	int firstface;
+	/* submodels just draw faces without walking the bsp tree */
+	int numfaces;
+};
+struct dvertex_t{
+	float point[3];
+};
+struct dplane_t{
+	float normal[3];
+	float dist;
+	int type;	// PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
+};
+struct dnode_t{
+	int planenum;
+	int children[2];	// negative numbers are -(leafs+1), not nodes
+	short mins[3];	// for frustom culling
+	short maxs[3];
+	ushort firstface;
+	ushort numfaces;	// counting both sides
+};
+struct texinfo_t{
+	float vecs[2][4];	// [s/t][xyz offset]
+	int flags;	// miptex flags + overrides
+	int value;	// light emission, etc
+	char texture[32];	// texture name (textures/*.wal)
+	int nexttexinfo;	// for animations, -1 = end of chain
+};
+
+enum{
+	MAXLIGHTMAPS = 4,
+	ANGLE_UP = -1,
+	ANGLE_DOWN = -2
+};
+/* note that edge 0 is never used, because negative edge nums are used for
+ * counterclockwise use of the edge in a face */
+struct dedge_t{
+	ushort v[2];	// vertex numbers
+};
+struct dface_t{
+	ushort planenum;
+	short side;
+	int firstedge;	// we must support > 64k edges
+	short numedges;	
+	short texinfo;
+	/* lighting info */
+	uchar styles[MAXLIGHTMAPS];
+	int lightofs;	// start of [numstyles*surfsize] samples
+};
+struct dleaf_t{
+	int contents;	// OR of all brushes (not needed?)
+	short cluster;
+	short area;
+	short mins[3];	// for frustum culling
+	short maxs[3];
+	ushort firstleafface;
+	ushort numleaffaces;
+	ushort firstleafbrush;
+	ushort numleafbrushes;
+};
+struct dbrushside_t{
+	ushort planenum;	// facing out of the leaf
+	short texinfo;
+};
+struct dbrush_t{
+	int firstside;
+	int numsides;
+	int contents;
+};
+
+/* the visibility lump consists of a header with a count, then byte offsets for
+ * the PVS and PHS of each cluster, then the raw compressed bit vectors */
+enum{
+	DVIS_PVS = 0,
+	DVIS_PHS = 1
+};
+struct dvis_t{
+	int numclusters;
+	int bitofs[8][2];	// bitofs[numclusters][2]
+};
+/* each area has a list of portals that lead into other areas; when portals are
+ * closed, other areas may not be visible or hearable even if the vis info says
+ * that it should be */
+struct dareaportal_t{
+	int portalnum;
+	int otherarea;
+};
+struct darea_t{
+	int numareaportals;
+	int firstareaportal;
+};
+
+#pragma pack off
+
+struct vrect_t{
+	int x;
+	int y;
+	int width;
+	int height;
+	vrect_t	*pnext;
+};
+struct viddef_t{
+	int width;          
+	int height;
+	pixel_t *buffer;	// invisible buffer
+	pixel_t *colormap;	// 256 * VID_GRADES size
+	pixel_t *alphamap;	// 256 * 256 translucency map
+	int rowbytes;	// may be > width if displayed in a window or <0 for stupid dibs
+};
+extern viddef_t vid;
+
+#define REF_VERSION "SOFT 0.01"
+/* skins are outline flood filled and mip mapped; pics and sprites with alpha
+ * will be outline flood filled pic won't be mip mapped */
+
+extern cvar_t *sw_aliasstats;
+extern cvar_t *sw_clearcolor;
+extern cvar_t *sw_drawflat;
+extern cvar_t *sw_draworder;
+extern cvar_t *sw_maxedges;
+extern cvar_t *sw_maxsurfs;
+extern cvar_t *sw_mipcap;
+extern cvar_t *sw_mipscale;
+extern cvar_t *sw_mode;
+extern cvar_t *sw_reportsurfout;
+extern cvar_t *sw_reportedgeout;
+extern cvar_t *sw_stipplealpha;
+extern cvar_t *sw_surfcacheoverride;
+extern cvar_t *sw_waterwarp;
+extern cvar_t *r_fullbright;
+extern cvar_t *r_lefthand;
+extern cvar_t *r_drawentities;
+extern cvar_t *r_drawworld;
+extern cvar_t *r_dspeeds;
+extern cvar_t *r_lerpmodels;
+extern cvar_t *r_speeds;
+extern cvar_t *r_lightlevel;  //FIXME HACK
+
+typedef enum imagetype_t{
+	it_skin,
+	it_sprite,
+	it_wall,
+	it_pic,
+	it_sky
+}imagetype_t;
+struct image_t{
+	char name[MAX_QPATH];	// game path, including extension
+	imagetype_t type;
+	int width;
+	int height;
+	qboolean transparent;	// true if any 255 pixels in image
+	int registration_sequence;	// 0 = free
+	uchar *pixels[4];	// mip levels
+};
+
+typedef enum rserr_t{
+	rserr_ok,
+	rserr_invalid_fullscreen,
+	rserr_invalid_mode,
+	rserr_unknown
+}rserr_t;
+
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct oldrefdef_t{
+	vrect_t vrect;	// subwindow in video for refresh
+	// FIXME: not need vrect next field here?
+	vrect_t aliasvrect;	// scaled Alias version
+	int vrectright;
+	int vrectbottom;	// right & bottom screen coords
+	int aliasvrectright;
+	int aliasvrectbottom;	// scaled Alias versions
+	/* rightmost right edge we care about, for use in edge list */
+	float vrectrightedge;
+	float fvrectx;
+	float fvrecty;	// for floating-point compares
+	float fvrectx_adj;
+	float fvrecty_adj;	// left and top edges, for clamping
+	int vrect_x_adj_shift20;	// vrect.x+0.5-epsilon << 20
+	int vrectright_adj_shift20;	// vrectright+0.5-epsilon << 20
+	float fvrectright_adj;
+	float fvrectbottom_adj;
+	/* right and bottom edges, for clamping */
+	float fvrectright;	// rightmost edge, for Alias clamping
+	float fvrectbottom;	// bottommost edge, for Alias clamping
+	/* at Z = 1.0, this many X is visible; 2.0 = 90 degrees */
+	float horizontalFieldOfView;
+	float xOrigin;	// should probably always be 0.5
+	float yOrigin;	// between be around 0.3 to 0.5
+	vec3_t vieworg;
+	vec3_t viewangles;
+	int ambientlight;
+};
+extern oldrefdef_t r_refdef;
+
+/* d*_t structures are on-disk representations; m*_t structures are in-memory */
+
+enum{
+	SIDE_FRONT = 0,
+	SIDE_BACK = 1,
+	SIDE_ON = 2,
+
+	// FIXME: differentiate from texinfo SURF_ flags
+	SURF_PLANEBACK = 1<<1,
+	SURF_DRAWSKY = 1<<2,	// sky brush face
+	SURF_DRAWTURB = 1<<4,
+	SURF_DRAWBACKGROUND = 1<<6,
+	SURF_DRAWSKYBOX = 1<<7,	// sky box
+	SURF_FLOW = 1<<8,
+
+	CONTENTS_NODE = -1
+};
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct mvertex_t{
+	vec3_t position;
+};
+/* !!! if this is changed, it must be changed in asm_i386.h too !!! */
+struct mplane_t{
+	vec3_t normal;
+	float dist;
+	uchar type;	// for texture axis selection and fast side tests
+	uchar signbits;	// signx + signy<<1 + signz<<1
+	uchar pad[2];
+};
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct medge_t{
+	ushort v[2];
+	uint cachededgeoffset;
+};
+struct mtexinfo_t{
+	float vecs[2][4];
+	float mipadjust;
+	image_t *image;
+	int flags;
+	int numframes;
+	mtexinfo_t *next;	// animation chain
+};
+struct msurface_t{
+	int visframe;	// should be drawn when node is crossed
+	int dlightframe;
+	int dlightbits;
+	mplane_t *plane;
+	int flags;
+	int firstedge;	// look up in model->surfedges[], negative numbers
+	int numedges;	// are backwards edges
+	/* surface generation data */
+	surfcache_t *cachespots[MIPLEVELS];
+	short texturemins[2];
+	short extents[2];
+	mtexinfo_t *texinfo;
+	/* lighting info */
+	uchar styles[MAXLIGHTMAPS];
+	uchar *samples;	// [numstyles*surfsize]
+	msurface_t *nextalphasurface;
+};
+
+struct mnode_t{
+	/* common with leaf */
+	int contents;	// CONTENTS_NODE, to differentiate from leafs
+	int visframe;	// node needs to be traversed if current
+	short minmaxs[6];	// for bounding box culling
+	mnode_t *parent;
+	/* node specific */
+	mplane_t *plane;
+	mnode_t *children[2];
+	ushort firstsurface;
+	ushort numsurfaces;
+};
+struct mleaf_t{
+	/* common with node */
+	int contents;	// wil be something other than CONTENTS_NODE
+	int visframe;	// node needs to be traversed if current
+	short minmaxs[6];	// for bounding box culling
+	mnode_t	*parent;
+	/* leaf specific */
+	int cluster;
+	int area;
+	msurface_t **firstmarksurface;
+	int nummarksurfaces;
+	int key;	// BSP sequence number for leaf's contents
+};
+
+typedef enum modtype_t{
+	mod_bad,
+	mod_brush,
+	mod_sprite,
+	mod_alias
+}modtype_t;
+struct model_t{
+	char name[MAX_QPATH];
+	int registration_sequence;
+	modtype_t type;
+	int numframes;
+	int flags;
+	/* volume occupied by the model graphics */		
+	vec3_t mins;
+	vec3_t maxs;
+	/* solid volume for clipping (sent from server) */
+	qboolean clipbox;
+	vec3_t clipmins;
+	vec3_t clipmaxs;
+	/* brush model */
+	int firstmodelsurface;
+	int nummodelsurfaces;
+	int numsubmodels;
+	dmodel_t *submodels;
+	int numplanes;
+	mplane_t *planes;
+	int numleafs;	// number of visible leafs, not counting 0
+	mleaf_t *leafs;
+	int numvertexes;
+	mvertex_t *vertexes;
+	int numedges;
+	medge_t *edges;
+	int numnodes;
+	int firstnode;
+	mnode_t *nodes;
+	int numtexinfo;
+	mtexinfo_t *texinfo;
+	int numsurfaces;
+	msurface_t *surfaces;
+	int numsurfedges;
+	int *surfedges;
+	int nummarksurfaces;
+	msurface_t **marksurfaces;
+	dvis_t *vis;
+	uchar *lightdata;
+	/* for alias models and sprites */
+	image_t *skins[MAX_MD2SKINS];
+	void *extradata;
+	int extradatasize;
+};
+
+extern int registration_sequence;
+
+#define PARTICLE_Z_CLIP	8.0
+#define XCENTERING	(1.0 / 2.0)
+#define YCENTERING	(1.0 / 2.0)
+#define CLIP_EPSILON	0.001
+#define BACKFACE_EPSILON	0.01
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+#define NEAR_CLIP	0.01
+enum{
+	CACHE_SIZE = 32,
+	VID_CBITS = 6,
+	VID_GRADES = 1<<VID_CBITS,
+	MAXVERTS = 64,	// max points in a surface polygon
+	/* max points in an intermediate polygon (while processing) */
+	MAXWORKINGVERTS = MAXVERTS+4,
+	/* !!! if this is changed, it must be changed in d_ifacea.h too !!! */
+	MAXHEIGHT = 4096,
+	MAXWIDTH = 4096,
+	/* distance that's always guaranteed to be farther away than anything
+	 * in the scene */
+	INFINITE_DISTANCE = 0x10000,
+	WARP_WIDTH = 320,
+	WARP_HEIGHT = 240,
+	MAX_LBM_HEIGHT = 480,
+
+	/* !!! must be kept the same as in quakeasm.h !!! */
+	TRANSPARENT_COLOR = 0xff,
+	/* !!! if this is changed, it must be changed in d_ifacea.h too !!! */
+	TURB_TEX_SIZE = 64,	// base turbulent texture size
+	/* !!! if this is changed, it must be changed in d_ifacea.h too !!! */
+	CYCLE = 128,	// turbulent cycle size
+
+	SCANBUFFERPAD = 0x1000,
+	DS_SPAN_LIST_END = -128,
+	NUMSTACKEDGES = 2000,
+	MINEDGES = NUMSTACKEDGES,
+	NUMSTACKSURFACES = 1000,
+	MINSURFACES = NUMSTACKSURFACES,
+	MAXSPANS = 3000,
+
+	/* finalvert_t.flags */
+	ALIAS_LEFT_CLIP = 1<<0,
+	ALIAS_TOP_CLIP = 1<<1,
+	ALIAS_RIGHT_CLIP = 1<<2,
+	ALIAS_BOTTOM_CLIP = 1<<3,
+	ALIAS_Z_CLIP = 1<<4,
+	ALIAS_XY_CLIP_MASK = 0xf,
+
+	SURFCACHE_SIZE_AT_320X240 = 1024*768,
+	/* value returned by R_BmodelCheckBBox() if bbox is trivially rejected */
+	BMODEL_FULLY_CLIPPED = 1<<4,
+	MAXALIASVERTS = 2000,    // TODO: tune this
+	ALIAS_Z_CLIP_PLANE = 4,
+	/* turbulence stuff */
+	AMP = 0x80000,
+	AMP2 = 3,
+	SPEED = 20
+};
+struct emitpoint_t{
+	float u;
+	float v;
+	float s;
+	float t;
+	float zi;
+};
+
+/* asm: if you modidify finalvert_t's definition, make sure to change the
+ * associated offsets too! */
+#ifdef SMALL_FINALVERT
+struct finalvert_t{
+	short u;
+	short v;
+	short s;
+	short t;
+	int l;
+	int zi;
+	int flags;
+	float xyz[3];	// eye space
+};
+#else	// !SMALL_FINALVERT
+struct finalvert_t{
+	int u;
+	int v;
+	int s;
+	int t;
+	int l;
+	int zi;
+	int flags;
+	float xyz[3];	// eye space
+};
+#endif	// SMALL_FINALVERT
+
+struct affinetridesc_t{
+	void *pskin;
+	int pskindesc;
+	int skinwidth;
+	int skinheight;
+	dtriangle_t *ptriangles;
+	finalvert_t *pfinalverts;
+	int numtriangles;
+	int drawtype;
+	int seamfixupX16;
+	qboolean do_vis_thresh;
+	int vis_thresh;
+};
+extern affinetridesc_t r_affinetridesc;
+
+struct drawsurf_t{
+	uchar *surfdat;	// destination for generated surface
+	int rowbytes;	// destination logical width in bytes
+	msurface_t *surf;	// description for surface to generate
+	/* adjust for lightmap levels for dynamic lighting */
+	fixed8_t lightadj[MAXLIGHTMAPS];
+	image_t *image;
+	int surfmip;	// mipmapped ratio of surface texels / world pixels
+	int surfwidth;	// in mipmapped texels
+	int surfheight;	// in mipmapped texels
+};
+extern drawsurf_t r_drawsurf;
+
+struct alight_t{
+	int ambientlight;
+	int shadelight;
+	float *plightvec;
+};
+
+/* clipped bmodel edges */
+struct bedge_t{
+	mvertex_t *v[2];
+	bedge_t *pnext;
+};
+
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct clipplane_t{
+	vec3_t normal;
+	float dist;
+	clipplane_t *next;
+	uchar leftedge;
+	uchar rightedge;
+	uchar reserved[2];
+};
+
+struct surfcache_t{
+	surfcache_t *next;
+	surfcache_t **owner;	// nil is an empty chunk of memory
+	int lightadj[MAXLIGHTMAPS];	// checked for strobe flush
+	int dlight;
+	int size;	// including header
+	uint width;
+	uint height;	// DEBUG only needed for debug
+	float mipscale;
+	image_t *image;
+	uchar data[4];	// width*height elements
+};
+extern surfcache_t *sc_rover;
+extern surfcache_t *d_initial_rover;
+
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct espan_t{
+	int u;
+	int v;
+	int count;
+	espan_t *pnext;
+};
+
+/* used by the polygon drawer (R_POLY.C) and sprite setup code (R_SPRITE.C) */
+struct polydesc_t{
+	int nump;
+	emitpoint_t *pverts;
+	uchar *pixels;	// image
+	int pixel_width;	// image width
+	int pixel_height;	// image height
+	vec3_t vup;
+	vec3_t vright;
+	vec3_t vpn;	// in worldspace, for plane eq
+	float dist;
+	float s_offset;
+	float t_offset;
+	float viewer_position[3];
+	void	(*drawspanlet)(void);
+	int stipple_parity;
+};
+
+// FIXME: compress, make a union if that will help
+// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte
+struct surf_t{
+	surf_t *next;	// active surface stack in r_edge.c
+	surf_t *prev;	// used in r_edge.c for active surf stack
+	espan_t *spans;	// pointer to linked list of spans to draw
+	int key;	// sorting key (BSP order)
+	int last_u;	// set during tracing
+	int spanstate;	// 0 = not in span; 1 = in span; -1 in inverted span (end before start)
+	int flags;	// currentface flags
+	msurface_t *msurf;
+	entity_t *entity;
+	float nearzi;	// nearest 1/z on surface, for mipmapping
+	qboolean insubmodel;
+	float d_ziorigin;
+	float d_zistepu;
+	float d_zistepv;
+	int pad[2];	// to 64 bytes
+};
+
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct edge_t{
+	fixed16_t u;
+	fixed16_t u_step;
+	edge_t *prev;
+	edge_t *next;
+	ushort surfs[2];
+	edge_t *nextremove;
+	float nearzi;
+	medge_t *owner;
+};
+
+struct aliastriangleparms_t{
+	finalvert_t *a;
+	finalvert_t *b;
+	finalvert_t *c;
+};
+extern aliastriangleparms_t aliastriangleparms;
+
+struct swstate_t{
+	qboolean fullscreen;
+	int prev_mode;	// last valid SW mode
+	uchar gammatable[256];
+	uchar currentpalette[1024];
+
+};
+extern swstate_t sw_state;
+
+extern int d_spanpixcount;
+extern int r_framecount;	// sequence # of current frame since quake started
+/* scale-up factor for screen u and v on Alias vertices passed to driver */
+extern float r_aliasuvscale;
+extern qboolean r_dowarp;
+extern vec3_t r_pright;
+extern vec3_t r_pup;
+extern vec3_t r_ppn;
+extern void *acolormap;	// FIXME: should go away
+extern int c_surf;
+extern uchar r_warpbuffer[WARP_WIDTH*WARP_HEIGHT];
+extern float scale_for_mip;
+extern qboolean d_roverwrapped;
+
+extern float d_sdivzstepu;
+extern float d_tdivzstepu;
+extern float d_zistepu;
+extern float d_sdivzstepv;
+extern float d_tdivzstepv;
+extern float d_zistepv;
+extern float d_sdivzorigin;
+extern float d_tdivzorigin;
+extern float d_ziorigin;
+extern fixed16_t sadjust;
+extern fixed16_t tadjust;
+extern fixed16_t bbextents;
+extern fixed16_t bbextentt;
+
+extern int d_vrectx;
+extern int d_vrecty;
+extern int d_vrectright_particle;
+extern int d_vrectbottom_particle;
+extern int d_pix_min;
+extern int d_pix_max;
+extern int d_pix_shift;
+
+extern pixel_t *d_viewbuffer;
+extern short *d_pzbuffer;
+extern uint d_zrowbytes;
+extern uint d_zwidth;
+extern short *zspantable[MAXHEIGHT];
+extern int d_scantable[MAXHEIGHT];
+extern int d_minmip;
+extern float d_scalemip[3];
+
+/* surfaces are generated in back to front order by the bsp, so if a surf
+ * pointer is greater than another one, it should be drawn in front.
+ * surfaces[1] is the background, and is used as the active surface stack.
+ * surfaces[0] is a dummy, because index 0 is used to indicate no surface
+ * attached to an edge_t */
+extern int cachewidth;
+extern pixel_t *cacheblock;
+extern int r_screenwidth;
+extern int r_drawnpolycount;
+extern int sintable[1280];
+extern int intsintable[1280];
+extern int blanktable[1280];
+extern vec3_t vup;
+extern vec3_t base_vup;
+extern vec3_t vpn;
+extern vec3_t base_vpn;
+extern vec3_t vright;
+extern vec3_t base_vright;
+extern surf_t *surfaces;
+extern surf_t *surface_p;
+extern surf_t *surf_max;
+
+extern vec3_t sxformaxis[4];	// s axis transformed into viewspace
+extern vec3_t txformaxis[4];	// t axis transformed into viewspac
+extern float xcenter;
+extern float ycenter;
+extern float xscale;
+extern float yscale;
+extern float xscaleinv;
+extern float yscaleinv;
+extern float xscaleshrink;
+extern float yscaleshrink;
+extern int ubasestep;
+extern int errorterm;
+extern int erroradjustup;
+extern int erroradjustdown;
+
+extern clipplane_t view_clipplanes[4];
+extern int *pfrustum_indexes[4];
+
+extern mplane_t screenedge[4];
+extern vec3_t r_origin;
+extern entity_t	r_worldentity;
+extern model_t *currentmodel;
+extern entity_t *currententity;
+extern vec3_t modelorg;
+extern vec3_t r_entorigin;
+extern float verticalFieldOfView;
+extern float xOrigin;
+extern float yOrigin;
+extern int r_visframecount;
+extern msurface_t *r_alpha_surfaces;
+
+extern qboolean insubmodel;
+
+extern int c_faceclip;
+extern int r_polycount;
+extern int r_wholepolycount;
+extern int ubasestep;
+extern int errorterm;
+extern int erroradjustup;
+extern int erroradjustdown;
+extern fixed16_t sadjust;
+extern fixed16_t tadjust;
+extern fixed16_t bbextents;
+extern fixed16_t bbextentt;
+extern mvertex_t *r_ptverts;
+extern mvertex_t *r_ptvertsmax;
+extern float entity_rotation[3][3];
+extern int r_currentkey;
+extern int r_currentbkey;
+extern int r_amodels_drawn;
+extern edge_t *auxedges;
+extern int r_numallocatededges;
+extern edge_t *r_edges;
+extern edge_t *edge_p;
+extern edge_t *edge_max;
+extern edge_t *newedges[MAXHEIGHT];
+extern edge_t *removeedges[MAXHEIGHT];
+extern edge_t edge_head;	// FIXME: make stack vars when debugging done
+extern edge_t edge_tail;
+extern edge_t edge_aftertail;
+extern int r_aliasblendcolor;
+extern float aliasxscale;
+extern float aliasyscale;
+extern float aliasxcenter;
+extern float aliasycenter;
+extern int r_outofsurfaces;
+extern int r_outofedges;
+extern mvertex_t *r_pcurrentvertbase;
+extern int r_maxvalidedgeoffset;
+
+extern float r_time1;
+extern float da_time1;
+extern float da_time2;
+extern float dp_time1;
+extern float dp_time2;
+extern float db_time1;
+extern float db_time2;
+extern float rw_time1;
+extern float rw_time2;
+extern float se_time1;
+extern float se_time2;
+extern float de_time1;
+extern float de_time2;
+extern float dv_time1;
+extern float dv_time2;
+extern int r_frustum_indexes[4*6];
+extern int r_maxsurfsseen;
+extern int r_maxedgesseen;
+extern int r_cnumsurfs;
+extern qboolean r_surfsonstack;
+extern mleaf_t *r_viewleaf;
+extern int r_viewcluster;
+extern int r_oldviewcluster;
+extern int r_clipflags;
+extern int r_dlightframecount;
+extern qboolean r_fov_greater_than_90;
+extern image_t *r_notexture_mip;
+extern model_t *r_worldmodel;
+
+extern refdef_t r_newrefdef;
+extern surfcache_t *sc_rover;
+extern surfcache_t *sc_base;
+extern void *colormap;
+
+extern unsigned d_8to24table[256];	// base
+extern mtexinfo_t *sky_texinfo[6];
+
+extern cvar_t *vid_fullscreen;
+extern cvar_t *vid_gamma;
+extern cvar_t *scr_viewsize;
+extern cvar_t *crosshair;
+
+#define POWERSUIT_SCALE 4.0F
+enum{
+	API_VERSION = 3,
+	MAX_DLIGHTS = 32,
+	MAX_ENTITIES = 128,
+	MAX_PARTICLES = 4096,
+
+	SHELL_RED_COLOR = 0xf2,
+	SHELL_GREEN_COLOR = 0xd0,
+	SHELL_BLUE_COLOR = 0xf3,
+	SHELL_RG_COLOR = 0xdc,
+	SHELL_RB_COLOR = 0x68,
+	SHELL_BG_COLOR = 0x78,
+	SHELL_WHITE_COLOR = 0xd7,
+	/* ROGUE */
+	SHELL_DOUBLE_COLOR = 0xdf,
+	SHELL_HALF_DAM_COLOR = 0x90,
+	SHELL_CYAN_COLOR = 0x72,
+
+	ENTITY_FLAGS = 68
+};
+
+struct entity_t{
+	model_t *model;	// opaque type outside refresh
+	float angles[3];
+
+	/* most recent data */
+	float origin[3];	// also used as RF_BEAM's "from"
+	int frame;	// also used as RF_BEAM's diameter
+	/* previous data for lerping */
+	float oldorigin[3];	// also used as RF_BEAM's "to"
+	int oldframe;
+
+	float backlerp;	// 0.0 = current, 1.0 = old
+	int skinnum;	// also used as RF_BEAM's palette index
+	int lightstyle;	// for flashing entities
+	float alpha;	// ignore if RF_TRANSLUCENT isn't set
+	image_t	*skin;	// nil for inline skin
+	int flags;
+};
+struct dlight_t{
+	vec3_t origin;
+	vec3_t color;
+	float intensity;
+};
+struct particle_t{
+	vec3_t origin;
+	int color;
+	float alpha;
+};
+struct lightstyle_t{
+	float rgb[3];	// 0.0 - 2.0
+	float white;	// highest of rgb
+};
+
+struct refdef_t{
+	int x;	// in virtual screen coordinates
+	int y;
+	int width;
+	int height;
+	float fov_x;
+	float fov_y;
+	float vieworg[3];
+	float viewangles[3];
+	float blend[4];	// rgba 0-1 full screen blend
+	float time;	// time is uesed to auto animate
+	int rdflags;	// RDF_UNDERWATER, etc
+	uchar *areabits;	// if not nil, only areas with set bits will be drawn
+
+	lightstyle_t *lightstyles;	// [MAX_LIGHTSTYLES]
+	int num_entities;
+	entity_t *entities;
+	int num_dlights;
+	dlight_t *dlights;
+	int num_particles;
+	particle_t *particles;
+};
+
+struct refexport_t{
+	int api_version;
+	/* All data that will be used in a level should be registered before
+	 * rendering any frames to prevent disk hits, but they can still be
+	 * registered at a later time if necessary.
+	 * EndRegistration will free any remaining data that wasn't registered.
+	 * Any model_s or skin_s pointers from before the BeginRegistration are
+	 * no longer valid after EndRegistration.
+	 * Skins and images need to be differentiated, because skins are flood
+	 * filled to eliminate mip map edge errors, and pics have an implicit
+	 * "pics/" prepended to the name. (a pic name that starts with a slash
+	 * will not use the "pics/" prefix or the ".pcx" postfix) */
+	qboolean	(*Init)(void *, void *);
+	void	(*Shutdown)(void);
+	void	(*BeginRegistration)(char *);
+	model_t*	(*RegisterModel)(char *);
+	image_t*	(*RegisterSkin)(char *);
+	image_t*	(*RegisterPic)(char *);
+	void	(*SetSky)(char *, float, vec3_t);
+	void	(*EndRegistration)(void);
+	void	(*RenderFrame)(refdef_t *);
+	void	(*DrawGetPicSize)(int *, int *, char *);
+	void	(*DrawPic)(int, int, char *);
+	void	(*DrawStretchPic)(int, int, int, int, char *);
+	void	(*DrawChar)(int, int, int);
+	void	(*DrawTileClear)(int, int, int, int, char *);
+	void	(*DrawFill)(int, int, int, int, int);
+	void	(*DrawFadeScreen)(void);
+	void	(*DrawStretchRaw)(int, int, int, int, int, int, uchar *);
+	void	(*CinematicSetPalette)(uchar *);
+	void	(*BeginFrame)(float);
+	void	(*EndFrame)(void);
+	void	(*AppActivate)(qboolean);
+};
+extern refexport_t re;
+
+struct refimport_t{
+	void	(*Sys_Error)(int, char *, ...);
+	void	(*Cmd_AddCommand)(char *, void(*)(void));
+	void	(*Cmd_RemoveCommand)(char *);
+	int	(*Cmd_Argc)(void);
+	char*	(*Cmd_Argv)(int);
+	void	(*Cmd_ExecuteText)(int, char *);
+	void	(*Con_Printf)(int, char *, ...);
+	/* files will be memory mapped read only; the returned buffer may be
+	 * part of a larger pak file, or a discrete file from anywhere in the
+	 * quake search path
+	 * a -1 return means the file does not exist
+	 * nil can be passed for buf to just determine existance */
+	int	(*FS_LoadFile)(char *, void **);
+	void	(*FS_FreeFile)(void *);
+	char*	(*FS_Gamedir)(void);
+	cvar_t*	(*Cvar_Get)(char *, char *, int);
+	cvar_t*	(*Cvar_Set)(char *, char *);
+	void	(*Cvar_SetValue)(char *, float);
+	qboolean	(*Vid_GetModeInfo)(int *, int *, int);
+	void	(*Vid_MenuInit)(void);
+	void	(*Vid_NewWindow)(int, int);
+};
+extern refimport_t ri;
+
+extern float scr_con_current;
+extern float scr_conlines;	// lines of console to display
+extern int sb_lines;
+extern vrect_t scr_vrect;	// position of render window
+extern char crosshair_pic[MAX_QPATH];
+extern int crosshair_width;
+extern int crosshair_height;
+
+extern cvar_t *s_volume;
+extern cvar_t *s_loadas8bit;
+extern cvar_t *s_khz;
+extern cvar_t *s_show;
+extern cvar_t *s_mixahead;
+extern cvar_t *s_testsound;
+extern cvar_t *s_primary;
+
+enum{
+	MAX_CHANNELS = 32,
+	MAX_RAW_SAMPLES = 8192
+};
+
+/* !!! if this is changed, the asm code must change !!! */
+struct portable_samplepair_t{
+	int left;
+	int right;
+};
+extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
+
+struct sfxcache_t{
+	int length;
+	int loopstart;
+	int speed;	// not needed, because converted on load?
+	int width;
+	int stereo;
+	uchar data[1];	// variable sized
+};
+
+struct sfx_t{
+	char name[MAX_QPATH];
+	int registration_sequence;
+	sfxcache_t *cache;
+	char *truename;
+};
+
+/* a playsound_t will be generated by each call to S_StartSound, when the mixer
+ * reaches playsound->begin, the playsound will be assigned to a channel */
+struct playsound_t{
+	playsound_t *prev;
+	playsound_t *next;
+	sfx_t *sfx;
+	float volume;
+	float attenuation;
+	int entnum;
+	int entchannel;
+	qboolean fixed_origin;	// use origin field instead of entnum's origin
+	vec3_t origin;
+	uint begin;	// begin on this sample
+};
+extern playsound_t s_pendingplays;
+
+struct dma_t{
+	int channels;
+	int samples;	// mono samples in buffer
+	int submission_chunk;	// don't mix less than this #
+	int samplepos;	// in mono samples
+	int samplebits;
+	int speed;
+	uchar *buffer;
+};
+extern dma_t dma;
+
+/* !!! if this is changed, the asm code must change !!! */
+struct channel_t{
+	sfx_t *sfx;	// sfx number
+	int leftvol;	// 0-255 volume
+	int rightvol;	// 0-255 volume
+	int end;	// end time in global paintsamples
+	int pos;	// sample position in sfx
+	int looping;	// where to loop, -1 = no looping OBSOLETE?
+	int entnum;	// to allow overriding a specific sound
+	int entchannel;
+	vec3_t origin;	// only use if fixed_origin is set
+	vec_t dist_mult;	// distance multiplier (attenuation/clipK)
+	int master_vol;	// 0-255 master volume
+	qboolean fixed_origin;	// use origin instead of fetching entnum's origin
+	qboolean autosound;	// from an entity->sound, cleared each frame
+};
+extern channel_t channels[MAX_CHANNELS];
+
+struct wavinfo_t{
+	int rate;
+	int width;
+	int channels;
+	int loopstart;
+	int samples;
+	int dataofs;	// chunk starts this many bytes from file start
+};
+
+extern int paintedtime;
+extern int s_rawend;
+extern vec3_t listener_origin;
+extern vec3_t listener_forward;
+extern vec3_t listener_right;
+extern vec3_t listener_up;
+
+extern cvar_t *in_joystick;
+extern cvar_t *lookspring;
+extern cvar_t *lookstrafe;
+extern cvar_t *sensitivity;
+extern cvar_t *freelook;
+extern cvar_t *m_pitch;
+
+/* key numbers passed to Key_Event() */
+enum{
+	K_TAB = 9,
+	K_ENTER = 13,
+	K_ESCAPE = 27,
+	K_SPACE = 32,
+	/* normal keys should be passed as lowercased ascii */
+	K_BACKSPACE = 127,
+	K_UPARROW = 128,
+	K_DOWNARROW = 129,
+	K_LEFTARROW = 130,
+	K_RIGHTARROW = 131,
+	K_ALT = 132,
+	K_CTRL = 133,
+	K_SHIFT = 134,
+	K_F1 = 135,
+	K_F2 = 136,
+	K_F3 = 137,
+	K_F4 = 138,
+	K_F5 = 139,
+	K_F6 = 140,
+	K_F7 = 141,
+	K_F8 = 142,
+	K_F9 = 143,
+	K_F10 = 144,
+	K_F11 = 145,
+	K_F12 = 146,
+	K_INS = 147,
+	K_DEL = 148,
+	K_PGDN = 149,
+	K_PGUP = 150,
+	K_HOME = 151,
+	K_END = 152,
+	K_KP_HOME = 160,
+	K_KP_UPARROW = 161,
+	K_KP_PGUP = 162,
+	K_KP_LEFTARROW = 163,
+	K_KP_5 = 164,
+	K_KP_RIGHTARROW = 165,
+	K_KP_END = 166,
+	K_KP_DOWNARROW = 167,
+	K_KP_PGDN = 168,
+	K_KP_ENTER = 169,
+	K_KP_INS    = 170,
+	K_KP_DEL = 171,
+	K_KP_SLASH = 172,
+	K_KP_MINUS = 173,
+	K_KP_PLUS = 174,
+	/* mouse buttons generate virtual keys */
+	K_MOUSE1 = 200,
+	K_MOUSE3 = 201,
+	K_MOUSE2 = 202,
+	K_MWHEELUP = 203,
+	K_MWHEELDOWN = 204,
+	/* joystick buttons */
+	K_JOY1 = 205,
+	K_JOY2 = 206,
+	K_JOY3 = 207,
+	K_JOY4 = 208,
+	/* aux keys are for multi-buttoned joysticks to generate so they can
+	 * use the normal binding process */
+	K_AUX1 = 209,
+	K_AUX2 = 210,
+	K_AUX3 = 211,
+	K_AUX4 = 212,
+	K_AUX5 = 213,
+	K_AUX6 = 214,
+	K_AUX7 = 215,
+	K_AUX8 = 216,
+	K_AUX9 = 217,
+	K_AUX10 = 218,
+	K_AUX11 = 219,
+	K_AUX12 = 220,
+	K_AUX13 = 221,
+	K_AUX14 = 222,
+	K_AUX15 = 223,
+	K_AUX16 = 224,
+	K_AUX17 = 225,
+	K_AUX18 = 226,
+	K_AUX19 = 227,
+	K_AUX20 = 228,
+	K_AUX21 = 229,
+	K_AUX22 = 230,
+	K_AUX23 = 231,
+	K_AUX24 = 232,
+	K_AUX25 = 233,
+	K_AUX26 = 234,
+	K_AUX27 = 235,
+	K_AUX28 = 236,
+	K_AUX29 = 237,
+	K_AUX30 = 238,
+	K_AUX31 = 239,
+	K_AUX32 = 240,
+	K_PAUSE = 255
+};
+extern char *keybindings[256];
+extern int key_repeats[256];
+extern int anykeydown;
+extern char chat_buffer[];
+extern int chat_bufferlen;
+extern qboolean chat_team;
+
+enum{
+	NUM_CON_TIMES = 4,
+	CON_TEXTSIZE = 32768
+};
+struct console_t{
+	qboolean initialized;
+	char text[CON_TEXTSIZE];
+	int current;	// line where next message will be printed
+	int x;	// offset in current line for next print
+	int display;	// bottom of console displays this line
+	int ormask;	// high bit mask for colored characters
+	int linewidth;	// characters across screen
+	int totallines;	// total lines in console scrollback
+	float cursorspeed;
+	int vislines;
+	/* cls.realtime time the line was generated for transparent notify lines */
+	float times[NUM_CON_TIMES];
+};
+extern console_t con;
+
+extern cvar_t *cl_stereo_separation;
+extern cvar_t *cl_stereo;
+extern cvar_t *cl_gun;
+extern cvar_t *cl_add_blend;
+extern cvar_t *cl_add_lights;
+extern cvar_t *cl_add_particles;
+extern cvar_t *cl_add_entities;
+extern cvar_t *cl_predict;
+extern cvar_t *cl_footsteps;
+extern cvar_t *cl_noskins;
+extern cvar_t *cl_autoskins;
+extern cvar_t *cl_upspeed;
+extern cvar_t *cl_forwardspeed;
+extern cvar_t *cl_sidespeed;
+extern cvar_t *cl_yawspeed;
+extern cvar_t *cl_pitchspeed;
+extern cvar_t *cl_run;
+extern cvar_t *cl_anglespeedkey;
+extern cvar_t *cl_shownet;
+extern cvar_t *cl_showmiss;
+extern cvar_t *cl_showclamp;
+extern cvar_t *cl_lightlevel;	// FIXME HACK
+extern cvar_t *cl_paused;
+extern cvar_t *cl_timedemo;
+extern cvar_t *cl_vwep;
+
+struct frame_t{
+	qboolean valid;	// cleared if delta parsing was invalid
+	int serverframe;
+	int servertime;	// server time the message is valid for (in msec)
+	int deltaframe;
+	uchar areabits[MAX_MAP_AREAS/8];	// portalarea visibility bits
+	player_state_t playerstate;
+	int num_entities;
+	int parse_entities;	// non-masked index into cl_parse_entities array
+};
+
+struct centity_t{
+	entity_state_t baseline;	// delta from this if not from a previous frame
+	entity_state_t current;
+	entity_state_t prev;	// will always be valid, but can be just a copy of current
+	int serverframe;	// if not current, this ent isn't in the frame
+	int trailcount;	// for diminishing grenade trails
+	vec3_t lerp_origin;	// for trails (variable hz)
+	int fly_stoptime;
+};
+extern centity_t cl_entities[MAX_EDICTS];
+
+enum{
+	MAX_CLIENTWEAPONMODELS = 20
+};
+struct clientinfo_t{
+	char name[MAX_QPATH];
+	char cinfo[MAX_QPATH];
+	image_t	*skin;
+	image_t	*icon;
+	char iconname[MAX_QPATH];
+	model_t	*model;
+	model_t	*weaponmodel[MAX_CLIENTWEAPONMODELS];
+};
+extern char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
+extern int num_cl_weaponmodels;
+
+enum{
+	CMD_BACKUP = 64	// allow a lot of command backups for very fast systems
+};
+/* client_state_t is wiped completely at every server map change */
+struct client_state_t{
+	int timeoutcount;
+	int timedemo_frames;
+	int timedemo_start;
+	qboolean refresh_prepped;	// false if on new level or new ref dll
+	qboolean sound_prepped;	// ambient sounds can start
+	qboolean force_refdef;	// vid has changed, so we can't use a paused refdef
+	int parse_entities;	// index (not anded off) into cl_parse_entities[]
+	usercmd_t cmd;
+	usercmd_t cmds[CMD_BACKUP];	// each mesage will send several old cmds
+	int cmd_time[CMD_BACKUP];	// time sent, for calculating pings
+	short predicted_origins[CMD_BACKUP][3];	// for debug comparing against server
+	float predicted_step;	// for stair up smoothing
+	uint predicted_step_time;
+	vec3_t predicted_origin;	// generated by CL_PredictMovement
+	vec3_t predicted_angles;
+	vec3_t prediction_error;
+	frame_t frame;	// received from server
+	int surpressCount;	// number of messages rate supressed
+	frame_t frames[UPDATE_BACKUP];
+
+	/* the client maintains its own idea of view angles, which are sent to
+	 * the server each frame. it is cleared to 0 upon entering each level.
+	 * the server sends a delta each frame which is added to the locally
+	 * tracked view angles to account for standing on rotating objects, and
+	 * teleport direction changes. */
+	vec3_t viewangles;
+	/* time that the client is rendering at. always <= cls.realtime */
+	int time;	// this is the time value that the client
+	float lerpfrac;	// between oldframe and frame
+	refdef_t refdef;
+	vec3_t v_forward;
+	vec3_t v_right;
+	vec3_t v_up;	// set when refdef.angles is set
+
+	/* transient data from server */
+	char layout[1024];	// general 2D overlay
+	int inventory[MAX_ITEMS];
+
+	// FIXME: move this cinematic stuff into the cin_t structure
+	/* non-gameserver infornamtion */
+	FILE *cinematic_file;
+	int cinematictime;	// cls.realtime for first cinematic frame
+	int cinematicframe;
+	char cinematicpalette[768];
+	qboolean cinematicpalette_active;
+
+	/* server state information */
+	qboolean attractloop;	// running the attract loop, any key will menu
+	int servercount;	// server identification for prespawns
+	char gamedir[MAX_QPATH];
+	int playernum;
+	char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
+
+	/* locally derived information from server state */
+	model_t *model_draw[MAX_MODELS];
+	cmodel_t *model_clip[MAX_MODELS];
+	sfx_t *sound_precache[MAX_SOUNDS];
+	image_t *image_precache[MAX_IMAGES];
+	clientinfo_t clientinfo[MAX_CLIENTS];
+	clientinfo_t baseclientinfo;
+};
+extern client_state_t cl;
+
+typedef enum connstate_t{
+	ca_uninitialized,
+	ca_disconnected,	// not talking to a server
+	ca_connecting,	// sending request packets to the server
+	ca_connected,	// netchan_t established, waiting for svc_serverdata
+	ca_active	// game views should be displayed
+}connstate_t;
+typedef enum dltype_t{
+	dl_none,
+	dl_model,
+	dl_sound,
+	dl_skin,
+	dl_single
+}dltype_t;
+typedef enum keydest_t{
+	key_game,
+	key_console,
+	key_message,
+	key_menu
+}keydest_t;
+/* the client_static_t structure is persistant through an arbitrary number of
+ * server connections */
+struct client_static_t{
+	connstate_t state;
+	keydest_t key_dest;
+	int framecount;
+	int realtime;	// always increasing, no clamping, etc
+	float frametime;	// seconds since last frame
+
+	/* screen rendering information */
+	/* showing loading plaque between levels; if time gets >30 sec ahead,
+	 * break it */
+	float disable_screen;
+	/* on receiving a frame and cl.servercount > cls.disable_servercount,
+	 * clear disable_screen */
+	int disable_servercount;
+
+	/* connection information */
+	char servername[MAX_OSPATH];	// name of server from original connect
+	float connect_time;	// for connection retransmits
+	/* ushort allowing servers to work around address translating routers */
+	int quakePort;
+	netchan_t netchan;
+	int serverProtocol;	// in case we are doing some kind of version hack
+	int challenge;	// from the server to use for connecting
+
+	FILE *download;			// file transfer from server
+	char downloadtempname[MAX_OSPATH];
+	char downloadname[MAX_OSPATH];
+	int downloadnumber;
+	dltype_t downloadtype;
+	int downloadpercent;
+
+	/* demo recording info must be here, so it isn't cleared on level change */
+	qboolean demorecording;
+	qboolean demowaiting;	// don't record until a non-delta message is received
+	FILE *demofile;
+};
+extern client_static_t cls;
+
+struct cdlight_t{
+	int key;	// so entities can reuse same entry
+	vec3_t color;
+	vec3_t origin;
+	float radius;
+	float die;	// stop lighting after this time
+	float decay;	// drop this each second
+	float minlight;	// don't add when contributing less
+};
+extern cdlight_t cl_dlights[MAX_DLIGHTS];
+
+enum{
+	MAX_SUSTAINS = 32
+};
+struct cl_sustain_t{
+	int id;
+	int type;
+	int endtime;
+	int nextthink;
+	int thinkinterval;
+	vec3_t org;
+	vec3_t dir;
+	int color;
+	int count;
+	int magnitude;
+	void	(*think)(cl_sustain_t *);
+};
+
+#define INSTANT_PARTICLE -10000.0
+enum{
+	PARTICLE_GRAVITY = 40,
+	BLASTER_PARTICLE_COLOR = 0xe0
+};
+struct cparticle_t{
+	cparticle_t *next;
+	float time;
+	vec3_t org;
+	vec3_t vel;
+	vec3_t accel;
+	float color;
+	float colorvel;
+	float alpha;
+	float alphavel;
+};
+
+struct kbutton_t{
+	int down[2];	// key nums holding it down
+	uint downtime;	// msec timestamp
+	uint msec;	// msec down this frame
+	int state;
+};
+extern kbutton_t in_mlook;
+extern kbutton_t in_klook;
+extern kbutton_t in_strafe;
+extern kbutton_t in_speed;
+
+extern int gun_frame;
+extern model_t *gun_model;
+
+enum{
+	MAXMENUITEMS = 64,
+	MTYPE_SLIDER = 0,
+	MTYPE_LIST = 1,
+	MTYPE_ACTION = 2,
+	MTYPE_SPINCONTROL = 3,
+	MTYPE_SEPARATOR   = 4,
+	MTYPE_FIELD = 5,
+	QMF_LEFT_JUSTIFY = 1<<0,
+	QMF_GRAYED = 1<<1,
+	QMF_NUMBERSONLY = 1<<2,
+};
+struct menuframework_t{
+	int x;
+	int y;
+	int cursor;
+	int nitems;
+	int nslots;
+	void *items[64];
+	char *statusbar;
+	void	(*cursordraw)(menuframework_t *);
+};
+struct menucommon_t{
+	int type;
+	char *name;
+	int x;
+	int y;
+	menuframework_t *parent;
+	int cursor_offset;
+	int localdata[4];
+	uint flags;
+	char *statusbar;
+	void	(*callback)(void *);
+	void	(*statusbarfunc)(void *);
+	void	(*ownerdraw)(void *);
+	void	(*cursordraw)(void *);
+};
+struct menufield_t{
+	menucommon_t generic;
+	char buffer[80];
+	int cursor;
+	int length;
+	int visible_length;
+	int visible_offset;
+};
+struct menuslider_t{
+	menucommon_t generic;
+	float minvalue;
+	float maxvalue;
+	float curvalue;
+	float range;
+};
+struct menulist_t{
+	menucommon_t generic;
+	int curvalue;
+	char **itemnames;
+};
+struct menuaction_t{
+	menucommon_t generic;
+};
+struct menuseparator_t{
+	menucommon_t generic;
+};
+
+extern cvar_t *sv_paused;
+extern cvar_t *maxclients;
+/* don't reload level state when reentering */
+extern cvar_t *sv_noreload;
+/* don't reload level state when reentering development tool */
+extern cvar_t *sv_airaccelerate;
+extern cvar_t *sv_enforcetime;
+
+typedef enum redirect_t{
+	RD_NONE,
+	RD_CLIENT,
+	RD_PACKET
+}redirect_t;
+
+typedef enum server_state_t{
+	ss_dead,	// no map loaded
+	ss_loading,	// spawning level edicts
+	ss_game,	// actively running
+	ss_cinematic,
+	ss_demo,
+	ss_pic
+}server_state_t;
+/* some qc commands are only valid before the server has finished initializing
+ * (precache commands, static sounds / objects, etc) */
+struct server_t{
+	server_state_t state;	// precache commands are only valid during load
+	qboolean attractloop;	// running cinematics and demos for the local system only
+	qboolean loadgame;	// client begins should reuse existing entity
+	uint time;	// always sv.framenum * 100 msec
+	int framenum;
+	char name[MAX_QPATH];	// map name, or cinematic name
+	cmodel_t *models[MAX_MODELS];
+	char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
+	entity_state_t baselines[MAX_EDICTS];
+	/* the multicast buffer is used to send a message to a set of clients
+	 * it is only used to marshall data until SV_Multicast is called */
+	sizebuf_t multicast;
+	uchar multicast_buf[MAX_MSGLEN];
+	/* demo server information */
+	FILE *demofile;
+	qboolean timedemo;	// don't time sync
+};
+extern server_t sv;	// local server
+
+#define EDICT_NUM(n) ((edict_t *)((uchar *)ge->edicts + ge->edict_size*(n)))
+#define NUM_FOR_EDICT(e) ( ((uchar *)(e)-(uchar *)ge->edicts ) / ge->edict_size)
+
+struct client_frame_t{
+	int areabytes;
+	uchar areabits[MAX_MAP_AREAS/8];	// portalarea visibility bits
+	player_state_t ps;
+	int num_entities;
+	int first_entity;	// into the circular sv_packet_entities[]
+	int senttime;	// for ping calculations
+};
+
+typedef enum clstate_t{
+	cs_free,	// can be reused for a new connection
+	cs_zombie,	// client disconnected, don't reuse connection for a couple secs
+	cs_connected,	// has been assigned to a client_t, but not in game yet
+	cs_spawned	// client is fully in game
+}clstate_t;
+
+enum{
+	LATENCY_COUNTS = 16,
+	RATE_MESSAGES = 10
+};
+struct client_t{
+	clstate_t state;
+	char userinfo[MAX_INFO_STRING];	// name, etc
+	int lastframe;	// for delta compression
+	usercmd_t lastcmd;	// for filling in big drops
+	/* every seconds this is reset, if user commands exhaust it, assume
+	 * time cheating */
+	int commandMsec;
+	int frame_latency[LATENCY_COUNTS];
+	int ping;
+	int message_size[RATE_MESSAGES];	// used to rate drop packets
+	int rate;
+	int surpressCount;	// number of messages rate supressed
+	edict_t *edict;	// EDICT_NUM(clientnum+1)
+	char name[32];	// extracted from userinfo, high bits masked
+	int messagelevel;	// for filtering printed messages
+	/* the datagram is written to by sound calls, prints, temp ents, etc.
+	 * it can be harmlessly overflowed. */
+	sizebuf_t datagram;
+	uchar datagram_buf[MAX_MSGLEN];
+	client_frame_t frames[UPDATE_BACKUP];	// updates can be delta'd from here
+	uchar *download;	// file being downloaded
+	int downloadsize;	// total bytes (can't use EOF because of paks)
+	int downloadcount;	// bytes sent
+	int lastmessage;	// sv.framenum when packet was last received
+	int lastconnect;
+	int challenge;	// challenge of this user, randomly generated
+	netchan_t netchan;
+};
+extern client_t *sv_client;
+
+/* a client can leave the server in one of four ways: dropping properly by
+ * quiting or disconnecting; timing out if no valid messages are received for
+ * timeout.value seconds; getting kicked off by the server operator; a program
+ * error, like an overflowed reliable buffer */
+enum{
+	/* for preventing denial of service attacks that could cycle all of
+	 * them out before legitimate users connected */
+	MAX_CHALLENGES = 1024,
+	SV_OUTPUTBUF_LENGTH = MAX_MSGLEN - 16
+};
+struct challenge_t{
+	netadr_t adr;
+	int challenge;
+	int time;
+};
+struct server_static_t{
+	qboolean initialized;	// sv_init has completed
+	int realtime;	// always increasing, no clamping, etc
+	char mapcmd[MAX_TOKEN_CHARS];	// ie: *intro.cin+base 
+	int spawncount;	// incremented each server start used to check late spawns
+	client_t *clients;	// [maxclients->value];
+	int num_client_entities;	// maxclients->value*UPDATE_BACKUP*MAX_PACKET_ENTITIES
+	int next_client_entities;	// next client_entity to use
+	entity_state_t *client_entities;	// [num_client_entities]
+	int last_heartbeat;
+	challenge_t challenges[MAX_CHALLENGES];	// to prevent invalid IPs from connecting
+	/* serverrecord values */
+	FILE *demofile;
+	sizebuf_t demo_multicast;
+	uchar demo_multicast_buf[MAX_MSGLEN];
+};
+extern server_static_t svs;	// persistant server info
+
+extern edict_t *sv_player;
+extern char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
--- /dev/null
+++ b/files.c
@@ -1,0 +1,860 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+// define this to dissalow any data but the demo pak file
+//#define	NO_ADDONS
+
+// if a packfile directory differs from this, it is assumed to be hacked
+// Full version
+#define	PAK0_CHECKSUM	0x40e614e0
+// Demo
+//#define	PAK0_CHECKSUM	0xb2c6d7ea
+// OEM
+//#define	PAK0_CHECKSUM	0x78e135c
+
+/*
+=============================================================================
+
+QUAKE FILESYSTEM
+
+=============================================================================
+*/
+
+
+//
+// in memory
+//
+
+typedef struct
+{
+	char	name[MAX_QPATH];
+	int		filepos, filelen;
+} packfile_t;
+
+typedef struct pack_s
+{
+	char	filename[MAX_OSPATH];
+	FILE	*handle;
+	int		numfiles;
+	packfile_t	*files;
+} pack_t;
+
+char	fs_gamedir[MAX_OSPATH];
+cvar_t	*fs_basedir;
+cvar_t	*fs_cddir;
+cvar_t	*fs_gamedirvar;
+
+typedef struct filelink_s
+{
+	struct filelink_s	*next;
+	char	*from;
+	int		fromlength;
+	char	*to;
+} filelink_t;
+
+filelink_t	*fs_links;
+
+typedef struct searchpath_s
+{
+	char	filename[MAX_OSPATH];
+	pack_t	*pack;		// only one of filename / pack will be used
+	struct searchpath_s *next;
+} searchpath_t;
+
+searchpath_t	*fs_searchpaths;
+searchpath_t	*fs_base_searchpaths;	// without gamedirs
+
+
+/*
+
+All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.
+
+The "base directory" is the path to the directory holding the quake.exe and all game directories.  The sys_* files pass this to host_init in quakeparms_t->basedir.  This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory.  The base directory is
+only used during filesystem initialization.
+
+The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to.  This can be overridden with the "-game" command line parameter.  The game directory can never be changed while quake is executing.  This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.
+
+*/
+
+
+/*
+================
+FS_filelength
+================
+*/
+int FS_filelength (FILE *f)
+{
+	int		pos;
+	int		end;
+
+	pos = ftell (f);
+	fseek (f, 0, SEEK_END);
+	end = ftell (f);
+	fseek (f, pos, SEEK_SET);
+
+	return end;
+}
+
+
+/*
+============
+FS_CreatePath
+
+Creates any directories needed to store the given filename
+============
+*/
+void	FS_CreatePath (char *path)
+{
+	char	*ofs;
+	
+	for (ofs = path+1 ; *ofs ; ofs++)
+	{
+		if (*ofs == '/')
+		{	// create the directory
+			*ofs = 0;
+			Sys_Mkdir (path);
+			*ofs = '/';
+		}
+	}
+}
+
+
+/*
+==============
+FS_FCloseFile
+
+For some reason, other dll's can't just cal fclose()
+on files returned by FS_FOpenFile...
+==============
+*/
+void FS_FCloseFile (FILE *f)
+{
+	fclose (f);
+}
+
+
+// RAFAEL
+/*
+	Developer_searchpath
+*/
+int	Developer_searchpath (int /*who*/)
+{
+	
+	// PMM - warning removal
+//	char	*start;
+	searchpath_t	*search;
+
+	for (search = fs_searchpaths ; search ; search = search->next)
+	{
+		if (strstr (search->filename, "xatrix"))
+			return 1;
+
+		if (strstr (search->filename, "rogue"))
+			return 2;
+/*
+		start = strchr (search->filename, ch);
+
+		if (start == NULL)
+			continue;
+
+		if (strcmp (start ,"xatrix") == 0)
+			return (1);
+*/
+	}
+	return (0);
+
+}
+
+
+/*
+===========
+FS_FOpenFile
+
+Finds the file in the search path.
+returns filesize and an open FILE *
+Used for streaming data out of either a pak file or
+a seperate file.
+===========
+*/
+int file_from_pak = 0;
+#ifndef NO_ADDONS
+int FS_FOpenFile (char *filename, FILE **file)
+{
+	searchpath_t	*search;
+	char			netpath[MAX_OSPATH];
+	pack_t			*pak;
+	int				i;
+	filelink_t		*link;
+
+	file_from_pak = 0;
+
+	// check for links first
+	for (link = fs_links ; link ; link=link->next)
+	{
+		if (!strncmp (filename, link->from, link->fromlength))
+		{
+			Com_sprintf (netpath, sizeof(netpath), "%s%s",link->to, filename+link->fromlength);
+			*file = fopen (netpath, "rb");
+			if (*file)
+			{		
+				Com_DPrintf ("link file: %s\n",netpath);
+				return FS_filelength (*file);
+			}
+			return -1;
+		}
+	}
+
+//
+// search through the path, one element at a time
+//
+	for (search = fs_searchpaths ; search ; search = search->next)
+	{
+	// is the element a pak file?
+		if (search->pack)
+		{
+		// look through all the pak file elements
+			pak = search->pack;
+			for (i=0 ; i<pak->numfiles ; i++)
+				if (!cistrcmp (pak->files[i].name, filename))
+				{	// found it!
+					file_from_pak = 1;
+					Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
+				// open a new file on the pakfile
+					*file = fopen (pak->filename, "rb");
+					if (!*file)
+						Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);	
+					fseek (*file, pak->files[i].filepos, SEEK_SET);
+					return pak->files[i].filelen;
+				}
+		}
+		else
+		{		
+	// check a file in the directory tree
+			
+			Com_sprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename);
+			
+			*file = fopen (netpath, "rb");
+			if (!*file)
+				continue;
+			
+			Com_DPrintf ("FindFile: %s\n",netpath);
+
+			return FS_filelength (*file);
+		}
+		
+	}
+	
+	Com_DPrintf ("FindFile: can't find %s\n", filename);
+	
+	*file = NULL;
+	return -1;
+}
+
+#else
+
+// this is just for demos to prevent add on hacking
+
+int FS_FOpenFile (char *filename, FILE **file)
+{
+	searchpath_t	*search;
+	char			netpath[MAX_OSPATH];
+	pack_t			*pak;
+	int				i;
+
+	file_from_pak = 0;
+
+	// get config from directory, everything else from pak
+	if (!strcmp(filename, "config.cfg") || !strncmp(filename, "players/", 8))
+	{
+		Com_sprintf (netpath, sizeof(netpath), "%s/%s",FS_Gamedir(), filename);
+		
+		*file = fopen (netpath, "rb");
+		if (!*file)
+			return -1;
+		
+		Com_DPrintf ("FindFile: %s\n",netpath);
+
+		return FS_filelength (*file);
+	}
+
+	for (search = fs_searchpaths ; search ; search = search->next)
+		if (search->pack)
+			break;
+	if (!search)
+	{
+		*file = NULL;
+		return -1;
+	}
+
+	pak = search->pack;
+	for (i=0 ; i<pak->numfiles ; i++)
+		if (!cistrcmp (pak->files[i].name, filename))
+		{	// found it!
+			file_from_pak = 1;
+			Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
+		// open a new file on the pakfile
+			*file = fopen (pak->filename, "rb");
+			if (!*file)
+				Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);	
+			fseek (*file, pak->files[i].filepos, SEEK_SET);
+			return pak->files[i].filelen;
+		}
+	
+	Com_DPrintf ("FindFile: can't find %s\n", filename);
+	
+	*file = NULL;
+	return -1;
+}
+
+#endif
+
+
+/*
+=================
+FS_ReadFile
+
+Properly handles partial reads
+=================
+*/
+void CDAudio_Stop(void);
+#define	MAX_READ	0x10000		// read in blocks of 64k
+void FS_Read (void *buffer, int len, FILE *f)
+{
+	int		block, remaining;
+	int		read;
+	byte	*buf;
+	int		tries;
+
+	buf = (byte *)buffer;
+
+	// read in chunks for progress bar
+	remaining = len;
+	tries = 0;
+	while (remaining)
+	{
+		block = remaining;
+		if (block > MAX_READ)
+			block = MAX_READ;
+		read = fread (buf, 1, block, f);
+		if (read == 0)
+		{
+			// we might have been trying to read from a CD
+			if (!tries)
+			{
+				tries = 1;
+				CDAudio_Stop();
+			}
+			else
+				Com_Error (ERR_FATAL, "FS_Read: 0 bytes read");
+		}
+
+		if (read == -1)
+			Com_Error (ERR_FATAL, "FS_Read: -1 bytes read");
+
+		// do some progress bar thing here...
+
+		remaining -= read;
+		buf += read;
+	}
+}
+
+/*
+============
+FS_LoadFile
+
+Filename are reletive to the quake search path
+a null buffer will just return the file length without loading
+============
+*/
+int FS_LoadFile (char *path, void **buffer)
+{
+	FILE	*h;
+	byte	*buf;
+	int		len;
+
+// look for it in the filesystem or pack files
+	len = FS_FOpenFile (path, &h);
+	if (!h)
+	{
+		if (buffer)
+			*buffer = NULL;
+		return -1;
+	}
+	
+	if (!buffer)
+	{
+		fclose (h);
+		return len;
+	}
+
+	buf = Z_Malloc(len);
+	*buffer = buf;
+
+	FS_Read (buf, len, h);
+
+	fclose (h);
+
+	return len;
+}
+
+
+/*
+=============
+FS_FreeFile
+=============
+*/
+void FS_FreeFile (void *buffer)
+{
+	Z_Free (buffer);
+}
+
+/*
+=================
+FS_LoadPackFile
+
+Takes an explicit (not game tree related) path to a pak file.
+
+Loads the header and directory, adding the files at the beginning
+of the list so they override previous pack files.
+=================
+*/
+pack_t *FS_LoadPackFile (char *packfile)
+{
+	dpackheader_t	header;
+	int				i;
+	packfile_t		*newfiles;
+	int				numpackfiles;
+	pack_t			*pack;
+	FILE			*packhandle;
+	dpackfile_t		info[MAX_FILES_IN_PACK];
+	unsigned		checksum;
+
+	packhandle = fopen(packfile, "rb");
+	if (!packhandle)
+		return NULL;
+
+	fread (&header, 1, sizeof(header), packhandle);
+	if (LittleLong(header.ident) != IDPAKHEADER)
+		Com_Error (ERR_FATAL, "%s is not a packfile", packfile);
+	header.dirofs = LittleLong (header.dirofs);
+	header.dirlen = LittleLong (header.dirlen);
+
+	numpackfiles = header.dirlen / sizeof(dpackfile_t);
+
+	if (numpackfiles > MAX_FILES_IN_PACK)
+		Com_Error (ERR_FATAL, "%s has %i files", packfile, numpackfiles);
+
+	newfiles = Z_Malloc (numpackfiles * sizeof(packfile_t));
+
+	fseek (packhandle, header.dirofs, SEEK_SET);
+	fread (info, 1, header.dirlen, packhandle);
+
+// crc the directory to check for modifications
+	checksum = Com_BlockChecksum ((void *)info, header.dirlen);
+
+#ifdef NO_ADDONS
+	if (checksum != PAK0_CHECKSUM)
+		return NULL;
+#else
+	USED(checksum);
+#endif
+// parse the directory
+	for (i=0 ; i<numpackfiles ; i++)
+	{
+		strcpy (newfiles[i].name, info[i].name);
+		newfiles[i].filepos = LittleLong(info[i].filepos);
+		newfiles[i].filelen = LittleLong(info[i].filelen);
+	}
+
+	pack = Z_Malloc (sizeof (pack_t));
+	strcpy (pack->filename, packfile);
+	pack->handle = packhandle;
+	pack->numfiles = numpackfiles;
+	pack->files = newfiles;
+	
+	Com_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
+	return pack;
+}
+
+
+/*
+================
+FS_AddGameDirectory
+
+Sets fs_gamedir, adds the directory to the head of the path,
+then loads and adds pak1.pak pak2.pak ... 
+================
+*/
+void FS_AddGameDirectory (char *dir)
+{
+	int				i;
+	searchpath_t	*search;
+	pack_t			*pak;
+	char			pakfile[MAX_OSPATH];
+
+	strcpy (fs_gamedir, dir);
+
+	//
+	// add the directory to the search path
+	//
+	search = Z_Malloc (sizeof(searchpath_t));
+	strcpy (search->filename, dir);
+	search->next = fs_searchpaths;
+	fs_searchpaths = search;
+
+	//
+	// add any pak files in the format pak0.pak pak1.pak, ...
+	//
+	for (i=0; i<10; i++)
+	{
+		Com_sprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", dir, i);
+		pak = FS_LoadPackFile (pakfile);
+		if (!pak)
+			continue;
+		search = Z_Malloc (sizeof(searchpath_t));
+		search->pack = pak;
+		search->next = fs_searchpaths;
+		fs_searchpaths = search;		
+	}
+
+
+}
+
+/*
+============
+FS_Gamedir
+
+Called to find where to write a file (demos, savegames, etc)
+============
+*/
+char *FS_Gamedir (void)
+{
+	return fs_gamedir;
+}
+
+/*
+=============
+FS_ExecAutoexec
+=============
+*/
+void FS_ExecAutoexec (void)
+{
+	char *dir;
+	char name [MAX_QPATH];
+
+	dir = Cvar_VariableString("gamedir");
+	if (*dir)
+		Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, dir); 
+	else
+		Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, BASEDIRNAME); 
+	if (Sys_FindFirst(name, 0, SFF_SUBDIR))
+		Cbuf_AddText ("exec autoexec.cfg\n");
+	Sys_FindClose();
+}
+
+
+/*
+================
+FS_SetGamedir
+
+Sets the gamedir and path to a different directory.
+================
+*/
+void FS_SetGamedir (char *dir)
+{
+	searchpath_t	*next;
+
+	if (strstr(dir, "..") || strstr(dir, "/")
+		|| strstr(dir, "\\") || strstr(dir, ":") )
+	{
+		Com_Printf ("Gamedir should be a single filename, not a path\n");
+		return;
+	}
+
+	//
+	// free up any current game dir info
+	//
+	while (fs_searchpaths != fs_base_searchpaths)
+	{
+		if (fs_searchpaths->pack)
+		{
+			fclose (fs_searchpaths->pack->handle);
+			Z_Free (fs_searchpaths->pack->files);
+			Z_Free (fs_searchpaths->pack);
+		}
+		next = fs_searchpaths->next;
+		Z_Free (fs_searchpaths);
+		fs_searchpaths = next;
+	}
+
+	//
+	// flush all data, so it will be forced to reload
+	//
+	if (dedicated && !dedicated->value)
+		Cbuf_AddText ("vid_restart\nsnd_restart\n");
+
+	Com_sprintf (fs_gamedir, sizeof(fs_gamedir), "%s/%s", fs_basedir->string, dir);
+
+	if (!strcmp(dir,BASEDIRNAME) || (*dir == 0))
+	{
+		Cvar_FullSet ("gamedir", "", CVAR_SERVERINFO|CVAR_NOSET);
+		Cvar_FullSet ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
+	}
+	else
+	{
+		Cvar_FullSet ("gamedir", dir, CVAR_SERVERINFO|CVAR_NOSET);
+		if (fs_cddir->string[0])
+			FS_AddGameDirectory (va("%s/%s", fs_cddir->string, dir) );
+		FS_AddGameDirectory (va("%s/%s", fs_basedir->string, dir) );
+	}
+}
+
+
+/*
+================
+FS_Link_f
+
+Creates a filelink_t
+================
+*/
+void FS_Link_f (void)
+{
+	filelink_t	*l, **prev;
+
+	if (Cmd_Argc() != 3)
+	{
+		Com_Printf ("USAGE: link <from> <to>\n");
+		return;
+	}
+
+	// see if the link already exists
+	prev = &fs_links;
+	for (l=fs_links ; l ; l=l->next)
+	{
+		if (!strcmp (l->from, Cmd_Argv(1)))
+		{
+			Z_Free (l->to);
+			if (!strlen(Cmd_Argv(2)))
+			{	// delete it
+				*prev = l->next;
+				Z_Free (l->from);
+				Z_Free (l);
+				return;
+			}
+			l->to = CopyString (Cmd_Argv(2));
+			return;
+		}
+		prev = &l->next;
+	}
+
+	// create a new link
+	l = Z_Malloc(sizeof(*l));
+	l->next = fs_links;
+	fs_links = l;
+	l->from = CopyString(Cmd_Argv(1));
+	l->fromlength = strlen(l->from);
+	l->to = CopyString(Cmd_Argv(2));
+}
+
+/*
+** FS_ListFiles
+*/
+char **FS_ListFiles( char *findname, int *numfiles, unsigned musthave, unsigned canthave )
+{
+	char *s;
+	int nfiles = 0;
+	char **list;
+
+	s = Sys_FindFirst( findname, musthave, canthave );
+	while ( s )
+	{
+		if ( s[strlen(s)-1] != '.' )
+			nfiles++;
+		s = Sys_FindNext( musthave, canthave );
+	}
+	Sys_FindClose ();
+
+	if ( !nfiles )
+		return NULL;
+
+	nfiles++; // add space for a guard
+	*numfiles = nfiles;
+
+	list = malloc( sizeof( char * ) * nfiles );
+	memset( list, 0, sizeof( char * ) * nfiles );
+
+	s = Sys_FindFirst( findname, musthave, canthave );
+	nfiles = 0;
+	while ( s )
+	{
+		if ( s[strlen(s)-1] != '.' )
+		{
+			list[nfiles] = strdup( s );
+			nfiles++;
+		}
+		s = Sys_FindNext( musthave, canthave );
+	}
+	Sys_FindClose ();
+
+	return list;
+}
+
+/*
+** FS_Dir_f
+*/
+void FS_Dir_f( void )
+{
+	char	*path = NULL;
+	char	findname[1024];
+	char	wildcard[1024] = "*.*";
+	char	**dirnames;
+	int		ndirs;
+
+	if ( Cmd_Argc() != 1 )
+	{
+		strcpy( wildcard, Cmd_Argv( 1 ) );
+	}
+
+	while ( ( path = FS_NextPath( path ) ) != NULL )
+	{
+		char *tmp = findname;
+
+		Com_sprintf( findname, sizeof(findname), "%s/%s", path, wildcard );
+
+		while ( *tmp != 0 )
+		{
+			if ( *tmp == '\\' ) 
+				*tmp = '/';
+			tmp++;
+		}
+		Com_Printf( "Directory of %s\n", findname );
+		Com_Printf( "----\n" );
+
+		if ( ( dirnames = FS_ListFiles( findname, &ndirs, 0, 0 ) ) != 0 )
+		{
+			int i;
+
+			for ( i = 0; i < ndirs-1; i++ )
+			{
+				if ( strrchr( dirnames[i], '/' ) )
+					Com_Printf( "%s\n", strrchr( dirnames[i], '/' ) + 1 );
+				else
+					Com_Printf( "%s\n", dirnames[i] );
+
+				free( dirnames[i] );
+			}
+			free( dirnames );
+		}
+		Com_Printf( "\n" );
+	};
+}
+
+/*
+============
+FS_Path_f
+
+============
+*/
+void FS_Path_f (void)
+{
+	searchpath_t	*s;
+	filelink_t		*l;
+
+	Com_Printf ("Current search path:\n");
+	for (s=fs_searchpaths ; s ; s=s->next)
+	{
+		if (s == fs_base_searchpaths)
+			Com_Printf ("----------\n");
+		if (s->pack)
+			Com_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
+		else
+			Com_Printf ("%s\n", s->filename);
+	}
+
+	Com_Printf ("\nLinks:\n");
+	for (l=fs_links ; l ; l=l->next)
+		Com_Printf ("%s : %s\n", l->from, l->to);
+}
+
+/*
+================
+FS_NextPath
+
+Allows enumerating all of the directories in the search path
+================
+*/
+char *FS_NextPath (char *prevpath)
+{
+	searchpath_t	*s;
+	char			*prev;
+
+	if (!prevpath)
+		return fs_gamedir;
+
+	prev = fs_gamedir;
+	for (s=fs_searchpaths ; s ; s=s->next)
+	{
+		if (s->pack)
+			continue;
+		if (prevpath == prev)
+			return s->filename;
+		prev = s->filename;
+	}
+
+	return NULL;
+}
+
+
+/*
+================
+FS_InitFilesystem
+================
+*/
+void FS_InitFilesystem (void)
+{
+	static char homedir[1024];
+	char *home;
+
+	Cmd_AddCommand ("path", FS_Path_f);
+	Cmd_AddCommand ("link", FS_Link_f);
+	Cmd_AddCommand ("dir", FS_Dir_f );
+
+	//
+	// basedir <path>
+	// allows the game to run from outside the data tree
+	//
+	if(home = getenv("home")){
+		snprint(homedir, sizeof homedir, "%s/lib/quake2", home);
+		free(home);
+	}else
+		snprint(homedir, sizeof homedir, "/sys/lib/quake2");
+	fs_basedir = Cvar_Get ("basedir", homedir, CVAR_NOSET);
+
+	//
+	// cddir <path>
+	// Logically concatenates the cddir after the basedir for 
+	// allows the game to run from outside the data tree
+	//
+	fs_cddir = Cvar_Get ("cddir", "", CVAR_NOSET);
+	if (fs_cddir->string[0])
+		FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_cddir->string) );
+
+	//
+	// start up with baseq2 by default
+	//
+	FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_basedir->string) );
+
+	// any set gamedirs will be freed up to here
+	fs_base_searchpaths = fs_searchpaths;
+
+	// check for game override
+	fs_gamedirvar = Cvar_Get ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
+	if (fs_gamedirvar->string[0])
+		FS_SetGamedir (fs_gamedirvar->string);
+}
+
+
+
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,613 @@
+void	Qcommon_Init(int, char **);
+void	Qcommon_Frame(int);
+void	Z_Free(void *);
+void*	Z_Malloc(int);
+void*	Z_TagMalloc(int, int);
+void	Z_FreeTags(int);
+int	COM_Argc(void);
+char*	COM_Argv(int);
+void	COM_ClearArgv(int);
+int	COM_CheckParm(char *);
+void	COM_AddParm(char *);
+void	COM_Init(void);
+void	COM_InitArgv(int, char **);
+char*	COM_SkipPath(char *);
+void	COM_StripExtension(char *, char *);
+void	COM_FileBase(char *, char *);
+void	COM_FilePath(char *, char *);
+void	COM_DefaultExtension(char *, char *);
+char*	COM_Parse(char **);
+void	Com_PageInMemory(uchar *, int);
+char*	CopyString(char *);
+char*	va(char *, ...);
+void	Com_sprintf(char *, int, char *, ...);
+void	Info_Print(char *);
+void	Com_BeginRedirect(int, char *, int, void(*));
+void	Com_EndRedirect(void);
+void	Com_Printf(char *, ...);
+void	Com_DPrintf(char *, ...);
+void	Com_Error(int, char *, ...);
+void	Com_Quit(void);
+int	Com_ServerState(void);
+void	Com_SetServerState(int state);
+unsigned	Com_BlockChecksum(void *, int);
+uchar	COM_BlockSequenceCRCByte(uchar *, int, int);
+float	qfrand(void);
+float	crand(void);
+
+void	FS_InitFilesystem(void);
+void	FS_SetGamedir(char *);
+char*	FS_Gamedir(void);
+char*	FS_NextPath(char *);
+void	FS_ExecAutoexec(void);
+int	FS_FOpenFile(char *, FILE **);
+void	FS_FCloseFile(FILE *);
+int	FS_LoadFile(char *, void **);
+void	FS_Read(void *, int, FILE *);
+void	FS_FreeFile(void *);
+void	FS_CreatePath(char *);
+
+char*	Sys_FindFirst(char *, uint, uint);
+char*	Sys_FindNext(uint, uint);
+void	Sys_FindClose(void);
+int	Sys_Milliseconds(void);
+void	Sys_Mkdir(char *);
+void	Sys_Init(void);
+void	Sys_AppActivate(void);
+void	Sys_UnloadGame(void);
+char*	Sys_ConsoleInput(void);
+void	Sys_ConsoleOutput(char *);
+void	Sys_SendKeyEvents(void);
+void	Sys_Error(char *, ...);
+void	Sys_Quit(void);
+char*	Sys_GetClipboardData(void);
+void	Sys_CopyProtect(void);
+void	Sys_MakeCodeWriteable(ulong, ulong);
+void	Sys_SetFPCW(void);
+vlong	flen(int);
+void*	Hunk_Begin(int);
+void*	Hunk_Alloc(int);
+void	Hunk_Free(void *);
+int	Hunk_End(void);
+
+void	CL_Init(void);
+void	CL_Drop(void);
+void	CL_Shutdown(void);
+void	CL_Frame(int);
+
+short	BigShort(short);
+short	LittleShort(short);
+int	BigLong(int);
+int	LittleLong(int);
+float	BigFloat(float);
+float	LittleFloat(float);
+void	Swap_Init(void);
+
+char*	Info_ValueForKey(char *, char *);
+void	Info_RemoveKey(char *, char *);
+void	Info_SetValueForKey(char *, char *, char *);
+qboolean	Info_Validate(char *);
+
+void	SZ_Init(sizebuf_t *, uchar *, int);
+void	SZ_Clear(sizebuf_t *);
+void*	SZ_GetSpace(sizebuf_t *, int);
+void	SZ_Write(sizebuf_t *, void *, int);
+void	SZ_Print(sizebuf_t *, char *);
+void	MSG_WriteChar(sizebuf_t *, int);
+void	MSG_WriteByte(sizebuf_t *, int);
+void	MSG_WriteShort(sizebuf_t *, int);
+void	MSG_WriteLong(sizebuf_t *, int);
+void	MSG_WriteFloat(sizebuf_t *, float);
+void	MSG_WriteString(sizebuf_t *, char *);
+void	MSG_WriteCoord(sizebuf_t *, float);
+void	MSG_WritePos(sizebuf_t *, vec3_t);
+void	MSG_WriteAngle(sizebuf_t *, float);
+void	MSG_WriteAngle16(sizebuf_t *, float);
+void	MSG_WriteDeltaUsercmd(sizebuf_t *, usercmd_t *, usercmd_t *);
+void	MSG_WriteDeltaEntity(entity_state_t *, entity_state_t *, sizebuf_t *, qboolean, qboolean);
+void	MSG_WriteDir(sizebuf_t *, vec3_t);
+void	MSG_BeginReading(sizebuf_t *);
+int	MSG_ReadChar(sizebuf_t *);
+int	MSG_ReadByte(sizebuf_t *);
+int	MSG_ReadShort(sizebuf_t *);
+int	MSG_ReadLong(sizebuf_t *);
+float	MSG_ReadFloat(sizebuf_t *);
+char*	MSG_ReadString(sizebuf_t *);
+char*	MSG_ReadStringLine(sizebuf_t *);
+float	MSG_ReadCoord(sizebuf_t *);
+void	MSG_ReadPos(sizebuf_t *, vec3_t);
+float	MSG_ReadAngle(sizebuf_t *);
+float	MSG_ReadAngle16(sizebuf_t *);
+void	MSG_ReadDeltaUsercmd(sizebuf_t *, usercmd_t *, usercmd_t *);
+void	MSG_ReadDir(sizebuf_t *, vec3_t);
+void	MSG_ReadData(sizebuf_t *, void *, int);
+
+void	CRC_Init(ushort *);
+void	CRC_ProcessByte(ushort *, uchar);
+ushort	CRC_Value(ushort);
+ushort	CRC_Block(uchar *, int);
+
+void	Cbuf_Init(void);
+void	Cbuf_AddText(char *);
+void	Cbuf_InsertText(char *);
+void	Cbuf_ExecuteText(int, char *);
+void	Cbuf_Execute(void);
+void	Cbuf_AddEarlyCommands(qboolean);
+qboolean	Cbuf_AddLateCommands(void);
+void	Cbuf_CopyToDefer(void);
+void	Cbuf_InsertFromDefer(void);
+void	Cmd_Init(void);
+void	Cmd_AddCommand(char *, xcommand_t);
+void	Cmd_RemoveCommand(char *);
+qboolean	Cmd_Exists(char *);
+char*	Cmd_CompleteCommand(char *);
+int	Cmd_Argc(void);
+char*	Cmd_Argv(int);
+char*	Cmd_Args(void);
+void	Cmd_TokenizeString(char *, qboolean);
+void	Cmd_ExecuteString(char *);
+void	Cmd_ForwardToServer(void);
+
+void	Con_DrawCharacter(int, int, int);
+void	Con_CheckResize(void);
+void	Con_Init(void);
+void	Con_DrawConsole(float);
+void	Con_Print(char *);
+void	Con_CenteredPrint(char *);
+void	Con_Clear_f(void);
+void	Con_DrawNotify(void);
+void	Con_ClearNotify(void);
+void	Con_ToggleConsole_f(void);
+void	DrawString(int, int, char *);
+void	DrawAltString(int, int, char *);
+
+cvar_t*	Cvar_Get(char *, char *, int);
+cvar_t*	Cvar_Set(char *, char *);
+cvar_t*	Cvar_ForceSet(char *, char *);
+cvar_t*	Cvar_FullSet(char *, char *, int);
+void	Cvar_SetValue(char *, float);
+float	Cvar_VariableValue(char *);
+char*	Cvar_VariableString(char *);
+char*	Cvar_CompleteVariable(char *);
+void	Cvar_GetLatchedVars(void);
+qboolean	Cvar_Command(void);
+void	Cvar_WriteVariables(char *);
+void	Cvar_Init(void);
+char*	Cvar_Userinfo(void);
+char*	Cvar_Serverinfo(void);
+
+void	CL_ParticleSteamEffect2(cl_sustain_t *);
+void	CL_TeleporterParticles(entity_state_t *);
+void	CL_ParticleEffect(vec3_t, vec3_t, int, int);
+void	CL_ParticleEffect2(vec3_t, vec3_t, int, int);
+void	CL_ParticleEffect3(vec3_t, vec3_t, int, int);
+void	CL_ClearEffects(void);
+void	CL_ClearTEnts(void);
+void	CL_BlasterTrail(vec3_t, vec3_t);
+void	CL_QuadTrail(vec3_t, vec3_t);
+void	CL_RailTrail(vec3_t, vec3_t);
+void	CL_BubbleTrail(vec3_t, vec3_t);
+void	CL_FlagTrail(vec3_t, vec3_t, float);
+void	CL_IonripperTrail(vec3_t, vec3_t);
+void	CL_BlasterParticles2(vec3_t, vec3_t, uint);
+void	CL_BlasterTrail2(vec3_t, vec3_t);
+void	CL_DebugTrail(vec3_t, vec3_t);
+void	CL_SmokeTrail(vec3_t, vec3_t, int, int, int);
+void	CL_Flashlight(int, vec3_t);
+void	CL_ForceWall(vec3_t, vec3_t, int);
+void	CL_FlameEffects(centity_t *, vec3_t);
+void	CL_GenericParticleEffect(vec3_t, vec3_t, int, int, int, int, float);
+void	CL_BubbleTrail2(vec3_t, vec3_t, int);
+void	CL_Heatbeam(vec3_t, vec3_t);
+void	CL_ParticleSteamEffect(vec3_t, vec3_t, int, int, int);
+void	CL_TrackerTrail(vec3_t, vec3_t, int);
+void	CL_Tracker_Explode(vec3_t);
+void	CL_TagTrail(vec3_t, vec3_t, float);
+void	CL_ColorFlash(vec3_t, int, int, float, float, float);
+void	CL_Tracker_Shell(vec3_t);
+void	CL_MonsterPlasma_Shell(vec3_t);
+void	CL_ColorExplosionParticles(vec3_t, int, int);
+void	CL_ParticleSmokeEffect(vec3_t, vec3_t, int, int, int);
+void	CL_Widowbeamout(cl_sustain_t *);
+void	CL_Nukeblast(cl_sustain_t *);
+void	CL_WidowSplash(vec3_t);
+int	CL_ParseEntityBits(int *);
+void	CL_ParseDelta(entity_state_t *, entity_state_t *, int, int);
+void	CL_ParseFrame(void);
+void	CL_ParseTEnt(void);
+void	CL_ParseConfigString(void);
+void	CL_ParseMuzzleFlash(void);
+void	CL_ParseMuzzleFlash2(void);
+void	SmokeAndFlash(vec3_t);
+void	CL_SetLightstyle(int);
+void	CL_RunParticles(void);
+void	CL_RunDLights(void);
+void	CL_RunLightStyles(void);
+void	CL_AddEntities(void);
+void	CL_AddDLights(void);
+void	CL_AddTEnts(void);
+void	CL_AddLightStyles(void);
+void	CL_PrepRefresh(void);
+void	CL_RegisterSounds(void);
+void	CL_Quit_f(void);
+void	CL_ParseLayout(void);
+void	CL_Init(void);
+void	CL_FixUpGender(void);
+void	CL_Disconnect(void);
+void	CL_Disconnect_f(void);
+void	CL_GetChallengePacket(void);
+void	CL_PingServers_f(void);
+void	CL_Snd_Restart_f(void);
+void	CL_RequestNextDownload(void);
+void	CL_InitInput(void);
+void	CL_SendCmd(void);
+void	CL_SendMove(usercmd_t *);
+void	CL_ClearState(void);
+void	CL_ReadPackets(void);
+int	CL_ReadFromServer(void);
+void	CL_WriteToServer(usercmd_t *);
+void	CL_BaseMove(usercmd_t *);
+void	IN_CenterView(void);
+float	CL_KeyState(kbutton_t *);
+char*	Key_KeynumToString(int);
+void	CL_WriteDemoMessage(void);
+void	CL_Stop_f(void);
+void	CL_Record_f(void);
+void	CL_ParseServerMessage(void);
+void	CL_LoadClientinfo(clientinfo_t *, char *);
+void	SHOWNET(char *);
+void	CL_ParseClientinfo(int);
+void	CL_Download_f(void);
+void	V_Init(void);
+void	V_RenderView(float);
+void	V_AddEntity(entity_t *);
+void	V_AddParticle(vec3_t, int, float);
+void	V_AddLight(vec3_t, float, float, float, float);
+void	V_AddLightStyle(int, float, float, float);
+void	CL_RegisterTEntSounds(void);
+void	CL_RegisterTEntModels(void);
+void	CL_SmokeAndFlash(vec3_t);
+void	CL_InitPrediction(void);
+void	CL_PredictMove(void);
+void	CL_CheckPredictionError(void);
+cdlight_t*	CL_AllocDlight(int);
+void	CL_BigTeleportParticles(vec3_t);
+void	CL_RocketTrail(vec3_t, vec3_t, centity_t *);
+void	CL_DiminishingTrail(vec3_t, vec3_t, centity_t *, int);
+void	CL_FlyEffect(centity_t *, vec3_t);
+void	CL_BfgParticles(entity_t *);
+void	CL_AddParticles(void);
+void	CL_EntityEvent(entity_state_t *);
+void	CL_TrapParticles(entity_t *);
+void	M_Init(void);
+void	M_Keydown(int);
+void	M_Draw(void);
+void	M_Menu_Main_f(void);
+void	M_ForceMenuOff(void);
+void	M_AddToServerList(netadr_t, char *);
+void	CL_ParseInventory(void);
+void	CL_KeyInventory(int);
+void	CL_DrawInventory(void);
+void	CL_PredictMovement(void);
+qboolean	CL_CheckOrDownloadFile(char *);
+void	CL_AddNetgraph(void);
+
+void	SV_Init(void);
+void	SV_Shutdown(char *, qboolean);
+void	SV_Frame(int);
+void	SV_FinalMessage(char *, qboolean);
+void	SV_DropClient(client_t *);
+int	SV_ModelIndex(char *);
+int	SV_SoundIndex(char *);
+int	SV_ImageIndex(char *);
+void	SV_WriteClientdataToMessage(client_t *, sizebuf_t *);
+void	SV_ExecuteUserCommand(char *);
+void	SV_InitOperatorCommands(void);
+void	SV_SendServerinfo(client_t *);
+void	SV_UserinfoChanged(client_t *);
+void	Master_Heartbeat(void);
+void	Master_Packet(void);
+void	SV_InitGame(void);
+void	SV_Map(qboolean, char *, qboolean);
+void	SV_PrepWorldFrame(void);
+void	SV_FlushRedirect(int, char *);
+void	SV_DemoCompleted(void);
+void	SV_SendClientMessages(void);
+void	SV_Multicast(vec3_t, multicast_t);
+void	SV_StartSound(vec3_t, edict_t *, int, int, float, float, float);
+void	SV_ClientPrintf(client_t *, int, char *, ...);
+void	SV_BroadcastPrintf(int, char *, ...);
+void	SV_BroadcastCommand(char *, ...);
+void	SV_Nextserver(void);
+void	SV_ExecuteClientMessage(client_t *);
+void	SV_ReadLevelFile(void);
+void	SV_Status_f(void);
+void	SV_WriteFrameToClient(client_t *, sizebuf_t *);
+void	SV_RecordDemoMessage(void);
+void	SV_BuildClientFrame(client_t *);
+void	SV_Error(char *, ...);
+void	SV_InitGameProgs(void);
+void	SV_ShutdownGameProgs(void);
+void	SV_InitEdict(edict_t *);
+void	SV_ClearWorld(void);
+void	SV_UnlinkEdict(edict_t *);
+void	SV_LinkEdict(edict_t *);
+int	SV_AreaEdicts(vec3_t, vec3_t, edict_t **, int, int);
+int	SV_PointContents(vec3_t);
+trace_t	SV_Trace(vec3_t, vec3_t, vec3_t, vec3_t, edict_t *, int);
+
+void	NET_Init(void);
+void	NET_Shutdown(void);
+void	NET_Config(qboolean);
+qboolean	NET_GetPacket(netsrc_t, netadr_t *, sizebuf_t *);
+void	NET_SendPacket(netsrc_t, int, void *, netadr_t);
+qboolean	NET_CompareAdr(netadr_t, netadr_t);
+qboolean	NET_CompareBaseAdr(netadr_t, netadr_t);
+qboolean	NET_IsLocalAddress(netadr_t);
+char*	NET_AdrToString(netadr_t);
+qboolean	NET_StringToAdr (char *, netadr_t *);
+void	NET_Sleep(int);
+
+void	Netchan_Init(void);
+void	Netchan_Setup(netsrc_t, netchan_t *, netadr_t, int);
+qboolean	Netchan_NeedReliable(netchan_t *);
+void	Netchan_Transmit(netchan_t *, int, uchar *);
+void	Netchan_OutOfBand(int, netadr_t, int, uchar *);
+void	Netchan_OutOfBandPrint(int, netadr_t, char *, ...);
+qboolean	Netchan_Process(netchan_t *, sizebuf_t *);
+qboolean	Netchan_CanReliable(netchan_t *);
+
+void	Mod_Init(void);
+void	Mod_ClearAll(void);
+model_t*	Mod_ForName(char *, qboolean);
+void*	Mod_Extradata(model_t *);
+void	Mod_TouchModel(char *);
+mleaf_t*	Mod_PointInLeaf(float *, model_t *);
+uchar*	Mod_ClusterPVS(int, model_t *);
+void	Mod_Modellist_f(void);
+void	Mod_FreeAll(void);
+void	Mod_Free(model_t *);
+
+void	D_DrawSurfaces(void);
+void	D_ViewChanged(void);
+void	D_WarpScreen(void);
+void	D_DrawSpans16(espan_t *);
+void	D_DrawZSpans(espan_t *);
+void	Turbulent8(espan_t *);
+void	NonTurbulent8(espan_t *);
+void	TransformVector(vec3_t, vec3_t);
+void	SetUpForLineScan(fixed8_t, fixed8_t, fixed8_t, fixed8_t);
+surfcache_t*	D_CacheSurface(msurface_t *, int);
+void	R_DrawParticle(void);
+void	R_PolysetUpdateTables(void);
+void	R_DrawSurface(void);
+void	R_RenderWorld(void);
+void	R_ClearPolyList(void);
+void	R_DrawPolyList(void);
+void	R_DrawAlphaSurfaces(void);
+void	R_DrawSprite(void);
+void	R_DrawBeam(entity_t *);
+void	R_RenderFace(msurface_t *, int);
+void	R_RenderBmodelFace(bedge_t *, msurface_t *);
+void	R_TransformPlane(mplane_t *, float *, float *);
+void	R_TransformFrustum(void);
+void	R_DrawSurfaceBlock16(void);
+void	R_DrawSurfaceBlock8(void);
+void	R_GenSkyTile(void *);
+void	R_GenSkyTile16(void *);
+void	R_Surf8Patch(void);
+void	R_Surf16Patch(void);
+void	R_DrawSubmodelPolygons(model_t *, int, mnode_t *);
+void	R_DrawSolidClippedSubmodelPolygons(model_t *, mnode_t *);
+void	R_AddPolygonEdges(emitpoint_t *, int, int);
+surf_t*	R_GetSurf(void);
+void	R_AliasDrawModel(void);
+void	R_BeginEdgeFrame(void);
+void	R_ScanEdges(void);
+void	D_DrawSurfaces(void);
+void	R_InsertNewEdges(edge_t *, edge_t *);
+void	R_StepActiveU(edge_t *);
+void	R_RemoveEdges(edge_t *);
+void	R_PushDlights(model_t *);
+void	R_Surf8Start(void);
+void	R_Surf8End(void);
+void	R_Surf16Start(void);
+void	R_Surf16End(void);
+void	R_EdgeCodeStart(void);
+void	R_EdgeCodeEnd(void);
+void	R_RotateBmodel(void);
+void	R_InitTurb(void);
+void	R_DrawParticles(void);
+void	R_SurfacePatch(void);
+void	R_DrawTriangle(void);
+void	R_AliasClipTriangle(finalvert_t *, finalvert_t *, finalvert_t *);
+void	R_PrintAliasStats(void);
+void	R_PrintTimes(void);
+void	R_PrintDSpeeds(void);
+void	R_AnimateLight(void);
+void	R_LightPoint(vec3_t, vec3_t);
+void	R_SetupFrame(void);
+void	R_cshift_f(void);
+void	R_EmitEdge(mvertex_t *, mvertex_t *);
+void	R_ClipEdge(mvertex_t *, mvertex_t *, clipplane_t *);
+void	R_SplitEntityOnNode2(mnode_t *);
+float	R_DLightPoint(vec3_t);
+void	R_NewMap(void);
+void	R_Register(void);
+void	R_UnRegister(void);
+void	Draw_InitLocal(void);
+qboolean	R_Init(void *, void *);
+void	R_Shutdown(void);
+void	R_InitCaches(void);
+void	D_FlushCaches(void);
+void	R_ScreenShot_f(void);
+void	R_BeginRegistration(char *map);
+model_t*	R_RegisterModel(char *);
+void	R_EndRegistration(void);
+void	R_RenderFrame(refdef_t *);
+image_t*	Draw_FindPic(char *);
+void	Draw_GetPicSize(int *, int *, char *);
+void	Draw_Pic(int, int, char *);
+void	Draw_StretchPic(int, int, int, int, char *);
+void	Draw_StretchRaw(int, int, int, int, int, int, uchar *);
+void	Draw_Char(int, int, int);
+void	Draw_TileClear(int, int, int, int, char *);
+void	Draw_Fill(int, int, int, int, int);
+void	Draw_FadeScreen(void);
+void	Draw_GetPalette(void);
+void	R_BeginFrame(float);
+void	R_CinematicSetPalette(uchar *palette);
+void	LoadPCX(char *, uchar **, uchar **, int *, int *);
+void	R_InitImages(void);
+void	R_ShutdownImages(void);
+image_t*	R_FindImage(char *, imagetype_t);
+void	R_FreeUnusedImages(void);
+void	R_GammaCorrectAndSetPalette(uchar *pal);
+void	R_InitSkyBox(void);
+void	R_IMFlatShadedQuad(vec3_t, vec3_t, vec3_t, vec3_t, int, float);
+image_t*	R_RegisterSkin(char *);
+
+void	VectorMA(vec3_t, float, vec3_t, vec3_t);
+vec_t	_DotProduct(vec3_t, vec3_t);	// just in case you do't want to use the macros
+void	_VectorSubtract(vec3_t, vec3_t, vec3_t);
+void	_VectorAdd(vec3_t, vec3_t, vec3_t);
+void	_VectorCopy(vec3_t, vec3_t);
+void	ClearBounds(vec3_t, vec3_t);
+void	AddPointToBounds(vec3_t, vec3_t, vec3_t);
+int	VectorCompare(vec3_t, vec3_t);
+vec_t	VectorLength(vec3_t);
+void	CrossProduct(vec3_t, vec3_t, vec3_t);
+vec_t	VectorNormalize(vec3_t);
+vec_t	VectorNormalize2 (vec3_t, vec3_t);
+void	VectorInverse(vec3_t);
+void	VectorScale(vec3_t, vec_t, vec3_t);
+void	R_ConcatRotations(float[3][3], float[3][3], float[3][3]);
+void	R_ConcatTransforms(float[3][4], float[3][4], float[3][4]);
+void	AngleVectors(vec3_t, vec3_t, vec3_t, vec3_t);
+int	BoxOnPlaneSide(vec3_t, vec3_t, cplane_t *);
+float	anglemod(float);
+float	LerpAngle(float, float, float);
+void	ProjectPointOnPlane(vec3_t, vec3_t, vec3_t);
+void	PerpendicularVector(vec3_t, vec3_t);
+void	RotatePointAroundVector(vec3_t, vec3_t, vec3_t, float);
+
+cmodel_t*	CM_LoadMap(char *, qboolean, unsigned *);
+cmodel_t*	CM_InlineModel(char *);
+int	CM_NumClusters(void);
+int	CM_NumInlineModels(void);
+char*	CM_EntityString(void);
+int	CM_HeadnodeForBox(vec3_t, vec3_t);
+int	CM_PointContents(vec3_t, int);
+int	CM_TransformedPointContents(vec3_t, int, vec3_t, vec3_t);
+trace_t	CM_BoxTrace(vec3_t, vec3_t, vec3_t, vec3_t, int, int);
+trace_t	CM_TransformedBoxTrace(vec3_t, vec3_t, vec3_t, vec3_t, int, int, vec3_t, vec3_t);
+uchar*	CM_ClusterPVS(int);
+uchar*	CM_ClusterPHS(int);
+int	CM_PointLeafnum(vec3_t);
+int	CM_BoxLeafnums(vec3_t, vec3_t, int *, int, int *);
+int	CM_LeafContents(int);
+int	CM_LeafCluster(int);
+int	CM_LeafArea(int);
+void	CM_SetAreaPortalState(int, qboolean);
+qboolean	CM_AreasConnected(int, int);
+int	CM_WriteAreaBits(uchar *, int);
+qboolean	CM_HeadnodeVisible(int, uchar *);
+void	CM_WritePortalState(FILE *);
+void	CM_ReadPortalState(FILE *);
+
+void	Pmove(pmove_t *);
+
+void	SCR_Init(void);
+void	SCR_UpdateScreen(void);
+void	SCR_SizeUp(void);
+void	SCR_SizeDown(void);
+void	SCR_CenterPrint(char *);
+void	SCR_BeginLoadingPlaque(void);
+void	SCR_EndLoadingPlaque(void);
+void	SCR_DebugGraph(float, int);
+void	SCR_TouchPics(void);
+void	SCR_RunConsole(void);
+void	SCR_AddDirtyPoint(int, int);
+void	SCR_DirtyScreen(void);
+void	SCR_PlayCinematic (char *name);
+qboolean	SCR_DrawCinematic(void);
+void	SCR_RunCinematic(void);
+void	SCR_StopCinematic(void);
+void	SCR_FinishCinematic(void);
+
+void	VID_Init(void);
+void	VID_Shutdown(void);
+void	VID_CheckChanges(void);
+void	VID_MenuInit(void);
+void	VID_MenuDraw(void);
+char*	VID_MenuKey(int);
+
+void	SWimp_BeginFrame(float);
+void	SWimp_EndFrame(void);
+int	SWimp_Init(void *, void *);
+void	SWimp_SetPalette(uchar *);
+void	SWimp_Shutdown(void);
+rserr_t	SWimp_SetMode(int *, int *, int, qboolean);
+void	SWimp_AppActivate(qboolean);
+
+void	S_Init(void);
+void	S_Shutdown(void);
+void	S_StartSound(vec3_t, int, int, sfx_t *, float,  float, float);
+void	S_StartLocalSound(char *);
+void	S_RawSamples(int, int, int, int, uchar *);
+void	S_StopAllSounds(void);
+void	S_Update(vec3_t, vec3_t, vec3_t, vec3_t);
+void	S_Activate(qboolean);
+void	S_BeginRegistration(void);
+sfx_t*	S_RegisterSound(char *);
+void	S_EndRegistration(void);
+void	CL_GetEntitySoundOrigin(int, vec3_t);
+qboolean	SNDDMA_Init(void);
+int	SNDDMA_GetDMAPos(void);
+void	SNDDMA_Shutdown(void);
+void	SNDDMA_BeginPainting(void);
+void	SNDDMA_Submit(void);
+wavinfo_t	GetWavinfo(char *, uchar *, int);
+void	S_InitScaletable(void);
+sfxcache_t*	S_LoadSound(sfx_t *);
+void	S_IssuePlaysound(playsound_t *);
+void	S_PaintChannels(int);
+channel_t*	S_PickChannel(int, int);
+void	S_Spatialize(channel_t *);
+
+int	CDAudio_Init(void);
+void	CDAudio_Shutdown(void);
+void	CDAudio_Play(int, qboolean);
+void	CDAudio_Stop(void);
+void	CDAudio_Update(void);
+void	CDAudio_Activate(qboolean);
+
+void	IN_Init(void);
+void	IN_Shutdown(void);
+void	IN_Commands(void);
+void	IN_Frame(void);
+void	IN_Move(usercmd_t *);
+void	IN_Activate(qboolean);
+void	IN_Grabm(int);
+
+void	Key_Event(int, qboolean, unsigned);
+void	Key_Init(void);
+void	Key_WriteBindings(FILE *);
+void	Key_SetBinding(int, char *);
+void	Key_ClearStates(void);
+int	Key_GetKey(void);
+
+qboolean	Field_Key(menufield_t *, int);
+void	Menu_AddItem(menuframework_t *, void *);
+void	Menu_AdjustCursor(menuframework_t *, int);
+void	Menu_Center(menuframework_t *);
+void	Menu_Draw(menuframework_t *);
+void*	Menu_ItemAtCursor(menuframework_t *);
+qboolean	Menu_SelectItem(menuframework_t *);
+void	Menu_SetStatusBar(menuframework_t *, char *);
+void	Menu_SlideItem(menuframework_t *, int);
+int	Menu_TallySlots(menuframework_t *);
+void	Menu_DrawString(int, int, char *);
+void	Menu_DrawStringDark(int, int, char *);
+void	Menu_DrawStringR2L(int, int, char *);
+void	Menu_DrawStringR2LDark(int, int, char *);
--- a/game/g_ai.c
+++ b/game/g_ai.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 qboolean FindTarget (edict_t *self);
 extern cvar_t	*maxclients;
--- a/game/g_chase.c
+++ b/game/g_chase.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 void UpdateChaseCam(edict_t *ent)
 {
--- a/game/g_cmds.c
+++ b/game/g_cmds.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_player.h"
 
 
--- a/game/g_combat.c
+++ b/game/g_combat.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 /*
 ============
--- a/game/g_func.c
+++ b/game/g_func.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 /*
 =========================================================
--- a/game/g_items.c
+++ b/game/g_items.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 
 qboolean	Pickup_Weapon (edict_t *ent, edict_t *other);
--- a/game/g_local.h
+++ /dev/null
@@ -1,1074 +1,0 @@
-// g_local.h -- local definitions for game module
-
-// the "gameversion" client command will print this plus compile date
-#define	GAMEVERSION	"baseq2"
-
-// view pitching times
-#define DAMAGE_TIME		0.5
-#define	FALL_TIME		0.3
-
-
-// edict->spawnflags
-// these are set with checkboxes on each entity in the map editor
-#define	SPAWNFLAG_NOT_EASY			0x00000100
-#define	SPAWNFLAG_NOT_MEDIUM		0x00000200
-#define	SPAWNFLAG_NOT_HARD			0x00000400
-#define	SPAWNFLAG_NOT_DEATHMATCH	0x00000800
-#define	SPAWNFLAG_NOT_COOP			0x00001000
-
-// edict->flags
-#define	FL_FLY					0x00000001
-#define	FL_SWIM					0x00000002	// implied immunity to drowining
-#define FL_IMMUNE_LASER			0x00000004
-#define	FL_INWATER				0x00000008
-#define	FL_GODMODE				0x00000010
-#define	FL_NOTARGET				0x00000020
-#define FL_IMMUNE_SLIME			0x00000040
-#define FL_IMMUNE_LAVA			0x00000080
-#define	FL_PARTIALGROUND		0x00000100	// not all corners are valid
-#define	FL_WATERJUMP			0x00000200	// player jumping out of water
-#define	FL_TEAMSLAVE			0x00000400	// not the first on the team
-#define FL_NO_KNOCKBACK			0x00000800
-#define FL_POWER_ARMOR			0x00001000	// power armor (if any) is active
-#define FL_RESPAWN				0x80000000	// used for item respawning
-
-
-#define	FRAMETIME		0.1
-
-// memory tags to allow dynamic memory to be cleaned up
-#define	TAG_GAME	765		// clear when unloading the dll
-#define	TAG_LEVEL	766		// clear when loading a new level
-
-
-#define MELEE_DISTANCE	80
-
-#define BODY_QUEUE_SIZE		8
-
-typedef enum
-{
-	DAMAGE_NO,
-	DAMAGE_YES,			// will take damage if hit
-	DAMAGE_AIM			// auto targeting recognizes this
-} damage_t;
-
-typedef enum 
-{
-	WEAPON_READY, 
-	WEAPON_ACTIVATING,
-	WEAPON_DROPPING,
-	WEAPON_FIRING
-} weaponstate_t;
-
-typedef enum
-{
-	AMMO_BULLETS,
-	AMMO_SHELLS,
-	AMMO_ROCKETS,
-	AMMO_GRENADES,
-	AMMO_CELLS,
-	AMMO_SLUGS
-} ammo_t;
-
-
-//deadflag
-#define DEAD_NO					0
-#define DEAD_DYING				1
-#define DEAD_DEAD				2
-#define DEAD_RESPAWNABLE		3
-
-//range
-#define RANGE_MELEE				0
-#define RANGE_NEAR				1
-#define RANGE_MID				2
-#define RANGE_FAR				3
-
-//gib types
-#define GIB_ORGANIC				0
-#define GIB_METALLIC			1
-
-//monster ai flags
-#define AI_STAND_GROUND			0x00000001
-#define AI_TEMP_STAND_GROUND	0x00000002
-#define AI_SOUND_TARGET			0x00000004
-#define AI_LOST_SIGHT			0x00000008
-#define AI_PURSUIT_LAST_SEEN	0x00000010
-#define AI_PURSUE_NEXT			0x00000020
-#define AI_PURSUE_TEMP			0x00000040
-#define AI_HOLD_FRAME			0x00000080
-#define AI_GOOD_GUY				0x00000100
-#define AI_BRUTAL				0x00000200
-#define AI_NOSTEP				0x00000400
-#define AI_DUCKED				0x00000800
-#define AI_COMBAT_POINT			0x00001000
-#define AI_MEDIC				0x00002000
-#define AI_RESURRECTING			0x00004000
-
-//monster attack state
-#define AS_STRAIGHT				1
-#define AS_SLIDING				2
-#define	AS_MELEE				3
-#define	AS_MISSILE				4
-
-// armor types
-#define ARMOR_NONE				0
-#define ARMOR_JACKET			1
-#define ARMOR_COMBAT			2
-#define ARMOR_BODY				3
-#define ARMOR_SHARD				4
-
-// power armor types
-#define POWER_ARMOR_NONE		0
-#define POWER_ARMOR_SCREEN		1
-#define POWER_ARMOR_SHIELD		2
-
-// handedness values
-#define RIGHT_HANDED			0
-#define LEFT_HANDED				1
-#define CENTER_HANDED			2
-
-
-// game.serverflags values
-#define SFL_CROSS_TRIGGER_1		0x00000001
-#define SFL_CROSS_TRIGGER_2		0x00000002
-#define SFL_CROSS_TRIGGER_3		0x00000004
-#define SFL_CROSS_TRIGGER_4		0x00000008
-#define SFL_CROSS_TRIGGER_5		0x00000010
-#define SFL_CROSS_TRIGGER_6		0x00000020
-#define SFL_CROSS_TRIGGER_7		0x00000040
-#define SFL_CROSS_TRIGGER_8		0x00000080
-#define SFL_CROSS_TRIGGER_MASK	0x000000ff
-
-
-// noise types for PlayerNoise
-#define PNOISE_SELF				0
-#define PNOISE_WEAPON			1
-#define PNOISE_IMPACT			2
-
-
-// edict->movetype values
-typedef enum
-{
-MOVETYPE_NONE,			// never moves
-MOVETYPE_NOCLIP,		// origin and angles change with no interaction
-MOVETYPE_PUSH,			// no clip to world, push on box contact
-MOVETYPE_STOP,			// no clip to world, stops on box contact
-
-MOVETYPE_WALK,			// gravity
-MOVETYPE_STEP,			// gravity, special edge handling
-MOVETYPE_FLY,
-MOVETYPE_TOSS,			// gravity
-MOVETYPE_FLYMISSILE,	// extra size to monsters
-MOVETYPE_BOUNCE
-} movetype_t;
-
-
-
-typedef struct
-{
-	int		base_count;
-	int		max_count;
-	float	normal_protection;
-	float	energy_protection;
-	int		armor;
-} gitem_armor_t;
-
-
-// gitem_t->flags
-#define	IT_WEAPON		1		// use makes active weapon
-#define	IT_AMMO			2
-#define IT_ARMOR		4
-#define IT_STAY_COOP	8
-#define IT_KEY			16
-#define IT_POWERUP		32
-
-// gitem_t->weapmodel for weapons indicates model index
-#define WEAP_BLASTER			1 
-#define WEAP_SHOTGUN			2 
-#define WEAP_SUPERSHOTGUN		3 
-#define WEAP_MACHINEGUN			4 
-#define WEAP_CHAINGUN			5 
-#define WEAP_GRENADES			6 
-#define WEAP_GRENADELAUNCHER	7 
-#define WEAP_ROCKETLAUNCHER		8 
-#define WEAP_HYPERBLASTER		9 
-#define WEAP_RAILGUN			10
-#define WEAP_BFG				11
-
-typedef struct gitem_s
-{
-	char		*classname;	// spawning name
-	qboolean	(*pickup)(edict_t *ent, edict_t *other);
-	void		(*use)(edict_t *ent, struct gitem_s *item);
-	void		(*drop)(edict_t *ent, struct gitem_s *item);
-	void		(*weaponthink)(edict_t *ent);
-	char		*pickup_sound;
-	char		*world_model;
-	int			world_model_flags;
-	char		*view_model;
-
-	// client side info
-	char		*icon;
-	char		*pickup_name;	// for printing on pickup
-	int			count_width;		// number of digits to display by icon
-
-	int			quantity;		// for ammo how much, for weapons how much is used per shot
-	char		*ammo;			// for weapons
-	int			flags;			// IT_* flags
-
-	int			weapmodel;		// weapon model index (for weapons)
-
-	void		*info;
-	int			tag;
-
-	char		*precaches;		// string of all models, sounds, and images this item will use
-} gitem_t;
-
-
-
-//
-// this structure is left intact through an entire game
-// it should be initialized at dll load time, and read/written to
-// the server.ssv file for savegames
-//
-typedef struct
-{
-	char		helpmessage1[512];
-	char		helpmessage2[512];
-	int			helpchanged;	// flash F1 icon if non 0, play sound
-								// and increment only if 1, 2, or 3
-
-	gclient_t	*clients;		// [maxclients]
-
-	// can't store spawnpoint in level, because
-	// it would get overwritten by the savegame restore
-	char		spawnpoint[512];	// needed for coop respawns
-
-	// store latched cvars here that we want to get at often
-	int			maxclients;
-	int			maxentities;
-
-	// cross level triggers
-	int			serverflags;
-
-	// items
-	int			num_items;
-
-	qboolean	autosaved;
-} game_locals_t;
-
-
-//
-// this structure is cleared as each map is entered
-// it is read/written to the level.sav file for savegames
-//
-typedef struct
-{
-	int			framenum;
-	float		time;
-
-	char		level_name[MAX_QPATH];	// the descriptive name (Outer Base, etc)
-	char		mapname[MAX_QPATH];		// the server name (base1, etc)
-	char		nextmap[MAX_QPATH];		// go here when fraglimit is hit
-
-	// intermission state
-	float		intermissiontime;		// time the intermission was started
-	char		*changemap;
-	int			exitintermission;
-	vec3_t		intermission_origin;
-	vec3_t		intermission_angle;
-
-	edict_t		*sight_client;	// changed once each frame for coop games
-
-	edict_t		*sight_entity;
-	int			sight_entity_framenum;
-	edict_t		*sound_entity;
-	int			sound_entity_framenum;
-	edict_t		*sound2_entity;
-	int			sound2_entity_framenum;
-
-	int			pic_health;
-
-	int			total_secrets;
-	int			found_secrets;
-
-	int			total_goals;
-	int			found_goals;
-
-	int			total_monsters;
-	int			killed_monsters;
-
-	edict_t		*current_entity;	// entity running from G_RunFrame
-	int			body_que;			// dead bodies
-
-	int			power_cubes;		// ugly necessity for coop
-} level_locals_t;
-
-
-// spawn_temp_t is only used to hold entity field values that
-// can be set from the editor, but aren't actualy present
-// in edict_t during gameplay
-typedef struct
-{
-	// world vars
-	char		*sky;
-	float		skyrotate;
-	vec3_t		skyaxis;
-	char		*nextmap;
-
-	int			lip;
-	int			distance;
-	int			height;
-	char		*noise;
-	float		pausetime;
-	char		*item;
-	char		*gravity;
-
-	float		minyaw;
-	float		maxyaw;
-	float		minpitch;
-	float		maxpitch;
-} spawn_temp_t;
-
-
-typedef struct
-{
-	// fixed data
-	vec3_t		start_origin;
-	vec3_t		start_angles;
-	vec3_t		end_origin;
-	vec3_t		end_angles;
-
-	int			sound_start;
-	int			sound_middle;
-	int			sound_end;
-
-	float		accel;
-	float		speed;
-	float		decel;
-	float		distance;
-
-	float		wait;
-
-	// state data
-	int			state;
-	vec3_t		dir;
-	float		current_speed;
-	float		move_speed;
-	float		next_speed;
-	float		remaining_distance;
-	float		decel_distance;
-	void		(*endfunc)(edict_t *);
-} moveinfo_t;
-
-
-typedef struct
-{
-	void	(*aifunc)(edict_t *self, float dist);
-	float	dist;
-	void	(*thinkfunc)(edict_t *self);
-} mframe_t;
-
-typedef struct
-{
-	int			firstframe;
-	int			lastframe;
-	mframe_t	*frame;
-	void		(*endfunc)(edict_t *self);
-} mmove_t;
-
-typedef struct
-{
-	mmove_t		*currentmove;
-	int			aiflags;
-	int			nextframe;
-	float		scale;
-
-	void		(*stand)(edict_t *self);
-	void		(*idle)(edict_t *self);
-	void		(*search)(edict_t *self);
-	void		(*walk)(edict_t *self);
-	void		(*run)(edict_t *self);
-	void		(*dodge)(edict_t *self, edict_t *other, float eta);
-	void		(*attack)(edict_t *self);
-	void		(*melee)(edict_t *self);
-	void		(*sight)(edict_t *self, edict_t *other);
-	qboolean	(*checkattack)(edict_t *self);
-
-	float		pausetime;
-	float		attack_finished;
-
-	vec3_t		saved_goal;
-	float		search_time;
-	float		trail_time;
-	vec3_t		last_sighting;
-	int			attack_state;
-	int			lefty;
-	float		idle_time;
-	int			linkcount;
-
-	int			power_armor_type;
-	int			power_armor_power;
-} monsterinfo_t;
-
-
-
-extern	game_locals_t	game;
-extern	level_locals_t	level;
-extern	game_import_t	gi;
-extern	game_export_t	globals;
-extern	spawn_temp_t	st;
-
-extern	int	sm_meat_index;
-extern	int	snd_fry;
-
-
-// means of death
-#define MOD_UNKNOWN			0
-#define MOD_BLASTER			1
-#define MOD_SHOTGUN			2
-#define MOD_SSHOTGUN		3
-#define MOD_MACHINEGUN		4
-#define MOD_CHAINGUN		5
-#define MOD_GRENADE			6
-#define MOD_G_SPLASH		7
-#define MOD_ROCKET			8
-#define MOD_R_SPLASH		9
-#define MOD_HYPERBLASTER	10
-#define MOD_RAILGUN			11
-#define MOD_BFG_LASER		12
-#define MOD_BFG_BLAST		13
-#define MOD_BFG_EFFECT		14
-#define MOD_HANDGRENADE		15
-#define MOD_HG_SPLASH		16
-#define MOD_WATER			17
-#define MOD_SLIME			18
-#define MOD_LAVA			19
-#define MOD_CRUSH			20
-#define MOD_TELEFRAG		21
-#define MOD_FALLING			22
-#define MOD_SUICIDE			23
-#define MOD_HELD_GRENADE	24
-#define MOD_EXPLOSIVE		25
-#define MOD_BARREL			26
-#define MOD_BOMB			27
-#define MOD_EXIT			28
-#define MOD_SPLASH			29
-#define MOD_TARGET_LASER	30
-#define MOD_TRIGGER_HURT	31
-#define MOD_HIT				32
-#define MOD_TARGET_BLASTER	33
-#define MOD_FRIENDLY_FIRE	0x8000000
-
-extern	int	meansOfDeath;
-
-
-extern	edict_t			*g_edicts;
-
-#define	FOFS(x) (uintptr)&(((edict_t *)0)->x)
-#define	STOFS(x) (uintptr)&(((spawn_temp_t *)0)->x)
-#define	LLOFS(x) (uintptr)&(((level_locals_t *)0)->x)
-#define	CLOFS(x) (uintptr)&(((gclient_t *)0)->x)
-
-#define qrandom()	((rand () & 0x7fff) / ((float)0x7fff))	/* >_< arrrrggghh */
-#define crandom()	(2.0 * (qrandom() - 0.5))
-
-extern	cvar_t	*maxentities;
-extern	cvar_t	*deathmatch;
-extern	cvar_t	*coop;
-extern	cvar_t	*dmflags;
-extern	cvar_t	*skill;
-extern	cvar_t	*fraglimit;
-extern	cvar_t	*timelimit;
-extern	cvar_t	*password;
-extern	cvar_t	*spectator_password;
-extern	cvar_t	*g_select_empty;
-extern	cvar_t	*dedicated;
-
-extern	cvar_t	*filterban;
-
-extern	cvar_t	*sv_gravity;
-extern	cvar_t	*sv_maxvelocity;
-
-extern	cvar_t	*gun_x, *gun_y, *gun_z;
-extern	cvar_t	*sv_rollspeed;
-extern	cvar_t	*sv_rollangle;
-
-extern	cvar_t	*run_pitch;
-extern	cvar_t	*run_roll;
-extern	cvar_t	*bob_up;
-extern	cvar_t	*bob_pitch;
-extern	cvar_t	*bob_roll;
-
-extern	cvar_t	*sv_cheats;
-extern	cvar_t	*maxclients;
-extern	cvar_t	*maxspectators;
-
-extern	cvar_t	*flood_msgs;
-extern	cvar_t	*flood_persecond;
-extern	cvar_t	*flood_waitdelay;
-
-extern	cvar_t	*sv_maplist;
-
-#define WORLD	(&g_edicts[0])
-
-// item spawnflags
-#define ITEM_TRIGGER_SPAWN		0x00000001
-#define ITEM_NO_TOUCH			0x00000002
-// 6 bits reserved for editor flags
-// 8 bits used as power cube id bits for coop games
-#define DROPPED_ITEM			0x00010000
-#define	DROPPED_PLAYER_ITEM		0x00020000
-#define ITEM_TARGETS_USED		0x00040000
-
-//
-// fields are needed for spawning from the entity string
-// and saving / loading games
-//
-#define FFL_SPAWNTEMP		1
-#define FFL_NOSPAWN			2
-
-typedef enum {
-	F_INT, 
-	F_FLOAT,
-	F_LSTRING,			// string on disk, pointer in memory, TAG_LEVEL
-	F_GSTRING,			// string on disk, pointer in memory, TAG_GAME
-	F_VECTOR,
-	F_ANGLEHACK,
-	F_EDICT,			// index on disk, pointer in memory
-	F_ITEM,				// index on disk, pointer in memory
-	F_CLIENT,			// index on disk, pointer in memory
-	F_FUNCTION,
-	F_MMOVE,
-	F_IGNORE
-} fieldtype_t;
-
-typedef struct
-{
-	char	*name;
-	int		ofs;
-	fieldtype_t	type;
-	int		flags;
-} field_t;
-
-
-extern	field_t fields[];
-extern	gitem_t	itemlist[];
-
-
-//
-// g_cmds.c
-//
-void Cmd_Help_f (edict_t *ent);
-void Cmd_Score_f (edict_t *ent);
-
-//
-// g_items.c
-//
-void PrecacheItem (gitem_t *it);
-void InitItems (void);
-void SetItemNames (void);
-gitem_t	*FindItem (char *pickup_name);
-gitem_t	*FindItemByClassname (char *classname);
-#define	ITEM_INDEX(x) ((x)-itemlist)
-edict_t *Drop_Item (edict_t *ent, gitem_t *item);
-void SetRespawn (edict_t *ent, float delay);
-void ChangeWeapon (edict_t *ent);
-void SpawnItem (edict_t *ent, gitem_t *item);
-void Think_Weapon (edict_t *ent);
-int ArmorIndex (edict_t *ent);
-int PowerArmorType (edict_t *ent);
-gitem_t	*GetItemByIndex (int index);
-qboolean Add_Ammo (edict_t *ent, gitem_t *item, int count);
-void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf);
-
-//
-// g_utils.c
-//
-qboolean	KillBox (edict_t *ent);
-void	G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result);
-edict_t *G_Find (edict_t *from, int fieldofs, char *match);
-edict_t *findradius (edict_t *from, vec3_t org, float rad);
-edict_t *G_PickTarget (char *targetname);
-void	G_UseTargets (edict_t *ent, edict_t *activator);
-void	G_SetMovedir (vec3_t angles, vec3_t movedir);
-
-void	G_InitEdict (edict_t *e);
-edict_t	*G_Spawn (void);
-void	G_FreeEdict (edict_t *e);
-
-void	G_TouchTriggers (edict_t *ent);
-void	G_TouchSolids (edict_t *ent);
-
-char	*G_CopyString (char *in);
-
-float	*tv (float x, float y, float z);
-char	*vtos (vec3_t v);
-
-float vectoyaw (vec3_t vec);
-void vectoangles (vec3_t vec, vec3_t angles);
-
-//
-// g_combat.c
-//
-qboolean OnSameTeam (edict_t *ent1, edict_t *ent2);
-qboolean CanDamage (edict_t *targ, edict_t *inflictor);
-void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod);
-void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod);
-
-// damage flags
-#define DAMAGE_RADIUS			0x00000001	// damage was indirect
-#define DAMAGE_NO_ARMOR			0x00000002	// armour does not protect from this damage
-#define DAMAGE_ENERGY			0x00000004	// damage is from an energy based weapon
-#define DAMAGE_NO_KNOCKBACK		0x00000008	// do not affect velocity, just view angles
-#define DAMAGE_BULLET			0x00000010  // damage is from a bullet (used for ricochets)
-#define DAMAGE_NO_PROTECTION	0x00000020  // armor, shields, invulnerability, and godmode have no effect
-
-#define DEFAULT_BULLET_HSPREAD	300
-#define DEFAULT_BULLET_VSPREAD	500
-#define DEFAULT_SHOTGUN_HSPREAD	1000
-#define DEFAULT_SHOTGUN_VSPREAD	500
-#define DEFAULT_DEATHMATCH_SHOTGUN_COUNT	12
-#define DEFAULT_SHOTGUN_COUNT	12
-#define DEFAULT_SSHOTGUN_COUNT	20
-
-//
-// g_monster.c
-//
-void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype);
-void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int flashtype);
-void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect);
-void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype);
-void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype);
-void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype);
-void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype);
-void M_droptofloor (edict_t *ent);
-void monster_think (edict_t *self);
-void walkmonster_start (edict_t *self);
-void swimmonster_start (edict_t *self);
-void flymonster_start (edict_t *self);
-void AttackFinished (edict_t *self, float time);
-void monster_death_use (edict_t *self);
-void M_CatagorizePosition (edict_t *ent);
-qboolean M_CheckAttack (edict_t *self);
-void M_FlyCheck (edict_t *self);
-void M_CheckGround (edict_t *ent);
-
-//
-// g_misc.c
-//
-void ThrowHead (edict_t *self, char *gibname, int damage, int type);
-void ThrowClientHead (edict_t *self, int damage);
-void ThrowGib (edict_t *self, char *gibname, int damage, int type);
-void BecomeExplosion1(edict_t *self);
-
-//
-// g_ai.c
-//
-void AI_SetSightClient (void);
-
-void ai_stand (edict_t *self, float dist);
-void ai_move (edict_t *self, float dist);
-void ai_walk (edict_t *self, float dist);
-void ai_turn (edict_t *self, float dist);
-void ai_run (edict_t *self, float dist);
-void ai_charge (edict_t *self, float dist);
-int range (edict_t *self, edict_t *other);
-
-void FoundTarget (edict_t *self);
-qboolean infront (edict_t *self, edict_t *other);
-qboolean visible (edict_t *self, edict_t *other);
-qboolean FacingIdeal(edict_t *self);
-
-//
-// g_weapon.c
-//
-void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin);
-qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick);
-void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int mod);
-void fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int mod);
-void fire_blaster (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int effect, qboolean hyper);
-void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius);
-void fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held);
-void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage);
-void fire_rail (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick);
-void fire_bfg (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius);
-
-//
-// g_ptrail.c
-//
-void PlayerTrail_Init (void);
-void PlayerTrail_Add (vec3_t spot);
-void PlayerTrail_New (vec3_t spot);
-edict_t *PlayerTrail_PickFirst (edict_t *self);
-edict_t *PlayerTrail_PickNext (edict_t *self);
-edict_t	*PlayerTrail_LastSpot (void);
-
-//
-// g_client.c
-//
-void respawn (edict_t *ent);
-void BeginIntermission (edict_t *targ);
-void PutClientInServer (edict_t *ent);
-void InitClientPersistant (gclient_t *client);
-void InitClientResp (gclient_t *client);
-void InitBodyQue (void);
-void ClientBeginServerFrame (edict_t *ent);
-
-//
-// g_player.c
-//
-void player_pain (edict_t *self, edict_t *other, float kick, int damage);
-void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
-
-//
-// g_svcmds.c
-//
-void	ServerCommand (void);
-qboolean SV_FilterPacket (char *from);
-
-//
-// p_view.c
-//
-void ClientEndServerFrame (edict_t *ent);
-
-//
-// p_hud.c
-//
-void MoveClientToIntermission (edict_t *client);
-void G_SetStats (edict_t *ent);
-void G_SetSpectatorStats (edict_t *ent);
-void G_CheckChaseStats (edict_t *ent);
-void ValidateSelectedItem (edict_t *ent);
-void DeathmatchScoreboardMessage (edict_t *client, edict_t *killer);
-
-//
-// g_pweapon.c
-//
-void PlayerNoise(edict_t *who, vec3_t where, int type);
-
-//
-// m_move.c
-//
-qboolean M_CheckBottom (edict_t *ent);
-qboolean M_walkmove (edict_t *ent, float yaw, float dist);
-void M_MoveToGoal (edict_t *ent, float dist);
-void M_ChangeYaw (edict_t *ent);
-
-//
-// g_phys.c
-//
-void G_RunEntity (edict_t *ent);
-
-//
-// g_main.c
-//
-void SaveClientData (void);
-void FetchClientEntData (edict_t *ent);
-
-//
-// g_chase.c
-//
-void UpdateChaseCam(edict_t *ent);
-void ChaseNext(edict_t *ent);
-void ChasePrev(edict_t *ent);
-void GetChaseTarget(edict_t *ent);
-
-//============================================================================
-
-// client_t->anim_priority
-#define	ANIM_BASIC		0		// stand / run
-#define	ANIM_WAVE		1
-#define	ANIM_JUMP		2
-#define	ANIM_PAIN		3
-#define	ANIM_ATTACK		4
-#define	ANIM_DEATH		5
-#define	ANIM_REVERSE	6
-
-
-// client data that stays across multiple level loads
-typedef struct
-{
-	char		userinfo[MAX_INFO_STRING];
-	char		netname[16];
-	int			hand;
-
-	qboolean	connected;			// a loadgame will leave valid entities that
-									// just don't have a connection yet
-
-	// values saved and restored from edicts when changing levels
-	int			health;
-	int			max_health;
-	int			savedFlags;
-
-	int			selected_item;
-	int			inventory[MAX_ITEMS];
-
-	// ammo capacities
-	int			max_bullets;
-	int			max_shells;
-	int			max_rockets;
-	int			max_grenades;
-	int			max_cells;
-	int			max_slugs;
-
-	gitem_t		*weapon;
-	gitem_t		*lastweapon;
-
-	int			power_cubes;	// used for tracking the cubes in coop games
-	int			score;			// for calculating total unit score in coop games
-
-	int			game_helpchanged;
-	int			helpchanged;
-
-	qboolean	spectator;			// client is a spectator
-} client_persistant_t;
-
-// client data that stays across deathmatch respawns
-typedef struct
-{
-	client_persistant_t	coop_respawn;	// what to set client->pers to on a respawn
-	int			enterframe;			// level.framenum the client entered the game
-	int			score;				// frags, etc
-	vec3_t		cmd_angles;			// angles sent over in the last command
-
-	qboolean	spectator;			// client is a spectator
-} client_respawn_t;
-
-// this structure is cleared on each PutClientInServer(),
-// except for 'client->pers'
-struct gclient_t
-{
-	// known to server
-	player_state_t	ps;				// communicated by server to clients
-	int				ping;
-
-// the server expects the first part
-// of gclient_s to be a player_state_t
-// but the rest of it is opaque
-
-	// DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
-	// EXPECTS THE FIELDS IN THAT ORDER!
-	//================================
-
-	client_persistant_t	pers;
-	client_respawn_t	resp;
-	pmove_state_t		old_pmove;	// for detecting out-of-pmove changes
-
-	qboolean	showscores;			// set layout stat
-	qboolean	showinventory;		// set layout stat
-	qboolean	showhelp;
-	qboolean	showhelpicon;
-
-	int			ammo_index;
-
-	int			buttons;
-	int			oldbuttons;
-	int			latched_buttons;
-
-	qboolean	weapon_thunk;
-
-	gitem_t		*newweapon;
-
-	// sum up damage over an entire frame, so
-	// shotgun blasts give a single big kick
-	int			damage_armor;		// damage absorbed by armor
-	int			damage_parmor;		// damage absorbed by power armor
-	int			damage_blood;		// damage taken out of health
-	int			damage_knockback;	// impact damage
-	vec3_t		damage_from;		// origin for vector calculation
-
-	float		killer_yaw;			// when dead, look at killer
-
-	weaponstate_t	weaponstate;
-	vec3_t		kick_angles;	// weapon kicks
-	vec3_t		kick_origin;
-	float		v_dmg_roll, v_dmg_pitch, v_dmg_time;	// damage kicks
-	float		fall_time, fall_value;		// for view drop on fall
-	float		damage_alpha;
-	float		bonus_alpha;
-	vec3_t		damage_blend;
-	vec3_t		v_angle;			// aiming direction
-	float		bobtime;			// so off-ground doesn't change it
-	vec3_t		oldviewangles;
-	vec3_t		oldvelocity;
-
-	float		next_drown_time;
-	int			old_waterlevel;
-	int			breather_sound;
-
-	int			machinegun_shots;	// for weapon raising
-
-	// animation vars
-	int			anim_end;
-	int			anim_priority;
-	qboolean	anim_duck;
-	qboolean	anim_run;
-
-	// powerup timers
-	float		quad_framenum;
-	float		invincible_framenum;
-	float		breather_framenum;
-	float		enviro_framenum;
-
-	qboolean	grenade_blew_up;
-	float		grenade_time;
-	int			silencer_shots;
-	int			weapon_sound;
-
-	float		pickup_msg_time;
-
-	float		flood_locktill;		// locked from talking
-	float		flood_when[10];		// when messages were said
-	int			flood_whenhead;		// head pointer for when said
-
-	float		respawn_time;		// can respawn when time > this
-
-	edict_t		*chase_target;		// player we are chasing
-	qboolean	update_chase;		// need to update chase info?
-};
-
-
-struct edict_t
-{
-	entity_state_t	s;
-	gclient_t	*client;	// NULL if not a player
-
-	qboolean	inuse;
-	int			linkcount;
-
-	// FIXME: move these fields to a server private sv_entity_t
-	link_t		area;				// linked to a division node or leaf
-	
-	int			num_clusters;		// if -1, use headnode instead
-	int			clusternums[MAX_ENT_CLUSTERS];
-	int			headnode;			// unused if num_clusters != -1
-	int			areanum, areanum2;
-
-	//================================
-
-	int			svflags;	// SCF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc.
-	vec3_t		mins, maxs;
-	vec3_t		absmin, absmax, size;
-	solid_t		solid;
-	int			clipmask;
-	edict_t		*owner;
-
-	// DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
-	// EXPECTS THE FIELDS IN THAT ORDER!
-	//================================
-
-	int			movetype;
-	int			flags;
-
-	char		*model;
-	float		freetime;			// sv.time when the object was freed
-	
-	//
-	// only used locally in game, not by server
-	//
-	char		*message;
-	char		*classname;
-	int			spawnflags;
-
-	float		timestamp;
-
-	float		angle;			// set in qe3, -1 = up, -2 = down
-	char		*target;
-	char		*targetname;
-	char		*killtarget;
-	char		*team;
-	char		*pathtarget;
-	char		*deathtarget;
-	char		*combattarget;
-	edict_t		*target_ent;
-
-	float		speed, accel, decel;
-	vec3_t		movedir;
-	vec3_t		pos1, pos2;
-
-	vec3_t		velocity;
-	vec3_t		avelocity;
-	int			mass;
-	float		air_finished;
-	float		gravity;		// per entity gravity multiplier (1.0 is normal)
-								// use for lowgrav artifact, flares
-
-	edict_t		*goalentity;
-	edict_t		*movetarget;
-	float		yaw_speed;
-	float		ideal_yaw;
-
-	float		nextthink;
-	void		(*prethink) (edict_t *ent);
-	void		(*think)(edict_t *self);
-	void		(*blocked)(edict_t *self, edict_t *other);	//move to moveinfo?
-	void		(*touch)(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
-	void		(*use)(edict_t *self, edict_t *other, edict_t *activator);
-	void		(*pain)(edict_t *self, edict_t *other, float kick, int damage);
-	void		(*die)(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
-
-	float		touch_debounce_time;		// are all these legit?  do we need more/less of them?
-	float		pain_debounce_time;
-	float		damage_debounce_time;
-	float		fly_sound_debounce_time;	//move to clientinfo
-	float		last_move_time;
-
-	int			health;
-	int			max_health;
-	int			gib_health;
-	int			deadflag;
-	qboolean	show_hostile;
-
-	float		powerarmor_time;
-
-	char		*map;			// target_changelevel
-
-	int			viewheight;		// height above origin where eyesight is determined
-	int			takedamage;
-	int			dmg;
-	int			radius_dmg;
-	float		dmg_radius;
-	int			sounds;			//make this a spawntemp var?
-	int			count;
-
-	edict_t		*chain;
-	edict_t		*enemy;
-	edict_t		*oldenemy;
-	edict_t		*activator;
-	edict_t		*groundentity;
-	int			groundentity_linkcount;
-	edict_t		*teamchain;
-	edict_t		*teammaster;
-
-	edict_t		*mynoise;		// can go in client only
-	edict_t		*mynoise2;
-
-	int			noise_index;
-	int			noise_index2;
-	float		volume;
-	float		attenuation;
-
-	// timing variables
-	float		wait;
-	float		delay;			// before firing targets
-	float		random;
-
-	float		teleport_time;
-
-	int			watertype;
-	int			waterlevel;
-
-	vec3_t		move_origin;
-	vec3_t		move_angles;
-
-	// move this to clientinfo?
-	int			light_level;
-
-	int			style;			// also used as areaportal number
-
-	gitem_t		*item;			// for bonus items
-
-	// common data blocks
-	moveinfo_t		moveinfo;
-	monsterinfo_t	monsterinfo;
-};
--- a/game/g_main.c
+++ b/game/g_main.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 game_locals_t	game;
 level_locals_t	level;
--- a/game/g_misc.c
+++ b/game/g_misc.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 
 /*QUAKED func_group (0 0 0) ?
--- a/game/g_monster.c
+++ b/game/g_monster.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 
 //
--- a/game/g_phys.c
+++ b/game/g_phys.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 /*
 
--- a/game/g_save.c
+++ b/game/g_save.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 #define Function(f) {#f, f}
 
--- a/game/g_spawn.c
+++ b/game/g_spawn.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 typedef struct
 {
--- a/game/g_svcmds.c
+++ b/game/g_svcmds.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 
 void	Svcmd_Test_f (void)
--- a/game/g_target.c
+++ b/game/g_target.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 /*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8)
 Fire an origin based temp entity event to the clients.
--- a/game/g_trigger.c
+++ b/game/g_trigger.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 
 void InitTrigger (edict_t *self)
--- a/game/g_turret.c
+++ b/game/g_turret.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 
 void AnglesNormalize(vec3_t vec)
--- a/game/g_utils.c
+++ b/game/g_utils.c
@@ -3,7 +3,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 
 void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
--- a/game/g_weapon.c
+++ b/game/g_weapon.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 
 /*
--- a/game/game.h
+++ b/game/game.h
@@ -1,173 +1,974 @@
-// game.h -- game dll information visible to server
+typedef struct link_t link_t;
+typedef struct game_import_t game_import_t;
+typedef struct game_export_t game_export_t;
+typedef struct gitem_armor_t gitem_armor_t;
+typedef struct gitem_t gitem_t;
+typedef struct game_locals_t game_locals_t;
+typedef struct level_locals_t level_locals_t;
+typedef struct spawn_temp_t spawn_temp_t;
+typedef struct moveinfo_t moveinfo_t;
+typedef struct mframe_t mframe_t;
+typedef struct mmove_t mmove_t;
+typedef struct monsterinfo_t monsterinfo_t;
+typedef struct field_t field_t;
+typedef struct client_persistant_t client_persistant_t;
+typedef struct client_respawn_t client_respawn_t;
+typedef struct edict_t edict_t;
+typedef struct gclient_t gclient_t;
 
-#define	GAME_API_VERSION	3
+extern cvar_t *maxentities;
+extern cvar_t *deathmatch;
+extern cvar_t *coop;
+extern cvar_t *dmflags;
+extern cvar_t *skill;
+extern cvar_t *fraglimit;
+extern cvar_t *timelimit;
+extern cvar_t *password;
+extern cvar_t *spectator_password;
+extern cvar_t *g_select_empty;
+extern cvar_t *dedicated;
+extern cvar_t *filterban;
+extern cvar_t *sv_gravity;
+extern cvar_t *sv_maxvelocity;
+extern cvar_t *gun_x, *gun_y, *gun_z;
+extern cvar_t *sv_rollspeed;
+extern cvar_t *sv_rollangle;
+extern cvar_t *run_pitch;
+extern cvar_t *run_roll;
+extern cvar_t *bob_up;
+extern cvar_t *bob_pitch;
+extern cvar_t *bob_roll;
+extern cvar_t *sv_cheats;
+extern cvar_t *maxclients;
+extern cvar_t *maxspectators;
+extern cvar_t *flood_msgs;
+extern cvar_t *flood_persecond;
+extern cvar_t *flood_waitdelay;
+extern cvar_t *sv_maplist;
 
-// edict->svflags
+enum{
+	GAME_API_VERSION = 3,
 
-#define	SVF_NOCLIENT			0x00000001	// don't send entity to clients, even if it has effects
-#define	SVF_DEADMONSTER			0x00000002	// treat as CONTENTS_DEADMONSTER for collision
-#define	SVF_MONSTER				0x00000004	// treat as CONTENTS_MONSTER for collision
+	/* edict->svflags */
+	SVF_NOCLIENT = 1<<0,	// don't send entity to clients, even if it has effects
+	SVF_DEADMONSTER = 1<<1,	// treat as CONTENTS_DEADMONSTER for collision
+	SVF_MONSTER = 1<<2,	// treat as CONTENTS_MONSTER for collision
 
-// edict->solid values
+	MAX_ENT_CLUSTERS = 16
+};
 
-typedef enum
-{
-SOLID_NOT,			// no interaction with other objects
-SOLID_TRIGGER,		// only touch when inside, after moving
-SOLID_BBOX,			// touch on edge
-SOLID_BSP			// bsp clip, touch on edge
-} solid_t;
+/* edict->solid values */
+typedef enum solid_t{
+	SOLID_NOT,	// no interaction with other objects
+	SOLID_TRIGGER,	// only touch when inside, after moving
+	SOLID_BBOX,	// touch on edge
+	SOLID_BSP	// bsp clip, touch on edge
+}solid_t;
+
+/* link_t is only used for entity area links now */
+struct link_t{
+	link_t *prev;
+	link_t *next;
+};
+
+struct game_import_t{
+	void	(*bprintf)(int, char *, ...);
+	void	(*dprintf)(char *, ...);
+	void	(*cprintf)(edict_t *, int, char *, ...);
+	void	(*centerprintf)(edict_t *, char *, ...);
+	void	(*sound)(edict_t *, int, int, float, float, float);
+	void	(*positioned_sound)(vec3_t, edict_t *, int, int, float, float, float);
+	/* config strings hold all the index strings, the lightstyles, and misc
+	 * data like the sky definition and cdtrack. all of the current
+	 * configstrings are sent to clients when they connect, and changes are
+	 * sent to all connected clients. */
+	void	(*configstring)(int, char *);
+	void	(*error)(char *, ...);
+	/* the *index functions create configstrings and some internal server
+	 * state */
+	int	(*modelindex)(char *);
+	int	(*soundindex)(char *);
+	int	(*imageindex)(char *);
+	void	(*setmodel)(edict_t *, char *);
+	/* collision detection */
+	trace_t	(*trace)(vec3_t, vec3_t, vec3_t, vec3_t, edict_t *, int);
+	int	(*pointcontents)(vec3_t);
+	qboolean	(*inPVS)(vec3_t, vec3_t);
+	qboolean	(*inPHS)(vec3_t, vec3_t);
+	void	(*SetAreaPortalState)(int, qboolean);
+	qboolean	(*AreasConnected)(int, int);
+	/* an entity will never be sent to a client or used for collision if it
+	 * is not passed to linkentity.  If the size, position, or solidity
+	 * changes, it must be relinked. */
+	void	(*linkentity)(edict_t *);
+	/* call before removing an interactive edict */
+	void	(*unlinkentity)(edict_t *);
+	int	(*BoxEdicts)(vec3_t, vec3_t, edict_t **, int, int);
+	/* player movement code common with client prediction */
+	void	(*Pmove)(pmove_t *);
+	/* network messaging */
+	void	(*multicast)(vec3_t, multicast_t);
+	void	(*unicast)(edict_t *, qboolean);
+	void	(*WriteChar)(int);
+	void	(*WriteByte)(int);
+	void	(*WriteShort)(int);
+	void	(*WriteLong)(int);
+	void	(*WriteFloat)(float);
+	void	(*WriteString)(char *);
+	void	(*WritePosition)(vec3_t);	// some fractional bits
+	void	(*WriteDir)(vec3_t);	// single byte encoded, very coarse
+	void	(*WriteAngle)(float);
+	/* managed memory allocation */
+	void*	(*TagMalloc)(int, int);
+	void	(*TagFree)(void *);
+	void	(*FreeTags)(int);
+	/* console variable interaction */
+	cvar_t*	(*cvar)(char *, char *, int);
+	cvar_t*	(*cvar_set)(char *, char *);
+	cvar_t*	(*cvar_forceset)(char *, char *);
+	/* ClientCommand and ServerCommand parameter access */
+	int	(*argc)(void);
+	char*	(*argv)(int);
+	char*	(*args)(void);	// concatenation of all argv >= 1
+	/* add commands to the server console as if they were typed in for map
+	 * changing, etc */
+	void	(*AddCommandString)(char *);
+	void	(*DebugGraph)(float, int);
+};
+extern game_import_t gi;
+
+struct game_export_t{
+	int apiversion;
+	/* the init function will only be called when a game starts, not each
+	 * time a level is loaded.  Persistant data for clients and the server
+	 * can be allocated in init */
+	void	(*Init)(void);
+	void	(*Shutdown)(void);
+	/* each new level entered will cause a call to SpawnEntities */
+	void	(*SpawnEntities)(char *, char *, char *);
+	/* Read/Write Game is for storing persistant cross level information
+	 * about the world state and the clients. WriteGame is called every
+	 * time a level is exited. ReadGame is called on a loadgame. */
+	void	(*WriteGame)(char *, qboolean);
+	void	(*ReadGame)(char *);
+	/* ReadLevel is called after the default map information has been
+	 * loaded with SpawnEntities */
+	void	(*WriteLevel)(char *);
+	void	(*ReadLevel)(char *);
+	qboolean	(*ClientConnect)(edict_t *, char *);
+	void	(*ClientBegin)(edict_t *);
+	void	(*ClientUserinfoChanged)(edict_t *, char *);
+	void	(*ClientDisconnect)(edict_t *);
+	void	(*ClientCommand)(edict_t *);
+	void	(*ClientThink)(edict_t *, usercmd_t *);
+	void	(*RunFrame)(void);
+	/* ServerCommand will be called when an "sv <command>" command is
+	 * issued on the server console. the game can issue gi.argc() or
+	 * gi.argv() commands to get the rest of the parameters */
+	void	(*ServerCommand)(void);
+	/* global variables shared between game and server: the edict array is
+	 * allocated in the game dll so it can vary in size from one game to
+	 * another. the size will be fixed when ge->Init() is called */
+	edict_t *edicts;
+	int edict_size;
+	int num_edicts;	// current number, <= max_edicts
+	int max_edicts;
+};
+extern game_export_t globals;
 
-//===============================================================
+game_export_t *GetGameAPI(game_import_t *);
 
-// link_t is only used for entity area links now
-typedef struct link_s
-{
-	struct link_s	*prev, *next;
-} link_t;
+#define	GAMEVERSION	"baseq2"
+#define DAMAGE_TIME	0.5	// view pitching times
+#define	FALL_TIME	0.3
+#define	FRAMETIME	0.1
+enum{
+	/* edict->spawnflags */
+	SPAWNFLAG_NOT_EASY = 1<<8,
+	SPAWNFLAG_NOT_MEDIUM = 1<<9,
+	SPAWNFLAG_NOT_HARD = 1<<10,
+	SPAWNFLAG_NOT_DEATHMATCH = 1<<11,
+	SPAWNFLAG_NOT_COOP = 1<<12,
+	/* edict->flags */
+	FL_FLY = 1<<0,
+	FL_SWIM = 1<<1,	// implied immunity to drowining
+	FL_IMMUNE_LASER = 1<<2,
+	FL_INWATER = 1<<3,
+	FL_GODMODE = 1<<4,
+	FL_NOTARGET = 1<<5,
+	FL_IMMUNE_SLIME = 1<<6,
+	FL_IMMUNE_LAVA = 1<<7,
+	FL_PARTIALGROUND = 1<<8,	// not all corners are valid
+	FL_WATERJUMP = 1<<9,	// player jumping out of water
+	FL_TEAMSLAVE = 1<<10,	// not the first on the team
+	FL_NO_KNOCKBACK = 1<<11,
+	FL_POWER_ARMOR = 1<<12,	// power armor (if any) is active
+	FL_RESPAWN = 1<<31,	// used for item respawning
 
-#define	MAX_ENT_CLUSTERS	16
+	/* memory tags to allow dynamic memory to be cleaned up */
+	TAG_GAME = 765,	// clear when unloading the dll
+	TAG_LEVEL = 766,	// clear when loading a new level
+	MELEE_DISTANCE = 80,
+	BODY_QUEUE_SIZE = 8,
 
-typedef struct edict_t edict_t;
-typedef struct gclient_t gclient_t;
+	/* deadflag */
+	DEAD_NO = 0,
+	DEAD_DYING = 1,
+	DEAD_DEAD = 2,
+	DEAD_RESPAWNABLE = 3,
+	/* range */
+	RANGE_MELEE = 0,
+	RANGE_NEAR = 1,
+	RANGE_MID = 2,
+	RANGE_FAR = 3,
+	/* gib types */
+	GIB_ORGANIC = 0,
+	GIB_METALLIC = 1,
+	/* monster ai flags */
+	AI_STAND_GROUND = 1<<0,
+	AI_TEMP_STAND_GROUND = 1<<1,
+	AI_SOUND_TARGET = 1<<2,
+	AI_LOST_SIGHT = 1<<3,
+	AI_PURSUIT_LAST_SEEN = 1<<4,
+	AI_PURSUE_NEXT = 1<<5,
+	AI_PURSUE_TEMP = 1<<6,
+	AI_HOLD_FRAME = 1<<7,
+	AI_GOOD_GUY = 1<<8,
+	AI_BRUTAL = 1<<9,
+	AI_NOSTEP = 1<<10,
+	AI_DUCKED = 1<<11,
+	AI_COMBAT_POINT = 1<<12,
+	AI_MEDIC = 1<<13,
+	AI_RESURRECTING = 1<<14,
+	/* monster attack state */
+	AS_STRAIGHT = 1,
+	AS_SLIDING = 2,
+	AS_MELEE = 3,
+	AS_MISSILE = 4,
+	/* armor types */
+	ARMOR_NONE = 0,
+	ARMOR_JACKET = 1,
+	ARMOR_COMBAT = 2,
+	ARMOR_BODY = 3,
+	ARMOR_SHARD = 4,
+	/* power armor types */
+	POWER_ARMOR_NONE = 0,
+	POWER_ARMOR_SCREEN = 1,
+	POWER_ARMOR_SHIELD = 2,
+	/* handedness values */
+	RIGHT_HANDED = 0,
+	LEFT_HANDED = 1,
+	CENTER_HANDED = 2,
+	/* game.serverflags values */
+	SFL_CROSS_TRIGGER_1 = 1<<0,
+	SFL_CROSS_TRIGGER_2 = 1<<1,
+	SFL_CROSS_TRIGGER_3 = 1<<2,
+	SFL_CROSS_TRIGGER_4 = 1<<3,
+	SFL_CROSS_TRIGGER_5 = 1<<4,
+	SFL_CROSS_TRIGGER_6 = 1<<5,
+	SFL_CROSS_TRIGGER_7 = 1<<6,
+	SFL_CROSS_TRIGGER_8 = 1<<7,
+	SFL_CROSS_TRIGGER_MASK = 0xff,
+	/* noise types for PlayerNoise */
+	PNOISE_SELF = 0,
+	PNOISE_WEAPON = 1,
+	PNOISE_IMPACT = 2,
+};
 
+typedef enum damage_t{
+	DAMAGE_NO,
+	DAMAGE_YES,	// will take damage if hit
+	DAMAGE_AIM	// auto targeting recognizes this
+}damage_t;
+typedef enum weaponstate_t{
+	WEAPON_READY, 
+	WEAPON_ACTIVATING,
+	WEAPON_DROPPING,
+	WEAPON_FIRING
+}weaponstate_t;
+typedef enum ammo_t{
+	AMMO_BULLETS,
+	AMMO_SHELLS,
+	AMMO_ROCKETS,
+	AMMO_GRENADES,
+	AMMO_CELLS,
+	AMMO_SLUGS
+}ammo_t;
 
-//===============================================================
+/* edict->movetype values */
+typedef enum movetype_t{
+	MOVETYPE_NONE,	// never moves
+	MOVETYPE_NOCLIP,	// origin and angles change with no interaction
+	MOVETYPE_PUSH,	// no clip to world, push on box contact
+	MOVETYPE_STOP,	// no clip to world, stops on box contact
+	MOVETYPE_WALK,	// gravity
+	MOVETYPE_STEP,	// gravity, special edge handling
+	MOVETYPE_FLY,
+	MOVETYPE_TOSS,	// gravity
+	MOVETYPE_FLYMISSILE,	// extra size to monsters
+	MOVETYPE_BOUNCE
+}movetype_t;
 
-//
-// functions provided by the main engine
-//
-typedef struct
-{
-	// special messages
-	void	(*bprintf) (int printlevel, char *fmt, ...);
-	void	(*dprintf) (char *fmt, ...);
-	void	(*cprintf) (edict_t *ent, int printlevel, char *fmt, ...);
-	void	(*centerprintf) (edict_t *ent, char *fmt, ...);
-	void	(*sound) (edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs);
-	void	(*positioned_sound) (vec3_t origin, edict_t *ent, int channel, int soundinedex, float volume, float attenuation, float timeofs);
+struct gitem_armor_t{
+	int base_count;
+	int max_count;
+	float normal_protection;
+	float energy_protection;
+	int armor;
+};
 
-	// config strings hold all the index strings, the lightstyles,
-	// and misc data like the sky definition and cdtrack.
-	// All of the current configstrings are sent to clients when
-	// they connect, and changes are sent to all connected clients.
-	void	(*configstring) (int num, char *string);
+enum{
+	/* gitem_t->flags */
+	IT_WEAPON = 1<<0,		// use makes active weapon
+	IT_AMMO = 1<<1,
+	IT_ARMOR = 1<<2,
+	IT_STAY_COOP = 1<<3,
+	IT_KEY = 1<<4,
+	IT_POWERUP = 1<<5,
+	/* gitem_t->weapmodel for weapons indicates model index */
+	WEAP_BLASTER = 1, 
+	WEAP_SHOTGUN = 2, 
+	WEAP_SUPERSHOTGUN = 3, 
+	WEAP_MACHINEGUN = 4, 
+	WEAP_CHAINGUN = 5, 
+	WEAP_GRENADES = 6, 
+	WEAP_GRENADELAUNCHER = 7, 
+	WEAP_ROCKETLAUNCHER = 8, 
+	WEAP_HYPERBLASTER = 9, 
+	WEAP_RAILGUN = 10,
+	WEAP_BFG = 11
+};
+struct gitem_t{
+	char *classname;	// spawning name
+	qboolean	(*pickup)(edict_t *, edict_t *);
+	void	(*use)(edict_t *, gitem_t *);
+	void	(*drop)(edict_t *, gitem_t *);
+	void	(*weaponthink)(edict_t *);
+	char *pickup_sound;
+	char *world_model;
+	int world_model_flags;
+	char *view_model;
+	/* client side info */
+	char *icon;
+	char *pickup_name;	// for printing on pickup
+	int count_width;	// number of digits to display by icon
+	int quantity;	// for ammo how much, for weapons how much is used per shot
+	char *ammo;	// for weapons
+	int flags;	// IT_* flags
+	int weapmodel;	// weapon model index (for weapons)
+	void *info;
+	int tag;
+	/* string of all models, sounds, and images this item will use */
+	char *precaches;
+};
+extern gitem_t itemlist[];
 
-	void	(*error) (char *fmt, ...);
+/* this structure is left intact through an entire game it should be
+ * initialized at dll load time, and read/written to the server.ssv file for
+ * savegames */
+struct game_locals_t{
+	char helpmessage1[512];
+	char helpmessage2[512];
+	/* flash F1 icon if non 0, play sound and increment only if 1, 2, or 3 */
+	int helpchanged;
+	gclient_t *clients;	// [maxclients]
+	/* can't store spawnpoint in level, because it would get overwritten
+	 * by the savegame restore */
+	char spawnpoint[512];	// needed for coop respawns
+	/* store latched cvars here that we want to get at often */
+	int maxclients;
+	int maxentities;
+	/* cross level triggers */
+	int serverflags;
+	int num_items;
+	qboolean autosaved;
+};
+extern game_locals_t game;
 
-	// the *index functions create configstrings and some internal server state
-	int		(*modelindex) (char *name);
-	int		(*soundindex) (char *name);
-	int		(*imageindex) (char *name);
+/* this structure is cleared as each map is entered; it is read/written to the
+ * level.sav file for savegames */
+struct level_locals_t{
+	int framenum;
+	float time;
+	char level_name[MAX_QPATH];	// the descriptive name (Outer Base, etc)
+	char mapname[MAX_QPATH];	// the server name (base1, etc)
+	char nextmap[MAX_QPATH];	// go here when fraglimit is hit
+	/* intermission state */
+	float intermissiontime;	// time the intermission was started
+	char *changemap;
+	int exitintermission;
+	vec3_t intermission_origin;
+	vec3_t intermission_angle;
+	edict_t *sight_client;	// changed once each frame for coop games
+	edict_t *sight_entity;
+	int sight_entity_framenum;
+	edict_t *sound_entity;
+	int sound_entity_framenum;
+	edict_t *sound2_entity;
+	int sound2_entity_framenum;
+	int pic_health;
+	int total_secrets;
+	int found_secrets;
+	int total_goals;
+	int found_goals;
+	int total_monsters;
+	int killed_monsters;
+	edict_t *current_entity;	// entity running from G_RunFrame
+	int body_que;	// dead bodies
+	int power_cubes;	// ugly necessity for coop
+};
+extern level_locals_t level;
 
-	void	(*setmodel) (edict_t *ent, char *name);
+/* spawn_temp_t is only used to hold entity field values that can be set from
+ * the editor, but aren't actualy present in edict_t during gameplay */
+struct spawn_temp_t{
+	/* world vars */
+	char *sky;
+	float skyrotate;
+	vec3_t skyaxis;
+	char *nextmap;
 
-	// collision detection
-	trace_t	(*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask);
-	int		(*pointcontents) (vec3_t point);
-	qboolean	(*inPVS) (vec3_t p1, vec3_t p2);
-	qboolean	(*inPHS) (vec3_t p1, vec3_t p2);
-	void		(*SetAreaPortalState) (int portalnum, qboolean open);
-	qboolean	(*AreasConnected) (int area1, int area2);
+	int lip;
+	int distance;
+	int height;
+	char *noise;
+	float pausetime;
+	char *item;
+	char *gravity;
+	float minyaw;
+	float maxyaw;
+	float minpitch;
+	float maxpitch;
+};
+extern spawn_temp_t st;
 
-	// an entity will never be sent to a client or used for collision
-	// if it is not passed to linkentity.  If the size, position, or
-	// solidity changes, it must be relinked.
-	void	(*linkentity) (edict_t *ent);
-	void	(*unlinkentity) (edict_t *ent);		// call before removing an interactive edict
-	int		(*BoxEdicts) (vec3_t mins, vec3_t maxs, edict_t **list,	int maxcount, int areatype);
-	void	(*Pmove) (pmove_t *pmove);		// player movement code common with client prediction
+struct moveinfo_t{
+	/* fixed data */
+	vec3_t start_origin;
+	vec3_t start_angles;
+	vec3_t end_origin;
+	vec3_t end_angles;
+	int sound_start;
+	int sound_middle;
+	int sound_end;
+	float accel;
+	float speed;
+	float decel;
+	float distance;
+	float wait;
+	/* state data */
+	int state;
+	vec3_t dir;
+	float current_speed;
+	float move_speed;
+	float next_speed;
+	float remaining_distance;
+	float decel_distance;
+	void	(*endfunc)(edict_t *);
+};
 
-	// network messaging
-	void	(*multicast) (vec3_t origin, multicast_t to);
-	void	(*unicast) (edict_t *ent, qboolean reliable);
-	void	(*WriteChar) (int c);
-	void	(*WriteByte) (int c);
-	void	(*WriteShort) (int c);
-	void	(*WriteLong) (int c);
-	void	(*WriteFloat) (float f);
-	void	(*WriteString) (char *s);
-	void	(*WritePosition) (vec3_t pos);	// some fractional bits
-	void	(*WriteDir) (vec3_t pos);		// single byte encoded, very coarse
-	void	(*WriteAngle) (float f);
+struct mframe_t{
+	void	(*aifunc)(edict_t *, float);
+	float dist;
+	void	(*thinkfunc)(edict_t *);
+};
 
-	// managed memory allocation
-	void	*(*TagMalloc) (int size, int tag);
-	void	(*TagFree) (void *block);
-	void	(*FreeTags) (int tag);
+struct mmove_t{
+	int firstframe;
+	int lastframe;
+	mframe_t *frame;
+	void	(*endfunc)(edict_t *);
+};
 
-	// console variable interaction
-	cvar_t	*(*cvar) (char *var_name, char *value, int flags);
-	cvar_t	*(*cvar_set) (char *var_name, char *value);
-	cvar_t	*(*cvar_forceset) (char *var_name, char *value);
+struct monsterinfo_t{
+	mmove_t *currentmove;
+	int aiflags;
+	int nextframe;
+	float scale;
+	void	(*stand)(edict_t *);
+	void	(*idle)(edict_t *);
+	void	(*search)(edict_t *);
+	void	(*walk)(edict_t *);
+	void	(*run)(edict_t *);
+	void	(*dodge)(edict_t *, edict_t *, float);
+	void	(*attack)(edict_t *);
+	void	(*melee)(edict_t *);
+	void	(*sight)(edict_t *, edict_t *);
+	qboolean	(*checkattack)(edict_t *);
+	float pausetime;
+	float attack_finished;
+	vec3_t saved_goal;
+	float search_time;
+	float trail_time;
+	vec3_t last_sighting;
+	int attack_state;
+	int lefty;
+	float idle_time;
+	int linkcount;
+	int power_armor_type;
+	int power_armor_power;
+};
 
-	// ClientCommand and ServerCommand parameter access
-	int		(*argc) (void);
-	char	*(*argv) (int n);
-	char	*(*args) (void);	// concatenation of all argv >= 1
+extern int sm_meat_index;
+extern int snd_fry;
 
-	// add commands to the server console as if they were typed in
-	// for map changing, etc
-	void	(*AddCommandString) (char *text);
+/* means of death */
+enum{
+	MOD_UNKNOWN = 0,
+	MOD_BLASTER = 1,
+	MOD_SHOTGUN = 2,
+	MOD_SSHOTGUN = 3,
+	MOD_MACHINEGUN = 4,
+	MOD_CHAINGUN = 5,
+	MOD_GRENADE = 6,
+	MOD_G_SPLASH = 7,
+	MOD_ROCKET = 8,
+	MOD_R_SPLASH = 9,
+	MOD_HYPERBLASTER = 10,
+	MOD_RAILGUN = 11,
+	MOD_BFG_LASER = 12,
+	MOD_BFG_BLAST = 13,
+	MOD_BFG_EFFECT = 14,
+	MOD_HANDGRENADE = 15,
+	MOD_HG_SPLASH = 16,
+	MOD_WATER = 17,
+	MOD_SLIME = 18,
+	MOD_LAVA = 19,
+	MOD_CRUSH = 20,
+	MOD_TELEFRAG = 21,
+	MOD_FALLING = 22,
+	MOD_SUICIDE = 23,
+	MOD_HELD_GRENADE = 24,
+	MOD_EXPLOSIVE = 25,
+	MOD_BARREL = 26,
+	MOD_BOMB = 27,
+	MOD_EXIT = 28,
+	MOD_SPLASH = 29,
+	MOD_TARGET_LASER = 30,
+	MOD_TRIGGER_HURT = 31,
+	MOD_HIT = 32,
+	MOD_TARGET_BLASTER = 33,
+	MOD_FRIENDLY_FIRE = 1<<31
+};
+extern int meansOfDeath;
 
-	void	(*DebugGraph) (float value, int color);
-} game_import_t;
+enum{
+	/* item spawnflags */
+	ITEM_TRIGGER_SPAWN = 1<<0,
+	ITEM_NO_TOUCH = 1<<1,
+	/* 6 bits reserved for editor flags; 8 bits used as power cube id bits
+	 * for coop games */
+	DROPPED_ITEM = 1<<16,
+	DROPPED_PLAYER_ITEM = 1<<17,
+	ITEM_TARGETS_USED = 1<<18,
+	/* fields are needed for spawning from the entity string and saving or
+	 * loading games */
+	FFL_SPAWNTEMP = 1,
+	FFL_NOSPAWN = 2
+};
+typedef enum fieldtype_t{
+	F_INT, 
+	F_FLOAT,
+	F_LSTRING,	// string on disk, pointer in memory, TAG_LEVEL
+	F_GSTRING,	// string on disk, pointer in memory, TAG_GAME
+	F_VECTOR,
+	F_ANGLEHACK,
+	F_EDICT,	// index on disk, pointer in memory
+	F_ITEM,	// index on disk, pointer in memory
+	F_CLIENT,	// index on disk, pointer in memory
+	F_FUNCTION,
+	F_MMOVE,
+	F_IGNORE
+}fieldtype_t;
+struct field_t{
+	char *name;
+	int ofs;
+	fieldtype_t type;
+	int flags;
+};
+extern field_t fields[];
 
-//
-// functions exported by the game subsystem
-//
-typedef struct
-{
-	int			apiversion;
+enum{
+	/* damage flags */
+	DAMAGE_RADIUS = 1<<0,	// indirect dmg
+	DAMAGE_NO_ARMOR = 1<<1,	// not protected by armour
+	DAMAGE_ENERGY = 1<<2,	// is from an energy based weapon
+	DAMAGE_NO_KNOCKBACK = 1<<3,	// do not affect velocity, just view angles
+	DAMAGE_BULLET = 1<<4,	// is from a bullet (used for ricochets)
+	/* no effect from armor, shields, invulnerability, and godmode */
+	DAMAGE_NO_PROTECTION = 1<<5,
 
-	// the init function will only be called when a game starts,
-	// not each time a level is loaded.  Persistant data for clients
-	// and the server can be allocated in init
-	void		(*Init) (void);
-	void		(*Shutdown) (void);
+	DEFAULT_BULLET_HSPREAD = 300,
+	DEFAULT_BULLET_VSPREAD = 500,
+	DEFAULT_SHOTGUN_HSPREAD = 1000,
+	DEFAULT_SHOTGUN_VSPREAD = 500,
+	DEFAULT_DEATHMATCH_SHOTGUN_COUNT = 12,
+	DEFAULT_SHOTGUN_COUNT = 12,
+	DEFAULT_SSHOTGUN_COUNT = 20,
 
-	// each new level entered will cause a call to SpawnEntities
-	void		(*SpawnEntities) (char *mapname, char *entstring, char *spawnpoint);
+	/* client_t->anim_priority */
+	ANIM_BASIC = 0,	// stand / run
+	ANIM_WAVE = 1,
+	ANIM_JUMP = 2,
+	ANIM_PAIN = 3,
+	ANIM_ATTACK = 4,
+	ANIM_DEATH = 5,
+	ANIM_REVERSE = 6
+};
 
-	// Read/Write Game is for storing persistant cross level information
-	// about the world state and the clients.
-	// WriteGame is called every time a level is exited.
-	// ReadGame is called on a loadgame.
-	void		(*WriteGame) (char *filename, qboolean autosave);
-	void		(*ReadGame) (char *filename);
+/* client data that stays across multiple level loads */
+struct client_persistant_t{
+	char userinfo[MAX_INFO_STRING];
+	char netname[16];
+	int hand;
+	/* a loadgame will leave valid entities that just don't have a connection yet */
+	qboolean connected;
+	/* values saved and restored from edicts when changing levels */
+	int health;
+	int max_health;
+	int savedFlags;
+	int selected_item;
+	int inventory[MAX_ITEMS];
+	int max_bullets;
+	int max_shells;
+	int max_rockets;
+	int max_grenades;
+	int max_cells;
+	int max_slugs;
+	gitem_t *weapon;
+	gitem_t *lastweapon;
+	int power_cubes;	// used for tracking the cubes in coop games
+	int score;	// for calculating total unit score in coop games
+	int game_helpchanged;
+	int helpchanged;
+	qboolean spectator;	// client is a spectator
+};
+/* client data that stays across deathmatch respawns */
+struct client_respawn_t{
+	client_persistant_t coop_respawn;	// assigned to client->pers on a respawn
+	int enterframe;	// level.framenum the client entered the game
+	int score;	// frags, etc
+	vec3_t cmd_angles;	// angles sent over in the last command
+	qboolean spectator;	// client is a spectator
+};
+/* this structure is cleared on each PutClientInServer(), except for .pers */
+struct gclient_t{
+	/* known to server */
+	player_state_t ps;	// communicated by server to clients
+	int ping;
 
-	// ReadLevel is called after the default map information has been
-	// loaded with SpawnEntities
-	void		(*WriteLevel) (char *filename);
-	void		(*ReadLevel) (char *filename);
+	/* the server expects the first part of gclient_s to be a
+	 * player_state_t but the rest of it is opaque
+	 * DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER EXPECTS THE FIELDS IN
+	 * THAT ORDER! */
 
-	qboolean	(*ClientConnect) (edict_t *ent, char *userinfo);
-	void		(*ClientBegin) (edict_t *ent);
-	void		(*ClientUserinfoChanged) (edict_t *ent, char *userinfo);
-	void		(*ClientDisconnect) (edict_t *ent);
-	void		(*ClientCommand) (edict_t *ent);
-	void		(*ClientThink) (edict_t *ent, usercmd_t *cmd);
+	client_persistant_t pers;
+	client_respawn_t resp;
+	pmove_state_t old_pmove;	// for detecting out-of-pmove changes
+	qboolean showscores;	// set layout stat
+	qboolean showinventory;	// set layout stat
+	qboolean showhelp;
+	qboolean showhelpicon;
+	int ammo_index;
+	int buttons;
+	int oldbuttons;
+	int latched_buttons;
+	qboolean weapon_thunk;
+	gitem_t *newweapon;
 
-	void		(*RunFrame) (void);
+	/* sum up damage over an entire frame, so shotgun blasts give a single
+	 * big kick */
+	int damage_armor;	// damage absorbed by armor
+	int damage_parmor;	// damage absorbed by power armor
+	int damage_blood;	// damage taken out of health
+	int damage_knockback;	// impact damage
+	vec3_t damage_from;	// origin for vector calculation
+	float killer_yaw;	// when dead, look at killer
+	weaponstate_t weaponstate;
+	vec3_t kick_angles;	// weapon kicks
+	vec3_t kick_origin;
+	float v_dmg_roll;	// damage kicks
+	float v_dmg_pitch;
+	float v_dmg_time;
+	float fall_time;	// for view drop on fall
+	float fall_value;
+	float damage_alpha;
+	float bonus_alpha;
+	vec3_t damage_blend;
+	vec3_t v_angle;	// aiming direction so off-ground doesn't change it
+	float bobtime;
+	vec3_t oldviewangles;
+	vec3_t oldvelocity;
+	float next_drown_time;
+	int old_waterlevel;
+	int breather_sound;
+	int machinegun_shots;	// for weapon raising
+	int anim_end;
+	int anim_priority;
+	qboolean anim_duck;
+	qboolean anim_run;
+	/* powerup timers */
+	float quad_framenum;
+	float invincible_framenum;
+	float breather_framenum;
+	float enviro_framenum;
+	qboolean grenade_blew_up;
+	float grenade_time;
+	int silencer_shots;
+	int weapon_sound;
+	float pickup_msg_time;
+	float flood_locktill;	// locked from talking
+	float flood_when[10];	// when messages were said
+	int flood_whenhead;	// head pointer for when said
+	float respawn_time;	// can respawn when time > this
+	edict_t *chase_target;	// player we are chasing
+	qboolean update_chase;	// need to update chase info?
+};
+struct edict_t{
+	entity_state_t s;
+	gclient_t *client;	// nil if not a player
+	qboolean inuse;
+	int linkcount;
+	// FIXME: move these fields to a server private sv_entity_t
+	link_t area;	// linked to a division node or leaf
+	int num_clusters;	// if -1, use headnode instead
+	int clusternums[MAX_ENT_CLUSTERS];
+	int headnode;	// unused if num_clusters != -1
+	int areanum;
+	int areanum2;
+	int svflags;	// SCF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc.
+	vec3_t mins;
+	vec3_t maxs;
+	vec3_t absmin;
+	vec3_t absmax;
+	vec3_t size;
+	solid_t solid;
+	int clipmask;
+	edict_t *owner;
 
-	// ServerCommand will be called when an "sv <command>" command is issued on the
-	// server console.
-	// The game can issue gi.argc() / gi.argv() commands to get the rest
-	// of the parameters
-	void		(*ServerCommand) (void);
+	/* DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER EXPECTS THE FIELDS IN
+	 * THAT ORDER! */
 
-	//
-	// global variables shared between game and server
-	//
+	int movetype;
+	int flags;
+	char *model;
+	float freetime;	// sv.time when the object was freed
+	/* only used locally in game, not by server */
+	char *message;
+	char *classname;
+	int spawnflags;
+	float timestamp;
+	float angle;	// set in qe3, -1 = up, -2 = down
+	char *target;
+	char *targetname;
+	char *killtarget;
+	char *team;
+	char *pathtarget;
+	char *deathtarget;
+	char *combattarget;
+	edict_t *target_ent;
+	float speed;
+	float accel;
+	float decel;
+	vec3_t movedir;
+	vec3_t pos1;
+	vec3_t pos2;
+	vec3_t velocity;
+	vec3_t avelocity;
+	int mass;
+	float air_finished;
+	/* per entity gravity multiplier (1.0 is normal); use for lowgrav
+	 * artifact, flares */
+	float gravity;
+	edict_t *goalentity;
+	edict_t *movetarget;
+	float yaw_speed;
+	float ideal_yaw;
+	float nextthink;
+	void	(*prethink)(edict_t *);
+	void	(*think)(edict_t *);
+	void	(*blocked)(edict_t *, edict_t *);	//move to moveinfo?
+	void	(*touch)(edict_t *, edict_t *, cplane_t *, csurface_t *);
+	void	(*use)(edict_t *, edict_t *, edict_t *);
+	void	(*pain)(edict_t *, edict_t *, float, int);
+	void	(*die)(edict_t *, edict_t *, edict_t *, int, vec3_t);
+	float touch_debounce_time;	// are all these legit?  do we need more/less of them?
+	float pain_debounce_time;
+	float damage_debounce_time;
+	float fly_sound_debounce_time;	//move to clientinfo
+	float last_move_time;
+	int health;
+	int max_health;
+	int gib_health;
+	int deadflag;
+	qboolean show_hostile;
+	float powerarmor_time;
+	char *map;	// target_changelevel
+	int viewheight;	// height above origin where eyesight is determined
+	int takedamage;
+	int dmg;
+	int radius_dmg;
+	float dmg_radius;
+	int sounds;	//make this a spawntemp var?
+	int count;
+	edict_t *chain;
+	edict_t *enemy;
+	edict_t *oldenemy;
+	edict_t *activator;
+	edict_t *groundentity;
+	int groundentity_linkcount;
+	edict_t *teamchain;
+	edict_t *teammaster;
+	edict_t *mynoise;	// can go in client only
+	edict_t *mynoise2;
+	int noise_index;
+	int noise_index2;
+	float volume;
+	float attenuation;
+	/* timing variables */
+	float wait;
+	float delay;	// before firing targets
+	float random;
+	float teleport_time;
+	int watertype;
+	int waterlevel;
+	vec3_t move_origin;
+	vec3_t move_angles;
+	/* move this to clientinfo? */
+	int light_level;
+	int style;	// also used as areaportal number
+	gitem_t *item;	// for bonus items
+	/* common data blocks */
+	moveinfo_t moveinfo;
+	monsterinfo_t monsterinfo;
+};
+extern edict_t *g_edicts;
 
-	// The edict array is allocated in the game dll so it
-	// can vary in size from one game to another.
-	// 
-	// The size will be fixed when ge->Init() is called
-	edict_t	*edicts;
-	int			edict_size;
-	int			num_edicts;		// current number, <= max_edicts
-	int			max_edicts;
-} game_export_t;
+#define WORLD	(&g_edicts[0])
 
-game_export_t *GetGameAPI (game_import_t *import);
+#define	ITEM_INDEX(x)	((x)-itemlist)
+#define	FOFS(x)	(uintptr)&(((edict_t *)0)->x)
+#define	STOFS(x)	(uintptr)&(((spawn_temp_t *)0)->x)
+#define	LLOFS(x)	(uintptr)&(((level_locals_t *)0)->x)
+#define	CLOFS(x)	(uintptr)&(((gclient_t *)0)->x)
+#define qrandom()	((rand () & 0x7fff) / ((float)0x7fff))	/* >_< arrrrggghh */
+#define crandom()	(2.0 * (qrandom() - 0.5))
+
+void	Cmd_Help_f(edict_t *);
+void	Cmd_Score_f(edict_t *);
+void	PrecacheItem(gitem_t *);
+void	InitItems(void);
+void	SetItemNames(void);
+gitem_t*	FindItem(char *);
+gitem_t*	FindItemByClassname(char *);
+edict_t*	Drop_Item(edict_t *, gitem_t *);
+void	SetRespawn(edict_t *, float);
+void	ChangeWeapon(edict_t *);
+void	SpawnItem(edict_t *, gitem_t *);
+void	Think_Weapon(edict_t *);
+int	ArmorIndex(edict_t *);
+int	PowerArmorType(edict_t *);
+gitem_t*	GetItemByIndex(int);
+qboolean	Add_Ammo(edict_t *, gitem_t *, int);
+void	Touch_Item(edict_t *, edict_t *, cplane_t *, csurface_t *);
+qboolean	KillBox(edict_t *);
+void	G_ProjectSource(vec3_t, vec3_t, vec3_t, vec3_t, vec3_t);
+edict_t*	G_Find(edict_t *, int, char *);
+edict_t*	findradius(edict_t *, vec3_t, float);
+edict_t*	G_PickTarget(char *);
+void	G_UseTargets(edict_t *, edict_t *);
+void	G_SetMovedir(vec3_t, vec3_t);
+void	G_InitEdict(edict_t *);
+edict_t*	G_Spawn(void);
+void	G_FreeEdict(edict_t *);
+void	G_TouchTriggers(edict_t *);
+void	G_TouchSolids(edict_t *);
+char*	G_CopyString(char *);
+float*	tv(float, float, float);
+char*	vtos(vec3_t);
+float	vectoyaw(vec3_t);
+void	vectoangles(vec3_t, vec3_t);
+qboolean	OnSameTeam(edict_t *, edict_t *);
+qboolean	CanDamage(edict_t *, edict_t *);
+void	T_Damage(edict_t *, edict_t *, edict_t *, vec3_t, vec3_t, vec3_t, int, int, int, int);
+void	T_RadiusDamage(edict_t *, edict_t *, float, edict_t *, float, int);
+void	monster_fire_bullet(edict_t *, vec3_t, vec3_t, int, int, int, int, int);
+void	monster_fire_shotgun(edict_t *, vec3_t, vec3_t, int, int, int, int, int, int);
+void	monster_fire_blaster(edict_t *, vec3_t, vec3_t, int, int, int, int);
+void	monster_fire_grenade(edict_t *, vec3_t, vec3_t, int, int, int);
+void	monster_fire_rocket(edict_t *, vec3_t, vec3_t, int, int, int);
+void	monster_fire_railgun(edict_t *, vec3_t, vec3_t, int, int, int);
+void	monster_fire_bfg(edict_t *, vec3_t, vec3_t, int, int, int, float, int);
+void	M_droptofloor(edict_t *);
+void	monster_think(edict_t *);
+void	walkmonster_start(edict_t *);
+void	swimmonster_start(edict_t *);
+void	flymonster_start(edict_t *);
+void	AttackFinished(edict_t *, float);
+void	monster_death_use(edict_t *);
+void	M_CatagorizePosition(edict_t *);
+qboolean	M_CheckAttack(edict_t *);
+void	M_FlyCheck(edict_t *);
+void	M_CheckGround(edict_t *);
+void	ThrowHead(edict_t *, char *, int, int);
+void	ThrowClientHead(edict_t *, int);
+void	ThrowGib(edict_t *, char *, int, int);
+void	BecomeExplosion1(edict_t *);
+void	AI_SetSightClient(void);
+void	ai_stand(edict_t *, float);
+void	ai_move(edict_t *, float);
+void	ai_walk(edict_t *, float);
+void	ai_turn(edict_t *, float);
+void	ai_run(edict_t *, float);
+void	ai_charge(edict_t *, float);
+int	range(edict_t *, edict_t *);
+void	FoundTarget(edict_t *);
+qboolean	infront(edict_t *, edict_t *);
+qboolean	visible(edict_t *, edict_t *);
+qboolean	FacingIdeal(edict_t *);
+void	ThrowDebris(edict_t *, char *, float, vec3_t);
+qboolean	fire_hit(edict_t *, vec3_t, int, int);
+void	fire_bullet(edict_t *, vec3_t, vec3_t, int, int, int, int, int);
+void	fire_shotgun(edict_t *, vec3_t, vec3_t, int, int, int, int, int, int);
+void	fire_blaster(edict_t *, vec3_t, vec3_t, int, int, int, qboolean);
+void	fire_grenade(edict_t *, vec3_t, vec3_t, int, int, float, float);
+void	fire_grenade2(edict_t *, vec3_t, vec3_t, int, int, float, float, qboolean);
+void	fire_rocket(edict_t *, vec3_t, vec3_t, int, int, float, int);
+void	fire_rail(edict_t *, vec3_t, vec3_t, int, int);
+void	fire_bfg(edict_t *, vec3_t, vec3_t, int, int, float);
+void	PlayerTrail_Init(void);
+void	PlayerTrail_Add(vec3_t);
+void	PlayerTrail_New(vec3_t);
+edict_t*	PlayerTrail_PickFirst(edict_t *);
+edict_t*	PlayerTrail_PickNext(edict_t *);
+edict_t*	PlayerTrail_LastSpot(void);
+void	respawn(edict_t *);
+void	BeginIntermission(edict_t *);
+void	PutClientInServer(edict_t *);
+void	InitClientPersistant(gclient_t *);
+void	InitClientResp(gclient_t *);
+void	InitBodyQue(void);
+void	ClientBeginServerFrame(edict_t *);
+void	player_pain(edict_t *, edict_t *, float, int);
+void	player_die(edict_t *, edict_t *, edict_t *, int, vec3_t);
+void	ServerCommand(void);
+qboolean	SV_FilterPacket(char *);
+void	ClientEndServerFrame(edict_t *);
+void	MoveClientToIntermission(edict_t *);
+void	G_SetStats(edict_t *);
+void	G_SetSpectatorStats(edict_t *);
+void	G_CheckChaseStats(edict_t *);
+void	ValidateSelectedItem(edict_t *);
+void	DeathmatchScoreboardMessage(edict_t *, edict_t *);
+void	PlayerNoise(edict_t *, vec3_t, int);
+qboolean	M_CheckBottom(edict_t *);
+qboolean	M_walkmove(edict_t *, float, float);
+void	M_MoveToGoal(edict_t *, float);
+void	M_ChangeYaw(edict_t *);
+void	G_RunEntity(edict_t *);
+void	SaveClientData(void);
+void	FetchClientEntData(edict_t *);
+void	UpdateChaseCam(edict_t *);
+void	ChaseNext(edict_t *);
+void	ChasePrev(edict_t *);
+void	GetChaseTarget(edict_t *);
--- a/game/m_actor.c
+++ b/game/m_actor.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_actor.h"
 
 #define	MAX_ACTOR_NAMES		8
--- a/game/m_berserk.c
+++ b/game/m_berserk.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_berserk.h"
 
 
--- a/game/m_boss2.c
+++ b/game/m_boss2.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_boss2.h"
 
 void BossExplode (edict_t *self);
--- a/game/m_boss3.c
+++ b/game/m_boss3.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_boss32.h"
 
 void Use_Boss3 (edict_t *ent, edict_t */*other*/, edict_t */*activator*/)
--- a/game/m_boss31.c
+++ b/game/m_boss31.c
@@ -3,7 +3,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_boss31.h"
 
 extern SP_monster_makron (edict_t *self);
--- a/game/m_boss32.c
+++ b/game/m_boss32.c
@@ -3,7 +3,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_boss32.h"
 
 qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_brain.c
+++ b/game/m_brain.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_brain.h"
 
 
--- a/game/m_chick.c
+++ b/game/m_chick.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_chick.h"
 
 qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_flash.c
+++ b/game/m_flash.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 // this file is included in both the game dll and quake2,
 // the game needs it to source shot locations, the client
--- a/game/m_flipper.c
+++ b/game/m_flipper.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_flipper.h"
 
 
--- a/game/m_float.c
+++ b/game/m_float.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_float.h"
 
 
--- a/game/m_flyer.c
+++ b/game/m_flyer.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_flyer.h"
 
 qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_gladiator.c
+++ b/game/m_gladiator.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_gladiator.h"
 
 
--- a/game/m_gunner.c
+++ b/game/m_gunner.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_gunner.h"
 
 
--- a/game/m_hover.c
+++ b/game/m_hover.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_hover.h"
 
 qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_infantry.c
+++ b/game/m_infantry.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_infantry.h"
 
 void InfantryMachineGun (edict_t *self);
--- a/game/m_insane.c
+++ b/game/m_insane.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_insane.h"
 
 
--- a/game/m_medic.c
+++ b/game/m_medic.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_medic.h"
 
 qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_move.c
+++ b/game/m_move.c
@@ -3,7 +3,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 #define	STEPSIZE	18
 
--- a/game/m_mutant.c
+++ b/game/m_mutant.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_mutant.h"
 
 
--- a/game/m_parasite.c
+++ b/game/m_parasite.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_parasite.h"
 
 
--- a/game/m_soldier.c
+++ b/game/m_soldier.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_soldier.h"
 
 
--- a/game/m_supertank.c
+++ b/game/m_supertank.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_supertank.h"
 
 qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_tank.c
+++ b/game/m_tank.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_tank.h"
 
 
--- a/game/p_client.c
+++ b/game/p_client.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_player.h"
 
 void ClientUserinfoChanged (edict_t *ent, char *userinfo);
--- a/game/p_hud.c
+++ b/game/p_hud.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 /*
 ======================================================================
--- a/game/p_trail.c
+++ b/game/p_trail.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 
 /*
--- a/game/p_view.c
+++ b/game/p_view.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_player.h"
 
 
--- a/game/p_weapon.c
+++ b/game/p_weapon.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 #include "m_player.h"
 
 
--- a/game/q_shared.c
+++ b/game/q_shared.c
@@ -1,7 +1,8 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
 
 #define DEG2RAD( a ) ( a * M_PI ) / 180.0F
 
@@ -251,7 +252,7 @@
 
 
 // this is the slow, general version
-int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, cplane_t *p)
 {
 	int		i;
 	float	dist1, dist2;
@@ -289,7 +290,7 @@
 Returns 1, 2, or 1 + 2
 ==================
 */
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, cplane_t *p)
 {
 	float	dist1, dist2;
 	int		sides;
--- /dev/null
+++ b/in.c
@@ -1,0 +1,455 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <draw.h>
+#include <thread.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include "dat.h"
+#include "fns.h"
+
+extern int resized;		/* vid.c */
+extern Point center;
+extern Channel *fuckchan, *tchan;	/* sys.c */
+
+cvar_t *in_joystick;
+cvar_t *sensitivity;
+cvar_t *lookstrafe;
+cvar_t *lookspring;
+cvar_t *freelook;
+cvar_t *m_pitch;
+
+static cvar_t *m_filter;
+static cvar_t *m_windowed;
+static cvar_t *m_yaw;
+static cvar_t *m_side;
+static cvar_t *m_forward;
+
+static int mouseon;
+static int mlooking;
+static int dx, dy;
+static int oldmwin;
+
+typedef struct Kev Kev;
+struct Kev{
+	int key;
+	int down;
+};
+enum{
+	Nbuf	= 64
+};
+static Channel *kchan, *mchan;
+static int iop = -1, pfd[2];
+static QLock killock;
+
+
+char *
+Sys_ConsoleInput(void)
+{
+	static char buf[256];
+	int n;
+
+	if(dedicated != nil && dedicated->value && iop >= 0){
+		if(flen(pfd[1]) < 1)	/* only poll for input */
+			return nil;
+		if((n = read(pfd[1], buf, sizeof buf)) < 0)
+			sysfatal("Sys_ConsoleInput:read: %r");
+		if(n == 0){
+			iop = -1;
+			return nil;
+		}
+		return buf;
+	}
+	return nil;
+}
+
+void
+IN_Grabm(int on)
+{
+	static char nocurs[2*4+2*2*16];
+	static int fd = -1;
+
+	if(mouseon == on)
+		return;
+	if(mouseon = on && m_windowed->value){
+		if((fd = open("/dev/cursor", ORDWR|OCEXEC)) < 0){
+			sysfatal("IN_Grabm:open: %r\n");
+			return;
+		}
+		write(fd, nocurs, sizeof nocurs);
+	}else if(fd >= 0){
+		close(fd);
+		fd = -1;
+	}
+}
+
+void
+IN_Commands(void)
+{
+	/* joystick stuff */
+}
+
+void
+btnev(int btn, ulong msec)
+{
+	static int oldb;
+	int i, b;
+
+	for(i = 0; i < 3; i++){
+		b = 1<<i;
+		if(btn & b && ~oldb & b)
+			Key_Event(K_MOUSE1+i, true, msec);
+		else if(~btn & b && oldb & b)
+			Key_Event(K_MOUSE1+i, false, msec);
+	}
+	oldb = btn;
+	/* mwheelup and mwheeldn buttons are never held down */
+	for(i = 3; i < 5; i++){
+		b = 1<<i;
+		if(btn & b){
+			Key_Event(K_MOUSE1+i, true, msec);
+			Key_Event(K_MOUSE1+i, false, msec);
+		}
+	}
+}
+
+void
+KBD_Update(void)
+{
+	int r;
+	Kev ev;
+	Mouse m;
+
+	if(oldmwin != m_windowed->value){
+		oldmwin = m_windowed->value;
+		IN_Grabm(m_windowed->value);
+	}
+	while((r = nbrecv(kchan, &ev)) > 0)
+		Key_Event(ev.key, ev.down, Sys_Milliseconds());
+	if(r < 0)
+		sysfatal("KBD_Update:nbrecv: %r\n");
+	while((r = nbrecv(mchan, &m)) > 0){
+		dx += m.xy.x;
+		dy += m.xy.y;
+		btnev(m.buttons, m.msec);
+	}
+	if(r < 0)
+		sysfatal("KBD_Update:nbrecv: %r\n");
+}
+
+void
+IN_Move(usercmd_t *cmd)
+{
+	static int oldmx, oldmy;
+	int mx, my;
+
+	if(!mouseon)
+		return;
+
+	if(m_filter->value){
+		mx = (dx + oldmx) * 0.5;
+		my = (dy + oldmy) * 0.5;
+	}else{
+		mx = dx;
+		my = dy;
+	}
+	oldmx = dx;
+	oldmy = dy;
+	dx = dy = 0;
+	if(!mx && !my)
+		return;
+	mx *= sensitivity->value;
+	my *= sensitivity->value;
+
+	/* add mouse x/y movement to cmd */
+	if(in_strafe.state & 1 || lookstrafe->value && mlooking)
+		cmd->sidemove += m_side->value * mx;
+	else
+		cl.viewangles[YAW] -= m_yaw->value * mx;
+	if((mlooking || freelook->value) && ~in_strafe.state & 1)
+		cl.viewangles[PITCH] += m_pitch->value * my;
+	else
+		cmd->forwardmove -= m_forward->value * my;
+}
+
+/* called on focus/unfocus in win32 */
+void
+IN_Activate(qboolean)
+{
+}
+
+/* called every frame even if not generating commands */
+void
+IN_Frame(void)
+{
+}
+
+void
+IN_ForceCenterView(void)
+{
+	cl.viewangles[PITCH] = 0;
+}
+
+void
+IN_MLookDown(void)
+{
+	mlooking = true;
+}
+
+void
+IN_MLookUp(void)
+{
+	mlooking = false;
+	IN_CenterView();
+}
+
+static int
+runetokey(Rune r)
+{
+	int k = 0;
+
+	switch(r){
+	case Kpgup:	k = K_PGUP; break;
+	case Kpgdown:	k = K_PGDN; break;
+	case Khome:	k = K_HOME; break;
+	case Kend:	k = K_END; break;
+	case Kleft:	k = K_LEFTARROW; break;
+	case Kright:	k = K_RIGHTARROW; break;
+	case Kdown:	k = K_DOWNARROW; break;
+	case Kup:	k = K_UPARROW; break;
+	case Kesc:	k = K_ESCAPE; break;
+	case '\n':	k = K_ENTER; break;
+	case '\t':	k = K_TAB; break;
+	case KF|1:	k = K_F1; break;
+	case KF|2:	k = K_F2; break;
+	case KF|3:	k = K_F3; break;
+	case KF|4:	k = K_F4; break;
+	case KF|5:	k = K_F5; break;
+	case KF|6:	k = K_F6; break;
+	case KF|7:	k = K_F7; break;
+	case KF|8:	k = K_F8; break;
+	case KF|9:	k = K_F9; break;
+	case KF|10:	k = K_F10; break;
+	case KF|11:	k = K_F11; break;
+	case KF|12:	k = K_F12; break;
+	case Kbs:	k = K_BACKSPACE; break;
+	case Kdel:	k = K_DEL; break;
+	case Kbreak:	k = K_PAUSE; break;
+	case Kshift:	k = K_SHIFT; break;
+	case Kctl:	k = K_CTRL; break;
+	case Kalt:
+	case Kaltgr:	k = K_ALT; break;
+	case Kins:	k = K_INS; break;
+	default:
+		if(r < 0x80)
+			k = r;
+	};
+	return k;
+}
+
+static void
+kproc(void *)
+{
+	int n, k, fd;
+	char buf[128], kdown[128], *s;
+	Rune r;
+	Kev ev;
+
+	if(threadsetgrp(THin) < 0)
+		sysfatal("kproc:threadsetgrp: %r");
+	if((fd = open("/dev/kbd", OREAD)) < 0)
+		sysfatal("open /dev/kbd: %r");
+
+	kdown[0] = kdown[1] = 0;
+	while((n = read(fd, buf, sizeof buf)) > 0){
+		buf[n-1] = 0;
+		switch(*buf){
+		case 'c':
+		default:
+			continue;
+		case 'k':
+			s = buf+1;
+			while(*s){
+				s += chartorune(&r, s);
+				if(utfrune(kdown+1, r) == nil){
+					if(k = runetokey(r)){
+						ev.key = k;
+						ev.down = true;
+						if(send(kchan, &ev) < 0)
+							sysfatal("kproc:nbsend: %r\n");
+					}
+				}
+			}
+			break;
+		case 'K':
+			s = kdown+1;
+			while(*s){
+				s += chartorune(&r, s);
+				if(utfrune(buf+1, r) == nil){
+					if(k = runetokey(r)){
+						ev.key = k;
+						ev.down = false;
+						if(send(kchan, &ev) < 0)
+							sysfatal("mproc:nbsend: %r\n");
+					}
+				}
+			}
+			break;
+		}
+		strcpy(kdown, buf);
+	}
+	fprint(2, "kproc: %r\n");
+	close(fd);
+}
+
+static void
+mproc(void *)
+{
+	int n, nerr = 0, fd;
+	char buf[1+5*12];
+	Mouse m;
+
+	if(threadsetgrp(THin) < 0)
+		sysfatal("mproc:threadsetgrp: %r");
+	if((fd = open("/dev/mouse", ORDWR)) < 0)
+		sysfatal("open /dev/mouse: %r");
+
+	for(;;){
+		if((n = read(fd, buf, sizeof buf)) != 1+4*12){
+			fprint(2, "mproc:read: bad count %d not 49: %r\n", n);
+			if(n < 0 || ++nerr > 10)
+				break;
+			continue;
+		}
+		nerr = 0;
+		switch(*buf){
+		case 'r':
+			resized = 1;
+			/* fall through */
+		case 'm':
+			if(!mouseon)
+				break;
+
+			m.xy.x = atoi(buf+1+0*12) - center.x;
+			m.xy.y = atoi(buf+1+1*12) - center.y;
+			if(m.xy.x != 0 || m.xy.y != 0)
+				fprint(fd, "m%d %d", center.x, center.y);
+			m.buttons = atoi(buf+1+2*12);
+			m.msec = atoi(buf+1+3*12);
+			if(nbsend(mchan, &m) < 0)
+				sysfatal("mproc:nbsend: %r\n");
+			break;
+		}
+	}
+	fprint(2, "mproc: %r\n");
+	IN_Grabm(0);
+	close(fd);
+}
+
+static void
+tproc(void *)	/* stupid select() timeout bullshit */
+{
+	int t, ms, n, r;
+
+	threadsetgrp(THin);
+
+	t = ms = 0;
+	for(;;){
+		sleep(1);
+		t++;
+
+		if((r = nbrecv(tchan, &n)) < 0)
+			sysfatal("tproc:nbrecv: %r");
+		if(r == 0){
+			if(t == ms && nbsend(fuckchan, nil) < 0)
+				sysfatal("tproc:nbsend: %r");
+			continue;
+		}
+		if(n <= 0)
+			ms = 0;
+		else{
+			ms = n;
+			t = 0;
+		}
+	}
+}
+
+static void
+iproc(void *)
+{
+	int n;
+	char s[256];
+
+	threadsetgrp(THin);
+
+	if((iop = pipe(pfd)) < 0)
+		sysfatal("iproc:pipe: %r");
+	for(;;){
+		if((n = read(0, s, sizeof s)) <= 0)
+			break;
+		s[n-1] = 0;
+		if((write(pfd[0], s, n)) != n)
+			break;
+		if(nbsend(fuckchan, nil) < 0)
+			sysfatal("iproc:nbsend: %r");
+	}
+	fprint(2, "iproc %d: %r\n", threadpid(threadid()));
+	iop = -1;
+}
+
+void
+IN_Shutdown(void)
+{
+	qlock(&killock);	/* there can be only one */
+	IN_Grabm(0);
+	threadkillgrp(THin);
+	iop = -1;
+	close(pfd[0]);
+	close(pfd[1]);
+	if(kchan != nil){
+		chanfree(kchan);
+		kchan = nil;
+	}
+	if(mchan != nil){
+		chanfree(mchan);
+		mchan = nil;
+	}
+	qunlock(&killock);
+}
+
+void
+IN_Init(void)
+{
+	if(dedicated->value){
+		if(proccreate(iproc, nil, 8192) < 0)
+			sysfatal("proccreate iproc: %r");
+		if(proccreate(tproc, nil, 8192) < 0)
+			sysfatal("proccreate tproc: %r");
+		return;
+	}
+	in_joystick = Cvar_Get("in_joystick", "0", CVAR_ARCHIVE);
+	sensitivity = Cvar_Get("sensitivity", "3", CVAR_ARCHIVE);
+	freelook = Cvar_Get("freelook", "0", CVAR_ARCHIVE);
+	lookspring = Cvar_Get("lookspring", "0", CVAR_ARCHIVE);
+	lookstrafe = Cvar_Get("lookstrafe", "0", CVAR_ARCHIVE);
+	m_pitch = Cvar_Get("m_pitch", "0.022", CVAR_ARCHIVE);
+
+	m_yaw = Cvar_Get("m_yaw", "0.022", 0);
+	m_forward = Cvar_Get("m_forward", "1", 0);
+	m_side = Cvar_Get("m_side", "0.8", 0);
+	m_windowed = Cvar_Get("m_windowed", "0", CVAR_ARCHIVE);
+	m_filter = Cvar_Get("m_filter", "0", 0);
+
+	Cmd_AddCommand("+mlook", IN_MLookDown);
+	Cmd_AddCommand("-mlook", IN_MLookUp);
+	Cmd_AddCommand("force_centerview", IN_ForceCenterView);
+
+	if((kchan = chancreate(sizeof(Kev), Nbuf)) == nil)
+		sysfatal("chancreate kchan: %r");
+	if(proccreate(kproc, nil, 8192) < 0)
+		sysfatal("proccreate kproc: %r");
+	if((mchan = chancreate(sizeof(Mouse), Nbuf)) == nil)
+		sysfatal("chancreate kchan: %r");
+	if(proccreate(mproc, nil, 8192) < 0)
+		sysfatal("proccreate mproc: %r");
+}
--- /dev/null
+++ b/keys.c
@@ -1,0 +1,928 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+
+key up events are sent even if in console mode
+
+*/
+
+
+#define		MAXCMDLINE	256
+char	key_lines[32][MAXCMDLINE];
+int		key_linepos;
+int		shift_down=false;
+int	anykeydown;
+
+int		edit_line=0;
+int		history_line=0;
+
+int		key_waiting;
+char	*keybindings[256];
+qboolean	consolekeys[256];	// if true, can't be rebound while in console
+qboolean	menubound[256];	// if true, can't be rebound while in menu
+int		keyshift[256];		// key to map to if shift held down in console
+int		key_repeats[256];	// if > 1, it is autorepeating
+qboolean	keydown[256];
+
+typedef struct
+{
+	char	*name;
+	int		keynum;
+} keyname_t;
+
+keyname_t keynames[] =
+{
+	{"TAB", K_TAB},
+	{"ENTER", K_ENTER},
+	{"ESCAPE", K_ESCAPE},
+	{"SPACE", K_SPACE},
+	{"BACKSPACE", K_BACKSPACE},
+	{"UPARROW", K_UPARROW},
+	{"DOWNARROW", K_DOWNARROW},
+	{"LEFTARROW", K_LEFTARROW},
+	{"RIGHTARROW", K_RIGHTARROW},
+
+	{"ALT", K_ALT},
+	{"CTRL", K_CTRL},
+	{"SHIFT", K_SHIFT},
+	
+	{"F1", K_F1},
+	{"F2", K_F2},
+	{"F3", K_F3},
+	{"F4", K_F4},
+	{"F5", K_F5},
+	{"F6", K_F6},
+	{"F7", K_F7},
+	{"F8", K_F8},
+	{"F9", K_F9},
+	{"F10", K_F10},
+	{"F11", K_F11},
+	{"F12", K_F12},
+
+	{"INS", K_INS},
+	{"DEL", K_DEL},
+	{"PGDN", K_PGDN},
+	{"PGUP", K_PGUP},
+	{"HOME", K_HOME},
+	{"END", K_END},
+
+	{"MOUSE1", K_MOUSE1},
+	{"MOUSE2", K_MOUSE2},
+	{"MOUSE3", K_MOUSE3},
+
+	{"JOY1", K_JOY1},
+	{"JOY2", K_JOY2},
+	{"JOY3", K_JOY3},
+	{"JOY4", K_JOY4},
+
+	{"AUX1", K_AUX1},
+	{"AUX2", K_AUX2},
+	{"AUX3", K_AUX3},
+	{"AUX4", K_AUX4},
+	{"AUX5", K_AUX5},
+	{"AUX6", K_AUX6},
+	{"AUX7", K_AUX7},
+	{"AUX8", K_AUX8},
+	{"AUX9", K_AUX9},
+	{"AUX10", K_AUX10},
+	{"AUX11", K_AUX11},
+	{"AUX12", K_AUX12},
+	{"AUX13", K_AUX13},
+	{"AUX14", K_AUX14},
+	{"AUX15", K_AUX15},
+	{"AUX16", K_AUX16},
+	{"AUX17", K_AUX17},
+	{"AUX18", K_AUX18},
+	{"AUX19", K_AUX19},
+	{"AUX20", K_AUX20},
+	{"AUX21", K_AUX21},
+	{"AUX22", K_AUX22},
+	{"AUX23", K_AUX23},
+	{"AUX24", K_AUX24},
+	{"AUX25", K_AUX25},
+	{"AUX26", K_AUX26},
+	{"AUX27", K_AUX27},
+	{"AUX28", K_AUX28},
+	{"AUX29", K_AUX29},
+	{"AUX30", K_AUX30},
+	{"AUX31", K_AUX31},
+	{"AUX32", K_AUX32},
+
+	{"KP_HOME",			K_KP_HOME },
+	{"KP_UPARROW",		K_KP_UPARROW },
+	{"KP_PGUP",			K_KP_PGUP },
+	{"KP_LEFTARROW",	K_KP_LEFTARROW },
+	{"KP_5",			K_KP_5 },
+	{"KP_RIGHTARROW",	K_KP_RIGHTARROW },
+	{"KP_END",			K_KP_END },
+	{"KP_DOWNARROW",	K_KP_DOWNARROW },
+	{"KP_PGDN",			K_KP_PGDN },
+	{"KP_ENTER",		K_KP_ENTER },
+	{"KP_INS",			K_KP_INS },
+	{"KP_DEL",			K_KP_DEL },
+	{"KP_SLASH",		K_KP_SLASH },
+	{"KP_MINUS",		K_KP_MINUS },
+	{"KP_PLUS",			K_KP_PLUS },
+
+	{"MWHEELUP", K_MWHEELUP },
+	{"MWHEELDOWN", K_MWHEELDOWN },
+
+	{"PAUSE", K_PAUSE},
+
+	{"SEMICOLON", ';'},	// because a raw semicolon seperates commands
+
+	{NULL,0}
+};
+
+/*
+==============================================================================
+
+			LINE TYPING INTO THE CONSOLE
+
+==============================================================================
+*/
+
+void CompleteCommand (void)
+{
+	char	*cmd, *s;
+
+	s = key_lines[edit_line]+1;
+	if (*s == '\\' || *s == '/')
+		s++;
+
+	cmd = Cmd_CompleteCommand (s);
+	if (!cmd)
+		cmd = Cvar_CompleteVariable (s);
+	if (cmd)
+	{
+		key_lines[edit_line][1] = '/';
+		strcpy (key_lines[edit_line]+2, cmd);
+		key_linepos = strlen(cmd)+2;
+		key_lines[edit_line][key_linepos] = ' ';
+		key_linepos++;
+		key_lines[edit_line][key_linepos] = 0;
+		return;
+	}
+}
+
+/*
+====================
+Key_Console
+
+Interactive line editing and console scrollback
+====================
+*/
+void Key_Console (int key)
+{
+
+	switch ( key )
+	{
+	case K_KP_SLASH:
+		key = '/';
+		break;
+	case K_KP_MINUS:
+		key = '-';
+		break;
+	case K_KP_PLUS:
+		key = '+';
+		break;
+	case K_KP_HOME:
+		key = '7';
+		break;
+	case K_KP_UPARROW:
+		key = '8';
+		break;
+	case K_KP_PGUP:
+		key = '9';
+		break;
+	case K_KP_LEFTARROW:
+		key = '4';
+		break;
+	case K_KP_5:
+		key = '5';
+		break;
+	case K_KP_RIGHTARROW:
+		key = '6';
+		break;
+	case K_KP_END:
+		key = '1';
+		break;
+	case K_KP_DOWNARROW:
+		key = '2';
+		break;
+	case K_KP_PGDN:
+		key = '3';
+		break;
+	case K_KP_INS:
+		key = '0';
+		break;
+	case K_KP_DEL:
+		key = '.';
+		break;
+	}
+
+	if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
+		 ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
+	{
+		char *cbd;
+		
+		if ( ( cbd = Sys_GetClipboardData() ) != 0 )
+		{
+			int i;
+
+			strtok( cbd, "\n\r\b" );
+
+			i = strlen( cbd );
+			if ( i + key_linepos >= MAXCMDLINE)
+				i= MAXCMDLINE - key_linepos;
+
+			if ( i > 0 )
+			{
+				cbd[i]=0;
+				strcat( key_lines[edit_line], cbd );
+				key_linepos += i;
+			}
+			free( cbd );
+		}
+
+		return;
+	}
+
+	if ( key == 'l' ) 
+	{
+		if ( keydown[K_CTRL] )
+		{
+			Cbuf_AddText ("clear\n");
+			return;
+		}
+	}
+
+	if ( key == K_ENTER || key == K_KP_ENTER )
+	{	// backslash text are commands, else chat
+		if (key_lines[edit_line][1] == '\\' || key_lines[edit_line][1] == '/')
+			Cbuf_AddText (key_lines[edit_line]+2);	// skip the >
+		else
+			Cbuf_AddText (key_lines[edit_line]+1);	// valid command
+
+		Cbuf_AddText ("\n");
+		Com_Printf ("%s\n",key_lines[edit_line]);
+		edit_line = (edit_line + 1) & 31;
+		history_line = edit_line;
+		key_lines[edit_line][0] = ']';
+		key_linepos = 1;
+		if (cls.state == ca_disconnected)
+			SCR_UpdateScreen ();	// force an update, because the command
+									// may take some time
+		return;
+	}
+
+	if (key == K_TAB)
+	{	// command completion
+		CompleteCommand ();
+		return;
+	}
+	
+	if ( ( key == K_BACKSPACE ) || ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) || ( ( key == 'h' ) && ( keydown[K_CTRL] ) ) )
+	{
+		if (key_linepos > 1)
+			key_linepos--;
+		return;
+	}
+
+	if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
+		 ( ( key == 'p' ) && keydown[K_CTRL] ) )
+	{
+		do
+		{
+			history_line = (history_line - 1) & 31;
+		} while (history_line != edit_line
+				&& !key_lines[history_line][1]);
+		if (history_line == edit_line)
+			history_line = (edit_line+1)&31;
+		strcpy(key_lines[edit_line], key_lines[history_line]);
+		key_linepos = strlen(key_lines[edit_line]);
+		return;
+	}
+
+	if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
+		 ( ( key == 'n' ) && keydown[K_CTRL] ) )
+	{
+		if (history_line == edit_line) return;
+		do
+		{
+			history_line = (history_line + 1) & 31;
+		}
+		while (history_line != edit_line
+			&& !key_lines[history_line][1]);
+		if (history_line == edit_line)
+		{
+			key_lines[edit_line][0] = ']';
+			key_linepos = 1;
+		}
+		else
+		{
+			strcpy(key_lines[edit_line], key_lines[history_line]);
+			key_linepos = strlen(key_lines[edit_line]);
+		}
+		return;
+	}
+
+	if (key == K_PGUP || key == K_KP_PGUP )
+	{
+		con.display -= 2;
+		return;
+	}
+
+	if (key == K_PGDN || key == K_KP_PGDN ) 
+	{
+		con.display += 2;
+		if (con.display > con.current)
+			con.display = con.current;
+		return;
+	}
+
+	if (key == K_HOME || key == K_KP_HOME )
+	{
+		con.display = con.current - con.totallines + 10;
+		return;
+	}
+
+	if (key == K_END || key == K_KP_END )
+	{
+		con.display = con.current;
+		return;
+	}
+	
+	if (key < 32 || key > 127)
+		return;	// non printable
+		
+	if (key_linepos < MAXCMDLINE-1)
+	{
+		key_lines[edit_line][key_linepos] = key;
+		key_linepos++;
+		key_lines[edit_line][key_linepos] = 0;
+	}
+
+}
+
+//============================================================================
+
+qboolean	chat_team;
+char		chat_buffer[MAXCMDLINE];
+int			chat_bufferlen = 0;
+
+void Key_Message (int key)
+{
+
+	if ( key == K_ENTER || key == K_KP_ENTER )
+	{
+		if (chat_team)
+			Cbuf_AddText ("say_team \"");
+		else
+			Cbuf_AddText ("say \"");
+		Cbuf_AddText(chat_buffer);
+		Cbuf_AddText("\"\n");
+
+		cls.key_dest = key_game;
+		chat_bufferlen = 0;
+		chat_buffer[0] = 0;
+		return;
+	}
+
+	if (key == K_ESCAPE)
+	{
+		cls.key_dest = key_game;
+		chat_bufferlen = 0;
+		chat_buffer[0] = 0;
+		return;
+	}
+
+	if (key < 32 || key > 127)
+		return;	// non printable
+
+	if (key == K_BACKSPACE)
+	{
+		if (chat_bufferlen)
+		{
+			chat_bufferlen--;
+			chat_buffer[chat_bufferlen] = 0;
+		}
+		return;
+	}
+
+	if (chat_bufferlen == sizeof(chat_buffer)-1)
+		return; // all full
+
+	chat_buffer[chat_bufferlen++] = key;
+	chat_buffer[chat_bufferlen] = 0;
+}
+
+//============================================================================
+
+
+/*
+===================
+Key_StringToKeynum
+
+Returns a key number to be used to index keybindings[] by looking at
+the given string.  Single ascii characters return themselves, while
+the K_* names are matched up.
+===================
+*/
+int Key_StringToKeynum (char *str)
+{
+	keyname_t	*kn;
+	
+	if (!str || !str[0])
+		return -1;
+	if (!str[1])
+		return str[0];
+
+	for (kn=keynames ; kn->name ; kn++)
+	{
+		if (!cistrcmp(str,kn->name))
+			return kn->keynum;
+	}
+	return -1;
+}
+
+/*
+===================
+Key_KeynumToString
+
+Returns a string (either a single ascii char, or a K_* name) for the
+given keynum.
+FIXME: handle quote special (general escape sequence?)
+===================
+*/
+char *Key_KeynumToString (int keynum)
+{
+	keyname_t	*kn;	
+	static	char	tinystr[2];
+	
+	if (keynum == -1)
+		return "<KEY NOT FOUND>";
+	if (keynum > 32 && keynum < 127)
+	{	// printable ascii
+		tinystr[0] = keynum;
+		tinystr[1] = 0;
+		return tinystr;
+	}
+	
+	for (kn=keynames ; kn->name ; kn++)
+		if (keynum == kn->keynum)
+			return kn->name;
+
+	return "<UNKNOWN KEYNUM>";
+}
+
+
+/*
+===================
+Key_SetBinding
+===================
+*/
+void Key_SetBinding (int keynum, char *binding)
+{
+	char	*new;
+	int		l;
+			
+	if (keynum == -1)
+		return;
+
+// free old bindings
+	if (keybindings[keynum])
+	{
+		Z_Free (keybindings[keynum]);
+		keybindings[keynum] = NULL;
+	}
+			
+// allocate memory for new binding
+	l = strlen (binding);	
+	new = Z_Malloc (l+1);
+	strcpy (new, binding);
+	new[l] = 0;
+	keybindings[keynum] = new;	
+}
+
+/*
+===================
+Key_Unbind_f
+===================
+*/
+void Key_Unbind_f (void)
+{
+	int		b;
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("unbind <key> : remove commands from a key\n");
+		return;
+	}
+	
+	b = Key_StringToKeynum (Cmd_Argv(1));
+	if (b==-1)
+	{
+		Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
+		return;
+	}
+
+	Key_SetBinding (b, "");
+}
+
+void Key_Unbindall_f (void)
+{
+	int		i;
+	
+	for (i=0 ; i<256 ; i++)
+		if (keybindings[i])
+			Key_SetBinding (i, "");
+}
+
+
+/*
+===================
+Key_Bind_f
+===================
+*/
+void Key_Bind_f (void)
+{
+	int			i, c, b;
+	char		cmd[1024];
+	
+	c = Cmd_Argc();
+
+	if (c < 2)
+	{
+		Com_Printf ("bind <key> [command] : attach a command to a key\n");
+		return;
+	}
+	b = Key_StringToKeynum (Cmd_Argv(1));
+	if (b==-1)
+	{
+		Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
+		return;
+	}
+
+	if (c == 2)
+	{
+		if (keybindings[b])
+			Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
+		else
+			Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
+		return;
+	}
+	
+// copy the rest of the command line
+	cmd[0] = 0;		// start out with a null string
+	for (i=2 ; i< c ; i++)
+	{
+		strcat (cmd, Cmd_Argv(i));
+		if (i != (c-1))
+			strcat (cmd, " ");
+	}
+
+	Key_SetBinding (b, cmd);
+}
+
+/*
+============
+Key_WriteBindings
+
+Writes lines containing "bind key value"
+============
+*/
+void Key_WriteBindings (FILE *f)
+{
+	int		i;
+
+	for (i=0 ; i<256 ; i++)
+		if (keybindings[i] && keybindings[i][0])
+			fprintf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
+}
+
+
+/*
+============
+Key_Bindlist_f
+
+============
+*/
+void Key_Bindlist_f (void)
+{
+	int		i;
+
+	for (i=0 ; i<256 ; i++)
+		if (keybindings[i] && keybindings[i][0])
+			Com_Printf ("%s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
+}
+
+
+/*
+===================
+Key_Init
+===================
+*/
+void Key_Init (void)
+{
+	int		i;
+
+	for (i=0 ; i<32 ; i++)
+	{
+		key_lines[i][0] = ']';
+		key_lines[i][1] = 0;
+	}
+	key_linepos = 1;
+	
+//
+// init ascii characters in console mode
+//
+	for (i=32 ; i<128 ; i++)
+		consolekeys[i] = true;
+	consolekeys[K_ENTER] = true;
+	consolekeys[K_KP_ENTER] = true;
+	consolekeys[K_TAB] = true;
+	consolekeys[K_LEFTARROW] = true;
+	consolekeys[K_KP_LEFTARROW] = true;
+	consolekeys[K_RIGHTARROW] = true;
+	consolekeys[K_KP_RIGHTARROW] = true;
+	consolekeys[K_UPARROW] = true;
+	consolekeys[K_KP_UPARROW] = true;
+	consolekeys[K_DOWNARROW] = true;
+	consolekeys[K_KP_DOWNARROW] = true;
+	consolekeys[K_BACKSPACE] = true;
+	consolekeys[K_HOME] = true;
+	consolekeys[K_KP_HOME] = true;
+	consolekeys[K_END] = true;
+	consolekeys[K_KP_END] = true;
+	consolekeys[K_PGUP] = true;
+	consolekeys[K_KP_PGUP] = true;
+	consolekeys[K_PGDN] = true;
+	consolekeys[K_KP_PGDN] = true;
+	consolekeys[K_SHIFT] = true;
+	consolekeys[K_INS] = true;
+	consolekeys[K_KP_INS] = true;
+	consolekeys[K_KP_DEL] = true;
+	consolekeys[K_KP_SLASH] = true;
+	consolekeys[K_KP_PLUS] = true;
+	consolekeys[K_KP_MINUS] = true;
+	consolekeys[K_KP_5] = true;
+
+	consolekeys['`'] = false;
+	consolekeys['~'] = false;
+
+	for (i=0 ; i<256 ; i++)
+		keyshift[i] = i;
+	for (i='a' ; i<='z' ; i++)
+		keyshift[i] = i - 'a' + 'A';
+	keyshift['1'] = '!';
+	keyshift['2'] = '@';
+	keyshift['3'] = '#';
+	keyshift['4'] = '$';
+	keyshift['5'] = '%';
+	keyshift['6'] = '^';
+	keyshift['7'] = '&';
+	keyshift['8'] = '*';
+	keyshift['9'] = '(';
+	keyshift['0'] = ')';
+	keyshift['-'] = '_';
+	keyshift['='] = '+';
+	keyshift[','] = '<';
+	keyshift['.'] = '>';
+	keyshift['/'] = '?';
+	keyshift[';'] = ':';
+	keyshift['\''] = '"';
+	keyshift['['] = '{';
+	keyshift[']'] = '}';
+	keyshift['`'] = '~';
+	keyshift['\\'] = '|';
+
+	menubound[K_ESCAPE] = true;
+	for (i=0 ; i<12 ; i++)
+		menubound[K_F1+i] = true;
+
+//
+// register our functions
+//
+	Cmd_AddCommand ("bind",Key_Bind_f);
+	Cmd_AddCommand ("unbind",Key_Unbind_f);
+	Cmd_AddCommand ("unbindall",Key_Unbindall_f);
+	Cmd_AddCommand ("bindlist",Key_Bindlist_f);
+}
+
+/*
+===================
+Key_Event
+
+Called by the system between frames for both key up and key down events
+Should NOT be called during an interrupt!
+===================
+*/
+void Key_Event (int key, qboolean down, unsigned time)
+{
+	char	*kb;
+	char	cmd[1024];
+
+	// hack for modal presses
+	if (key_waiting == -1)
+	{
+		if (down)
+			key_waiting = key;
+		return;
+	}
+
+	// update auto-repeat status
+	if (down)
+	{
+		key_repeats[key]++;
+		if (key != K_BACKSPACE 
+			&& key != K_PAUSE 
+			&& key != K_PGUP 
+			&& key != K_KP_PGUP 
+			&& key != K_PGDN
+			&& key != K_KP_PGDN
+			&& key_repeats[key] > 1)
+			return;	// ignore most autorepeats
+			
+		if (key >= 200 && !keybindings[key])
+			Com_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
+	}
+	else
+	{
+		key_repeats[key] = 0;
+	}
+
+	if (key == K_SHIFT)
+		shift_down = down;
+
+	// console key is hardcoded, so the user can never unbind it
+	if (key == '`' || key == '~')
+	{
+		if (!down)
+			return;
+		Con_ToggleConsole_f ();
+		return;
+	}
+
+	// any key during the attract mode will bring up the menu
+	if (cl.attractloop && cls.key_dest != key_menu)
+		key = K_ESCAPE;
+
+	// menu key is hardcoded, so the user can never unbind it
+	if (key == K_ESCAPE)
+	{
+		if (!down)
+			return;
+
+		if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
+		{	// put away help computer / inventory
+			Cbuf_AddText ("cmd putaway\n");
+			return;
+		}
+		switch (cls.key_dest)
+		{
+		case key_message:
+			Key_Message (key);
+			break;
+		case key_menu:
+			M_Keydown (key);
+			break;
+		case key_game:
+		case key_console:
+			M_Menu_Main_f ();
+			break;
+		default:
+			Com_Error (ERR_FATAL, "Bad cls.key_dest");
+		}
+		return;
+	}
+
+	// track if any key is down for BUTTON_ANY
+	keydown[key] = down;
+	if (down)
+	{
+		if (key_repeats[key] == 1)
+			anykeydown++;
+	}
+	else
+	{
+		anykeydown--;
+		if (anykeydown < 0)
+			anykeydown = 0;
+	}
+
+//
+// key up events only generate commands if the game key binding is
+// a button command (leading + sign).  These will occur even in console mode,
+// to keep the character from continuing an action started before a console
+// switch.  Button commands include the kenum as a parameter, so multiple
+// downs can be matched with ups
+//
+	if (!down)
+	{
+		kb = keybindings[key];
+		if (kb && kb[0] == '+')
+		{
+			Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
+			Cbuf_AddText (cmd);
+		}
+		if (keyshift[key] != key)
+		{
+			kb = keybindings[keyshift[key]];
+			if (kb && kb[0] == '+')
+			{
+				Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
+				Cbuf_AddText (cmd);
+			}
+		}
+		return;
+	}
+
+//
+// if not a consolekey, send to the interpreter no matter what mode is
+//
+	if ( (cls.key_dest == key_menu && menubound[key])
+	|| (cls.key_dest == key_console && !consolekeys[key])
+	|| (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
+	{
+		kb = keybindings[key];
+		if (kb)
+		{
+			if (kb[0] == '+')
+			{	// button commands add keynum and time as a parm
+				Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
+				Cbuf_AddText (cmd);
+			}
+			else
+			{
+				Cbuf_AddText (kb);
+				Cbuf_AddText ("\n");
+			}
+		}
+		return;
+	}
+
+	if (!down)
+		return;		// other systems only care about key down events
+
+	if (shift_down)
+		key = keyshift[key];
+
+	switch (cls.key_dest)
+	{
+	case key_message:
+		Key_Message (key);
+		break;
+	case key_menu:
+		M_Keydown (key);
+		break;
+
+	case key_game:
+	case key_console:
+		Key_Console (key);
+		break;
+	default:
+		Com_Error (ERR_FATAL, "Bad cls.key_dest");
+	}
+}
+
+/*
+===================
+Key_ClearStates
+===================
+*/
+void Key_ClearStates (void)
+{
+	int		i;
+
+	anykeydown = false;
+
+	for (i=0 ; i<256 ; i++)
+	{
+		if ( keydown[i] || key_repeats[i] )
+			Key_Event( i, false, 0 );
+		keydown[i] = 0;
+		key_repeats[i] = 0;
+	}
+}
+
+
+/*
+===================
+Key_GetKey
+===================
+*/
+int Key_GetKey (void)
+{
+	key_waiting = -1;
+
+	while (key_waiting == -1)
+		Sys_SendKeyEvents ();
+
+	return key_waiting;
+}
+
--- /dev/null
+++ b/md4.c
@@ -1,0 +1,276 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+  
+/* MD4.H - header file for MD4C.C */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. 
+
+All rights reserved.
+  
+License to copy and use this software is granted provided that it is identified as the �RSA Data Security, Inc. MD4 Message-Digest Algorithm� in all material mentioning or referencing this software or this function.
+License is also granted to make and use derivative works provided that such works are identified as �derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm� in all material mentioning or referencing the derived work.
+RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided �as is� without express or implied warranty of any kind.
+  
+These notices must be retained in any copies of any part of this documentation and/or software. */
+
+/* MD4 context. */
+typedef struct {
+	UINT4 state[4];				/* state (ABCD) */
+	UINT4 count[2];				/* number of bits, modulo 2^64 (lsb first) */
+	unsigned char buffer[64]; 			/* input buffer */
+} MD4_CTX;
+
+void MD4Init (MD4_CTX *);
+void MD4Update (MD4_CTX *, unsigned char *, unsigned int);
+void MD4Final (unsigned char [16], MD4_CTX *);
+  
+
+  
+/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm */
+/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
+  
+License to copy and use this software is granted provided that it is identified as the
+RSA Data Security, Inc. MD4 Message-Digest Algorithm
+ in all material mentioning or referencing this software or this function.
+License is also granted to make and use derivative works provided that such works are identified as 
+derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm
+in all material mentioning or referencing the derived work.
+RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided
+as is without express or implied warranty of any kind.
+  
+These notices must be retained in any copies of any part of this documentation and/or software. */
+
+/* Constants for MD4Transform routine.  */
+#define S11 3
+#define S12 7
+#define S13 11
+#define S14 19
+#define S21 3
+#define S22 5
+#define S23 9
+#define S24 13
+#define S31 3
+#define S32 9
+#define S33 11
+#define S34 15
+
+static void MD4Transform (UINT4 [4], unsigned char [64]);
+static void Encode (unsigned char *, UINT4 *, unsigned int);
+static void Decode (UINT4 *, unsigned char *, unsigned int);
+
+static unsigned char PADDING[64] = {
+0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G and H are basic MD4 functions. */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits. */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) {(a) += F ((b), (c), (d)) + (x); (a) = ROTATE_LEFT ((a), (s));}
+
+#define GG(a, b, c, d, x, s) {(a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; (a) = ROTATE_LEFT ((a), (s));}
+
+#define HH(a, b, c, d, x, s) {(a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; (a) = ROTATE_LEFT ((a), (s));}
+
+
+/* MD4 initialization. Begins an MD4 operation, writing a new context. */
+void MD4Init (MD4_CTX *context)
+{
+	context->count[0] = context->count[1] = 0;
+
+/* Load magic initialization constants.*/
+context->state[0] = 0x67452301;
+context->state[1] = 0xefcdab89;
+context->state[2] = 0x98badcfe;
+context->state[3] = 0x10325476;
+}
+
+/* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */
+void MD4Update (MD4_CTX *context, unsigned char *input, unsigned int inputLen)
+{
+	unsigned int i, index, partLen;
+
+	/* Compute number of bytes mod 64 */
+	index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+	/* Update number of bits */
+	if ((context->count[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3))
+		context->count[1]++;
+
+	context->count[1] += ((UINT4)inputLen >> 29);
+
+	partLen = 64 - index;
+
+	/* Transform as many times as possible.*/
+	if (inputLen >= partLen)
+	{
+ 		memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ 		MD4Transform (context->state, context->buffer);
+
+ 		for (i = partLen; i + 63 < inputLen; i += 64)
+ 			MD4Transform (context->state, &input[i]);
+
+ 		index = 0;
+	}
+	else
+ 		i = 0;
+
+	/* Buffer remaining input */
+	memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
+}
+
+
+/* MD4 finalization. Ends an MD4 message-digest operation, writing the the message digest and zeroizing the context. */
+void MD4Final (unsigned char digest[16], MD4_CTX *context)
+{
+	unsigned char bits[8];
+	unsigned int index, padLen;
+
+	/* Save number of bits */
+	Encode (bits, context->count, 8);
+
+	/* Pad out to 56 mod 64.*/
+	index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+	padLen = (index < 56) ? (56 - index) : (120 - index);
+	MD4Update (context, PADDING, padLen);
+
+	/* Append length (before padding) */
+	MD4Update (context, bits, 8);
+	
+	/* Store state in digest */
+	Encode (digest, context->state, 16);
+
+	/* Zeroize sensitive information.*/
+	memset ((POINTER)context, 0, sizeof (*context));
+}
+
+
+/* MD4 basic transformation. Transforms state based on block. */
+static void MD4Transform (UINT4 state[4], unsigned char block[64])
+{
+	UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+	Decode (x, block, 64);
+
+/* Round 1 */
+FF (a, b, c, d, x[ 0], S11); 				/* 1 */
+FF (d, a, b, c, x[ 1], S12); 				/* 2 */
+FF (c, d, a, b, x[ 2], S13); 				/* 3 */
+FF (b, c, d, a, x[ 3], S14); 				/* 4 */
+FF (a, b, c, d, x[ 4], S11); 				/* 5 */
+FF (d, a, b, c, x[ 5], S12); 				/* 6 */
+FF (c, d, a, b, x[ 6], S13); 				/* 7 */
+FF (b, c, d, a, x[ 7], S14); 				/* 8 */
+FF (a, b, c, d, x[ 8], S11); 				/* 9 */
+FF (d, a, b, c, x[ 9], S12); 				/* 10 */
+FF (c, d, a, b, x[10], S13); 			/* 11 */
+FF (b, c, d, a, x[11], S14); 			/* 12 */
+FF (a, b, c, d, x[12], S11); 			/* 13 */
+FF (d, a, b, c, x[13], S12); 			/* 14 */
+FF (c, d, a, b, x[14], S13); 			/* 15 */
+FF (b, c, d, a, x[15], S14); 			/* 16 */
+
+/* Round 2 */
+GG (a, b, c, d, x[ 0], S21); 			/* 17 */
+GG (d, a, b, c, x[ 4], S22); 			/* 18 */
+GG (c, d, a, b, x[ 8], S23); 			/* 19 */
+GG (b, c, d, a, x[12], S24); 			/* 20 */
+GG (a, b, c, d, x[ 1], S21); 			/* 21 */
+GG (d, a, b, c, x[ 5], S22); 			/* 22 */
+GG (c, d, a, b, x[ 9], S23); 			/* 23 */
+GG (b, c, d, a, x[13], S24); 			/* 24 */
+GG (a, b, c, d, x[ 2], S21); 			/* 25 */
+GG (d, a, b, c, x[ 6], S22); 			/* 26 */
+GG (c, d, a, b, x[10], S23); 			/* 27 */
+GG (b, c, d, a, x[14], S24); 			/* 28 */
+GG (a, b, c, d, x[ 3], S21); 			/* 29 */
+GG (d, a, b, c, x[ 7], S22); 			/* 30 */
+GG (c, d, a, b, x[11], S23); 			/* 31 */
+GG (b, c, d, a, x[15], S24); 			/* 32 */
+
+/* Round 3 */
+HH (a, b, c, d, x[ 0], S31);				/* 33 */
+HH (d, a, b, c, x[ 8], S32); 			/* 34 */
+HH (c, d, a, b, x[ 4], S33); 			/* 35 */
+HH (b, c, d, a, x[12], S34); 			/* 36 */
+HH (a, b, c, d, x[ 2], S31); 			/* 37 */
+HH (d, a, b, c, x[10], S32); 			/* 38 */
+HH (c, d, a, b, x[ 6], S33); 			/* 39 */
+HH (b, c, d, a, x[14], S34); 			/* 40 */
+HH (a, b, c, d, x[ 1], S31); 			/* 41 */
+HH (d, a, b, c, x[ 9], S32); 			/* 42 */
+HH (c, d, a, b, x[ 5], S33); 			/* 43 */
+HH (b, c, d, a, x[13], S34); 			/* 44 */
+HH (a, b, c, d, x[ 3], S31); 			/* 45 */
+HH (d, a, b, c, x[11], S32); 			/* 46 */
+HH (c, d, a, b, x[ 7], S33); 			/* 47 */
+HH (b, c, d, a, x[15], S34);			/* 48 */
+
+state[0] += a;
+state[1] += b;
+state[2] += c;
+state[3] += d;
+
+	/* Zeroize sensitive information.*/
+	memset ((POINTER)x, 0, sizeof (x));
+}
+
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */
+static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
+{
+	unsigned int i, j;
+
+	for (i = 0, j = 0; j < len; i++, j += 4) {
+ 		output[j] = (unsigned char)(input[i] & 0xff);
+ 		output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ 		output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ 		output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+	}
+}
+
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */
+static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
+{
+unsigned int i, j;
+
+for (i = 0, j = 0; j < len; i++, j += 4)
+ 	output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+//===================================================================
+
+unsigned Com_BlockChecksum (void *buffer, int length)
+{
+	int			digest[4];
+	unsigned	val;
+	MD4_CTX		ctx;
+
+	MD4Init (&ctx);
+	MD4Update (&ctx, (unsigned char *)buffer, length);
+	MD4Final ( (unsigned char *)digest, &ctx);
+	
+	val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
+
+	return val;
+}
--- /dev/null
+++ b/menu.c
@@ -1,0 +1,3998 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "dat.h"
+#include "fns.h"
+
+static int	m_main_cursor;
+
+#define NUM_CURSOR_FRAMES 15
+
+static char *menu_in_sound		= "misc/menu1.wav";
+static char *menu_move_sound	= "misc/menu2.wav";
+static char *menu_out_sound		= "misc/menu3.wav";
+
+void M_Menu_Main_f (void);
+	void M_Menu_Game_f (void);
+		void M_Menu_LoadGame_f (void);
+		void M_Menu_SaveGame_f (void);
+		void M_Menu_PlayerConfig_f (void);
+			void M_Menu_DownloadOptions_f (void);
+		void M_Menu_Credits_f( void );
+	void M_Menu_Multiplayer_f( void );
+		void M_Menu_JoinServer_f (void);
+			void M_Menu_AddressBook_f( void );
+		void M_Menu_StartServer_f (void);
+			void M_Menu_DMOptions_f (void);
+	void M_Menu_Video_f (void);
+	void M_Menu_Options_f (void);
+		void M_Menu_Keys_f (void);
+	void M_Menu_Quit_f (void);
+
+	void M_Menu_Credits( void );
+
+qboolean	m_entersound;		// play after drawing a frame, so caching
+								// won't disrupt the sound
+
+void	(*m_drawfunc) (void);
+char *(*m_keyfunc) (int key);
+
+//=============================================================================
+/* Support Routines */
+
+#define	MAX_MENU_DEPTH	8
+
+
+typedef struct
+{
+	void	(*draw) (void);
+	char *(*key) (int k);
+} menulayer_t;
+
+menulayer_t	m_layers[MAX_MENU_DEPTH];
+int		m_menudepth;
+
+static void M_Banner( char *name )
+{
+	int w, h;
+
+	re.DrawGetPicSize (&w, &h, name );
+	re.DrawPic( vid.width / 2 - w / 2, vid.height / 2 - 110, name );
+}
+
+void M_PushMenu ( void (*draw) (void), char *(*key) (int k) )
+{
+	int		i;
+
+	if (Cvar_VariableValue ("maxclients") == 1 
+		&& Com_ServerState ())
+		Cvar_Set ("paused", "1");
+
+	// if this menu is already present, drop back to that level
+	// to avoid stacking menus by hotkeys
+	for (i=0 ; i<m_menudepth ; i++)
+		if (m_layers[i].draw == draw &&
+			m_layers[i].key == key)
+		{
+			m_menudepth = i;
+		}
+
+	if (i == m_menudepth)
+	{
+		if (m_menudepth >= MAX_MENU_DEPTH)
+			Com_Error (ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH");
+		m_layers[m_menudepth].draw = m_drawfunc;
+		m_layers[m_menudepth].key = m_keyfunc;
+		m_menudepth++;
+	}
+
+	m_drawfunc = draw;
+	m_keyfunc = key;
+
+	m_entersound = true;
+
+	cls.key_dest = key_menu;
+}
+
+void M_ForceMenuOff (void)
+{
+	m_drawfunc = 0;
+	m_keyfunc = 0;
+	cls.key_dest = key_game;
+	m_menudepth = 0;
+	Key_ClearStates ();
+	Cvar_Set ("paused", "0");
+	IN_Grabm (1);
+}
+
+void M_PopMenu (void)
+{
+	S_StartLocalSound( menu_out_sound );
+	if (m_menudepth < 1)
+		Com_Error (ERR_FATAL, "M_PopMenu: depth < 1");
+	m_menudepth--;
+
+	m_drawfunc = m_layers[m_menudepth].draw;
+	m_keyfunc = m_layers[m_menudepth].key;
+
+	if (!m_menudepth)
+		M_ForceMenuOff ();
+}
+
+
+char *Default_MenuKey( menuframework_t *m, int key )
+{
+	char *sound = nil;
+	menucommon_t *item;
+
+	if ( m )
+	{
+		if ( ( item = Menu_ItemAtCursor( m ) ) != 0 )
+		{
+			if ( item->type == MTYPE_FIELD )
+			{
+				if ( Field_Key( ( menufield_t * ) item, key ) )
+					return NULL;
+			}
+		}
+	}
+
+	switch ( key )
+	{
+	case K_ESCAPE:
+		M_PopMenu();
+		return menu_out_sound;
+	case K_KP_UPARROW:
+	case K_UPARROW:
+		if ( m )
+		{
+			m->cursor--;
+			Menu_AdjustCursor( m, -1 );
+			sound = menu_move_sound;
+		}
+		break;
+	case K_TAB:
+		if ( m )
+		{
+			m->cursor++;
+			Menu_AdjustCursor( m, 1 );
+			sound = menu_move_sound;
+		}
+		break;
+	case K_KP_DOWNARROW:
+	case K_DOWNARROW:
+		if ( m )
+		{
+			m->cursor++;
+			Menu_AdjustCursor( m, 1 );
+			sound = menu_move_sound;
+		}
+		break;
+	case K_KP_LEFTARROW:
+	case K_LEFTARROW:
+		if ( m )
+		{
+			Menu_SlideItem( m, -1 );
+			sound = menu_move_sound;
+		}
+		break;
+	case K_KP_RIGHTARROW:
+	case K_RIGHTARROW:
+		if ( m )
+		{
+			Menu_SlideItem( m, 1 );
+			sound = menu_move_sound;
+		}
+		break;
+
+	case K_MOUSE1:
+	case K_MOUSE2:
+	case K_MOUSE3:
+	case K_JOY1:
+	case K_JOY2:
+	case K_JOY3:
+	case K_JOY4:
+	case K_AUX1:
+	case K_AUX2:
+	case K_AUX3:
+	case K_AUX4:
+	case K_AUX5:
+	case K_AUX6:
+	case K_AUX7:
+	case K_AUX8:
+	case K_AUX9:
+	case K_AUX10:
+	case K_AUX11:
+	case K_AUX12:
+	case K_AUX13:
+	case K_AUX14:
+	case K_AUX15:
+	case K_AUX16:
+	case K_AUX17:
+	case K_AUX18:
+	case K_AUX19:
+	case K_AUX20:
+	case K_AUX21:
+	case K_AUX22:
+	case K_AUX23:
+	case K_AUX24:
+	case K_AUX25:
+	case K_AUX26:
+	case K_AUX27:
+	case K_AUX28:
+	case K_AUX29:
+	case K_AUX30:
+	case K_AUX31:
+	case K_AUX32:
+		
+	case K_KP_ENTER:
+	case K_ENTER:
+		if ( m )
+			Menu_SelectItem( m );
+		sound = menu_move_sound;
+		break;
+	}
+
+	return sound;
+}
+
+//=============================================================================
+
+/*
+================
+M_DrawCharacter
+
+Draws one solid graphics character
+cx and cy are in 320*240 coordinates, and will be centered on
+higher res screens.
+================
+*/
+void M_DrawCharacter (int cx, int cy, int num)
+{
+	re.DrawChar ( cx + ((vid.width - 320)>>1), cy + ((vid.height - 240)>>1), num);
+}
+
+void M_Print (int cx, int cy, char *str)
+{
+	while (*str)
+	{
+		M_DrawCharacter (cx, cy, (*str)+128);
+		str++;
+		cx += 8;
+	}
+}
+
+void M_PrintWhite (int cx, int cy, char *str)
+{
+	while (*str)
+	{
+		M_DrawCharacter (cx, cy, *str);
+		str++;
+		cx += 8;
+	}
+}
+
+void M_DrawPic (int x, int y, char *pic)
+{
+	re.DrawPic (x + ((vid.width - 320)>>1), y + ((vid.height - 240)>>1), pic);
+}
+
+
+/*
+=============
+M_DrawCursor
+
+Draws an animating cursor with the point at
+x,y.  The pic will extend to the left of x,
+and both above and below y.
+=============
+*/
+void M_DrawCursor( int x, int y, int f )
+{
+	char	cursorname[80];
+	static qboolean cached;
+
+	if ( !cached )
+	{
+		int i;
+
+		for ( i = 0; i < NUM_CURSOR_FRAMES; i++ )
+		{
+			Com_sprintf( cursorname, sizeof( cursorname ), "m_cursor%d", i );
+
+			re.RegisterPic( cursorname );
+		}
+		cached = true;
+	}
+
+	Com_sprintf( cursorname, sizeof(cursorname), "m_cursor%d", f );
+	re.DrawPic( x, y, cursorname );
+}
+
+void M_DrawTextBox (int x, int y, int width, int lines)
+{
+	int		cx, cy;
+	int		n;
+
+	// draw left side
+	cx = x;
+	cy = y;
+	M_DrawCharacter (cx, cy, 1);
+	for (n = 0; n < lines; n++)
+	{
+		cy += 8;
+		M_DrawCharacter (cx, cy, 4);
+	}
+	M_DrawCharacter (cx, cy+8, 7);
+
+	// draw middle
+	cx += 8;
+	while (width > 0)
+	{
+		cy = y;
+		M_DrawCharacter (cx, cy, 2);
+		for (n = 0; n < lines; n++)
+		{
+			cy += 8;
+			M_DrawCharacter (cx, cy, 5);
+		}
+		M_DrawCharacter (cx, cy+8, 8);
+		width -= 1;
+		cx += 8;
+	}
+
+	// draw right side
+	cy = y;
+	M_DrawCharacter (cx, cy, 3);
+	for (n = 0; n < lines; n++)
+	{
+		cy += 8;
+		M_DrawCharacter (cx, cy, 6);
+	}
+	M_DrawCharacter (cx, cy+8, 9);
+}
+
+		
+/*
+=======================================================================
+
+MAIN MENU
+
+=======================================================================
+*/
+#define	MAIN_ITEMS	5
+
+
+void M_Main_Draw (void)
+{
+	int i;
+	int w, h;
+	int ystart;
+	int	xoffset;
+	int widest = -1;
+	int totalheight = 0;
+	char litname[80];
+	char *names[] =
+	{
+		"m_main_game",
+		"m_main_multiplayer",
+		"m_main_options",
+		"m_main_video",
+		"m_main_quit",
+		0
+	};
+
+	for ( i = 0; names[i] != 0; i++ )
+	{
+		re.DrawGetPicSize( &w, &h, names[i] );
+
+		if ( w > widest )
+			widest = w;
+		totalheight += ( h + 12 );
+	}
+
+	ystart = ( vid.height / 2 - 110 );
+	xoffset = ( vid.width - widest + 70 ) / 2;
+
+	for ( i = 0; names[i] != 0; i++ )
+	{
+		if ( i != m_main_cursor )
+			re.DrawPic( xoffset, ystart + i * 40 + 13, names[i] );
+	}
+	strcpy( litname, names[m_main_cursor] );
+	strcat( litname, "_sel" );
+	re.DrawPic( xoffset, ystart + m_main_cursor * 40 + 13, litname );
+
+	M_DrawCursor( xoffset - 25, ystart + m_main_cursor * 40 + 11, (int)(cls.realtime / 100)%NUM_CURSOR_FRAMES );
+
+	re.DrawGetPicSize( &w, &h, "m_main_plaque" );
+	re.DrawPic( xoffset - 30 - w, ystart, "m_main_plaque" );
+
+	re.DrawPic( xoffset - 30 - w, ystart + h + 5, "m_main_logo" );
+}
+
+
+char *M_Main_Key (int key)
+{
+	char *sound = menu_move_sound;
+
+	switch (key)
+	{
+	case K_ESCAPE:
+		M_PopMenu ();
+		break;
+
+	case K_KP_DOWNARROW:
+	case K_DOWNARROW:
+		if (++m_main_cursor >= MAIN_ITEMS)
+			m_main_cursor = 0;
+		return sound;
+
+	case K_KP_UPARROW:
+	case K_UPARROW:
+		if (--m_main_cursor < 0)
+			m_main_cursor = MAIN_ITEMS - 1;
+		return sound;
+
+	case K_KP_ENTER:
+	case K_ENTER:
+		m_entersound = true;
+
+		switch (m_main_cursor)
+		{
+		case 0:
+			M_Menu_Game_f ();
+			break;
+
+		case 1:
+			M_Menu_Multiplayer_f();
+			break;
+
+		case 2:
+			M_Menu_Options_f ();
+			break;
+
+		case 3:
+			M_Menu_Video_f ();
+			break;
+
+		case 4:
+			M_Menu_Quit_f ();
+			break;
+		}
+	}
+
+	return NULL;
+}
+
+
+void M_Menu_Main_f (void)
+{
+	IN_Grabm (0);
+	M_PushMenu (M_Main_Draw, M_Main_Key);
+}
+
+/*
+=======================================================================
+
+MULTIPLAYER MENU
+
+=======================================================================
+*/
+static menuframework_t	s_multiplayer_menu;
+static menuaction_t		s_join_network_server_action;
+static menuaction_t		s_start_network_server_action;
+static menuaction_t		s_player_setup_action;
+
+static void Multiplayer_MenuDraw (void)
+{
+	M_Banner( "m_banner_multiplayer" );
+
+	Menu_AdjustCursor( &s_multiplayer_menu, 1 );
+	Menu_Draw( &s_multiplayer_menu );
+}
+
+static void PlayerSetupFunc( void * )
+{
+	M_Menu_PlayerConfig_f();
+}
+
+static void JoinNetworkServerFunc( void * )
+{
+	M_Menu_JoinServer_f();
+}
+
+static void StartNetworkServerFunc( void * )
+{
+	M_Menu_StartServer_f ();
+}
+
+void Multiplayer_MenuInit( void )
+{
+	s_multiplayer_menu.x = vid.width * 0.50 - 64;
+	s_multiplayer_menu.nitems = 0;
+
+	s_join_network_server_action.generic.type	= MTYPE_ACTION;
+	s_join_network_server_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_join_network_server_action.generic.x		= 0;
+	s_join_network_server_action.generic.y		= 0;
+	s_join_network_server_action.generic.name	= " join network server";
+	s_join_network_server_action.generic.callback = JoinNetworkServerFunc;
+
+	s_start_network_server_action.generic.type	= MTYPE_ACTION;
+	s_start_network_server_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_start_network_server_action.generic.x		= 0;
+	s_start_network_server_action.generic.y		= 10;
+	s_start_network_server_action.generic.name	= " start network server";
+	s_start_network_server_action.generic.callback = StartNetworkServerFunc;
+
+	s_player_setup_action.generic.type	= MTYPE_ACTION;
+	s_player_setup_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_player_setup_action.generic.x		= 0;
+	s_player_setup_action.generic.y		= 20;
+	s_player_setup_action.generic.name	= " player setup";
+	s_player_setup_action.generic.callback = PlayerSetupFunc;
+
+	Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_join_network_server_action );
+	Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_start_network_server_action );
+	Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_player_setup_action );
+
+	Menu_SetStatusBar( &s_multiplayer_menu, NULL );
+
+	Menu_Center( &s_multiplayer_menu );
+}
+
+char *Multiplayer_MenuKey( int key )
+{
+	return Default_MenuKey( &s_multiplayer_menu, key );
+}
+
+void M_Menu_Multiplayer_f( void )
+{
+	Multiplayer_MenuInit();
+	M_PushMenu( Multiplayer_MenuDraw, Multiplayer_MenuKey );
+}
+
+/*
+=======================================================================
+
+KEYS MENU
+
+=======================================================================
+*/
+char *bindnames[][2] =
+{
+{"+attack", 		"attack"},
+{"weapnext", 		"next weapon"},
+{"+forward", 		"walk forward"},
+{"+back", 			"backpedal"},
+{"+left", 			"turn left"},
+{"+right", 			"turn right"},
+{"+speed", 			"run"},
+{"+moveleft", 		"step left"},
+{"+moveright", 		"step right"},
+{"+strafe", 		"sidestep"},
+{"+lookup", 		"look up"},
+{"+lookdown", 		"look down"},
+{"centerview", 		"center view"},
+{"+mlook", 			"mouse look"},
+{"+klook", 			"keyboard look"},
+{"+moveup",			"up / jump"},
+{"+movedown",		"down / crouch"},
+
+{"inven",			"inventory"},
+{"invuse",			"use item"},
+{"invdrop",			"drop item"},
+{"invprev",			"prev item"},
+{"invnext",			"next item"},
+
+{"cmd help", 		"help computer" }, 
+{ 0, 0 }
+};
+
+int				keys_cursor;
+static int		bind_grab;
+
+static menuframework_t	s_keys_menu;
+static menuaction_t		s_keys_attack_action;
+static menuaction_t		s_keys_change_weapon_action;
+static menuaction_t		s_keys_walk_forward_action;
+static menuaction_t		s_keys_backpedal_action;
+static menuaction_t		s_keys_turn_left_action;
+static menuaction_t		s_keys_turn_right_action;
+static menuaction_t		s_keys_run_action;
+static menuaction_t		s_keys_step_left_action;
+static menuaction_t		s_keys_step_right_action;
+static menuaction_t		s_keys_sidestep_action;
+static menuaction_t		s_keys_look_up_action;
+static menuaction_t		s_keys_look_down_action;
+static menuaction_t		s_keys_center_view_action;
+static menuaction_t		s_keys_mouse_look_action;
+static menuaction_t		s_keys_keyboard_look_action;
+static menuaction_t		s_keys_move_up_action;
+static menuaction_t		s_keys_move_down_action;
+static menuaction_t		s_keys_inventory_action;
+static menuaction_t		s_keys_inv_use_action;
+static menuaction_t		s_keys_inv_drop_action;
+static menuaction_t		s_keys_inv_prev_action;
+static menuaction_t		s_keys_inv_next_action;
+
+static menuaction_t		s_keys_help_computer_action;
+
+static void M_UnbindCommand (char *command)
+{
+	int		j;
+	int		l;
+	char	*b;
+
+	l = strlen(command);
+
+	for (j=0 ; j<256 ; j++)
+	{
+		b = keybindings[j];
+		if (!b)
+			continue;
+		if (!strncmp (b, command, l) )
+			Key_SetBinding (j, "");
+	}
+}
+
+static void M_FindKeysForCommand (char *command, int *twokeys)
+{
+	int		count;
+	int		j;
+	int		l;
+	char	*b;
+
+	twokeys[0] = twokeys[1] = -1;
+	l = strlen(command);
+	count = 0;
+
+	for (j=0 ; j<256 ; j++)
+	{
+		b = keybindings[j];
+		if (!b)
+			continue;
+		if (!strncmp (b, command, l) )
+		{
+			twokeys[count] = j;
+			count++;
+			if (count == 2)
+				break;
+		}
+	}
+}
+
+static void KeyCursorDrawFunc( menuframework_t *menu )
+{
+	if ( bind_grab )
+		re.DrawChar( menu->x, menu->y + menu->cursor * 9, '=' );
+	else
+		re.DrawChar( menu->x, menu->y + menu->cursor * 9, 12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ) );
+}
+
+static void DrawKeyBindingFunc( void *self )
+{
+	int keys[2];
+	menuaction_t *a = ( menuaction_t * ) self;
+
+	M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys);
+		
+	if (keys[0] == -1)
+	{
+		Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, "???" );
+	}
+	else
+	{
+		int x;
+		char *name;
+
+		name = Key_KeynumToString (keys[0]);
+
+		Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, name );
+
+		x = strlen(name) * 8;
+
+		if (keys[1] != -1)
+		{
+			Menu_DrawString( a->generic.x + a->generic.parent->x + 24 + x, a->generic.y + a->generic.parent->y, "or" );
+			Menu_DrawString( a->generic.x + a->generic.parent->x + 48 + x, a->generic.y + a->generic.parent->y, Key_KeynumToString (keys[1]) );
+		}
+	}
+}
+
+static void KeyBindingFunc( void *self )
+{
+	menuaction_t *a = ( menuaction_t * ) self;
+	int keys[2];
+
+	M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys );
+
+	if (keys[1] != -1)
+		M_UnbindCommand( bindnames[a->generic.localdata[0]][0]);
+
+	bind_grab = true;
+
+	Menu_SetStatusBar( &s_keys_menu, "press a key or button for this action" );
+}
+
+static void Keys_MenuInit( void )
+{
+	int y = 0;
+	int i = 0;
+
+	s_keys_menu.x = vid.width * 0.50;
+	s_keys_menu.nitems = 0;
+	s_keys_menu.cursordraw = KeyCursorDrawFunc;
+
+	s_keys_attack_action.generic.type	= MTYPE_ACTION;
+	s_keys_attack_action.generic.flags  = QMF_GRAYED;
+	s_keys_attack_action.generic.x		= 0;
+	s_keys_attack_action.generic.y		= y;
+	s_keys_attack_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_attack_action.generic.localdata[0] = i;
+	s_keys_attack_action.generic.name	= bindnames[s_keys_attack_action.generic.localdata[0]][1];
+
+	s_keys_change_weapon_action.generic.type	= MTYPE_ACTION;
+	s_keys_change_weapon_action.generic.flags  = QMF_GRAYED;
+	s_keys_change_weapon_action.generic.x		= 0;
+	s_keys_change_weapon_action.generic.y		= y += 9;
+	s_keys_change_weapon_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_change_weapon_action.generic.localdata[0] = ++i;
+	s_keys_change_weapon_action.generic.name	= bindnames[s_keys_change_weapon_action.generic.localdata[0]][1];
+
+	s_keys_walk_forward_action.generic.type	= MTYPE_ACTION;
+	s_keys_walk_forward_action.generic.flags  = QMF_GRAYED;
+	s_keys_walk_forward_action.generic.x		= 0;
+	s_keys_walk_forward_action.generic.y		= y += 9;
+	s_keys_walk_forward_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_walk_forward_action.generic.localdata[0] = ++i;
+	s_keys_walk_forward_action.generic.name	= bindnames[s_keys_walk_forward_action.generic.localdata[0]][1];
+
+	s_keys_backpedal_action.generic.type	= MTYPE_ACTION;
+	s_keys_backpedal_action.generic.flags  = QMF_GRAYED;
+	s_keys_backpedal_action.generic.x		= 0;
+	s_keys_backpedal_action.generic.y		= y += 9;
+	s_keys_backpedal_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_backpedal_action.generic.localdata[0] = ++i;
+	s_keys_backpedal_action.generic.name	= bindnames[s_keys_backpedal_action.generic.localdata[0]][1];
+
+	s_keys_turn_left_action.generic.type	= MTYPE_ACTION;
+	s_keys_turn_left_action.generic.flags  = QMF_GRAYED;
+	s_keys_turn_left_action.generic.x		= 0;
+	s_keys_turn_left_action.generic.y		= y += 9;
+	s_keys_turn_left_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_turn_left_action.generic.localdata[0] = ++i;
+	s_keys_turn_left_action.generic.name	= bindnames[s_keys_turn_left_action.generic.localdata[0]][1];
+
+	s_keys_turn_right_action.generic.type	= MTYPE_ACTION;
+	s_keys_turn_right_action.generic.flags  = QMF_GRAYED;
+	s_keys_turn_right_action.generic.x		= 0;
+	s_keys_turn_right_action.generic.y		= y += 9;
+	s_keys_turn_right_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_turn_right_action.generic.localdata[0] = ++i;
+	s_keys_turn_right_action.generic.name	= bindnames[s_keys_turn_right_action.generic.localdata[0]][1];
+
+	s_keys_run_action.generic.type	= MTYPE_ACTION;
+	s_keys_run_action.generic.flags  = QMF_GRAYED;
+	s_keys_run_action.generic.x		= 0;
+	s_keys_run_action.generic.y		= y += 9;
+	s_keys_run_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_run_action.generic.localdata[0] = ++i;
+	s_keys_run_action.generic.name	= bindnames[s_keys_run_action.generic.localdata[0]][1];
+
+	s_keys_step_left_action.generic.type	= MTYPE_ACTION;
+	s_keys_step_left_action.generic.flags  = QMF_GRAYED;
+	s_keys_step_left_action.generic.x		= 0;
+	s_keys_step_left_action.generic.y		= y += 9;
+	s_keys_step_left_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_step_left_action.generic.localdata[0] = ++i;
+	s_keys_step_left_action.generic.name	= bindnames[s_keys_step_left_action.generic.localdata[0]][1];
+
+	s_keys_step_right_action.generic.type	= MTYPE_ACTION;
+	s_keys_step_right_action.generic.flags  = QMF_GRAYED;
+	s_keys_step_right_action.generic.x		= 0;
+	s_keys_step_right_action.generic.y		= y += 9;
+	s_keys_step_right_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_step_right_action.generic.localdata[0] = ++i;
+	s_keys_step_right_action.generic.name	= bindnames[s_keys_step_right_action.generic.localdata[0]][1];
+
+	s_keys_sidestep_action.generic.type	= MTYPE_ACTION;
+	s_keys_sidestep_action.generic.flags  = QMF_GRAYED;
+	s_keys_sidestep_action.generic.x		= 0;
+	s_keys_sidestep_action.generic.y		= y += 9;
+	s_keys_sidestep_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_sidestep_action.generic.localdata[0] = ++i;
+	s_keys_sidestep_action.generic.name	= bindnames[s_keys_sidestep_action.generic.localdata[0]][1];
+
+	s_keys_look_up_action.generic.type	= MTYPE_ACTION;
+	s_keys_look_up_action.generic.flags  = QMF_GRAYED;
+	s_keys_look_up_action.generic.x		= 0;
+	s_keys_look_up_action.generic.y		= y += 9;
+	s_keys_look_up_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_look_up_action.generic.localdata[0] = ++i;
+	s_keys_look_up_action.generic.name	= bindnames[s_keys_look_up_action.generic.localdata[0]][1];
+
+	s_keys_look_down_action.generic.type	= MTYPE_ACTION;
+	s_keys_look_down_action.generic.flags  = QMF_GRAYED;
+	s_keys_look_down_action.generic.x		= 0;
+	s_keys_look_down_action.generic.y		= y += 9;
+	s_keys_look_down_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_look_down_action.generic.localdata[0] = ++i;
+	s_keys_look_down_action.generic.name	= bindnames[s_keys_look_down_action.generic.localdata[0]][1];
+
+	s_keys_center_view_action.generic.type	= MTYPE_ACTION;
+	s_keys_center_view_action.generic.flags  = QMF_GRAYED;
+	s_keys_center_view_action.generic.x		= 0;
+	s_keys_center_view_action.generic.y		= y += 9;
+	s_keys_center_view_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_center_view_action.generic.localdata[0] = ++i;
+	s_keys_center_view_action.generic.name	= bindnames[s_keys_center_view_action.generic.localdata[0]][1];
+
+	s_keys_mouse_look_action.generic.type	= MTYPE_ACTION;
+	s_keys_mouse_look_action.generic.flags  = QMF_GRAYED;
+	s_keys_mouse_look_action.generic.x		= 0;
+	s_keys_mouse_look_action.generic.y		= y += 9;
+	s_keys_mouse_look_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_mouse_look_action.generic.localdata[0] = ++i;
+	s_keys_mouse_look_action.generic.name	= bindnames[s_keys_mouse_look_action.generic.localdata[0]][1];
+
+	s_keys_keyboard_look_action.generic.type	= MTYPE_ACTION;
+	s_keys_keyboard_look_action.generic.flags  = QMF_GRAYED;
+	s_keys_keyboard_look_action.generic.x		= 0;
+	s_keys_keyboard_look_action.generic.y		= y += 9;
+	s_keys_keyboard_look_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_keyboard_look_action.generic.localdata[0] = ++i;
+	s_keys_keyboard_look_action.generic.name	= bindnames[s_keys_keyboard_look_action.generic.localdata[0]][1];
+
+	s_keys_move_up_action.generic.type	= MTYPE_ACTION;
+	s_keys_move_up_action.generic.flags  = QMF_GRAYED;
+	s_keys_move_up_action.generic.x		= 0;
+	s_keys_move_up_action.generic.y		= y += 9;
+	s_keys_move_up_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_move_up_action.generic.localdata[0] = ++i;
+	s_keys_move_up_action.generic.name	= bindnames[s_keys_move_up_action.generic.localdata[0]][1];
+
+	s_keys_move_down_action.generic.type	= MTYPE_ACTION;
+	s_keys_move_down_action.generic.flags  = QMF_GRAYED;
+	s_keys_move_down_action.generic.x		= 0;
+	s_keys_move_down_action.generic.y		= y += 9;
+	s_keys_move_down_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_move_down_action.generic.localdata[0] = ++i;
+	s_keys_move_down_action.generic.name	= bindnames[s_keys_move_down_action.generic.localdata[0]][1];
+
+	s_keys_inventory_action.generic.type	= MTYPE_ACTION;
+	s_keys_inventory_action.generic.flags  = QMF_GRAYED;
+	s_keys_inventory_action.generic.x		= 0;
+	s_keys_inventory_action.generic.y		= y += 9;
+	s_keys_inventory_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_inventory_action.generic.localdata[0] = ++i;
+	s_keys_inventory_action.generic.name	= bindnames[s_keys_inventory_action.generic.localdata[0]][1];
+
+	s_keys_inv_use_action.generic.type	= MTYPE_ACTION;
+	s_keys_inv_use_action.generic.flags  = QMF_GRAYED;
+	s_keys_inv_use_action.generic.x		= 0;
+	s_keys_inv_use_action.generic.y		= y += 9;
+	s_keys_inv_use_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_inv_use_action.generic.localdata[0] = ++i;
+	s_keys_inv_use_action.generic.name	= bindnames[s_keys_inv_use_action.generic.localdata[0]][1];
+
+	s_keys_inv_drop_action.generic.type	= MTYPE_ACTION;
+	s_keys_inv_drop_action.generic.flags  = QMF_GRAYED;
+	s_keys_inv_drop_action.generic.x		= 0;
+	s_keys_inv_drop_action.generic.y		= y += 9;
+	s_keys_inv_drop_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_inv_drop_action.generic.localdata[0] = ++i;
+	s_keys_inv_drop_action.generic.name	= bindnames[s_keys_inv_drop_action.generic.localdata[0]][1];
+
+	s_keys_inv_prev_action.generic.type	= MTYPE_ACTION;
+	s_keys_inv_prev_action.generic.flags  = QMF_GRAYED;
+	s_keys_inv_prev_action.generic.x		= 0;
+	s_keys_inv_prev_action.generic.y		= y += 9;
+	s_keys_inv_prev_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_inv_prev_action.generic.localdata[0] = ++i;
+	s_keys_inv_prev_action.generic.name	= bindnames[s_keys_inv_prev_action.generic.localdata[0]][1];
+
+	s_keys_inv_next_action.generic.type	= MTYPE_ACTION;
+	s_keys_inv_next_action.generic.flags  = QMF_GRAYED;
+	s_keys_inv_next_action.generic.x		= 0;
+	s_keys_inv_next_action.generic.y		= y += 9;
+	s_keys_inv_next_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_inv_next_action.generic.localdata[0] = ++i;
+	s_keys_inv_next_action.generic.name	= bindnames[s_keys_inv_next_action.generic.localdata[0]][1];
+
+	s_keys_help_computer_action.generic.type	= MTYPE_ACTION;
+	s_keys_help_computer_action.generic.flags  = QMF_GRAYED;
+	s_keys_help_computer_action.generic.x		= 0;
+	s_keys_help_computer_action.generic.y		= y += 9;
+	s_keys_help_computer_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_help_computer_action.generic.localdata[0] = ++i;
+	s_keys_help_computer_action.generic.name	= bindnames[s_keys_help_computer_action.generic.localdata[0]][1];
+
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_attack_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_change_weapon_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_walk_forward_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_backpedal_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_left_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_right_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_run_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_left_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_right_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_sidestep_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_up_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_down_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_center_view_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_mouse_look_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_keyboard_look_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_up_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_down_action );
+
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inventory_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_use_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_drop_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_prev_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_next_action );
+
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_help_computer_action );
+	
+	Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
+	Menu_Center( &s_keys_menu );
+}
+
+static void Keys_MenuDraw (void)
+{
+	Menu_AdjustCursor( &s_keys_menu, 1 );
+	Menu_Draw( &s_keys_menu );
+}
+
+static char *Keys_MenuKey( int key )
+{
+	menuaction_t *item = ( menuaction_t * ) Menu_ItemAtCursor( &s_keys_menu );
+
+	if ( bind_grab )
+	{	
+		if ( key != K_ESCAPE && key != '`' )
+		{
+			char cmd[1024];
+
+			Com_sprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item->generic.localdata[0]][0]);
+			Cbuf_InsertText (cmd);
+		}
+		
+		Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
+		bind_grab = false;
+		return menu_out_sound;
+	}
+
+	switch ( key )
+	{
+	case K_KP_ENTER:
+	case K_ENTER:
+		KeyBindingFunc( item );
+		return menu_in_sound;
+	case K_BACKSPACE:		// delete bindings
+	case K_DEL:				// delete bindings
+	case K_KP_DEL:
+		M_UnbindCommand( bindnames[item->generic.localdata[0]][0] );
+		return menu_out_sound;
+	default:
+		return Default_MenuKey( &s_keys_menu, key );
+	}
+}
+
+void M_Menu_Keys_f (void)
+{
+	Keys_MenuInit();
+	M_PushMenu( Keys_MenuDraw, Keys_MenuKey );
+}
+
+
+/*
+=======================================================================
+
+CONTROLS MENU
+
+=======================================================================
+*/
+static cvar_t *win_noalttab;
+
+static menuframework_t	s_options_menu;
+static menuaction_t		s_options_defaults_action;
+static menuaction_t		s_options_customize_options_action;
+static menuslider_t		s_options_sensitivity_slider;
+static menulist_t		s_options_freelook_box;
+static menulist_t		s_options_noalttab_box;
+static menulist_t		s_options_alwaysrun_box;
+static menulist_t		s_options_invertmouse_box;
+static menulist_t		s_options_lookspring_box;
+static menulist_t		s_options_lookstrafe_box;
+static menulist_t		s_options_crosshair_box;
+static menuslider_t		s_options_sfxvolume_slider;
+static menulist_t		s_options_joystick_box;
+static menulist_t		s_options_cdvolume_box;
+static menulist_t		s_options_quality_list;
+static menulist_t		s_options_compatibility_list;
+static menulist_t		s_options_console_action;
+
+static void CrosshairFunc( void * )
+{
+	Cvar_SetValue( "crosshair", s_options_crosshair_box.curvalue );
+}
+
+static void JoystickFunc( void * )
+{
+	Cvar_SetValue( "in_joystick", s_options_joystick_box.curvalue );
+}
+
+static void CustomizeControlsFunc( void * )
+{
+	M_Menu_Keys_f();
+}
+
+static void AlwaysRunFunc( void * )
+{
+	Cvar_SetValue( "cl_run", s_options_alwaysrun_box.curvalue );
+}
+
+static void FreeLookFunc( void * )
+{
+	Cvar_SetValue( "freelook", s_options_freelook_box.curvalue );
+}
+
+static void MouseSpeedFunc( void * )
+{
+	Cvar_SetValue( "sensitivity", s_options_sensitivity_slider.curvalue / 2.0F );
+}
+
+static void NoAltTabFunc( void * )
+{
+	Cvar_SetValue( "win_noalttab", s_options_noalttab_box.curvalue );
+}
+
+static float ClampCvar( float min, float max, float value )
+{
+	if ( value < min ) return min;
+	if ( value > max ) return max;
+	return value;
+}
+
+static void ControlsSetMenuItemValues( void )
+{
+	s_options_sfxvolume_slider.curvalue		= Cvar_VariableValue( "s_volume" ) * 10;
+	s_options_cdvolume_box.curvalue 		= !Cvar_VariableValue("cd_nocd");
+	s_options_quality_list.curvalue			= !Cvar_VariableValue( "s_loadas8bit" );
+	s_options_sensitivity_slider.curvalue	= ( sensitivity->value ) * 2;
+
+	Cvar_SetValue( "cl_run", ClampCvar( 0, 1, cl_run->value ) );
+	s_options_alwaysrun_box.curvalue		= cl_run->value;
+
+	s_options_invertmouse_box.curvalue		= m_pitch->value < 0;
+
+	Cvar_SetValue( "lookspring", ClampCvar( 0, 1, lookspring->value ) );
+	s_options_lookspring_box.curvalue		= lookspring->value;
+
+	Cvar_SetValue( "lookstrafe", ClampCvar( 0, 1, lookstrafe->value ) );
+	s_options_lookstrafe_box.curvalue		= lookstrafe->value;
+
+	Cvar_SetValue( "freelook", ClampCvar( 0, 1, freelook->value ) );
+	s_options_freelook_box.curvalue			= freelook->value;
+
+	Cvar_SetValue( "crosshair", ClampCvar( 0, 3, crosshair->value ) );
+	s_options_crosshair_box.curvalue		= crosshair->value;
+
+	Cvar_SetValue( "in_joystick", ClampCvar( 0, 1, in_joystick->value ) );
+	s_options_joystick_box.curvalue		= in_joystick->value;
+
+	s_options_noalttab_box.curvalue			= win_noalttab->value;
+}
+
+static void ControlsResetDefaultsFunc( void * )
+{
+	Cbuf_AddText ("exec default.cfg\n");
+	Cbuf_Execute();
+
+	ControlsSetMenuItemValues();
+}
+
+static void InvertMouseFunc( void * )
+{
+	if ( s_options_invertmouse_box.curvalue == 0 )
+	{
+		Cvar_SetValue( "m_pitch", fabs( m_pitch->value ) );
+	}
+	else
+	{
+		Cvar_SetValue( "m_pitch", -fabs( m_pitch->value ) );
+	}
+}
+
+static void LookspringFunc( void * )
+{
+	Cvar_SetValue( "lookspring", s_options_lookspring_box.curvalue );
+}
+
+static void LookstrafeFunc( void * )
+{
+	Cvar_SetValue( "lookstrafe", s_options_lookstrafe_box.curvalue );
+}
+
+static void UpdateVolumeFunc( void * )
+{
+	Cvar_SetValue( "s_volume", s_options_sfxvolume_slider.curvalue / 10 );
+}
+
+static void UpdateCDVolumeFunc( void * )
+{
+	Cvar_SetValue( "cd_nocd", !s_options_cdvolume_box.curvalue );
+}
+
+static void ConsoleFunc( void * )
+{
+	/*
+	** the proper way to do this is probably to have ToggleConsole_f accept a parameter
+	*/
+	extern void Key_ClearTyping( void );
+
+	if ( cl.attractloop )
+	{
+		Cbuf_AddText ("killserver\n");
+		return;
+	}
+
+	Key_ClearTyping ();
+	Con_ClearNotify ();
+
+	M_ForceMenuOff ();
+	cls.key_dest = key_console;
+}
+
+static void UpdateSoundQualityFunc( void * )
+{
+	if ( s_options_quality_list.curvalue )
+	{
+		Cvar_SetValue( "s_khz", 22 );
+		Cvar_SetValue( "s_loadas8bit", false );
+	}
+	else
+	{
+		Cvar_SetValue( "s_khz", 11 );
+		Cvar_SetValue( "s_loadas8bit", true );
+	}
+	
+	Cvar_SetValue( "s_primary", s_options_compatibility_list.curvalue );
+
+	M_DrawTextBox( 8, 120 - 48, 36, 3 );
+	M_Print( 16 + 16, 120 - 48 + 8,  "Restarting the sound system. This" );
+	M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
+	M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
+
+	// the text box won't show up unless we do a buffer swap
+	re.EndFrame();
+
+	CL_Snd_Restart_f();
+}
+
+void Options_MenuInit( void )
+{
+	static char *cd_music_items[] =
+	{
+		"disabled",
+		"enabled",
+		0
+	};
+	static char *quality_items[] =
+	{
+		"low", "high", 0
+	};
+
+	static char *compatibility_items[] =
+	{
+		"max compatibility", "max performance", 0
+	};
+
+	static char *yesno_names[] =
+	{
+		"no",
+		"yes",
+		0
+	};
+
+	static char *crosshair_names[] =
+	{
+		"none",
+		"cross",
+		"dot",
+		"angle",
+		0
+	};
+
+	win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
+
+	/*
+	** configure controls menu and menu items
+	*/
+	s_options_menu.x = vid.width / 2;
+	s_options_menu.y = vid.height / 2 - 58;
+	s_options_menu.nitems = 0;
+
+	s_options_sfxvolume_slider.generic.type	= MTYPE_SLIDER;
+	s_options_sfxvolume_slider.generic.x	= 0;
+	s_options_sfxvolume_slider.generic.y	= 0;
+	s_options_sfxvolume_slider.generic.name	= "effects volume";
+	s_options_sfxvolume_slider.generic.callback	= UpdateVolumeFunc;
+	s_options_sfxvolume_slider.minvalue		= 0;
+	s_options_sfxvolume_slider.maxvalue		= 10;
+	s_options_sfxvolume_slider.curvalue		= Cvar_VariableValue( "s_volume" ) * 10;
+
+	s_options_cdvolume_box.generic.type	= MTYPE_SPINCONTROL;
+	s_options_cdvolume_box.generic.x		= 0;
+	s_options_cdvolume_box.generic.y		= 10;
+	s_options_cdvolume_box.generic.name	= "CD music";
+	s_options_cdvolume_box.generic.callback	= UpdateCDVolumeFunc;
+	s_options_cdvolume_box.itemnames		= cd_music_items;
+	s_options_cdvolume_box.curvalue 		= !Cvar_VariableValue("cd_nocd");
+
+	s_options_quality_list.generic.type	= MTYPE_SPINCONTROL;
+	s_options_quality_list.generic.x		= 0;
+	s_options_quality_list.generic.y		= 20;;
+	s_options_quality_list.generic.name		= "sound quality";
+	s_options_quality_list.generic.callback = UpdateSoundQualityFunc;
+	s_options_quality_list.itemnames		= quality_items;
+	s_options_quality_list.curvalue			= !Cvar_VariableValue( "s_loadas8bit" );
+
+	s_options_compatibility_list.generic.type	= MTYPE_SPINCONTROL;
+	s_options_compatibility_list.generic.x		= 0;
+	s_options_compatibility_list.generic.y		= 30;
+	s_options_compatibility_list.generic.name	= "sound compatibility";
+	s_options_compatibility_list.generic.callback = UpdateSoundQualityFunc;
+	s_options_compatibility_list.itemnames		= compatibility_items;
+	s_options_compatibility_list.curvalue		= Cvar_VariableValue( "s_primary" );
+
+	s_options_sensitivity_slider.generic.type	= MTYPE_SLIDER;
+	s_options_sensitivity_slider.generic.x		= 0;
+	s_options_sensitivity_slider.generic.y		= 50;
+	s_options_sensitivity_slider.generic.name	= "mouse speed";
+	s_options_sensitivity_slider.generic.callback = MouseSpeedFunc;
+	s_options_sensitivity_slider.minvalue		= 2;
+	s_options_sensitivity_slider.maxvalue		= 22;
+
+	s_options_alwaysrun_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_alwaysrun_box.generic.x	= 0;
+	s_options_alwaysrun_box.generic.y	= 60;
+	s_options_alwaysrun_box.generic.name	= "always run";
+	s_options_alwaysrun_box.generic.callback = AlwaysRunFunc;
+	s_options_alwaysrun_box.itemnames = yesno_names;
+
+	s_options_invertmouse_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_invertmouse_box.generic.x	= 0;
+	s_options_invertmouse_box.generic.y	= 70;
+	s_options_invertmouse_box.generic.name	= "invert mouse";
+	s_options_invertmouse_box.generic.callback = InvertMouseFunc;
+	s_options_invertmouse_box.itemnames = yesno_names;
+
+	s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_lookspring_box.generic.x	= 0;
+	s_options_lookspring_box.generic.y	= 80;
+	s_options_lookspring_box.generic.name	= "lookspring";
+	s_options_lookspring_box.generic.callback = LookspringFunc;
+	s_options_lookspring_box.itemnames = yesno_names;
+
+	s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_lookstrafe_box.generic.x	= 0;
+	s_options_lookstrafe_box.generic.y	= 90;
+	s_options_lookstrafe_box.generic.name	= "lookstrafe";
+	s_options_lookstrafe_box.generic.callback = LookstrafeFunc;
+	s_options_lookstrafe_box.itemnames = yesno_names;
+
+	s_options_freelook_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_freelook_box.generic.x	= 0;
+	s_options_freelook_box.generic.y	= 100;
+	s_options_freelook_box.generic.name	= "free look";
+	s_options_freelook_box.generic.callback = FreeLookFunc;
+	s_options_freelook_box.itemnames = yesno_names;
+
+	s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_crosshair_box.generic.x	= 0;
+	s_options_crosshair_box.generic.y	= 110;
+	s_options_crosshair_box.generic.name	= "crosshair";
+	s_options_crosshair_box.generic.callback = CrosshairFunc;
+	s_options_crosshair_box.itemnames = crosshair_names;
+/*
+	s_options_noalttab_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_noalttab_box.generic.x	= 0;
+	s_options_noalttab_box.generic.y	= 110;
+	s_options_noalttab_box.generic.name	= "disable alt-tab";
+	s_options_noalttab_box.generic.callback = NoAltTabFunc;
+	s_options_noalttab_box.itemnames = yesno_names;
+*/
+	s_options_joystick_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_joystick_box.generic.x	= 0;
+	s_options_joystick_box.generic.y	= 120;
+	s_options_joystick_box.generic.name	= "use joystick";
+	s_options_joystick_box.generic.callback = JoystickFunc;
+	s_options_joystick_box.itemnames = yesno_names;
+
+	s_options_customize_options_action.generic.type	= MTYPE_ACTION;
+	s_options_customize_options_action.generic.x		= 0;
+	s_options_customize_options_action.generic.y		= 140;
+	s_options_customize_options_action.generic.name	= "customize controls";
+	s_options_customize_options_action.generic.callback = CustomizeControlsFunc;
+
+	s_options_defaults_action.generic.type	= MTYPE_ACTION;
+	s_options_defaults_action.generic.x		= 0;
+	s_options_defaults_action.generic.y		= 150;
+	s_options_defaults_action.generic.name	= "reset defaults";
+	s_options_defaults_action.generic.callback = ControlsResetDefaultsFunc;
+
+	s_options_console_action.generic.type	= MTYPE_ACTION;
+	s_options_console_action.generic.x		= 0;
+	s_options_console_action.generic.y		= 160;
+	s_options_console_action.generic.name	= "go to console";
+	s_options_console_action.generic.callback = ConsoleFunc;
+
+	ControlsSetMenuItemValues();
+
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_sfxvolume_slider );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_cdvolume_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_quality_list );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_compatibility_list );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_sensitivity_slider );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_alwaysrun_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_invertmouse_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookspring_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookstrafe_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_freelook_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_crosshair_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_joystick_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_customize_options_action );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_defaults_action );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_console_action );
+}
+
+void Options_MenuDraw (void)
+{
+	M_Banner( "m_banner_options" );
+	Menu_AdjustCursor( &s_options_menu, 1 );
+	Menu_Draw( &s_options_menu );
+}
+
+char *Options_MenuKey( int key )
+{
+	return Default_MenuKey( &s_options_menu, key );
+}
+
+void M_Menu_Options_f (void)
+{
+	Options_MenuInit();
+	M_PushMenu ( Options_MenuDraw, Options_MenuKey );
+}
+
+/*
+=======================================================================
+
+VIDEO MENU
+
+=======================================================================
+*/
+
+void M_Menu_Video_f (void)
+{
+	VID_MenuInit();
+	M_PushMenu( VID_MenuDraw, VID_MenuKey );
+}
+
+/*
+=============================================================================
+
+END GAME MENU
+
+=============================================================================
+*/
+static int credits_start_time;
+static char **credits;
+static char *creditsIndex[256];
+static char *creditsBuffer;
+static char *idcredits[] =
+{
+	"+QUAKE II BY ID SOFTWARE",
+	"",
+	"+PROGRAMMING",
+	"John Carmack",
+	"John Cash",
+	"Brian Hook",
+	"",
+	"+ART",
+	"Adrian Carmack",
+	"Kevin Cloud",
+	"Paul Steed",
+	"",
+	"+LEVEL DESIGN",
+	"Tim Willits",
+	"American McGee",
+	"Christian Antkow",
+	"Paul Jaquays",
+	"Brandon James",
+	"",
+	"+BIZ",
+	"Todd Hollenshead",
+	"Barrett (Bear) Alexander",
+	"Donna Jackson",
+	"",
+	"",
+	"+SPECIAL THANKS",
+	"Ben Donges for beta testing",
+	"",
+	"",
+	"",
+	"",
+	"",
+	"",
+	"+ADDITIONAL SUPPORT",
+	"",
+	"+LINUX PORT AND CTF",
+	"Dave \"Zoid\" Kirsch",
+	"",
+	"+CINEMATIC SEQUENCES",
+	"Ending Cinematic by Blur Studio - ",
+	"Venice, CA",
+	"",
+	"Environment models for Introduction",
+	"Cinematic by Karl Dolgener",
+	"",
+	"Assistance with environment design",
+	"by Cliff Iwai",
+	"",
+	"+SOUND EFFECTS AND MUSIC",
+	"Sound Design by Soundelux Media Labs.",
+	"Music Composed and Produced by",
+	"Soundelux Media Labs.  Special thanks",
+	"to Bill Brown, Tom Ozanich, Brian",
+	"Celano, Jeff Eisner, and The Soundelux",
+	"Players.",
+	"",
+	"\"Level Music\" by Sonic Mayhem",
+	"www.sonicmayhem.com",
+	"",
+	"\"Quake II Theme Song\"",
+	"(C) 1997 Rob Zombie. All Rights",
+	"Reserved.",
+	"",
+	"Track 10 (\"Climb\") by Jer Sypult",
+	"",
+	"Voice of computers by",
+	"Carly Staehlin-Taylor",
+	"",
+	"+THANKS TO ACTIVISION",
+	"+IN PARTICULAR:",
+	"",
+	"John Tam",
+	"Steve Rosenthal",
+	"Marty Stratton",
+	"Henk Hartong",
+	"",
+	"Quake II(tm) (C)1997 Id Software, Inc.",
+	"All Rights Reserved.  Distributed by",
+	"Activision, Inc. under license.",
+	"Quake II(tm), the Id Software name,",
+	"the \"Q II\"(tm) logo and id(tm)",
+	"logo are trademarks of Id Software,",
+	"Inc. Activision(R) is a registered",
+	"trademark of Activision, Inc. All",
+	"other trademarks and trade names are",
+	"properties of their respective owners.",
+	0
+};
+
+static char *xatcredits[] =
+{
+	"+QUAKE II MISSION PACK: THE RECKONING",
+	"+BY",
+	"+XATRIX ENTERTAINMENT, INC.",
+	"",
+	"+DESIGN AND DIRECTION",
+	"Drew Markham",
+	"",
+	"+PRODUCED BY",
+	"Greg Goodrich",
+	"",
+	"+PROGRAMMING",
+	"Rafael Paiz",
+	"",
+	"+LEVEL DESIGN / ADDITIONAL GAME DESIGN",
+	"Alex Mayberry",
+	"",
+	"+LEVEL DESIGN",
+	"Mal Blackwell",
+	"Dan Koppel",
+	"",
+	"+ART DIRECTION",
+	"Michael \"Maxx\" Kaufman",
+	"",
+	"+COMPUTER GRAPHICS SUPERVISOR AND",
+	"+CHARACTER ANIMATION DIRECTION",
+	"Barry Dempsey",
+	"",
+	"+SENIOR ANIMATOR AND MODELER",
+	"Jason Hoover",
+	"",
+	"+CHARACTER ANIMATION AND",
+	"+MOTION CAPTURE SPECIALIST",
+	"Amit Doron",
+	"",
+	"+ART",
+	"Claire Praderie-Markham",
+	"Viktor Antonov",
+	"Corky Lehmkuhl",
+	"",
+	"+INTRODUCTION ANIMATION",
+	"Dominique Drozdz",
+	"",
+	"+ADDITIONAL LEVEL DESIGN",
+	"Aaron Barber",
+	"Rhett Baldwin",
+	"",
+	"+3D CHARACTER ANIMATION TOOLS",
+	"Gerry Tyra, SA Technology",
+	"",
+	"+ADDITIONAL EDITOR TOOL PROGRAMMING",
+	"Robert Duffy",
+	"",
+	"+ADDITIONAL PROGRAMMING",
+	"Ryan Feltrin",
+	"",
+	"+PRODUCTION COORDINATOR",
+	"Victoria Sylvester",
+	"",
+	"+SOUND DESIGN",
+	"Gary Bradfield",
+	"",
+	"+MUSIC BY",
+	"Sonic Mayhem",
+	"",
+	"",
+	"",
+	"+SPECIAL THANKS",
+	"+TO",
+	"+OUR FRIENDS AT ID SOFTWARE",
+	"",
+	"John Carmack",
+	"John Cash",
+	"Brian Hook",
+	"Adrian Carmack",
+	"Kevin Cloud",
+	"Paul Steed",
+	"Tim Willits",
+	"Christian Antkow",
+	"Paul Jaquays",
+	"Brandon James",
+	"Todd Hollenshead",
+	"Barrett (Bear) Alexander",
+	"Dave \"Zoid\" Kirsch",
+	"Donna Jackson",
+	"",
+	"",
+	"",
+	"+THANKS TO ACTIVISION",
+	"+IN PARTICULAR:",
+	"",
+	"Marty Stratton",
+	"Henk \"The Original Ripper\" Hartong",
+	"Kevin Kraff",
+	"Jamey Gottlieb",
+	"Chris Hepburn",
+	"",
+	"+AND THE GAME TESTERS",
+	"",
+	"Tim Vanlaw",
+	"Doug Jacobs",
+	"Steven Rosenthal",
+	"David Baker",
+	"Chris Campbell",
+	"Aaron Casillas",
+	"Steve Elwell",
+	"Derek Johnstone",
+	"Igor Krinitskiy",
+	"Samantha Lee",
+	"Michael Spann",
+	"Chris Toft",
+	"Juan Valdes",
+	"",
+	"+THANKS TO INTERGRAPH COMPUTER SYTEMS",
+	"+IN PARTICULAR:",
+	"",
+	"Michael T. Nicolaou",
+	"",
+	"",
+	"Quake II Mission Pack: The Reckoning",
+	"(tm) (C)1998 Id Software, Inc. All",
+	"Rights Reserved. Developed by Xatrix",
+	"Entertainment, Inc. for Id Software,",
+	"Inc. Distributed by Activision Inc.",
+	"under license. Quake(R) is a",
+	"registered trademark of Id Software,",
+	"Inc. Quake II Mission Pack: The",
+	"Reckoning(tm), Quake II(tm), the Id",
+	"Software name, the \"Q II\"(tm) logo",
+	"and id(tm) logo are trademarks of Id",
+	"Software, Inc. Activision(R) is a",
+	"registered trademark of Activision,",
+	"Inc. Xatrix(R) is a registered",
+	"trademark of Xatrix Entertainment,",
+	"Inc. All other trademarks and trade",
+	"names are properties of their",
+	"respective owners.",
+	0
+};
+
+static char *roguecredits[] =
+{
+	"+QUAKE II MISSION PACK 2: GROUND ZERO",
+	"+BY",
+	"+ROGUE ENTERTAINMENT, INC.",
+	"",
+	"+PRODUCED BY",
+	"Jim Molinets",
+	"",
+	"+PROGRAMMING",
+	"Peter Mack",
+	"Patrick Magruder",
+	"",
+	"+LEVEL DESIGN",
+	"Jim Molinets",
+	"Cameron Lamprecht",
+	"Berenger Fish",
+	"Robert Selitto",
+	"Steve Tietze",
+	"Steve Thoms",
+	"",
+	"+ART DIRECTION",
+	"Rich Fleider",
+	"",
+	"+ART",
+	"Rich Fleider",
+	"Steve Maines",
+	"Won Choi",
+	"",
+	"+ANIMATION SEQUENCES",
+	"Creat Studios",
+	"Steve Maines",
+	"",
+	"+ADDITIONAL LEVEL DESIGN",
+	"Rich Fleider",
+	"Steve Maines",
+	"Peter Mack",
+	"",
+	"+SOUND",
+	"James Grunke",
+	"",
+	"+GROUND ZERO THEME",
+	"+AND",
+	"+MUSIC BY",
+	"Sonic Mayhem",
+	"",
+	"+VWEP MODELS",
+	"Brent \"Hentai\" Dill",
+	"",
+	"",
+	"",
+	"+SPECIAL THANKS",
+	"+TO",
+	"+OUR FRIENDS AT ID SOFTWARE",
+	"",
+	"John Carmack",
+	"John Cash",
+	"Brian Hook",
+	"Adrian Carmack",
+	"Kevin Cloud",
+	"Paul Steed",
+	"Tim Willits",
+	"Christian Antkow",
+	"Paul Jaquays",
+	"Brandon James",
+	"Todd Hollenshead",
+	"Barrett (Bear) Alexander",
+	"Katherine Anna Kang",
+	"Donna Jackson",
+	"Dave \"Zoid\" Kirsch",
+	"",
+	"",
+	"",
+	"+THANKS TO ACTIVISION",
+	"+IN PARTICULAR:",
+	"",
+	"Marty Stratton",
+	"Henk Hartong",
+	"Mitch Lasky",
+	"Steve Rosenthal",
+	"Steve Elwell",
+	"",
+	"+AND THE GAME TESTERS",
+	"",
+	"The Ranger Clan",
+	"Dave \"Zoid\" Kirsch",
+	"Nihilistic Software",
+	"Robert Duffy",
+	"",
+	"And Countless Others",
+	"",
+	"",
+	"",
+	"Quake II Mission Pack 2: Ground Zero",
+	"(tm) (C)1998 Id Software, Inc. All",
+	"Rights Reserved. Developed by Rogue",
+	"Entertainment, Inc. for Id Software,",
+	"Inc. Distributed by Activision Inc.",
+	"under license. Quake(R) is a",
+	"registered trademark of Id Software,",
+	"Inc. Quake II Mission Pack 2: Ground",
+	"Zero(tm), Quake II(tm), the Id",
+	"Software name, the \"Q II\"(tm) logo",
+	"and id(tm) logo are trademarks of Id",
+	"Software, Inc. Activision(R) is a",
+	"registered trademark of Activision,",
+	"Inc. Rogue(R) is a registered",
+	"trademark of Rogue Entertainment,",
+	"Inc. All other trademarks and trade",
+	"names are properties of their",
+	"respective owners.",
+	0
+};
+
+
+void M_Credits_MenuDraw( void )
+{
+	int i, y;
+
+	/*
+	** draw the credits
+	*/
+	for ( i = 0, y = vid.height - ( ( cls.realtime - credits_start_time ) / 40.0F ); credits[i] && y < vid.height; y += 10, i++ )
+	{
+		int j, stringoffset;
+		int bold;
+
+		if ( y <= -8 )
+			continue;
+
+		if ( credits[i][0] == '+' )
+		{
+			bold = true;
+			stringoffset = 1;
+		}
+		else
+		{
+			bold = false;
+			stringoffset = 0;
+		}
+
+		for ( j = 0; credits[i][j+stringoffset]; j++ )
+		{
+			int x;
+
+			x = ( vid.width - strlen( credits[i] ) * 8 - stringoffset * 8 ) / 2 + ( j + stringoffset ) * 8;
+
+			if ( bold )
+				re.DrawChar( x, y, credits[i][j+stringoffset] + 128 );
+			else
+				re.DrawChar( x, y, credits[i][j+stringoffset] );
+		}
+	}
+
+	if ( y < 0 )
+		credits_start_time = cls.realtime;
+}
+
+char *M_Credits_Key( int key )
+{
+	switch (key)
+	{
+	case K_ESCAPE:
+		if (creditsBuffer)
+			FS_FreeFile (creditsBuffer);
+		M_PopMenu ();
+		break;
+	}
+
+	return menu_out_sound;
+
+}
+
+extern int Developer_searchpath (int who);
+
+void M_Menu_Credits_f( void )
+{
+	int		n;
+	int		count;
+	char	*p;
+	int		isdeveloper;
+
+	creditsBuffer = NULL;
+	count = FS_LoadFile ("credits", &creditsBuffer);
+	if (count != -1)
+	{
+		p = creditsBuffer;
+		for (n = 0; n < 255; n++)
+		{
+			creditsIndex[n] = p;
+			while (*p != '\r' && *p != '\n')
+			{
+				p++;
+				if (--count == 0)
+					break;
+			}
+			if (*p == '\r')
+			{
+				*p++ = 0;
+				if (--count == 0)
+					break;
+			}
+			*p++ = 0;
+			if (--count == 0)
+				break;
+		}
+		creditsIndex[++n] = 0;
+		credits = creditsIndex;
+	}
+	else
+	{
+		isdeveloper = Developer_searchpath (1);
+		
+		if (isdeveloper == 1)			// xatrix
+			credits = xatcredits;
+		else if (isdeveloper == 2)		// ROGUE
+			credits = roguecredits;
+		else
+		{
+			credits = idcredits;	
+		}
+
+	}
+
+	credits_start_time = cls.realtime;
+	M_PushMenu( M_Credits_MenuDraw, M_Credits_Key);
+}
+
+/*
+=============================================================================
+
+GAME MENU
+
+=============================================================================
+*/
+
+static int		m_game_cursor;
+
+static menuframework_t	s_game_menu;
+static menuaction_t		s_easy_game_action;
+static menuaction_t		s_medium_game_action;
+static menuaction_t		s_hard_game_action;
+static menuaction_t		s_load_game_action;
+static menuaction_t		s_save_game_action;
+static menuaction_t		s_credits_action;
+static menuseparator_t	s_blankline;
+
+static void StartGame( void )
+{
+	// disable updates and start the cinematic going
+	cl.servercount = -1;
+	M_ForceMenuOff ();
+	Cvar_SetValue( "deathmatch", 0 );
+	Cvar_SetValue( "coop", 0 );
+
+	Cvar_SetValue( "gamerules", 0 );		//PGM
+
+	Cbuf_AddText ("loading ; killserver ; wait ; newgame\n");
+	cls.key_dest = key_game;
+}
+
+static void EasyGameFunc( void * )
+{
+	Cvar_ForceSet( "skill", "0" );
+	StartGame();
+}
+
+static void MediumGameFunc( void * )
+{
+	Cvar_ForceSet( "skill", "1" );
+	StartGame();
+}
+
+static void HardGameFunc( void * )
+{
+	Cvar_ForceSet( "skill", "2" );
+	StartGame();
+}
+
+static void LoadGameFunc( void * )
+{
+	M_Menu_LoadGame_f ();
+}
+
+static void SaveGameFunc( void * )
+{
+	M_Menu_SaveGame_f();
+}
+
+static void CreditsFunc( void * )
+{
+	M_Menu_Credits_f();
+}
+
+void Game_MenuInit( void )
+{
+	static char *difficulty_names[] =
+	{
+		"easy",
+		"medium",
+		"hard",
+		0
+	};
+
+	s_game_menu.x = vid.width * 0.50;
+	s_game_menu.nitems = 0;
+
+	s_easy_game_action.generic.type	= MTYPE_ACTION;
+	s_easy_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_easy_game_action.generic.x		= 0;
+	s_easy_game_action.generic.y		= 0;
+	s_easy_game_action.generic.name	= "easy";
+	s_easy_game_action.generic.callback = EasyGameFunc;
+
+	s_medium_game_action.generic.type	= MTYPE_ACTION;
+	s_medium_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_medium_game_action.generic.x		= 0;
+	s_medium_game_action.generic.y		= 10;
+	s_medium_game_action.generic.name	= "medium";
+	s_medium_game_action.generic.callback = MediumGameFunc;
+
+	s_hard_game_action.generic.type	= MTYPE_ACTION;
+	s_hard_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_hard_game_action.generic.x		= 0;
+	s_hard_game_action.generic.y		= 20;
+	s_hard_game_action.generic.name	= "hard";
+	s_hard_game_action.generic.callback = HardGameFunc;
+
+	s_blankline.generic.type = MTYPE_SEPARATOR;
+
+	s_load_game_action.generic.type	= MTYPE_ACTION;
+	s_load_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_load_game_action.generic.x		= 0;
+	s_load_game_action.generic.y		= 40;
+	s_load_game_action.generic.name	= "load game";
+	s_load_game_action.generic.callback = LoadGameFunc;
+
+	s_save_game_action.generic.type	= MTYPE_ACTION;
+	s_save_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_save_game_action.generic.x		= 0;
+	s_save_game_action.generic.y		= 50;
+	s_save_game_action.generic.name	= "save game";
+	s_save_game_action.generic.callback = SaveGameFunc;
+
+	s_credits_action.generic.type	= MTYPE_ACTION;
+	s_credits_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_credits_action.generic.x		= 0;
+	s_credits_action.generic.y		= 60;
+	s_credits_action.generic.name	= "credits";
+	s_credits_action.generic.callback = CreditsFunc;
+
+	Menu_AddItem( &s_game_menu, ( void * ) &s_easy_game_action );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_medium_game_action );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_hard_game_action );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_load_game_action );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_save_game_action );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_credits_action );
+
+	Menu_Center( &s_game_menu );
+}
+
+void Game_MenuDraw( void )
+{
+	M_Banner( "m_banner_game" );
+	Menu_AdjustCursor( &s_game_menu, 1 );
+	Menu_Draw( &s_game_menu );
+}
+
+char *Game_MenuKey( int key )
+{
+	return Default_MenuKey( &s_game_menu, key );
+}
+
+void M_Menu_Game_f (void)
+{
+	Game_MenuInit();
+	M_PushMenu( Game_MenuDraw, Game_MenuKey );
+	m_game_cursor = 1;
+}
+
+/*
+=============================================================================
+
+LOADGAME MENU
+
+=============================================================================
+*/
+
+#define	MAX_SAVEGAMES	15
+
+static menuframework_t	s_savegame_menu;
+
+static menuframework_t	s_loadgame_menu;
+static menuaction_t		s_loadgame_actions[MAX_SAVEGAMES];
+
+char		m_savestrings[MAX_SAVEGAMES][32];
+qboolean	m_savevalid[MAX_SAVEGAMES];
+
+void Create_Savestrings (void)
+{
+	int		i;
+	FILE	*f;
+	char	name[MAX_OSPATH];
+
+	for (i=0 ; i<MAX_SAVEGAMES ; i++)
+	{
+		Com_sprintf (name, sizeof(name), "%s/save/save%i/server.ssv", FS_Gamedir(), i);
+		f = fopen (name, "rb");
+		if (!f)
+		{
+			strcpy (m_savestrings[i], "<EMPTY>");
+			m_savevalid[i] = false;
+		}
+		else
+		{
+			FS_Read (m_savestrings[i], sizeof(m_savestrings[i]), f);
+			fclose (f);
+			m_savevalid[i] = true;
+		}
+	}
+}
+
+void LoadGameCallback( void *self )
+{
+	menuaction_t *a = ( menuaction_t * ) self;
+
+	if ( m_savevalid[ a->generic.localdata[0] ] )
+		Cbuf_AddText (va("load save%i\n",  a->generic.localdata[0] ) );
+	M_ForceMenuOff ();
+}
+
+void LoadGame_MenuInit( void )
+{
+	int i;
+
+	s_loadgame_menu.x = vid.width / 2 - 120;
+	s_loadgame_menu.y = vid.height / 2 - 58;
+	s_loadgame_menu.nitems = 0;
+
+	Create_Savestrings();
+
+	for ( i = 0; i < MAX_SAVEGAMES; i++ )
+	{
+		s_loadgame_actions[i].generic.name			= m_savestrings[i];
+		s_loadgame_actions[i].generic.flags			= QMF_LEFT_JUSTIFY;
+		s_loadgame_actions[i].generic.localdata[0]	= i;
+		s_loadgame_actions[i].generic.callback		= LoadGameCallback;
+
+		s_loadgame_actions[i].generic.x = 0;
+		s_loadgame_actions[i].generic.y = ( i ) * 10;
+		if (i>0)	// separate from autosave
+			s_loadgame_actions[i].generic.y += 10;
+
+		s_loadgame_actions[i].generic.type = MTYPE_ACTION;
+
+		Menu_AddItem( &s_loadgame_menu, &s_loadgame_actions[i] );
+	}
+}
+
+void LoadGame_MenuDraw( void )
+{
+	M_Banner( "m_banner_load_game" );
+//	Menu_AdjustCursor( &s_loadgame_menu, 1 );
+	Menu_Draw( &s_loadgame_menu );
+}
+
+char *LoadGame_MenuKey( int key )
+{
+	if ( key == K_ESCAPE || key == K_ENTER )
+	{
+		s_savegame_menu.cursor = s_loadgame_menu.cursor - 1;
+		if ( s_savegame_menu.cursor < 0 )
+			s_savegame_menu.cursor = 0;
+	}
+	return Default_MenuKey( &s_loadgame_menu, key );
+}
+
+void M_Menu_LoadGame_f (void)
+{
+	LoadGame_MenuInit();
+	M_PushMenu( LoadGame_MenuDraw, LoadGame_MenuKey );
+}
+
+
+/*
+=============================================================================
+
+SAVEGAME MENU
+
+=============================================================================
+*/
+static menuframework_t	s_savegame_menu;
+static menuaction_t		s_savegame_actions[MAX_SAVEGAMES];
+
+void SaveGameCallback( void *self )
+{
+	menuaction_t *a = ( menuaction_t * ) self;
+
+	Cbuf_AddText (va("save save%i\n", a->generic.localdata[0] ));
+	M_ForceMenuOff ();
+}
+
+void SaveGame_MenuDraw( void )
+{
+	M_Banner( "m_banner_save_game" );
+	Menu_AdjustCursor( &s_savegame_menu, 1 );
+	Menu_Draw( &s_savegame_menu );
+}
+
+void SaveGame_MenuInit( void )
+{
+	int i;
+
+	s_savegame_menu.x = vid.width / 2 - 120;
+	s_savegame_menu.y = vid.height / 2 - 58;
+	s_savegame_menu.nitems = 0;
+
+	Create_Savestrings();
+
+	// don't include the autosave slot
+	for ( i = 0; i < MAX_SAVEGAMES-1; i++ )
+	{
+		s_savegame_actions[i].generic.name = m_savestrings[i+1];
+		s_savegame_actions[i].generic.localdata[0] = i+1;
+		s_savegame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
+		s_savegame_actions[i].generic.callback = SaveGameCallback;
+
+		s_savegame_actions[i].generic.x = 0;
+		s_savegame_actions[i].generic.y = ( i ) * 10;
+
+		s_savegame_actions[i].generic.type = MTYPE_ACTION;
+
+		Menu_AddItem( &s_savegame_menu, &s_savegame_actions[i] );
+	}
+}
+
+char *SaveGame_MenuKey( int key )
+{
+	if ( key == K_ENTER || key == K_ESCAPE )
+	{
+		s_loadgame_menu.cursor = s_savegame_menu.cursor - 1;
+		if ( s_loadgame_menu.cursor < 0 )
+			s_loadgame_menu.cursor = 0;
+	}
+	return Default_MenuKey( &s_savegame_menu, key );
+}
+
+void M_Menu_SaveGame_f (void)
+{
+	if (!Com_ServerState())
+		return;		// not playing a game
+
+	SaveGame_MenuInit();
+	M_PushMenu( SaveGame_MenuDraw, SaveGame_MenuKey );
+	Create_Savestrings ();
+}
+
+
+/*
+=============================================================================
+
+JOIN SERVER MENU
+
+=============================================================================
+*/
+#define MAX_LOCAL_SERVERS 8
+
+static menuframework_t	s_joinserver_menu;
+static menuseparator_t	s_joinserver_server_title;
+static menuaction_t		s_joinserver_search_action;
+static menuaction_t		s_joinserver_address_book_action;
+static menuaction_t		s_joinserver_server_actions[MAX_LOCAL_SERVERS];
+
+int		m_num_servers;
+#define	NO_SERVER_STRING	"<no server>"
+
+// user readable information
+static char local_server_names[MAX_LOCAL_SERVERS][80];
+
+// network address
+static netadr_t local_server_netadr[MAX_LOCAL_SERVERS];
+
+void M_AddToServerList (netadr_t adr, char *info)
+{
+	int		i;
+
+	if (m_num_servers == MAX_LOCAL_SERVERS)
+		return;
+	while ( *info == ' ' )
+		info++;
+
+	// ignore if duplicated
+	for (i=0 ; i<m_num_servers ; i++)
+		if (!strcmp(info, local_server_names[i]))
+			return;
+
+	local_server_netadr[m_num_servers] = adr;
+	strncpy (local_server_names[m_num_servers], info, sizeof(local_server_names[0])-1);
+	m_num_servers++;
+}
+
+
+void JoinServerFunc( void *self )
+{
+	char	buffer[128];
+	int		index;
+
+	index = ( menuaction_t * ) self - s_joinserver_server_actions;
+
+	if ( cistrcmp( local_server_names[index], NO_SERVER_STRING ) == 0 )
+		return;
+
+	if (index >= m_num_servers)
+		return;
+
+	Com_sprintf (buffer, sizeof(buffer), "connect %s\n", NET_AdrToString (local_server_netadr[index]));
+	Cbuf_AddText (buffer);
+	M_ForceMenuOff ();
+}
+
+void AddressBookFunc( void * )
+{
+	M_Menu_AddressBook_f();
+}
+
+void NullCursorDraw( void * )
+{
+}
+
+void SearchLocalGames( void )
+{
+	int		i;
+
+	m_num_servers = 0;
+	for (i=0 ; i<MAX_LOCAL_SERVERS ; i++)
+		strcpy (local_server_names[i], NO_SERVER_STRING);
+
+	M_DrawTextBox( 8, 120 - 48, 36, 3 );
+	M_Print( 16 + 16, 120 - 48 + 8,  "Searching for local servers, this" );
+	M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
+	M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
+
+	// the text box won't show up unless we do a buffer swap
+	re.EndFrame();
+
+	// send out info packets
+	CL_PingServers_f();
+}
+
+void SearchLocalGamesFunc( void * )
+{
+	SearchLocalGames();
+}
+
+void JoinServer_MenuInit( void )
+{
+	int i;
+
+	s_joinserver_menu.x = vid.width * 0.50 - 120;
+	s_joinserver_menu.nitems = 0;
+
+	s_joinserver_address_book_action.generic.type	= MTYPE_ACTION;
+	s_joinserver_address_book_action.generic.name	= "address book";
+	s_joinserver_address_book_action.generic.flags	= QMF_LEFT_JUSTIFY;
+	s_joinserver_address_book_action.generic.x		= 0;
+	s_joinserver_address_book_action.generic.y		= 0;
+	s_joinserver_address_book_action.generic.callback = AddressBookFunc;
+
+	s_joinserver_search_action.generic.type = MTYPE_ACTION;
+	s_joinserver_search_action.generic.name	= "refresh server list";
+	s_joinserver_search_action.generic.flags	= QMF_LEFT_JUSTIFY;
+	s_joinserver_search_action.generic.x	= 0;
+	s_joinserver_search_action.generic.y	= 10;
+	s_joinserver_search_action.generic.callback = SearchLocalGamesFunc;
+	s_joinserver_search_action.generic.statusbar = "search for servers";
+
+	s_joinserver_server_title.generic.type = MTYPE_SEPARATOR;
+	s_joinserver_server_title.generic.name = "connect to...";
+	s_joinserver_server_title.generic.x    = 80;
+	s_joinserver_server_title.generic.y	   = 30;
+
+	for ( i = 0; i < MAX_LOCAL_SERVERS; i++ )
+	{
+		s_joinserver_server_actions[i].generic.type	= MTYPE_ACTION;
+		strcpy (local_server_names[i], NO_SERVER_STRING);
+		s_joinserver_server_actions[i].generic.name	= local_server_names[i];
+		s_joinserver_server_actions[i].generic.flags	= QMF_LEFT_JUSTIFY;
+		s_joinserver_server_actions[i].generic.x		= 0;
+		s_joinserver_server_actions[i].generic.y		= 40 + i*10;
+		s_joinserver_server_actions[i].generic.callback = JoinServerFunc;
+		s_joinserver_server_actions[i].generic.statusbar = "press ENTER to connect";
+	}
+
+	Menu_AddItem( &s_joinserver_menu, &s_joinserver_address_book_action );
+	Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_title );
+	Menu_AddItem( &s_joinserver_menu, &s_joinserver_search_action );
+
+	for ( i = 0; i < 8; i++ )
+		Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_actions[i] );
+
+	Menu_Center( &s_joinserver_menu );
+
+	SearchLocalGames();
+}
+
+void JoinServer_MenuDraw(void)
+{
+	M_Banner( "m_banner_join_server" );
+	Menu_Draw( &s_joinserver_menu );
+}
+
+
+char *JoinServer_MenuKey( int key )
+{
+	return Default_MenuKey( &s_joinserver_menu, key );
+}
+
+void M_Menu_JoinServer_f (void)
+{
+	JoinServer_MenuInit();
+	M_PushMenu( JoinServer_MenuDraw, JoinServer_MenuKey );
+}
+
+
+/*
+=============================================================================
+
+START SERVER MENU
+
+=============================================================================
+*/
+static menuframework_t s_startserver_menu;
+static char **mapnames;
+static int	  nummaps;
+
+static menuaction_t	s_startserver_start_action;
+static menuaction_t	s_startserver_dmoptions_action;
+static menufield_t	s_timelimit_field;
+static menufield_t	s_fraglimit_field;
+static menufield_t	s_maxclients_field;
+static menufield_t	s_hostname_field;
+static menulist_t	s_startmap_list;
+static menulist_t	s_rules_box;
+
+void DMOptionsFunc( void * )
+{
+	if (s_rules_box.curvalue == 1)
+		return;
+	M_Menu_DMOptions_f();
+}
+
+void RulesChangeFunc ( void * )
+{
+	// DM
+	if (s_rules_box.curvalue == 0)
+	{
+		s_maxclients_field.generic.statusbar = NULL;
+		s_startserver_dmoptions_action.generic.statusbar = NULL;
+	}
+	else if(s_rules_box.curvalue == 1)		// coop				// PGM
+	{
+		s_maxclients_field.generic.statusbar = "4 maximum for cooperative";
+		if (atoi(s_maxclients_field.buffer) > 4)
+			strcpy( s_maxclients_field.buffer, "4" );
+		s_startserver_dmoptions_action.generic.statusbar = "N/A for cooperative";
+	}
+//=====
+//PGM
+	// ROGUE GAMES
+	else if(Developer_searchpath(2) == 2)
+	{
+		if (s_rules_box.curvalue == 2)			// tag	
+		{
+			s_maxclients_field.generic.statusbar = NULL;
+			s_startserver_dmoptions_action.generic.statusbar = NULL;
+		}
+/*
+		else if(s_rules_box.curvalue == 3)		// deathball
+		{
+			s_maxclients_field.generic.statusbar = NULL;
+			s_startserver_dmoptions_action.generic.statusbar = NULL;
+		}
+*/
+	}
+//PGM
+//=====
+}
+
+void StartServerActionFunc( void * )
+{
+	char	startmap[1024];
+	int		timelimit;
+	int		fraglimit;
+	int		maxclients;
+	char	*spot;
+
+	strcpy( startmap, strchr( mapnames[s_startmap_list.curvalue], '\n' ) + 1 );
+
+	maxclients  = atoi( s_maxclients_field.buffer );
+	timelimit	= atoi( s_timelimit_field.buffer );
+	fraglimit	= atoi( s_fraglimit_field.buffer );
+
+	Cvar_SetValue( "maxclients", ClampCvar( 0, maxclients, maxclients ) );
+	Cvar_SetValue ("timelimit", ClampCvar( 0, timelimit, timelimit ) );
+	Cvar_SetValue ("fraglimit", ClampCvar( 0, fraglimit, fraglimit ) );
+	Cvar_Set("hostname", s_hostname_field.buffer );
+//	Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
+//	Cvar_SetValue ("coop", s_rules_box.curvalue );
+
+//PGM
+	if((s_rules_box.curvalue < 2) || (Developer_searchpath(2) != 2))
+	{
+		Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
+		Cvar_SetValue ("coop", s_rules_box.curvalue );
+		Cvar_SetValue ("gamerules", 0 );
+	}
+	else
+	{
+		Cvar_SetValue ("deathmatch", 1 );	// deathmatch is always true for rogue games, right?
+		Cvar_SetValue ("coop", 0 );			// FIXME - this might need to depend on which game we're running
+		Cvar_SetValue ("gamerules", s_rules_box.curvalue );
+	}
+//PGM
+
+	spot = NULL;
+	if (s_rules_box.curvalue == 1)		// PGM
+	{
+ 		if(cistrcmp(startmap, "bunk1") == 0)
+  			spot = "start";
+ 		else if(cistrcmp(startmap, "mintro") == 0)
+  			spot = "start";
+ 		else if(cistrcmp(startmap, "fact1") == 0)
+  			spot = "start";
+ 		else if(cistrcmp(startmap, "power1") == 0)
+  			spot = "pstart";
+ 		else if(cistrcmp(startmap, "biggun") == 0)
+  			spot = "bstart";
+ 		else if(cistrcmp(startmap, "hangar1") == 0)
+  			spot = "unitstart";
+ 		else if(cistrcmp(startmap, "city1") == 0)
+  			spot = "unitstart";
+ 		else if(cistrcmp(startmap, "boss1") == 0)
+			spot = "bosstart";
+	}
+
+	if (spot)
+	{
+		if (Com_ServerState())
+			Cbuf_AddText ("disconnect\n");
+		Cbuf_AddText (va("gamemap \"*%s$%s\"\n", startmap, spot));
+	}
+	else
+	{
+		Cbuf_AddText (va("map %s\n", startmap));
+	}
+
+	M_ForceMenuOff ();
+}
+
+void StartServer_MenuInit( void )
+{
+	static char *dm_coop_names[] =
+	{
+		"deathmatch",
+		"cooperative",
+		0
+	};
+//=======
+//PGM
+	static char *dm_coop_names_rogue[] =
+	{
+		"deathmatch",
+		"cooperative",
+		"tag",
+//		"deathball",
+		0
+	};
+//PGM
+//=======
+	char *buffer;
+	char  mapsname[1024];
+	char *s;
+	int length;
+	int i;
+	FILE *fp;
+
+	/*
+	** load the list of map names
+	*/
+	Com_sprintf( mapsname, sizeof( mapsname ), "%s/maps.lst", FS_Gamedir() );
+	if ( ( fp = fopen( mapsname, "rb" ) ) == 0 )
+	{
+		if ( ( length = FS_LoadFile( "maps.lst", ( void ** ) &buffer ) ) == -1 )
+			Com_Error( ERR_DROP, "couldn't find maps.lst\n" );
+	}
+	else
+	{
+#ifdef _WIN32
+		length = filelength( fileno( fp  ) );
+#else
+		fseek(fp, 0, SEEK_END);
+		length = ftell(fp);
+		fseek(fp, 0, SEEK_SET);
+#endif
+		buffer = malloc( length );
+		fread( buffer, length, 1, fp );
+	}
+
+	s = buffer;
+
+	i = 0;
+	while ( i < length )
+	{
+		if ( s[i] == '\r' )
+			nummaps++;
+		i++;
+	}
+
+	if ( nummaps == 0 )
+		Com_Error( ERR_DROP, "no maps in maps.lst\n" );
+
+	mapnames = malloc( sizeof( char * ) * ( nummaps + 1 ) );
+	memset( mapnames, 0, sizeof( char * ) * ( nummaps + 1 ) );
+
+	s = buffer;
+
+	for ( i = 0; i < nummaps; i++ )
+	{
+    char  shortname[MAX_TOKEN_CHARS];
+    char  longname[MAX_TOKEN_CHARS];
+		char  scratch[200];
+		int		j, l;
+
+		strcpy( shortname, COM_Parse( &s ) );
+		l = strlen(shortname);
+		for (j=0 ; j<l ; j++)
+			shortname[j] = toupper(shortname[j]);
+		strcpy( longname, COM_Parse( &s ) );
+		Com_sprintf( scratch, sizeof( scratch ), "%s\n%s", longname, shortname );
+
+		mapnames[i] = malloc( strlen( scratch ) + 1 );
+		strcpy( mapnames[i], scratch );
+	}
+	mapnames[nummaps] = 0;
+
+	if ( fp != 0 )
+	{
+		free( buffer );
+	}
+	else
+	{
+		FS_FreeFile( buffer );
+	}
+
+	/*
+	** initialize the menu stuff
+	*/
+	s_startserver_menu.x = vid.width * 0.50;
+	s_startserver_menu.nitems = 0;
+
+	s_startmap_list.generic.type = MTYPE_SPINCONTROL;
+	s_startmap_list.generic.x	= 0;
+	s_startmap_list.generic.y	= 0;
+	s_startmap_list.generic.name	= "initial map";
+	s_startmap_list.itemnames = mapnames;
+
+	s_rules_box.generic.type = MTYPE_SPINCONTROL;
+	s_rules_box.generic.x	= 0;
+	s_rules_box.generic.y	= 20;
+	s_rules_box.generic.name	= "rules";
+	
+//PGM - rogue games only available with rogue DLL.
+	if(Developer_searchpath(2) == 2)
+		s_rules_box.itemnames = dm_coop_names_rogue;
+	else
+		s_rules_box.itemnames = dm_coop_names;
+//PGM
+
+	if (Cvar_VariableValue("coop"))
+		s_rules_box.curvalue = 1;
+	else
+		s_rules_box.curvalue = 0;
+	s_rules_box.generic.callback = RulesChangeFunc;
+
+	s_timelimit_field.generic.type = MTYPE_FIELD;
+	s_timelimit_field.generic.name = "time limit";
+	s_timelimit_field.generic.flags = QMF_NUMBERSONLY;
+	s_timelimit_field.generic.x	= 0;
+	s_timelimit_field.generic.y	= 36;
+	s_timelimit_field.generic.statusbar = "0 = no limit";
+	s_timelimit_field.length = 3;
+	s_timelimit_field.visible_length = 3;
+	strcpy( s_timelimit_field.buffer, Cvar_VariableString("timelimit") );
+
+	s_fraglimit_field.generic.type = MTYPE_FIELD;
+	s_fraglimit_field.generic.name = "frag limit";
+	s_fraglimit_field.generic.flags = QMF_NUMBERSONLY;
+	s_fraglimit_field.generic.x	= 0;
+	s_fraglimit_field.generic.y	= 54;
+	s_fraglimit_field.generic.statusbar = "0 = no limit";
+	s_fraglimit_field.length = 3;
+	s_fraglimit_field.visible_length = 3;
+	strcpy( s_fraglimit_field.buffer, Cvar_VariableString("fraglimit") );
+
+	/*
+	** maxclients determines the maximum number of players that can join
+	** the game.  If maxclients is only "1" then we should default the menu
+	** option to 8 players, otherwise use whatever its current value is. 
+	** Clamping will be done when the server is actually started.
+	*/
+	s_maxclients_field.generic.type = MTYPE_FIELD;
+	s_maxclients_field.generic.name = "max players";
+	s_maxclients_field.generic.flags = QMF_NUMBERSONLY;
+	s_maxclients_field.generic.x	= 0;
+	s_maxclients_field.generic.y	= 72;
+	s_maxclients_field.generic.statusbar = NULL;
+	s_maxclients_field.length = 3;
+	s_maxclients_field.visible_length = 3;
+	if ( Cvar_VariableValue( "maxclients" ) == 1 )
+		strcpy( s_maxclients_field.buffer, "8" );
+	else 
+		strcpy( s_maxclients_field.buffer, Cvar_VariableString("maxclients") );
+
+	s_hostname_field.generic.type = MTYPE_FIELD;
+	s_hostname_field.generic.name = "hostname";
+	s_hostname_field.generic.flags = 0;
+	s_hostname_field.generic.x	= 0;
+	s_hostname_field.generic.y	= 90;
+	s_hostname_field.generic.statusbar = NULL;
+	s_hostname_field.length = 12;
+	s_hostname_field.visible_length = 12;
+	strcpy( s_hostname_field.buffer, Cvar_VariableString("hostname") );
+
+	s_startserver_dmoptions_action.generic.type = MTYPE_ACTION;
+	s_startserver_dmoptions_action.generic.name	= " deathmatch flags";
+	s_startserver_dmoptions_action.generic.flags= QMF_LEFT_JUSTIFY;
+	s_startserver_dmoptions_action.generic.x	= 24;
+	s_startserver_dmoptions_action.generic.y	= 108;
+	s_startserver_dmoptions_action.generic.statusbar = NULL;
+	s_startserver_dmoptions_action.generic.callback = DMOptionsFunc;
+
+	s_startserver_start_action.generic.type = MTYPE_ACTION;
+	s_startserver_start_action.generic.name	= " begin";
+	s_startserver_start_action.generic.flags= QMF_LEFT_JUSTIFY;
+	s_startserver_start_action.generic.x	= 24;
+	s_startserver_start_action.generic.y	= 128;
+	s_startserver_start_action.generic.callback = StartServerActionFunc;
+
+	Menu_AddItem( &s_startserver_menu, &s_startmap_list );
+	Menu_AddItem( &s_startserver_menu, &s_rules_box );
+	Menu_AddItem( &s_startserver_menu, &s_timelimit_field );
+	Menu_AddItem( &s_startserver_menu, &s_fraglimit_field );
+	Menu_AddItem( &s_startserver_menu, &s_maxclients_field );
+	Menu_AddItem( &s_startserver_menu, &s_hostname_field );
+	Menu_AddItem( &s_startserver_menu, &s_startserver_dmoptions_action );
+	Menu_AddItem( &s_startserver_menu, &s_startserver_start_action );
+
+	Menu_Center( &s_startserver_menu );
+
+	// call this now to set proper inital state
+	RulesChangeFunc ( NULL );
+}
+
+void StartServer_MenuDraw(void)
+{
+	Menu_Draw( &s_startserver_menu );
+}
+
+char *StartServer_MenuKey( int key )
+{
+	if ( key == K_ESCAPE )
+	{
+		if ( mapnames )
+		{
+			int i;
+
+			for ( i = 0; i < nummaps; i++ )
+				free( mapnames[i] );
+			free( mapnames );
+		}
+		mapnames = 0;
+		nummaps = 0;
+	}
+
+	return Default_MenuKey( &s_startserver_menu, key );
+}
+
+void M_Menu_StartServer_f (void)
+{
+	StartServer_MenuInit();
+	M_PushMenu( StartServer_MenuDraw, StartServer_MenuKey );
+}
+
+/*
+=============================================================================
+
+DMOPTIONS BOOK MENU
+
+=============================================================================
+*/
+static char dmoptions_statusbar[128];
+
+static menuframework_t s_dmoptions_menu;
+
+static menulist_t	s_friendlyfire_box;
+static menulist_t	s_falls_box;
+static menulist_t	s_weapons_stay_box;
+static menulist_t	s_instant_powerups_box;
+static menulist_t	s_powerups_box;
+static menulist_t	s_health_box;
+static menulist_t	s_spawn_farthest_box;
+static menulist_t	s_teamplay_box;
+static menulist_t	s_samelevel_box;
+static menulist_t	s_force_respawn_box;
+static menulist_t	s_armor_box;
+static menulist_t	s_allow_exit_box;
+static menulist_t	s_infinite_ammo_box;
+static menulist_t	s_fixed_fov_box;
+static menulist_t	s_quad_drop_box;
+
+//ROGUE
+static menulist_t	s_no_mines_box;
+static menulist_t	s_no_nukes_box;
+static menulist_t	s_stack_double_box;
+static menulist_t	s_no_spheres_box;
+//ROGUE
+
+static void DMFlagCallback( void *self )
+{
+	menulist_t *f = ( menulist_t * ) self;
+	int flags;
+	int bit = 0;
+
+	flags = Cvar_VariableValue( "dmflags" );
+
+	if ( f == &s_friendlyfire_box )
+	{
+		if ( f->curvalue )
+			flags &= ~DF_NO_FRIENDLY_FIRE;
+		else
+			flags |= DF_NO_FRIENDLY_FIRE;
+		goto setvalue;
+	}
+	else if ( f == &s_falls_box )
+	{
+		if ( f->curvalue )
+			flags &= ~DF_NO_FALLING;
+		else
+			flags |= DF_NO_FALLING;
+		goto setvalue;
+	}
+	else if ( f == &s_weapons_stay_box ) 
+	{
+		bit = DF_WEAPONS_STAY;
+	}
+	else if ( f == &s_instant_powerups_box )
+	{
+		bit = DF_INSTANT_ITEMS;
+	}
+	else if ( f == &s_allow_exit_box )
+	{
+		bit = DF_ALLOW_EXIT;
+	}
+	else if ( f == &s_powerups_box )
+	{
+		if ( f->curvalue )
+			flags &= ~DF_NO_ITEMS;
+		else
+			flags |= DF_NO_ITEMS;
+		goto setvalue;
+	}
+	else if ( f == &s_health_box )
+	{
+		if ( f->curvalue )
+			flags &= ~DF_NO_HEALTH;
+		else
+			flags |= DF_NO_HEALTH;
+		goto setvalue;
+	}
+	else if ( f == &s_spawn_farthest_box )
+	{
+		bit = DF_SPAWN_FARTHEST;
+	}
+	else if ( f == &s_teamplay_box )
+	{
+		if ( f->curvalue == 1 )
+		{
+			flags |=  DF_SKINTEAMS;
+			flags &= ~DF_MODELTEAMS;
+		}
+		else if ( f->curvalue == 2 )
+		{
+			flags |=  DF_MODELTEAMS;
+			flags &= ~DF_SKINTEAMS;
+		}
+		else
+		{
+			flags &= ~( DF_MODELTEAMS | DF_SKINTEAMS );
+		}
+
+		goto setvalue;
+	}
+	else if ( f == &s_samelevel_box )
+	{
+		bit = DF_SAME_LEVEL;
+	}
+	else if ( f == &s_force_respawn_box )
+	{
+		bit = DF_FORCE_RESPAWN;
+	}
+	else if ( f == &s_armor_box )
+	{
+		if ( f->curvalue )
+			flags &= ~DF_NO_ARMOR;
+		else
+			flags |= DF_NO_ARMOR;
+		goto setvalue;
+	}
+	else if ( f == &s_infinite_ammo_box )
+	{
+		bit = DF_INFINITE_AMMO;
+	}
+	else if ( f == &s_fixed_fov_box )
+	{
+		bit = DF_FIXED_FOV;
+	}
+	else if ( f == &s_quad_drop_box )
+	{
+		bit = DF_QUAD_DROP;
+	}
+
+//=======
+//ROGUE
+	else if (Developer_searchpath(2) == 2)
+	{
+		if ( f == &s_no_mines_box)
+		{
+			bit = DF_NO_MINES;
+		}
+		else if ( f == &s_no_nukes_box)
+		{
+			bit = DF_NO_NUKES;
+		}
+		else if ( f == &s_stack_double_box)
+		{
+			bit = DF_NO_STACK_DOUBLE;
+		}
+		else if ( f == &s_no_spheres_box)
+		{
+			bit = DF_NO_SPHERES;
+		}
+	}
+//ROGUE
+//=======
+
+	if ( f )
+	{
+		if ( f->curvalue == 0 )
+			flags &= ~bit;
+		else
+			flags |= bit;
+	}
+
+setvalue:
+	Cvar_SetValue ("dmflags", flags);
+
+	Com_sprintf( dmoptions_statusbar, sizeof( dmoptions_statusbar ), "dmflags = %d", flags );
+
+}
+
+void DMOptions_MenuInit( void )
+{
+	static char *yes_no_names[] =
+	{
+		"no", "yes", 0
+	};
+	static char *teamplay_names[] = 
+	{
+		"disabled", "by skin", "by model", 0
+	};
+	int dmflags = Cvar_VariableValue( "dmflags" );
+	int y = 0;
+
+	s_dmoptions_menu.x = vid.width * 0.50;
+	s_dmoptions_menu.nitems = 0;
+
+	s_falls_box.generic.type = MTYPE_SPINCONTROL;
+	s_falls_box.generic.x	= 0;
+	s_falls_box.generic.y	= y;
+	s_falls_box.generic.name	= "falling damage";
+	s_falls_box.generic.callback = DMFlagCallback;
+	s_falls_box.itemnames = yes_no_names;
+	s_falls_box.curvalue = ( dmflags & DF_NO_FALLING ) == 0;
+
+	s_weapons_stay_box.generic.type = MTYPE_SPINCONTROL;
+	s_weapons_stay_box.generic.x	= 0;
+	s_weapons_stay_box.generic.y	= y += 10;
+	s_weapons_stay_box.generic.name	= "weapons stay";
+	s_weapons_stay_box.generic.callback = DMFlagCallback;
+	s_weapons_stay_box.itemnames = yes_no_names;
+	s_weapons_stay_box.curvalue = ( dmflags & DF_WEAPONS_STAY ) != 0;
+
+	s_instant_powerups_box.generic.type = MTYPE_SPINCONTROL;
+	s_instant_powerups_box.generic.x	= 0;
+	s_instant_powerups_box.generic.y	= y += 10;
+	s_instant_powerups_box.generic.name	= "instant powerups";
+	s_instant_powerups_box.generic.callback = DMFlagCallback;
+	s_instant_powerups_box.itemnames = yes_no_names;
+	s_instant_powerups_box.curvalue = ( dmflags & DF_INSTANT_ITEMS ) != 0;
+
+	s_powerups_box.generic.type = MTYPE_SPINCONTROL;
+	s_powerups_box.generic.x	= 0;
+	s_powerups_box.generic.y	= y += 10;
+	s_powerups_box.generic.name	= "allow powerups";
+	s_powerups_box.generic.callback = DMFlagCallback;
+	s_powerups_box.itemnames = yes_no_names;
+	s_powerups_box.curvalue = ( dmflags & DF_NO_ITEMS ) == 0;
+
+	s_health_box.generic.type = MTYPE_SPINCONTROL;
+	s_health_box.generic.x	= 0;
+	s_health_box.generic.y	= y += 10;
+	s_health_box.generic.callback = DMFlagCallback;
+	s_health_box.generic.name	= "allow health";
+	s_health_box.itemnames = yes_no_names;
+	s_health_box.curvalue = ( dmflags & DF_NO_HEALTH ) == 0;
+
+	s_armor_box.generic.type = MTYPE_SPINCONTROL;
+	s_armor_box.generic.x	= 0;
+	s_armor_box.generic.y	= y += 10;
+	s_armor_box.generic.name	= "allow armor";
+	s_armor_box.generic.callback = DMFlagCallback;
+	s_armor_box.itemnames = yes_no_names;
+	s_armor_box.curvalue = ( dmflags & DF_NO_ARMOR ) == 0;
+
+	s_spawn_farthest_box.generic.type = MTYPE_SPINCONTROL;
+	s_spawn_farthest_box.generic.x	= 0;
+	s_spawn_farthest_box.generic.y	= y += 10;
+	s_spawn_farthest_box.generic.name	= "spawn farthest";
+	s_spawn_farthest_box.generic.callback = DMFlagCallback;
+	s_spawn_farthest_box.itemnames = yes_no_names;
+	s_spawn_farthest_box.curvalue = ( dmflags & DF_SPAWN_FARTHEST ) != 0;
+
+	s_samelevel_box.generic.type = MTYPE_SPINCONTROL;
+	s_samelevel_box.generic.x	= 0;
+	s_samelevel_box.generic.y	= y += 10;
+	s_samelevel_box.generic.name	= "same map";
+	s_samelevel_box.generic.callback = DMFlagCallback;
+	s_samelevel_box.itemnames = yes_no_names;
+	s_samelevel_box.curvalue = ( dmflags & DF_SAME_LEVEL ) != 0;
+
+	s_force_respawn_box.generic.type = MTYPE_SPINCONTROL;
+	s_force_respawn_box.generic.x	= 0;
+	s_force_respawn_box.generic.y	= y += 10;
+	s_force_respawn_box.generic.name	= "force respawn";
+	s_force_respawn_box.generic.callback = DMFlagCallback;
+	s_force_respawn_box.itemnames = yes_no_names;
+	s_force_respawn_box.curvalue = ( dmflags & DF_FORCE_RESPAWN ) != 0;
+
+	s_teamplay_box.generic.type = MTYPE_SPINCONTROL;
+	s_teamplay_box.generic.x	= 0;
+	s_teamplay_box.generic.y	= y += 10;
+	s_teamplay_box.generic.name	= "teamplay";
+	s_teamplay_box.generic.callback = DMFlagCallback;
+	s_teamplay_box.itemnames = teamplay_names;
+
+	s_allow_exit_box.generic.type = MTYPE_SPINCONTROL;
+	s_allow_exit_box.generic.x	= 0;
+	s_allow_exit_box.generic.y	= y += 10;
+	s_allow_exit_box.generic.name	= "allow exit";
+	s_allow_exit_box.generic.callback = DMFlagCallback;
+	s_allow_exit_box.itemnames = yes_no_names;
+	s_allow_exit_box.curvalue = ( dmflags & DF_ALLOW_EXIT ) != 0;
+
+	s_infinite_ammo_box.generic.type = MTYPE_SPINCONTROL;
+	s_infinite_ammo_box.generic.x	= 0;
+	s_infinite_ammo_box.generic.y	= y += 10;
+	s_infinite_ammo_box.generic.name	= "infinite ammo";
+	s_infinite_ammo_box.generic.callback = DMFlagCallback;
+	s_infinite_ammo_box.itemnames = yes_no_names;
+	s_infinite_ammo_box.curvalue = ( dmflags & DF_INFINITE_AMMO ) != 0;
+
+	s_fixed_fov_box.generic.type = MTYPE_SPINCONTROL;
+	s_fixed_fov_box.generic.x	= 0;
+	s_fixed_fov_box.generic.y	= y += 10;
+	s_fixed_fov_box.generic.name	= "fixed FOV";
+	s_fixed_fov_box.generic.callback = DMFlagCallback;
+	s_fixed_fov_box.itemnames = yes_no_names;
+	s_fixed_fov_box.curvalue = ( dmflags & DF_FIXED_FOV ) != 0;
+
+	s_quad_drop_box.generic.type = MTYPE_SPINCONTROL;
+	s_quad_drop_box.generic.x	= 0;
+	s_quad_drop_box.generic.y	= y += 10;
+	s_quad_drop_box.generic.name	= "quad drop";
+	s_quad_drop_box.generic.callback = DMFlagCallback;
+	s_quad_drop_box.itemnames = yes_no_names;
+	s_quad_drop_box.curvalue = ( dmflags & DF_QUAD_DROP ) != 0;
+
+	s_friendlyfire_box.generic.type = MTYPE_SPINCONTROL;
+	s_friendlyfire_box.generic.x	= 0;
+	s_friendlyfire_box.generic.y	= y += 10;
+	s_friendlyfire_box.generic.name	= "friendly fire";
+	s_friendlyfire_box.generic.callback = DMFlagCallback;
+	s_friendlyfire_box.itemnames = yes_no_names;
+	s_friendlyfire_box.curvalue = ( dmflags & DF_NO_FRIENDLY_FIRE ) == 0;
+
+//============
+//ROGUE
+	if(Developer_searchpath(2) == 2)
+	{
+		s_no_mines_box.generic.type = MTYPE_SPINCONTROL;
+		s_no_mines_box.generic.x	= 0;
+		s_no_mines_box.generic.y	= y += 10;
+		s_no_mines_box.generic.name	= "remove mines";
+		s_no_mines_box.generic.callback = DMFlagCallback;
+		s_no_mines_box.itemnames = yes_no_names;
+		s_no_mines_box.curvalue = ( dmflags & DF_NO_MINES ) != 0;
+
+		s_no_nukes_box.generic.type = MTYPE_SPINCONTROL;
+		s_no_nukes_box.generic.x	= 0;
+		s_no_nukes_box.generic.y	= y += 10;
+		s_no_nukes_box.generic.name	= "remove nukes";
+		s_no_nukes_box.generic.callback = DMFlagCallback;
+		s_no_nukes_box.itemnames = yes_no_names;
+		s_no_nukes_box.curvalue = ( dmflags & DF_NO_NUKES ) != 0;
+
+		s_stack_double_box.generic.type = MTYPE_SPINCONTROL;
+		s_stack_double_box.generic.x	= 0;
+		s_stack_double_box.generic.y	= y += 10;
+		s_stack_double_box.generic.name	= "2x/4x stacking off";
+		s_stack_double_box.generic.callback = DMFlagCallback;
+		s_stack_double_box.itemnames = yes_no_names;
+		s_stack_double_box.curvalue = ( dmflags & DF_NO_STACK_DOUBLE ) != 0;
+
+		s_no_spheres_box.generic.type = MTYPE_SPINCONTROL;
+		s_no_spheres_box.generic.x	= 0;
+		s_no_spheres_box.generic.y	= y += 10;
+		s_no_spheres_box.generic.name	= "remove spheres";
+		s_no_spheres_box.generic.callback = DMFlagCallback;
+		s_no_spheres_box.itemnames = yes_no_names;
+		s_no_spheres_box.curvalue = ( dmflags & DF_NO_SPHERES ) != 0;
+
+	}
+//ROGUE
+//============
+
+	Menu_AddItem( &s_dmoptions_menu, &s_falls_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_weapons_stay_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_instant_powerups_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_powerups_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_health_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_armor_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_spawn_farthest_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_samelevel_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_force_respawn_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_teamplay_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_allow_exit_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_infinite_ammo_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_fixed_fov_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_quad_drop_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_friendlyfire_box );
+
+//=======
+//ROGUE
+	if(Developer_searchpath(2) == 2)
+	{
+		Menu_AddItem( &s_dmoptions_menu, &s_no_mines_box );
+		Menu_AddItem( &s_dmoptions_menu, &s_no_nukes_box );
+		Menu_AddItem( &s_dmoptions_menu, &s_stack_double_box );
+		Menu_AddItem( &s_dmoptions_menu, &s_no_spheres_box );
+	}
+//ROGUE
+//=======
+
+	Menu_Center( &s_dmoptions_menu );
+
+	// set the original dmflags statusbar
+	DMFlagCallback( 0 );
+	Menu_SetStatusBar( &s_dmoptions_menu, dmoptions_statusbar );
+}
+
+void DMOptions_MenuDraw(void)
+{
+	Menu_Draw( &s_dmoptions_menu );
+}
+
+char *DMOptions_MenuKey( int key )
+{
+	return Default_MenuKey( &s_dmoptions_menu, key );
+}
+
+void M_Menu_DMOptions_f (void)
+{
+	DMOptions_MenuInit();
+	M_PushMenu( DMOptions_MenuDraw, DMOptions_MenuKey );
+}
+
+/*
+=============================================================================
+
+DOWNLOADOPTIONS BOOK MENU
+
+=============================================================================
+*/
+static menuframework_t s_downloadoptions_menu;
+
+static menuseparator_t	s_download_title;
+static menulist_t	s_allow_download_box;
+static menulist_t	s_allow_download_maps_box;
+static menulist_t	s_allow_download_models_box;
+static menulist_t	s_allow_download_players_box;
+static menulist_t	s_allow_download_sounds_box;
+
+static void DownloadCallback( void *self )
+{
+	menulist_t *f = ( menulist_t * ) self;
+
+	if (f == &s_allow_download_box)
+	{
+		Cvar_SetValue("allow_download", f->curvalue);
+	}
+
+	else if (f == &s_allow_download_maps_box)
+	{
+		Cvar_SetValue("allow_download_maps", f->curvalue);
+	}
+
+	else if (f == &s_allow_download_models_box)
+	{
+		Cvar_SetValue("allow_download_models", f->curvalue);
+	}
+
+	else if (f == &s_allow_download_players_box)
+	{
+		Cvar_SetValue("allow_download_players", f->curvalue);
+	}
+
+	else if (f == &s_allow_download_sounds_box)
+	{
+		Cvar_SetValue("allow_download_sounds", f->curvalue);
+	}
+}
+
+void DownloadOptions_MenuInit( void )
+{
+	static char *yes_no_names[] =
+	{
+		"no", "yes", 0
+	};
+	int y = 0;
+
+	s_downloadoptions_menu.x = vid.width * 0.50;
+	s_downloadoptions_menu.nitems = 0;
+
+	s_download_title.generic.type = MTYPE_SEPARATOR;
+	s_download_title.generic.name = "Download Options";
+	s_download_title.generic.x    = 48;
+	s_download_title.generic.y	 = y;
+
+	s_allow_download_box.generic.type = MTYPE_SPINCONTROL;
+	s_allow_download_box.generic.x	= 0;
+	s_allow_download_box.generic.y	= y += 20;
+	s_allow_download_box.generic.name	= "allow downloading";
+	s_allow_download_box.generic.callback = DownloadCallback;
+	s_allow_download_box.itemnames = yes_no_names;
+	s_allow_download_box.curvalue = (Cvar_VariableValue("allow_download") != 0);
+
+	s_allow_download_maps_box.generic.type = MTYPE_SPINCONTROL;
+	s_allow_download_maps_box.generic.x	= 0;
+	s_allow_download_maps_box.generic.y	= y += 20;
+	s_allow_download_maps_box.generic.name	= "maps";
+	s_allow_download_maps_box.generic.callback = DownloadCallback;
+	s_allow_download_maps_box.itemnames = yes_no_names;
+	s_allow_download_maps_box.curvalue = (Cvar_VariableValue("allow_download_maps") != 0);
+
+	s_allow_download_players_box.generic.type = MTYPE_SPINCONTROL;
+	s_allow_download_players_box.generic.x	= 0;
+	s_allow_download_players_box.generic.y	= y += 10;
+	s_allow_download_players_box.generic.name	= "player models/skins";
+	s_allow_download_players_box.generic.callback = DownloadCallback;
+	s_allow_download_players_box.itemnames = yes_no_names;
+	s_allow_download_players_box.curvalue = (Cvar_VariableValue("allow_download_players") != 0);
+
+	s_allow_download_models_box.generic.type = MTYPE_SPINCONTROL;
+	s_allow_download_models_box.generic.x	= 0;
+	s_allow_download_models_box.generic.y	= y += 10;
+	s_allow_download_models_box.generic.name	= "models";
+	s_allow_download_models_box.generic.callback = DownloadCallback;
+	s_allow_download_models_box.itemnames = yes_no_names;
+	s_allow_download_models_box.curvalue = (Cvar_VariableValue("allow_download_models") != 0);
+
+	s_allow_download_sounds_box.generic.type = MTYPE_SPINCONTROL;
+	s_allow_download_sounds_box.generic.x	= 0;
+	s_allow_download_sounds_box.generic.y	= y += 10;
+	s_allow_download_sounds_box.generic.name	= "sounds";
+	s_allow_download_sounds_box.generic.callback = DownloadCallback;
+	s_allow_download_sounds_box.itemnames = yes_no_names;
+	s_allow_download_sounds_box.curvalue = (Cvar_VariableValue("allow_download_sounds") != 0);
+
+	Menu_AddItem( &s_downloadoptions_menu, &s_download_title );
+	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_box );
+	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_maps_box );
+	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_players_box );
+	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_models_box );
+	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_sounds_box );
+
+	Menu_Center( &s_downloadoptions_menu );
+
+	// skip over title
+	if (s_downloadoptions_menu.cursor == 0)
+		s_downloadoptions_menu.cursor = 1;
+}
+
+void DownloadOptions_MenuDraw(void)
+{
+	Menu_Draw( &s_downloadoptions_menu );
+}
+
+char *DownloadOptions_MenuKey( int key )
+{
+	return Default_MenuKey( &s_downloadoptions_menu, key );
+}
+
+void M_Menu_DownloadOptions_f (void)
+{
+	DownloadOptions_MenuInit();
+	M_PushMenu( DownloadOptions_MenuDraw, DownloadOptions_MenuKey );
+}
+/*
+=============================================================================
+
+ADDRESS BOOK MENU
+
+=============================================================================
+*/
+#define NUM_ADDRESSBOOK_ENTRIES 9
+
+static menuframework_t	s_addressbook_menu;
+static menufield_t		s_addressbook_fields[NUM_ADDRESSBOOK_ENTRIES];
+
+void AddressBook_MenuInit( void )
+{
+	int i;
+
+	s_addressbook_menu.x = vid.width / 2 - 142;
+	s_addressbook_menu.y = vid.height / 2 - 58;
+	s_addressbook_menu.nitems = 0;
+
+	for ( i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++ )
+	{
+		cvar_t *adr;
+		char buffer[20];
+
+		Com_sprintf( buffer, sizeof( buffer ), "adr%d", i );
+
+		adr = Cvar_Get( buffer, "", CVAR_ARCHIVE );
+
+		s_addressbook_fields[i].generic.type = MTYPE_FIELD;
+		s_addressbook_fields[i].generic.name = 0;
+		s_addressbook_fields[i].generic.callback = 0;
+		s_addressbook_fields[i].generic.x		= 0;
+		s_addressbook_fields[i].generic.y		= i * 18 + 0;
+		s_addressbook_fields[i].generic.localdata[0] = i;
+		s_addressbook_fields[i].cursor			= 0;
+		s_addressbook_fields[i].length			= 60;
+		s_addressbook_fields[i].visible_length	= 30;
+
+		strcpy( s_addressbook_fields[i].buffer, adr->string );
+
+		Menu_AddItem( &s_addressbook_menu, &s_addressbook_fields[i] );
+	}
+}
+
+char *AddressBook_MenuKey( int key )
+{
+	if ( key == K_ESCAPE )
+	{
+		int index;
+		char buffer[20];
+
+		for ( index = 0; index < NUM_ADDRESSBOOK_ENTRIES; index++ )
+		{
+			Com_sprintf( buffer, sizeof( buffer ), "adr%d", index );
+			Cvar_Set( buffer, s_addressbook_fields[index].buffer );
+		}
+	}
+	return Default_MenuKey( &s_addressbook_menu, key );
+}
+
+void AddressBook_MenuDraw(void)
+{
+	M_Banner( "m_banner_addressbook" );
+	Menu_Draw( &s_addressbook_menu );
+}
+
+void M_Menu_AddressBook_f(void)
+{
+	AddressBook_MenuInit();
+	M_PushMenu( AddressBook_MenuDraw, AddressBook_MenuKey );
+}
+
+/*
+=============================================================================
+
+PLAYER CONFIG MENU
+
+=============================================================================
+*/
+static menuframework_t	s_player_config_menu;
+static menufield_t		s_player_name_field;
+static menulist_t		s_player_model_box;
+static menulist_t		s_player_skin_box;
+static menulist_t		s_player_handedness_box;
+static menulist_t		s_player_rate_box;
+static menuseparator_t	s_player_skin_title;
+static menuseparator_t	s_player_model_title;
+static menuseparator_t	s_player_hand_title;
+static menuseparator_t	s_player_rate_title;
+static menuaction_t		s_player_download_action;
+
+#define MAX_DISPLAYNAME 16
+#define MAX_PLAYERMODELS 1024
+
+typedef struct
+{
+	int		nskins;
+	char	**skindisplaynames;
+	char	displayname[MAX_DISPLAYNAME];
+	char	directory[MAX_QPATH];
+} playermodelinfo_s;
+
+static playermodelinfo_s s_pmi[MAX_PLAYERMODELS];
+static char *s_pmnames[MAX_PLAYERMODELS];
+static int s_numplayermodels;
+
+static int rate_tbl[] = { 2500, 3200, 5000, 10000, 25000, 0 };
+static char *rate_names[] = { "28.8 Modem", "33.6 Modem", "Single ISDN",
+	"Dual ISDN/Cable", "T1/LAN", "User defined", 0 };
+
+void DownloadOptionsFunc( void * )
+{
+	M_Menu_DownloadOptions_f();
+}
+
+static void HandednessCallback( void * )
+{
+	Cvar_SetValue( "hand", s_player_handedness_box.curvalue );
+}
+
+static void RateCallback( void * )
+{
+	if (s_player_rate_box.curvalue != sizeof(rate_tbl) / sizeof(*rate_tbl) - 1)
+		Cvar_SetValue( "rate", rate_tbl[s_player_rate_box.curvalue] );
+}
+
+static void ModelCallback( void * )
+{
+	s_player_skin_box.itemnames = s_pmi[s_player_model_box.curvalue].skindisplaynames;
+	s_player_skin_box.curvalue = 0;
+}
+
+static void FreeFileList( char **list, int n )
+{
+	int i;
+
+	for ( i = 0; i < n; i++ )
+	{
+		if ( list[i] )
+		{
+			free( list[i] );
+			list[i] = 0;
+		}
+	}
+	free( list );
+}
+
+static qboolean IconOfSkinExists( char *skin, char **pcxfiles, int npcxfiles )
+{
+	int i;
+	char scratch[1024];
+
+	strcpy( scratch, skin );
+	*strrchr( scratch, '.' ) = 0;
+	strcat( scratch, "_i.pcx" );
+
+	for ( i = 0; i < npcxfiles; i++ )
+	{
+		if ( strcmp( pcxfiles[i], scratch ) == 0 )
+			return true;
+	}
+
+	return false;
+}
+
+static qboolean PlayerConfig_ScanDirectories( void )
+{
+	char findname[1024];
+	char scratch[1024];
+	int ndirs = 0, npms;
+	char **dirnames = NULL;
+	char *path = NULL;
+	int i;
+
+	extern char **FS_ListFiles( char *, int *, unsigned, unsigned );
+
+	s_numplayermodels = 0;
+
+	/*
+	** get a list of directories
+	*/
+	do 
+	{
+		if ( ( path = FS_NextPath( path ) ) == NULL)
+			break;
+		Com_sprintf( findname, sizeof(findname), "%s/players/*.*", path );
+
+		if ( ( dirnames = FS_ListFiles( findname, &ndirs, SFF_SUBDIR, 0 ) ) != 0 )
+			break;
+	} while ( path );
+
+	if ( !dirnames )
+		return false;
+
+	/*
+	** go through the subdirectories
+	*/
+	npms = ndirs;
+	if ( npms > MAX_PLAYERMODELS )
+		npms = MAX_PLAYERMODELS;
+
+	for ( i = 0; i < npms; i++ )
+	{
+		int k, s;
+		char *a, *b, *c;
+		char **pcxnames;
+		char **skinnames;
+		int npcxfiles;
+		int nskins = 0;
+
+		if ( dirnames[i] == 0 )
+			continue;
+
+		// verify the existence of tris.md2
+		strcpy( scratch, dirnames[i] );
+		strcat( scratch, "/tris.md2" );
+		if ( !Sys_FindFirst( scratch, 0, SFF_SUBDIR ) )
+		{
+			free( dirnames[i] );
+			dirnames[i] = 0;
+			Sys_FindClose();
+			continue;
+		}
+		Sys_FindClose();
+
+		// verify the existence of at least one pcx skin
+		strcpy( scratch, dirnames[i] );
+		strcat( scratch, "/*.pcx" );
+		pcxnames = FS_ListFiles( scratch, &npcxfiles, 0, SFF_SUBDIR);
+
+		if ( !pcxnames )
+		{
+			free( dirnames[i] );
+			dirnames[i] = 0;
+			continue;
+		}
+
+		// count valid skins, which consist of a skin with a matching "_i" icon
+		for ( k = 0; k < npcxfiles-1; k++ )
+		{
+			if ( !strstr( pcxnames[k], "_i.pcx" ) )
+			{
+				if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
+				{
+					nskins++;
+				}
+			}
+		}
+		if ( !nskins )
+			continue;
+
+		skinnames = malloc( sizeof( char * ) * ( nskins + 1 ) );
+		memset( skinnames, 0, sizeof( char * ) * ( nskins + 1 ) );
+
+		// copy the valid skins
+		for ( s = 0, k = 0; k < npcxfiles-1; k++ )
+		{
+			char *a, *b, *c;
+
+			if ( !strstr( pcxnames[k], "_i.pcx" ) )
+			{
+				if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
+				{
+					a = strrchr( pcxnames[k], '/' );
+					b = strrchr( pcxnames[k], '\\' );
+
+					if ( a > b )
+						c = a;
+					else
+						c = b;
+
+					strcpy( scratch, c + 1 );
+
+					if ( strrchr( scratch, '.' ) )
+						*strrchr( scratch, '.' ) = 0;
+
+					skinnames[s] = strdup( scratch );
+					s++;
+				}
+			}
+		}
+
+		// at this point we have a valid player model
+		s_pmi[s_numplayermodels].nskins = nskins;
+		s_pmi[s_numplayermodels].skindisplaynames = skinnames;
+
+		// make short name for the model
+		a = strrchr( dirnames[i], '/' );
+		b = strrchr( dirnames[i], '\\' );
+
+		if ( a > b )
+			c = a;
+		else
+			c = b;
+
+		strncpy( s_pmi[s_numplayermodels].displayname, c + 1, MAX_DISPLAYNAME-1 );
+		strcpy( s_pmi[s_numplayermodels].directory, c + 1 );
+
+		FreeFileList( pcxnames, npcxfiles );
+
+		s_numplayermodels++;
+	}
+	if ( dirnames )
+		FreeFileList( dirnames, ndirs );
+	return true;
+}
+
+static int pmicmpfnc( void *_a, void *_b )
+{
+	playermodelinfo_s *a = ( playermodelinfo_s * ) _a;
+	playermodelinfo_s *b = ( playermodelinfo_s * ) _b;
+
+	/*
+	** sort by male, female, then alphabetical
+	*/
+	if ( strcmp( a->directory, "male" ) == 0 )
+		return -1;
+	else if ( strcmp( b->directory, "male" ) == 0 )
+		return 1;
+
+	if ( strcmp( a->directory, "female" ) == 0 )
+		return -1;
+	else if ( strcmp( b->directory, "female" ) == 0 )
+		return 1;
+
+	return strcmp( a->directory, b->directory );
+}
+
+
+qboolean PlayerConfig_MenuInit( void )
+{
+	extern cvar_t *name;
+	extern cvar_t *team;
+	extern cvar_t *skin;
+	char currentdirectory[1024];
+	char currentskin[1024];
+	int i;
+
+	int currentdirectoryindex = 0;
+	int currentskinindex = 0;
+
+	cvar_t *hand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
+
+	static char *handedness[] = { "right", "left", "center", 0 };
+
+	PlayerConfig_ScanDirectories();
+
+	if (s_numplayermodels == 0)
+		return false;
+
+	if ( hand->value < 0 || hand->value > 2 )
+		Cvar_SetValue( "hand", 0 );
+
+	strcpy( currentdirectory, skin->string );
+
+	if ( strchr( currentdirectory, '/' ) )
+	{
+		strcpy( currentskin, strchr( currentdirectory, '/' ) + 1 );
+		*strchr( currentdirectory, '/' ) = 0;
+	}
+	else if ( strchr( currentdirectory, '\\' ) )
+	{
+		strcpy( currentskin, strchr( currentdirectory, '\\' ) + 1 );
+		*strchr( currentdirectory, '\\' ) = 0;
+	}
+	else
+	{
+		strcpy( currentdirectory, "male" );
+		strcpy( currentskin, "grunt" );
+	}
+
+	qsort( s_pmi, s_numplayermodels, sizeof( s_pmi[0] ), pmicmpfnc );
+
+	memset( s_pmnames, 0, sizeof( s_pmnames ) );
+	for ( i = 0; i < s_numplayermodels; i++ )
+	{
+		s_pmnames[i] = s_pmi[i].displayname;
+		if ( cistrcmp( s_pmi[i].directory, currentdirectory ) == 0 )
+		{
+			int j;
+
+			currentdirectoryindex = i;
+
+			for ( j = 0; j < s_pmi[i].nskins; j++ )
+			{
+				if ( cistrcmp( s_pmi[i].skindisplaynames[j], currentskin ) == 0 )
+				{
+					currentskinindex = j;
+					break;
+				}
+			}
+		}
+	}
+
+	s_player_config_menu.x = vid.width / 2 - 95; 
+	s_player_config_menu.y = vid.height / 2 - 97;
+	s_player_config_menu.nitems = 0;
+
+	s_player_name_field.generic.type = MTYPE_FIELD;
+	s_player_name_field.generic.name = "name";
+	s_player_name_field.generic.callback = 0;
+	s_player_name_field.generic.x		= 0;
+	s_player_name_field.generic.y		= 0;
+	s_player_name_field.length	= 20;
+	s_player_name_field.visible_length = 20;
+	strcpy( s_player_name_field.buffer, name->string );
+	s_player_name_field.cursor = strlen( name->string );
+
+	s_player_model_title.generic.type = MTYPE_SEPARATOR;
+	s_player_model_title.generic.name = "model";
+	s_player_model_title.generic.x    = -8;
+	s_player_model_title.generic.y	 = 60;
+
+	s_player_model_box.generic.type = MTYPE_SPINCONTROL;
+	s_player_model_box.generic.x	= -56;
+	s_player_model_box.generic.y	= 70;
+	s_player_model_box.generic.callback = ModelCallback;
+	s_player_model_box.generic.cursor_offset = -48;
+	s_player_model_box.curvalue = currentdirectoryindex;
+	s_player_model_box.itemnames = s_pmnames;
+
+	s_player_skin_title.generic.type = MTYPE_SEPARATOR;
+	s_player_skin_title.generic.name = "skin";
+	s_player_skin_title.generic.x    = -16;
+	s_player_skin_title.generic.y	 = 84;
+
+	s_player_skin_box.generic.type = MTYPE_SPINCONTROL;
+	s_player_skin_box.generic.x	= -56;
+	s_player_skin_box.generic.y	= 94;
+	s_player_skin_box.generic.name	= 0;
+	s_player_skin_box.generic.callback = 0;
+	s_player_skin_box.generic.cursor_offset = -48;
+	s_player_skin_box.curvalue = currentskinindex;
+	s_player_skin_box.itemnames = s_pmi[currentdirectoryindex].skindisplaynames;
+
+	s_player_hand_title.generic.type = MTYPE_SEPARATOR;
+	s_player_hand_title.generic.name = "handedness";
+	s_player_hand_title.generic.x    = 32;
+	s_player_hand_title.generic.y	 = 108;
+
+	s_player_handedness_box.generic.type = MTYPE_SPINCONTROL;
+	s_player_handedness_box.generic.x	= -56;
+	s_player_handedness_box.generic.y	= 118;
+	s_player_handedness_box.generic.name	= 0;
+	s_player_handedness_box.generic.cursor_offset = -48;
+	s_player_handedness_box.generic.callback = HandednessCallback;
+	s_player_handedness_box.curvalue = Cvar_VariableValue( "hand" );
+	s_player_handedness_box.itemnames = handedness;
+
+	for (i = 0; i < sizeof(rate_tbl) / sizeof(*rate_tbl) - 1; i++)
+		if (Cvar_VariableValue("rate") == rate_tbl[i])
+			break;
+
+	s_player_rate_title.generic.type = MTYPE_SEPARATOR;
+	s_player_rate_title.generic.name = "connect speed";
+	s_player_rate_title.generic.x    = 56;
+	s_player_rate_title.generic.y	 = 156;
+
+	s_player_rate_box.generic.type = MTYPE_SPINCONTROL;
+	s_player_rate_box.generic.x	= -56;
+	s_player_rate_box.generic.y	= 166;
+	s_player_rate_box.generic.name	= 0;
+	s_player_rate_box.generic.cursor_offset = -48;
+	s_player_rate_box.generic.callback = RateCallback;
+	s_player_rate_box.curvalue = i;
+	s_player_rate_box.itemnames = rate_names;
+
+	s_player_download_action.generic.type = MTYPE_ACTION;
+	s_player_download_action.generic.name	= "download options";
+	s_player_download_action.generic.flags= QMF_LEFT_JUSTIFY;
+	s_player_download_action.generic.x	= -24;
+	s_player_download_action.generic.y	= 186;
+	s_player_download_action.generic.statusbar = NULL;
+	s_player_download_action.generic.callback = DownloadOptionsFunc;
+
+	Menu_AddItem( &s_player_config_menu, &s_player_name_field );
+	Menu_AddItem( &s_player_config_menu, &s_player_model_title );
+	Menu_AddItem( &s_player_config_menu, &s_player_model_box );
+	if ( s_player_skin_box.itemnames )
+	{
+		Menu_AddItem( &s_player_config_menu, &s_player_skin_title );
+		Menu_AddItem( &s_player_config_menu, &s_player_skin_box );
+	}
+	Menu_AddItem( &s_player_config_menu, &s_player_hand_title );
+	Menu_AddItem( &s_player_config_menu, &s_player_handedness_box );
+	Menu_AddItem( &s_player_config_menu, &s_player_rate_title );
+	Menu_AddItem( &s_player_config_menu, &s_player_rate_box );
+	Menu_AddItem( &s_player_config_menu, &s_player_download_action );
+
+	return true;
+}
+
+void PlayerConfig_MenuDraw( void )
+{
+	extern float CalcFov( float fov_x, float w, float h );
+	refdef_t refdef;
+	char scratch[MAX_QPATH];
+
+	memset( &refdef, 0, sizeof( refdef ) );
+
+	refdef.x = vid.width / 2;
+	refdef.y = vid.height / 2 - 72;
+	refdef.width = 144;
+	refdef.height = 168;
+	refdef.fov_x = 40;
+	refdef.fov_y = CalcFov( refdef.fov_x, refdef.width, refdef.height );
+	refdef.time = cls.realtime*0.001;
+
+	if ( s_pmi[s_player_model_box.curvalue].skindisplaynames )
+	{
+		static int yaw;
+		entity_t entity;
+
+		memset( &entity, 0, sizeof( entity ) );
+
+		Com_sprintf( scratch, sizeof( scratch ), "players/%s/tris.md2", s_pmi[s_player_model_box.curvalue].directory );
+		entity.model = re.RegisterModel( scratch );
+		Com_sprintf( scratch, sizeof( scratch ), "players/%s/%s.pcx", s_pmi[s_player_model_box.curvalue].directory, s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
+		entity.skin = re.RegisterSkin( scratch );
+		entity.flags = RF_FULLBRIGHT;
+		entity.origin[0] = 80;
+		entity.origin[1] = 0;
+		entity.origin[2] = 0;
+		VectorCopy( entity.origin, entity.oldorigin );
+		entity.frame = 0;
+		entity.oldframe = 0;
+		entity.backlerp = 0.0;
+		entity.angles[1] = yaw++;
+		if ( ++yaw > 360 )
+			yaw -= 360;
+
+		refdef.areabits = 0;
+		refdef.num_entities = 1;
+		refdef.entities = &entity;
+		refdef.lightstyles = 0;
+		refdef.rdflags = RDF_NOWORLDMODEL;
+
+		Menu_Draw( &s_player_config_menu );
+
+		M_DrawTextBox( ( refdef.x ) * ( 320.0F / vid.width ) - 8, ( vid.height / 2 ) * ( 240.0F / vid.height) - 77, refdef.width / 8, refdef.height / 8 );
+		refdef.height += 4;
+
+		re.RenderFrame( &refdef );
+
+		Com_sprintf( scratch, sizeof( scratch ), "/players/%s/%s_i.pcx", 
+			s_pmi[s_player_model_box.curvalue].directory,
+			s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
+		re.DrawPic( s_player_config_menu.x - 40, refdef.y, scratch );
+	}
+}
+
+char *PlayerConfig_MenuKey (int key)
+{
+	int i;
+
+	if ( key == K_ESCAPE )
+	{
+		char scratch[1024];
+
+		Cvar_Set( "name", s_player_name_field.buffer );
+
+		Com_sprintf( scratch, sizeof( scratch ), "%s/%s", 
+			s_pmi[s_player_model_box.curvalue].directory, 
+			s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
+
+		Cvar_Set( "skin", scratch );
+
+		for ( i = 0; i < s_numplayermodels; i++ )
+		{
+			int j;
+
+			for ( j = 0; j < s_pmi[i].nskins; j++ )
+			{
+				if ( s_pmi[i].skindisplaynames[j] )
+					free( s_pmi[i].skindisplaynames[j] );
+				s_pmi[i].skindisplaynames[j] = 0;
+			}
+			free( s_pmi[i].skindisplaynames );
+			s_pmi[i].skindisplaynames = 0;
+			s_pmi[i].nskins = 0;
+		}
+	}
+	return Default_MenuKey( &s_player_config_menu, key );
+}
+
+
+void M_Menu_PlayerConfig_f (void)
+{
+	if (!PlayerConfig_MenuInit())
+	{
+		Menu_SetStatusBar( &s_multiplayer_menu, "No valid player models found" );
+		return;
+	}
+	Menu_SetStatusBar( &s_multiplayer_menu, NULL );
+	M_PushMenu( PlayerConfig_MenuDraw, PlayerConfig_MenuKey );
+}
+
+
+/*
+=======================================================================
+
+GALLERY MENU
+
+=======================================================================
+*/
+/* commented out in release
+void M_Menu_Gallery_f( void )
+{
+	extern void Gallery_MenuDraw( void );
+	extern char *Gallery_MenuKey( int key );
+
+	M_PushMenu( Gallery_MenuDraw, Gallery_MenuKey );
+}
+*/
+
+/*
+=======================================================================
+
+QUIT MENU
+
+=======================================================================
+*/
+
+char *M_Quit_Key (int key)
+{
+	switch (key)
+	{
+	case K_ESCAPE:
+	case 'n':
+	case 'N':
+		M_PopMenu ();
+		break;
+
+	case 'Y':
+	case 'y':
+		cls.key_dest = key_console;
+		CL_Quit_f ();
+		break;
+
+	default:
+		break;
+	}
+
+	return NULL;
+
+}
+
+
+void M_Quit_Draw (void)
+{
+	int		w, h;
+
+	re.DrawGetPicSize (&w, &h, "quit");
+	re.DrawPic ( (vid.width-w)/2, (vid.height-h)/2, "quit");
+}
+
+
+void M_Menu_Quit_f (void)
+{
+	M_PushMenu (M_Quit_Draw, M_Quit_Key);
+}
+
+
+
+//=============================================================================
+/* Menu Subsystem */
+
+
+/*
+=================
+M_Init
+=================
+*/
+void M_Init (void)
+{
+	Cmd_AddCommand ("menu_main", M_Menu_Main_f);
+	Cmd_AddCommand ("menu_game", M_Menu_Game_f);
+		Cmd_AddCommand ("menu_loadgame", M_Menu_LoadGame_f);
+		Cmd_AddCommand ("menu_savegame", M_Menu_SaveGame_f);
+		Cmd_AddCommand ("menu_joinserver", M_Menu_JoinServer_f);
+			Cmd_AddCommand ("menu_addressbook", M_Menu_AddressBook_f);
+		Cmd_AddCommand ("menu_startserver", M_Menu_StartServer_f);
+			Cmd_AddCommand ("menu_dmoptions", M_Menu_DMOptions_f);
+		Cmd_AddCommand ("menu_playerconfig", M_Menu_PlayerConfig_f);
+			Cmd_AddCommand ("menu_downloadoptions", M_Menu_DownloadOptions_f);
+		Cmd_AddCommand ("menu_credits", M_Menu_Credits_f );
+	Cmd_AddCommand ("menu_multiplayer", M_Menu_Multiplayer_f );
+	Cmd_AddCommand ("menu_video", M_Menu_Video_f);
+	Cmd_AddCommand ("menu_options", M_Menu_Options_f);
+		Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
+	Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
+}
+
+
+/*
+=================
+M_Draw
+=================
+*/
+void M_Draw (void)
+{
+	if (cls.key_dest != key_menu)
+		return;
+
+	// repaint everything next frame
+	SCR_DirtyScreen ();
+
+	// dim everything behind it down
+	if (cl.cinematictime > 0)
+		re.DrawFill (0,0,vid.width, vid.height, 0);
+	else
+		re.DrawFadeScreen ();
+
+	m_drawfunc ();
+
+	// delay playing the enter sound until after the
+	// menu has been drawn, to avoid delay while
+	// caching images
+	if (m_entersound)
+	{
+		S_StartLocalSound( menu_in_sound );
+		m_entersound = false;
+	}
+}
+
+
+/*
+=================
+M_Keydown
+=================
+*/
+void M_Keydown (int key)
+{
+	char *s;
+
+	if (m_keyfunc)
+		if ( ( s = m_keyfunc( key ) ) != 0 )
+			S_StartLocalSound( ( char * ) s );
+}
+
+
--- a/mk.baseq2
+++ b/mk.baseq2
@@ -1,3 +1,5 @@
+TARG=quake2
+
 GMOFILES=\
 	game/g_ai.$O\
 	game/p_client.$O\
@@ -49,7 +51,6 @@
 	game/q_shared.$O\
 
 GMHFILES=\
-	game/g_local.h\
 	game/game.h\
 	game/m_actor.h\
 	game/m_berserk.h\
--- a/mk.ctf
+++ b/mk.ctf
@@ -1,35 +1,32 @@
+TARG=q2ctf
+
 GMOFILES=\
-	ctf/g_ai.$O\
-	ctf/g_chase.$O\
-	ctf/g_cmds.$O\
-	ctf/g_combat.$O\
-	ctf/g_ctf.$O\
-	ctf/g_func.$O\
-	ctf/g_items.$O\
-	ctf/g_main.$O\
-	ctf/g_misc.$O\
-	ctf/g_monster.$O\
-	ctf/g_phys.$O\
-	ctf/g_save.$O\
-	ctf/g_spawn.$O\
-	ctf/g_svcmds.$O\
-	ctf/g_target.$O\
-	ctf/g_trigger.$O\
-	ctf/g_utils.$O\
-	ctf/g_weapon.$O\
-	ctf/m_move.$O\
-	ctf/p_client.$O\
-	ctf/p_hud.$O\
-	ctf/p_menu.$O\
-	ctf/p_trail.$O\
-	ctf/p_view.$O\
-	ctf/p_weapon.$O\
-	ctf/q_shared.$O\
+	game/g_ai.$O\
+	game/g_chase.$O\
+	game/g_cmds.$O\
+	game/g_combat.$O\
+	game/g_game.$O\
+	game/g_func.$O\
+	game/g_items.$O\
+	game/g_main.$O\
+	game/g_misc.$O\
+	game/g_monster.$O\
+	game/g_phys.$O\
+	game/g_save.$O\
+	game/g_spawn.$O\
+	game/g_svcmds.$O\
+	game/g_target.$O\
+	game/g_trigger.$O\
+	game/g_utils.$O\
+	game/g_weapon.$O\
+	game/m_move.$O\
+	game/p_client.$O\
+	game/p_hud.$O\
+	game/p_menu.$O\
+	game/p_trail.$O\
+	game/p_view.$O\
+	game/p_weapon.$O\
+	game/q_shared.$O\
 
 GMHFILES=\
-	ctf/g_ctf.h\
-	ctf/g_local.h\
-	ctf/game.h\
-	ctf/m_player.h\
-	ctf/p_menu.h\
-
+	game/game.h\
--- a/mk.xatrix
+++ /dev/null
@@ -1,55 +1,0 @@
-GMFILES=\
-	xatrix/g_ai.$O\
-	xatrix/g_cmds.$O\
-	xatrix/g_combat.$O\
-	xatrix/g_func.$O\
-	xatrix/g_items.$O\
-	xatrix/g_main.$O\
-	xatrix/g_misc.$O\
-	xatrix/g_monster.$O\
-	xatrix/g_phys.$O\
-	xatrix/g_save.$O\
-	xatrix/g_spawn.$O\
-	xatrix/g_svcmds.$O\
-	xatrix/g_target.$O\
-	xatrix/g_trigger.$O\
-	xatrix/g_turret.$O\
-	xatrix/g_utils.$O\
-	xatrix/g_weapon.$O\
-	xatrix/m_actor.$O\
-	xatrix/m_berserk.$O\
-	xatrix/m_boss2.$O\
-	xatrix/m_boss3.$O\
-	xatrix/m_boss31.$O\
-	xatrix/m_boss32.$O\
-	xatrix/m_boss5.$O\
-	xatrix/m_brain.$O\
-	xatrix/m_chick.$O\
-	xatrix/m_fixbot.$O\
-	xatrix/m_flash.$O\
-	xatrix/m_flipper.$O\
-	xatrix/m_float.$O\
-	xatrix/m_flyer.$O\
-	xatrix/m_gekk.$O\
-	xatrix/m_gladb.$O\
-	xatrix/m_gladiator.$O\
-	xatrix/m_gunner.$O\
-	xatrix/m_hover.$O\
-	xatrix/m_infantry.$O\
-	xatrix/m_insane.$O\
-	xatrix/m_medic.$O\
-	xatrix/m_move.$O\
-	xatrix/m_mutant.$O\
-	xatrix/m_parasite.$O\
-	xatrix/m_soldier.$O\
-	xatrix/m_supertank.$O\
-	xatrix/m_tank.$O\
-	xatrix/p_client.$O\
-	xatrix/p_hud.$O\
-	xatrix/p_trail.$O\
-	xatrix/p_view.$O\
-	xatrix/p_weapon.$O\
-	xatrix/q_shared.$O\
-
-GMHFILES=\
-
--- a/mkfile
+++ b/mkfile
@@ -1,95 +1,79 @@
 </$objtype/mkfile
 
 BIN=$home/bin/$objtype
-TARG=quake2
 
 # change this to build/load a different game "dll"
 <mk.baseq2
 
 OFILES=\
-	client/cl_cin.$O\
-	client/cl_ents.$O\
-	client/cl_fx.$O\
-	client/cl_newfx.$O\
-	client/cl_input.$O\
-	client/cl_inv.$O\
-	client/cl_main.$O\
-	client/cl_parse.$O\
-	client/cl_pred.$O\
-	client/cl_tent.$O\
-	client/cl_scrn.$O\
-	client/cl_view.$O\
-	client/console.$O\
-	client/keys.$O\
-	client/menu.$O\
-	client/snd_dma.$O\
-	client/snd_mem.$O\
-	client/snd_mix.$O\
-	client/qmenu.$O\
-	server/sv_ccmds.$O\
-	server/sv_ents.$O\
-	server/sv_game.$O\
-	server/sv_init.$O\
-	server/sv_main.$O\
-	server/sv_send.$O\
-	server/sv_user.$O\
-	server/sv_world.$O\
-	qcommon/cmd.$O\
-	qcommon/cmodel.$O\
-	qcommon/common.$O\
-	qcommon/crc.$O\
-	qcommon/cvar.$O\
-	qcommon/files.$O\
-	qcommon/md4.$O\
-	qcommon/net_chan.$O\
-	qcommon/pmove.$O\
-	plan9/cd.$O\
-	plan9/in.$O\
-	plan9/menu.$O\
-	plan9/snd.$O\
-	plan9/sys.$O\
-	plan9/udp.$O\
-	plan9/vid.$O\
-	ref/r_aclip.$O\
-	ref/r_alias.$O\
-	ref/r_bsp.$O\
-	ref/r_draw.$O\
-	ref/r_edge.$O\
-	ref/r_image.$O\
-	ref/r_light.$O\
-	ref/r_main.$O\
-	ref/r_misc.$O\
-	ref/r_model.$O\
-	ref/r_part.$O\
-	ref/r_poly.$O\
-	ref/r_polyse.$O\
-	ref/r_rast.$O\
-	ref/r_scan.$O\
-	ref/r_sprite.$O\
-	ref/r_surf.$O\
+	cl_cin.$O\
+	cl_ents.$O\
+	cl_fx.$O\
+	cl_newfx.$O\
+	cl_input.$O\
+	cl_inv.$O\
+	cl_main.$O\
+	cl_parse.$O\
+	cl_pred.$O\
+	cl_tent.$O\
+	cl_scrn.$O\
+	cl_view.$O\
+	console.$O\
+	keys.$O\
+	menu.$O\
+	snd_dma.$O\
+	snd_mem.$O\
+	snd_mix.$O\
+	qmenu.$O\
+	sv_ccmds.$O\
+	sv_ents.$O\
+	sv_game.$O\
+	sv_init.$O\
+	sv_main.$O\
+	sv_send.$O\
+	sv_user.$O\
+	sv_world.$O\
+	cmd.$O\
+	cmodel.$O\
+	common.$O\
+	crc.$O\
+	cvar.$O\
+	files.$O\
+	md4.$O\
+	net_chan.$O\
+	pmove.$O\
+	cd.$O\
+	in.$O\
+	snd.$O\
+	sys.$O\
+	udp.$O\
+	vid.$O\
+	vmenu.$O\
+	r_aclip.$O\
+	r_alias.$O\
+	r_bsp.$O\
+	r_draw.$O\
+	r_edge.$O\
+	r_image.$O\
+	r_light.$O\
+	r_main.$O\
+	r_misc.$O\
+	r_model.$O\
+	r_part.$O\
+	r_poly.$O\
+	r_polyse.$O\
+	r_rast.$O\
+	r_scan.$O\
+	r_sprite.$O\
+	r_surf.$O\
 	$GMOFILES\
 
 HFILES=\
+	adivtab.h\
 	anorms.h\
-	q_shared.h\
-	client/cdaudio.h\
-	client/client.h\
-	client/console.h\
-	client/input.h\
-	client/keys.h\
-	client/qmenu.h\
-	client/ref.h\
-	client/screen.h\
-	client/snd_loc.h\
-	client/sound.h\
-	client/vid.h\
-	server/server.h\
-	qcommon/crc.h\
-	qcommon/qcommon.h\
-	qcommon/qfiles.h\
-	ref/adivtab.h\
-	ref/r_local.h\
-	ref/rand1k.h\
+	dat.h\
+	fns.h\
+	rand1k.h\
 	$GMHFILES\
 
 # FIXME
--- /dev/null
+++ b/net_chan.c
@@ -1,0 +1,370 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+
+packet header
+-------------
+31	sequence
+1	does this message contain a reliable payload
+31	acknowledge sequence
+1	acknowledge receipt of even/odd message
+16	qport
+
+The remote connection never knows if it missed a reliable message, the
+local side detects that it has been dropped by seeing a sequence acknowledge
+higher thatn the last reliable sequence, but without the correct evon/odd
+bit for the reliable set.
+
+If the sender notices that a reliable message has been dropped, it will be
+retransmitted.  It will not be retransmitted again until a message after
+the retransmit has been acknowledged and the reliable still failed to get there.
+
+if the sequence number is -1, the packet should be handled without a netcon
+
+The reliable message can be added to at any time by doing
+MSG_Write* (&netchan->message, <data>).
+
+If the message buffer is overflowed, either by a single message, or by
+multiple frames worth piling up while the last reliable transmit goes
+unacknowledged, the netchan signals a fatal error.
+
+Reliable messages are always placed first in a packet, then the unreliable
+message is included if there is sufficient room.
+
+To the receiver, there is no distinction between the reliable and unreliable
+parts of the message, they are just processed out as a single larger message.
+
+Illogical packet sequence numbers cause the packet to be dropped, but do
+not kill the connection.  This, combined with the tight window of valid
+reliable acknowledgement numbers provides protection against malicious
+address spoofing.
+
+
+The qport field is a workaround for bad address translating routers that
+sometimes remap the client's source port on a packet during gameplay.
+
+If the base part of the net address matches and the qport matches, then the
+channel matches even if the IP port differs.  The IP port should be updated
+to the new value before sending out any replies.
+
+
+If there is no information that needs to be transfered on a given frame,
+such as during the connection stage while waiting for the client to load,
+then a packet only needs to be delivered if there is something in the
+unacknowledged reliable
+*/
+
+cvar_t		*showpackets;
+cvar_t		*showdrop;
+cvar_t		*qport;
+
+netadr_t	net_from;
+sizebuf_t	net_message;
+byte		net_message_buffer[MAX_MSGLEN];
+
+/*
+===============
+Netchan_Init
+
+===============
+*/
+void Netchan_Init (void)
+{
+	int		port;
+
+	// pick a port value that should be nice and random
+	port = Sys_Milliseconds() & 0xffff;
+
+	showpackets = Cvar_Get ("showpackets", "0", 0);
+	showdrop = Cvar_Get ("showdrop", "0", 0);
+	qport = Cvar_Get ("qport", va("%i", port), CVAR_NOSET);
+}
+
+/*
+===============
+Netchan_OutOfBand
+
+Sends an out-of-band datagram
+================
+*/
+void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data)
+{
+	sizebuf_t	send;
+	byte		send_buf[MAX_MSGLEN];
+
+// write the packet header
+	SZ_Init (&send, send_buf, sizeof(send_buf));
+	
+	MSG_WriteLong (&send, -1);	// -1 sequence means out of band
+	SZ_Write (&send, data, length);
+
+// send the datagram
+	NET_SendPacket (net_socket, send.cursize, send.data, adr);
+}
+
+/*
+===============
+Netchan_OutOfBandPrint
+
+Sends a text message in an out-of-band datagram
+================
+*/
+void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...)
+{
+	va_list		argptr;
+	static char		string[MAX_MSGLEN - 4];
+	
+	va_start (argptr, format);
+	vsprintf (string, format,argptr);
+	va_end (argptr);
+
+	Netchan_OutOfBand (net_socket, adr, strlen(string), (byte *)string);
+}
+
+
+/*
+==============
+Netchan_Setup
+
+called to open a channel to a remote system
+==============
+*/
+void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport)
+{
+	memset (chan, 0, sizeof(*chan));
+	
+	chan->sock = sock;
+	chan->remote_address = adr;
+	chan->qport = qport;
+	chan->last_received = curtime;
+	chan->incoming_sequence = 0;
+	chan->outgoing_sequence = 1;
+
+	SZ_Init (&chan->message, chan->message_buf, sizeof(chan->message_buf));
+	chan->message.allowoverflow = true;
+}
+
+
+/*
+===============
+Netchan_CanReliable
+
+Returns true if the last reliable message has acked
+================
+*/
+qboolean Netchan_CanReliable (netchan_t *chan)
+{
+	if (chan->reliable_length)
+		return false;			// waiting for ack
+	return true;
+}
+
+
+qboolean Netchan_NeedReliable (netchan_t *chan)
+{
+	qboolean	send_reliable;
+
+// if the remote side dropped the last reliable message, resend it
+	send_reliable = false;
+
+	if (chan->incoming_acknowledged > chan->last_reliable_sequence
+	&& chan->incoming_reliable_acknowledged != chan->reliable_sequence)
+		send_reliable = true;
+
+// if the reliable transmit buffer is empty, copy the current message out
+	if (!chan->reliable_length && chan->message.cursize)
+	{
+		send_reliable = true;
+	}
+
+	return send_reliable;
+}
+
+/*
+===============
+Netchan_Transmit
+
+tries to send an unreliable message to a connection, and handles the
+transmition / retransmition of the reliable messages.
+
+A 0 length will still generate a packet and deal with the reliable messages.
+================
+*/
+void Netchan_Transmit (netchan_t *chan, int length, byte *data)
+{
+	sizebuf_t	send;
+	byte		send_buf[MAX_MSGLEN];
+	qboolean	send_reliable;
+	unsigned	w1, w2;
+
+// check for message overflow
+	if (chan->message.overflowed)
+	{
+		chan->fatal_error = true;
+		Com_Printf ("%s:Outgoing message overflow\n"
+			, NET_AdrToString (chan->remote_address));
+		return;
+	}
+
+	send_reliable = Netchan_NeedReliable (chan);
+
+	if (!chan->reliable_length && chan->message.cursize)
+	{
+		memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize);
+		chan->reliable_length = chan->message.cursize;
+		chan->message.cursize = 0;
+		chan->reliable_sequence ^= 1;
+	}
+
+
+// write the packet header
+	SZ_Init (&send, send_buf, sizeof(send_buf));
+
+	w1 = ( chan->outgoing_sequence & ~(1<<31) ) | (send_reliable<<31);
+	w2 = ( chan->incoming_sequence & ~(1<<31) ) | (chan->incoming_reliable_sequence<<31);
+
+	chan->outgoing_sequence++;
+	chan->last_sent = curtime;
+
+	MSG_WriteLong (&send, w1);
+	MSG_WriteLong (&send, w2);
+
+	// send the qport if we are a client
+	if (chan->sock == NS_CLIENT)
+		MSG_WriteShort (&send, qport->value);
+
+// copy the reliable message to the packet first
+	if (send_reliable)
+	{
+		SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
+		chan->last_reliable_sequence = chan->outgoing_sequence;
+	}
+	
+// add the unreliable part if space is available
+	if (send.maxsize - send.cursize >= length)
+		SZ_Write (&send, data, length);
+	else
+		Com_Printf ("Netchan_Transmit: dumped unreliable\n");
+
+// send the datagram
+	NET_SendPacket (chan->sock, send.cursize, send.data, chan->remote_address);
+
+	if (showpackets->value)
+	{
+		if (send_reliable)
+			Com_Printf ("send %4i : s=%i reliable=%i ack=%i rack=%i\n"
+				, send.cursize
+				, chan->outgoing_sequence - 1
+				, chan->reliable_sequence
+				, chan->incoming_sequence
+				, chan->incoming_reliable_sequence);
+		else
+			Com_Printf ("send %4i : s=%i ack=%i rack=%i\n"
+				, send.cursize
+				, chan->outgoing_sequence - 1
+				, chan->incoming_sequence
+				, chan->incoming_reliable_sequence);
+	}
+}
+
+/*
+=================
+Netchan_Process
+
+called when the current net_message is from remote_address
+modifies net_message so that it points to the packet payload
+=================
+*/
+qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg)
+{
+	unsigned	sequence, sequence_ack;
+	unsigned	reliable_ack, reliable_message;
+
+// get sequence numbers		
+	MSG_BeginReading (msg);
+	sequence = MSG_ReadLong (msg);
+	sequence_ack = MSG_ReadLong (msg);
+
+	// read the qport if we are a server
+	if (chan->sock == NS_SERVER)
+		MSG_ReadShort (msg);	/* toss read */
+
+	reliable_message = sequence >> 31;
+	reliable_ack = sequence_ack >> 31;
+
+	sequence &= ~(1<<31);
+	sequence_ack &= ~(1<<31);	
+
+	if (showpackets->value)
+	{
+		if (reliable_message)
+			Com_Printf ("recv %4i : s=%i reliable=%i ack=%i rack=%i\n"
+				, msg->cursize
+				, sequence
+				, chan->incoming_reliable_sequence ^ 1
+				, sequence_ack
+				, reliable_ack);
+		else
+			Com_Printf ("recv %4i : s=%i ack=%i rack=%i\n"
+				, msg->cursize
+				, sequence
+				, sequence_ack
+				, reliable_ack);
+	}
+
+//
+// discard stale or duplicated packets
+//
+	if (sequence <= chan->incoming_sequence)
+	{
+		if (showdrop->value)
+			Com_Printf ("%s:Out of order packet %i at %i\n"
+				, NET_AdrToString (chan->remote_address)
+				,  sequence
+				, chan->incoming_sequence);
+		return false;
+	}
+
+//
+// dropped packets don't keep the message from being used
+//
+	chan->dropped = sequence - (chan->incoming_sequence+1);
+	if (chan->dropped > 0)
+	{
+		if (showdrop->value)
+			Com_Printf ("%s:Dropped %i packets at %i\n"
+			, NET_AdrToString (chan->remote_address)
+			, chan->dropped
+			, sequence);
+	}
+
+//
+// if the current outgoing reliable message has been acknowledged
+// clear the buffer to make way for the next
+//
+	if (reliable_ack == chan->reliable_sequence)
+		chan->reliable_length = 0;	// it has been received
+	
+//
+// if this message contains a reliable message, bump incoming_reliable_sequence 
+//
+	chan->incoming_sequence = sequence;
+	chan->incoming_acknowledged = sequence_ack;
+	chan->incoming_reliable_acknowledged = reliable_ack;
+	if (reliable_message)
+	{
+		chan->incoming_reliable_sequence ^= 1;
+	}
+
+//
+// the message can now be read from the current message pointer
+//
+	chan->last_received = curtime;
+
+	return true;
+}
+
--- a/plan9/cd.c
+++ /dev/null
@@ -1,414 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-qboolean cdValid = false;
-qboolean playing = false;
-qboolean wasPlaying = false;
-qboolean initialized = false;
-qboolean enabled = true;
-qboolean playLooping = false;
-float cdvolume;
-byte remap[100];
-byte playTrack;
-byte maxTrack;
-int cdfile = -1;
-
-cvar_t	*cd_volume;
-cvar_t *cd_nocd;
-cvar_t *cd_dev;
-
-
-void CDAudio_Eject(void)
-{
-	if (cdfile == -1 || !enabled)
-		return;
-
-	Com_DPrintf("CDAudio_Eject: PORTME\n");
-	/*
-	if ( ioctl(cdfile, CDROMEJECT) == -1 ) 
-		Com_DPrintf("ioctl cdromeject failed\n");
-	*/
-}
-
-void CDAudio_CloseDoor(void)
-{
-	if (cdfile == -1 || !enabled)
-		return;
-
-	Com_DPrintf("CDAudio_CloseDoor: PORTME\n");
-	/*
-	if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 ) 
-		Com_DPrintf("ioctl cdromclosetray failed\n");
-	*/
-}
-
-int CDAudio_GetAudioDiskInfo(void)
-{
-	cdValid = false;
-	Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
-	return -1;
-
-	/*
-	struct cdrom_tochdr tochdr;
-
-	if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 ) 
-	{
-		Com_DPrintf("ioctl cdromreadtochdr failed\n");
-		return -1;
-	}
-
-	if (tochdr.cdth_trk0 < 1)
-	{
-		Com_DPrintf("CDAudio: no music tracks\n");
-		return -1;
-	}
-
-	cdValid = true;
-	maxTrack = tochdr.cdth_trk1;
-	return 0;
-	*/
-}
-
-void CDAudio_Pause(void)
-{
-	if (cdfile == -1 || !enabled)
-		return;
-	if (!playing)
-		return;
-
-	Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
-
-	/*
-	if ( ioctl(cdfile, CDROMPAUSE) == -1 ) 
-		Com_DPrintf("ioctl cdrompause failed\n");
-
-	wasPlaying = playing;
-	playing = false;
-	*/
-}
-
-void CDAudio_Play(int track, qboolean looping)
-{
-	if (cdfile == -1 || !enabled)
-		return;
-	if (!cdValid)
-	{
-		CDAudio_GetAudioDiskInfo();
-		if (!cdValid)
-			return;
-	}
-
-	track = remap[track];
-	if (track < 1 || track > maxTrack)
-	{
-		Com_DPrintf("CDAudio: Bad track number %u.\n", track);
-		return;
-	}
-
-	USED(looping);
-	Com_DPrintf("CDAudio_Play: PORTME\n");
-
-	/*
-	struct cdrom_tocentry entry;
-	struct cdrom_ti ti;
-
-	// don't try to play a non-audio track
-	entry.cdte_track = track;
-	entry.cdte_format = CDROM_MSF;
-	if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 )
-	{
-		Com_DPrintf("ioctl cdromreadtocentry failed\n");
-		return;
-	}
-	if (entry.cdte_ctrl == CDROM_DATA_TRACK)
-	{
-		Com_Printf("CDAudio: track %i is not audio\n", track);
-		return;
-	}
-
-	if (playing)
-	{
-		if (playTrack == track)
-			return;
-		CDAudio_Stop();
-	}
-
-	ti.cdti_trk0 = track;
-	ti.cdti_trk1 = track;
-	ti.cdti_ind0 = 1;
-	ti.cdti_ind1 = 99;
-	if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 ) 
-	{
-		Com_DPrintf("ioctl cdromplaytrkind failed\n");
-		return;
-	}
-	if ( ioctl(cdfile, CDROMRESUME) == -1 ) 
-		Com_DPrintf("ioctl cdromresume failed\n");
-
-	playLooping = looping;
-	playTrack = track;
-	playing = true;
-
-	if (cd_volume->value == 0.0)
-		CDAudio_Pause ();
-	*/
-}
-
-
-void CDAudio_Stop(void)
-{
-	if (cdfile == -1 || !enabled)
-		return;
-	if (!playing)
-		return;
-
-	Com_DPrintf("CDAudio_Stop: PORTME\n");
-
-	/*
-	if ( ioctl(cdfile, CDROMSTOP) == -1 )
-		Com_DPrintf("ioctl cdromstop failed (%d)\n", errno);
-
-	wasPlaying = false;
-	playing = false;
-	*/
-}
-
-void CDAudio_Resume(void)
-{
-	if (cdfile == -1 || !enabled)
-		return;
-	if (!cdValid)
-		return;
-	if (!wasPlaying)
-		return;
-
-	Com_DPrintf("CDAudio_Stop: PORTME\n");
-
-	/*
-	if ( ioctl(cdfile, CDROMRESUME) == -1 ) 
-		Com_DPrintf("ioctl cdromresume failed\n");
-	playing = true;
-	*/
-}
-
-static void CD_f (void)
-{
-	char	*command;
-	int n, ret;
-
-	if (Cmd_Argc() < 2)
-		return;
-
-	command = Cmd_Argv (1);
-
-	if (cistrcmp(command, "on") == 0)
-	{
-		enabled = true;
-		return;
-	}
-
-	if (cistrcmp(command, "off") == 0)
-	{
-		if (playing)
-			CDAudio_Stop();
-		enabled = false;
-		return;
-	}
-
-	if (cistrcmp(command, "reset") == 0)
-	{
-		enabled = true;
-		if (playing)
-			CDAudio_Stop();
-		for (n = 0; n < 100; n++)
-			remap[n] = n;
-		CDAudio_GetAudioDiskInfo();
-		return;
-	}
-
-	if (cistrcmp(command, "remap") == 0)
-	{
-		ret = Cmd_Argc() - 2;
-		if (ret <= 0)
-		{
-			for (n = 1; n < 100; n++)
-				if (remap[n] != n)
-					Com_Printf("  %u -> %u\n", n, remap[n]);
-			return;
-		}
-		for (n = 1; n <= ret; n++)
-			remap[n] = atoi(Cmd_Argv (n+1));
-		return;
-	}
-
-	if (cistrcmp(command, "close") == 0)
-	{
-		CDAudio_CloseDoor();
-		return;
-	}
-
-	if (!cdValid)
-	{
-		CDAudio_GetAudioDiskInfo();
-		if (!cdValid)
-		{
-			Com_Printf("No CD in player.\n");
-			return;
-		}
-	}
-
-	if (cistrcmp(command, "play") == 0)
-	{
-		CDAudio_Play((byte)atoi(Cmd_Argv (2)), false);
-		return;
-	}
-
-	if (cistrcmp(command, "loop") == 0)
-	{
-		CDAudio_Play((byte)atoi(Cmd_Argv (2)), true);
-		return;
-	}
-
-	if (cistrcmp(command, "stop") == 0)
-	{
-		CDAudio_Stop();
-		return;
-	}
-
-	if (cistrcmp(command, "pause") == 0)
-	{
-		CDAudio_Pause();
-		return;
-	}
-
-	if (cistrcmp(command, "resume") == 0)
-	{
-		CDAudio_Resume();
-		return;
-	}
-
-	if (cistrcmp(command, "eject") == 0)
-	{
-		if (playing)
-			CDAudio_Stop();
-		CDAudio_Eject();
-		cdValid = false;
-		return;
-	}
-
-	if (cistrcmp(command, "info") == 0)
-	{
-		Com_Printf("%u tracks\n", maxTrack);
-		if (playing)
-			Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
-		else if (wasPlaying)
-			Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
-		Com_Printf("Volume is %f\n", cdvolume);
-		return;
-	}
-}
-
-void CDAudio_Update(void)
-{
-	if (cdfile == -1 || !enabled)
-		return;
-	if (cd_volume && cd_volume->value != cdvolume)
-	{
-		if (cdvolume)
-		{
-			Cvar_SetValue ("cd_volume", 0.0);
-			cdvolume = cd_volume->value;
-			CDAudio_Pause ();
-		}
-		else
-		{
-			Cvar_SetValue ("cd_volume", 1.0);
-			cdvolume = cd_volume->value;
-			CDAudio_Resume ();
-		}
-	}
-
-	Com_DPrintf("CDAudio_Stop: PORTME\n");
-
-	/*
-	struct cdrom_subchnl subchnl;
-	static time_t lastchk;
-
-	if (playing && lastchk < time(NULL)) {
-		lastchk = time(NULL) + 2; //two seconds between chks
-		subchnl.cdsc_format = CDROM_MSF;
-		if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) {
-			Com_DPrintf("ioctl cdromsubchnl failed\n");
-			playing = false;
-			return;
-		}
-		if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY &&
-			subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) {
-			playing = false;
-			if (playLooping)
-				CDAudio_Play(playTrack, true);
-		}
-	}
-	*/
-}
-
-int CDAudio_Init(void)
-{
-	int i;
-	cvar_t	*cv;
-
-	cv = Cvar_Get ("nocdaudio", "0", CVAR_NOSET);
-	if (cv->value)
-		return -1;
-
-	cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
-	if ( cd_nocd->value)
-		return -1;
-
-	cd_volume = Cvar_Get ("cd_volume", "1", CVAR_ARCHIVE);
-
-	cd_dev = Cvar_Get("cd_dev", "/dev/cdrom", CVAR_ARCHIVE);
-
-	if((cdfile = open(cd_dev->string, OREAD)) < 0){
-		fprint(2, "CDAudio_Init: %r\n");
-		Com_Printf("CDAudio_Init: failed to open \"%s\"\n", cd_dev->string);
-		cdfile = -1;
-		return -1;
-	}
-
-	for (i = 0; i < 100; i++)
-		remap[i] = i;
-	initialized = true;
-	enabled = true;
-
-	if (CDAudio_GetAudioDiskInfo())
-	{
-		Com_Printf("CDAudio_Init: No CD in player.\n");
-		cdValid = false;
-	}
-
-	Cmd_AddCommand ("cd", CD_f);
-
-	Com_Printf("CD Audio Initialized\n");
-
-	return 0;
-}
-
-void CDAudio_Activate (qboolean active)
-{
-	if (active)
-		CDAudio_Resume ();
-	else
-		CDAudio_Pause ();
-}
-
-void CDAudio_Shutdown(void)
-{
-	if (!initialized)
-		return;
-	CDAudio_Stop();
-	close(cdfile);
-	cdfile = -1;
-}
--- a/plan9/in.c
+++ /dev/null
@@ -1,454 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <draw.h>
-#include <thread.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include "../q_shared.h"
-
-extern int resized;		/* vid.c */
-extern Point center;
-extern Channel *fuckchan, *tchan;	/* sys.c */
-
-cvar_t *in_joystick;
-cvar_t *sensitivity;
-cvar_t *lookstrafe;
-cvar_t *lookspring;
-cvar_t *freelook;
-cvar_t *m_pitch;
-
-static cvar_t *m_filter;
-static cvar_t *m_windowed;
-static cvar_t *m_yaw;
-static cvar_t *m_side;
-static cvar_t *m_forward;
-
-static int mouseon;
-static int mlooking;
-static int dx, dy;
-static int oldmwin;
-
-typedef struct Kev Kev;
-struct Kev{
-	int key;
-	int down;
-};
-enum{
-	Nbuf	= 64
-};
-static Channel *kchan, *mchan;
-static int iop = -1, pfd[2];
-static QLock killock;
-
-
-char *
-Sys_ConsoleInput(void)
-{
-	static char buf[256];
-	int n;
-
-	if(dedicated != nil && dedicated->value && iop >= 0){
-		if(flen(pfd[1]) < 1)	/* only poll for input */
-			return nil;
-		if((n = read(pfd[1], buf, sizeof buf)) < 0)
-			sysfatal("Sys_ConsoleInput:read: %r");
-		if(n == 0){
-			iop = -1;
-			return nil;
-		}
-		return buf;
-	}
-	return nil;
-}
-
-void
-IN_Grabm(int on)
-{
-	static char nocurs[2*4+2*2*16];
-	static int fd = -1;
-
-	if(mouseon == on)
-		return;
-	if(mouseon = on && m_windowed->value){
-		if((fd = open("/dev/cursor", ORDWR|OCEXEC)) < 0){
-			sysfatal("IN_Grabm:open: %r\n");
-			return;
-		}
-		write(fd, nocurs, sizeof nocurs);
-	}else if(fd >= 0){
-		close(fd);
-		fd = -1;
-	}
-}
-
-void
-IN_Commands(void)
-{
-	/* joystick stuff */
-}
-
-void
-btnev(int btn, ulong msec)
-{
-	static int oldb;
-	int i, b;
-
-	for(i = 0; i < 3; i++){
-		b = 1<<i;
-		if(btn & b && ~oldb & b)
-			Key_Event(K_MOUSE1+i, true, msec);
-		else if(~btn & b && oldb & b)
-			Key_Event(K_MOUSE1+i, false, msec);
-	}
-	oldb = btn;
-	/* mwheelup and mwheeldn buttons are never held down */
-	for(i = 3; i < 5; i++){
-		b = 1<<i;
-		if(btn & b){
-			Key_Event(K_MOUSE1+i, true, msec);
-			Key_Event(K_MOUSE1+i, false, msec);
-		}
-	}
-}
-
-void
-KBD_Update(void)
-{
-	int r;
-	Kev ev;
-	Mouse m;
-
-	if(oldmwin != m_windowed->value){
-		oldmwin = m_windowed->value;
-		IN_Grabm(m_windowed->value);
-	}
-	while((r = nbrecv(kchan, &ev)) > 0)
-		Key_Event(ev.key, ev.down, Sys_Milliseconds());
-	if(r < 0)
-		sysfatal("KBD_Update:nbrecv: %r\n");
-	while((r = nbrecv(mchan, &m)) > 0){
-		dx += m.xy.x;
-		dy += m.xy.y;
-		btnev(m.buttons, m.msec);
-	}
-	if(r < 0)
-		sysfatal("KBD_Update:nbrecv: %r\n");
-}
-
-void
-IN_Move(usercmd_t *cmd)
-{
-	static int oldmx, oldmy;
-	int mx, my;
-
-	if(!mouseon)
-		return;
-
-	if(m_filter->value){
-		mx = (dx + oldmx) * 0.5;
-		my = (dy + oldmy) * 0.5;
-	}else{
-		mx = dx;
-		my = dy;
-	}
-	oldmx = dx;
-	oldmy = dy;
-	dx = dy = 0;
-	if(!mx && !my)
-		return;
-	mx *= sensitivity->value;
-	my *= sensitivity->value;
-
-	/* add mouse x/y movement to cmd */
-	if(in_strafe.state & 1 || lookstrafe->value && mlooking)
-		cmd->sidemove += m_side->value * mx;
-	else
-		cl.viewangles[YAW] -= m_yaw->value * mx;
-	if((mlooking || freelook->value) && ~in_strafe.state & 1)
-		cl.viewangles[PITCH] += m_pitch->value * my;
-	else
-		cmd->forwardmove -= m_forward->value * my;
-}
-
-/* called on focus/unfocus in win32 */
-void
-IN_Activate(qboolean)
-{
-}
-
-/* called every frame even if not generating commands */
-void
-IN_Frame(void)
-{
-}
-
-void
-IN_ForceCenterView(void)
-{
-	cl.viewangles[PITCH] = 0;
-}
-
-void
-IN_MLookDown(void)
-{
-	mlooking = true;
-}
-
-void
-IN_MLookUp(void)
-{
-	mlooking = false;
-	IN_CenterView();
-}
-
-static int
-runetokey(Rune r)
-{
-	int k = 0;
-
-	switch(r){
-	case Kpgup:	k = K_PGUP; break;
-	case Kpgdown:	k = K_PGDN; break;
-	case Khome:	k = K_HOME; break;
-	case Kend:	k = K_END; break;
-	case Kleft:	k = K_LEFTARROW; break;
-	case Kright:	k = K_RIGHTARROW; break;
-	case Kdown:	k = K_DOWNARROW; break;
-	case Kup:	k = K_UPARROW; break;
-	case Kesc:	k = K_ESCAPE; break;
-	case '\n':	k = K_ENTER; break;
-	case '\t':	k = K_TAB; break;
-	case KF|1:	k = K_F1; break;
-	case KF|2:	k = K_F2; break;
-	case KF|3:	k = K_F3; break;
-	case KF|4:	k = K_F4; break;
-	case KF|5:	k = K_F5; break;
-	case KF|6:	k = K_F6; break;
-	case KF|7:	k = K_F7; break;
-	case KF|8:	k = K_F8; break;
-	case KF|9:	k = K_F9; break;
-	case KF|10:	k = K_F10; break;
-	case KF|11:	k = K_F11; break;
-	case KF|12:	k = K_F12; break;
-	case Kbs:	k = K_BACKSPACE; break;
-	case Kdel:	k = K_DEL; break;
-	case Kbreak:	k = K_PAUSE; break;
-	case Kshift:	k = K_SHIFT; break;
-	case Kctl:	k = K_CTRL; break;
-	case Kalt:
-	case Kaltgr:	k = K_ALT; break;
-	case Kins:	k = K_INS; break;
-	default:
-		if(r < 0x80)
-			k = r;
-	};
-	return k;
-}
-
-static void
-kproc(void *)
-{
-	int n, k, fd;
-	char buf[128], kdown[128], *s;
-	Rune r;
-	Kev ev;
-
-	if(threadsetgrp(THin) < 0)
-		sysfatal("kproc:threadsetgrp: %r");
-	if((fd = open("/dev/kbd", OREAD)) < 0)
-		sysfatal("open /dev/kbd: %r");
-
-	kdown[0] = kdown[1] = 0;
-	while((n = read(fd, buf, sizeof buf)) > 0){
-		buf[n-1] = 0;
-		switch(*buf){
-		case 'c':
-		default:
-			continue;
-		case 'k':
-			s = buf+1;
-			while(*s){
-				s += chartorune(&r, s);
-				if(utfrune(kdown+1, r) == nil){
-					if(k = runetokey(r)){
-						ev.key = k;
-						ev.down = true;
-						if(send(kchan, &ev) < 0)
-							sysfatal("kproc:nbsend: %r\n");
-					}
-				}
-			}
-			break;
-		case 'K':
-			s = kdown+1;
-			while(*s){
-				s += chartorune(&r, s);
-				if(utfrune(buf+1, r) == nil){
-					if(k = runetokey(r)){
-						ev.key = k;
-						ev.down = false;
-						if(send(kchan, &ev) < 0)
-							sysfatal("mproc:nbsend: %r\n");
-					}
-				}
-			}
-			break;
-		}
-		strcpy(kdown, buf);
-	}
-	fprint(2, "kproc: %r\n");
-	close(fd);
-}
-
-static void
-mproc(void *)
-{
-	int n, nerr = 0, fd;
-	char buf[1+5*12];
-	Mouse m;
-
-	if(threadsetgrp(THin) < 0)
-		sysfatal("mproc:threadsetgrp: %r");
-	if((fd = open("/dev/mouse", ORDWR)) < 0)
-		sysfatal("open /dev/mouse: %r");
-
-	for(;;){
-		if((n = read(fd, buf, sizeof buf)) != 1+4*12){
-			fprint(2, "mproc:read: bad count %d not 49: %r\n", n);
-			if(n < 0 || ++nerr > 10)
-				break;
-			continue;
-		}
-		nerr = 0;
-		switch(*buf){
-		case 'r':
-			resized = 1;
-			/* fall through */
-		case 'm':
-			if(!mouseon)
-				break;
-
-			m.xy.x = atoi(buf+1+0*12) - center.x;
-			m.xy.y = atoi(buf+1+1*12) - center.y;
-			if(m.xy.x != 0 || m.xy.y != 0)
-				fprint(fd, "m%d %d", center.x, center.y);
-			m.buttons = atoi(buf+1+2*12);
-			m.msec = atoi(buf+1+3*12);
-			if(nbsend(mchan, &m) < 0)
-				sysfatal("mproc:nbsend: %r\n");
-			break;
-		}
-	}
-	fprint(2, "mproc: %r\n");
-	IN_Grabm(0);
-	close(fd);
-}
-
-static void
-tproc(void *)	/* stupid select() timeout bullshit */
-{
-	int t, ms, n, r;
-
-	threadsetgrp(THin);
-
-	t = ms = 0;
-	for(;;){
-		sleep(1);
-		t++;
-
-		if((r = nbrecv(tchan, &n)) < 0)
-			sysfatal("tproc:nbrecv: %r");
-		if(r == 0){
-			if(t == ms && nbsend(fuckchan, nil) < 0)
-				sysfatal("tproc:nbsend: %r");
-			continue;
-		}
-		if(n <= 0)
-			ms = 0;
-		else{
-			ms = n;
-			t = 0;
-		}
-	}
-}
-
-static void
-iproc(void *)
-{
-	int n;
-	char s[256];
-
-	threadsetgrp(THin);
-
-	if((iop = pipe(pfd)) < 0)
-		sysfatal("iproc:pipe: %r");
-	for(;;){
-		if((n = read(0, s, sizeof s)) <= 0)
-			break;
-		s[n-1] = 0;
-		if((write(pfd[0], s, n)) != n)
-			break;
-		if(nbsend(fuckchan, nil) < 0)
-			sysfatal("iproc:nbsend: %r");
-	}
-	fprint(2, "iproc %d: %r\n", threadpid(threadid()));
-	iop = -1;
-}
-
-void
-IN_Shutdown(void)
-{
-	qlock(&killock);	/* there can be only one */
-	IN_Grabm(0);
-	threadkillgrp(THin);
-	iop = -1;
-	close(pfd[0]);
-	close(pfd[1]);
-	if(kchan != nil){
-		chanfree(kchan);
-		kchan = nil;
-	}
-	if(mchan != nil){
-		chanfree(mchan);
-		mchan = nil;
-	}
-	qunlock(&killock);
-}
-
-void
-IN_Init(void)
-{
-	if(dedicated->value){
-		if(proccreate(iproc, nil, 8192) < 0)
-			sysfatal("proccreate iproc: %r");
-		if(proccreate(tproc, nil, 8192) < 0)
-			sysfatal("proccreate tproc: %r");
-		return;
-	}
-	in_joystick = Cvar_Get("in_joystick", "0", CVAR_ARCHIVE);
-	sensitivity = Cvar_Get("sensitivity", "3", CVAR_ARCHIVE);
-	freelook = Cvar_Get("freelook", "0", CVAR_ARCHIVE);
-	lookspring = Cvar_Get("lookspring", "0", CVAR_ARCHIVE);
-	lookstrafe = Cvar_Get("lookstrafe", "0", CVAR_ARCHIVE);
-	m_pitch = Cvar_Get("m_pitch", "0.022", CVAR_ARCHIVE);
-
-	m_yaw = Cvar_Get("m_yaw", "0.022", 0);
-	m_forward = Cvar_Get("m_forward", "1", 0);
-	m_side = Cvar_Get("m_side", "0.8", 0);
-	m_windowed = Cvar_Get("m_windowed", "0", CVAR_ARCHIVE);
-	m_filter = Cvar_Get("m_filter", "0", 0);
-
-	Cmd_AddCommand("+mlook", IN_MLookDown);
-	Cmd_AddCommand("-mlook", IN_MLookUp);
-	Cmd_AddCommand("force_centerview", IN_ForceCenterView);
-
-	if((kchan = chancreate(sizeof(Kev), Nbuf)) == nil)
-		sysfatal("chancreate kchan: %r");
-	if(proccreate(kproc, nil, 8192) < 0)
-		sysfatal("proccreate kproc: %r");
-	if((mchan = chancreate(sizeof(Mouse), Nbuf)) == nil)
-		sysfatal("chancreate kchan: %r");
-	if(proccreate(mproc, nil, 8192) < 0)
-		sysfatal("proccreate mproc: %r");
-}
--- a/plan9/menu.c
+++ /dev/null
@@ -1,137 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-extern void M_PopMenu(void);
-
-static menuframework_s vmenu;
-static menuslider_s ssizeslide, gammaslide;
-static menulist_s fullscrbox;
-static menuaction_s applyaction, defaultsaction;
-
-
-void
-vmssize(void *s)
-{
-	Cvar_SetValue("viewsize", ((menuslider_s *)s)->curvalue * 10);
-}
-
-void
-vmgamma(void *s)
-{
-	// invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
-	Cvar_SetValue("vid_gamma", 0.8 - (((menuslider_s *)s)->curvalue/10.0 - 0.5) + 0.5);
-}
-
-void
-vmreset(void *)
-{
-	VID_MenuInit();
-}
-
-void
-vmapply(void *)
-{
-	Cvar_SetValue("vid_gamma", 0.8 - (gammaslide.curvalue/10.0 - 0.5) + 0.5);
-	Cvar_SetValue("vid_fullscreen", fullscrbox.curvalue);
-	M_ForceMenuOff();
-}
-
-void
-VID_MenuInit(void)
-{
-	static char *yesno[] = {"no", "yes", nil};
-
-	if(!scr_viewsize)
-		scr_viewsize = Cvar_Get("viewsize", "100", CVAR_ARCHIVE);
-	ssizeslide.curvalue = scr_viewsize->value/10;
-
-	vmenu.x = vid.width * 0.50;
-	vmenu.nitems = 0;
-
-	ssizeslide.generic.type = MTYPE_SLIDER;
-	ssizeslide.generic.x = 0;
-	ssizeslide.generic.y = 20;
-	ssizeslide.generic.name = "screen size";
-	ssizeslide.minvalue = 3;
-	ssizeslide.maxvalue = 12;
-	ssizeslide.generic.callback = vmssize;
-
-	gammaslide.generic.type = MTYPE_SLIDER;
-	gammaslide.generic.x = 0;
-	gammaslide.generic.y = 30;
-	gammaslide.generic.name = "gamma";
-	gammaslide.generic.callback = vmgamma;
-	gammaslide.minvalue = 5;
-	gammaslide.maxvalue = 13;
-	gammaslide.curvalue = (1.3 - vid_gamma->value + 0.5) * 10;
-
-	fullscrbox.generic.type = MTYPE_SPINCONTROL;
-	fullscrbox.generic.x = 0;
-	fullscrbox.generic.y = 40;
-	fullscrbox.generic.name = "fullscreen";
-	fullscrbox.itemnames = yesno;
-	fullscrbox.curvalue = vid_fullscreen->value;
-
-	defaultsaction.generic.type = MTYPE_ACTION;
-	defaultsaction.generic.name = "reset to default";
-	defaultsaction.generic.x = 0;
-	defaultsaction.generic.y = 90;
-	defaultsaction.generic.callback = vmreset;
-
-	applyaction.generic.type = MTYPE_ACTION;
-	applyaction.generic.name = "apply";
-	applyaction.generic.x = 0;
-	applyaction.generic.y = 100;
-	applyaction.generic.callback = vmapply;
-
-	Menu_AddItem(&vmenu, (void *)&ssizeslide);
-	Menu_AddItem(&vmenu, (void *)&gammaslide);
-	Menu_AddItem(&vmenu, (void *)&fullscrbox);
-	Menu_AddItem(&vmenu, (void *)&defaultsaction);
-	Menu_AddItem(&vmenu, (void *)&applyaction);
-
-	Menu_Center(&vmenu);
-	vmenu.x -= 8;
-}
-
-void
-VID_MenuDraw(void)
-{
-	int w, h;
-
-	Draw_GetPicSize(&w, &h, "m_banner_video");
-	Draw_Pic(vid.width/2 - w/2, vid.height/2 - 110, "m_banner_video");
-	Menu_AdjustCursor(&vmenu, 1);	// starting position
-	Menu_Draw(&vmenu);
-}
-
-char *VID_MenuKey (int key)
-{
-	static char *sound = "misc/menu1.wav";
-
-	switch(key){
-	case K_ESCAPE:
-		M_PopMenu();
-		return NULL;
-	case K_UPARROW:
-		vmenu.cursor--;
-		Menu_AdjustCursor(&vmenu, -1);
-		break;
-	case K_DOWNARROW:
-		vmenu.cursor++;
-		Menu_AdjustCursor(&vmenu, 1);
-		break;
-	case K_LEFTARROW:
-		Menu_SlideItem(&vmenu, -1);
-		break;
-	case K_RIGHTARROW:
-		Menu_SlideItem(&vmenu, 1);
-		break;
-	case K_ENTER:
-		Menu_SelectItem(&vmenu);
-		break;
-	}
-	return sound;
-}
--- a/plan9/snd.c
+++ /dev/null
@@ -1,128 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <thread.h>
-#include "../q_shared.h"
-
-static cvar_t *sndbits;
-static cvar_t *sndspeed;
-static cvar_t *sndchannels;
-static cvar_t *snddev;
-
-static int afd, sndon, wpos;
-enum{
-	Nbuf	= 32
-};
-static Channel *schan;
-static QLock sndlock;
-
-
-static void
-sproc(void *)
-{
-	int n;
-
-	threadsetgrp(THsnd);
-
-	for(;;){
-		if(recv(schan, nil) < 0){
-			fprint(2, "sproc:recv %r\n");
-			break;
-		}
-		if((n = write(afd, dma.buffer, dma.samplebits/8 * dma.samples)) < 0){
-			fprint(2, "sproc:write %r\n");
-			break;
-		}
-		qlock(&sndlock);
-		wpos += n;
-		qunlock(&sndlock);
-	}
-	fprint(2, "sproc %d: %r\n", threadpid(threadid()));
-}
-
-qboolean
-SNDDMA_Init(void)
-{
-	if(sndon)
-		return false;
-
-	if(COM_CheckParm("-nosound"))
-		return false;
-
-	if(snddev == nil){
-		sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
-		sndspeed = Cvar_Get("sndspeed", "44100", CVAR_ARCHIVE);
-		sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
-		snddev = Cvar_Get("snddev", "/dev/audio", CVAR_ARCHIVE);
-	}
-
-	if((afd = open(snddev->string, OWRITE)) < 0){
-		fprint(2, "SNDDMA_Init:open %r\n");
-		return false;
-	}
-
-	dma.samplebits = (int)sndbits->value;
-	if(dma.samplebits != 16 && dma.samplebits != 8)
-		dma.samplebits = 16;
-	dma.speed = (int)sndspeed->value;
-	if(dma.speed != 44100)
-		dma.speed = 44100;
-	dma.channels = (int)sndchannels->value;
-	if(dma.channels < 1 || dma.channels > 2)
-		dma.channels = 2;
-	dma.samples = 8192;
-	dma.submission_chunk = 1;
-	if((dma.buffer = mallocz(dma.samplebits/8 * dma.samples, 1)) == nil)
-		sysfatal("SNDDMA_Init:mallocz: %r\n");
-	dma.samplepos = 0;
-	sndon = 1;
-	wpos = 0;
-
-	schan = chancreate(sizeof(int), Nbuf);
-	if(proccreate(sproc, nil, 8192) < 0){
-		SNDDMA_Shutdown();
-		sysfatal("SNDDMA_Init:proccreate: %r\n");
-	}
-	return true;
-}
-
-int
-SNDDMA_GetDMAPos(void)
-{
-	if(!sndon)
-		return 0;
-	qlock(&sndlock);
-	dma.samplepos = wpos / (dma.samplebits/8);
-	qunlock(&sndlock);
-	return dma.samplepos;
-}
-
-void
-SNDDMA_Shutdown(void)
-{
-	if(!sndon)
-		return;
-
-	threadkillgrp(THsnd);
-	close(afd);
-	if(schan != nil){
-		chanfree(schan);
-		schan = nil;
-	}
-	free(dma.buffer);
-	sndon = 0;
-}
-
-void
-SNDDMA_Submit(void)
-{
-	if(nbsend(schan, nil) < 0){
-		fprint(2, "SNDDMA_Submit:nbsend: %r\n");
-		SNDDMA_Shutdown();
-	}
-}
-
-void
-SNDDMA_BeginPainting(void)
-{
-}
--- a/plan9/sys.c
+++ /dev/null
@@ -1,452 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <thread.h>
-#include "../q_shared.h"
-
-void KBD_Update(void);
-
-mainstacksize = 512*1024;
-int curtime;
-uint sys_frame_time;
-Channel *fuckchan, *tchan;
-
-static uchar *membase;
-static int maxhunksize, curhunksize;
-static char findbase[MAX_OSPATH], findpath[MAX_OSPATH], findpattern[MAX_OSPATH];
-static Dir *dirs;
-static long dirn, di;
-
-static int glob_match(char *, char *);
-
-
-/* Like glob_match, but match PATTERN against any final segment of TEXT.  */
-static int
-glob_match_after_star(char *pattern, char *text)
-{
-	char *p = pattern, *t = text;
-	char c, c1;
-
-	while ((c = *p++) == '?' || c == '*')
-		if (c == '?' && *t++ == '\0')
-			return 0;
-
-	if (c == '\0')
-		return 1;
-
-	if (c == '\\')
-		c1 = *p;
-	else
-		c1 = c;
-
-	while (1) {
-		if ((c == '[' || *t == c1) && glob_match(p - 1, t))
-			return 1;
-		if (*t++ == '\0')
-			return 0;
-	}
-}
-
-/* Return nonzero if PATTERN has any special globbing chars in it.  */
-static int
-glob_pattern_p(char *pattern)
-{
-	char *p = pattern;
-	char c;
-	int open = 0;
-
-	while ((c = *p++) != '\0')
-		switch (c) {
-		case '?':
-		case '*':
-			return 1;
-
-		case '[':		/* Only accept an open brace if there is a close */
-			open++;		/* brace to match it.  Bracket expressions must be */
-			continue;	/* complete, according to Posix.2 */
-		case ']':
-			if (open)
-				return 1;
-			continue;
-
-		case '\\':
-			if (*p++ == '\0')
-				return 0;
-		}
-
-	return 0;
-}
-
-/* Match the pattern PATTERN against the string TEXT;
-   return 1 if it matches, 0 otherwise.
-
-   A match means the entire string TEXT is used up in matching.
-
-   In the pattern string, `*' matches any sequence of characters,
-   `?' matches any character, [SET] matches any character in the specified set,
-   [!SET] matches any character not in the specified set.
-
-   A set is composed of characters or ranges; a range looks like
-   character hyphen character (as in 0-9 or A-Z).
-   [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
-   Any other character in the pattern must be matched exactly.
-
-   To suppress the special syntactic significance of any of `[]*?!-\',
-   and match the character exactly, precede it with a `\'.
-*/
-
-static int
-glob_match(char *pattern, char *text)
-{
-	char *p = pattern, *t = text;
-	char c, c1, cstart, cend;
-	int invert;
-
-	while ((c = *p++) != '\0')
-		switch (c) {
-		case '?':
-			if (*t == '\0')
-				return 0;
-			else
-				++t;
-			break;
-
-		case '\\':
-			if (*p++ != *t++)
-				return 0;
-			break;
-
-		case '*':
-			return glob_match_after_star(p, t);
-
-		case '[':
-			{
-				c1 = *t++;
-
-				if (!c1)
-					return (0);
-
-				invert = ((*p == '!') || (*p == '^'));
-				if (invert)
-					p++;
-
-				c = *p++;
-				while (1) {
-					cstart = c;
-					cend = c;
-
-					if (c == '\\') {
-						cstart = *p++;
-						cend = cstart;
-					}
-					if (c == '\0')
-						return 0;
-
-					c = *p++;
-					if (c == '-' && *p != ']') {
-						cend = *p++;
-						if (cend == '\\')
-							cend = *p++;
-						if (cend == '\0')
-							return 0;
-						c = *p++;
-					}
-					if (c1 >= cstart && c1 <= cend)
-						goto match;
-					if (c == ']')
-						break;
-				}
-				if (!invert)
-					return 0;
-				break;
-
-			  match:
-				/* Skip the rest of the [...] construct that already matched.  */
-				while (c != ']') {
-					if (c == '\0')
-						return 0;
-					c = *p++;
-					if (c == '\0')
-						return 0;
-					else if (c == '\\')
-						++p;
-				}
-				if (invert)
-					return 0;
-				break;
-			}
-
-		default:
-			if (c != *t++)
-				return 0;
-		}
-
-	/* if the pattern is empty, Sys_FindNext looks at the current file anyway */
-	return *t == '\0';
-}
-
-void *
-Hunk_Begin(int maxsize)
-{
-	// reserve a huge chunk of memory, but don't commit any yet
-	maxhunksize = maxsize;
-	curhunksize = 0;
-	if((membase = mallocz(maxhunksize, 1)) == nil)
-		sysfatal("Hunk_Begin:malloc %d: %r", maxhunksize);
-	return membase;
-}
-
-void *
-Hunk_Alloc(int size)
-{
-	byte *buf;
-
-	// round to cacheline
-	size = (size+31)&~31;
-	if(curhunksize + size > maxhunksize)
-		Sys_Error("Hunk_Alloc overflow");
-	buf = membase + curhunksize;
-	curhunksize += size;
-	return buf;
-}
-
-int
-Hunk_End(void)
-{
-	if(realloc(membase, curhunksize) != membase)
-		sysfatal("Hunk_End:realloc: %r");
-	return curhunksize;
-}
-
-void
-Hunk_Free(void *base)
-{
-	if(base != nil)
-		free(base);
-}
-
-static qboolean
-CompareAttributes(ulong m, uint musthave, uint canthave)
-{
-	if(m & DMDIR && canthave & SFF_SUBDIR)
-		return false;
-	if(musthave & SFF_SUBDIR && ~m & DMDIR)
-		return false;
-	return true;
-}
-
-char *
-Sys_FindFirst(char *path, uint musthave, uint canhave)
-{
-	char *p;
-	int fd;
-
-	if(dirs != nil)
-		Sys_Error("Sys_BeginFind without close");
-
-	strncpy(findbase, path, sizeof findbase-1);
-	if((p = strrchr(findbase, '/')) != nil){
-		*p = 0;
-		strncpy(findpattern, p+1, sizeof findpattern-1);
-	}else
-		strcpy(findpattern, "*");
-	if(strcmp(findpattern, "*.*") == 0)
-		strcpy(findpattern, "*");
-	if(*findpattern == '\0'){
-		Com_Printf("Sys_BeginFind: empty pattern\n");
-		return nil;
-	}
-
-	if((fd = open(findbase, OREAD)) < 0){
-		fprint(2, "Sys_BeginFind:open: %r\n");
-		return nil;
-	}
-	dirn = dirreadall(fd, &dirs);
-	close(fd);
-	if(dirn == 0)
-		return nil;
-	if(dirn < 0){
-		fprint(2, "Sys_BeginFind:dirread: %r\n");
-		return nil;
-	}
-
-	di = 0;
-	return Sys_FindNext (musthave, canhave);
-}
-
-char *
-Sys_FindNext(uint musthave, uint canhave)
-{
-	int i;
-
-	if(dirs == nil)
-		Sys_Error("Sys_FindNext without open\n");
-
-	while(di < dirn){
-		i = di++;
-		if(glob_match(findpattern, dirs[i].name)){
-			if(CompareAttributes(dirs[i].mode, musthave, canhave)){
-				snprintf(findpath, sizeof findpath, "%s/%s", findbase, dirs[i].name);
-				return findpath;
-			}
-		}
-	}
-	return nil;
-}
-
-void
-Sys_FindClose(void)
-{
-	if(dirs != nil){
-		free(dirs);
-		dirs = nil;
-	}
-}
-
-/* prints to "debugging console" */
-void
-Sys_ConsoleOutput(char *s)
-{
-	write(1, s, strlen(s));
-}
-
-void
-Sys_Error(char *error, ...)
-{ 
-	char buf[1024], *out;
-	va_list arg;
-
-	CL_Shutdown();
-
-	va_start(arg, error);
-	out = vseprint(buf, buf+sizeof(buf), error, arg);
-	va_end(arg);
-	write(2, buf, out-buf);
-	print("\n");
-	sysfatal("ending.");
-}
-
-int
-Sys_Milliseconds(void)
-{
-	static long msbase;
-
-	if(msbase == 0)
-		msbase = time(nil)*1000;
-	curtime = nsec()/1000000 - msbase;
-	return curtime;
-}
-
-void
-Sys_Mkdir(char *path)
-{
-	int d;
-
-	if((d = create(path, OREAD, DMDIR|0777)) < 0)
-		fprint(2, "Sys_Mkdir:create: %r\n");
-	else
-		close(d);
-}
-
-vlong
-flen(int fd)
-{
-	uchar bs[1024];
-
-	if(fstat(fd, bs, sizeof bs) < 0){
-		fprint(2, "flen:fstat: %r\n");
-		return -1;
-	}
-	return *((vlong *)(bs+2+2+4+1+4+8+4+4+4));	/* length[8] */
-}
-
-int
-Sys_FileTime(char *path)
-{
-	uchar sb[1024];
-
-	if(stat(path, sb, sizeof sb) < 0){
-		fprint(2, "Sys_FileTime:stat: %r\n");
-		return -1;
-	}
-	return *((int *)(sb+25));
-}
-
-void
-Sys_UnloadGame(void)
-{
-}
-
-void
-Sys_AppActivate(void)
-{
-}
-
-void
-Sys_SendKeyEvents(void)
-{
-	KBD_Update();
-	sys_frame_time = Sys_Milliseconds();	// grab frame time 
-}
-
-char *
-Sys_GetClipboardData(void)
-{
-	return nil;
-}
-
-void
-Sys_CopyProtect(void)
-{
-}
-
-void
-Sys_Quit(void)
-{
-	chanfree(fuckchan);
-	chanfree(tchan);
-	threadexitsall(nil);
-}
-
-void
-Sys_Init(void)
-{
-	//Sys_SetFPCW();
-	if((fuckchan = chancreate(sizeof(int), 1)) == nil)
-		sysfatal("chancreate fuckchan: %r");
-	if((tchan = chancreate(sizeof(int), 16)) == nil)
-		sysfatal("chancreate tchan: %r");
-}
-
-void
-croak(void *, char *note)
-{
-	if(!strncmp(note, "sys:", 4)){
-		IN_Shutdown();
-		SNDDMA_Shutdown();
-		NET_Shutdown();
-	}
-	noted(NDFLT);
-}
-
-void
-threadmain(int argc, char *argv[])
-{
-	int time, oldtime, newtime;
-
-	setfcr(getfcr() & ~(FPOVFL|FPUNFL|FPINVAL|FPZDIV));	/* assumed ignored in code */
-	notify(croak);
-
-	Qcommon_Init(argc, argv);
-
-	oldtime = Sys_Milliseconds();
-	for(;;){
-		do{
-			newtime = Sys_Milliseconds();
-			time = newtime - oldtime;
-		}while(time < 1);	// find time spent rendering last frame
-		Qcommon_Frame(time);
-		oldtime = newtime;
-	}
-}
--- a/plan9/udp.c
+++ /dev/null
@@ -1,552 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <thread.h>
-#include <bio.h>
-#include <ndb.h>
-#include <ip.h>
-#include "../q_shared.h"
-
-/* FIXME: this shit SUCKS, and ipv4 only because of other code */
-
-extern Channel *fuckchan, *tchan;
-
-static cvar_t *svport;	/* server port and copy of string value */
-static char srv[6];
-static cvar_t *clport;	/* "client" port and copy */
-static char clsrv[6];
-
-typedef struct Loopmsg Loopmsg;
-typedef struct Loopback Loopback;
-typedef struct Conmsg Conmsg;
-typedef struct Conlist Conlist;
-
-enum{
-	Hdrsz		= 16+16+16+2+2,	/* sizeof Udphdr w/o padding */
-	Bufsz		= MAX_MSGLEN,
-	Nbuf		= 64,
-	MAX_LOOPBACK	= 4,
-	CLPORT		= 27909
-};
-struct Loopmsg{
-	byte	data[MAX_MSGLEN];
-	int	datalen;
-};
-struct Loopback{
-	Loopmsg	msgs[MAX_LOOPBACK];
-	int	get;
-	int	send;
-};
-static Loopback loopbacks[2];
-
-struct Conlist{
-	Conlist *p;
-	uchar	u[IPaddrlen+2];
-	char	addr[IPaddrlen*2+8+6];	/* ipv6 + separators + port in decimal */
-	int	dfd;
-	Udphdr	h;
-	int	src;	/* q2 assumes broadcast replies are received on NS_CLIENT */
-};
-static Conlist *cnroot;
-
-struct Conmsg{
-	Conlist *p;
-	int	n;
-	uchar	buf[Bufsz];
-};
-static Channel *udpchan, *clchan;
-
-static netadr_t laddr;		/* 0.0.0.0:0 */
-static int cfd = -1, ufd = -1, clfd = -1, cldfd = -1;
-static QLock cnlock;
-
-
-qboolean
-NET_CompareAdr(netadr_t a, netadr_t b)
-{
-	return(a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port);
-}
-
-/* compares without the port */
-qboolean
-NET_CompareBaseAdr(netadr_t a, netadr_t b)
-{
-	if(a.type != b.type)
-		return false;
-	switch(a.type){
-	case NA_LOOPBACK:
-		return true;
-	case NA_IP:
-		return (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3]);
-	case NA_IPX:
-		return !memcmp(a.ipx, b.ipx, 10);
-	default:
-		return false;
-	}
-}
-
-char *
-NET_AdrToString(netadr_t a)
-{
-	static char s[256];
-
-	seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud:%hud", a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port));
-	return s;
-}
-
-char *
-NET_BaseAdrToString(netadr_t a)
-{
-	static char s[256];
-
-	seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
-	return s;
-}
-
-/*
-=============
-NET_StringToAdr
-
-localhost
-idnewt
-idnewt:28000
-192.246.40.70
-192.246.40.70:28000
-=============
-*/
-qboolean
-NET_StringToAdr(char *addr, netadr_t *a)	/* assumes IPv4 */
-{
-	int i;
-	char s[256], *p, *pp;
-	Ndbtuple *t, *nt;
-
-	if(!strcmp(addr, "localhost")){
-		memset(a, 0, sizeof *a);
-		a->type = NA_LOOPBACK;
-		return true;
-	}
-
-	strncpy(s, addr, sizeof s);
-	s[sizeof(s)-1] = 0;
-
-	/* FIXME: arbitrary length strings */
-	if((p = strrchr(s, ':')) != nil){
-		*p++ = '\0';
-		a->port = BigShort(atoi(p));
-	}
-
-	if((t = dnsquery(nil, s, "ip")) == nil){
-		fprint(2, "NET_StringToAdr:dnsquery %s: %r\n", s);
-		return 0;
-	}
-
-	for(nt = t; nt != nil; nt = nt->entry)
-		if(!strcmp(nt->attr, "ip")){
-			strncpy(s, nt->val, sizeof(s)-1);
-			break;
-		}
-	ndbfree(t);
-
-	/* FIXMEGASHIT */
-	for(i = 0, pp = s; i < IPv4addrlen; i++){
-		if((p = strchr(pp, '.')) != nil)
-			*p++ = '\0';
-		a->ip[i] = atoi(pp);
-		pp = p;
-	}
-	a->type = NA_IP;
-	return true;
-}
-
-qboolean
-NET_IsLocalAddress(netadr_t adr)
-{
-	return NET_CompareAdr(adr, laddr);
-}
-
-static int
-looprecv(netsrc_t sock, netadr_t *net_from, sizebuf_t *d)
-{
-	int i;
-	Loopback *l;
-
-	l = &loopbacks[sock];
-	if(l->send - l->get > MAX_LOOPBACK)
-		l->get = l->send - MAX_LOOPBACK;
-	if(l->get >= l->send)
-		return 0;
-	i = l->get & (MAX_LOOPBACK-1);
-	l->get++;
-
-	memcpy(d->data, l->msgs[i].data, l->msgs[i].datalen);
-	d->cursize = l->msgs[i].datalen;
-	*net_from = laddr;
-	return 1;
-}
-
-static void
-loopsend(netsrc_t sock, int length, void *data, netadr_t /*to*/)
-{
-	Loopback *l;
-	int i;
-
-	l = &loopbacks[sock^1];
-	i = l->send & (MAX_LOOPBACK-1);
-	l->send++;
-	memcpy(l->msgs[i].data, data, length);
-	l->msgs[i].datalen = length;
-}
-
-static void
-cninit(void)
-{
-	if(cnroot != nil)
-		return;
-	if((cnroot = malloc(sizeof *cnroot)) == nil)
-		sysfatal("cninit:malloc: %r");
-	cnroot->p = cnroot;
-	memset(cnroot->u, 0, sizeof cnroot->u);
-	memset(cnroot->addr, 0, sizeof cnroot->addr);
-	cnroot->dfd = -1;
-}
-
-static Conlist *
-cnins(int fd, char *addr, uchar *u, Udphdr *h, int src)
-{
-	Conlist *p, *l;
-
-	l = cnroot;
-	if((p = malloc(sizeof *p)) == nil)
-		sysfatal("cnins:malloc: %r");
-
-	strncpy(p->addr, addr, sizeof p->addr);
-	memcpy(p->u, u, sizeof p->u);
-	p->dfd = fd;
-	if(h != nil)
-		memcpy(&p->h, h, sizeof p->h);
-	p->src = src;
-	p->p = l->p;
-	l->p = p;
-	return p;
-}
-
-static Conlist *
-cnfind(char *raddr)
-{
-	Conlist *p = cnroot->p;
-
-	while(p != cnroot){
-		if(!strncmp(p->addr, raddr, strlen(p->addr)))
-			return p;
-		p = p->p;
-	}
-	return nil;
-}
-
-static void
-cndel(Conlist *p)
-{
-	Conlist *l = cnroot;
-
-	while(l->p != p){
-		l = l->p;
-		if(l == cnroot)
-			sysfatal("cndel: bad unlink: cnroot 0x%p node 0x%p\n", cnroot, p);
-	}
-	l->p = p->p;
-	if(p->dfd != ufd && p->dfd != cldfd && p->dfd != -1)
-		close(p->dfd);
-	free(p);
-}
-
-static void
-cnnuke(void)
-{
-	Conlist *p, *l = cnroot;
-
-	if(cnroot == nil)
-		return;
-	do{
-		p = l;
-		l = l->p;
-		if(p->dfd != -1)
-			close(p->dfd);
-		free(p);
-	}while(l != cnroot);
-	cnroot = nil;
-}
-
-static void
-dproc(void *me)
-{
-	int n, fd;
-	Conmsg m;
-	Conlist *p;
-	Channel *c;
-
-	threadsetgrp(THnet);
-
-	m.p = p = me;
-	c = p->src == NS_CLIENT ? clchan : udpchan;
-	fd = p->dfd;
-
-	for(;;){
-		if((n = read(fd, m.buf, sizeof m.buf)) <= 0)
-			break;
-		m.n = n;
-		if(send(c, &m) < 0)
-			sysfatal("uproc:send: %r");
-		if(nbsend(fuckchan, nil) < 0)
-			sysfatal("uproc:nbsend; %r");
-	}
-	fprint(2, "dproc %d: %r\n", threadpid(threadid()));
-	cndel(me);
-}
-
-static void
-uproc(void *c)
-{
-	int n, fd;
-	uchar udpbuf[Bufsz+Hdrsz], u[IPaddrlen+2];
-	char a[IPaddrlen*2+8+6];
-	Udphdr h;
-	Conmsg m;
-	Conlist *p;
-
-	threadsetgrp(THnet);
-
-	fd = ufd;
-	if(c == clchan)
-		fd = cldfd;
-	for(;;){
-		if((n = read(fd, udpbuf, sizeof udpbuf)) <= 0)
-			sysfatal("uproc:read: %r");
-		memcpy(&h, udpbuf, Hdrsz);
-
-		memcpy(u, h.raddr, IPaddrlen);
-		memcpy(u+IPaddrlen, h.rport, 2);
-		snprint(a, sizeof a, "%ud.%ud.%ud.%ud:%hud", u[12], u[13], u[14], u[15], u[16]<<8 | u[17]);
-		qlock(&cnlock);
-		if((p = cnfind(a)) == nil)
-			p = cnins(fd, a, u, &h, 0);
-		qunlock(&cnlock);
-		m.p = p;
-
-		if(n - Hdrsz < 0){	/* FIXME */
-			m.n = n;
-			memcpy(m.buf, udpbuf, m.n);
-		}else{
-			m.n = n - Hdrsz;
-			memcpy(m.buf, udpbuf+Hdrsz, m.n);
-		}
-		if(send(c, &m) < 0)
-			sysfatal("uproc:send: %r");
-		if(nbsend(fuckchan, nil) < 0)
-			sysfatal("uproc:nbsend: %r");
-	}
-}
-
-qboolean
-NET_GetPacket(netsrc_t src, netadr_t *from, sizebuf_t *d)
-{
-	int n;
-	Conmsg m;
-
-	if(looprecv(src, from, d))
-		return true;
-	if(cfd == -1)
-		return false;
-
-	if((n = nbrecv(src == NS_SERVER ? udpchan : clchan, &m)) < 0)
-		sysfatal("NET_GetPacket:nbrecv: %r");
-	if(n == 0)
-		return false;
-
-	memcpy(from->ip, m.p->u+12, 4);
-	from->port = m.p->u[17] << 8 | m.p->u[16];
-	if(m.n == d->maxsize){
-		Com_Printf("Oversize packet from %s\n", NET_AdrToString(*from));
-		return false;
-	}
-	from->type = NA_IP;
-	d->cursize = m.n;
-	memcpy(d->data, m.buf, m.n);
-	return true;
-}
-
-void
-NET_SendPacket(netsrc_t src, int length, void *data, netadr_t to)
-{
-	int fd;
-	char *addr, *s, *lport;
-	uchar b[Bufsz+Hdrsz], u[IPaddrlen+2];
-	Conlist *p;
-
-	switch(to.type){
-	case NA_LOOPBACK:
-		loopsend(src, length, data, to);
-		break;
-	case NA_BROADCAST_IPX:
-	case NA_IPX:
-		break;
-	case NA_BROADCAST:
-		memset(to.ip, 0xff, 4);
-		addr = NET_AdrToString(to);	/* port is PORT_SERVER */
-		s = strrchr(addr, ':');
-		*s++ = '\0';
-		if((fd = dial(netmkaddr(addr, "udp", s), clsrv, nil, nil)) < 0)
-			sysfatal("NET_SendPacket:dial bcast: %r");
-		if(write(fd, data, length) != length)
-			sysfatal("NET_SendPacket:write bcast: %r");
-		close(fd);
-		break;
-	case NA_IP:
-		if(cfd == -1)
-			break;
-
-		addr = NET_AdrToString(to);
-		qlock(&cnlock);
-		p = cnfind(addr);
-		qunlock(&cnlock);
-		if(p != nil){
-			fd = p->dfd;
-			if(fd == ufd || fd == cldfd){
-				memcpy(b, &p->h, Hdrsz);
-				memcpy(b+Hdrsz, data, length);
-				write(fd, b, length+Hdrsz);
-				break;
-			}
-		}else{
-			lport = strrchr(addr, ':');
-			*lport++ = '\0';
-			s = netmkaddr(addr, "udp", lport);
-			if((fd = dial(s, srv, nil, nil)) < 0)
-				sysfatal("NET_SendPacket:dial: %r");
-
-			memcpy(u, v4prefix, sizeof v4prefix);
-			memcpy(u+IPv4off, to.ip, IPv4addrlen);
-			u[16] = to.port;
-			u[17] = to.port >> 8;
-			*(lport-1) = ':';
-			qlock(&cnlock);
-			p = cnins(fd, addr, u, nil, src);
-			qunlock(&cnlock);
-
-			if(proccreate(dproc, p, 8196) < 0)
-				sysfatal("NET_SendPacket:proccreate: %r");
-		}
-		if(write(fd, data, length) != length)
-			sysfatal("NET_SendPacket:write: %r");
-		break;
-	default:
-		Com_Error(ERR_FATAL, "NET_SendPacket: bad address type");
-	}
-}
-
-void
-NET_Sleep(int ms)	/* sleep for ms, or wakeup for stdio or incoming packets */
-{
-	if(cfd == -1 || dedicated != nil && !dedicated->value)
-		return; // we're not a server, just run full speed
-
-	if(send(tchan, &ms) < 0)
-		sysfatal("NET_Sleep:send: %r");
-	if(recv(fuckchan, nil) < 0)
-		sysfatal("NET_Sleep:recv: %r");
-	ms = -1;
-	if(nbsend(tchan, &ms) < 0)	/* stop timer */
-		sysfatal("NET_Sleep:nbsend: %r");
-}
-
-static int
-openname(char *port, int *dfd, Channel **c)
-{
-	int fd;
-	char data[64], adir[40];
-
-	if((fd = announce(netmkaddr("*", "udp", port), adir)) < 0)
-		sysfatal("openname:announce udp!*!%s: %r", port);
-	if(fprint(fd, "headers") < 0)
-		sysfatal("openname: failed to set header mode: %r");
-	snprint(data, sizeof data, "%s/data", adir);
-	if((*dfd = open(data, ORDWR)) < 0)
-		sysfatal("openname:open %r");
-	if((*c = chancreate(sizeof(Conmsg), Nbuf)) == nil)
-		sysfatal("openname:chancreate: %r");
-	if(proccreate(uproc, *c, 8192) < 0)
-		sysfatal("openname:proccreate: %r");
-	return fd;
-}
-
-static void
-openudp(void)
-{
-	if(cfd != -1)
-		return;
-
-	/* svport value can be changed at any time */
-	if(svport->value == PORT_ANY || svport->value > 32767)
-		/* FIXME */
-		strncpy(srv, "*", sizeof(srv)-1);
-	else
-		strncpy(srv, svport->string, sizeof(srv)-1);
-	cfd = openname(srv, &ufd, &udpchan);
-
-	/* broadcast kluge */
-	if(clport->value == PORT_ANY || clport->value > 32767)
-		strncpy(clsrv, "*", sizeof(clsrv)-1);
-	else
-		strncpy(clsrv, clport->string, sizeof(clsrv)-1);
-	clfd = openname(clsrv, &cldfd, &clchan);
-}
-
-/* a single player game will only use the loopback code */
-void
-NET_Config(qboolean multiplayer)
-{
-	if(!multiplayer){	/* shut down existing udp connections */
-		threadkillgrp(THnet);
-		cnnuke();
-		if(udpchan != nil){
-			chanfree(udpchan);
-			udpchan = nil;
-		}
-		if(clchan != nil){
-			chanfree(clchan);
-			clchan = nil;
-		}
-		if(cfd != -1){
-			close(cfd);
-			cfd = -1;
-		}
-		if(clfd != -1){
-			close(clfd);
-			clfd = -1;
-		}
-		if(ufd != -1){
-			close(ufd);
-			ufd = -1;
-		}
-		if(cldfd != -1){
-			close(cldfd);
-			cldfd = -1;
-		}
-	}else{			/* announce open line and get cfd for it */
-		cninit();
-		openudp();
-	}
-}
-
-void
-NET_Shutdown(void)
-{
-	NET_Config(false);
-}
-
-void
-NET_Init(void)
-{
-	svport = Cvar_Get("port", va("%hu", PORT_SERVER), CVAR_NOSET);
-	clport = Cvar_Get("clport", va("%hu", CLPORT), CVAR_NOSET);
-}
--- a/plan9/vid.c
+++ /dev/null
@@ -1,249 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <stdio.h>
-#include <ctype.h>
-#include "../q_shared.h"
-
-refexport_t re;	/* exported functions from refresh DLL */
-int resized;
-Point center;
-
-typedef ulong PIXEL;
-
-static int rwon;
-static uchar *framebuf;
-static Image *fbim;
-static PIXEL st2d_8to24table[256];
-static int shiftmask_fl;
-static int r_shift, g_shift, b_shift;
-static uint r_mask, g_mask, b_mask;
-
-refexport_t GetRefAPI(refimport_t);
-
-
-static void
-shiftmask_init(void)
-{
-	uint x;
-
-	r_mask = 0xff0000;
-	g_mask = 0xff00;
-	b_mask = 0xff;
-	for(r_shift = -8, x = 1; x < r_mask; x <<= 1)
-		r_shift++;
-	for(g_shift = -8, x = 1; x < g_mask; x <<= 1)
-		g_shift++;
-	for(b_shift = -8, x = 1; x < b_mask; x <<= 1)
-		b_shift++;
-	shiftmask_fl = 1;
-}
-
-static PIXEL
-rgb24(int r, int g, int b)
-{
-	PIXEL p = 0;
-
-	if(shiftmask_fl == 0)
-		shiftmask_init();
-
-	if(r_shift > 0)
-		p = r<<r_shift & r_mask;
-	else if(r_shift < 0)
-        	p = r>>-r_shift & r_mask;
-	else
-		p |= r & r_mask;
-	if(g_shift > 0)
-		p |= g<<g_shift & g_mask;
-	else if(g_shift < 0)
-		p |= g>>-g_shift & g_mask;
-	else
-		p |= g & g_mask;
-	if(b_shift > 0)
-		p |= b<<b_shift & b_mask;
-	else if(b_shift < 0)
-		p |= b>>-b_shift & b_mask;
-	else
-		p |= b & b_mask;
-	return p;
-}
-
-static void
-st3_fixup(void)
-{
-	int x, y;
-	uchar *src;
-	PIXEL *dest;
-
-	for(y = 0; y < vid.height; y++){
-		src = &framebuf[y*vid.rowbytes];
-		dest = (PIXEL*)src;
-
-		/* vid.width % 8 not always 0
-		for(x = vid.width-1; x >= 0; x -= 8) {
-			dest[x  ] = st2d_8to24table[src[x  ]];
-			dest[x-1] = st2d_8to24table[src[x-1]];
-			dest[x-2] = st2d_8to24table[src[x-2]];
-			dest[x-3] = st2d_8to24table[src[x-3]];
-			dest[x-4] = st2d_8to24table[src[x-4]];
-			dest[x-5] = st2d_8to24table[src[x-5]];
-			dest[x-6] = st2d_8to24table[src[x-6]];
-			dest[x-7] = st2d_8to24table[src[x-7]];
-		}
-		*/
-
-		for(x = vid.width-1; x >= 0; x--)
-			dest[x] = st2d_8to24table[src[x]];
-	}
-}
-
-static void
-resetfb(void)
-{
-	vid.width = Dx(screen->r);
-	vid.height = Dy(screen->r);
-	if(framebuf != nil){
-		free(framebuf);
-		framebuf = nil;
-	}
-	if(fbim != nil){
-		freeimage(fbim);
-		fbim = nil;
-	}
-	if((framebuf = malloc(sizeof *framebuf * vid.width * vid.height * screen->depth/8)) == nil)
-		sysfatal("resetfb:malloc: %r");
-	if((fbim = allocimage(display, Rect(0, 0, vid.width, vid.height), screen->chan, 1, DNofill)) == nil)
-		sysfatal("resetfb: %r");
-	vid.buffer = framebuf;
-	vid.rowbytes = vid.width * screen->depth/8;
-	center = addpt(screen->r.min, Pt(vid.width/2, vid.height/2));
-	sw_mode->modified = true;	/* make ref_soft refresh its shit */
-}
-
-int
-SWimp_Init(void *, void *)
-{
-	srand(getpid());
-
-	if(initdraw(nil, nil, "quake2") < 0)
-		sysfatal("VID_Init:initdraw: %r\n");
-	resetfb();
-	rwon = 1;
-	return 1;
-}
-
-/* copy backbuffer to front buffer */
-void
-SWimp_EndFrame(void)
-{
-	if(resized){		/* skip frame if window resizes */
-		resized = 0;
-		if(getwindow(display, Refnone) < 0)
-			sysfatal("SWimp_EndFrame:getwindow: %r\n");
-		resetfb();
-		return;
-	}
-	st3_fixup();
-	loadimage(fbim, fbim->r, framebuf, vid.height * vid.rowbytes);
-	draw(screen, screen->r, fbim, nil, ZP);
-	flushimage(display, 1);
-}
-
-rserr_t
-SWimp_SetMode(int */*pwidth*/, int */*pheight*/, int /*mode*/, qboolean /*fullscreen*/)
-{
-	return rserr_ok;
-}
-
-/* nil palette == use existing; palette is expected to be in padded 4-byte xRGB format */
-void
-SWimp_SetPalette(uchar *palette)
-{
-	int i;
-
-	if(!rwon)
-		return;
-	if(!palette)
-        	palette = (uchar *)sw_state.currentpalette;
-	for(i = 0; i < 256; i++)
-		st2d_8to24table[i] = rgb24(palette[i*4], palette[i*4+1], palette[i*4+2]);
-}
-
-void
-SWimp_Shutdown(void)
-{
-	if(!rwon)
-		return;
-	if(framebuf != nil)
-		free(framebuf);
-	if(fbim != nil)
-		freeimage(fbim);
-	rwon = 0;
-}
-
-void
-SWimp_AppActivate(qboolean /*active*/)
-{
-}
-
-void
-VID_Printf(int print_level, char *fmt, ...)
-{
-	va_list argptr;
-	char msg[4096];
-	
-	va_start(argptr, fmt);
-	vsprintf(msg, fmt, argptr);
-	va_end(argptr);
-	if(print_level == PRINT_ALL)
-		Com_Printf("%s", msg);
-	else
-		Com_DPrintf("%s", msg);
-}
-
-void
-VID_Error(int err_level, char *fmt, ...)
-{
-	va_list argptr;
-	char msg[4096];
-	
-	va_start(argptr, fmt);
-	vsprintf(msg, fmt, argptr);
-	va_end(argptr);
-	Com_Error(err_level, "%s", msg);
-}
-
-void
-VID_CheckChanges(void)
-{
-}
-
-void
-VID_Shutdown(void)
-{
-	R_Shutdown();
-}
-
-void
-VID_Init(void)
-{
-	refimport_t ri;
-
-	ri.Cmd_AddCommand = Cmd_AddCommand;
-	ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
-	ri.Cmd_Argc = Cmd_Argc;
-	ri.Cmd_Argv = Cmd_Argv;
-	ri.Cmd_ExecuteText = Cbuf_ExecuteText;
-	ri.Con_Printf = VID_Printf;
-	ri.Sys_Error = VID_Error;
-	ri.FS_LoadFile = FS_LoadFile;
-	ri.FS_FreeFile = FS_FreeFile;
-	ri.FS_Gamedir = FS_Gamedir;
-	ri.Cvar_Get = Cvar_Get;
-	ri.Cvar_Set = Cvar_Set;
-	ri.Cvar_SetValue = Cvar_SetValue;
-	ri.Vid_MenuInit = VID_MenuInit;
-
-	re = GetRefAPI(ri);
-	re.Init(nil, nil);
-}
--- /dev/null
+++ b/pmove.c
@@ -1,0 +1,1338 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+#define	STEPSIZE	18
+
+// all of the locals will be zeroed before each
+// pmove, just to make damn sure we don't have
+// any differences when running on client or server
+
+typedef struct
+{
+	vec3_t		origin;			// full float precision
+	vec3_t		velocity;		// full float precision
+
+	vec3_t		forward, right, up;
+	float		frametime;
+
+
+	csurface_t	*groundsurface;
+	cplane_t	groundplane;
+	int			groundcontents;
+
+	vec3_t		previous_origin;
+	qboolean	ladder;
+} pml_t;
+
+pmove_t		*pm;
+pml_t		pml;
+
+
+// movement parameters
+float	pm_stopspeed = 100;
+float	pm_maxspeed = 300;
+float	pm_duckspeed = 100;
+float	pm_accelerate = 10;
+float	pm_airaccelerate = 0;
+float	pm_wateraccelerate = 10;
+float	pm_friction = 6;
+float	pm_waterfriction = 1;
+float	pm_waterspeed = 400;
+
+/*
+
+  walking up a step should kill some velocity
+
+*/
+
+
+/*
+==================
+PM_ClipVelocity
+
+Slide off of the impacting object
+returns the blocked flags (1 = floor, 2 = step / wall)
+==================
+*/
+#define	STOP_EPSILON	0.1
+
+void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
+{
+	float	backoff;
+	float	change;
+	int		i;
+	
+	backoff = DotProduct (in, normal) * overbounce;
+
+	for (i=0 ; i<3 ; i++)
+	{
+		change = normal[i]*backoff;
+		out[i] = in[i] - change;
+		if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
+			out[i] = 0;
+	}
+}
+
+
+
+
+/*
+==================
+PM_StepSlideMove
+
+Each intersection will try to step over the obstruction instead of
+sliding along it.
+
+Returns a new origin, velocity, and contact entity
+Does not modify any world state?
+==================
+*/
+#define	MIN_STEP_NORMAL	0.7		// can't step up onto very steep slopes
+#define	MAX_CLIP_PLANES	5
+void PM_StepSlideMove_ (void)
+{
+	int			bumpcount, numbumps;
+	vec3_t		dir;
+	float		d;
+	int			numplanes;
+	vec3_t		planes[MAX_CLIP_PLANES];
+	vec3_t		primal_velocity;
+	int			i, j;
+	trace_t	trace;
+	vec3_t		end;
+	float		time_left;
+	
+	numbumps = 4;
+	
+	VectorCopy (pml.velocity, primal_velocity);
+	numplanes = 0;
+	
+	time_left = pml.frametime;
+
+	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
+	{
+		for (i=0 ; i<3 ; i++)
+			end[i] = pml.origin[i] + time_left * pml.velocity[i];
+
+		trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
+
+		if (trace.allsolid)
+		{	// entity is trapped in another solid
+			pml.velocity[2] = 0;	// don't build up falling damage
+			return;
+		}
+
+		if (trace.fraction > 0)
+		{	// actually covered some distance
+			VectorCopy (trace.endpos, pml.origin);
+			numplanes = 0;
+		}
+
+		if (trace.fraction == 1)
+			 break;		// moved the entire distance
+
+		// save entity for contact
+		if (pm->numtouch < MAXTOUCH && trace.ent)
+		{
+			pm->touchents[pm->numtouch] = trace.ent;
+			pm->numtouch++;
+		}
+		
+		time_left -= time_left * trace.fraction;
+
+		// slide along this plane
+		if (numplanes >= MAX_CLIP_PLANES)
+		{	// this shouldn't really happen
+			VectorCopy (vec3_origin, pml.velocity);
+			break;
+		}
+
+		VectorCopy (trace.plane.normal, planes[numplanes]);
+		numplanes++;
+
+/* commented out in release
+	float		rub;
+
+		//
+		// modify velocity so it parallels all of the clip planes
+		//
+		if (numplanes == 1)
+		{	// go along this plane
+			VectorCopy (pml.velocity, dir);
+			VectorNormalize (dir);
+			rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
+
+			// slide along the plane
+			PM_ClipVelocity (pml.velocity, planes[0], pml.velocity, 1.01);
+			// rub some extra speed off on xy axis
+			// not on Z, or you can scrub down walls
+			pml.velocity[0] *= rub;
+			pml.velocity[1] *= rub;
+			pml.velocity[2] *= rub;
+		}
+		else if (numplanes == 2)
+		{	// go along the crease
+			VectorCopy (pml.velocity, dir);
+			VectorNormalize (dir);
+			rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
+
+			// slide along the plane
+			CrossProduct (planes[0], planes[1], dir);
+			d = DotProduct (dir, pml.velocity);
+			VectorScale (dir, d, pml.velocity);
+
+			// rub some extra speed off
+			VectorScale (pml.velocity, rub, pml.velocity);
+		}
+		else
+		{
+//			Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
+			VectorCopy (vec3_origin, pml.velocity);
+			break;
+		}
+
+*/
+//
+// modify original_velocity so it parallels all of the clip planes
+//
+		for (i=0 ; i<numplanes ; i++)
+		{
+			PM_ClipVelocity (pml.velocity, planes[i], pml.velocity, 1.01);
+			for (j=0 ; j<numplanes ; j++)
+				if (j != i)
+				{
+					if (DotProduct (pml.velocity, planes[j]) < 0)
+						break;	// not ok
+				}
+			if (j == numplanes)
+				break;
+		}
+		
+		if (i != numplanes)
+		{	// go along this plane
+		}
+		else
+		{	// go along the crease
+			if (numplanes != 2)
+			{
+//				Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
+				VectorCopy (vec3_origin, pml.velocity);
+				break;
+			}
+			CrossProduct (planes[0], planes[1], dir);
+			d = DotProduct (dir, pml.velocity);
+			VectorScale (dir, d, pml.velocity);
+		}
+		//
+		// if velocity is against the original velocity, stop dead
+		// to avoid tiny occilations in sloping corners
+		//
+		if (DotProduct (pml.velocity, primal_velocity) <= 0)
+		{
+			VectorCopy (vec3_origin, pml.velocity);
+			break;
+		}
+	}
+
+	if (pm->s.pm_time)
+	{
+		VectorCopy (primal_velocity, pml.velocity);
+	}
+}
+
+/*
+==================
+PM_StepSlideMove
+
+==================
+*/
+void PM_StepSlideMove (void)
+{
+	vec3_t		start_o, start_v;
+	vec3_t		down_o, down_v;
+	trace_t		trace;
+	float		down_dist, up_dist;
+//	vec3_t		delta;
+	vec3_t		up, down;
+
+	VectorCopy (pml.origin, start_o);
+	VectorCopy (pml.velocity, start_v);
+
+	PM_StepSlideMove_ ();
+
+	VectorCopy (pml.origin, down_o);
+	VectorCopy (pml.velocity, down_v);
+
+	VectorCopy (start_o, up);
+	up[2] += STEPSIZE;
+
+	trace = pm->trace (up, pm->mins, pm->maxs, up);
+	if (trace.allsolid)
+		return;		// can't step up
+
+	// try sliding above
+	VectorCopy (up, pml.origin);
+	VectorCopy (start_v, pml.velocity);
+
+	PM_StepSlideMove_ ();
+
+	// push down the final amount
+	VectorCopy (pml.origin, down);
+	down[2] -= STEPSIZE;
+	trace = pm->trace (pml.origin, pm->mins, pm->maxs, down);
+	if (!trace.allsolid)
+	{
+		VectorCopy (trace.endpos, pml.origin);
+	}
+
+/*
+	VectorSubtract (pml.origin, up, delta);
+	up_dist = DotProduct (delta, start_v);
+
+	VectorSubtract (down_o, start_o, delta);
+	down_dist = DotProduct (delta, start_v);
+*/
+	VectorCopy(pml.origin, up);
+
+	// decide which one went farther
+    down_dist = (down_o[0] - start_o[0])*(down_o[0] - start_o[0])
+        + (down_o[1] - start_o[1])*(down_o[1] - start_o[1]);
+    up_dist = (up[0] - start_o[0])*(up[0] - start_o[0])
+        + (up[1] - start_o[1])*(up[1] - start_o[1]);
+
+	if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL)
+	{
+		VectorCopy (down_o, pml.origin);
+		VectorCopy (down_v, pml.velocity);
+		return;
+	}
+	//!! Special case
+	// if we were walking along a plane, then we need to copy the Z over
+	pml.velocity[2] = down_v[2];
+}
+
+
+/*
+==================
+PM_Friction
+
+Handles both ground friction and water friction
+==================
+*/
+void PM_Friction (void)
+{
+	float	*vel;
+	float	speed, newspeed, control;
+	float	friction;
+	float	drop;
+	
+	vel = pml.velocity;
+	
+	speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]);
+	if (speed < 1)
+	{
+		vel[0] = 0;
+		vel[1] = 0;
+		return;
+	}
+
+	drop = 0;
+
+// apply ground friction
+	if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK) ) || (pml.ladder) )
+	{
+		friction = pm_friction;
+		control = speed < pm_stopspeed ? pm_stopspeed : speed;
+		drop += control*friction*pml.frametime;
+	}
+
+// apply water friction
+	if (pm->waterlevel && !pml.ladder)
+		drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
+
+// scale the velocity
+	newspeed = speed - drop;
+	if (newspeed < 0)
+	{
+		newspeed = 0;
+	}
+	newspeed /= speed;
+
+	vel[0] = vel[0] * newspeed;
+	vel[1] = vel[1] * newspeed;
+	vel[2] = vel[2] * newspeed;
+}
+
+
+/*
+==============
+PM_Accelerate
+
+Handles user intended acceleration
+==============
+*/
+void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel)
+{
+	int			i;
+	float		addspeed, accelspeed, currentspeed;
+
+	currentspeed = DotProduct (pml.velocity, wishdir);
+	addspeed = wishspeed - currentspeed;
+	if (addspeed <= 0)
+		return;
+	accelspeed = accel*pml.frametime*wishspeed;
+	if (accelspeed > addspeed)
+		accelspeed = addspeed;
+	
+	for (i=0 ; i<3 ; i++)
+		pml.velocity[i] += accelspeed*wishdir[i];	
+}
+
+void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel)
+{
+	int			i;
+	float		addspeed, accelspeed, currentspeed, wishspd = wishspeed;
+		
+	if (wishspd > 30)
+		wishspd = 30;
+	currentspeed = DotProduct (pml.velocity, wishdir);
+	addspeed = wishspd - currentspeed;
+	if (addspeed <= 0)
+		return;
+	accelspeed = accel * wishspeed * pml.frametime;
+	if (accelspeed > addspeed)
+		accelspeed = addspeed;
+	
+	for (i=0 ; i<3 ; i++)
+		pml.velocity[i] += accelspeed*wishdir[i];	
+}
+
+/*
+=============
+PM_AddCurrents
+=============
+*/
+void PM_AddCurrents (vec3_t	wishvel)
+{
+	vec3_t	v;
+	float	s;
+
+	//
+	// account for ladders
+	//
+
+	if (pml.ladder && fabs(pml.velocity[2]) <= 200)
+	{
+		if ((pm->viewangles[PITCH] <= -15) && (pm->cmd.forwardmove > 0))
+			wishvel[2] = 200;
+		else if ((pm->viewangles[PITCH] >= 15) && (pm->cmd.forwardmove > 0))
+			wishvel[2] = -200;
+		else if (pm->cmd.upmove > 0)
+			wishvel[2] = 200;
+		else if (pm->cmd.upmove < 0)
+			wishvel[2] = -200;
+		else
+			wishvel[2] = 0;
+
+		// limit horizontal speed when on a ladder
+		if (wishvel[0] < -25)
+			wishvel[0] = -25;
+		else if (wishvel[0] > 25)
+			wishvel[0] = 25;
+
+		if (wishvel[1] < -25)
+			wishvel[1] = -25;
+		else if (wishvel[1] > 25)
+			wishvel[1] = 25;
+	}
+
+
+	//
+	// add water currents
+	//
+
+	if (pm->watertype & MASK_CURRENT)
+	{
+		VectorClear (v);
+
+		if (pm->watertype & CONTENTS_CURRENT_0)
+			v[0] += 1;
+		if (pm->watertype & CONTENTS_CURRENT_90)
+			v[1] += 1;
+		if (pm->watertype & CONTENTS_CURRENT_180)
+			v[0] -= 1;
+		if (pm->watertype & CONTENTS_CURRENT_270)
+			v[1] -= 1;
+		if (pm->watertype & CONTENTS_CURRENT_UP)
+			v[2] += 1;
+		if (pm->watertype & CONTENTS_CURRENT_DOWN)
+			v[2] -= 1;
+
+		s = pm_waterspeed;
+		if ((pm->waterlevel == 1) && (pm->groundentity))
+			s /= 2;
+
+		VectorMA (wishvel, s, v, wishvel);
+	}
+
+	//
+	// add conveyor belt velocities
+	//
+
+	if (pm->groundentity)
+	{
+		VectorClear (v);
+
+		if (pml.groundcontents & CONTENTS_CURRENT_0)
+			v[0] += 1;
+		if (pml.groundcontents & CONTENTS_CURRENT_90)
+			v[1] += 1;
+		if (pml.groundcontents & CONTENTS_CURRENT_180)
+			v[0] -= 1;
+		if (pml.groundcontents & CONTENTS_CURRENT_270)
+			v[1] -= 1;
+		if (pml.groundcontents & CONTENTS_CURRENT_UP)
+			v[2] += 1;
+		if (pml.groundcontents & CONTENTS_CURRENT_DOWN)
+			v[2] -= 1;
+
+		VectorMA (wishvel, 100 /* pm->groundentity->speed */, v, wishvel);
+	}
+}
+
+
+/*
+===================
+PM_WaterMove
+
+===================
+*/
+void PM_WaterMove (void)
+{
+	int		i;
+	vec3_t	wishvel;
+	float	wishspeed;
+	vec3_t	wishdir;
+
+//
+// user intentions
+//
+	for (i=0 ; i<3 ; i++)
+		wishvel[i] = pml.forward[i]*pm->cmd.forwardmove + pml.right[i]*pm->cmd.sidemove;
+
+	if (!pm->cmd.forwardmove && !pm->cmd.sidemove && !pm->cmd.upmove)
+		wishvel[2] -= 60;		// drift towards bottom
+	else
+		wishvel[2] += pm->cmd.upmove;
+
+	PM_AddCurrents (wishvel);
+
+	VectorCopy (wishvel, wishdir);
+	wishspeed = VectorNormalize(wishdir);
+
+	if (wishspeed > pm_maxspeed)
+	{
+		VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
+		wishspeed = pm_maxspeed;
+	}
+	wishspeed *= 0.5;
+
+	PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
+
+	PM_StepSlideMove ();
+}
+
+
+/*
+===================
+PM_AirMove
+
+===================
+*/
+void PM_AirMove (void)
+{
+	int			i;
+	vec3_t		wishvel;
+	float		fmove, smove;
+	vec3_t		wishdir;
+	float		wishspeed;
+	float		maxspeed;
+
+	fmove = pm->cmd.forwardmove;
+	smove = pm->cmd.sidemove;
+	
+//!!!!! pitch should be 1/3 so this isn't needed??!
+/*
+	pml.forward[2] = 0;
+	pml.right[2] = 0;
+	VectorNormalize (pml.forward);
+	VectorNormalize (pml.right);
+*/
+
+	for (i=0 ; i<2 ; i++)
+		wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
+	wishvel[2] = 0;
+
+	PM_AddCurrents (wishvel);
+
+	VectorCopy (wishvel, wishdir);
+	wishspeed = VectorNormalize(wishdir);
+
+//
+// clamp to server defined max speed
+//
+	maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pm_maxspeed;
+
+	if (wishspeed > maxspeed)
+	{
+		VectorScale (wishvel, maxspeed/wishspeed, wishvel);
+		wishspeed = maxspeed;
+	}
+	
+	if ( pml.ladder )
+	{
+		PM_Accelerate (wishdir, wishspeed, pm_accelerate);
+		if (!wishvel[2])
+		{
+			if (pml.velocity[2] > 0)
+			{
+				pml.velocity[2] -= pm->s.gravity * pml.frametime;
+				if (pml.velocity[2] < 0)
+					pml.velocity[2]  = 0;
+			}
+			else
+			{
+				pml.velocity[2] += pm->s.gravity * pml.frametime;
+				if (pml.velocity[2] > 0)
+					pml.velocity[2]  = 0;
+			}
+		}
+		PM_StepSlideMove ();
+	}
+	else if ( pm->groundentity )
+	{	// walking on ground
+		pml.velocity[2] = 0; //!!! this is before the accel
+		PM_Accelerate (wishdir, wishspeed, pm_accelerate);
+
+// PGM	-- fix for negative trigger_gravity fields
+//		pml.velocity[2] = 0;
+		if(pm->s.gravity > 0)
+			pml.velocity[2] = 0;
+		else
+			pml.velocity[2] -= pm->s.gravity * pml.frametime;
+// PGM
+
+		if (!pml.velocity[0] && !pml.velocity[1])
+			return;
+		PM_StepSlideMove ();
+	}
+	else
+	{	// not on ground, so little effect on velocity
+		if (pm_airaccelerate)
+			PM_AirAccelerate (wishdir, wishspeed, pm_accelerate);
+		else
+			PM_Accelerate (wishdir, wishspeed, 1);
+		// add gravity
+		pml.velocity[2] -= pm->s.gravity * pml.frametime;
+		PM_StepSlideMove ();
+	}
+}
+
+
+
+/*
+=============
+PM_CatagorizePosition
+=============
+*/
+void PM_CatagorizePosition (void)
+{
+	vec3_t		point;
+	int			cont;
+	trace_t		trace;
+	int			sample1;
+	int			sample2;
+
+// if the player hull point one unit down is solid, the player
+// is on ground
+
+// see if standing on something solid	
+	point[0] = pml.origin[0];
+	point[1] = pml.origin[1];
+	point[2] = pml.origin[2] - 0.25;
+	if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel)
+	{
+		pm->s.pm_flags &= ~PMF_ON_GROUND;
+		pm->groundentity = NULL;
+	}
+	else
+	{
+		trace = pm->trace (pml.origin, pm->mins, pm->maxs, point);
+		pml.groundplane = trace.plane;
+		pml.groundsurface = trace.surface;
+		pml.groundcontents = trace.contents;
+
+		if (!trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid) )
+		{
+			pm->groundentity = NULL;
+			pm->s.pm_flags &= ~PMF_ON_GROUND;
+		}
+		else
+		{
+			pm->groundentity = trace.ent;
+
+			// hitting solid ground will end a waterjump
+			if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
+			{
+				pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
+				pm->s.pm_time = 0;
+			}
+
+			if (! (pm->s.pm_flags & PMF_ON_GROUND) )
+			{	// just hit the ground
+				pm->s.pm_flags |= PMF_ON_GROUND;
+				// don't do landing time if we were just going down a slope
+				if (pml.velocity[2] < -200)
+				{
+					pm->s.pm_flags |= PMF_TIME_LAND;
+					// don't allow another jump for a little while
+					if (pml.velocity[2] < -400)
+						pm->s.pm_time = 25;	
+					else
+						pm->s.pm_time = 18;
+				}
+			}
+		}
+
+/*
+		if (trace.fraction < 1.0 && trace.ent && pml.velocity[2] < 0)
+			pml.velocity[2] = 0;
+*/
+
+		if (pm->numtouch < MAXTOUCH && trace.ent)
+		{
+			pm->touchents[pm->numtouch] = trace.ent;
+			pm->numtouch++;
+		}
+	}
+
+//
+// get waterlevel, accounting for ducking
+//
+	pm->waterlevel = 0;
+	pm->watertype = 0;
+
+	sample2 = pm->viewheight - pm->mins[2];
+	sample1 = sample2 / 2;
+
+	point[2] = pml.origin[2] + pm->mins[2] + 1;	
+	cont = pm->pointcontents (point);
+
+	if (cont & MASK_WATER)
+	{
+		pm->watertype = cont;
+		pm->waterlevel = 1;
+		point[2] = pml.origin[2] + pm->mins[2] + sample1;
+		cont = pm->pointcontents (point);
+		if (cont & MASK_WATER)
+		{
+			pm->waterlevel = 2;
+			point[2] = pml.origin[2] + pm->mins[2] + sample2;
+			cont = pm->pointcontents (point);
+			if (cont & MASK_WATER)
+				pm->waterlevel = 3;
+		}
+	}
+
+}
+
+
+/*
+=============
+PM_CheckJump
+=============
+*/
+void PM_CheckJump (void)
+{
+	if (pm->s.pm_flags & PMF_TIME_LAND)
+	{	// hasn't been long enough since landing to jump again
+		return;
+	}
+
+	if (pm->cmd.upmove < 10)
+	{	// not holding jump
+		pm->s.pm_flags &= ~PMF_JUMP_HELD;
+		return;
+	}
+
+	// must wait for jump to be released
+	if (pm->s.pm_flags & PMF_JUMP_HELD)
+		return;
+
+	if (pm->s.pm_type == PM_DEAD)
+		return;
+
+	if (pm->waterlevel >= 2)
+	{	// swimming, not jumping
+		pm->groundentity = NULL;
+
+		if (pml.velocity[2] <= -300)
+			return;
+
+		if (pm->watertype == CONTENTS_WATER)
+			pml.velocity[2] = 100;
+		else if (pm->watertype == CONTENTS_SLIME)
+			pml.velocity[2] = 80;
+		else
+			pml.velocity[2] = 50;
+		return;
+	}
+
+	if (pm->groundentity == NULL)
+		return;		// in air, so no effect
+
+	pm->s.pm_flags |= PMF_JUMP_HELD;
+
+	pm->groundentity = NULL;
+	pml.velocity[2] += 270;
+	if (pml.velocity[2] < 270)
+		pml.velocity[2] = 270;
+}
+
+
+/*
+=============
+PM_CheckSpecialMovement
+=============
+*/
+void PM_CheckSpecialMovement (void)
+{
+	vec3_t	spot;
+	int		cont;
+	vec3_t	flatforward;
+	trace_t	trace;
+
+	if (pm->s.pm_time)
+		return;
+
+	pml.ladder = false;
+
+	// check for ladder
+	flatforward[0] = pml.forward[0];
+	flatforward[1] = pml.forward[1];
+	flatforward[2] = 0;
+	VectorNormalize (flatforward);
+
+	VectorMA (pml.origin, 1, flatforward, spot);
+	trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot);
+	if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER))
+		pml.ladder = true;
+
+	// check for water jump
+	if (pm->waterlevel != 2)
+		return;
+
+	VectorMA (pml.origin, 30, flatforward, spot);
+	spot[2] += 4;
+	cont = pm->pointcontents (spot);
+	if (!(cont & CONTENTS_SOLID))
+		return;
+
+	spot[2] += 16;
+	cont = pm->pointcontents (spot);
+	if (cont)
+		return;
+	// jump out of water
+	VectorScale (flatforward, 50, pml.velocity);
+	pml.velocity[2] = 350;
+
+	pm->s.pm_flags |= PMF_TIME_WATERJUMP;
+	pm->s.pm_time = 255;
+}
+
+
+/*
+===============
+PM_FlyMove
+===============
+*/
+void PM_FlyMove (qboolean doclip)
+{
+	float	speed, drop, friction, control, newspeed;
+	float	currentspeed, addspeed, accelspeed;
+	int			i;
+	vec3_t		wishvel;
+	float		fmove, smove;
+	vec3_t		wishdir;
+	float		wishspeed;
+	vec3_t		end;
+	trace_t	trace;
+
+	pm->viewheight = 22;
+
+	// friction
+
+	speed = VectorLength (pml.velocity);
+	if (speed < 1)
+	{
+		VectorCopy (vec3_origin, pml.velocity);
+	}
+	else
+	{
+		drop = 0;
+
+		friction = pm_friction*1.5;	// extra friction
+		control = speed < pm_stopspeed ? pm_stopspeed : speed;
+		drop += control*friction*pml.frametime;
+
+		// scale the velocity
+		newspeed = speed - drop;
+		if (newspeed < 0)
+			newspeed = 0;
+		newspeed /= speed;
+
+		VectorScale (pml.velocity, newspeed, pml.velocity);
+	}
+
+	// accelerate
+	fmove = pm->cmd.forwardmove;
+	smove = pm->cmd.sidemove;
+	
+	VectorNormalize (pml.forward);
+	VectorNormalize (pml.right);
+
+	for (i=0 ; i<3 ; i++)
+		wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
+	wishvel[2] += pm->cmd.upmove;
+
+	VectorCopy (wishvel, wishdir);
+	wishspeed = VectorNormalize(wishdir);
+
+	//
+	// clamp to server defined max speed
+	//
+	if (wishspeed > pm_maxspeed)
+	{
+		VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
+		wishspeed = pm_maxspeed;
+	}
+
+
+	currentspeed = DotProduct(pml.velocity, wishdir);
+	addspeed = wishspeed - currentspeed;
+	if (addspeed <= 0)
+		return;
+	accelspeed = pm_accelerate*pml.frametime*wishspeed;
+	if (accelspeed > addspeed)
+		accelspeed = addspeed;
+	
+	for (i=0 ; i<3 ; i++)
+		pml.velocity[i] += accelspeed*wishdir[i];	
+
+	if (doclip) {
+		for (i=0 ; i<3 ; i++)
+			end[i] = pml.origin[i] + pml.frametime * pml.velocity[i];
+
+		trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
+
+		VectorCopy (trace.endpos, pml.origin);
+	} else {
+		// move
+		VectorMA (pml.origin, pml.frametime, pml.velocity, pml.origin);
+	}
+}
+
+
+/*
+==============
+PM_CheckDuck
+
+Sets mins, maxs, and pm->viewheight
+==============
+*/
+void PM_CheckDuck (void)
+{
+	trace_t	trace;
+
+	pm->mins[0] = -16;
+	pm->mins[1] = -16;
+
+	pm->maxs[0] = 16;
+	pm->maxs[1] = 16;
+
+	if (pm->s.pm_type == PM_GIB)
+	{
+		pm->mins[2] = 0;
+		pm->maxs[2] = 16;
+		pm->viewheight = 8;
+		return;
+	}
+
+	pm->mins[2] = -24;
+
+	if (pm->s.pm_type == PM_DEAD)
+	{
+		pm->s.pm_flags |= PMF_DUCKED;
+	}
+	else if (pm->cmd.upmove < 0 && (pm->s.pm_flags & PMF_ON_GROUND) )
+	{	// duck
+		pm->s.pm_flags |= PMF_DUCKED;
+	}
+	else
+	{	// stand up if possible
+		if (pm->s.pm_flags & PMF_DUCKED)
+		{
+			// try to stand up
+			pm->maxs[2] = 32;
+			trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin);
+			if (!trace.allsolid)
+				pm->s.pm_flags &= ~PMF_DUCKED;
+		}
+	}
+
+	if (pm->s.pm_flags & PMF_DUCKED)
+	{
+		pm->maxs[2] = 4;
+		pm->viewheight = -2;
+	}
+	else
+	{
+		pm->maxs[2] = 32;
+		pm->viewheight = 22;
+	}
+}
+
+
+/*
+==============
+PM_DeadMove
+==============
+*/
+void PM_DeadMove (void)
+{
+	float	forward;
+
+	if (!pm->groundentity)
+		return;
+
+	// extra friction
+
+	forward = VectorLength (pml.velocity);
+	forward -= 20;
+	if (forward <= 0)
+	{
+		VectorClear (pml.velocity);
+	}
+	else
+	{
+		VectorNormalize (pml.velocity);
+		VectorScale (pml.velocity, forward, pml.velocity);
+	}
+}
+
+
+qboolean	PM_GoodPosition (void)
+{
+	trace_t	trace;
+	vec3_t	origin, end;
+	int		i;
+
+	if (pm->s.pm_type == PM_SPECTATOR)
+		return true;
+
+	for (i=0 ; i<3 ; i++)
+		origin[i] = end[i] = pm->s.origin[i]*0.125;
+	trace = pm->trace (origin, pm->mins, pm->maxs, end);
+
+	return !trace.allsolid;
+}
+
+/*
+================
+PM_SnapPosition
+
+On exit, the origin will have a value that is pre-quantized to the 0.125
+precision of the network channel and in a valid position.
+================
+*/
+void PM_SnapPosition (void)
+{
+	int		sign[3];
+	int		i, j, bits;
+	short	base[3];
+	// try all single bits first
+	static int jitterbits[8] = {0,4,1,2,3,5,6,7};
+
+	// snap velocity to eigths
+	for (i=0 ; i<3 ; i++)
+		pm->s.velocity[i] = (int)(pml.velocity[i]*8);
+
+	for (i=0 ; i<3 ; i++)
+	{
+		if (pml.origin[i] >= 0)
+			sign[i] = 1;
+		else 
+			sign[i] = -1;
+		pm->s.origin[i] = (int)(pml.origin[i]*8);
+		if (pm->s.origin[i]*0.125 == pml.origin[i])
+			sign[i] = 0;
+	}
+	VectorCopy (pm->s.origin, base);
+
+	// try all combinations
+	for (j=0 ; j<8 ; j++)
+	{
+		bits = jitterbits[j];
+		VectorCopy (base, pm->s.origin);
+		for (i=0 ; i<3 ; i++)
+			if (bits & (1<<i) )
+				pm->s.origin[i] += sign[i];
+
+		if (PM_GoodPosition ())
+			return;
+	}
+
+	// go back to the last position
+	VectorCopy (pml.previous_origin, pm->s.origin);
+//	Com_DPrintf ("using previous_origin\n");
+}
+
+/*
+================
+PM_InitialSnapPosition
+
+================
+*/
+/* NO LONGER USED
+void PM_InitialSnapPosition (void)
+{
+	int		x, y, z;
+	short	base[3];
+
+	VectorCopy (pm->s.origin, base);
+
+	for (z=1 ; z>=-1 ; z--)
+	{
+		pm->s.origin[2] = base[2] + z;
+		for (y=1 ; y>=-1 ; y--)
+		{
+			pm->s.origin[1] = base[1] + y;
+			for (x=1 ; x>=-1 ; x--)
+			{
+				pm->s.origin[0] = base[0] + x;
+				if (PM_GoodPosition ())
+				{
+					pml.origin[0] = pm->s.origin[0]*0.125;
+					pml.origin[1] = pm->s.origin[1]*0.125;
+					pml.origin[2] = pm->s.origin[2]*0.125;
+					VectorCopy (pm->s.origin, pml.previous_origin);
+					return;
+				}
+			}
+		}
+	}
+
+	Com_DPrintf ("Bad InitialSnapPosition\n");
+}
+*/
+/*
+================
+PM_InitialSnapPosition
+
+================
+*/
+void PM_InitialSnapPosition(void)
+{
+	int        x, y, z;
+	short      base[3];
+	static int offset[3] = { 0, -1, 1 };
+
+	VectorCopy (pm->s.origin, base);
+
+	for ( z = 0; z < 3; z++ ) {
+		pm->s.origin[2] = base[2] + offset[ z ];
+		for ( y = 0; y < 3; y++ ) {
+			pm->s.origin[1] = base[1] + offset[ y ];
+			for ( x = 0; x < 3; x++ ) {
+				pm->s.origin[0] = base[0] + offset[ x ];
+				if (PM_GoodPosition ()) {
+					pml.origin[0] = pm->s.origin[0]*0.125;
+					pml.origin[1] = pm->s.origin[1]*0.125;
+					pml.origin[2] = pm->s.origin[2]*0.125;
+					VectorCopy (pm->s.origin, pml.previous_origin);
+					return;
+				}
+			}
+		}
+	}
+
+	Com_DPrintf ("Bad InitialSnapPosition\n");
+}
+
+/*
+================
+PM_ClampAngles
+
+================
+*/
+void PM_ClampAngles (void)
+{
+	short	temp;
+	int		i;
+
+	if (pm->s.pm_flags & PMF_TIME_TELEPORT)
+	{
+		pm->viewangles[YAW] = SHORT2ANGLE(pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]);
+		pm->viewangles[PITCH] = 0;
+		pm->viewangles[ROLL] = 0;
+	}
+	else
+	{
+		// circularly clamp the angles with deltas
+		for (i=0 ; i<3 ; i++)
+		{
+			temp = pm->cmd.angles[i] + pm->s.delta_angles[i];
+			pm->viewangles[i] = SHORT2ANGLE(temp);
+		}
+
+		// don't let the player look up or down more than 90 degrees
+		if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180)
+			pm->viewangles[PITCH] = 89;
+		else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180)
+			pm->viewangles[PITCH] = 271;
+	}
+	AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up);
+}
+
+/*
+================
+Pmove
+
+Can be called by either the server or the client
+================
+*/
+void Pmove (pmove_t *pmove)
+{
+	pm = pmove;
+
+	// clear results
+	pm->numtouch = 0;
+	VectorClear (pm->viewangles);
+	pm->viewheight = 0;
+	pm->groundentity = 0;
+	pm->watertype = 0;
+	pm->waterlevel = 0;
+
+	// clear all pmove local vars
+	memset (&pml, 0, sizeof(pml));
+
+	// convert origin and velocity to float values
+	pml.origin[0] = pm->s.origin[0]*0.125;
+	pml.origin[1] = pm->s.origin[1]*0.125;
+	pml.origin[2] = pm->s.origin[2]*0.125;
+
+	pml.velocity[0] = pm->s.velocity[0]*0.125;
+	pml.velocity[1] = pm->s.velocity[1]*0.125;
+	pml.velocity[2] = pm->s.velocity[2]*0.125;
+
+	// save old org in case we get stuck
+	VectorCopy (pm->s.origin, pml.previous_origin);
+
+	pml.frametime = pm->cmd.msec * 0.001;
+
+	PM_ClampAngles ();
+
+	if (pm->s.pm_type == PM_SPECTATOR)
+	{
+		PM_FlyMove (false);
+		PM_SnapPosition ();
+		return;
+	}
+
+	if (pm->s.pm_type >= PM_DEAD)
+	{
+		pm->cmd.forwardmove = 0;
+		pm->cmd.sidemove = 0;
+		pm->cmd.upmove = 0;
+	}
+
+	if (pm->s.pm_type == PM_FREEZE)
+		return;		// no movement at all
+
+	// set mins, maxs, and viewheight
+	PM_CheckDuck ();
+
+	if (pm->snapinitial)
+		PM_InitialSnapPosition ();
+
+	// set groundentity, watertype, and waterlevel
+	PM_CatagorizePosition ();
+
+	if (pm->s.pm_type == PM_DEAD)
+		PM_DeadMove ();
+
+	PM_CheckSpecialMovement ();
+
+	// drop timing counter
+	if (pm->s.pm_time)
+	{
+		int		msec;
+
+		msec = pm->cmd.msec >> 3;
+		if (!msec)
+			msec = 1;
+		if ( msec >= pm->s.pm_time) 
+		{
+			pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
+			pm->s.pm_time = 0;
+		}
+		else
+			pm->s.pm_time -= msec;
+	}
+
+	if (pm->s.pm_flags & PMF_TIME_TELEPORT)
+	{	// teleport pause stays exactly in place
+	}
+	else if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
+	{	// waterjump has no control, but falls
+		pml.velocity[2] -= pm->s.gravity * pml.frametime;
+		if (pml.velocity[2] < 0)
+		{	// cancel as soon as we are falling down again
+			pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
+			pm->s.pm_time = 0;
+		}
+
+		PM_StepSlideMove ();
+	}
+	else
+	{
+		PM_CheckJump ();
+
+		PM_Friction ();
+
+		if (pm->waterlevel >= 2)
+			PM_WaterMove ();
+		else {
+			vec3_t	angles;
+
+			VectorCopy(pm->viewangles, angles);
+			if (angles[PITCH] > 180)
+				angles[PITCH] = angles[PITCH] - 360;
+			angles[PITCH] /= 3;
+
+			AngleVectors (angles, pml.forward, pml.right, pml.up);
+
+			PM_AirMove ();
+		}
+	}
+
+	// set groundentity, watertype, and waterlevel for final spot
+	PM_CatagorizePosition ();
+
+	PM_SnapPosition ();
+}
+
--- a/q_shared.h
+++ /dev/null
@@ -1,1149 +1,0 @@
-// q_shared.h -- included first by ALL program modules
-
-//#define id386
-
-typedef unsigned char 		byte;
-typedef enum {false, true}	qboolean;
-
-typedef struct edict_t edict_t;
-
-// angle indexes
-#define	PITCH				0		// up / down
-#define	YAW					1		// left / right
-#define	ROLL				2		// fall over
-
-#define	MAX_STRING_CHARS	1024	// max length of a string passed to Cmd_TokenizeString
-#define	MAX_STRING_TOKENS	80		// max tokens resulting from Cmd_TokenizeString
-#define	MAX_TOKEN_CHARS		128		// max length of an individual token
-
-#define	MAX_QPATH			64		// max length of a quake game pathname
-#define	MAX_OSPATH			128		// max length of a filesystem pathname
-
-//
-// per-level limits
-//
-#define	MAX_CLIENTS			256		// absolute limit
-#define	MAX_EDICTS			1024	// must change protocol to increase more
-#define	MAX_LIGHTSTYLES		256
-#define	MAX_MODELS			256		// these are sent over the net as bytes
-#define	MAX_SOUNDS			256		// so they cannot be blindly increased
-#define	MAX_IMAGES			256
-#define	MAX_ITEMS			256
-#define MAX_GENERAL			(MAX_CLIENTS*2)	// general config strings
-
-
-// game print flags
-#define	PRINT_LOW			0		// pickup messages
-#define	PRINT_MEDIUM		1		// death messages
-#define	PRINT_HIGH			2		// critical messages
-#define	PRINT_CHAT			3		// chat messages
-
-
-// destination class for gi.multicast()
-typedef enum
-{
-MULTICAST_ALL,
-MULTICAST_PHS,
-MULTICAST_PVS,
-MULTICAST_ALL_R,
-MULTICAST_PHS_R,
-MULTICAST_PVS_R
-} multicast_t;
-
-
-/*
-==============================================================
-
-MATHLIB
-
-==============================================================
-*/
-
-typedef float vec_t;
-typedef vec_t vec3_t[3];
-typedef vec_t vec5_t[5];
-
-typedef	int	fixed4_t;
-typedef	int	fixed8_t;
-typedef	int	fixed16_t;
-
-#ifndef M_PI
-#define M_PI		3.14159265358979323846	// matches value in gcc v2 math.h
-#endif
-
-struct cplane_s;
-
-extern vec3_t vec3_origin;
-
-#define	nanmask (255<<23)
-
-#define	IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
-
-#define DotProduct(x,y)			(x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
-#define VectorSubtract(a,b,c)	(c[0]=a[0]-b[0],c[1]=a[1]-b[1],c[2]=a[2]-b[2])
-#define VectorAdd(a,b,c)		(c[0]=a[0]+b[0],c[1]=a[1]+b[1],c[2]=a[2]+b[2])
-#define VectorCopy(a,b)			(b[0]=a[0],b[1]=a[1],b[2]=a[2])
-#define VectorClear(a)			(a[0]=a[1]=a[2]=0)
-#define VectorNegate(a,b)		(b[0]=-a[0],b[1]=-a[1],b[2]=-a[2])
-#define VectorSet(v, x, y, z)	(v[0]=(x), v[1]=(y), v[2]=(z))
-
-void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc);
-
-// just in case you do't want to use the macros
-vec_t _DotProduct (vec3_t v1, vec3_t v2);
-void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out);
-void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out);
-void _VectorCopy (vec3_t in, vec3_t out);
-
-void ClearBounds (vec3_t mins, vec3_t maxs);
-void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs);
-int VectorCompare (vec3_t v1, vec3_t v2);
-vec_t VectorLength (vec3_t v);
-void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
-vec_t VectorNormalize (vec3_t v);		// returns vector length
-vec_t VectorNormalize2 (vec3_t v, vec3_t out);
-void VectorInverse (vec3_t v);
-void VectorScale (vec3_t in, vec_t scale, vec3_t out);
-
-void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
-void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);
-
-void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane);
-float	anglemod(float a);
-float LerpAngle (float a1, float a2, float frac);
-
-#define BOX_ON_PLANE_SIDE(emins, emaxs, p)	\
-	(((p)->type < 3)?						\
-	(										\
-		((p)->dist <= (emins)[(p)->type])?	\
-			1								\
-		:									\
-		(									\
-			((p)->dist >= (emaxs)[(p)->type])?\
-				2							\
-			:								\
-				3							\
-		)									\
-	)										\
-	:										\
-		BoxOnPlaneSide( (emins), (emaxs), (p)))
-
-void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal );
-void PerpendicularVector( vec3_t dst, const vec3_t src );
-void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
-
-
-//=============================================
-
-char *COM_SkipPath (char *pathname);
-void COM_StripExtension (char *in, char *out);
-void COM_FileBase (char *in, char *out);
-void COM_FilePath (char *in, char *out);
-void COM_DefaultExtension (char *path, char *extension);
-
-char *COM_Parse (char **data_p);
-// data is an in/out parm, returns a parsed out token
-
-void Com_sprintf (char *dest, int size, char *fmt, ...);
-
-void Com_PageInMemory (byte *buffer, int size);
-
-//=============================================
-
-short	BigShort(short l);
-short	LittleShort(short l);
-int		BigLong (int l);
-int		LittleLong (int l);
-float	BigFloat (float l);
-float	LittleFloat (float l);
-
-void	Swap_Init (void);
-char	*va(char *format, ...);
-
-//=============================================
-
-//
-// key / value info strings
-//
-#define	MAX_INFO_KEY		64
-#define	MAX_INFO_VALUE		64
-#define	MAX_INFO_STRING		512
-
-char *Info_ValueForKey (char *s, char *key);
-void Info_RemoveKey (char *s, char *key);
-void Info_SetValueForKey (char *s, char *key, char *value);
-qboolean Info_Validate (char *s);
-
-/*
-==============================================================
-
-SYSTEM SPECIFIC
-
-==============================================================
-*/
-
-extern	int	curtime;		// time returned by last Sys_Milliseconds
-
-int		Sys_Milliseconds (void);
-void	Sys_Mkdir (char *path);
-vlong	flen(int);
-
-// large block stack allocation routines
-void	*Hunk_Begin (int maxsize);
-void	*Hunk_Alloc (int size);
-void	Hunk_Free (void *buf);
-int		Hunk_End (void);
-
-// directory searching
-#define SFF_ARCH    0x01
-#define SFF_HIDDEN  0x02
-#define SFF_RDONLY  0x04
-#define SFF_SUBDIR  0x08
-#define SFF_SYSTEM  0x10
-
-/*
-** pass in an attribute mask of things you wish to REJECT
-*/
-char	*Sys_FindFirst (char *path, uint musthave, uint canthave );
-char	*Sys_FindNext ( uint musthave, uint canthave );
-void	Sys_FindClose (void);
-
-
-// this is only here so the functions in q_shared.c and q_shwin.c can link
-void Sys_Error (char *error, ...);
-void Com_Printf (char *msg, ...);
-
-
-/*
-==========================================================
-
-CVARS (console variables)
-
-==========================================================
-*/
-
-#ifndef CVAR
-#define	CVAR
-
-#define	CVAR_ARCHIVE	1	// set to cause it to be saved to vars.rc
-#define	CVAR_USERINFO	2	// added to userinfo  when changed
-#define	CVAR_SERVERINFO	4	// added to serverinfo when changed
-#define	CVAR_NOSET		8	// don't allow change from console at all,
-							// but can be set from the command line
-#define	CVAR_LATCH		16	// save changes until server restart
-
-// nothing outside the Cvar_*() functions should modify these fields!
-typedef struct cvar_s
-{
-	char		*name;
-	char		*string;
-	char		*latched_string;	// for CVAR_LATCH vars
-	int			flags;
-	qboolean	modified;	// set each time the cvar is changed
-	float		value;
-	struct cvar_s *next;
-} cvar_t;
-
-#endif		// CVAR
-
-/*
-==============================================================
-
-COLLISION DETECTION
-
-==============================================================
-*/
-
-// lower bits are stronger, and will eat weaker brushes completely
-#define	CONTENTS_SOLID			1		// an eye is never valid in a solid
-#define	CONTENTS_WINDOW			2		// translucent, but not watery
-#define	CONTENTS_AUX			4
-#define	CONTENTS_LAVA			8
-#define	CONTENTS_SLIME			16
-#define	CONTENTS_WATER			32
-#define	CONTENTS_MIST			64
-#define	LAST_VISIBLE_CONTENTS	64
-
-// remaining contents are non-visible, and don't eat brushes
-
-#define	CONTENTS_AREAPORTAL		0x8000
-
-#define	CONTENTS_PLAYERCLIP		0x10000
-#define	CONTENTS_MONSTERCLIP	0x20000
-
-// currents can be added to any other contents, and may be mixed
-#define	CONTENTS_CURRENT_0		0x40000
-#define	CONTENTS_CURRENT_90		0x80000
-#define	CONTENTS_CURRENT_180	0x100000
-#define	CONTENTS_CURRENT_270	0x200000
-#define	CONTENTS_CURRENT_UP		0x400000
-#define	CONTENTS_CURRENT_DOWN	0x800000
-
-#define	CONTENTS_ORIGIN			0x1000000	// removed before bsping an entity
-
-#define	CONTENTS_MONSTER		0x2000000	// should never be on a brush, only in game
-#define	CONTENTS_DEADMONSTER	0x4000000
-#define	CONTENTS_DETAIL			0x8000000	// brushes to be added after vis leafs
-#define	CONTENTS_TRANSLUCENT	0x10000000	// auto set if any surface has trans
-#define	CONTENTS_LADDER			0x20000000
-
-
-
-#define	SURF_LIGHT		0x1		// value will hold the light strength
-
-#define	SURF_SLICK		0x2		// effects game physics
-
-#define	SURF_SKY		0x4		// don't draw, but add to skybox
-#define	SURF_WARP		0x8		// turbulent water warp
-#define	SURF_TRANS33	0x10
-#define	SURF_TRANS66	0x20
-#define	SURF_FLOWING	0x40	// scroll towards angle
-#define	SURF_NODRAW		0x80	// don't bother referencing the texture
-
-
-
-// content masks
-#define	MASK_ALL				(-1)
-#define	MASK_SOLID				(CONTENTS_SOLID|CONTENTS_WINDOW)
-#define	MASK_PLAYERSOLID		(CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)
-#define	MASK_DEADSOLID			(CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW)
-#define	MASK_MONSTERSOLID		(CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)
-#define	MASK_WATER				(CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)
-#define	MASK_OPAQUE				(CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA)
-#define	MASK_SHOT				(CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEADMONSTER)
-#define MASK_CURRENT			(CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN)
-
-
-// gi.BoxEdicts() can return a list of either solid or trigger entities
-// FIXME: eliminate AREA_ distinction?
-#define	AREA_SOLID		1
-#define	AREA_TRIGGERS	2
-
-
-// plane_t structure
-// !!! if this is changed, it must be changed in asm code too !!!
-typedef struct cplane_s
-{
-	vec3_t	normal;
-	float	dist;
-	byte	type;			// for fast side tests
-	byte	signbits;		// signx + (signy<<1) + (signz<<1)
-	byte	pad[2];
-} cplane_t;
-
-// structure offset for asm code
<