shithub: qk2

Download patch

ref: 61e35a208c16f339e39e5b4d6244e12ddcc980f7
parent: 4cae69d325329e3c1d7bf043eb52d610369a26bb
author: Konstantinn Bonnet <[email protected]>
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

diff: cannot open a/client//null: file does not exist: 'a/client//null' diff: cannot open a/plan9//null: file does not exist: 'a/plan9//null' diff: cannot open a/qcommon//null: file does not exist: 'a/qcommon//null' diff: cannot open a/ref//null: file does not exist: 'a/ref//null' diff: cannot open a/server//null: file does not exist: 'a/server//null'
--- /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
-#define CPLANE_NORMAL_X			0
-#define CPLANE_NORMAL_Y			4
-#define CPLANE_NORMAL_Z			8
-#define CPLANE_DIST				12
-#define CPLANE_TYPE				16
-#define CPLANE_SIGNBITS			17
-#define CPLANE_PAD0				18
-#define CPLANE_PAD1				19
-
-typedef struct cmodel_s
-{
-	vec3_t		mins, maxs;
-	vec3_t		origin;		// for sounds or lights
-	int			headnode;
-} cmodel_t;
-
-typedef struct csurface_s
-{
-	char		name[16];
-	int			flags;
-	int			value;
-} csurface_t;
-
-typedef struct mapsurface_s  // used internally due to name len probs //ZOID
-{
-	csurface_t	c;
-	char		rname[32];
-} mapsurface_t;
-
-// a trace is returned when a box is swept through the world
-typedef struct
-{
-	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
-} trace_t;
-
-
-
-// pmove_state_t is the information necessary for client side movement
-// prediction
-typedef enum 
-{
-	// can accelerate and turn
-	PM_NORMAL,
-	PM_SPECTATOR,
-	// no acceleration or turning
-	PM_DEAD,
-	PM_GIB,		// different bounding box
-	PM_FREEZE
-} pmtype_t;
-
-// pmove->pm_flags
-#define	PMF_DUCKED			1
-#define	PMF_JUMP_HELD		2
-#define	PMF_ON_GROUND		4
-#define	PMF_TIME_WATERJUMP	8	// pm_time is waterjump
-#define	PMF_TIME_LAND		16	// pm_time is time before rejump
-#define	PMF_TIME_TELEPORT	32	// pm_time is non-moving time
-#define PMF_NO_PREDICTION	64	// temporarily disables prediction (used for grappling hook)
-
-// 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.
-typedef struct
-{
-	pmtype_t	pm_type;
-
-	short		origin[3];		// 12.3
-	short		velocity[3];	// 12.3
-	byte		pm_flags;		// ducked, jump_held, etc
-	byte		pm_time;		// each unit = 8 ms
-	short		gravity;
-	short		delta_angles[3];	// add to command angles to get view direction
-									// changed by spawns, rotating objects, and teleporters
-} pmove_state_t;
-
-
-//
-// button bits
-//
-#define	BUTTON_ATTACK		1
-#define	BUTTON_USE			2
-#define	BUTTON_ANY			128			// any key whatsoever
-
-
-// usercmd_t is sent to the server each client frame
-typedef struct usercmd_s
-{
-	byte	msec;
-	byte	buttons;
-	short	angles[3];
-	short	forwardmove, sidemove, upmove;
-	byte	impulse;		// remove?
-	byte	lightlevel;		// light level the player is standing on
-} usercmd_t;
-
-
-#define	MAXTOUCH	32
-typedef struct
-{
-	// state (in / out)
-	pmove_state_t	s;
-
-	// 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, maxs;			// bounding box size
-
-	edict_t	*groundentity;
-	int			watertype;
-	int			waterlevel;
-
-	// callbacks to test the world
-	trace_t		(*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
-	int			(*pointcontents) (vec3_t point);
-} pmove_t;
-
-
-// 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.
-#define	EF_ROTATE			0x00000001		// rotate (bonus items)
-#define	EF_GIB				0x00000002		// leave a trail
-#define	EF_BLASTER			0x00000008		// redlight + trail
-#define	EF_ROCKET			0x00000010		// redlight + trail
-#define	EF_GRENADE			0x00000020
-#define	EF_HYPERBLASTER		0x00000040
-#define	EF_BFG				0x00000080
-#define EF_COLOR_SHELL		0x00000100
-#define EF_POWERSCREEN		0x00000200
-#define	EF_ANIM01			0x00000400		// automatically cycle between frames 0 and 1 at 2 hz
-#define	EF_ANIM23			0x00000800		// automatically cycle between frames 2 and 3 at 2 hz
-#define EF_ANIM_ALL			0x00001000		// automatically cycle through all frames at 2hz
-#define EF_ANIM_ALLFAST		0x00002000		// automatically cycle through all frames at 10hz
-#define	EF_FLIES			0x00004000
-#define	EF_QUAD				0x00008000
-#define	EF_PENT				0x00010000
-#define	EF_TELEPORTER		0x00020000		// particle fountain
-#define EF_FLAG1			0x00040000
-#define EF_FLAG2			0x00080000
-// RAFAEL
-#define EF_IONRIPPER		0x00100000
-#define EF_GREENGIB			0x00200000
-#define	EF_BLUEHYPERBLASTER 0x00400000
-#define EF_SPINNINGLIGHTS	0x00800000
-#define EF_PLASMA			0x01000000
-#define EF_TRAP				0x02000000
-
-//ROGUE
-#define EF_TRACKER			0x04000000
-#define	EF_DOUBLE			0x08000000
-#define	EF_SPHERETRANS		0x10000000
-#define EF_TAGTRAIL			0x20000000
-#define EF_HALF_DAMAGE		0x40000000
-#define EF_TRACKERTRAIL		0x80000000
-//ROGUE
-
-// entity_state_t->renderfx flags
-#define	RF_MINLIGHT			1		// allways have some light (viewmodel)
-#define	RF_VIEWERMODEL		2		// don't draw through eyes, only mirrors
-#define	RF_WEAPONMODEL		4		// only draw through eyes
-#define	RF_FULLBRIGHT		8		// allways draw full intensity
-#define	RF_DEPTHHACK		16		// for view weapon Z crunching
-#define	RF_TRANSLUCENT		32
-#define	RF_FRAMELERP		64
-#define RF_BEAM				128
-#define	RF_CUSTOMSKIN		256		// skin is an index in image_precache
-#define	RF_GLOW				512		// pulse lighting for bonus items
-#define RF_SHELL_RED		1024
-#define	RF_SHELL_GREEN		2048
-#define RF_SHELL_BLUE		4096
-
-//ROGUE
-#define RF_IR_VISIBLE		0x00008000		// 32768
-#define	RF_SHELL_DOUBLE		0x00010000		// 65536
-#define	RF_SHELL_HALF_DAM	0x00020000
-#define RF_USE_DISGUISE		0x00040000
-//ROGUE
-
-// player_state_t->refdef flags
-#define	RDF_UNDERWATER		1		// warp the screen as apropriate
-#define RDF_NOWORLDMODEL	2		// used for player configuration screen
-
-//ROGUE
-#define	RDF_IRGOGGLES		4
-#define RDF_UVGOGGLES		8
-//ROGUE
-
-//
-// muzzle flashes / player effects
-//
-#define	MZ_BLASTER			0
-#define MZ_MACHINEGUN		1
-#define	MZ_SHOTGUN			2
-#define	MZ_CHAINGUN1		3
-#define	MZ_CHAINGUN2		4
-#define	MZ_CHAINGUN3		5
-#define	MZ_RAILGUN			6
-#define	MZ_ROCKET			7
-#define	MZ_GRENADE			8
-#define	MZ_LOGIN			9
-#define	MZ_LOGOUT			10
-#define	MZ_RESPAWN			11
-#define	MZ_BFG				12
-#define	MZ_SSHOTGUN			13
-#define	MZ_HYPERBLASTER		14
-#define	MZ_ITEMRESPAWN		15
-// RAFAEL
-#define MZ_IONRIPPER		16
-#define MZ_BLUEHYPERBLASTER 17
-#define MZ_PHALANX			18
-#define MZ_SILENCED			128		// bit flag ORed with one of the above numbers
-
-//ROGUE
-#define MZ_ETF_RIFLE		30
-#define MZ_UNUSED			31
-#define MZ_SHOTGUN2			32
-#define MZ_HEATBEAM			33
-#define MZ_BLASTER2			34
-#define	MZ_TRACKER			35
-#define	MZ_NUKE1			36
-#define	MZ_NUKE2			37
-#define	MZ_NUKE4			38
-#define	MZ_NUKE8			39
-//ROGUE
-
-//
-// monster muzzle flashes
-//
-#define MZ2_TANK_BLASTER_1				1
-#define MZ2_TANK_BLASTER_2				2
-#define MZ2_TANK_BLASTER_3				3
-#define MZ2_TANK_MACHINEGUN_1			4
-#define MZ2_TANK_MACHINEGUN_2			5
-#define MZ2_TANK_MACHINEGUN_3			6
-#define MZ2_TANK_MACHINEGUN_4			7
-#define MZ2_TANK_MACHINEGUN_5			8
-#define MZ2_TANK_MACHINEGUN_6			9
-#define MZ2_TANK_MACHINEGUN_7			10
-#define MZ2_TANK_MACHINEGUN_8			11
-#define MZ2_TANK_MACHINEGUN_9			12
-#define MZ2_TANK_MACHINEGUN_10			13
-#define MZ2_TANK_MACHINEGUN_11			14
-#define MZ2_TANK_MACHINEGUN_12			15
-#define MZ2_TANK_MACHINEGUN_13			16
-#define MZ2_TANK_MACHINEGUN_14			17
-#define MZ2_TANK_MACHINEGUN_15			18
-#define MZ2_TANK_MACHINEGUN_16			19
-#define MZ2_TANK_MACHINEGUN_17			20
-#define MZ2_TANK_MACHINEGUN_18			21
-#define MZ2_TANK_MACHINEGUN_19			22
-#define MZ2_TANK_ROCKET_1				23
-#define MZ2_TANK_ROCKET_2				24
-#define MZ2_TANK_ROCKET_3				25
-
-#define MZ2_INFANTRY_MACHINEGUN_1		26
-#define MZ2_INFANTRY_MACHINEGUN_2		27
-#define MZ2_INFANTRY_MACHINEGUN_3		28
-#define MZ2_INFANTRY_MACHINEGUN_4		29
-#define MZ2_INFANTRY_MACHINEGUN_5		30
-#define MZ2_INFANTRY_MACHINEGUN_6		31
-#define MZ2_INFANTRY_MACHINEGUN_7		32
-#define MZ2_INFANTRY_MACHINEGUN_8		33
-#define MZ2_INFANTRY_MACHINEGUN_9		34
-#define MZ2_INFANTRY_MACHINEGUN_10		35
-#define MZ2_INFANTRY_MACHINEGUN_11		36
-#define MZ2_INFANTRY_MACHINEGUN_12		37
-#define MZ2_INFANTRY_MACHINEGUN_13		38
-
-#define MZ2_SOLDIER_BLASTER_1			39
-#define MZ2_SOLDIER_BLASTER_2			40
-#define MZ2_SOLDIER_SHOTGUN_1			41
-#define MZ2_SOLDIER_SHOTGUN_2			42
-#define MZ2_SOLDIER_MACHINEGUN_1		43
-#define MZ2_SOLDIER_MACHINEGUN_2		44
-
-#define MZ2_GUNNER_MACHINEGUN_1			45
-#define MZ2_GUNNER_MACHINEGUN_2			46
-#define MZ2_GUNNER_MACHINEGUN_3			47
-#define MZ2_GUNNER_MACHINEGUN_4			48
-#define MZ2_GUNNER_MACHINEGUN_5			49
-#define MZ2_GUNNER_MACHINEGUN_6			50
-#define MZ2_GUNNER_MACHINEGUN_7			51
-#define MZ2_GUNNER_MACHINEGUN_8			52
-#define MZ2_GUNNER_GRENADE_1			53
-#define MZ2_GUNNER_GRENADE_2			54
-#define MZ2_GUNNER_GRENADE_3			55
-#define MZ2_GUNNER_GRENADE_4			56
-
-#define MZ2_CHICK_ROCKET_1				57
-
-#define MZ2_FLYER_BLASTER_1				58
-#define MZ2_FLYER_BLASTER_2				59
-
-#define MZ2_MEDIC_BLASTER_1				60
-
-#define MZ2_GLADIATOR_RAILGUN_1			61
-
-#define MZ2_HOVER_BLASTER_1				62
-
-#define MZ2_ACTOR_MACHINEGUN_1			63
-
-#define MZ2_SUPERTANK_MACHINEGUN_1		64
-#define MZ2_SUPERTANK_MACHINEGUN_2		65
-#define MZ2_SUPERTANK_MACHINEGUN_3		66
-#define MZ2_SUPERTANK_MACHINEGUN_4		67
-#define MZ2_SUPERTANK_MACHINEGUN_5		68
-#define MZ2_SUPERTANK_MACHINEGUN_6		69
-#define MZ2_SUPERTANK_ROCKET_1			70
-#define MZ2_SUPERTANK_ROCKET_2			71
-#define MZ2_SUPERTANK_ROCKET_3			72
-
-#define MZ2_BOSS2_MACHINEGUN_L1			73
-#define MZ2_BOSS2_MACHINEGUN_L2			74
-#define MZ2_BOSS2_MACHINEGUN_L3			75
-#define MZ2_BOSS2_MACHINEGUN_L4			76
-#define MZ2_BOSS2_MACHINEGUN_L5			77
-#define MZ2_BOSS2_ROCKET_1				78
-#define MZ2_BOSS2_ROCKET_2				79
-#define MZ2_BOSS2_ROCKET_3				80
-#define MZ2_BOSS2_ROCKET_4				81
-
-#define MZ2_FLOAT_BLASTER_1				82
-
-#define MZ2_SOLDIER_BLASTER_3			83
-#define MZ2_SOLDIER_SHOTGUN_3			84
-#define MZ2_SOLDIER_MACHINEGUN_3		85
-#define MZ2_SOLDIER_BLASTER_4			86
-#define MZ2_SOLDIER_SHOTGUN_4			87
-#define MZ2_SOLDIER_MACHINEGUN_4		88
-#define MZ2_SOLDIER_BLASTER_5			89
-#define MZ2_SOLDIER_SHOTGUN_5			90
-#define MZ2_SOLDIER_MACHINEGUN_5		91
-#define MZ2_SOLDIER_BLASTER_6			92
-#define MZ2_SOLDIER_SHOTGUN_6			93
-#define MZ2_SOLDIER_MACHINEGUN_6		94
-#define MZ2_SOLDIER_BLASTER_7			95
-#define MZ2_SOLDIER_SHOTGUN_7			96
-#define MZ2_SOLDIER_MACHINEGUN_7		97
-#define MZ2_SOLDIER_BLASTER_8			98
-#define MZ2_SOLDIER_SHOTGUN_8			99
-#define MZ2_SOLDIER_MACHINEGUN_8		100
-
-// --- Xian shit below ---
-#define	MZ2_MAKRON_BFG					101
-#define MZ2_MAKRON_BLASTER_1			102
-#define MZ2_MAKRON_BLASTER_2			103
-#define MZ2_MAKRON_BLASTER_3			104
-#define MZ2_MAKRON_BLASTER_4			105
-#define MZ2_MAKRON_BLASTER_5			106
-#define MZ2_MAKRON_BLASTER_6			107
-#define MZ2_MAKRON_BLASTER_7			108
-#define MZ2_MAKRON_BLASTER_8			109
-#define MZ2_MAKRON_BLASTER_9			110
-#define MZ2_MAKRON_BLASTER_10			111
-#define MZ2_MAKRON_BLASTER_11			112
-#define MZ2_MAKRON_BLASTER_12			113
-#define MZ2_MAKRON_BLASTER_13			114
-#define MZ2_MAKRON_BLASTER_14			115
-#define MZ2_MAKRON_BLASTER_15			116
-#define MZ2_MAKRON_BLASTER_16			117
-#define MZ2_MAKRON_BLASTER_17			118
-#define MZ2_MAKRON_RAILGUN_1			119
-#define	MZ2_JORG_MACHINEGUN_L1			120
-#define	MZ2_JORG_MACHINEGUN_L2			121
-#define	MZ2_JORG_MACHINEGUN_L3			122
-#define	MZ2_JORG_MACHINEGUN_L4			123
-#define	MZ2_JORG_MACHINEGUN_L5			124
-#define	MZ2_JORG_MACHINEGUN_L6			125
-#define	MZ2_JORG_MACHINEGUN_R1			126
-#define	MZ2_JORG_MACHINEGUN_R2			127
-#define	MZ2_JORG_MACHINEGUN_R3			128
-#define	MZ2_JORG_MACHINEGUN_R4			129
-#define MZ2_JORG_MACHINEGUN_R5			130
-#define	MZ2_JORG_MACHINEGUN_R6			131
-#define MZ2_JORG_BFG_1					132
-#define MZ2_BOSS2_MACHINEGUN_R1			133
-#define MZ2_BOSS2_MACHINEGUN_R2			134
-#define MZ2_BOSS2_MACHINEGUN_R3			135
-#define MZ2_BOSS2_MACHINEGUN_R4			136
-#define MZ2_BOSS2_MACHINEGUN_R5			137
-
-//ROGUE
-#define	MZ2_CARRIER_MACHINEGUN_L1		138
-#define	MZ2_CARRIER_MACHINEGUN_R1		139
-#define	MZ2_CARRIER_GRENADE				140
-#define MZ2_TURRET_MACHINEGUN			141
-#define MZ2_TURRET_ROCKET				142
-#define MZ2_TURRET_BLASTER				143
-#define MZ2_STALKER_BLASTER				144
-#define MZ2_DAEDALUS_BLASTER			145
-#define MZ2_MEDIC_BLASTER_2				146
-#define	MZ2_CARRIER_RAILGUN				147
-#define	MZ2_WIDOW_DISRUPTOR				148
-#define	MZ2_WIDOW_BLASTER				149
-#define	MZ2_WIDOW_RAIL					150
-#define	MZ2_WIDOW_PLASMABEAM			151		// PMM - not used
-#define	MZ2_CARRIER_MACHINEGUN_L2		152
-#define	MZ2_CARRIER_MACHINEGUN_R2		153
-#define	MZ2_WIDOW_RAIL_LEFT				154
-#define	MZ2_WIDOW_RAIL_RIGHT			155
-#define	MZ2_WIDOW_BLASTER_SWEEP1		156
-#define	MZ2_WIDOW_BLASTER_SWEEP2		157
-#define	MZ2_WIDOW_BLASTER_SWEEP3		158
-#define	MZ2_WIDOW_BLASTER_SWEEP4		159
-#define	MZ2_WIDOW_BLASTER_SWEEP5		160
-#define	MZ2_WIDOW_BLASTER_SWEEP6		161
-#define	MZ2_WIDOW_BLASTER_SWEEP7		162
-#define	MZ2_WIDOW_BLASTER_SWEEP8		163
-#define	MZ2_WIDOW_BLASTER_SWEEP9		164
-#define	MZ2_WIDOW_BLASTER_100			165
-#define	MZ2_WIDOW_BLASTER_90			166
-#define	MZ2_WIDOW_BLASTER_80			167
-#define	MZ2_WIDOW_BLASTER_70			168
-#define	MZ2_WIDOW_BLASTER_60			169
-#define	MZ2_WIDOW_BLASTER_50			170
-#define	MZ2_WIDOW_BLASTER_40			171
-#define	MZ2_WIDOW_BLASTER_30			172
-#define	MZ2_WIDOW_BLASTER_20			173
-#define	MZ2_WIDOW_BLASTER_10			174
-#define	MZ2_WIDOW_BLASTER_0				175
-#define	MZ2_WIDOW_BLASTER_10L			176
-#define	MZ2_WIDOW_BLASTER_20L			177
-#define	MZ2_WIDOW_BLASTER_30L			178
-#define	MZ2_WIDOW_BLASTER_40L			179
-#define	MZ2_WIDOW_BLASTER_50L			180
-#define	MZ2_WIDOW_BLASTER_60L			181
-#define	MZ2_WIDOW_BLASTER_70L			182
-#define	MZ2_WIDOW_RUN_1					183
-#define	MZ2_WIDOW_RUN_2					184
-#define	MZ2_WIDOW_RUN_3					185
-#define	MZ2_WIDOW_RUN_4					186
-#define	MZ2_WIDOW_RUN_5					187
-#define	MZ2_WIDOW_RUN_6					188
-#define	MZ2_WIDOW_RUN_7					189
-#define	MZ2_WIDOW_RUN_8					190
-#define	MZ2_CARRIER_ROCKET_1			191
-#define	MZ2_CARRIER_ROCKET_2			192
-#define	MZ2_CARRIER_ROCKET_3			193
-#define	MZ2_CARRIER_ROCKET_4			194
-#define	MZ2_WIDOW2_BEAMER_1				195
-#define	MZ2_WIDOW2_BEAMER_2				196
-#define	MZ2_WIDOW2_BEAMER_3				197
-#define	MZ2_WIDOW2_BEAMER_4				198
-#define	MZ2_WIDOW2_BEAMER_5				199
-#define	MZ2_WIDOW2_BEAM_SWEEP_1			200
-#define	MZ2_WIDOW2_BEAM_SWEEP_2			201
-#define	MZ2_WIDOW2_BEAM_SWEEP_3			202
-#define	MZ2_WIDOW2_BEAM_SWEEP_4			203
-#define	MZ2_WIDOW2_BEAM_SWEEP_5			204
-#define	MZ2_WIDOW2_BEAM_SWEEP_6			205
-#define	MZ2_WIDOW2_BEAM_SWEEP_7			206
-#define	MZ2_WIDOW2_BEAM_SWEEP_8			207
-#define	MZ2_WIDOW2_BEAM_SWEEP_9			208
-#define	MZ2_WIDOW2_BEAM_SWEEP_10		209
-#define	MZ2_WIDOW2_BEAM_SWEEP_11		210
-
-// ROGUE
-
-extern	vec3_t monster_flash_offset [];
-
-
-// temp entity events
-//
-// 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
-{
-	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
-//ROGUE
-} temp_event_t;
-
-#define SPLASH_UNKNOWN		0
-#define SPLASH_SPARKS		1
-#define SPLASH_BLUE_WATER	2
-#define SPLASH_BROWN_WATER	3
-#define SPLASH_SLIME		4
-#define	SPLASH_LAVA			5
-#define SPLASH_BLOOD		6
-
-
-// sound channels
-// channel 0 never willingly overrides
-// other channels (1-7) allways override a playing sound on that channel
-#define	CHAN_AUTO               0
-#define	CHAN_WEAPON             1
-#define	CHAN_VOICE              2
-#define	CHAN_ITEM               3
-#define	CHAN_BODY               4
-// modifier flags
-#define	CHAN_NO_PHS_ADD			8	// send to all clients, not just ones in PHS (ATTN 0 will also do this)
-#define	CHAN_RELIABLE			16	// send by reliable message, not datagram
-
-
-// sound attenuation values
-#define	ATTN_NONE               0	// full volume the entire level
-#define	ATTN_NORM               1
-#define	ATTN_IDLE               2
-#define	ATTN_STATIC             3	// diminish very rapidly with distance
-
-
-// player_state->stats[] indexes
-#define STAT_HEALTH_ICON		0
-#define	STAT_HEALTH				1
-#define	STAT_AMMO_ICON			2
-#define	STAT_AMMO				3
-#define	STAT_ARMOR_ICON			4
-#define	STAT_ARMOR				5
-#define	STAT_SELECTED_ICON		6
-#define	STAT_PICKUP_ICON		7
-#define	STAT_PICKUP_STRING		8
-#define	STAT_TIMER_ICON			9
-#define	STAT_TIMER				10
-#define	STAT_HELPICON			11
-#define	STAT_SELECTED_ITEM		12
-#define	STAT_LAYOUTS			13
-#define	STAT_FRAGS				14
-#define	STAT_FLASHES			15		// cleared each frame, 1 = health, 2 = armor
-#define STAT_CHASE				16
-#define STAT_SPECTATOR			17
-
-#define	MAX_STATS				32
-
-
-// dmflags->value flags
-#define	DF_NO_HEALTH		0x00000001	// 1
-#define	DF_NO_ITEMS			0x00000002	// 2
-#define	DF_WEAPONS_STAY		0x00000004	// 4
-#define	DF_NO_FALLING		0x00000008	// 8
-#define	DF_INSTANT_ITEMS	0x00000010	// 16
-#define	DF_SAME_LEVEL		0x00000020	// 32
-#define DF_SKINTEAMS		0x00000040	// 64
-#define DF_MODELTEAMS		0x00000080	// 128
-#define DF_NO_FRIENDLY_FIRE	0x00000100	// 256
-#define	DF_SPAWN_FARTHEST	0x00000200	// 512
-#define DF_FORCE_RESPAWN	0x00000400	// 1024
-#define DF_NO_ARMOR			0x00000800	// 2048
-#define DF_ALLOW_EXIT		0x00001000	// 4096
-#define DF_INFINITE_AMMO	0x00002000	// 8192
-#define DF_QUAD_DROP		0x00004000	// 16384
-#define DF_FIXED_FOV		0x00008000	// 32768
-
-// RAFAEL
-#define	DF_QUADFIRE_DROP	0x00010000	// 65536
-
-//ROGUE
-#define DF_NO_MINES			0x00020000
-#define DF_NO_STACK_DOUBLE	0x00040000
-#define DF_NO_NUKES			0x00080000
-#define DF_NO_SPHERES		0x00100000
-//ROGUE
-
-/*
-ROGUE - VERSIONS
-1234	08/13/1998		Activision
-1235	08/14/1998		Id Software
-1236	08/15/1998		Steve Tietze
-1237	08/15/1998		Phil Dobranski
-1238	08/15/1998		John Sheley
-1239	08/17/1998		Barrett Alexander
-1230	08/17/1998		Brandon Fish
-1245	08/17/1998		Don MacAskill
-1246	08/17/1998		David "Zoid" Kirsch
-1247	08/17/1998		Manu Smith
-1248	08/17/1998		Geoff Scully
-1249	08/17/1998		Andy Van Fossen
-1240	08/20/1998		Activision Build 2
-1256	08/20/1998		Ranger Clan
-1257	08/20/1998		Ensemble Studios
-1258	08/21/1998		Robert Duffy
-1259	08/21/1998		Stephen Seachord
-1250	08/21/1998		Stephen Heaslip
-1267	08/21/1998		Samir Sandesara
-1268	08/21/1998		Oliver Wyman
-1269	08/21/1998		Steven Marchegiano
-1260	08/21/1998		Build #2 for Nihilistic
-1278	08/21/1998		Build #2 for Ensemble
-
-9999	08/20/1998		Internal Use
-*/
-#define ROGUE_VERSION_ID		1278
-
-#define ROGUE_VERSION_STRING	"08/21/1998 Beta 2 for Ensemble"
-
-// ROGUE
-/*
-==========================================================
-
-  ELEMENTS COMMUNICATED ACROSS THE NET
-
-==========================================================
-*/
-
-#define	ANGLE2SHORT(x)	((int)((x)*65536/360) & 65535)
-#define	SHORT2ANGLE(x)	((x)*(360.0/65536))
-
-
-//
-// 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.
-//
-#define	CS_NAME				0
-#define	CS_CDTRACK			1
-#define	CS_SKY				2
-#define	CS_SKYAXIS			3		// %f %f %f format
-#define	CS_SKYROTATE		4
-#define	CS_STATUSBAR		5		// display program string
-
-#define CS_AIRACCEL			29		// air acceleration control
-#define	CS_MAXCLIENTS		30
-#define	CS_MAPCHECKSUM		31		// for catching cheater maps
-
-#define	CS_MODELS			32
-#define	CS_SOUNDS			(CS_MODELS+MAX_MODELS)
-#define	CS_IMAGES			(CS_SOUNDS+MAX_SOUNDS)
-#define	CS_LIGHTS			(CS_IMAGES+MAX_IMAGES)
-#define	CS_ITEMS			(CS_LIGHTS+MAX_LIGHTSTYLES)
-#define	CS_PLAYERSKINS		(CS_ITEMS+MAX_ITEMS)
-#define CS_GENERAL			(CS_PLAYERSKINS+MAX_CLIENTS)
-#define	MAX_CONFIGSTRINGS	(CS_GENERAL+MAX_GENERAL)
-
-
-//==============================================
-
-
-// entity_state_t->event values
-// ertity events are for effects that take place reletive
-// to an existing entities origin.  Very network efficient.
-// All muzzle flashes really should be converted to events...
-typedef enum
-{
-	EV_NONE,
-	EV_ITEM_RESPAWN,
-	EV_FOOTSTEP,
-	EV_FALLSHORT,
-	EV_FALL,
-	EV_FALLFAR,
-	EV_PLAYER_TELEPORT,
-	EV_OTHER_TELEPORT
-} entity_event_t;
-
-
-// entity_state_t is the information conveyed from the server
-// in an update message about entities that the client will
-// need to render in some way
-typedef struct entity_state_s
-{
-	int		number;			// edict index
-
-	vec3_t	origin;
-	vec3_t	angles;
-	vec3_t	old_origin;		// for lerping
-	int		modelindex;
-	int		modelindex2, modelindex3, modelindex4;	// weapons, CTF flags, etc
-	int		frame;
-	int		skinnum;
-	unsigned int		effects;		// PGM - we're filling it, so it needs to be unsigned
-	int		renderfx;
-	int		solid;			// for client side prediction, 8*(bits 0-4) is x/y radius
-							// 8*(bits 5-9) is z down distance, 8(bits10-15) is z up
-							// gi.linkentity sets this properly
-	int		sound;			// for looping sounds, to guarantee shutoff
-	int		event;			// impulse events -- muzzle flashes, footsteps, etc
-							// events only go out for a single frame, they
-							// are automatically cleared each frame
-} entity_state_t;
-
-//==============================================
-
-
-// player_state_t is the information needed in addition to pmove_state_t
-// to rendered 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
-typedef struct
-{
-	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
-	vec3_t		kick_angles;	// add to view direction to get render angles
-								// set by weapon kicks, pain effects, etc
-
-	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
-} player_state_t;
-
-
-// ==================
-// PGM 
-#define VIDREF_GL		1
-#define VIDREF_SOFT		2
-#define VIDREF_OTHER	3
-
-extern int vidref_val;
-// PGM
-// ==================
-
-/* FIXME: figure out how to do this cleanly without kilometric headers */
-
-/* game dll */
-#include "../game/game.h"		/* baseq2 */
-#include "../game/g_local.h"
-//#include "../ctf/game.h"		/* ctf */
-//#include "../ctf/p_menu.h"
-//#include "../ctf/g_ctf.h"
-/* common */
-#include "../qcommon/qcommon.h"
-#include "../qcommon/qfiles.h"
-/* client */
-#include "../client/cdaudio.h"
-#include "../client/ref.h"
-#include "../client/vid.h"
-#include "../client/screen.h"
-#include "../client/snd_loc.h"
-#include "../client/sound.h"
-#include "../client/input.h"
-#include "../client/keys.h"
-#include "../client/console.h"
-#include "../client/client.h"
-#include "../client/qmenu.h"
-/* refresh */
-#include "../ref/r_local.h"
-/* server */
-#include "../server/server.h"
--- a/qcommon/cmd.c
+++ /dev/null
@@ -1,876 +1,0 @@
-// cmd.c -- Quake script command processing module
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-void Cmd_ForwardToServer (void);
-
-#define	MAX_ALIAS_NAME	32
-
-typedef struct cmdalias_s
-{
-	struct cmdalias_s	*next;
-	char	name[MAX_ALIAS_NAME];
-	char	*value;
-} cmdalias_t;
-
-cmdalias_t	*cmd_alias;
-
-qboolean	cmd_wait;
-
-#define	ALIAS_LOOP_COUNT	16
-int		alias_count;		// for detecting runaway loops
-
-
-//=============================================================================
-
-/*
-============
-Cmd_Wait_f
-
-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;
-}
-
-
-/*
-=============================================================================
-
-						COMMAND BUFFER
-
-=============================================================================
-*/
-
-sizebuf_t	cmd_text;
-byte		cmd_text_buf[8192];
-
-byte		defer_text_buf[8192];
-
-/*
-============
-Cbuf_Init
-============
-*/
-void Cbuf_Init (void)
-{
-	SZ_Init (&cmd_text, cmd_text_buf, sizeof(cmd_text_buf));
-}
-
-/*
-============
-Cbuf_AddText
-
-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, strlen (text));
-}
-
-
-/*
-============
-Cbuf_InsertText
-
-Adds command text immediately after the current command
-Adds a \n to the text
-FIXME: actually change the command buffer to do less copying
-============
-*/
-void Cbuf_InsertText (char *text)
-{
-	char	*temp;
-	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);
-	}
-	else
-		temp = NULL;	// shut up compiler
-		
-// add the entire text of the file
-	Cbuf_AddText (text);
-	
-// add the copied off data
-	if (templen)
-	{
-		SZ_Write (&cmd_text, temp, templen);
-		Z_Free (temp);
-	}
-}
-
-
-/*
-============
-Cbuf_CopyToDefer
-============
-*/
-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;
-}
-
-/*
-============
-Cbuf_InsertFromDefer
-============
-*/
-void Cbuf_InsertFromDefer (void)
-{
-	Cbuf_InsertText ((char *)defer_text_buf);
-	defer_text_buf[0] = 0;
-}
-
-
-/*
-============
-Cbuf_ExecuteText
-============
-*/
-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");
-	}
-}
-
-/*
-============
-Cbuf_Execute
-============
-*/
-void Cbuf_Execute (void)
-{
-	int		i;
-	char	*text;
-	char	line[1024];
-	int		quotes;
-
-	alias_count = 0;		// don't allow infinite alias loops
-
-	while (cmd_text.cursize)
-	{
-// find a \n or ; line break
-		text = (char *)cmd_text.data;
-
-		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);
-		}
-
-// execute the command line
-		Cmd_ExecuteString (line);
-		
-		if (cmd_wait)
-		{
-			// skip out while text still remains in buffer, leaving it
-			// for next frame
-			cmd_wait = false;
-			break;
-		}
-	}
-}
-
-
-/*
-===============
-Cbuf_AddEarlyCommands
-
-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;
-	}
-}
-
-/*
-=================
-Cbuf_AddLateCommands
-
-Adds command line parameters as script statements
-Commands lead with a + and continue until another + or -
-quake +vid_ref gl +map amlev1
-
-Returns true if any late commands were added, which
-will keep the demoloop from immediately starting
-=================
-*/
-qboolean Cbuf_AddLateCommands (void)
-{
-	int		i, j;
-	int		s;
-	char	*text, *build, c;
-	int		argc;
-	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;
-}
-
-
-/*
-==============================================================================
-
-						SCRIPT COMMANDS
-
-==============================================================================
-*/
-
-
-/*
-===============
-Cmd_Exec_f
-===============
-*/
-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);
-}
-
-
-/*
-===============
-Cmd_Echo_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");
-}
-
-/*
-===============
-Cmd_Alias_f
-
-Creates a new command that executes a command string (possibly ; seperated)
-===============
-*/
-void Cmd_Alias_f (void)
-{
-	cmdalias_t	*a;
-	char		cmd[1024];
-	int			i, c;
-	char		*s;
-
-	if (Cmd_Argc() == 1)
-	{
-		Com_Printf ("Current alias commands:\n");
-		for (a = cmd_alias ; a ; a=a->next)
-			Com_Printf ("%s : %s\n", a->name, a->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 (a = cmd_alias ; a ; a=a->next)
-	{
-		if (!strcmp(s, a->name))
-		{
-			Z_Free (a->value);
-			break;
-		}
-	}
-
-	if (!a)
-	{
-		a = Z_Malloc (sizeof(cmdalias_t));
-		a->next = cmd_alias;
-		cmd_alias = a;
-	}
-	strcpy (a->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");
-	
-	a->value = CopyString (cmd);
-}
-
-/*
-=============================================================================
-
-					COMMAND EXECUTION
-
-=============================================================================
-*/
-
-typedef struct cmd_function_s
-{
-	struct cmd_function_s	*next;
-	char					*name;
-	xcommand_t				function;
-} cmd_function_t;
-
-
-static	int			cmd_argc;
-static	char		*cmd_argv[MAX_STRING_TOKENS];
-static	char		*cmd_null_string = "";
-static	char		cmd_args[MAX_STRING_CHARS];
-
-static	cmd_function_t	*cmd_functions;		// possible commands to execute
-
-/*
-============
-Cmd_Argc
-============
-*/
-int		Cmd_Argc (void)
-{
-	return cmd_argc;
-}
-
-/*
-============
-Cmd_Argv
-============
-*/
-char	*Cmd_Argv (int arg)
-{
-	if ( (unsigned)arg >= cmd_argc )
-		return cmd_null_string;
-	return cmd_argv[arg];	
-}
-
-/*
-============
-Cmd_Args
-
-Returns a single string containing argv(1) to argv(argc()-1)
-============
-*/
-char		*Cmd_Args (void)
-{
-	return cmd_args;
-}
-
-
-/*
-======================
-Cmd_MacroExpandString
-======================
-*/
-char *Cmd_MacroExpandString (char *text)
-{
-	int		i, j, count, len;
-	qboolean	inquote;
-	char	*scan;
-	static	char	expanded[MAX_STRING_CHARS];
-	char	temporary[MAX_STRING_CHARS];
-	char	*token, *start;
-
-	inquote = false;
-	scan = text;
-
-	len = strlen (scan);
-	if (len >= MAX_STRING_CHARS)
-	{
-		Com_Printf ("Line exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
-		return NULL;
-	}
-
-	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 %i chars, discarded.\n", MAX_STRING_CHARS);
-			return NULL;
-		}
-
-		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 NULL;
-		}
-	}
-
-	if (inquote)
-	{
-		Com_Printf ("Line has unmatched quote, discarded.\n");
-		return NULL;
-	}
-
-	return scan;
-}
-
-
-/*
-============
-Cmd_TokenizeString
-
-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;
-	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)
-		return;
-
-	while (1)
-	{
-// skip whitespace up to a /n
-		while (*text && *text <= ' ' && *text != '\n')
-		{
-			text++;
-		}
-		
-		if (*text == '\n')
-		{	// a newline seperates commands in the buffer
-			text++;
-			break;
-		}
-
-		if (!*text)
-			return;
-
-		// set cmd_args to everything after the first arg
-		if (cmd_argc == 1)
-		{
-			int		l;
-
-			strcpy (cmd_args, text);
-
-			// strip off any trailing whitespace
-			l = strlen(cmd_args) - 1;
-			for ( ; l >= 0 ; l--)
-				if (cmd_args[l] <= ' ')
-					cmd_args[l] = 0;
-				else
-					break;
-		}
-			
-		com_token = COM_Parse (&text);
-		if (!text)
-			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++;
-		}
-	}
-	
-}
-
-
-/*
-============
-Cmd_AddCommand
-============
-*/
-void	Cmd_AddCommand (char *cmd_name, xcommand_t function)
-{
-	cmd_function_t	*cmd;
-	
-// fail if the command is a variable name
-	if (Cvar_VariableString(cmd_name)[0])
-	{
-		Com_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
-		return;
-	}
-	
-// fail if the command already exists
-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
-	{
-		if (!strcmp (cmd_name, cmd->name))
-		{
-			Com_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
-			return;
-		}
-	}
-
-	cmd = Z_Malloc (sizeof(cmd_function_t));
-	cmd->name = cmd_name;
-	cmd->function = function;
-	cmd->next = cmd_functions;
-	cmd_functions = cmd;
-}
-
-/*
-============
-Cmd_RemoveCommand
-============
-*/
-void	Cmd_RemoveCommand (char *cmd_name)
-{
-	cmd_function_t	*cmd, **back;
-
-	back = &cmd_functions;
-	while (1)
-	{
-		cmd = *back;
-		if (!cmd)
-		{
-			Com_Printf ("Cmd_RemoveCommand: %s not added\n", cmd_name);
-			return;
-		}
-		if (!strcmp (cmd_name, cmd->name))
-		{
-			*back = cmd->next;
-			Z_Free (cmd);
-			return;
-		}
-		back = &cmd->next;
-	}
-}
-
-/*
-============
-Cmd_Exists
-============
-*/
-qboolean	Cmd_Exists (char *cmd_name)
-{
-	cmd_function_t	*cmd;
-
-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
-	{
-		if (!strcmp (cmd_name,cmd->name))
-			return true;
-	}
-
-	return false;
-}
-
-
-
-/*
-============
-Cmd_CompleteCommand
-============
-*/
-char *Cmd_CompleteCommand (char *partial)
-{
-	cmd_function_t	*cmd;
-	int				len;
-	cmdalias_t		*a;
-	
-	len = strlen(partial);
-	
-	if (!len)
-		return NULL;
-		
-// check for exact match
-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
-		if (!strcmp (partial,cmd->name))
-			return cmd->name;
-	for (a=cmd_alias ; a ; a=a->next)
-		if (!strcmp (partial, a->name))
-			return a->name;
-
-// check for partial match
-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
-		if (!strncmp (partial,cmd->name, len))
-			return cmd->name;
-	for (a=cmd_alias ; a ; a=a->next)
-		if (!strncmp (partial, a->name, len))
-			return a->name;
-
-	return NULL;
-}
-
-
-/*
-============
-Cmd_ExecuteString
-
-A complete command line has been parsed, so try to execute it
-FIXME: lookupnoadd the token to speed search?
-============
-*/
-void	Cmd_ExecuteString (char *text)
-{	
-	cmd_function_t	*cmd;
-	cmdalias_t		*a;
-
-	Cmd_TokenizeString (text, true);
-			
-	// execute the command line
-	if (!Cmd_Argc())
-		return;		// no tokens
-
-	// check functions
-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
-	{
-		if (!cistrcmp (cmd_argv[0],cmd->name))
-		{
-			if (!cmd->function)
-			{	// forward to server command
-				Cmd_ExecuteString (va("cmd %s", text));
-			}
-			else
-				cmd->function ();
-			return;
-		}
-	}
-
-	// check alias
-	for (a=cmd_alias ; a ; 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 ();
-}
-
-/*
-============
-Cmd_List_f
-============
-*/
-void Cmd_List_f (void)
-{
-	cmd_function_t	*cmd;
-	int				i;
-
-	i = 0;
-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next, i++)
-		Com_Printf ("%s\n", cmd->name);
-	Com_Printf ("%i commands\n", i);
-}
-
-/*
-============
-Cmd_Init
-============
-*/
-void Cmd_Init (void)
-{
-//
-// register our commands
-//
-	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);
-}
-
--- a/qcommon/cmodel.c
+++ /dev/null
@@ -1,1745 +1,0 @@
-// cmodel.c -- model loading
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.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
-
-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;
-}
-
-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);
-}
-
--- a/qcommon/common.c
+++ /dev/null
@@ -1,1563 +1,0 @@
-// common.c -- misc functions used in client and server
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.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
-==================
-*/
-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_s
-{
-	struct zhead_s	*prev, *next;
-	short	magic;
-	short	tag;			// for group free
-	int		size;
-} zhead_t;
-
-zhead_t		z_chain;
-int		z_count, 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(zhead_t);
-	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;
-}
-
-//========================================================
-
-float	qfrand(void)
-{
-	return (rand()&32767)* (1.0/32767);
-}
-
-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);
-	}	
-}
--- a/qcommon/crc.c
+++ /dev/null
@@ -1,74 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.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/qcommon/crc.h
+++ /dev/null
@@ -1,4 +1,0 @@
-void CRC_Init(unsigned short *crcvalue);
-void CRC_ProcessByte(unsigned short *crcvalue, byte data);
-unsigned short CRC_Value(unsigned short crcvalue);
-unsigned short CRC_Block (byte *start, int count);
--- a/qcommon/cvar.c
+++ /dev/null
@@ -1,511 +1,0 @@
-// cvar.c -- dynamic variable tracking
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-cvar_t	*cvar_vars;
-
-/*
-============
-Cvar_InfoValidate
-============
-*/
-static qboolean Cvar_InfoValidate (char *s)
-{
-	if (strstr (s, "\\"))
-		return false;
-	if (strstr (s, "\""))
-		return false;
-	if (strstr (s, ";"))
-		return false;
-	return true;
-}
-
-/*
-============
-Cvar_FindVar
-============
-*/
-static cvar_t *Cvar_FindVar (char *var_name)
-{
-	cvar_t	*var;
-	
-	for (var=cvar_vars ; var ; var=var->next)
-		if (!strcmp (var_name, var->name))
-			return var;
-
-	return NULL;
-}
-
-/*
-============
-Cvar_VariableValue
-============
-*/
-float Cvar_VariableValue (char *var_name)
-{
-	cvar_t	*var;
-	
-	var = Cvar_FindVar (var_name);
-	if (!var)
-		return 0;
-	return atof (var->string);
-}
-
-
-/*
-============
-Cvar_VariableString
-============
-*/
-char *Cvar_VariableString (char *var_name)
-{
-	cvar_t *var;
-	
-	var = Cvar_FindVar (var_name);
-	if (!var)
-		return "";
-	return var->string;
-}
-
-
-/*
-============
-Cvar_CompleteVariable
-============
-*/
-char *Cvar_CompleteVariable (char *partial)
-{
-	cvar_t		*cvar;
-	int			len;
-	
-	len = strlen(partial);
-	
-	if (!len)
-		return NULL;
-		
-	// check exact match
-	for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
-		if (!strcmp (partial,cvar->name))
-			return cvar->name;
-
-	// check partial match
-	for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
-		if (!strncmp (partial,cvar->name, len))
-			return cvar->name;
-
-	return NULL;
-}
-
-
-/*
-============
-Cvar_Get
-
-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	*var;
-	
-	if (flags & (CVAR_USERINFO | CVAR_SERVERINFO))
-	{
-		if (!Cvar_InfoValidate (var_name))
-		{
-			Com_Printf("invalid info cvar name\n");
-			return NULL;
-		}
-	}
-
-	var = Cvar_FindVar (var_name);
-	if (var)
-	{
-		var->flags |= flags;
-		return var;
-	}
-
-	if (!var_value)
-		return NULL;
-
-	if (flags & (CVAR_USERINFO | CVAR_SERVERINFO))
-	{
-		if (!Cvar_InfoValidate (var_value))
-		{
-			Com_Printf("invalid info cvar value\n");
-			return NULL;
-		}
-	}
-
-	var = Z_Malloc (sizeof(*var));
-	var->name = CopyString (var_name);
-	var->string = CopyString (var_value);
-	var->modified = true;
-	var->value = atof (var->string);
-
-	// link the variable in
-	var->next = cvar_vars;
-	cvar_vars = var;
-
-	var->flags = flags;
-
-	return var;
-}
-
-/*
-============
-Cvar_Set2
-============
-*/
-cvar_t *Cvar_Set2 (char *var_name, char *value, qboolean force)
-{
-	cvar_t	*var;
-
-	var = Cvar_FindVar (var_name);
-	if (!var)
-	{	// create it
-		return Cvar_Get (var_name, value, 0);
-	}
-
-	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) == 0)
-					return var;
-				Z_Free (var->latched_string);
-			}
-			else
-			{
-				if (strcmp(value, var->string) == 0)
-					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 = NULL;
-		}
-	}
-
-	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;
-}
-
-/*
-============
-Cvar_ForceSet
-============
-*/
-cvar_t *Cvar_ForceSet (char *var_name, char *value)
-{
-	return Cvar_Set2 (var_name, value, true);
-}
-
-/*
-============
-Cvar_Set
-============
-*/
-cvar_t *Cvar_Set (char *var_name, char *value)
-{
-	return Cvar_Set2 (var_name, value, false);
-}
-
-/*
-============
-Cvar_FullSet
-============
-*/
-cvar_t *Cvar_FullSet (char *var_name, char *value, int flags)
-{
-	cvar_t	*var;
-	
-	var = Cvar_FindVar (var_name);
-	if (!var)
-	{	// create it
-		return Cvar_Get (var_name, value, flags);
-	}
-
-	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;
-}
-
-/*
-============
-Cvar_SetValue
-============
-*/
-void Cvar_SetValue (char *var_name, float value)
-{
-	char	val[32];
-
-	if (value == (int)value)
-		Com_sprintf (val, sizeof(val), "%i",(int)value);
-	else
-		Com_sprintf (val, sizeof(val), "%f",value);
-	Cvar_Set (var_name, val);
-}
-
-
-/*
-============
-Cvar_GetLatchedVars
-
-Any variables with latched values will now be updated
-============
-*/
-void Cvar_GetLatchedVars (void)
-{
-	cvar_t	*var;
-
-	for (var = cvar_vars ; var ; var = var->next)
-	{
-		if (!var->latched_string)
-			continue;
-		Z_Free (var->string);
-		var->string = var->latched_string;
-		var->latched_string = NULL;
-		var->value = atof(var->string);
-		if (!strcmp(var->name, "game"))
-		{
-			FS_SetGamedir (var->string);
-			FS_ExecAutoexec ();
-		}
-	}
-}
-
-/*
-============
-Cvar_Command
-
-Handles variable inspection and changing from the console
-============
-*/
-qboolean Cvar_Command (void)
-{
-	cvar_t			*v;
-
-// check variables
-	v = Cvar_FindVar (Cmd_Argv(0));
-	if (!v)
-		return false;
-		
-// perform a variable print or set
-	if (Cmd_Argc() == 1)
-	{
-		Com_Printf ("\"%s\" is \"%s\"\n", v->name, v->string);
-		return true;
-	}
-
-	Cvar_Set (v->name, Cmd_Argv(1));
-	return true;
-}
-
-
-/*
-============
-Cvar_Set_f
-
-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));
-}
-
-
-/*
-============
-Cvar_WriteVariables
-
-Appends lines containing "set variable value" for all variables
-with the archive flag set to true.
-============
-*/
-void Cvar_WriteVariables (char *path)
-{
-	cvar_t	*var;
-	char	buffer[1024];
-	FILE	*f;
-
-	f = fopen (path, "a");
-	for (var = cvar_vars ; var ; var = var->next)
-	{
-		if (var->flags & CVAR_ARCHIVE)
-		{
-			Com_sprintf (buffer, sizeof(buffer), "set %s \"%s\"\n", var->name, var->string);
-			fprintf (f, "%s", buffer);
-		}
-	}
-	fclose (f);
-}
-
-/*
-============
-Cvar_List_f
-
-============
-*/
-void Cvar_List_f (void)
-{
-	cvar_t	*var;
-	int		i;
-
-	i = 0;
-	for (var = cvar_vars ; var ; var = var->next, i++)
-	{
-		if (var->flags & CVAR_ARCHIVE)
-			Com_Printf ("*");
-		else
-			Com_Printf (" ");
-		if (var->flags & CVAR_USERINFO)
-			Com_Printf ("U");
-		else
-			Com_Printf (" ");
-		if (var->flags & CVAR_SERVERINFO)
-			Com_Printf ("S");
-		else
-			Com_Printf (" ");
-		if (var->flags & CVAR_NOSET)
-			Com_Printf ("-");
-		else if (var->flags & CVAR_LATCH)
-			Com_Printf ("L");
-		else
-			Com_Printf (" ");
-		Com_Printf (" %s \"%s\"\n", var->name, var->string);
-	}
-	Com_Printf ("%i cvars\n", i);
-}
-
-
-qboolean userinfo_modified;
-
-
-char	*Cvar_BitInfo (int bit)
-{
-	static char	info[MAX_INFO_STRING];
-	cvar_t	*var;
-
-	info[0] = 0;
-
-	for (var = cvar_vars ; var ; var = var->next)
-	{
-		if (var->flags & bit)
-			Info_SetValueForKey (info, var->name, var->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);
-}
-
-/*
-============
-Cvar_Init
-
-Reads in all archived cvars
-============
-*/
-void Cvar_Init (void)
-{
-	Cmd_AddCommand ("set", Cvar_Set_f);
-	Cmd_AddCommand ("cvarlist", Cvar_List_f);
-
-}
--- a/qcommon/files.c
+++ /dev/null
@@ -1,859 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.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 | SFF_HIDDEN | SFF_SYSTEM))
-		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);
-}
-
-
-
--- a/qcommon/md4.c
+++ /dev/null
@@ -1,275 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.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;
-}
--- a/qcommon/net_chan.c
+++ /dev/null
@@ -1,369 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.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/qcommon/pmove.c
+++ /dev/null
@@ -1,1337 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.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/qcommon/qcommon.h
+++ /dev/null
@@ -1,754 +1,0 @@
-#define	VERSION		3.19
-
-#define	BASEDIRNAME	"baseq2"
-
-//============================================================================
-
-typedef struct sizebuf_s
-{
-	qboolean	allowoverflow;	// if false, do a Com_Error
-	qboolean	overflowed;		// set to true if the buffer size failed
-	byte	*data;
-	int		maxsize;
-	int		cursize;
-	int		readcount;
-} sizebuf_t;
-
-void SZ_Init (sizebuf_t *buf, byte *data, int length);
-void SZ_Clear (sizebuf_t *buf);
-void *SZ_GetSpace (sizebuf_t *buf, int length);
-void SZ_Write (sizebuf_t *buf, void *data, int length);
-void SZ_Print (sizebuf_t *buf, char *data);	// strcats onto the sizebuf
-
-//============================================================================
-
-struct usercmd_s;
-struct entity_state_s;
-
-void MSG_WriteChar (sizebuf_t *sb, int c);
-void MSG_WriteByte (sizebuf_t *sb, int c);
-void MSG_WriteShort (sizebuf_t *sb, int c);
-void MSG_WriteLong (sizebuf_t *sb, int c);
-void MSG_WriteFloat (sizebuf_t *sb, float f);
-void MSG_WriteString (sizebuf_t *sb, char *s);
-void MSG_WriteCoord (sizebuf_t *sb, float f);
-void MSG_WritePos (sizebuf_t *sb, vec3_t pos);
-void MSG_WriteAngle (sizebuf_t *sb, float f);
-void MSG_WriteAngle16 (sizebuf_t *sb, float f);
-void MSG_WriteDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd);
-void MSG_WriteDeltaEntity (struct entity_state_s *from, struct entity_state_s *to, sizebuf_t *msg, qboolean force, qboolean newentity);
-void MSG_WriteDir (sizebuf_t *sb, vec3_t vector);
-
-
-void	MSG_BeginReading (sizebuf_t *sb);
-
-int		MSG_ReadChar (sizebuf_t *sb);
-int		MSG_ReadByte (sizebuf_t *sb);
-int		MSG_ReadShort (sizebuf_t *sb);
-int		MSG_ReadLong (sizebuf_t *sb);
-float	MSG_ReadFloat (sizebuf_t *sb);
-char	*MSG_ReadString (sizebuf_t *sb);
-char	*MSG_ReadStringLine (sizebuf_t *sb);
-
-float	MSG_ReadCoord (sizebuf_t *sb);
-void	MSG_ReadPos (sizebuf_t *sb, vec3_t pos);
-float	MSG_ReadAngle (sizebuf_t *sb);
-float	MSG_ReadAngle16 (sizebuf_t *sb);
-void	MSG_ReadDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd);
-
-void	MSG_ReadDir (sizebuf_t *sb, vec3_t vector);
-
-void	MSG_ReadData (sizebuf_t *sb, void *buffer, int size);
-
-//============================================================================
-
-extern	qboolean		bigendien;
-
-extern	short	BigShort (short l);
-extern	short	LittleShort (short l);
-extern	int		BigLong (int l);
-extern	int		LittleLong (int l);
-extern	float	BigFloat (float l);
-extern	float	LittleFloat (float l);
-
-//============================================================================
-
-
-int	COM_Argc (void);
-char *COM_Argv (int arg);	// range and null checked
-void COM_ClearArgv (int arg);
-int COM_CheckParm (char *parm);
-void COM_AddParm (char *parm);
-
-void COM_Init (void);
-void COM_InitArgv (int argc, char **argv);
-
-char *CopyString (char *in);
-
-//============================================================================
-
-void Info_Print (char *s);
-
-
-/* crc.h */
-
-void CRC_Init(unsigned short *crcvalue);
-void CRC_ProcessByte(unsigned short *crcvalue, byte data);
-unsigned short CRC_Value(unsigned short crcvalue);
-unsigned short CRC_Block (byte *start, int count);
-
-
-
-/*
-==============================================================
-
-PROTOCOL
-
-==============================================================
-*/
-
-// protocol.h -- communications protocols
-
-#define	PROTOCOL_VERSION	34
-
-//=========================================
-
-#define	PORT_MASTER	27900
-#define	PORT_CLIENT	27901
-#define	PORT_SERVER	27910
-
-//=========================================
-
-#define	UPDATE_BACKUP	16	// copies of entity_state_t to keep buffered
-							// must be power of two
-#define	UPDATE_MASK		(UPDATE_BACKUP-1)
-
-
-
-//==================
-// the svc_strings[] array in cl_parse.c should mirror this
-//==================
-
-//
-// server to client: protocol bytes that can be directly added to messages
-//
-enum svc_ops_e
-{
-	svc_bad,
-
-	// 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,					// <see code>
-	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
-//
-enum clc_ops_e
-{
-	clc_bad,
-	clc_nop, 		
-	clc_move,				// [[usercmd_t]
-	clc_userinfo,			// [[userinfo string]
-	clc_stringcmd			// [string] message
-};
-
-//==============================================
-
-// plyer_state_t communication
-
-#define	PS_M_TYPE			(1<<0)
-#define	PS_M_ORIGIN			(1<<1)
-#define	PS_M_VELOCITY		(1<<2)
-#define	PS_M_TIME			(1<<3)
-#define	PS_M_FLAGS			(1<<4)
-#define	PS_M_GRAVITY		(1<<5)
-#define	PS_M_DELTA_ANGLES	(1<<6)
-
-#define	PS_VIEWOFFSET		(1<<7)
-#define	PS_VIEWANGLES		(1<<8)
-#define	PS_KICKANGLES		(1<<9)
-#define	PS_BLEND			(1<<10)
-#define	PS_FOV				(1<<11)
-#define	PS_WEAPONINDEX		(1<<12)
-#define	PS_WEAPONFRAME		(1<<13)
-#define	PS_RDFLAGS			(1<<14)
-
-//==============================================
-
-// user_cmd_t communication
-
-// ms and light always sent, the others are optional
-#define	CM_ANGLE1 	(1<<0)
-#define	CM_ANGLE2 	(1<<1)
-#define	CM_ANGLE3 	(1<<2)
-#define	CM_FORWARD	(1<<3)
-#define	CM_SIDE		(1<<4)
-#define	CM_UP		(1<<5)
-#define	CM_BUTTONS	(1<<6)
-#define	CM_IMPULSE	(1<<7)
-
-//==============================================
-
-// a sound without an ent or pos will be a local only sound
-#define	SND_VOLUME		(1<<0)		// a byte
-#define	SND_ATTENUATION	(1<<1)		// a byte
-#define	SND_POS			(1<<2)		// three coordinates
-#define	SND_ENT			(1<<3)		// a short 0-2: channel, 3-12: entity
-#define	SND_OFFSET		(1<<4)		// a byte, msec offset from frame start
-
-#define DEFAULT_SOUND_PACKET_VOLUME	1.0
-#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
-
-//==============================================
-
-// entity_state_t communication
-
-// try to pack the common update flags into the first byte
-#define	U_ORIGIN1	(1<<0)
-#define	U_ORIGIN2	(1<<1)
-#define	U_ANGLE2	(1<<2)
-#define	U_ANGLE3	(1<<3)
-#define	U_FRAME8	(1<<4)		// frame is a byte
-#define	U_EVENT		(1<<5)
-#define	U_REMOVE	(1<<6)		// REMOVE this entity, don't add it
-#define	U_MOREBITS1	(1<<7)		// read one additional byte
-
-// second byte
-#define	U_NUMBER16	(1<<8)		// NUMBER8 is implicit if not set
-#define	U_ORIGIN3	(1<<9)
-#define	U_ANGLE1	(1<<10)
-#define	U_MODEL		(1<<11)
-#define U_RENDERFX8	(1<<12)		// fullbright, etc
-#define	U_EFFECTS8	(1<<14)		// autorotate, trails, etc
-#define	U_MOREBITS2	(1<<15)		// read one additional byte
-
-// third byte
-#define	U_SKIN8		(1<<16)
-#define	U_FRAME16	(1<<17)		// frame is a short
-#define	U_RENDERFX16 (1<<18)	// 8 + 16 = 32
-#define	U_EFFECTS16	(1<<19)		// 8 + 16 = 32
-#define	U_MODEL2	(1<<20)		// weapons, flags, etc
-#define	U_MODEL3	(1<<21)
-#define	U_MODEL4	(1<<22)
-#define	U_MOREBITS3	(1<<23)		// read one additional byte
-
-// fourth byte
-#define	U_OLDORIGIN	(1<<24)		// FIXME: get rid of this
-#define	U_SKIN16	(1<<25)
-#define	U_SOUND		(1<<26)
-#define	U_SOLID		(1<<27)
-
-
-/*
-==============================================================
-
-CMD
-
-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 ();
-
-*/
-
-void Cbuf_Init (void);
-// allocates an initial text buffer that will grow as needed
-
-void Cbuf_AddText (char *text);
-// as new commands are generated from the console or keybindings,
-// the text is added to the end of the command buffer.
-
-void Cbuf_InsertText (char *text);
-// when a command wants to issue other commands immediately, the text is
-// inserted at the beginning of the buffer, before any remaining unexecuted
-// commands.
-
-void Cbuf_ExecuteText (int exec_when, char *text);
-// this can be used in place of either Cbuf_AddText or Cbuf_InsertText
-
-void Cbuf_AddEarlyCommands (qboolean clear);
-// adds all the +set commands from the command line
-
-qboolean Cbuf_AddLateCommands (void);
-// adds all the remaining + commands from the command line
-// Returns true if any late commands were added, which
-// will keep the demoloop from immediately starting
-
-void Cbuf_Execute (void);
-// Pulls off \n terminated lines of text from the command buffer and sends
-// them through Cmd_ExecuteString.  Stops when the buffer is empty.
-// Normally called once per frame, but may be explicitly invoked.
-// Do not call inside a command function!
-
-void Cbuf_CopyToDefer (void);
-void Cbuf_InsertFromDefer (void);
-// These two functions are used to defer any pending commands while a map
-// is being loaded
-
-//===========================================================================
-
-/*
-
-Command execution takes a null terminated string, breaks it into tokens,
-then searches for a command or variable that matches the first token.
-
-*/
-
-typedef void (*xcommand_t) (void);
-
-void	Cmd_Init (void);
-
-void	Cmd_AddCommand (char *cmd_name, xcommand_t function);
-// called by the init functions of other parts of the program to
-// register commands and functions to call for them.
-// The cmd_name is referenced later, so it should not be in temp memory
-// if function is NULL, the command will be forwarded to the server
-// as a clc_stringcmd instead of executed locally
-void	Cmd_RemoveCommand (char *cmd_name);
-
-qboolean Cmd_Exists (char *cmd_name);
-// used by the cvar code to check for cvar / command name overlap
-
-char 	*Cmd_CompleteCommand (char *partial);
-// attempts to match a partial command for automatic command line completion
-// returns NULL if nothing fits
-
-int		Cmd_Argc (void);
-char	*Cmd_Argv (int arg);
-char	*Cmd_Args (void);
-// The functions that execute commands get their parameters with these
-// functions. Cmd_Argv () will return an empty string, not a NULL
-// if arg > argc, so string operations are always safe.
-
-void	Cmd_TokenizeString (char *text, qboolean macroExpand);
-// Takes a null terminated string.  Does not need to be /n terminated.
-// breaks the string up into arg tokens.
-
-void	Cmd_ExecuteString (char *text);
-// Parses a single line of text into arguments and tries to execute it
-// as if it was typed at the console
-
-void	Cmd_ForwardToServer (void);
-// 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.
-
-
-/*
-==============================================================
-
-CVAR
-
-==============================================================
-*/
-
-/*
-
-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.
-*/
-
-extern	cvar_t	*cvar_vars;
-
-cvar_t *Cvar_Get (char *var_name, char *value, int flags);
-// creates the variable if it doesn't exist, or returns the existing one
-// if it exists, the value will not be changed, but flags will be ORed in
-// that allows variables to be unarchived without needing bitflags
-
-cvar_t 	*Cvar_Set (char *var_name, char *value);
-// will create the variable if it doesn't exist
-
-cvar_t *Cvar_ForceSet (char *var_name, char *value);
-// will set the variable even if NOSET or LATCH
-
-cvar_t 	*Cvar_FullSet (char *var_name, char *value, int flags);
-
-void	Cvar_SetValue (char *var_name, float value);
-// expands value to a string and calls Cvar_Set
-
-float	Cvar_VariableValue (char *var_name);
-// returns 0 if not defined or non numeric
-
-char	*Cvar_VariableString (char *var_name);
-// returns an empty string if not defined
-
-char 	*Cvar_CompleteVariable (char *partial);
-// attempts to match a partial variable name for command line completion
-// returns NULL if nothing fits
-
-void	Cvar_GetLatchedVars (void);
-// any CVAR_LATCHED variables that have been set will now take effect
-
-qboolean Cvar_Command (void);
-// 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)
-
-void 	Cvar_WriteVariables (char *path);
-// appends lines containing "set variable value" for all variables
-// with the archive flag set to true.
-
-void	Cvar_Init (void);
-
-char	*Cvar_Userinfo (void);
-// returns an info string containing all the CVAR_USERINFO cvars
-
-char	*Cvar_Serverinfo (void);
-// returns an info string containing all the CVAR_SERVERINFO cvars
-
-extern	qboolean	userinfo_modified;
-// this is set each time a CVAR_USERINFO variable is changed
-// so that the client knows to send it to the server
-
-/*
-==============================================================
-
-NET
-
-==============================================================
-*/
-
-// net.h -- quake's interface to the networking layer
-
-#define	PORT_ANY	-1
-
-#define	MAX_MSGLEN		1400		// max length of a message
-#define	PACKET_HEADER	10			// two ints and a short
-
-typedef enum {NA_LOOPBACK, NA_BROADCAST, NA_IP, NA_IPX, NA_BROADCAST_IPX} netadrtype_t;
-
-typedef enum {NS_CLIENT, NS_SERVER} netsrc_t;
-
-typedef struct
-{
-	netadrtype_t	type;
-
-	byte	ip[4];
-	byte	ipx[10];
-
-	unsigned short	port;
-} netadr_t;
-
-void		NET_Init (void);
-void		NET_Shutdown (void);
-
-void		NET_Config (qboolean multiplayer);
-
-qboolean	NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message);
-void		NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to);
-
-qboolean	NET_CompareAdr (netadr_t a, netadr_t b);
-qboolean	NET_CompareBaseAdr (netadr_t a, netadr_t b);
-qboolean	NET_IsLocalAddress (netadr_t adr);
-char		*NET_AdrToString (netadr_t a);
-qboolean	NET_StringToAdr (char *s, netadr_t *a);
-void		NET_Sleep(int msec);
-
-//============================================================================
-
-#define	OLD_AVG		0.99		// total = oldtotal*OLD_AVG + new*(1-OLD_AVG)
-
-#define	MAX_LATENT	32
-
-typedef struct
-{
-	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
-	byte		message_buf[MAX_MSGLEN-16];		// leave space for header
-
-// message is copied to this buffer when it is first transfered
-	int			reliable_length;
-	byte		reliable_buf[MAX_MSGLEN-16];	// unacked reliable message
-} netchan_t;
-
-extern	netadr_t	net_from;
-extern	sizebuf_t	net_message;
-extern	byte		net_message_buffer[MAX_MSGLEN];
-
-
-void Netchan_Init (void);
-void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport);
-
-qboolean Netchan_NeedReliable (netchan_t *chan);
-void Netchan_Transmit (netchan_t *chan, int length, byte *data);
-void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data);
-void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...);
-qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg);
-
-qboolean Netchan_CanReliable (netchan_t *chan);
-
-
-/*
-==============================================================
-
-CMODEL
-
-==============================================================
-*/
-
-
-cmodel_t	*CM_LoadMap (char *name, qboolean clientload, unsigned *checksum);
-cmodel_t	*CM_InlineModel (char *name);	// *1, *2, etc
-
-int			CM_NumClusters (void);
-int			CM_NumInlineModels (void);
-char		*CM_EntityString (void);
-
-// creates a clipping hull for an arbitrary box
-int			CM_HeadnodeForBox (vec3_t mins, vec3_t maxs);
-
-
-// returns an ORed contents mask
-int			CM_PointContents (vec3_t p, int headnode);
-int			CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles);
-
-trace_t		CM_BoxTrace (vec3_t start, vec3_t end,
-						  vec3_t mins, vec3_t maxs,
-						  int headnode, int brushmask);
-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);
-
-byte		*CM_ClusterPVS (int cluster);
-byte		*CM_ClusterPHS (int cluster);
-
-int			CM_PointLeafnum (vec3_t p);
-
-// call with topnode set to the headnode, returns with topnode
-// set to the first node that splits the box
-int			CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list,
-							int listsize, int *topnode);
-
-int			CM_LeafContents (int leafnum);
-int			CM_LeafCluster (int leafnum);
-int			CM_LeafArea (int leafnum);
-
-void		CM_SetAreaPortalState (int portalnum, qboolean open);
-qboolean	CM_AreasConnected (int area1, int area2);
-
-int			CM_WriteAreaBits (byte *buffer, int area);
-qboolean	CM_HeadnodeVisible (int headnode, byte *visbits);
-
-void		CM_WritePortalState (FILE *f);
-void		CM_ReadPortalState (FILE *f);
-
-/*
-==============================================================
-
-PLAYER MOVEMENT CODE
-
-Common between server and client so prediction matches
-
-==============================================================
-*/
-
-extern float pm_airaccelerate;
-
-void Pmove (pmove_t *pmove);
-
-/*
-==============================================================
-
-FILESYSTEM
-
-==============================================================
-*/
-
-void	FS_InitFilesystem (void);
-void	FS_SetGamedir (char *dir);
-char	*FS_Gamedir (void);
-char	*FS_NextPath (char *prevpath);
-void	FS_ExecAutoexec (void);
-
-int		FS_FOpenFile (char *filename, FILE **file);
-void	FS_FCloseFile (FILE *f);
-// note: this can't be called from another DLL, due to MS libc issues
-
-int		FS_LoadFile (char *path, void **buffer);
-// a null buffer will just return the file length without loading
-// a -1 length is not present
-
-void	FS_Read (void *buffer, int len, FILE *f);
-// properly handles partial reads
-
-void	FS_FreeFile (void *buffer);
-
-void	FS_CreatePath (char *path);
-
-
-/*
-==============================================================
-
-MISC
-
-==============================================================
-*/
-
-#define	ERR_FATAL	0		// exit the entire game with a popup window
-#define	ERR_DROP	1		// print to console and disconnect from game
-#define	ERR_QUIT	2		// not an error, just a normal exit
-#define	ERR_DISCONNECT	2		// don't kill server
-
-#define	EXEC_NOW	0		// don't return until completed
-#define	EXEC_INSERT	1		// insert at current position, but don't run yet
-#define	EXEC_APPEND	2		// add to end of the command buffer
-
-#define	PRINT_ALL		0
-#define PRINT_DEVELOPER	1	// only print when "developer 1"
-
-void		Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush));
-void		Com_EndRedirect (void);
-void 		Com_Printf (char *fmt, ...);
-void 		Com_DPrintf (char *fmt, ...);
-void 		Com_Error (int code, char *fmt, ...);
-void 		Com_Quit (void);
-
-int			Com_ServerState (void);		// this should have just been a cvar...
-void		Com_SetServerState (int state);
-
-unsigned	Com_BlockChecksum (void *buffer, int length);
-byte		COM_BlockSequenceCRCByte (byte *base, int length, int sequence);
-
-float	qfrand(void);	// 0 ti 1
-float	crand(void);	// -1 to 1
-
-extern	cvar_t	*developer;
-extern	cvar_t	*dedicated;
-extern	cvar_t	*host_speeds;
-extern	cvar_t	*log_stats;
-
-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;
-
-void Z_Free (void *ptr);
-void *Z_Malloc (int size);			// returns 0 filled memory
-void *Z_TagMalloc (int size, int tag);
-void Z_FreeTags (int tag);
-
-void Qcommon_Init (int argc, char **argv);
-void Qcommon_Frame (int msec);
-
-#define NUMVERTEXNORMALS	162
-extern	vec3_t	bytedirs[NUMVERTEXNORMALS];
-
-// this is in the client code, but can be used for debugging from server
-void SCR_DebugGraph (float value, int color);
-
-
-/*
-==============================================================
-
-NON-PORTABLE SYSTEM SERVICES
-
-==============================================================
-*/
-
-enum{
-	THin	= 1,
-	THsnd	= 2,
-	THnet	= 3
-};
-
-extern uint sys_frame_time;
-
-void	Sys_Init (void);
-
-void	Sys_AppActivate (void);
-
-void	Sys_UnloadGame (void);
-
-char	*Sys_ConsoleInput (void);
-void	Sys_ConsoleOutput (char *string);
-void	Sys_SendKeyEvents (void);
-void	Sys_Error (char *error, ...);
-void	Sys_Quit (void);
-char	*Sys_GetClipboardData( void );
-void	Sys_CopyProtect (void);
-
-/*
-==============================================================
-
-CLIENT / SERVER SYSTEMS
-
-==============================================================
-*/
-
-void CL_Init (void);
-void CL_Drop (void);
-void CL_Shutdown (void);
-void CL_Frame (int msec);
-void Con_Print (char *text);
-void SCR_BeginLoadingPlaque (void);
-
-void SV_Init (void);
-void SV_Shutdown (char *finalmsg, qboolean reconnect);
-void SV_Frame (int msec);
--- a/qcommon/qfiles.h
+++ /dev/null
@@ -1,460 +1,0 @@
-//
-// qfiles.h: quake file formats
-// This file must be identical in the quake and utils directories
-//
-
-/*
-========================================================================
-
-The .pak files are just a linear collapse of a directory tree
-
-========================================================================
-*/
-
-#define IDPAKHEADER		(('K'<<24)+('C'<<16)+('A'<<8)+'P')
-
-#pragma pack on
-
-typedef struct
-{
-	char	name[56];
-	int		filepos, filelen;
-} dpackfile_t;
-
-typedef struct
-{
-	int		ident;		// == IDPAKHEADER
-	int		dirofs;
-	int		dirlen;
-} dpackheader_t;
-
-#define	MAX_FILES_IN_PACK	4096
-
-
-/*
-========================================================================
-
-PCX files are used for as many images as possible
-
-========================================================================
-*/
-
-typedef struct
-{
-    char	manufacturer;
-    char	version;
-    char	encoding;
-    char	bits_per_pixel;
-    unsigned short	xmin,ymin,xmax,ymax;
-    unsigned short	hres,vres;
-    unsigned char	palette[48];
-    char	reserved;
-    char	color_planes;
-    unsigned short	bytes_per_line;
-    unsigned short	palette_type;
-    char	filler[58];
-    unsigned char	data;			// unbounded
-} pcx_t;
-
-
-/*
-========================================================================
-
-.MD2 triangle model file format
-
-========================================================================
-*/
-
-#define IDALIASHEADER		(('2'<<24)+('P'<<16)+('D'<<8)+'I')
-#define ALIAS_VERSION	8
-
-#define	MAX_TRIANGLES	4096
-#define MAX_VERTS		2048
-#define MAX_FRAMES		512
-#define MAX_MD2SKINS	32
-#define	MAX_SKINNAME	64
-
-typedef struct
-{
-	short	s;
-	short	t;
-} dstvert_t;
-
-typedef struct 
-{
-	short	index_xyz[3];
-	short	index_st[3];
-} dtriangle_t;
-
-typedef struct
-{
-	byte	v[3];			// scaled byte to fit in frame mins/maxs
-	byte	lightnormalindex;
-} dtrivertx_t;
-
-#define DTRIVERTX_V0   0
-#define DTRIVERTX_V1   1
-#define DTRIVERTX_V2   2
-#define DTRIVERTX_LNI  3
-#define DTRIVERTX_SIZE 4
-
-typedef struct
-{
-	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
-} daliasframe_t;
-
-
-// the 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.
-
-
-typedef struct
-{
-	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 list
-	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
-
-} dmdl_t;
-
-/*
-========================================================================
-
-.SP2 sprite file format
-
-========================================================================
-*/
-
-#define IDSPRITEHEADER	(('2'<<24)+('S'<<16)+('D'<<8)+'I')
-		// little-endian "IDS2"
-#define SPRITE_VERSION	2
-
-typedef struct
-{
-	int		width, height;
-	int		origin_x, origin_y;		// raster coordinates inside pic
-	char	name[MAX_SKINNAME];		// name of pcx file
-} dsprframe_t;
-
-typedef struct {
-	int			ident;
-	int			version;
-	int			numframes;
-	dsprframe_t	frames[1];			// variable sized
-} dsprite_t;
-
-/*
-==============================================================================
-
-  .WAL texture file format
-
-==============================================================================
-*/
-
-
-#define	MIPLEVELS	4
-typedef struct miptex_s
-{
-	char		name[32];
-	unsigned	width, height;
-	unsigned	offsets[MIPLEVELS];		// four mip maps stored
-	char		animname[32];			// next frame in animation chain
-	int			flags;
-	int			contents;
-	int			value;
-} miptex_t;
-
-
-
-/*
-==============================================================================
-
-  .BSP file format
-
-==============================================================================
-*/
-
-#define IDBSPHEADER	(('P'<<24)+('S'<<16)+('B'<<8)+'I')
-		// little-endian "IBSP"
-
-#define BSPVERSION	38
-
-
-// upper design bounds
-// leaffaces, leafbrushes, planes, and verts are still bounded by
-// 16 bit short limits
-#define	MAX_MAP_MODELS		1024
-#define	MAX_MAP_BRUSHES		8192
-#define	MAX_MAP_ENTITIES	2048
-#define	MAX_MAP_ENTSTRING	0x40000
-#define	MAX_MAP_TEXINFO		8192
-
-#define	MAX_MAP_AREAS		256
-#define	MAX_MAP_AREAPORTALS	1024
-#define	MAX_MAP_PLANES		65536
-#define	MAX_MAP_NODES		65536
-#define	MAX_MAP_BRUSHSIDES	65536
-#define	MAX_MAP_LEAFS		65536
-#define	MAX_MAP_VERTS		65536
-#define	MAX_MAP_FACES		65536
-#define	MAX_MAP_LEAFFACES	65536
-#define	MAX_MAP_LEAFBRUSHES 65536
-#define	MAX_MAP_PORTALS		65536
-#define	MAX_MAP_EDGES		128000
-#define	MAX_MAP_SURFEDGES	256000
-#define	MAX_MAP_LIGHTING	0x200000
-#define	MAX_MAP_VISIBILITY	0x100000
-
-// key / value pair sizes
-
-#define	MAX_KEY		32
-#define	MAX_VALUE	1024
-
-//=============================================================================
-
-typedef struct
-{
-	int		fileofs, filelen;
-} lump_t;
-
-#define	LUMP_ENTITIES		0
-#define	LUMP_PLANES			1
-#define	LUMP_VERTEXES		2
-#define	LUMP_VISIBILITY		3
-#define	LUMP_NODES			4
-#define	LUMP_TEXINFO		5
-#define	LUMP_FACES			6
-#define	LUMP_LIGHTING		7
-#define	LUMP_LEAFS			8
-#define	LUMP_LEAFFACES		9
-#define	LUMP_LEAFBRUSHES	10
-#define	LUMP_EDGES			11
-#define	LUMP_SURFEDGES		12
-#define	LUMP_MODELS			13
-#define	LUMP_BRUSHES		14
-#define	LUMP_BRUSHSIDES		15
-#define	LUMP_POP			16
-#define	LUMP_AREAS			17
-#define	LUMP_AREAPORTALS	18
-#define	HEADER_LUMPS		19
-
-typedef struct
-{
-	int			ident;
-	int			version;	
-	lump_t		lumps[HEADER_LUMPS];
-} dheader_t;
-
-typedef struct
-{
-	float		mins[3], maxs[3];
-	float		origin[3];		// for sounds or lights
-	int			headnode;
-	int			firstface, numfaces;	// submodels just draw faces
-										// without walking the bsp tree
-} dmodel_t;
-
-typedef struct
-{
-	float	point[3];
-} dvertex_t;
-
-// 0-2 are axial planes
-#define	PLANE_X			0
-#define	PLANE_Y			1
-#define	PLANE_Z			2
-
-// 3-5 are non-axial planes snapped to the nearest
-#define	PLANE_ANYX		3
-#define	PLANE_ANYY		4
-#define	PLANE_ANYZ		5
-
-// planes (x&~1) and (x&~1)+1 are always opposites
-
-typedef struct
-{
-	float	normal[3];
-	float	dist;
-	int		type;		// PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
-} dplane_t;
-
-// contents flags are seperate bits
-// a given brush can contribute multiple content bits
-// multiple brushes can be in a single leaf
-
-// these definitions also need to be in q_shared.h!
-
-/* ^-- macro redefinitions
-// 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
-*/
-
-typedef struct
-{
-	int			planenum;
-	int			children[2];	// negative numbers are -(leafs+1), not nodes
-	short		mins[3];		// for frustom culling
-	short		maxs[3];
-	unsigned short	firstface;
-	unsigned short	numfaces;	// counting both sides
-} dnode_t;
-
-typedef struct texinfo_s
-{
-	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
-} texinfo_t;
-
-// note that edge 0 is never used, because negative edge nums are used for
-// counterclockwise use of the edge in a face
-typedef struct
-{
-	unsigned short	v[2];		// vertex numbers
-} dedge_t;
-
-#define	MAXLIGHTMAPS	4
-typedef struct
-{
-	unsigned short	planenum;
-	short		side;
-
-	int			firstedge;		// we must support > 64k edges
-	short		numedges;	
-	short		texinfo;
-
-// lighting info
-	byte		styles[MAXLIGHTMAPS];
-	int			lightofs;		// start of [numstyles*surfsize] samples
-} dface_t;
-
-typedef struct
-{
-	int				contents;			// OR of all brushes (not needed?)
-
-	short			cluster;
-	short			area;
-
-	short			mins[3];			// for frustum culling
-	short			maxs[3];
-
-	unsigned short	firstleafface;
-	unsigned short	numleaffaces;
-
-	unsigned short	firstleafbrush;
-	unsigned short	numleafbrushes;
-} dleaf_t;
-
-typedef struct
-{
-	unsigned short	planenum;		// facing out of the leaf
-	short	texinfo;
-} dbrushside_t;
-
-typedef struct
-{
-	int			firstside;
-	int			numsides;
-	int			contents;
-} dbrush_t;
-
-#define	ANGLE_UP	-1
-#define	ANGLE_DOWN	-2
-
-
-// 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
-#define	DVIS_PVS	0
-#define	DVIS_PHS	1
-typedef struct
-{
-	int			numclusters;
-	int			bitofs[8][2];	// bitofs[numclusters][2]
-} dvis_t;
-
-// 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
-typedef struct
-{
-	int		portalnum;
-	int		otherarea;
-} dareaportal_t;
-
-typedef struct
-{
-	int		numareaportals;
-	int		firstareaportal;
-} darea_t;
-
-#pragma pack off
--- /dev/null
+++ b/qmenu.c
@@ -1,0 +1,652 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "dat.h"
+#include "fns.h"
+
+void	 Action_DoEnter( menuaction_t *a );
+void	 Action_Draw( menuaction_t *a );
+void  Menu_DrawStatusBar( char *string );
+void	 Menulist_DoEnter( menulist_t *l );
+void	 MenuList_Draw( menulist_t *l );
+void	 Separator_Draw( menuseparator_t *s );
+void	 Slider_DoSlide( menuslider_t *s, int dir );
+void	 Slider_Draw( menuslider_t *s );
+void	 SpinControl_DoEnter( menulist_t *s );
+void	 SpinControl_Draw( menulist_t *s );
+void	 SpinControl_DoSlide( menulist_t *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_t *a )
+{
+	if ( a->generic.callback )
+		a->generic.callback( a );
+}
+
+void Action_Draw( menuaction_t *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_t *f )
+{
+	if ( f->generic.callback )
+	{
+		f->generic.callback( f );
+		return true;
+	}
+	return false;
+}
+
+void Field_Draw( menufield_t *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_t *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_t *menu, void *item )
+{
+	if ( menu->nitems == 0 )
+		menu->nslots = 0;
+
+	if ( menu->nitems < MAXMENUITEMS )
+	{
+		menu->items[menu->nitems] = item;
+		( ( menucommon_t * ) 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_t *m, int dir )
+{
+	menucommon_t *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_t *menu )
+{
+	int height;
+
+	height = ( ( menucommon_t * ) menu->items[menu->nitems-1])->y;
+	height += 10;
+
+	menu->y = ( vid.height - height ) / 2;
+}
+
+void Menu_Draw( menuframework_t *menu )
+{
+	int i;
+	menucommon_t *item;
+
+	/*
+	** draw contents
+	*/
+	for ( i = 0; i < menu->nitems; i++ )
+	{
+		switch ( ( ( menucommon_t * ) menu->items[i] )->type )
+		{
+		case MTYPE_FIELD:
+			Field_Draw( ( menufield_t * ) menu->items[i] );
+			break;
+		case MTYPE_SLIDER:
+			Slider_Draw( ( menuslider_t * ) menu->items[i] );
+			break;
+		case MTYPE_LIST:
+			MenuList_Draw( ( menulist_t * ) menu->items[i] );
+			break;
+		case MTYPE_SPINCONTROL:
+			SpinControl_Draw( ( menulist_t * ) menu->items[i] );
+			break;
+		case MTYPE_ACTION:
+			Action_Draw( ( menuaction_t * ) menu->items[i] );
+			break;
+		case MTYPE_SEPARATOR:
+			Separator_Draw( ( menuseparator_t * ) 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( 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, 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, 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, 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, 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_t *m )
+{
+	if ( m->cursor < 0 || m->cursor >= m->nitems )
+		return 0;
+
+	return m->items[m->cursor];
+}
+
+qboolean Menu_SelectItem( menuframework_t *s )
+{
+	menucommon_t *item = ( menucommon_t * ) Menu_ItemAtCursor( s );
+
+	if ( item )
+	{
+		switch ( item->type )
+		{
+		case MTYPE_FIELD:
+			return Field_DoEnter( ( menufield_t * ) item ) ;
+		case MTYPE_ACTION:
+			Action_DoEnter( ( menuaction_t * ) item );
+			return true;
+		case MTYPE_LIST:
+//			Menulist_DoEnter( ( menulist_t * ) item );
+			return false;
+		case MTYPE_SPINCONTROL:
+//			SpinControl_DoEnter( ( menulist_t * ) item );
+			return false;
+		}
+	}
+	return false;
+}
+
+void Menu_SetStatusBar( menuframework_t *m, char *string )
+{
+	m->statusbar = string;
+}
+
+void Menu_SlideItem( menuframework_t *s, int dir )
+{
+	menucommon_t *item = ( menucommon_t * ) Menu_ItemAtCursor( s );
+
+	if ( item )
+	{
+		switch ( item->type )
+		{
+		case MTYPE_SLIDER:
+			Slider_DoSlide( ( menuslider_t * ) item, dir );
+			break;
+		case MTYPE_SPINCONTROL:
+			SpinControl_DoSlide( ( menulist_t * ) item, dir );
+			break;
+		}
+	}
+}
+
+int Menu_TallySlots( menuframework_t *menu )
+{
+	int i;
+	int total = 0;
+
+	for ( i = 0; i < menu->nitems; i++ )
+	{
+		if ( ( ( menucommon_t * ) menu->items[i] )->type == MTYPE_LIST )
+		{
+			int nitems = 0;
+			char **n = ( ( menulist_t * ) menu->items[i] )->itemnames;
+
+			while (*n)
+				nitems++, n++;
+
+			total += nitems;
+		}
+		else
+		{
+			total++;
+		}
+	}
+
+	return total;
+}
+
+void Menulist_DoEnter( menulist_t *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_t *l )
+{
+	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_t *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_t *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_t *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_t *s )
+{
+	s->curvalue++;
+	if ( s->itemnames[s->curvalue] == 0 )
+		s->curvalue = 0;
+
+	if ( s->generic.callback )
+		s->generic.callback( s );
+}
+
+void SpinControl_DoSlide( menulist_t *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_t *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 );
+	}
+}
+
--- /dev/null
+++ b/r_aclip.c
@@ -1,0 +1,304 @@
+// r_aclip.c: clip routines for drawing Alias models directly to the screen
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+static finalvert_t		fv[2][8];
+
+void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
+void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1,
+	finalvert_t *out);
+void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
+	finalvert_t *out);
+void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1,
+	finalvert_t *out);
+void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1,
+	finalvert_t *out);
+
+
+/*
+================
+R_Alias_clip_z
+
+pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex
+================
+*/
+void R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
+{
+	float		scale;
+
+	scale = (ALIAS_Z_CLIP_PLANE - pfv0->xyz[2]) /
+			(pfv1->xyz[2] - pfv0->xyz[2]);
+
+	out->xyz[0] = pfv0->xyz[0] + (pfv1->xyz[0] - pfv0->xyz[0]) * scale;
+	out->xyz[1] = pfv0->xyz[1] + (pfv1->xyz[1] - pfv0->xyz[1]) * scale;
+	out->xyz[2] = ALIAS_Z_CLIP_PLANE;
+
+	out->s =	pfv0->s + (pfv1->s - pfv0->s) * scale;
+	out->t =	pfv0->t + (pfv1->t - pfv0->t) * scale;
+	out->l =	pfv0->l + (pfv1->l - pfv0->l) * scale;
+
+	R_AliasProjectAndClipTestFinalVert (out);
+}
+
+
+void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
+{
+	float		scale;
+
+	if (pfv0->v >= pfv1->v )
+	{
+		scale = (float)(r_refdef.aliasvrect.x - pfv0->u) /
+				(pfv1->u - pfv0->u);
+		out->u  = pfv0->u  + ( pfv1->u  - pfv0->u ) * scale + 0.5;
+		out->v  = pfv0->v  + ( pfv1->v  - pfv0->v ) * scale + 0.5;
+		out->s  = pfv0->s  + ( pfv1->s  - pfv0->s ) * scale + 0.5;
+		out->t  = pfv0->t  + ( pfv1->t  - pfv0->t ) * scale + 0.5;
+		out->l  = pfv0->l  + ( pfv1->l  - pfv0->l ) * scale + 0.5;
+		out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
+	}
+	else
+	{
+		scale = (float)(r_refdef.aliasvrect.x - pfv1->u) /
+				(pfv0->u - pfv1->u);
+		out->u  = pfv1->u  + ( pfv0->u  - pfv1->u ) * scale + 0.5;
+		out->v  = pfv1->v  + ( pfv0->v  - pfv1->v ) * scale + 0.5;
+		out->s  = pfv1->s  + ( pfv0->s  - pfv1->s ) * scale + 0.5;
+		out->t  = pfv1->t  + ( pfv0->t  - pfv1->t ) * scale + 0.5;
+		out->l  = pfv1->l  + ( pfv0->l  - pfv1->l ) * scale + 0.5;
+		out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
+	}
+}
+
+
+void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
+{
+	float		scale;
+
+	if ( pfv0->v >= pfv1->v )
+	{
+		scale = (float)(r_refdef.aliasvrectright - pfv0->u ) /
+				(pfv1->u - pfv0->u );
+		out->u  = pfv0->u  + ( pfv1->u  - pfv0->u ) * scale + 0.5;
+		out->v  = pfv0->v  + ( pfv1->v  - pfv0->v ) * scale + 0.5;
+		out->s  = pfv0->s  + ( pfv1->s  - pfv0->s ) * scale + 0.5;
+		out->t  = pfv0->t  + ( pfv1->t  - pfv0->t ) * scale + 0.5;
+		out->l  = pfv0->l  + ( pfv1->l  - pfv0->l ) * scale + 0.5;
+		out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
+	}
+	else
+	{
+		scale = (float)(r_refdef.aliasvrectright - pfv1->u ) /
+				(pfv0->u - pfv1->u );
+		out->u  = pfv1->u  + ( pfv0->u  - pfv1->u ) * scale + 0.5;
+		out->v  = pfv1->v  + ( pfv0->v  - pfv1->v ) * scale + 0.5;
+		out->s  = pfv1->s  + ( pfv0->s  - pfv1->s ) * scale + 0.5;
+		out->t  = pfv1->t  + ( pfv0->t  - pfv1->t ) * scale + 0.5;
+		out->l  = pfv1->l  + ( pfv0->l  - pfv1->l ) * scale + 0.5;
+		out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
+	}
+}
+
+
+void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
+{
+	float		scale;
+
+	if (pfv0->v >= pfv1->v)
+	{
+		scale = (float)(r_refdef.aliasvrect.y - pfv0->v) /
+				(pfv1->v - pfv0->v);
+		out->u  = pfv0->u  + ( pfv1->u  - pfv0->u ) * scale + 0.5;
+		out->v  = pfv0->v  + ( pfv1->v  - pfv0->v ) * scale + 0.5;
+		out->s  = pfv0->s  + ( pfv1->s  - pfv0->s ) * scale + 0.5;
+		out->t  = pfv0->t  + ( pfv1->t  - pfv0->t ) * scale + 0.5;
+		out->l  = pfv0->l  + ( pfv1->l  - pfv0->l ) * scale + 0.5;
+		out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
+	}
+	else
+	{
+		scale = (float)(r_refdef.aliasvrect.y - pfv1->v) /
+				(pfv0->v - pfv1->v);
+		out->u  = pfv1->u  + ( pfv0->u  - pfv1->u ) * scale + 0.5;
+		out->v  = pfv1->v  + ( pfv0->v  - pfv1->v ) * scale + 0.5;
+		out->s  = pfv1->s  + ( pfv0->s  - pfv1->s ) * scale + 0.5;
+		out->t  = pfv1->t  + ( pfv0->t  - pfv1->t ) * scale + 0.5;
+		out->l  = pfv1->l  + ( pfv0->l  - pfv1->l ) * scale + 0.5;
+		out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
+	}
+}
+
+
+void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
+	finalvert_t *out)
+{
+	float		scale;
+
+	if (pfv0->v >= pfv1->v)
+	{
+		scale = (float)(r_refdef.aliasvrectbottom - pfv0->v) /
+				(pfv1->v - pfv0->v);
+
+		out->u  = pfv0->u  + ( pfv1->u  - pfv0->u ) * scale + 0.5;
+		out->v  = pfv0->v  + ( pfv1->v  - pfv0->v ) * scale + 0.5;
+		out->s  = pfv0->s  + ( pfv1->s  - pfv0->s ) * scale + 0.5;
+		out->t  = pfv0->t  + ( pfv1->t  - pfv0->t ) * scale + 0.5;
+		out->l  = pfv0->l  + ( pfv1->l  - pfv0->l ) * scale + 0.5;
+		out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
+	}
+	else
+	{
+		scale = (float)(r_refdef.aliasvrectbottom - pfv1->v) /
+				(pfv0->v - pfv1->v);
+
+		out->u  = pfv1->u  + ( pfv0->u  - pfv1->u ) * scale + 0.5;
+		out->v  = pfv1->v  + ( pfv0->v  - pfv1->v ) * scale + 0.5;
+		out->s  = pfv1->s  + ( pfv0->s  - pfv1->s ) * scale + 0.5;
+		out->t  = pfv1->t  + ( pfv0->t  - pfv1->t ) * scale + 0.5;
+		out->l  = pfv1->l  + ( pfv0->l  - pfv1->l ) * scale + 0.5;
+		out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
+	}
+}
+
+
+int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count,
+	void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) )
+{
+	int			i,j,k;
+	int			flags, oldflags;
+	
+	j = count-1;
+	k = 0;
+	for (i=0 ; i<count ; j = i, i++)
+	{
+		oldflags = in[j].flags & flag;
+		flags = in[i].flags & flag;
+
+		if (flags && oldflags)
+			continue;
+		if (oldflags ^ flags)
+		{
+			clip (&in[j], &in[i], &out[k]);
+			out[k].flags = 0;
+			if (out[k].u < r_refdef.aliasvrect.x)
+				out[k].flags |= ALIAS_LEFT_CLIP;
+			if (out[k].v < r_refdef.aliasvrect.y)
+				out[k].flags |= ALIAS_TOP_CLIP;
+			if (out[k].u > r_refdef.aliasvrectright)
+				out[k].flags |= ALIAS_RIGHT_CLIP;
+			if (out[k].v > r_refdef.aliasvrectbottom)
+				out[k].flags |= ALIAS_BOTTOM_CLIP;	
+			k++;
+		}
+		if (!flags)
+		{
+			out[k] = in[i];
+			k++;
+		}
+	}
+	
+	return k;
+}
+
+
+/*
+================
+R_AliasClipTriangle
+================
+*/
+void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2)
+{
+	int				i, k, pingpong;
+	unsigned		clipflags;
+
+// copy vertexes and fix seam texture coordinates
+	fv[0][0] = *index0;
+	fv[0][1] = *index1;
+	fv[0][2] = *index2;
+
+// clip
+	clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags;
+
+	if (clipflags & ALIAS_Z_CLIP)
+	{
+		k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z);
+		if (k == 0)
+			return;
+
+		pingpong = 1;
+		clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags;
+	}
+	else
+	{
+		pingpong = 0;
+		k = 3;
+	}
+
+	if (clipflags & ALIAS_LEFT_CLIP)
+	{
+		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
+							ALIAS_LEFT_CLIP, k, R_Alias_clip_left);
+		if (k == 0)
+			return;
+
+		pingpong ^= 1;
+	}
+
+	if (clipflags & ALIAS_RIGHT_CLIP)
+	{
+		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
+							ALIAS_RIGHT_CLIP, k, R_Alias_clip_right);
+		if (k == 0)
+			return;
+
+		pingpong ^= 1;
+	}
+
+	if (clipflags & ALIAS_BOTTOM_CLIP)
+	{
+		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
+							ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom);
+		if (k == 0)
+			return;
+
+		pingpong ^= 1;
+	}
+
+	if (clipflags & ALIAS_TOP_CLIP)
+	{
+		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
+							ALIAS_TOP_CLIP, k, R_Alias_clip_top);
+		if (k == 0)
+			return;
+
+		pingpong ^= 1;
+	}
+
+	for (i=0 ; i<k ; i++)
+	{
+		if (fv[pingpong][i].u < r_refdef.aliasvrect.x)
+			fv[pingpong][i].u = r_refdef.aliasvrect.x;
+		else if (fv[pingpong][i].u > r_refdef.aliasvrectright)
+			fv[pingpong][i].u = r_refdef.aliasvrectright;
+
+		if (fv[pingpong][i].v < r_refdef.aliasvrect.y)
+			fv[pingpong][i].v = r_refdef.aliasvrect.y;
+		else if (fv[pingpong][i].v > r_refdef.aliasvrectbottom)
+			fv[pingpong][i].v = r_refdef.aliasvrectbottom;
+
+		fv[pingpong][i].flags = 0;
+	}
+
+// draw triangles
+	for (i=1 ; i<k-1 ; i++)
+	{
+		aliastriangleparms.a = &fv[pingpong][0];
+		aliastriangleparms.b = &fv[pingpong][i];
+		aliastriangleparms.c = &fv[pingpong][i+1];
+		R_DrawTriangle();
+	}
+}
+
--- /dev/null
+++ b/r_alias.c
@@ -1,0 +1,861 @@
+// r_alias.c: routines for setting up to draw alias models
+
+/*
+** use a real variable to control lerping
+*/
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+#define LIGHT_MIN	5		// lowest light value we'll allow, to avoid the
+							//  need for inner-loop light clamping
+
+//PGM
+extern byte iractive;
+//PGM
+
+int				r_amodels_drawn;
+
+affinetridesc_t	r_affinetridesc;
+
+vec3_t			r_plightvec;
+vec3_t          r_lerped[1024];
+vec3_t          r_lerp_frontv, r_lerp_backv, r_lerp_move;
+
+int				r_ambientlight;
+int				r_aliasblendcolor;
+float			r_shadelight;
+
+
+daliasframe_t	*r_thisframe, *r_lastframe;
+dmdl_t			*s_pmdl;
+
+float	aliastransform[3][4];
+float   aliasworldtransform[3][4];
+float   aliasoldworldtransform[3][4];
+
+static float	s_ziscale;
+static vec3_t	s_alias_forward, s_alias_right, s_alias_up;
+
+
+float	r_avertexnormals[NUMVERTEXNORMALS][3] = {
+#include "anorms.h"
+};
+
+
+void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp );
+void R_AliasSetUpTransform (void);
+void R_AliasTransformVector (vec3_t in, vec3_t out, float m[3][4] );
+void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
+
+void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv );
+
+void R_AliasLerpFrames( dmdl_t *paliashdr, float backlerp );
+
+/*
+================
+R_AliasCheckBBox
+================
+*/
+typedef struct {
+	int	index0;
+	int	index1;
+} aedge_t;
+
+static aedge_t	aedges[12] = {
+{0, 1}, {1, 2}, {2, 3}, {3, 0},
+{4, 5}, {5, 6}, {6, 7}, {7, 4},
+{0, 5}, {1, 4}, {2, 7}, {3, 6}
+};
+
+#define BBOX_TRIVIAL_ACCEPT 0
+#define BBOX_MUST_CLIP_XY   1
+#define BBOX_MUST_CLIP_Z    2
+#define BBOX_TRIVIAL_REJECT 8
+
+/*
+** R_AliasCheckFrameBBox
+**
+** Checks a specific alias frame bounding box
+*/
+unsigned long R_AliasCheckFrameBBox( daliasframe_t *frame, float worldxf[3][4] )
+{
+	unsigned long aggregate_and_clipcode = ~0U, 
+		          aggregate_or_clipcode = 0;
+	int           i;
+	vec3_t        mins, maxs;
+	vec3_t        transformed_min, transformed_max;
+	qboolean      zclipped = false, zfullyclipped = true;
+	//float         minz = 9999.0F;
+
+	/*
+	** get the exact frame bounding box
+	*/
+	for (i=0 ; i<3 ; i++)
+	{
+		mins[i] = frame->translate[i];
+		maxs[i] = mins[i] + frame->scale[i]*255;
+	}
+
+	/*
+	** transform the min and max values into view space
+	*/
+	R_AliasTransformVector( mins, transformed_min, aliastransform );
+	R_AliasTransformVector( maxs, transformed_max, aliastransform );
+
+	if ( transformed_min[2] >= ALIAS_Z_CLIP_PLANE )
+		zfullyclipped = false;
+	if ( transformed_max[2] >= ALIAS_Z_CLIP_PLANE )
+		zfullyclipped = false;
+
+	if ( zfullyclipped )
+	{
+		return BBOX_TRIVIAL_REJECT;
+	}
+	if ( zclipped )
+	{
+		return ( BBOX_MUST_CLIP_XY | BBOX_MUST_CLIP_Z );
+	}
+
+	/*
+	** build a transformed bounding box from the given min and max
+	*/
+	for ( i = 0; i < 8; i++ )
+	{
+		int      j;
+		vec3_t   tmp, transformed;
+		unsigned long clipcode = 0;
+
+		if ( i & 1 )
+			tmp[0] = mins[0];
+		else
+			tmp[0] = maxs[0];
+
+		if ( i & 2 )
+			tmp[1] = mins[1];
+		else
+			tmp[1] = maxs[1];
+
+		if ( i & 4 )
+			tmp[2] = mins[2];
+		else
+			tmp[2] = maxs[2];
+
+		R_AliasTransformVector( tmp, transformed, worldxf );
+
+		for ( j = 0; j < 4; j++ )
+		{
+			float dp = DotProduct( transformed, view_clipplanes[j].normal );
+
+			if ( ( dp - view_clipplanes[j].dist ) < 0.0F )
+				clipcode |= 1 << j;
+		}
+
+		aggregate_and_clipcode &= clipcode;
+		aggregate_or_clipcode  |= clipcode;
+	}
+
+	if ( aggregate_and_clipcode )
+	{
+		return BBOX_TRIVIAL_REJECT;
+	}
+	if ( !aggregate_or_clipcode )
+	{
+		return BBOX_TRIVIAL_ACCEPT;
+	}
+
+	return BBOX_MUST_CLIP_XY;
+}
+
+qboolean R_AliasCheckBBox (void)
+{
+	unsigned long ccodes[2] = { 0, 0 };
+
+	ccodes[0] = R_AliasCheckFrameBBox( r_thisframe, aliasworldtransform );
+
+	/*
+	** non-lerping model
+	*/
+	if ( currententity->backlerp == 0 )
+	{
+		if ( ccodes[0] == BBOX_TRIVIAL_ACCEPT )
+			return BBOX_TRIVIAL_ACCEPT;
+		else if ( ccodes[0] & BBOX_TRIVIAL_REJECT )
+			return BBOX_TRIVIAL_REJECT;
+		else
+			return ( ccodes[0] & ~BBOX_TRIVIAL_REJECT );
+	}
+
+	ccodes[1] = R_AliasCheckFrameBBox( r_lastframe, aliasoldworldtransform );
+
+	if ( ( ccodes[0] | ccodes[1] ) == BBOX_TRIVIAL_ACCEPT )
+		return BBOX_TRIVIAL_ACCEPT;
+	else if ( ( ccodes[0] & ccodes[1] ) & BBOX_TRIVIAL_REJECT )
+		return BBOX_TRIVIAL_REJECT;
+	else
+		return ( ccodes[0] | ccodes[1] ) & ~BBOX_TRIVIAL_REJECT;
+}
+
+
+/*
+================
+R_AliasTransformVector
+================
+*/
+void R_AliasTransformVector(vec3_t in, vec3_t out, float xf[3][4] )
+{
+	out[0] = DotProduct(in, xf[0]) + xf[0][3];
+	out[1] = DotProduct(in, xf[1]) + xf[1][3];
+	out[2] = DotProduct(in, xf[2]) + xf[2][3];
+}
+
+
+/*
+================
+R_AliasPreparePoints
+
+General clipped case
+================
+*/
+typedef struct
+{
+	int          num_points;
+	dtrivertx_t *last_verts;   // verts from the last frame
+	dtrivertx_t *this_verts;   // verts from this frame
+	finalvert_t *dest_verts;   // destination for transformed verts
+} aliasbatchedtransformdata_t;
+
+aliasbatchedtransformdata_t aliasbatchedtransformdata;
+
+void R_AliasPreparePoints (void)
+{
+	int			i;
+	dstvert_t	*pstverts;
+	dtriangle_t	*ptri;
+	finalvert_t	*pfv[3];
+	finalvert_t	finalverts[MAXALIASVERTS +
+						((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 3];
+	finalvert_t	*pfinalverts;
+
+//PGM
+	iractive = (r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE);
+//	iractive = 0;
+//	if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
+//		iractive = 1;
+//PGM
+
+	// put work vertexes on stack, cache aligned
+	pfinalverts = (finalvert_t *)
+			(((uintptr)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+
+	aliasbatchedtransformdata.num_points = s_pmdl->num_xyz;
+	aliasbatchedtransformdata.last_verts = r_lastframe->verts;
+	aliasbatchedtransformdata.this_verts = r_thisframe->verts;
+	aliasbatchedtransformdata.dest_verts = pfinalverts;
+
+	R_AliasTransformFinalVerts( aliasbatchedtransformdata.num_points,
+		                        aliasbatchedtransformdata.dest_verts,
+								aliasbatchedtransformdata.last_verts,
+								aliasbatchedtransformdata.this_verts );
+
+// clip and draw all triangles
+//
+	pstverts = (dstvert_t *)((byte *)s_pmdl + s_pmdl->ofs_st);
+	ptri = (dtriangle_t *)((byte *)s_pmdl + s_pmdl->ofs_tris);
+
+	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
+	{
+		for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
+		{
+			pfv[0] = &pfinalverts[ptri->index_xyz[0]];
+			pfv[1] = &pfinalverts[ptri->index_xyz[1]];
+			pfv[2] = &pfinalverts[ptri->index_xyz[2]];
+
+			if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
+				continue;		// completely clipped
+
+			// insert s/t coordinates
+			pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
+			pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
+
+			pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
+			pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
+
+			pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
+			pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
+
+			if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
+			{	// totally unclipped
+				aliastriangleparms.a = pfv[2];
+				aliastriangleparms.b = pfv[1];
+				aliastriangleparms.c = pfv[0];
+
+				R_DrawTriangle();
+			}
+			else
+			{
+				R_AliasClipTriangle (pfv[2], pfv[1], pfv[0]);
+			}
+		}
+	}
+	else
+	{
+		for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
+		{
+			pfv[0] = &pfinalverts[ptri->index_xyz[0]];
+			pfv[1] = &pfinalverts[ptri->index_xyz[1]];
+			pfv[2] = &pfinalverts[ptri->index_xyz[2]];
+
+			if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
+				continue;		// completely clipped
+
+			// insert s/t coordinates
+			pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
+			pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
+
+			pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
+			pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
+
+			pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
+			pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
+
+			if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
+			{	// totally unclipped
+				aliastriangleparms.a = pfv[0];
+				aliastriangleparms.b = pfv[1];
+				aliastriangleparms.c = pfv[2];
+
+				R_DrawTriangle();
+			}
+			else		
+			{	// partially clipped
+				R_AliasClipTriangle (pfv[0], pfv[1], pfv[2]);
+			}
+		}
+	}
+}
+
+
+/*
+================
+R_AliasSetUpTransform
+================
+*/
+void R_AliasSetUpTransform (void)
+{
+	int				i;
+	static float	viewmatrix[3][4];
+	vec3_t			angles;
+
+// TODO: should really be stored with the entity instead of being reconstructed
+// TODO: should use a look-up table
+// TODO: could cache lazily, stored in the entity
+// 
+	angles[ROLL] = currententity->angles[ROLL];
+	angles[PITCH] = currententity->angles[PITCH];
+	angles[YAW] = currententity->angles[YAW];
+	AngleVectors( angles, s_alias_forward, s_alias_right, s_alias_up );
+
+// TODO: can do this with simple matrix rearrangement
+
+	memset( aliasworldtransform, 0, sizeof( aliasworldtransform ) );
+	memset( aliasoldworldtransform, 0, sizeof( aliasworldtransform ) );
+
+	for (i=0 ; i<3 ; i++)
+	{
+		aliasoldworldtransform[i][0] = aliasworldtransform[i][0] =  s_alias_forward[i];
+		aliasoldworldtransform[i][0] = aliasworldtransform[i][1] = -s_alias_right[i];
+		aliasoldworldtransform[i][0] = aliasworldtransform[i][2] =  s_alias_up[i];
+	}
+
+	aliasworldtransform[0][3] = currententity->origin[0]-r_origin[0];
+	aliasworldtransform[1][3] = currententity->origin[1]-r_origin[1];
+	aliasworldtransform[2][3] = currententity->origin[2]-r_origin[2];
+
+	aliasoldworldtransform[0][3] = currententity->oldorigin[0]-r_origin[0];
+	aliasoldworldtransform[1][3] = currententity->oldorigin[1]-r_origin[1];
+	aliasoldworldtransform[2][3] = currententity->oldorigin[2]-r_origin[2];
+
+// FIXME: can do more efficiently than full concatenation
+//	memcpy( rotationmatrix, t2matrix, sizeof( rotationmatrix ) );
+
+//	R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
+
+// TODO: should be global, set when vright, etc., set
+	VectorCopy (vright, viewmatrix[0]);
+	VectorCopy (vup, viewmatrix[1]);
+	VectorInverse (viewmatrix[1]);
+	VectorCopy (vpn, viewmatrix[2]);
+
+	viewmatrix[0][3] = 0;
+	viewmatrix[1][3] = 0;
+	viewmatrix[2][3] = 0;
+
+//	memcpy( aliasworldtransform, rotationmatrix, sizeof( aliastransform ) );
+
+	R_ConcatTransforms (viewmatrix, aliasworldtransform, aliastransform);
+
+	aliasworldtransform[0][3] = currententity->origin[0];
+	aliasworldtransform[1][3] = currententity->origin[1];
+	aliasworldtransform[2][3] = currententity->origin[2];
+
+	aliasoldworldtransform[0][3] = currententity->oldorigin[0];
+	aliasoldworldtransform[1][3] = currententity->oldorigin[1];
+	aliasoldworldtransform[2][3] = currententity->oldorigin[2];
+}
+
+
+/*
+================
+R_AliasTransformFinalVerts
+================
+*/
+void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv )
+{
+	int i;
+
+	for ( i = 0; i < numpoints; i++, fv++, oldv++, newv++ )
+	{
+		int		temp;
+		float	lightcos, *plightnormal;
+		vec3_t  lerped_vert;
+
+		lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0];
+		lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1];
+		lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2];
+
+		plightnormal = r_avertexnormals[newv->lightnormalindex];
+
+		// PMM - added double damage shell
+		if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
+		{
+			lerped_vert[0] += plightnormal[0] * POWERSUIT_SCALE;
+			lerped_vert[1] += plightnormal[1] * POWERSUIT_SCALE;
+			lerped_vert[2] += plightnormal[2] * POWERSUIT_SCALE;
+		}
+
+		fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3];
+		fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3];
+		fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3];
+
+		fv->flags = 0;
+
+		// lighting
+		lightcos = DotProduct (plightnormal, r_plightvec);
+		temp = r_ambientlight;
+
+		if (lightcos < 0)
+		{
+			temp += (int)(r_shadelight * lightcos);
+
+			// clamp; because we limited the minimum ambient and shading light, we
+			// don't have to clamp low light, just bright
+			if (temp < 0)
+				temp = 0;
+		}
+
+		fv->l = temp;
+
+		if ( fv->xyz[2] < ALIAS_Z_CLIP_PLANE )
+		{
+			fv->flags |= ALIAS_Z_CLIP;
+		}
+		else
+		{
+			R_AliasProjectAndClipTestFinalVert( fv );
+		}
+	}
+}
+
+/*
+================
+R_AliasProjectAndClipTestFinalVert
+================
+*/
+void R_AliasProjectAndClipTestFinalVert( finalvert_t *fv )
+{
+	float	zi;
+	float	x, y, z;
+
+	// project points
+	x = fv->xyz[0];
+	y = fv->xyz[1];
+	z = fv->xyz[2];
+	zi = 1.0 / z;
+
+	fv->zi = zi * s_ziscale;
+
+	fv->u = (x * aliasxscale * zi) + aliasxcenter;
+	fv->v = (y * aliasyscale * zi) + aliasycenter;
+
+	if (fv->u < r_refdef.aliasvrect.x)
+		fv->flags |= ALIAS_LEFT_CLIP;
+	if (fv->v < r_refdef.aliasvrect.y)
+		fv->flags |= ALIAS_TOP_CLIP;
+	if (fv->u > r_refdef.aliasvrectright)
+		fv->flags |= ALIAS_RIGHT_CLIP;
+	if (fv->v > r_refdef.aliasvrectbottom)
+		fv->flags |= ALIAS_BOTTOM_CLIP;	
+}
+
+/*
+===============
+R_AliasSetupSkin
+===============
+*/
+static qboolean R_AliasSetupSkin (void)
+{
+	int				skinnum;
+	image_t			*pskindesc;
+
+	if (currententity->skin)
+		pskindesc = currententity->skin;
+	else
+	{
+		skinnum = currententity->skinnum;
+		if ((skinnum >= s_pmdl->num_skins) || (skinnum < 0))
+		{
+			ri.Con_Printf (PRINT_ALL, "R_AliasSetupSkin %s: no such skin # %d\n", 
+				currentmodel->name, skinnum);
+			skinnum = 0;
+		}
+
+		pskindesc = currentmodel->skins[skinnum];
+	}
+
+	if ( !pskindesc )
+		return false;
+
+	r_affinetridesc.pskin = pskindesc->pixels[0];
+	r_affinetridesc.skinwidth = pskindesc->width;
+	r_affinetridesc.skinheight = pskindesc->height;
+
+	R_PolysetUpdateTables ();		// FIXME: precalc edge lookups
+
+	return true;
+}
+
+
+/*
+================
+R_AliasSetupLighting
+
+  FIXME: put lighting into tables
+================
+*/
+void R_AliasSetupLighting (void)
+{
+	alight_t		lighting;
+	float			lightvec[3] = {-1, 0, 0};
+	vec3_t			light;
+	int				i, j;
+
+	// all components of light should be identical in software
+	if ( currententity->flags & RF_FULLBRIGHT )
+	{
+		for (i=0 ; i<3 ; i++)
+			light[i] = 1.0;
+	}
+	else
+	{
+		R_LightPoint (currententity->origin, light);
+	}
+
+	// save off light value for server to look at (BIG HACK!)
+	if ( currententity->flags & RF_WEAPONMODEL )
+		r_lightlevel->value = 150.0 * light[0];
+
+
+	if ( currententity->flags & RF_MINLIGHT )
+	{
+		for (i=0 ; i<3 ; i++)
+			if (light[i] < 0.1)
+				light[i] = 0.1;
+	}
+
+	if ( currententity->flags & RF_GLOW )
+	{	// bonus items will pulse with time
+		float	scale;
+		float	min;
+
+		scale = 0.1 * sin(r_newrefdef.time*7);
+		for (i=0 ; i<3 ; i++)
+		{
+			min = light[i] * 0.8;
+			light[i] += scale;
+			if (light[i] < min)
+				light[i] = min;
+		}
+	}
+
+	j = (light[0] + light[1] + light[2])*0.3333*255;
+
+	lighting.ambientlight = j;
+	lighting.shadelight = j;
+
+	lighting.plightvec = lightvec;
+
+// clamp lighting so it doesn't overbright as much
+	if (lighting.ambientlight > 128)
+		lighting.ambientlight = 128;
+	if (lighting.ambientlight + lighting.shadelight > 192)
+		lighting.shadelight = 192 - lighting.ambientlight;
+
+// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have
+// to clamp off the bottom
+	r_ambientlight = lighting.ambientlight;
+
+	if (r_ambientlight < LIGHT_MIN)
+		r_ambientlight = LIGHT_MIN;
+
+	r_ambientlight = (255 - r_ambientlight) << VID_CBITS;
+
+	if (r_ambientlight < LIGHT_MIN)
+		r_ambientlight = LIGHT_MIN;
+
+	r_shadelight = lighting.shadelight;
+
+	if (r_shadelight < 0)
+		r_shadelight = 0;
+
+	r_shadelight *= VID_GRADES;
+
+// rotate the lighting vector into the model's frame of reference
+	r_plightvec[0] =  DotProduct( lighting.plightvec, s_alias_forward );
+	r_plightvec[1] = -DotProduct( lighting.plightvec, s_alias_right );
+	r_plightvec[2] =  DotProduct( lighting.plightvec, s_alias_up );
+}
+
+
+/*
+=================
+R_AliasSetupFrames
+
+=================
+*/
+void R_AliasSetupFrames( dmdl_t *pmdl )
+{
+	int thisframe = currententity->frame;
+	int lastframe = currententity->oldframe;
+
+	if ( ( thisframe >= pmdl->num_frames ) || ( thisframe < 0 ) )
+	{
+		ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such thisframe %d\n", 
+			currentmodel->name, thisframe);
+		thisframe = 0;
+	}
+	if ( ( lastframe >= pmdl->num_frames ) || ( lastframe < 0 ) )
+	{
+		ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such lastframe %d\n", 
+			currentmodel->name, lastframe);
+		lastframe = 0;
+	}
+
+	r_thisframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames 
+		+ thisframe * pmdl->framesize);
+
+	r_lastframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames 
+		+ lastframe * pmdl->framesize);
+}
+
+/*
+** R_AliasSetUpLerpData
+**
+** Precomputes lerp coefficients used for the whole frame.
+*/
+void R_AliasSetUpLerpData( dmdl_t */*pmdl*/, float backlerp )
+{
+	float	frontlerp;
+	vec3_t	translation, vectors[3];
+	int		i;
+
+	frontlerp = 1.0F - backlerp;
+
+	/*
+	** convert entity's angles into discrete vectors for R, U, and F
+	*/
+	AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]);
+
+	/*
+	** translation is the vector from last position to this position
+	*/
+	VectorSubtract (currententity->oldorigin, currententity->origin, translation);
+
+	/*
+	** move should be the delta back to the previous frame * backlerp
+	*/
+	r_lerp_move[0] =  DotProduct(translation, vectors[0]);	// forward
+	r_lerp_move[1] = -DotProduct(translation, vectors[1]);	// left
+	r_lerp_move[2] =  DotProduct(translation, vectors[2]);	// up
+
+	VectorAdd( r_lerp_move, r_lastframe->translate, r_lerp_move );
+
+	for (i=0 ; i<3 ; i++)
+	{
+		r_lerp_move[i] = backlerp*r_lerp_move[i] + frontlerp * r_thisframe->translate[i];
+	}
+
+	for (i=0 ; i<3 ; i++)
+	{
+		r_lerp_frontv[i] = frontlerp * r_thisframe->scale[i];
+		r_lerp_backv[i]  = backlerp  * r_lastframe->scale[i];
+	}
+}
+
+/*
+================
+R_AliasDrawModel
+================
+*/
+void R_AliasDrawModel (void)
+{
+	extern void	(*d_pdrawspans)(void *);
+	extern void R_PolysetDrawSpans8_Opaque( void * );
+	extern void R_PolysetDrawSpans8_33( void * );
+	extern void R_PolysetDrawSpans8_66( void * );
+	extern void R_PolysetDrawSpansConstant8_33( void * );
+	extern void R_PolysetDrawSpansConstant8_66( void * );
+
+	s_pmdl = (dmdl_t *)currentmodel->extradata;
+
+	if ( r_lerpmodels->value == 0 )
+		currententity->backlerp = 0;
+
+	if ( currententity->flags & RF_WEAPONMODEL )
+	{
+		if ( r_lefthand->value == 1.0F )
+			aliasxscale = -aliasxscale;
+		else if ( r_lefthand->value == 2.0F )
+			return;
+	}
+
+	/*
+	** we have to set our frame pointers and transformations before
+	** doing any real work
+	*/
+	R_AliasSetupFrames( s_pmdl );
+	R_AliasSetUpTransform();
+
+	// see if the bounding box lets us trivially reject, also sets
+	// trivial accept status
+	if ( R_AliasCheckBBox() == BBOX_TRIVIAL_REJECT )
+	{
+		if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
+		{
+			aliasxscale = -aliasxscale;
+		}
+		return;
+	}
+
+	// set up the skin and verify it exists
+	if ( !R_AliasSetupSkin () )
+	{
+		ri.Con_Printf( PRINT_ALL, "R_AliasDrawModel %s: NULL skin found\n",
+			currentmodel->name);
+		return;
+	}
+
+	r_amodels_drawn++;
+	R_AliasSetupLighting ();
+
+	/*
+	** select the proper span routine based on translucency
+	*/
+	// PMM - added double damage shell
+	// PMM - reordered to handle blending
+	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
+	{
+		int		color;
+
+		// PMM - added double
+		color = currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM);
+		// PMM - reordered, old code first
+/*
+		if ( color == RF_SHELL_RED )
+			r_aliasblendcolor = SHELL_RED_COLOR;
+		else if ( color == RF_SHELL_GREEN )
+			r_aliasblendcolor = SHELL_GREEN_COLOR;
+		else if ( color == RF_SHELL_BLUE )
+			r_aliasblendcolor = SHELL_BLUE_COLOR;
+		else if ( color == (RF_SHELL_RED | RF_SHELL_GREEN) )
+			r_aliasblendcolor = SHELL_RG_COLOR;
+		else if ( color == (RF_SHELL_RED | RF_SHELL_BLUE) )
+			r_aliasblendcolor = SHELL_RB_COLOR;
+		else if ( color == (RF_SHELL_BLUE | RF_SHELL_GREEN) )
+			r_aliasblendcolor = SHELL_BG_COLOR;
+		// PMM - added this .. it's yellowish
+		else if ( color == (RF_SHELL_DOUBLE) )
+			r_aliasblendcolor = SHELL_DOUBLE_COLOR;
+		else if ( color == (RF_SHELL_HALF_DAM) )
+			r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
+		// pmm
+		else
+			r_aliasblendcolor = SHELL_WHITE_COLOR;
+*/
+		if ( color & RF_SHELL_RED )
+		{
+			if ( ( color & RF_SHELL_BLUE) && ( color & RF_SHELL_GREEN) )
+				r_aliasblendcolor = SHELL_WHITE_COLOR;
+			else if ( color & (RF_SHELL_BLUE | RF_SHELL_DOUBLE))
+				r_aliasblendcolor = SHELL_RB_COLOR;
+			else
+				r_aliasblendcolor = SHELL_RED_COLOR;
+		}
+		else if ( color & RF_SHELL_BLUE)
+		{
+			if ( color & RF_SHELL_DOUBLE )
+				r_aliasblendcolor = SHELL_CYAN_COLOR;
+			else
+				r_aliasblendcolor = SHELL_BLUE_COLOR;
+		}
+		else if ( color & (RF_SHELL_DOUBLE) )
+			r_aliasblendcolor = SHELL_DOUBLE_COLOR;
+		else if ( color & (RF_SHELL_HALF_DAM) )
+			r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
+		else if ( color & RF_SHELL_GREEN )
+			r_aliasblendcolor = SHELL_GREEN_COLOR;
+		else
+			r_aliasblendcolor = SHELL_WHITE_COLOR;
+
+
+		if ( currententity->alpha > 0.33 )
+			d_pdrawspans = R_PolysetDrawSpansConstant8_66;
+		else
+			d_pdrawspans = R_PolysetDrawSpansConstant8_33;
+	}
+	else if ( currententity->flags & RF_TRANSLUCENT )
+	{
+		if ( currententity->alpha > 0.66 )
+			d_pdrawspans = R_PolysetDrawSpans8_Opaque;
+		else if ( currententity->alpha > 0.33 )
+			d_pdrawspans = R_PolysetDrawSpans8_66;
+		else
+			d_pdrawspans = R_PolysetDrawSpans8_33;
+	}
+	else
+	{
+		d_pdrawspans = R_PolysetDrawSpans8_Opaque;
+	}
+
+	/*
+	** compute this_frame and old_frame addresses
+	*/
+	R_AliasSetUpLerpData( s_pmdl, currententity->backlerp );
+
+	if (currententity->flags & RF_DEPTHHACK)
+		s_ziscale = (float)0x8000 * (float)0x10000 * 3.0;
+	else
+		s_ziscale = (float)0x8000 * (float)0x10000;
+
+	R_AliasPreparePoints ();
+
+	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
+	{
+		aliasxscale = -aliasxscale;
+	}
+}
+
+
+
--- /dev/null
+++ b/r_bsp.c
@@ -1,0 +1,620 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+//
+// current entity info
+//
+qboolean		insubmodel;
+entity_t		*currententity;
+vec3_t			modelorg;		// modelorg is the viewpoint reletive to
+								// the currently rendering entity
+vec3_t			r_entorigin;	// the currently rendering entity in world
+								// coordinates
+
+float			entity_rotation[3][3];
+
+int				r_currentbkey;
+
+typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t;
+
+#define MAX_BMODEL_VERTS	500			// 6K
+#define MAX_BMODEL_EDGES	1000		// 12K
+
+static mvertex_t	*pbverts;
+static bedge_t		*pbedges;
+static int			numbverts, numbedges;
+
+static mvertex_t	*pfrontenter, *pfrontexit;
+
+static qboolean		makeclippededge;
+
+
+//===========================================================================
+
+/*
+================
+R_EntityRotate
+================
+*/
+void R_EntityRotate (vec3_t vec)
+{
+	vec3_t	tvec;
+
+	VectorCopy (vec, tvec);
+	vec[0] = DotProduct (entity_rotation[0], tvec);
+	vec[1] = DotProduct (entity_rotation[1], tvec);
+	vec[2] = DotProduct (entity_rotation[2], tvec);
+}
+
+
+/*
+================
+R_RotateBmodel
+================
+*/
+void R_RotateBmodel (void)
+{
+	float	angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
+
+// TODO: should use a look-up table
+// TODO: should really be stored with the entity instead of being reconstructed
+// TODO: could cache lazily, stored in the entity
+// TODO: share work with R_SetUpAliasTransform
+
+// yaw
+	angle = currententity->angles[YAW];		
+	angle = angle * M_PI*2 / 360;
+	s = sin(angle);
+	c = cos(angle);
+
+	temp1[0][0] = c;
+	temp1[0][1] = s;
+	temp1[0][2] = 0;
+	temp1[1][0] = -s;
+	temp1[1][1] = c;
+	temp1[1][2] = 0;
+	temp1[2][0] = 0;
+	temp1[2][1] = 0;
+	temp1[2][2] = 1;
+
+
+// pitch
+	angle = currententity->angles[PITCH];		
+	angle = angle * M_PI*2 / 360;
+	s = sin(angle);
+	c = cos(angle);
+
+	temp2[0][0] = c;
+	temp2[0][1] = 0;
+	temp2[0][2] = -s;
+	temp2[1][0] = 0;
+	temp2[1][1] = 1;
+	temp2[1][2] = 0;
+	temp2[2][0] = s;
+	temp2[2][1] = 0;
+	temp2[2][2] = c;
+
+	R_ConcatRotations (temp2, temp1, temp3);
+
+// roll
+	angle = currententity->angles[ROLL];		
+	angle = angle * M_PI*2 / 360;
+	s = sin(angle);
+	c = cos(angle);
+
+	temp1[0][0] = 1;
+	temp1[0][1] = 0;
+	temp1[0][2] = 0;
+	temp1[1][0] = 0;
+	temp1[1][1] = c;
+	temp1[1][2] = s;
+	temp1[2][0] = 0;
+	temp1[2][1] = -s;
+	temp1[2][2] = c;
+
+	R_ConcatRotations (temp1, temp3, entity_rotation);
+
+//
+// rotate modelorg and the transformation matrix
+//
+	R_EntityRotate (modelorg);
+	R_EntityRotate (vpn);
+	R_EntityRotate (vright);
+	R_EntityRotate (vup);
+
+	R_TransformFrustum ();
+}
+
+
+/*
+================
+R_RecursiveClipBPoly
+
+Clip a bmodel poly down the world bsp tree
+================
+*/
+void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
+{
+	bedge_t		*psideedges[2], *pnextedge, *ptedge;
+	int			i, side, lastside;
+	float		dist, frac, lastdist;
+	mplane_t	*splitplane, tplane;
+	mvertex_t	*pvert, *plastvert, *ptvert;
+	mnode_t		*pn;
+	int			area;
+
+	psideedges[0] = psideedges[1] = NULL;
+
+	makeclippededge = false;
+
+// transform the BSP plane into model space
+// FIXME: cache these?
+	splitplane = pnode->plane;
+	tplane.dist = splitplane->dist -
+			DotProduct(r_entorigin, splitplane->normal);
+	tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal);
+	tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal);
+	tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal);
+
+// clip edges to BSP plane
+	for ( ; pedges ; pedges = pnextedge)
+	{
+		pnextedge = pedges->pnext;
+
+	// set the status for the last point as the previous point
+	// FIXME: cache this stuff somehow?
+		plastvert = pedges->v[0];
+		lastdist = DotProduct (plastvert->position, tplane.normal) -
+				   tplane.dist;
+
+		if (lastdist > 0)
+			lastside = 0;
+		else
+			lastside = 1;
+
+		pvert = pedges->v[1];
+
+		dist = DotProduct (pvert->position, tplane.normal) - tplane.dist;
+
+		if (dist > 0)
+			side = 0;
+		else
+			side = 1;
+
+		if (side != lastside)
+		{
+		// clipped
+			if (numbverts >= MAX_BMODEL_VERTS)
+				return;
+
+		// generate the clipped vertex
+			frac = lastdist / (lastdist - dist);
+			ptvert = &pbverts[numbverts++];
+			ptvert->position[0] = plastvert->position[0] +
+					frac * (pvert->position[0] -
+					plastvert->position[0]);
+			ptvert->position[1] = plastvert->position[1] +
+					frac * (pvert->position[1] -
+					plastvert->position[1]);
+			ptvert->position[2] = plastvert->position[2] +
+					frac * (pvert->position[2] -
+					plastvert->position[2]);
+
+		// split into two edges, one on each side, and remember entering
+		// and exiting points
+		// FIXME: share the clip edge by having a winding direction flag?
+			if (numbedges >= (MAX_BMODEL_EDGES - 1))
+			{
+				ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n");
+				return;
+			}
+
+			ptedge = &pbedges[numbedges];
+			ptedge->pnext = psideedges[lastside];
+			psideedges[lastside] = ptedge;
+			ptedge->v[0] = plastvert;
+			ptedge->v[1] = ptvert;
+
+			ptedge = &pbedges[numbedges + 1];
+			ptedge->pnext = psideedges[side];
+			psideedges[side] = ptedge;
+			ptedge->v[0] = ptvert;
+			ptedge->v[1] = pvert;
+
+			numbedges += 2;
+
+			if (side == 0)
+			{
+			// entering for front, exiting for back
+				pfrontenter = ptvert;
+				makeclippededge = true;
+			}
+			else
+			{
+				pfrontexit = ptvert;
+				makeclippededge = true;
+			}
+		}
+		else
+		{
+		// add the edge to the appropriate side
+			pedges->pnext = psideedges[side];
+			psideedges[side] = pedges;
+		}
+	}
+
+// if anything was clipped, reconstitute and add the edges along the clip
+// plane to both sides (but in opposite directions)
+	if (makeclippededge)
+	{
+		if (numbedges >= (MAX_BMODEL_EDGES - 2))
+		{
+			ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n");
+			return;
+		}
+
+		ptedge = &pbedges[numbedges];
+		ptedge->pnext = psideedges[0];
+		psideedges[0] = ptedge;
+		ptedge->v[0] = pfrontexit;
+		ptedge->v[1] = pfrontenter;
+
+		ptedge = &pbedges[numbedges + 1];
+		ptedge->pnext = psideedges[1];
+		psideedges[1] = ptedge;
+		ptedge->v[0] = pfrontenter;
+		ptedge->v[1] = pfrontexit;
+
+		numbedges += 2;
+	}
+
+// draw or recurse further
+	for (i=0 ; i<2 ; i++)
+	{
+		if (psideedges[i])
+		{
+		// draw if we've reached a non-solid leaf, done if all that's left is a
+		// solid leaf, and continue down the tree if it's not a leaf
+			pn = pnode->children[i];
+
+		// we're done with this branch if the node or leaf isn't in the PVS
+			if (pn->visframe == r_visframecount)
+			{
+				if (pn->contents != CONTENTS_NODE)
+				{
+					if (pn->contents != CONTENTS_SOLID)
+					{
+						if (r_newrefdef.areabits)
+						{
+							area = ((mleaf_t *)pn)->area;
+							if (! (r_newrefdef.areabits[area>>3] & (1<<(area&7)) ) )
+								continue;		// not visible
+						}
+
+						r_currentbkey = ((mleaf_t *)pn)->key;
+						R_RenderBmodelFace (psideedges[i], psurf);
+					}
+				}
+				else
+				{
+					R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
+									  psurf);
+				}
+			}
+		}
+	}
+}
+
+
+/*
+================
+R_DrawSolidClippedSubmodelPolygons
+
+Bmodel crosses multiple leafs
+================
+*/
+void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode)
+{
+	int			i, j, lindex;
+	vec_t		dot;
+	msurface_t	*psurf;
+	int			numsurfaces;
+	mplane_t	*pplane;
+	mvertex_t	bverts[MAX_BMODEL_VERTS];
+	bedge_t		bedges[MAX_BMODEL_EDGES], *pbedge;
+	medge_t		*pedge, *pedges;
+
+// FIXME: use bounding-box-based frustum clipping info?
+
+	psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
+	numsurfaces = pmodel->nummodelsurfaces;
+	pedges = pmodel->edges;
+
+	for (i=0 ; i<numsurfaces ; i++, psurf++)
+	{
+	// find which side of the node we are on
+		pplane = psurf->plane;
+
+		dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
+
+	// draw the polygon
+		if (( !(psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
+			((psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
+			continue;
+
+	// FIXME: use bounding-box-based frustum clipping info?
+
+	// copy the edges to bedges, flipping if necessary so always
+	// clockwise winding
+	// FIXME: if edges and vertices get caches, these assignments must move
+	// outside the loop, and overflow checking must be done here
+		pbverts = bverts;
+		pbedges = bedges;
+		numbverts = numbedges = 0;
+		pbedge = &bedges[numbedges];
+		numbedges += psurf->numedges;
+
+		for (j=0 ; j<psurf->numedges ; j++)
+		{
+		   lindex = pmodel->surfedges[psurf->firstedge+j];
+
+			if (lindex > 0)
+			{
+				pedge = &pedges[lindex];
+				pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
+				pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
+			}
+			else
+			{
+				lindex = -lindex;
+				pedge = &pedges[lindex];
+				pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
+				pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
+			}
+
+			pbedge[j].pnext = &pbedge[j+1];
+		}
+
+		pbedge[j-1].pnext = NULL;	// mark end of edges
+
+		if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) )
+			R_RecursiveClipBPoly (pbedge, topnode, psurf);
+		else
+			R_RenderBmodelFace( pbedge, psurf );
+	}
+}
+
+
+/*
+================
+R_DrawSubmodelPolygons
+
+All in one leaf
+================
+*/
+void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode)
+{
+	int			i;
+	vec_t		dot;
+	msurface_t	*psurf;
+	int			numsurfaces;
+	mplane_t	*pplane;
+
+// FIXME: use bounding-box-based frustum clipping info?
+
+	psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
+	numsurfaces = pmodel->nummodelsurfaces;
+
+	for (i=0 ; i<numsurfaces ; i++, psurf++)
+	{
+	// find which side of the node we are on
+		pplane = psurf->plane;
+
+		dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
+
+	// draw the polygon
+		if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
+			(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
+		{
+			r_currentkey = ((mleaf_t *)topnode)->key;
+
+		// FIXME: use bounding-box-based frustum clipping info?
+			R_RenderFace (psurf, clipflags);
+		}
+	}
+}
+
+
+int c_drawnode;
+
+/*
+================
+R_RecursiveWorldNode
+================
+*/
+void R_RecursiveWorldNode (mnode_t *node, int clipflags)
+{
+	int			i, c, side, *pindex;
+	vec3_t		acceptpt, rejectpt;
+	mplane_t	*plane;
+	msurface_t	*surf, **mark;
+	float		d, dot;
+	mleaf_t		*pleaf;
+
+	if (node->contents == CONTENTS_SOLID)
+		return;		// solid
+
+	if (node->visframe != r_visframecount)
+		return;
+
+// cull the clipping planes if not trivial accept
+// FIXME: the compiler is doing a lousy job of optimizing here; it could be
+//  twice as fast in ASM
+	if (clipflags)
+	{
+		for (i=0 ; i<4 ; i++)
+		{
+			if (! (clipflags & (1<<i)) )
+				continue;	// don't need to clip against it
+
+		// generate accept and reject points
+		// FIXME: do with fast look-ups or integer tests based on the sign bit
+		// of the floating point values
+
+			pindex = pfrustum_indexes[i];
+
+			rejectpt[0] = (float)node->minmaxs[pindex[0]];
+			rejectpt[1] = (float)node->minmaxs[pindex[1]];
+			rejectpt[2] = (float)node->minmaxs[pindex[2]];
+			
+			d = DotProduct (rejectpt, view_clipplanes[i].normal);
+			d -= view_clipplanes[i].dist;
+			if (d <= 0)
+				return;
+			acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
+			acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
+			acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
+
+			d = DotProduct (acceptpt, view_clipplanes[i].normal);
+			d -= view_clipplanes[i].dist;
+
+			if (d >= 0)
+				clipflags &= ~(1<<i);	// node is entirely on screen
+		}
+	}
+
+c_drawnode++;
+
+// if a leaf node, draw stuff
+	if (node->contents != -1)
+	{
+		pleaf = (mleaf_t *)node;
+
+		// check for door connected areas
+		if (r_newrefdef.areabits)
+		{
+			if (! (r_newrefdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
+				return;		// not visible
+		}
+
+		mark = pleaf->firstmarksurface;
+		c = pleaf->nummarksurfaces;
+
+		if (c)
+		{
+			do
+			{
+				(*mark)->visframe = r_framecount;
+				mark++;
+			} while (--c);
+		}
+
+		pleaf->key = r_currentkey;
+		r_currentkey++;		// all bmodels in a leaf share the same key
+	}
+	else
+	{
+	// node is just a decision point, so go down the apropriate sides
+
+	// find which side of the node we are on
+		plane = node->plane;
+
+		switch (plane->type)
+		{
+		case PLANE_X:
+			dot = modelorg[0] - plane->dist;
+			break;
+		case PLANE_Y:
+			dot = modelorg[1] - plane->dist;
+			break;
+		case PLANE_Z:
+			dot = modelorg[2] - plane->dist;
+			break;
+		default:
+			dot = DotProduct (modelorg, plane->normal) - plane->dist;
+			break;
+		}
+	
+		if (dot >= 0)
+			side = 0;
+		else
+			side = 1;
+
+	// recurse down the children, front side first
+		R_RecursiveWorldNode (node->children[side], clipflags);
+
+	// draw stuff
+		c = node->numsurfaces;
+
+		if (c)
+		{
+			surf = r_worldmodel->surfaces + node->firstsurface;
+
+			if (dot < -BACKFACE_EPSILON)
+			{
+				do
+				{
+					if ((surf->flags & SURF_PLANEBACK) &&
+						(surf->visframe == r_framecount))
+					{
+						R_RenderFace (surf, clipflags);
+					}
+
+					surf++;
+				} while (--c);
+			}
+			else if (dot > BACKFACE_EPSILON)
+			{
+				do
+				{
+					if (!(surf->flags & SURF_PLANEBACK) &&
+						(surf->visframe == r_framecount))
+					{
+						R_RenderFace (surf, clipflags);
+					}
+
+					surf++;
+				} while (--c);
+			}
+
+		// all surfaces on the same node share the same sequence number
+			r_currentkey++;
+		}
+
+	// recurse down the back side
+		R_RecursiveWorldNode (node->children[!side], clipflags);
+	}
+}
+
+
+
+/*
+================
+R_RenderWorld
+================
+*/
+void R_RenderWorld (void)
+{
+
+	if (!r_drawworld->value)
+		return;
+	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
+		return;
+
+	c_drawnode=0;
+
+	// auto cycle the world frame for texture animation
+	r_worldentity.frame = (int)(r_newrefdef.time*2);
+	currententity = &r_worldentity;
+
+	VectorCopy (r_origin, modelorg);
+	currentmodel = r_worldmodel;
+	r_pcurrentvertbase = currentmodel->vertexes;
+
+	R_RecursiveWorldNode (currentmodel->nodes, 15);
+}
+
+
--- /dev/null
+++ b/r_draw.c
@@ -1,0 +1,427 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+image_t		*draw_chars;				// 8*8 graphic characters
+
+//=============================================================================
+
+/*
+================
+Draw_FindPic
+================
+*/
+image_t *Draw_FindPic (char *name)
+{
+	image_t	*image;
+	char	fullname[MAX_QPATH];
+
+	if (name[0] != '/' && name[0] != '\\')
+	{
+		Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name);
+		image = R_FindImage (fullname, it_pic);
+	}
+	else
+		image = R_FindImage (name+1, it_pic);
+
+	return image;
+}
+
+
+
+/*
+===============
+Draw_InitLocal
+===============
+*/
+void Draw_InitLocal (void)
+{
+	draw_chars = Draw_FindPic ("conchars");
+}
+
+
+
+/*
+================
+Draw_Char
+
+Draws one 8*8 graphics character
+It can be clipped to the top of the screen to allow the console to be
+smoothly scrolled off.
+================
+*/
+void Draw_Char (int x, int y, int num)
+{
+	byte			*dest;
+	byte			*source;
+	int				drawline;	
+	int				row, col;
+
+	num &= 255;
+
+	if (num == 32 || num == 32+128)
+		return;
+
+	if (y <= -8)
+		return;			// totally off screen
+
+//	if ( ( y + 8 ) >= vid.height )
+	if ( ( y + 8 ) > vid.height )		// PGM - status text was missing in sw...
+		return;
+
+#ifdef PARANOID
+	if (y > vid.height - 8 || x < 0 || x > vid.width - 8)
+		ri.Sys_Error (ERR_FATAL,"Con_DrawCharacter: (%i, %i)", x, y);
+	if (num < 0 || num > 255)
+		ri.Sys_Error (ERR_FATAL,"Con_DrawCharacter: char %i", num);
+#endif
+
+	row = num>>4;
+	col = num&15;
+	source = draw_chars->pixels[0] + (row<<10) + (col<<3);
+
+	if (y < 0)
+	{	// clipped
+		drawline = 8 + y;
+		source -= 128*y;
+		y = 0;
+	}
+	else
+		drawline = 8;
+
+
+	dest = vid.buffer + y*vid.rowbytes + x;
+
+	while (drawline--)
+	{
+		if (source[0] != TRANSPARENT_COLOR)
+			dest[0] = source[0];
+		if (source[1] != TRANSPARENT_COLOR)
+			dest[1] = source[1];
+		if (source[2] != TRANSPARENT_COLOR)
+			dest[2] = source[2];
+		if (source[3] != TRANSPARENT_COLOR)
+			dest[3] = source[3];
+		if (source[4] != TRANSPARENT_COLOR)
+			dest[4] = source[4];
+		if (source[5] != TRANSPARENT_COLOR)
+			dest[5] = source[5];
+		if (source[6] != TRANSPARENT_COLOR)
+			dest[6] = source[6];
+		if (source[7] != TRANSPARENT_COLOR)
+			dest[7] = source[7];
+		source += 128;
+		dest += vid.rowbytes;
+	}
+}
+
+/*
+=============
+Draw_GetPicSize
+=============
+*/
+void Draw_GetPicSize (int *w, int *h, char *pic)
+{
+	image_t *gl;
+
+	gl = Draw_FindPic (pic);
+	if (!gl)
+	{
+		*w = *h = -1;
+		return;
+	}
+	*w = gl->width;
+	*h = gl->height;
+}
+
+/*
+=============
+Draw_StretchPicImplementation
+=============
+*/
+void Draw_StretchPicImplementation (int x, int y, int w, int h, image_t	*pic)
+{
+	byte			*dest, *source;
+	int				v, u, sv;
+	int				height;
+	int				f, fstep;
+	int				skip;
+
+	if ((x < 0) ||
+		(x + w > vid.width) ||
+		(y + h > vid.height))
+	{
+		ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates");
+	}
+
+	height = h;
+	if (y < 0)
+	{
+		skip = -y;
+		height += y;
+		y = 0;
+	}
+	else
+		skip = 0;
+
+	dest = vid.buffer + y * vid.rowbytes + x;
+
+	for (v=0 ; v<height ; v++, dest += vid.rowbytes)
+	{
+		sv = (skip + v)*pic->height/h;
+		source = pic->pixels[0] + sv*pic->width;
+		if (w == pic->width)
+			memcpy (dest, source, w);
+		else
+		{
+			f = 0;
+			fstep = pic->width*0x10000/w;
+			for (u=0 ; u<w ; u+=4)
+			{
+				dest[u] = source[f>>16];
+				f += fstep;
+				dest[u+1] = source[f>>16];
+				f += fstep;
+				dest[u+2] = source[f>>16];
+				f += fstep;
+				dest[u+3] = source[f>>16];
+				f += fstep;
+			}
+		}
+	}
+}
+
+/*
+=============
+Draw_StretchPic
+=============
+*/
+void Draw_StretchPic (int x, int y, int w, int h, char *name)
+{
+	image_t	*pic;
+
+	pic = Draw_FindPic (name);
+	if (!pic)
+	{
+		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
+		return;
+	}
+	Draw_StretchPicImplementation (x, y, w, h, pic);
+}
+
+/*
+=============
+Draw_StretchRaw
+=============
+*/
+void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data)
+{
+	image_t	pic;
+
+	pic.pixels[0] = data;
+	pic.width = cols;
+	pic.height = rows;
+	Draw_StretchPicImplementation (x, y, w, h, &pic);
+}
+
+/*
+=============
+Draw_Pic
+=============
+*/
+void Draw_Pic (int x, int y, char *name)
+{
+	image_t			*pic;
+	byte			*dest, *source;
+	int				v, u;
+	int				tbyte;
+	int				height;
+
+	pic = Draw_FindPic (name);
+	if (!pic)
+	{
+		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
+		return;
+	}
+
+	if ((x < 0) ||
+		(x + pic->width > vid.width) ||
+		(y + pic->height > vid.height))
+		return;	//	ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates");
+
+	height = pic->height;
+	source = pic->pixels[0];
+	if (y < 0)
+	{
+		height += y;
+		source += pic->width*-y;
+		y = 0;
+	}
+
+	dest = vid.buffer + y * vid.rowbytes + x;
+
+	if (!pic->transparent)
+	{
+		for (v=0 ; v<height ; v++)
+		{
+			memcpy (dest, source, pic->width);
+			dest += vid.rowbytes;
+			source += pic->width;
+		}
+	}
+	else
+	{
+		if (pic->width & 7)
+		{	// general
+			for (v=0 ; v<height ; v++)
+			{
+				for (u=0 ; u<pic->width ; u++)
+					if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
+						dest[u] = tbyte;
+
+				dest += vid.rowbytes;
+				source += pic->width;
+			}
+		}
+		else
+		{	// unwound
+			for (v=0 ; v<height ; v++)
+			{
+				for (u=0 ; u<pic->width ; u+=8)
+				{
+					if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
+						dest[u] = tbyte;
+					if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
+						dest[u+1] = tbyte;
+					if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
+						dest[u+2] = tbyte;
+					if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
+						dest[u+3] = tbyte;
+					if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
+						dest[u+4] = tbyte;
+					if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
+						dest[u+5] = tbyte;
+					if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
+						dest[u+6] = tbyte;
+					if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
+						dest[u+7] = tbyte;
+				}
+				dest += vid.rowbytes;
+				source += pic->width;
+			}
+		}
+	}
+}
+
+/*
+=============
+Draw_TileClear
+
+This repeats a 64*64 tile graphic to fill the screen around a sized down
+refresh window.
+=============
+*/
+void Draw_TileClear (int x, int y, int w, int h, char *name)
+{
+	int			i, j;
+	byte		*psrc;
+	byte		*pdest;
+	image_t		*pic;
+	int			x2;
+
+	if (x < 0)
+	{
+		w += x;
+		x = 0;
+	}
+	if (y < 0)
+	{
+		h += y;
+		y = 0;
+	}
+	if (x + w > vid.width)
+		w = vid.width - x;
+	if (y + h > vid.height)
+		h = vid.height - y;
+	if (w <= 0 || h <= 0)
+		return;
+
+	pic = Draw_FindPic (name);
+	if (!pic)
+	{
+		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
+		return;
+	}
+	x2 = x + w;
+	pdest = vid.buffer + y*vid.rowbytes;
+	for (i=0 ; i<h ; i++, pdest += vid.rowbytes)
+	{
+		psrc = pic->pixels[0] + pic->width * ((i+y)&63);
+		for (j=x ; j<x2 ; j++)
+			pdest[j] = psrc[j&63];
+	}
+}
+
+
+/*
+=============
+Draw_Fill
+
+Fills a box of pixels with a single color
+=============
+*/
+void Draw_Fill (int x, int y, int w, int h, int c)
+{
+	byte			*dest;
+	int				u, v;
+
+	if (x+w > vid.width)
+		w = vid.width - x;
+	if (y+h > vid.height)
+		h = vid.height - y;
+	if (x < 0)
+	{
+		w += x;
+		x = 0;
+	}
+	if (y < 0)
+	{
+		h += y;
+		y = 0;
+	}
+	if (w < 0 || h < 0)
+		return;
+	dest = vid.buffer + y*vid.rowbytes + x;
+	for (v=0 ; v<h ; v++, dest += vid.rowbytes)
+		for (u=0 ; u<w ; u++)
+			dest[u] = c;
+}
+//=============================================================================
+
+/*
+================
+Draw_FadeScreen
+
+================
+*/
+void Draw_FadeScreen (void)
+{
+	int			x,y;
+	byte		*pbuf;
+	int	t;
+
+	for (y=0 ; y<vid.height ; y++)
+	{
+		pbuf = (byte *)(vid.buffer + vid.rowbytes*y);
+		t = (y & 1) << 1;
+
+		for (x=0 ; x<vid.width ; x++)
+		{
+			if ((x & 3) != t)
+				pbuf[x] = 0;
+		}
+	}
+}
--- /dev/null
+++ b/r_edge.c
@@ -1,0 +1,1085 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+void R_SurfacePatch (void)
+{
+}
+
+void R_EdgeCodeStart (void)
+{
+}
+
+void R_EdgeCodeEnd (void)
+{
+}
+
+
+/*
+the complex cases add new polys on most lines, so dont optimize for keeping them the same
+have multiple free span lists to try to get better coherence?
+low depth complexity -- 1 to 3 or so
+
+have a sentinal at both ends?
+*/
+
+
+edge_t	*auxedges;
+edge_t	*r_edges, *edge_p, *edge_max;
+
+surf_t	*surfaces, *surface_p, *surf_max;
+
+// 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
+
+edge_t	*newedges[MAXHEIGHT];
+edge_t	*removeedges[MAXHEIGHT];
+
+espan_t	*span_p, *max_span_p;
+
+int		r_currentkey;
+
+int	current_iv;
+
+int	edge_head_u_shift20, edge_tail_u_shift20;
+
+static void (*pdrawfunc)(void);
+
+edge_t	edge_head;
+edge_t	edge_tail;
+edge_t	edge_aftertail;
+edge_t	edge_sentinel;
+
+float	fv;
+
+static int	miplevel;
+
+float		scale_for_mip;
+int			ubasestep, errorterm, erroradjustup, erroradjustdown;
+
+// FIXME: should go away
+extern void			R_RotateBmodel (void);
+extern void			R_TransformFrustum (void);
+
+
+
+void R_GenerateSpans (void);
+void R_GenerateSpansBackward (void);
+
+void R_LeadingEdge (edge_t *edge);
+void R_LeadingEdgeBackwards (edge_t *edge);
+void R_TrailingEdge (surf_t *surf, edge_t *edge);
+
+
+/*
+===============================================================================
+
+EDGE SCANNING
+
+===============================================================================
+*/
+
+/*
+==============
+R_BeginEdgeFrame
+==============
+*/
+void R_BeginEdgeFrame (void)
+{
+	int		v;
+
+	edge_p = r_edges;
+	edge_max = &r_edges[r_numallocatededges];
+
+	surface_p = &surfaces[2];	// background is surface 1,
+								//  surface 0 is a dummy
+	surfaces[1].spans = NULL;	// no background spans yet
+	surfaces[1].flags = SURF_DRAWBACKGROUND;
+
+// put the background behind everything in the world
+	if (sw_draworder->value)
+	{
+		pdrawfunc = R_GenerateSpansBackward;
+		surfaces[1].key = 0;
+		r_currentkey = 1;
+	}
+	else
+	{
+		pdrawfunc = R_GenerateSpans;
+		surfaces[1].key = 0x7FFfFFFF;
+		r_currentkey = 0;
+	}
+
+// FIXME: set with memset
+	for (v=r_refdef.vrect.y ; v<r_refdef.vrectbottom ; v++)
+	{
+		newedges[v] = removeedges[v] = NULL;
+	}
+}
+
+/*
+==============
+R_InsertNewEdges
+
+Adds the edges in the linked list edgestoadd, adding them to the edges in the
+linked list edgelist.  edgestoadd is assumed to be sorted on u, and non-empty (this is actually newedges[v]).  edgelist is assumed to be sorted on u, with a
+sentinel at the end (actually, this is the active edge table starting at
+edge_head.next).
+==============
+*/
+void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist)
+{
+	edge_t	*next_edge;
+
+	do
+	{
+		next_edge = edgestoadd->next;
+edgesearch:
+		if (edgelist->u >= edgestoadd->u)
+			goto addedge;
+		edgelist=edgelist->next;
+		if (edgelist->u >= edgestoadd->u)
+			goto addedge;
+		edgelist=edgelist->next;
+		if (edgelist->u >= edgestoadd->u)
+			goto addedge;
+		edgelist=edgelist->next;
+		if (edgelist->u >= edgestoadd->u)
+			goto addedge;
+		edgelist=edgelist->next;
+		goto edgesearch;
+
+	// insert edgestoadd before edgelist
+addedge:
+		edgestoadd->next = edgelist;
+		edgestoadd->prev = edgelist->prev;
+		edgelist->prev->next = edgestoadd;
+		edgelist->prev = edgestoadd;
+	} while ((edgestoadd = next_edge) != NULL);
+}
+
+
+/*
+==============
+R_RemoveEdges
+==============
+*/
+void R_RemoveEdges (edge_t *pedge)
+{
+
+	do
+	{
+		pedge->next->prev = pedge->prev;
+		pedge->prev->next = pedge->next;
+	} while ((pedge = pedge->nextremove) != NULL);
+}
+
+
+/*
+==============
+R_StepActiveU
+==============
+*/
+void R_StepActiveU (edge_t *pedge)
+{
+	edge_t		*pnext_edge, *pwedge;
+
+	while (1)
+	{
+nextedge:
+		pedge->u += pedge->u_step;
+		if (pedge->u < pedge->prev->u)
+			goto pushback;
+		pedge = pedge->next;
+			
+		pedge->u += pedge->u_step;
+		if (pedge->u < pedge->prev->u)
+			goto pushback;
+		pedge = pedge->next;
+			
+		pedge->u += pedge->u_step;
+		if (pedge->u < pedge->prev->u)
+			goto pushback;
+		pedge = pedge->next;
+			
+		pedge->u += pedge->u_step;
+		if (pedge->u < pedge->prev->u)
+			goto pushback;
+		pedge = pedge->next;
+			
+		goto nextedge;		
+		
+pushback:
+		if (pedge == &edge_aftertail)
+			return;
+			
+	// push it back to keep it sorted		
+		pnext_edge = pedge->next;
+
+	// pull the edge out of the edge list
+		pedge->next->prev = pedge->prev;
+		pedge->prev->next = pedge->next;
+
+	// find out where the edge goes in the edge list
+		pwedge = pedge->prev->prev;
+
+		while (pwedge->u > pedge->u)
+		{
+			pwedge = pwedge->prev;
+		}
+
+	// put the edge back into the edge list
+		pedge->next = pwedge->next;
+		pedge->prev = pwedge;
+		pedge->next->prev = pedge;
+		pwedge->next = pedge;
+
+		pedge = pnext_edge;
+		if (pedge == &edge_tail)
+			return;
+	}
+}
+
+
+/*
+==============
+R_CleanupSpan
+==============
+*/
+void R_CleanupSpan (void)
+{
+	surf_t	*surf;
+	int		iu;
+	espan_t	*span;
+
+// now that we've reached the right edge of the screen, we're done with any
+// unfinished surfaces, so emit a span for whatever's on top
+	surf = surfaces[1].next;
+	iu = edge_tail_u_shift20;
+	if (iu > surf->last_u)
+	{
+		span = span_p++;
+		span->u = surf->last_u;
+		span->count = iu - span->u;
+		span->v = current_iv;
+		span->pnext = surf->spans;
+		surf->spans = span;
+	}
+
+// reset spanstate for all surfaces in the surface stack
+	do
+	{
+		surf->spanstate = 0;
+		surf = surf->next;
+	} while (surf != &surfaces[1]);
+}
+
+
+/*
+==============
+R_LeadingEdgeBackwards
+==============
+*/
+void R_LeadingEdgeBackwards (edge_t *edge)
+{
+	espan_t			*span;
+	surf_t			*surf, *surf2;
+	int				iu;
+
+// it's adding a new surface in, so find the correct place
+	surf = &surfaces[edge->surfs[1]];
+
+// don't start a span if this is an inverted span, with the end
+// edge preceding the start edge (that is, we've already seen the
+// end edge)
+	if (++surf->spanstate == 1)
+	{
+		surf2 = surfaces[1].next;
+
+		if (surf->key > surf2->key)
+			goto newtop;
+
+	// if it's two surfaces on the same plane, the one that's already
+	// active is in front, so keep going unless it's a bmodel
+		if (surf->insubmodel && (surf->key == surf2->key))
+		{
+		// must be two bmodels in the same leaf; don't care, because they'll
+		// never be farthest anyway
+			goto newtop;
+		}
+
+continue_search:
+
+		do
+		{
+			surf2 = surf2->next;
+		} while (surf->key < surf2->key);
+
+		if (surf->key == surf2->key)
+		{
+		// if it's two surfaces on the same plane, the one that's already
+		// active is in front, so keep going unless it's a bmodel
+			if (!surf->insubmodel)
+				goto continue_search;
+
+		// must be two bmodels in the same leaf; don't care which is really
+		// in front, because they'll never be farthest anyway
+		}
+
+		goto gotposition;
+
+newtop:
+	// emit a span (obscures current top)
+		iu = edge->u >> 20;
+
+		if (iu > surf2->last_u)
+		{
+			span = span_p++;
+			span->u = surf2->last_u;
+			span->count = iu - span->u;
+			span->v = current_iv;
+			span->pnext = surf2->spans;
+			surf2->spans = span;
+		}
+
+		// set last_u on the new span
+		surf->last_u = iu;
+				
+gotposition:
+	// insert before surf2
+		surf->next = surf2;
+		surf->prev = surf2->prev;
+		surf2->prev->next = surf;
+		surf2->prev = surf;
+	}
+}
+
+
+/*
+==============
+R_TrailingEdge
+==============
+*/
+void R_TrailingEdge (surf_t *surf, edge_t *edge)
+{
+	espan_t			*span;
+	int				iu;
+
+// don't generate a span if this is an inverted span, with the end
+// edge preceding the start edge (that is, we haven't seen the
+// start edge yet)
+	if (--surf->spanstate == 0)
+	{
+		if (surf == surfaces[1].next)
+		{
+		// emit a span (current top going away)
+			iu = edge->u >> 20;
+			if (iu > surf->last_u)
+			{
+				span = span_p++;
+				span->u = surf->last_u;
+				span->count = iu - span->u;
+				span->v = current_iv;
+				span->pnext = surf->spans;
+				surf->spans = span;
+			}
+
+		// set last_u on the surface below
+			surf->next->last_u = iu;
+		}
+
+		surf->prev->next = surf->next;
+		surf->next->prev = surf->prev;
+	}
+}
+
+
+/*
+==============
+R_LeadingEdge
+==============
+*/
+void R_LeadingEdge (edge_t *edge)
+{
+	espan_t			*span;
+	surf_t			*surf, *surf2;
+	int				iu;
+	float			fu, newzi, testzi, newzitop, newzibottom;
+
+	if (edge->surfs[1])
+	{
+	// it's adding a new surface in, so find the correct place
+		surf = &surfaces[edge->surfs[1]];
+
+	// don't start a span if this is an inverted span, with the end
+	// edge preceding the start edge (that is, we've already seen the
+	// end edge)
+		if (++surf->spanstate == 1)
+		{
+			surf2 = surfaces[1].next;
+
+			if (surf->key < surf2->key)
+				goto newtop;
+
+		// if it's two surfaces on the same plane, the one that's already
+		// active is in front, so keep going unless it's a bmodel
+			if (surf->insubmodel && (surf->key == surf2->key))
+			{
+			// must be two bmodels in the same leaf; sort on 1/z
+				fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
+				newzi = surf->d_ziorigin + fv*surf->d_zistepv +
+						fu*surf->d_zistepu;
+				newzibottom = newzi * 0.99;
+
+				testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
+						fu*surf2->d_zistepu;
+
+				if (newzibottom >= testzi)
+				{
+					goto newtop;
+				}
+
+				newzitop = newzi * 1.01;
+				if (newzitop >= testzi)
+				{
+					if (surf->d_zistepu >= surf2->d_zistepu)
+					{
+						goto newtop;
+					}
+				}
+			}
+
+continue_search:
+
+			do
+			{
+				surf2 = surf2->next;
+			} while (surf->key > surf2->key);
+
+			if (surf->key == surf2->key)
+			{
+			// if it's two surfaces on the same plane, the one that's already
+			// active is in front, so keep going unless it's a bmodel
+				if (!surf->insubmodel)
+					goto continue_search;
+
+			// must be two bmodels in the same leaf; sort on 1/z
+				fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
+				newzi = surf->d_ziorigin + fv*surf->d_zistepv +
+						fu*surf->d_zistepu;
+				newzibottom = newzi * 0.99;
+
+				testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
+						fu*surf2->d_zistepu;
+
+				if (newzibottom >= testzi)
+				{
+					goto gotposition;
+				}
+
+				newzitop = newzi * 1.01;
+				if (newzitop >= testzi)
+				{
+					if (surf->d_zistepu >= surf2->d_zistepu)
+					{
+						goto gotposition;
+					}
+				}
+
+				goto continue_search;
+			}
+
+			goto gotposition;
+
+newtop:
+		// emit a span (obscures current top)
+			iu = edge->u >> 20;
+
+			if (iu > surf2->last_u)
+			{
+				span = span_p++;
+				span->u = surf2->last_u;
+				span->count = iu - span->u;
+				span->v = current_iv;
+				span->pnext = surf2->spans;
+				surf2->spans = span;
+			}
+
+			// set last_u on the new span
+			surf->last_u = iu;
+				
+gotposition:
+		// insert before surf2
+			surf->next = surf2;
+			surf->prev = surf2->prev;
+			surf2->prev->next = surf;
+			surf2->prev = surf;
+		}
+	}
+}
+
+
+/*
+==============
+R_GenerateSpans
+==============
+*/
+void R_GenerateSpans (void)
+{
+	edge_t			*edge;
+	surf_t			*surf;
+
+// clear active surfaces to just the background surface
+	surfaces[1].next = surfaces[1].prev = &surfaces[1];
+	surfaces[1].last_u = edge_head_u_shift20;
+
+// generate spans
+	for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
+	{			
+		if (edge->surfs[0])
+		{
+		// it has a left surface, so a surface is going away for this span
+			surf = &surfaces[edge->surfs[0]];
+
+			R_TrailingEdge (surf, edge);
+
+			if (!edge->surfs[1])
+				continue;
+		}
+
+		R_LeadingEdge (edge);
+	}
+
+	R_CleanupSpan ();
+}
+
+
+/*
+==============
+R_GenerateSpansBackward
+==============
+*/
+void R_GenerateSpansBackward (void)
+{
+	edge_t			*edge;
+
+// clear active surfaces to just the background surface
+	surfaces[1].next = surfaces[1].prev = &surfaces[1];
+	surfaces[1].last_u = edge_head_u_shift20;
+
+// generate spans
+	for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
+	{			
+		if (edge->surfs[0])
+			R_TrailingEdge (&surfaces[edge->surfs[0]], edge);
+
+		if (edge->surfs[1])
+			R_LeadingEdgeBackwards (edge);
+	}
+
+	R_CleanupSpan ();
+}
+
+
+/*
+==============
+R_ScanEdges
+
+Input: 
+newedges[] array
+	this has links to edges, which have links to surfaces
+
+Output:
+Each surface has a linked list of its visible spans
+==============
+*/
+void R_ScanEdges (void)
+{
+	int		iv, bottom;
+	byte	basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
+	espan_t	*basespan_p;
+	surf_t	*s;
+
+	basespan_p = (espan_t *)
+			((uintptr)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+	max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width];
+
+	span_p = basespan_p;
+
+// clear active edges to just the background edges around the whole screen
+// FIXME: most of this only needs to be set up once
+	edge_head.u = r_refdef.vrect.x << 20;
+	edge_head_u_shift20 = edge_head.u >> 20;
+	edge_head.u_step = 0;
+	edge_head.prev = NULL;
+	edge_head.next = &edge_tail;
+	edge_head.surfs[0] = 0;
+	edge_head.surfs[1] = 1;
+	
+	edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF;
+	edge_tail_u_shift20 = edge_tail.u >> 20;
+	edge_tail.u_step = 0;
+	edge_tail.prev = &edge_head;
+	edge_tail.next = &edge_aftertail;
+	edge_tail.surfs[0] = 1;
+	edge_tail.surfs[1] = 0;
+	
+	edge_aftertail.u = -1;		// force a move
+	edge_aftertail.u_step = 0;
+	edge_aftertail.next = &edge_sentinel;
+	edge_aftertail.prev = &edge_tail;
+
+// FIXME: do we need this now that we clamp x in r_draw.c?
+	edge_sentinel.u = 2000 << 24;		// make sure nothing sorts past this
+	edge_sentinel.prev = &edge_aftertail;
+
+//	
+// process all scan lines
+//
+	bottom = r_refdef.vrectbottom - 1;
+
+	for (iv=r_refdef.vrect.y ; iv<bottom ; iv++)
+	{
+		current_iv = iv;
+		fv = (float)iv;
+
+	// mark that the head (background start) span is pre-included
+		surfaces[1].spanstate = 1;
+
+		if (newedges[iv])
+		{
+			R_InsertNewEdges (newedges[iv], edge_head.next);
+		}
+
+		(*pdrawfunc) ();
+
+	// flush the span list if we can't be sure we have enough spans left for
+	// the next scan
+		if (span_p > max_span_p)
+		{
+			D_DrawSurfaces ();
+
+		// clear the surface span pointers
+			for (s = &surfaces[1] ; s<surface_p ; s++)
+				s->spans = NULL;
+
+			span_p = basespan_p;
+		}
+
+		if (removeedges[iv])
+			R_RemoveEdges (removeedges[iv]);
+
+		if (edge_head.next != &edge_tail)
+			R_StepActiveU (edge_head.next);
+	}
+
+// do the last scan (no need to step or sort or remove on the last scan)
+
+	current_iv = iv;
+	fv = (float)iv;
+
+// mark that the head (background start) span is pre-included
+	surfaces[1].spanstate = 1;
+
+	if (newedges[iv])
+		R_InsertNewEdges (newedges[iv], edge_head.next);
+
+	(*pdrawfunc) ();
+
+// draw whatever's left in the span list
+	D_DrawSurfaces ();
+}
+
+
+/*
+=========================================================================
+
+SURFACE FILLING
+
+=========================================================================
+*/
+
+msurface_t		*pface;
+surfcache_t		*pcurrentcache;
+vec3_t			transformed_modelorg;
+vec3_t			world_transformed_modelorg;
+vec3_t			local_modelorg;
+
+/*
+=============
+D_MipLevelForScale
+=============
+*/
+int D_MipLevelForScale (float scale)
+{
+	int		lmiplevel;
+
+	if (scale >= d_scalemip[0] )
+		lmiplevel = 0;
+	else if (scale >= d_scalemip[1] )
+		lmiplevel = 1;
+	else if (scale >= d_scalemip[2] )
+		lmiplevel = 2;
+	else
+		lmiplevel = 3;
+
+	if (lmiplevel < d_minmip)
+		lmiplevel = d_minmip;
+
+	return lmiplevel;
+}
+
+
+/*
+==============
+D_FlatFillSurface
+
+Simple single color fill with no texture mapping
+==============
+*/
+void D_FlatFillSurface (surf_t *surf, int color)
+{
+	espan_t	*span;
+	byte	*pdest;
+	int		u, u2;
+	
+	for (span=surf->spans ; span ; span=span->pnext)
+	{
+		pdest = (byte *)d_viewbuffer + r_screenwidth*span->v;
+		u = span->u;
+		u2 = span->u + span->count - 1;
+		for ( ; u <= u2 ; u++)
+			pdest[u] = color;
+	}
+}
+
+
+/*
+==============
+D_CalcGradients
+==============
+*/
+void D_CalcGradients (msurface_t *pface)
+{
+	float		mipscale;
+	vec3_t		p_temp1;
+	vec3_t		p_saxis, p_taxis;
+	float		t;
+
+	mipscale = 1.0 / (float)(1 << miplevel);
+
+	TransformVector (pface->texinfo->vecs[0], p_saxis);
+	TransformVector (pface->texinfo->vecs[1], p_taxis);
+
+	t = xscaleinv * mipscale;
+	d_sdivzstepu = p_saxis[0] * t;
+	d_tdivzstepu = p_taxis[0] * t;
+
+	t = yscaleinv * mipscale;
+	d_sdivzstepv = -p_saxis[1] * t;
+	d_tdivzstepv = -p_taxis[1] * t;
+
+	d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu -
+			ycenter * d_sdivzstepv;
+	d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu -
+			ycenter * d_tdivzstepv;
+
+	VectorScale (transformed_modelorg, mipscale, p_temp1);
+
+	t = 0x10000*mipscale;
+	sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
+			((pface->texturemins[0] << 16) >> miplevel)
+			+ pface->texinfo->vecs[0][3]*t;
+	tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
+			((pface->texturemins[1] << 16) >> miplevel)
+			+ pface->texinfo->vecs[1][3]*t;
+
+	// PGM - changing flow speed for non-warping textures.
+	if (pface->texinfo->flags & SURF_FLOWING)
+	{
+		if(pface->texinfo->flags & SURF_WARP)
+			sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.25) - (int)(r_newrefdef.time * 0.25) ));
+		else
+			sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.77) - (int)(r_newrefdef.time * 0.77) ));
+	}
+	// PGM
+
+//
+// -1 (-epsilon) so we never wander off the edge of the texture
+//
+	bbextents = ((pface->extents[0] << 16) >> miplevel) - 1;
+	bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1;
+}
+
+
+/*
+==============
+D_BackgroundSurf
+
+The grey background filler seen when there is a hole in the map
+==============
+*/
+void D_BackgroundSurf (surf_t *s)
+{
+// set up a gradient for the background surface that places it
+// effectively at infinity distance from the viewpoint
+	d_zistepu = 0;
+	d_zistepv = 0;
+	d_ziorigin = -0.9;
+
+	D_FlatFillSurface (s, (int)sw_clearcolor->value & 0xFF);
+	D_DrawZSpans (s->spans);
+}
+
+/*
+=================
+D_TurbulentSurf
+=================
+*/
+void D_TurbulentSurf (surf_t *s)
+{
+	d_zistepu = s->d_zistepu;
+	d_zistepv = s->d_zistepv;
+	d_ziorigin = s->d_ziorigin;
+
+	pface = s->msurf;
+	miplevel = 0;
+	cacheblock = pface->texinfo->image->pixels[0];
+	cachewidth = 64;
+
+	if (s->insubmodel)
+	{
+	// FIXME: we don't want to do all this for every polygon!
+	// TODO: store once at start of frame
+		currententity = s->entity;	//FIXME: make this passed in to
+									// R_RotateBmodel ()
+		VectorSubtract (r_origin, currententity->origin,
+				local_modelorg);
+		TransformVector (local_modelorg, transformed_modelorg);
+
+		R_RotateBmodel ();	// FIXME: don't mess with the frustum,
+							// make entity passed in
+	}
+
+	D_CalcGradients (pface);
+
+//============
+//PGM
+	// textures that aren't warping are just flowing. Use NonTurbulent8 instead
+	if(!(pface->texinfo->flags & SURF_WARP))
+		NonTurbulent8 (s->spans);
+	else
+		Turbulent8 (s->spans);
+//PGM
+//============
+
+	D_DrawZSpans (s->spans);
+
+	if (s->insubmodel)
+	{
+	//
+	// restore the old drawing state
+	// FIXME: we don't want to do this every time!
+	// TODO: speed up
+	//
+		currententity = NULL;	// &r_worldentity;
+		VectorCopy (world_transformed_modelorg,
+					transformed_modelorg);
+		VectorCopy (base_vpn, vpn);
+		VectorCopy (base_vup, vup);
+		VectorCopy (base_vright, vright);
+		R_TransformFrustum ();
+	}
+}
+
+/*
+==============
+D_SkySurf
+==============
+*/
+void D_SkySurf (surf_t *s)
+{
+	pface = s->msurf;
+	miplevel = 0;
+	if (!pface->texinfo->image)
+		return;
+	cacheblock = pface->texinfo->image->pixels[0];
+	cachewidth = 256;
+
+	d_zistepu = s->d_zistepu;
+	d_zistepv = s->d_zistepv;
+	d_ziorigin = s->d_ziorigin;
+
+	D_CalcGradients (pface);
+
+	D_DrawSpans16 (s->spans);
+
+// set up a gradient for the background surface that places it
+// effectively at infinity distance from the viewpoint
+	d_zistepu = 0;
+	d_zistepv = 0;
+	d_ziorigin = -0.9;
+
+	D_DrawZSpans (s->spans);
+}
+
+/*
+==============
+D_SolidSurf
+
+Normal surface cached, texture mapped surface
+==============
+*/
+void D_SolidSurf (surf_t *s)
+{
+	d_zistepu = s->d_zistepu;
+	d_zistepv = s->d_zistepv;
+	d_ziorigin = s->d_ziorigin;
+
+	if (s->insubmodel)
+	{
+	// FIXME: we don't want to do all this for every polygon!
+	// TODO: store once at start of frame
+		currententity = s->entity;	//FIXME: make this passed in to
+									// R_RotateBmodel ()
+		VectorSubtract (r_origin, currententity->origin, local_modelorg);
+		TransformVector (local_modelorg, transformed_modelorg);
+
+		R_RotateBmodel ();	// FIXME: don't mess with the frustum,
+							// make entity passed in
+	}
+	else
+		currententity = &r_worldentity;
+
+	pface = s->msurf;
+/* commented out in release
+	{
+		float dot;
+		float normal[3];
+
+		if ( s->insubmodel )
+		{
+			VectorCopy( pface->plane->normal, normal );
+//			TransformVector( pface->plane->normal, normal);
+			dot = DotProduct( normal, vpn );
+		}
+		else
+		{
+			VectorCopy( pface->plane->normal, normal );
+			dot = DotProduct( normal, vpn );
+		}
+
+		if ( pface->flags & SURF_PLANEBACK )
+			dot = -dot;
+
+		if ( dot > 0 )
+			printf( "blah" );
+
+		miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust);
+	}
+*/
+	miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust);
+
+// FIXME: make this passed in to D_CacheSurface
+	pcurrentcache = D_CacheSurface (pface, miplevel);
+
+	cacheblock = (pixel_t *)pcurrentcache->data;
+	cachewidth = pcurrentcache->width;
+
+	D_CalcGradients (pface);
+
+	D_DrawSpans16 (s->spans);
+
+	D_DrawZSpans (s->spans);
+
+	if (s->insubmodel)
+	{
+	//
+	// restore the old drawing state
+	// FIXME: we don't want to do this every time!
+	// TODO: speed up
+	//
+		VectorCopy (world_transformed_modelorg,
+					transformed_modelorg);
+		VectorCopy (base_vpn, vpn);
+		VectorCopy (base_vup, vup);
+		VectorCopy (base_vright, vright);
+		R_TransformFrustum ();
+		currententity = NULL;	//&r_worldentity;
+	}
+}
+
+/*
+=============
+D_DrawflatSurfaces
+
+To allow developers to see the polygon carving of the world
+=============
+*/
+void D_DrawflatSurfaces (void)
+{
+	surf_t			*s;
+
+	for (s = &surfaces[1] ; s<surface_p ; s++)
+	{
+		if (!s->spans)
+			continue;
+
+		d_zistepu = s->d_zistepu;
+		d_zistepv = s->d_zistepv;
+		d_ziorigin = s->d_ziorigin;
+
+		// make a stable color for each surface by taking the low
+		// bits of the msurface pointer
+		D_FlatFillSurface (s, (uintptr)s->msurf & 0xFF);
+		D_DrawZSpans (s->spans);
+	}
+}
+
+/*
+==============
+D_DrawSurfaces
+
+Rasterize all the span lists.  Guaranteed zero overdraw.
+May be called more than once a frame if the surf list overflows (higher res)
+==============
+*/
+void D_DrawSurfaces (void)
+{
+	surf_t			*s;
+
+//	currententity = NULL;	//&r_worldentity;
+	VectorSubtract (r_origin, vec3_origin, modelorg);
+	TransformVector (modelorg, transformed_modelorg);
+	VectorCopy (transformed_modelorg, world_transformed_modelorg);
+
+	if (!sw_drawflat->value)
+	{
+		for (s = &surfaces[1] ; s<surface_p ; s++)
+		{
+			if (!s->spans)
+				continue;
+
+			r_drawnpolycount++;
+
+			if (! (s->flags & (SURF_DRAWSKYBOX|SURF_DRAWBACKGROUND|SURF_DRAWTURB) ) )
+				D_SolidSurf (s);
+			else if (s->flags & SURF_DRAWSKYBOX)
+				D_SkySurf (s);
+			else if (s->flags & SURF_DRAWBACKGROUND)
+				D_BackgroundSurf (s);
+			else if (s->flags & SURF_DRAWTURB)
+				D_TurbulentSurf (s);
+		}
+	}
+	else
+		D_DrawflatSurfaces ();
+
+	currententity = NULL;	//&r_worldentity;
+	VectorSubtract (r_origin, vec3_origin, modelorg);
+	R_TransformFrustum ();
+}
+
--- /dev/null
+++ b/r_image.c
@@ -1,0 +1,581 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+#define	MAX_RIMAGES	1024
+image_t		r_images[MAX_RIMAGES];
+int			numr_images;
+
+
+/*
+===============
+R_ImageList_f
+===============
+*/
+void	R_ImageList_f (void)
+{
+	int		i;
+	image_t	*image;
+	int		texels;
+
+	ri.Con_Printf (PRINT_ALL, "------------------\n");
+	texels = 0;
+
+	for (i=0, image=r_images ; i<numr_images ; i++, image++)
+	{
+		if (image->registration_sequence <= 0)
+			continue;
+		texels += image->width*image->height;
+		switch (image->type)
+		{
+		case it_skin:
+			ri.Con_Printf (PRINT_ALL, "M");
+			break;
+		case it_sprite:
+			ri.Con_Printf (PRINT_ALL, "S");
+			break;
+		case it_wall:
+			ri.Con_Printf (PRINT_ALL, "W");
+			break;
+		case it_pic:
+			ri.Con_Printf (PRINT_ALL, "P");
+			break;
+		default:
+			ri.Con_Printf (PRINT_ALL, " ");
+			break;
+		}
+
+		ri.Con_Printf (PRINT_ALL,  " %3i %3i : %s\n",
+			image->width, image->height, image->name);
+	}
+	ri.Con_Printf (PRINT_ALL, "Total texel count: %i\n", texels);
+}
+
+
+/*
+=================================================================
+
+PCX LOADING
+
+=================================================================
+*/
+
+/*
+==============
+LoadPCX
+==============
+*/
+void 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 = ri.FS_LoadFile (filename, (void **)&raw);
+	if (!raw)
+	{
+		ri.Con_Printf (PRINT_DEVELOPER, "Bad pcx file %s\n", filename);
+		return;
+	}
+
+	//
+	// parse the PCX file
+	//
+	pcx = (pcx_t *)raw;
+
+    pcx->xmin = LittleShort(pcx->xmin);
+    pcx->ymin = LittleShort(pcx->ymin);
+    pcx->xmax = LittleShort(pcx->xmax);
+    pcx->ymax = LittleShort(pcx->ymax);
+    pcx->hres = LittleShort(pcx->hres);
+    pcx->vres = LittleShort(pcx->vres);
+    pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
+    pcx->palette_type = LittleShort(pcx->palette_type);
+
+	raw = &pcx->data;
+
+	if (pcx->manufacturer != 0x0a
+		|| pcx->version != 5
+		|| pcx->encoding != 1
+		|| pcx->bits_per_pixel != 8
+		|| pcx->xmax >= 640
+		|| pcx->ymax >= 480)
+	{
+		ri.Con_Printf (PRINT_ALL, "Bad pcx file %s\n", filename);
+		return;
+	}
+
+	out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
+
+	*pic = out;
+
+	pix = out;
+
+	if (palette)
+	{
+		*palette = 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)
+	{
+		ri.Con_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
+		free (*pic);
+		*pic = NULL;
+	}
+
+	ri.FS_FreeFile (pcx);
+}
+
+/*
+=========================================================
+
+TARGA LOADING
+
+=========================================================
+*/
+
+typedef struct _TargaHeader {
+	unsigned char 	id_length, colormap_type, image_type;
+	unsigned short	colormap_index, colormap_length;
+	unsigned char	colormap_size;
+	unsigned short	x_origin, y_origin, width, height;
+	unsigned char	pixel_size, attributes;
+} TargaHeader;
+
+
+/*
+=============
+LoadTGA
+=============
+*/
+void LoadTGA (char *name, byte **pic, int *width, int *height)
+{
+	int		columns, rows, numPixels;
+	byte	*pixbuf;
+	int		row, column;
+	byte	*buf_p;
+	byte	*buffer;
+	TargaHeader		targa_header;
+	byte			*targa_rgba;
+	uchar	red = 0, green = 0, blue = 0, alphabyte = 0, packetHeader, packetSize, j;
+
+	*pic = NULL;
+
+	//
+	// load the file
+	//
+	ri.FS_LoadFile (name, (void **)&buffer);	/* int length = */
+	if (!buffer)
+	{
+		ri.Con_Printf (PRINT_DEVELOPER, "Bad tga file %s\n", name);
+		return;
+	}
+
+	buf_p = buffer;
+
+	targa_header.id_length = *buf_p++;
+	targa_header.colormap_type = *buf_p++;
+	targa_header.image_type = *buf_p++;
+	
+	targa_header.colormap_index = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.colormap_length = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.colormap_size = *buf_p++;
+	targa_header.x_origin = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.y_origin = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.width = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.height = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.pixel_size = *buf_p++;
+	targa_header.attributes = *buf_p++;
+
+	if (targa_header.image_type!=2 
+		&& targa_header.image_type!=10) 
+		ri.Sys_Error (ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n");
+
+	if (targa_header.colormap_type !=0 
+		|| (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
+		ri.Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
+
+	columns = targa_header.width;
+	rows = targa_header.height;
+	numPixels = columns * rows;
+
+	if (width)
+		*width = columns;
+	if (height)
+		*height = rows;
+
+	targa_rgba = malloc (numPixels*4);
+	*pic = targa_rgba;
+
+	if (targa_header.id_length != 0)
+		buf_p += targa_header.id_length;  // skip TARGA image comment
+	
+	if (targa_header.image_type==2) {  // Uncompressed, RGB images
+		for(row=rows-1; row>=0; row--) {
+			pixbuf = targa_rgba + row*columns*4;
+			for(column=0; column<columns; column++) {
+				switch (targa_header.pixel_size) {
+					case 24:
+							
+							blue = *buf_p++;
+							green = *buf_p++;
+							red = *buf_p++;
+							*pixbuf++ = red;
+							*pixbuf++ = green;
+							*pixbuf++ = blue;
+							*pixbuf++ = 255;
+							break;
+					case 32:
+							blue = *buf_p++;
+							green = *buf_p++;
+							red = *buf_p++;
+							alphabyte = *buf_p++;
+							*pixbuf++ = red;
+							*pixbuf++ = green;
+							*pixbuf++ = blue;
+							*pixbuf++ = alphabyte;
+							break;
+				}
+			}
+		}
+	}
+	else if (targa_header.image_type==10) {   // Runlength encoded RGB images
+		for(row=rows-1; row>=0; row--) {
+			pixbuf = targa_rgba + row*columns*4;
+			for(column=0; column<columns; ) {
+				packetHeader= *buf_p++;
+				packetSize = 1 + (packetHeader & 0x7f);
+				if (packetHeader & 0x80) {        // run-length packet
+					switch (targa_header.pixel_size) {
+						case 24:
+								blue = *buf_p++;
+								green = *buf_p++;
+								red = *buf_p++;
+								alphabyte = 255;
+								break;
+						case 32:
+								blue = *buf_p++;
+								green = *buf_p++;
+								red = *buf_p++;
+								alphabyte = *buf_p++;
+								break;
+					}
+	
+					for(j=0;j<packetSize;j++) {
+						*pixbuf++=red;
+						*pixbuf++=green;
+						*pixbuf++=blue;
+						*pixbuf++=alphabyte;
+						column++;
+						if (column==columns) { // run spans across rows
+							column=0;
+							if (row>0)
+								row--;
+							else
+								goto breakOut;
+							pixbuf = targa_rgba + row*columns*4;
+						}
+					}
+				}
+				else {                            // non run-length packet
+					for(j=0;j<packetSize;j++) {
+						switch (targa_header.pixel_size) {
+							case 24:
+									blue = *buf_p++;
+									green = *buf_p++;
+									red = *buf_p++;
+									*pixbuf++ = red;
+									*pixbuf++ = green;
+									*pixbuf++ = blue;
+									*pixbuf++ = 255;
+									break;
+							case 32:
+									blue = *buf_p++;
+									green = *buf_p++;
+									red = *buf_p++;
+									alphabyte = *buf_p++;
+									*pixbuf++ = red;
+									*pixbuf++ = green;
+									*pixbuf++ = blue;
+									*pixbuf++ = alphabyte;
+									break;
+						}
+						column++;
+						if (column==columns) { // pixel packet run spans across rows
+							column=0;
+							if (row>0)
+								row--;
+							else
+								goto breakOut;
+							pixbuf = targa_rgba + row*columns*4;
+						}						
+					}
+				}
+			}
+			breakOut:;
+		}
+	}
+
+	ri.FS_FreeFile (buffer);
+}
+
+
+//=======================================================
+
+image_t *R_FindFreeImage (void)
+{
+	image_t		*image;
+	int			i;
+
+	// find a free image_t
+	for (i=0, image=r_images ; i<numr_images ; i++,image++)
+	{
+		if (!image->registration_sequence)
+			break;
+	}
+	if (i == numr_images)
+	{
+		if (numr_images == MAX_RIMAGES)
+			ri.Sys_Error (ERR_DROP, "MAX_RIMAGES");
+		numr_images++;
+	}
+	image = &r_images[i];
+
+	return image;
+}
+
+/*
+================
+GL_LoadPic
+
+================
+*/
+image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type)
+{
+	image_t		*image;
+	int			i, c, b;
+
+	image = R_FindFreeImage ();
+	if (strlen(name) >= sizeof(image->name))
+		ri.Sys_Error (ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name);
+	strcpy (image->name, name);
+	image->registration_sequence = registration_sequence;
+
+	image->width = width;
+	image->height = height;
+	image->type = type;
+
+	c = width*height;
+	image->pixels[0] = malloc (c);
+	image->transparent = false;
+	for (i=0 ; i<c ; i++)
+	{
+		b = pic[i];
+		if (b == 255)
+			image->transparent = true;
+		image->pixels[0][i] = b;
+	}
+
+	return image;
+}
+
+/*
+================
+R_LoadWal
+================
+*/
+image_t *R_LoadWal (char *name)
+{
+	miptex_t	*mt;
+	int			ofs;
+	image_t		*image;
+	int			size;
+
+	ri.FS_LoadFile (name, (void **)&mt);
+	if (!mt)
+	{
+		ri.Con_Printf (PRINT_ALL, "R_LoadWal: can't load %s\n", name);
+		return r_notexture_mip;
+	}
+
+	image = R_FindFreeImage ();
+	strcpy (image->name, name);
+	image->width = LittleLong (mt->width);
+	image->height = LittleLong (mt->height);
+	image->type = it_wall;
+	image->registration_sequence = registration_sequence;
+
+	size = image->width*image->height * (256+64+16+4)/256;
+	image->pixels[0] = malloc (size);
+	image->pixels[1] = image->pixels[0] + image->width*image->height;
+	image->pixels[2] = image->pixels[1] + image->width*image->height/4;
+	image->pixels[3] = image->pixels[2] + image->width*image->height/16;
+
+	ofs = LittleLong (mt->offsets[0]);
+	memcpy ( image->pixels[0], (byte *)mt + ofs, size);
+
+	ri.FS_FreeFile ((void *)mt);
+
+	return image;
+}
+
+
+/*
+===============
+R_FindImage
+
+Finds or loads the given image
+===============
+*/
+image_t	*R_FindImage (char *name, imagetype_t type)
+{
+	image_t	*image;
+	int		i, len;
+	byte	*pic, *palette;
+	int		width, height;
+
+	if (!name)
+		return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: NULL name");
+	len = strlen(name);
+	if (len<5)
+		return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: bad name: %s", name);
+
+	// look for it
+	for (i=0, image=r_images ; i<numr_images ; i++,image++)
+	{
+		if (!strcmp(name, image->name))
+		{
+			image->registration_sequence = registration_sequence;
+			return image;
+		}
+	}
+
+	//
+	// load the pic from disk
+	//
+	pic = NULL;
+	palette = NULL;
+	if (!strcmp(name+len-4, ".pcx"))
+	{
+		LoadPCX (name, &pic, &palette, &width, &height);
+		if (!pic)
+			return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s", name);
+		image = GL_LoadPic (name, pic, width, height, type);
+	}
+	else if (!strcmp(name+len-4, ".wal"))
+	{
+		image = R_LoadWal (name);
+	}
+	else if (!strcmp(name+len-4, ".tga"))
+		return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s in software renderer", name);
+	else
+		return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: bad extension on: %s", name);
+
+	if (pic)
+		free(pic);
+	if (palette)
+		free(palette);
+
+	return image;
+}
+
+image_t *
+R_RegisterSkin(char *name)
+{
+	return R_FindImage(name, it_skin);
+}
+
+
+/*
+================
+R_FreeUnusedImages
+
+Any image that was not touched on this registration sequence
+will be freed.
+================
+*/
+void R_FreeUnusedImages (void)
+{
+	int		i;
+	image_t	*image;
+
+	for (i=0, image=r_images ; i<numr_images ; i++, image++)
+	{
+		if (image->registration_sequence == registration_sequence)
+		{
+			Com_PageInMemory ((byte *)image->pixels[0], image->width*image->height);
+			continue;		// used this sequence
+		}
+		if (!image->registration_sequence)
+			continue;		// free texture
+		if (image->type == it_pic)
+			continue;		// don't free pics
+		// free it
+		free (image->pixels[0]);	// the other mip levels just follow
+		memset (image, 0, sizeof(*image));
+	}
+}
+
+void
+R_InitImages(void)
+{
+	registration_sequence = 1;
+}
+
+void
+R_ShutdownImages(void)
+{
+	int i;
+	image_t *image;
+
+	for(i=0, image=r_images; i<numr_images; i++, image++){
+		if(!image->registration_sequence)
+			continue;		// free texture
+		// free it
+		free(image->pixels[0]);	// the other mip levels just follow
+		memset(image, 0, sizeof *image);
+	}
+}
--- /dev/null
+++ b/r_light.c
@@ -1,0 +1,423 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+int	r_dlightframecount;
+
+
+/*
+=============================================================================
+
+DYNAMIC LIGHTS
+
+=============================================================================
+*/
+
+/*
+=============
+R_MarkLights
+=============
+*/
+void R_MarkLights (dlight_t *light, int bit, mnode_t *node)
+{
+	mplane_t	*splitplane;
+	float		dist;
+	msurface_t	*surf;
+	int			i;
+	
+	if (node->contents != -1)
+		return;
+
+	splitplane = node->plane;
+	dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
+	
+//=====
+//PGM
+	i=light->intensity;
+	if(i<0)
+		i=-i;
+//PGM
+//=====
+
+	if (dist > i)	// PGM (dist > light->intensity)
+	{
+		R_MarkLights (light, bit, node->children[0]);
+		return;
+	}
+	if (dist < -i)	// PGM (dist < -light->intensity)
+	{
+		R_MarkLights (light, bit, node->children[1]);
+		return;
+	}
+		
+// mark the polygons
+	surf = r_worldmodel->surfaces + node->firstsurface;
+	for (i=0 ; i<node->numsurfaces ; i++, surf++)
+	{
+		if (surf->dlightframe != r_dlightframecount)
+		{
+			surf->dlightbits = 0;
+			surf->dlightframe = r_dlightframecount;
+		}
+		surf->dlightbits |= bit;
+	}
+
+	R_MarkLights (light, bit, node->children[0]);
+	R_MarkLights (light, bit, node->children[1]);
+}
+
+
+/*
+=============
+R_PushDlights
+=============
+*/
+void R_PushDlights (model_t *model)
+{
+	int		i;
+	dlight_t	*l;
+
+	r_dlightframecount = r_framecount;
+	for (i=0, l = r_newrefdef.dlights ; i<r_newrefdef.num_dlights ; i++, l++)
+	{
+		R_MarkLights ( l, 1<<i, 
+			model->nodes + model->firstnode);
+	}
+}
+
+
+/*
+=============================================================================
+
+LIGHT SAMPLING
+
+=============================================================================
+*/
+
+vec3_t	pointcolor;
+mplane_t		*lightplane;		// used as shadow plane
+vec3_t			lightspot;
+
+int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
+{
+	float		front, back, frac;
+	int			side;
+	mplane_t	*plane;
+	vec3_t		mid;
+	msurface_t	*surf;
+	int			s, t, ds, dt;
+	int			i;
+	mtexinfo_t	*tex;
+	byte		*lightmap;
+	float		*scales;
+	int			maps;
+	float		samp;
+	int			r;
+
+	if (node->contents != -1)
+		return -1;		// didn't hit anything
+	
+// calculate mid point
+
+// FIXME: optimize for axial
+	plane = node->plane;
+	front = DotProduct (start, plane->normal) - plane->dist;
+	back = DotProduct (end, plane->normal) - plane->dist;
+	side = front < 0;
+	
+	if ( (back < 0) == side)
+		return RecursiveLightPoint (node->children[side], start, end);
+	
+	frac = front / (front-back);
+	mid[0] = start[0] + (end[0] - start[0])*frac;
+	mid[1] = start[1] + (end[1] - start[1])*frac;
+	mid[2] = start[2] + (end[2] - start[2])*frac;
+	if (plane->type < 3)	// axial planes
+		mid[plane->type] = plane->dist;
+
+// go down front side	
+	r = RecursiveLightPoint (node->children[side], start, mid);
+	if (r >= 0)
+		return r;		// hit something
+		
+	if ( (back < 0) == side )
+		return -1;		// didn't hit anuthing
+		
+// check for impact on this node
+	VectorCopy (mid, lightspot);
+	lightplane = plane;
+
+	surf = r_worldmodel->surfaces + node->firstsurface;
+	for (i=0 ; i<node->numsurfaces ; i++, surf++)
+	{
+		if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY)) 
+			continue;	// no lightmaps
+
+		tex = surf->texinfo;
+		
+		s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3];
+		t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];
+		if (s < surf->texturemins[0] ||
+		t < surf->texturemins[1])
+			continue;
+		
+		ds = s - surf->texturemins[0];
+		dt = t - surf->texturemins[1];
+		
+		if ( ds > surf->extents[0] || dt > surf->extents[1] )
+			continue;
+
+		if (!surf->samples)
+			return 0;
+
+		ds >>= 4;
+		dt >>= 4;
+
+		lightmap = surf->samples;
+		VectorCopy (vec3_origin, pointcolor);
+		if (lightmap)
+		{
+			lightmap += dt * ((surf->extents[0]>>4)+1) + ds;
+
+			for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
+					maps++)
+			{
+				samp = *lightmap * /* 0.5 * */ (1.0/255);	// adjust for gl scale
+				scales = r_newrefdef.lightstyles[surf->styles[maps]].rgb;
+				VectorMA (pointcolor, samp, scales, pointcolor);
+				lightmap += ((surf->extents[0]>>4)+1) *
+						((surf->extents[1]>>4)+1);
+			}
+		}
+		
+		return 1;
+	}
+
+// go down back side
+	return RecursiveLightPoint (node->children[!side], mid, end);
+}
+
+/*
+===============
+R_LightPoint
+===============
+*/
+void R_LightPoint (vec3_t p, vec3_t color)
+{
+	vec3_t		end;
+	float		r;
+	int			lnum;
+	dlight_t	*dl;
+	vec3_t		dist;
+	float		add;
+	
+	if (!r_worldmodel->lightdata)
+	{
+		color[0] = color[1] = color[2] = 1.0;
+		return;
+	}
+	
+	end[0] = p[0];
+	end[1] = p[1];
+	end[2] = p[2] - 2048;
+	
+	r = RecursiveLightPoint (r_worldmodel->nodes, p, end);
+	
+	if (r == -1)
+	{
+		VectorCopy (vec3_origin, color);
+	}
+	else
+	{
+		VectorCopy (pointcolor, color);
+	}
+
+	//
+	// add dynamic lights
+	//
+	for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
+	{
+		dl = &r_newrefdef.dlights[lnum];
+		VectorSubtract (currententity->origin,
+						dl->origin,
+						dist);
+		add = dl->intensity - VectorLength(dist);
+		add *= (1.0/256);
+		if (add > 0)
+		{
+			VectorMA (color, add, dl->color, color);
+		}
+	}
+}
+
+//===================================================================
+
+
+unsigned		blocklights[1024];	// allow some very large lightmaps
+
+/*
+===============
+R_AddDynamicLights
+===============
+*/
+void R_AddDynamicLights (void)
+{
+	msurface_t *surf;
+	int			lnum;
+	int			sd, td;
+	float		dist, rad, minlight;
+	vec3_t		impact, local;
+	int			s, t;
+	int			i;
+	int			smax, tmax;
+	mtexinfo_t	*tex;
+	dlight_t	*dl;
+	int			negativeLight;	//PGM
+
+	surf = r_drawsurf.surf;
+	smax = (surf->extents[0]>>4)+1;
+	tmax = (surf->extents[1]>>4)+1;
+	tex = surf->texinfo;
+
+	for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
+	{
+		if ( !(surf->dlightbits & (1<<lnum) ) )
+			continue;		// not lit by this light
+
+		dl = &r_newrefdef.dlights[lnum];
+		rad = dl->intensity;
+
+//=====
+//PGM
+		negativeLight = 0;
+		if(rad < 0)
+		{
+			negativeLight = 1;
+			rad = -rad;
+		}
+//PGM
+//=====
+
+		dist = DotProduct (dl->origin, surf->plane->normal) -
+				surf->plane->dist;
+		rad -= fabs(dist);
+		minlight = 32;		// dl->minlight;
+		if (rad < minlight)
+			continue;
+		minlight = rad - minlight;
+
+		for (i=0 ; i<3 ; i++)
+		{
+			impact[i] = dl->origin[i] -
+					surf->plane->normal[i]*dist;
+		}
+
+		local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
+		local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
+
+		local[0] -= surf->texturemins[0];
+		local[1] -= surf->texturemins[1];
+		
+		for (t = 0 ; t<tmax ; t++)
+		{
+			td = local[1] - t*16;
+			if (td < 0)
+				td = -td;
+			for (s=0 ; s<smax ; s++)
+			{
+				sd = local[0] - s*16;
+				if (sd < 0)
+					sd = -sd;
+				if (sd > td)
+					dist = sd + (td>>1);
+				else
+					dist = td + (sd>>1);
+//====
+//PGM
+				if(!negativeLight)
+				{
+					if (dist < minlight)
+						blocklights[t*smax + s] += (rad - dist)*256;
+				}
+				else
+				{
+					if (dist < minlight)
+						blocklights[t*smax + s] -= (rad - dist)*256;
+					if(blocklights[t*smax + s] < minlight)
+						blocklights[t*smax + s] = minlight;
+				}
+//PGM
+//====
+			}
+		}
+	}
+}
+
+/*
+===============
+R_BuildLightMap
+
+Combine and scale multiple lightmaps into the 8.8 format in blocklights
+===============
+*/
+void R_BuildLightMap (void)
+{
+	int			smax, tmax;
+	int			t;
+	int			i, size;
+	byte		*lightmap;
+	unsigned	scale;
+	int			maps;
+	msurface_t	*surf;
+
+	surf = r_drawsurf.surf;
+
+	smax = (surf->extents[0]>>4)+1;
+	tmax = (surf->extents[1]>>4)+1;
+	size = smax*tmax;
+
+	if (r_fullbright->value || !r_worldmodel->lightdata)
+	{
+		for (i=0 ; i<size ; i++)
+			blocklights[i] = 0;
+		return;
+	}
+
+// clear to no light
+	for (i=0 ; i<size ; i++)
+		blocklights[i] = 0;
+
+
+// add all the lightmaps
+	lightmap = surf->samples;
+	if (lightmap)
+		for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
+			 maps++)
+		{
+			scale = r_drawsurf.lightadj[maps];	// 8.8 fraction		
+			for (i=0 ; i<size ; i++)
+				blocklights[i] += lightmap[i] * scale;
+			lightmap += size;	// skip to next lightmap
+		}
+
+// add all the dynamic lights
+	if (surf->dlightframe == r_framecount)
+		R_AddDynamicLights ();
+
+// bound, invert, and shift
+	for (i=0 ; i<size ; i++)
+	{
+		t = (int)blocklights[i];
+		if (t < 0)
+			t = 0;
+		t = (255*256 - t) >> (8 - VID_CBITS);
+
+		if (t < (1 << 6))
+			t = (1 << 6);
+
+		blocklights[i] = t;
+	}
+}
+
--- /dev/null
+++ b/r_main.c
@@ -1,0 +1,1350 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+viddef_t	vid;
+refimport_t	ri;
+
+unsigned	d_8to24table[256];
+
+entity_t	r_worldentity;
+
+char		skyname[MAX_QPATH];
+float		skyrotate;
+vec3_t		skyaxis;
+image_t		*sky_images[6];
+
+refdef_t	r_newrefdef;
+model_t		*currentmodel;
+
+model_t		*r_worldmodel;
+
+byte		r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
+
+swstate_t sw_state;
+
+void		*colormap;
+vec3_t		viewlightvec;
+alight_t	r_viewlighting = {128, 192, viewlightvec};
+float		r_time1;
+int			r_numallocatededges;
+float		r_aliasuvscale = 1.0;
+int			r_outofsurfaces;
+int			r_outofedges;
+
+qboolean	r_dowarp;
+
+mvertex_t	*r_pcurrentvertbase;
+
+int			c_surf;
+int			r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
+qboolean	r_surfsonstack;
+int			r_clipflags;
+
+//
+// view origin
+//
+vec3_t	vup, base_vup;
+vec3_t	vpn, base_vpn;
+vec3_t	vright, base_vright;
+vec3_t	r_origin;
+
+//
+// screen size info
+//
+oldrefdef_t	r_refdef;
+float		xcenter, ycenter;
+float		xscale, yscale;
+float		xscaleinv, yscaleinv;
+float		xscaleshrink, yscaleshrink;
+float		aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
+
+int		r_screenwidth;
+
+float	verticalFieldOfView;
+float	xOrigin, yOrigin;
+
+mplane_t	screenedge[4];
+
+//
+// refresh flags
+//
+int		r_framecount = 1;	// so frame counts initialized to 0 don't match
+int		r_visframecount;
+int		d_spanpixcount;
+int		r_polycount;
+int		r_drawnpolycount;
+int		r_wholepolycount;
+
+int			*pfrustum_indexes[4];
+int			r_frustum_indexes[4*6];
+
+mleaf_t		*r_viewleaf;
+int			r_viewcluster, r_oldviewcluster;
+
+image_t  	*r_notexture_mip;
+
+float	da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
+float	se_time1, se_time2, de_time1, de_time2;
+
+void R_MarkLeaves (void);
+
+cvar_t	*r_lefthand;
+cvar_t	*sw_aliasstats;
+cvar_t	*sw_allow_modex;
+cvar_t	*sw_clearcolor;
+cvar_t	*sw_drawflat;
+cvar_t	*sw_draworder;
+cvar_t	*sw_maxedges;
+cvar_t	*sw_maxsurfs;
+cvar_t  *sw_mode;
+cvar_t	*sw_reportedgeout;
+cvar_t	*sw_reportsurfout;
+cvar_t  *sw_stipplealpha;
+cvar_t	*sw_surfcacheoverride;
+cvar_t	*sw_waterwarp;
+
+cvar_t	*r_drawworld;
+cvar_t	*r_drawentities;
+cvar_t	*r_dspeeds;
+cvar_t	*r_fullbright;
+cvar_t  *r_lerpmodels;
+cvar_t  *r_novis;
+
+cvar_t	*r_speeds;
+cvar_t	*r_lightlevel;	//FIXME HACK
+
+cvar_t	*vid_fullscreen;
+cvar_t	*vid_gamma;
+
+//PGM
+cvar_t	*sw_lockpvs;
+//PGM
+
+#define	STRINGER(x) "x"
+
+
+// r_vars.c
+
+// all global and static refresh variables are collected in a contiguous block
+// to avoid cache conflicts.
+
+//-------------------------------------------------------
+// global refresh variables
+//-------------------------------------------------------
+
+// FIXME: make into one big structure, like cl or sv
+// FIXME: do separately for refresh engine and driver
+
+
+// d_vars.c
+
+// all global and static refresh variables are collected in a contiguous block
+// to avoid cache conflicts.
+
+//-------------------------------------------------------
+// global refresh variables
+//-------------------------------------------------------
+
+// FIXME: make into one big structure, like cl or sv
+// FIXME: do separately for refresh engine and driver
+
+float	d_sdivzstepu, d_tdivzstepu, d_zistepu;
+float	d_sdivzstepv, d_tdivzstepv, d_zistepv;
+float	d_sdivzorigin, d_tdivzorigin, d_ziorigin;
+
+fixed16_t	sadjust, tadjust, bbextents, bbextentt;
+
+pixel_t			*cacheblock;
+int				cachewidth;
+pixel_t			*d_viewbuffer;
+short			*d_pzbuffer;
+unsigned int	d_zrowbytes;
+unsigned int	d_zwidth;
+
+
+byte	r_notexture_buffer[1024];
+
+/*
+==================
+R_InitTextures
+==================
+*/
+void	R_InitTextures (void)
+{
+	int		x,y, m;
+	byte	*dest;
+	
+// create a simple checkerboard texture for the default
+	r_notexture_mip = (image_t *)r_notexture_buffer;
+	
+	r_notexture_mip->width = r_notexture_mip->height = 16;
+	r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)];
+	r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16;
+	r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8;
+	r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4;
+	
+	for (m=0 ; m<4 ; m++)
+	{
+		dest = r_notexture_mip->pixels[m];
+		for (y=0 ; y< (16>>m) ; y++)
+			for (x=0 ; x< (16>>m) ; x++)
+			{
+				if (  (y< (8>>m) ) ^ (x< (8>>m) ) )
+
+					*dest++ = 0;
+				else
+					*dest++ = 0xff;
+			}
+	}	
+}
+
+
+/*
+================
+R_InitTurb
+================
+*/
+void R_InitTurb (void)
+{
+	int		i;
+	
+	for (i=0 ; i<1280 ; i++)
+	{
+		sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
+		intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2;	// AMP2, not 20
+		blanktable[i] = 0;			//PGM
+	}
+}
+
+void R_ImageList_f( void );
+
+void R_Register (void)
+{
+	sw_aliasstats = Cvar_Get("sw_polymodelstats", "0", 0);
+	sw_allow_modex = Cvar_Get("sw_allow_modex", "1", CVAR_ARCHIVE);
+	sw_clearcolor = Cvar_Get("sw_clearcolor", "2", 0);
+	sw_drawflat = Cvar_Get("sw_drawflat", "0", 0);
+	sw_draworder = Cvar_Get("sw_draworder", "0", 0);
+	sw_maxedges = Cvar_Get("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0);
+	sw_maxsurfs = Cvar_Get("sw_maxsurfs", "0", 0);
+	sw_mipcap = Cvar_Get("sw_mipcap", "0", 0);
+	sw_mipscale = Cvar_Get("sw_mipscale", "1", 0);
+	sw_reportedgeout = Cvar_Get("sw_reportedgeout", "0", 0);
+	sw_reportsurfout = Cvar_Get("sw_reportsurfout", "0", 0);
+	sw_stipplealpha = Cvar_Get("sw_stipplealpha", "0", CVAR_ARCHIVE);
+	sw_surfcacheoverride = Cvar_Get("sw_surfcacheoverride", "0", 0);
+	sw_waterwarp = Cvar_Get ("sw_waterwarp", "1", 0);
+	sw_mode = Cvar_Get("sw_mode", "0", CVAR_ARCHIVE);
+
+	r_lefthand = Cvar_Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
+	r_speeds = Cvar_Get("r_speeds", "0", 0);
+	r_fullbright = Cvar_Get("r_fullbright", "0", 0);
+	r_drawentities = Cvar_Get("r_drawentities", "1", 0);
+	r_drawworld = Cvar_Get("r_drawworld", "1", 0);
+	r_dspeeds = Cvar_Get("r_dspeeds", "0", 0);
+	r_lightlevel = Cvar_Get("r_lightlevel", "0", 0);
+	r_lerpmodels = Cvar_Get("r_lerpmodels", "1", 0);
+	r_novis = Cvar_Get("r_novis", "0", 0);
+
+	vid_fullscreen = Cvar_Get("vid_fullscreen", "0", CVAR_ARCHIVE);
+	vid_gamma = Cvar_Get("vid_gamma", "1", CVAR_ARCHIVE);
+
+	Cmd_AddCommand("modellist", Mod_Modellist_f);
+	Cmd_AddCommand("screenshot", R_ScreenShot_f);
+	Cmd_AddCommand("imagelist", R_ImageList_f);
+
+	sw_mode->modified = true; // force us to do mode specific stuff later
+	vid_gamma->modified = true; // force us to rebuild the gamma table later
+
+//PGM
+	sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0);
+//PGM
+}
+
+void
+R_UnRegister(void)
+{
+	Cmd_RemoveCommand("screenshot");
+	Cmd_RemoveCommand("modellist");
+	Cmd_RemoveCommand("imagelist");
+}
+
+/*
+===============
+R_Init
+===============
+*/
+qboolean R_Init( void *hInstance, void *wndProc )
+{
+	R_InitImages ();
+	Mod_Init ();
+	Draw_InitLocal ();
+	R_InitTextures ();
+
+	R_InitTurb ();
+
+	view_clipplanes[0].leftedge = true;
+	view_clipplanes[1].rightedge = true;
+	view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
+			view_clipplanes[3].leftedge = false;
+	view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
+			view_clipplanes[3].rightedge = false;
+
+	r_refdef.xOrigin = XCENTERING;
+	r_refdef.yOrigin = YCENTERING;
+
+	r_aliasuvscale = 1.0;
+
+	R_Register ();
+	Draw_GetPalette ();
+	SWimp_Init( hInstance, wndProc );
+
+	// create the window
+	R_BeginFrame( 0 );
+
+	ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n");
+
+	return true;
+}
+
+void
+R_Shutdown(void)
+{
+	if(d_pzbuffer){
+		free(d_pzbuffer);
+		d_pzbuffer = nil;
+	}
+	if(sc_base){
+		D_FlushCaches();
+		free(sc_base);
+		sc_base = nil;
+	}
+	if(vid.colormap){
+		free(vid.colormap);
+		vid.colormap = nil;
+	}
+	R_UnRegister();
+	Mod_FreeAll();
+	R_ShutdownImages();
+
+	SWimp_Shutdown();
+}
+
+/*
+===============
+R_NewMap
+===============
+*/
+void R_NewMap (void)
+{
+	r_viewcluster = -1;
+
+	r_cnumsurfs = sw_maxsurfs->value;
+
+	if (r_cnumsurfs <= MINSURFACES)
+		r_cnumsurfs = MINSURFACES;
+
+	if (r_cnumsurfs > NUMSTACKSURFACES)
+	{
+		surfaces = malloc (r_cnumsurfs * sizeof(surf_t));
+		surface_p = surfaces;
+		surf_max = &surfaces[r_cnumsurfs];
+		r_surfsonstack = false;
+	// surface 0 doesn't really exist; it's just a dummy because index 0
+	// is used to indicate no edge attached to surface
+		surfaces--;
+		R_SurfacePatch ();
+	}
+	else
+	{
+		r_surfsonstack = true;
+	}
+
+	r_maxedgesseen = 0;
+	r_maxsurfsseen = 0;
+
+	r_numallocatededges = sw_maxedges->value;
+
+	if (r_numallocatededges < MINEDGES)
+		r_numallocatededges = MINEDGES;
+
+	if (r_numallocatededges <= NUMSTACKEDGES)
+	{
+		auxedges = NULL;
+	}
+	else
+	{
+		auxedges = malloc (r_numallocatededges * sizeof(edge_t));
+	}
+}
+
+
+/*
+===============
+R_MarkLeaves
+
+Mark the leaves and nodes that are in the PVS for the current
+cluster
+===============
+*/
+void R_MarkLeaves (void)
+{
+	byte	*vis;
+	mnode_t	*node;
+	int		i;
+	mleaf_t	*leaf;
+	int		cluster;
+
+	if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)
+		return;
+	
+	// development aid to let you run around and see exactly where
+	// the pvs ends
+	if (sw_lockpvs->value)
+		return;
+
+	r_visframecount++;
+	r_oldviewcluster = r_viewcluster;
+
+	if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)
+	{
+		// mark everything
+		for (i=0 ; i<r_worldmodel->numleafs ; i++)
+			r_worldmodel->leafs[i].visframe = r_visframecount;
+		for (i=0 ; i<r_worldmodel->numnodes ; i++)
+			r_worldmodel->nodes[i].visframe = r_visframecount;
+		return;
+	}
+
+	vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);
+	
+	for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)
+	{
+		cluster = leaf->cluster;
+		if (cluster == -1)
+			continue;
+		if (vis[cluster>>3] & (1<<(cluster&7)))
+		{
+			node = (mnode_t *)leaf;
+			do
+			{
+				if (node->visframe == r_visframecount)
+					break;
+				node->visframe = r_visframecount;
+				node = node->parent;
+			} while (node);
+		}
+	}
+
+/*
+	for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)
+	{
+		if (vis[i>>3] & (1<<(i&7)))
+		{
+			node = (mnode_t *)&r_worldmodel->leafs[i];	// FIXME: cluster
+			do
+			{
+				if (node->visframe == r_visframecount)
+					break;
+				node->visframe = r_visframecount;
+				node = node->parent;
+			} while (node);
+		}
+	}
+*/
+}
+
+/*
+** R_DrawNullModel
+**
+** IMPLEMENT THIS!
+*/
+void R_DrawNullModel( void )
+{
+}
+
+/*
+=============
+R_DrawEntitiesOnList
+=============
+*/
+void R_DrawEntitiesOnList (void)
+{
+	int			i;
+	qboolean	translucent_entities = false;
+
+	if (!r_drawentities->value)
+		return;
+
+	// all bmodels have already been drawn by the edge list
+	for (i=0 ; i<r_newrefdef.num_entities ; i++)
+	{
+		currententity = &r_newrefdef.entities[i];
+
+		if ( currententity->flags & RF_TRANSLUCENT )
+		{
+			translucent_entities = true;
+			continue;
+		}
+
+		if ( currententity->flags & RF_BEAM )
+		{
+			modelorg[0] = -r_origin[0];
+			modelorg[1] = -r_origin[1];
+			modelorg[2] = -r_origin[2];
+			VectorCopy( vec3_origin, r_entorigin );
+			R_DrawBeam( currententity );
+		}
+		else
+		{
+			currentmodel = currententity->model;
+			if (!currentmodel)
+			{
+				R_DrawNullModel();
+				continue;
+			}
+			VectorCopy (currententity->origin, r_entorigin);
+			VectorSubtract (r_origin, r_entorigin, modelorg);
+
+			switch (currentmodel->type)
+			{
+			case mod_sprite:
+				R_DrawSprite ();
+				break;
+
+			case mod_alias:
+				R_AliasDrawModel ();
+				break;
+
+			default:
+				break;
+			}
+		}
+	}
+
+	if ( !translucent_entities )
+		return;
+
+	for (i=0 ; i<r_newrefdef.num_entities ; i++)
+	{
+		currententity = &r_newrefdef.entities[i];
+
+		if ( !( currententity->flags & RF_TRANSLUCENT ) )
+			continue;
+
+		if ( currententity->flags & RF_BEAM )
+		{
+			modelorg[0] = -r_origin[0];
+			modelorg[1] = -r_origin[1];
+			modelorg[2] = -r_origin[2];
+			VectorCopy( vec3_origin, r_entorigin );
+			R_DrawBeam( currententity );
+		}
+		else
+		{
+			currentmodel = currententity->model;
+			if (!currentmodel)
+			{
+				R_DrawNullModel();
+				continue;
+			}
+			VectorCopy (currententity->origin, r_entorigin);
+			VectorSubtract (r_origin, r_entorigin, modelorg);
+
+			switch (currentmodel->type)
+			{
+			case mod_sprite:
+				R_DrawSprite ();
+				break;
+
+			case mod_alias:
+				R_AliasDrawModel ();
+				break;
+
+			default:
+				break;
+			}
+		}
+	}
+}
+
+
+/*
+=============
+R_BmodelCheckBBox
+=============
+*/
+int R_BmodelCheckBBox (float *minmaxs)
+{
+	int			i, *pindex, clipflags;
+	vec3_t		acceptpt, rejectpt;
+	float		d;
+
+	clipflags = 0;
+
+	for (i=0 ; i<4 ; i++)
+	{
+	// generate accept and reject points
+	// FIXME: do with fast look-ups or integer tests based on the sign bit
+	// of the floating point values
+
+		pindex = pfrustum_indexes[i];
+
+		rejectpt[0] = minmaxs[pindex[0]];
+		rejectpt[1] = minmaxs[pindex[1]];
+		rejectpt[2] = minmaxs[pindex[2]];
+		
+		d = DotProduct (rejectpt, view_clipplanes[i].normal);
+		d -= view_clipplanes[i].dist;
+
+		if (d <= 0)
+			return BMODEL_FULLY_CLIPPED;
+
+		acceptpt[0] = minmaxs[pindex[3+0]];
+		acceptpt[1] = minmaxs[pindex[3+1]];
+		acceptpt[2] = minmaxs[pindex[3+2]];
+
+		d = DotProduct (acceptpt, view_clipplanes[i].normal);
+		d -= view_clipplanes[i].dist;
+
+		if (d <= 0)
+			clipflags |= (1<<i);
+	}
+
+	return clipflags;
+}
+
+
+/*
+===================
+R_FindTopnode
+
+Find the first node that splits the given box
+===================
+*/
+mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
+{
+	mplane_t	*splitplane;
+	int			sides;
+	mnode_t *node;
+
+	node = r_worldmodel->nodes;
+
+	while (1)
+	{
+		if (node->visframe != r_visframecount)
+			return NULL;		// not visible at all
+		
+		if (node->contents != CONTENTS_NODE)
+		{
+			if (node->contents != CONTENTS_SOLID)
+				return	node; // we've reached a non-solid leaf, so it's
+							//  visible and not BSP clipped
+			return NULL;	// in solid, so not visible
+		}
+		
+		splitplane = node->plane;
+		sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane);
+		
+		if (sides == 3)
+			return node;	// this is the splitter
+		
+	// not split yet; recurse down the contacted side
+		if (sides & 1)
+			node = node->children[0];
+		else
+			node = node->children[1];
+	}
+}
+
+
+/*
+=============
+RotatedBBox
+
+Returns an axially aligned box that contains the input box at the given rotation
+=============
+*/
+void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs)
+{
+	vec3_t	tmp, v;
+	int		i, j;
+	vec3_t	forward, right, up;
+
+	if (!angles[0] && !angles[1] && !angles[2])
+	{
+		VectorCopy (mins, tmins);
+		VectorCopy (maxs, tmaxs);
+		return;
+	}
+
+	for (i=0 ; i<3 ; i++)
+	{
+		tmins[i] = 99999;
+		tmaxs[i] = -99999;
+	}
+
+	AngleVectors (angles, forward, right, up);
+
+	for ( i = 0; i < 8; i++ )
+	{
+		if ( i & 1 )
+			tmp[0] = mins[0];
+		else
+			tmp[0] = maxs[0];
+
+		if ( i & 2 )
+			tmp[1] = mins[1];
+		else
+			tmp[1] = maxs[1];
+
+		if ( i & 4 )
+			tmp[2] = mins[2];
+		else
+			tmp[2] = maxs[2];
+
+
+		VectorScale (forward, tmp[0], v);
+		VectorMA (v, -tmp[1], right, v);
+		VectorMA (v, tmp[2], up, v);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			if (v[j] < tmins[j])
+				tmins[j] = v[j];
+			if (v[j] > tmaxs[j])
+				tmaxs[j] = v[j];
+		}
+	}
+}
+
+/*
+=============
+R_DrawBEntitiesOnList
+=============
+*/
+void R_DrawBEntitiesOnList (void)
+{
+	int			i, clipflags;
+	vec3_t		oldorigin;
+	vec3_t		mins, maxs;
+	float		minmaxs[6];
+	mnode_t		*topnode;
+
+	if (!r_drawentities->value)
+		return;
+
+	VectorCopy (modelorg, oldorigin);
+	insubmodel = true;
+	r_dlightframecount = r_framecount;
+
+	for (i=0 ; i<r_newrefdef.num_entities ; i++)
+	{
+		currententity = &r_newrefdef.entities[i];
+		currentmodel = currententity->model;
+		if (!currentmodel)
+			continue;
+		if (currentmodel->nummodelsurfaces == 0)
+			continue;	// clip brush only
+		if ( currententity->flags & RF_BEAM )
+			continue;
+		if (currentmodel->type != mod_brush)
+			continue;
+	// see if the bounding box lets us trivially reject, also sets
+	// trivial accept status
+		RotatedBBox (currentmodel->mins, currentmodel->maxs,
+			currententity->angles, mins, maxs);
+		VectorAdd (mins, currententity->origin, minmaxs);
+		VectorAdd (maxs, currententity->origin, (minmaxs+3));
+
+		clipflags = R_BmodelCheckBBox (minmaxs);
+		if (clipflags == BMODEL_FULLY_CLIPPED)
+			continue;	// off the edge of the screen
+
+		topnode = R_FindTopnode (minmaxs, minmaxs+3);
+		if (!topnode)
+			continue;	// no part in a visible leaf
+
+		VectorCopy (currententity->origin, r_entorigin);
+		VectorSubtract (r_origin, r_entorigin, modelorg);
+
+		r_pcurrentvertbase = currentmodel->vertexes;
+
+	// FIXME: stop transforming twice
+		R_RotateBmodel ();
+
+	// calculate dynamic lighting for bmodel
+		R_PushDlights (currentmodel);
+
+		if (topnode->contents == CONTENTS_NODE)
+		{
+		// not a leaf; has to be clipped to the world BSP
+			r_clipflags = clipflags;
+			R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode);
+		}
+		else
+		{
+		// falls entirely in one leaf, so we just put all the
+		// edges in the edge list and let 1/z sorting handle
+		// drawing order
+			R_DrawSubmodelPolygons (currentmodel, clipflags, topnode);
+		}
+
+	// put back world rotation and frustum clipping		
+	// FIXME: R_RotateBmodel should just work off base_vxx
+		VectorCopy (base_vpn, vpn);
+		VectorCopy (base_vup, vup);
+		VectorCopy (base_vright, vright);
+		VectorCopy (oldorigin, modelorg);
+		R_TransformFrustum ();
+	}
+
+	insubmodel = false;
+}
+
+
+/*
+================
+R_EdgeDrawing
+================
+*/
+void R_EdgeDrawing (void)
+{
+	edge_t	ledges[NUMSTACKEDGES +
+				((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
+	surf_t	lsurfs[NUMSTACKSURFACES +
+				((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
+
+	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
+		return;
+
+	if (auxedges)
+	{
+		r_edges = auxedges;
+	}
+	else
+	{
+		r_edges =  (edge_t *)
+				(((uintptr)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+	}
+
+	if (r_surfsonstack)
+	{
+		surfaces =  (surf_t *)
+				(((uintptr)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+		surf_max = &surfaces[r_cnumsurfs];
+	// surface 0 doesn't really exist; it's just a dummy because index 0
+	// is used to indicate no edge attached to surface
+		surfaces--;
+		R_SurfacePatch ();
+	}
+
+	R_BeginEdgeFrame ();
+
+	if (r_dspeeds->value)
+	{
+		rw_time1 = Sys_Milliseconds ();
+	}
+
+	R_RenderWorld ();
+
+	if (r_dspeeds->value)
+	{
+		rw_time2 = Sys_Milliseconds ();
+		db_time1 = rw_time2;
+	}
+
+	R_DrawBEntitiesOnList ();
+
+	if (r_dspeeds->value)
+	{
+		db_time2 = Sys_Milliseconds ();
+		se_time1 = db_time2;
+	}
+
+	R_ScanEdges ();
+}
+
+//=======================================================================
+
+
+/*
+=============
+R_CalcPalette
+
+=============
+*/
+void R_CalcPalette (void)
+{
+	static qboolean modified;
+	byte	palette[256][4], *in, *out;
+	int		i, j;
+	float	alpha, one_minus_alpha;
+	vec3_t	premult;
+	int		v;
+
+	alpha = r_newrefdef.blend[3];
+	if (alpha <= 0)
+	{
+		if (modified)
+		{	// set back to default
+			modified = false;
+			R_GammaCorrectAndSetPalette((uchar *)d_8to24table);
+			return;
+		}
+		return;
+	}
+
+	modified = true;
+	if (alpha > 1)
+		alpha = 1;
+
+	premult[0] = r_newrefdef.blend[0]*alpha*255;
+	premult[1] = r_newrefdef.blend[1]*alpha*255;
+	premult[2] = r_newrefdef.blend[2]*alpha*255;
+
+	one_minus_alpha = (1.0 - alpha);
+
+	in = (byte *)d_8to24table;
+	out = palette[0];
+	for (i=0 ; i<256 ; i++, in+=4, out+=4)
+	{
+		for (j=0 ; j<3 ; j++)
+		{
+			v = premult[j] + one_minus_alpha * in[j];
+			if (v > 255)
+				v = 255;
+			out[j] = v;
+		}
+		out[3] = 255;
+	}
+
+	R_GammaCorrectAndSetPalette((uchar *)palette[0]);
+//	SWimp_SetPalette( palette[0] );
+}
+
+//=======================================================================
+
+void R_SetLightLevel (void)
+{
+	vec3_t		light;
+
+	if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity))
+	{
+		r_lightlevel->value = 150.0;
+		return;
+	}
+
+	// save off light value for server to look at (BIG HACK!)
+	R_LightPoint (r_newrefdef.vieworg, light);
+	r_lightlevel->value = 150.0 * light[0];
+}
+
+
+/*
+@@@@@@@@@@@@@@@@
+R_RenderFrame
+
+@@@@@@@@@@@@@@@@
+*/
+void R_RenderFrame (refdef_t *fd)
+{
+	r_newrefdef = *fd;
+
+	if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
+		ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel");
+
+	VectorCopy (fd->vieworg, r_refdef.vieworg);
+	VectorCopy (fd->viewangles, r_refdef.viewangles);
+
+	if (r_speeds->value || r_dspeeds->value)
+		r_time1 = Sys_Milliseconds ();
+
+	R_SetupFrame ();
+
+	R_MarkLeaves ();	// done here so we know if we're in water
+
+	R_PushDlights (r_worldmodel);
+
+	R_EdgeDrawing ();
+
+	if (r_dspeeds->value)
+	{
+		se_time2 = Sys_Milliseconds ();
+		de_time1 = se_time2;
+	}
+
+	R_DrawEntitiesOnList ();
+
+	if (r_dspeeds->value)
+	{
+		de_time2 = Sys_Milliseconds ();
+		dp_time1 = Sys_Milliseconds ();
+	}
+
+	R_DrawParticles ();
+
+	if (r_dspeeds->value)
+		dp_time2 = Sys_Milliseconds ();
+
+	R_DrawAlphaSurfaces();
+
+	R_SetLightLevel ();
+
+	if (r_dowarp)
+		D_WarpScreen ();
+
+	if (r_dspeeds->value)
+		da_time1 = Sys_Milliseconds ();
+
+	if (r_dspeeds->value)
+		da_time2 = Sys_Milliseconds ();
+
+	R_CalcPalette ();
+
+	if (sw_aliasstats->value)
+		R_PrintAliasStats ();
+		
+	if (r_speeds->value)
+		R_PrintTimes ();
+
+	if (r_dspeeds->value)
+		R_PrintDSpeeds ();
+
+	if (sw_reportsurfout->value && r_outofsurfaces)
+		ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces);
+
+	if (sw_reportedgeout->value && r_outofedges)
+		ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3);
+}
+
+/*
+** R_InitGraphics
+*/
+void R_InitGraphics( int width, int height )
+{
+	vid.width  = width;
+	vid.height = height;
+
+	// free z buffer
+	if ( d_pzbuffer )
+	{
+		free( d_pzbuffer );
+		d_pzbuffer = NULL;
+	}
+
+	// free surface cache
+	if ( sc_base )
+	{
+		D_FlushCaches ();
+		free( sc_base );
+		sc_base = NULL;
+	}
+
+	d_pzbuffer = malloc(vid.width*vid.height*2);
+
+	R_InitCaches ();
+
+	R_GammaCorrectAndSetPalette((uchar *)d_8to24table);
+}
+
+/*
+** R_BeginFrame
+*/
+void R_BeginFrame( float /*camera_separation*/ )
+{
+	extern void Draw_BuildGammaTable( void );
+
+	/*
+	** rebuild the gamma correction palette if necessary
+	*/
+	if ( vid_gamma->modified )
+	{
+		Draw_BuildGammaTable();
+		R_GammaCorrectAndSetPalette((uchar *)d_8to24table);
+
+		vid_gamma->modified = false;
+	}
+
+	while ( sw_mode->modified || vid_fullscreen->modified )
+	{
+		rserr_t err;
+
+		/*
+		** if this returns rserr_invalid_fullscreen then it set the mode but not as a
+		** fullscreen mode, e.g. 320x200 on a system that doesn't support that res
+		*/
+		if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok )
+		{
+			R_InitGraphics( vid.width, vid.height );
+
+			sw_state.prev_mode = sw_mode->value;
+			vid_fullscreen->modified = false;
+			sw_mode->modified = false;
+		}
+		else
+		{
+			if ( err == rserr_invalid_mode )
+			{
+				ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode );
+				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" );
+			}
+			else if ( err == rserr_invalid_fullscreen )
+			{
+				R_InitGraphics( vid.width, vid.height );
+
+				ri.Cvar_SetValue( "vid_fullscreen", 0);
+				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" );
+				sw_state.prev_mode = sw_mode->value;
+//				vid_fullscreen->modified = false;
+//				sw_mode->modified = false;
+			}
+			else
+			{
+				ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" );
+			}
+		}
+	}
+}
+
+void
+R_GammaCorrectAndSetPalette(uchar *palette)
+{
+	int i;
+
+	for ( i = 0; i < 256; i++ )
+	{
+		sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]];
+		sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]];
+		sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]];
+	}
+
+	SWimp_SetPalette( sw_state.currentpalette );
+}
+
+void
+R_CinematicSetPalette(uchar *palette)
+{
+	byte palette32[1024];
+	int		i, j, w;
+	int		*d;
+
+	// clear screen to black to avoid any palette flash
+	w = abs(vid.rowbytes)>>2;	// stupid negative pitch win32 stuff...
+	for (i=0 ; i<vid.height ; i++)
+	{
+		d = (int *)(vid.buffer + i*vid.rowbytes);
+		for (j=0 ; j<w ; j++)
+			d[j] = 0;
+	}
+	// flush it to the screen
+	SWimp_EndFrame ();
+
+	if ( palette )
+	{
+		for ( i = 0; i < 256; i++ )
+		{
+			palette32[i*4+0] = palette[i*3+0];
+			palette32[i*4+1] = palette[i*3+1];
+			palette32[i*4+2] = palette[i*3+2];
+			palette32[i*4+3] = 0xFF;
+		}
+
+		R_GammaCorrectAndSetPalette( palette32 );
+	}
+	else
+	{
+		R_GammaCorrectAndSetPalette((uchar *)d_8to24table);
+	}
+}
+
+/*
+================
+Draw_BuildGammaTable
+================
+*/
+void Draw_BuildGammaTable (void)
+{
+	int		i, inf;
+	float	g;
+
+	g = vid_gamma->value;
+
+	if (g == 1.0)
+	{
+		for (i=0 ; i<256 ; i++)
+			sw_state.gammatable[i] = i;
+		return;
+	}
+	
+	for (i=0 ; i<256 ; i++)
+	{
+		inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
+		if (inf < 0)
+			inf = 0;
+		if (inf > 255)
+			inf = 255;
+		sw_state.gammatable[i] = inf;
+	}
+}
+
+/*
+** R_DrawBeam
+*/
+void R_DrawBeam( entity_t *e )
+{
+#define NUM_BEAM_SEGS 6
+
+	int	i;
+
+	vec3_t perpvec;
+	vec3_t direction, normalized_direction;
+	vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
+	vec3_t oldorigin, origin;
+
+	oldorigin[0] = e->oldorigin[0];
+	oldorigin[1] = e->oldorigin[1];
+	oldorigin[2] = e->oldorigin[2];
+
+	origin[0] = e->origin[0];
+	origin[1] = e->origin[1];
+	origin[2] = e->origin[2];
+
+	normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
+	normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
+	normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
+
+	if ( VectorNormalize( normalized_direction ) == 0 )
+		return;
+
+	PerpendicularVector( perpvec, normalized_direction );
+	VectorScale( perpvec, e->frame / 2, perpvec );
+
+	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
+	{
+		RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
+		VectorAdd( start_points[i], origin, start_points[i] );
+		VectorAdd( start_points[i], direction, end_points[i] );
+	}
+
+	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
+	{
+		R_IMFlatShadedQuad( start_points[i],
+		                    end_points[i],
+							end_points[(i+1)%NUM_BEAM_SEGS],
+							start_points[(i+1)%NUM_BEAM_SEGS],
+							e->skinnum & 0xFF,
+							e->alpha );
+	}
+}
+
+
+//===================================================================
+
+/*
+============
+R_SetSky
+============
+*/
+// 3dstudio environment map names
+char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+int	r_skysideimage[6] = {5, 2, 4, 1, 0, 3};
+extern	mtexinfo_t		r_skytexinfo[6];
+void R_SetSky (char *name, float rotate, vec3_t axis)
+{
+	int		i;
+	char	pathname[MAX_QPATH];
+
+	strncpy (skyname, name, sizeof(skyname)-1);
+	skyrotate = rotate;
+	VectorCopy (axis, skyaxis);
+
+	for (i=0 ; i<6 ; i++)
+	{
+		Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]);
+		r_skytexinfo[i].image = R_FindImage (pathname, it_sky);
+	}
+}
+
+
+/*
+===============
+Draw_GetPalette
+===============
+*/
+void Draw_GetPalette (void)
+{
+	byte	*pal, *out;
+	int		i;
+	int		r, g, b;
+
+	// get the palette and colormap
+	LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL);
+	if (!vid.colormap)
+		ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
+	vid.alphamap = vid.colormap + 64*256;
+
+	out = (byte *)d_8to24table;
+	for (i=0 ; i<256 ; i++, out+=4)
+	{
+		r = pal[i*3+0];
+		g = pal[i*3+1];
+		b = pal[i*3+2];
+
+        out[0] = r;
+        out[1] = g;
+        out[2] = b;
+	}
+
+	free (pal);
+}
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+GetRefAPI
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+refexport_t GetRefAPI (refimport_t rimp)
+{
+	refexport_t	re;
+
+	ri = rimp;
+
+	re.api_version = API_VERSION;
+
+	re.BeginRegistration = R_BeginRegistration;
+    re.RegisterModel = R_RegisterModel;
+    re.RegisterSkin = R_RegisterSkin;
+	re.RegisterPic = Draw_FindPic;
+	re.SetSky = R_SetSky;
+	re.EndRegistration = R_EndRegistration;
+
+	re.RenderFrame = R_RenderFrame;
+
+	re.DrawGetPicSize = Draw_GetPicSize;
+	re.DrawPic = Draw_Pic;
+	re.DrawStretchPic = Draw_StretchPic;
+	re.DrawChar = Draw_Char;
+	re.DrawTileClear = Draw_TileClear;
+	re.DrawFill = Draw_Fill;
+	re.DrawFadeScreen= Draw_FadeScreen;
+
+	re.DrawStretchRaw = Draw_StretchRaw;
+
+	re.Init = R_Init;
+	re.Shutdown = R_Shutdown;
+
+	re.CinematicSetPalette = R_CinematicSetPalette;
+	re.BeginFrame = R_BeginFrame;
+	re.EndFrame = SWimp_EndFrame;
+
+	re.AppActivate = SWimp_AppActivate;
+
+	Swap_Init ();
+
+	return re;
+}
--- /dev/null
+++ b/r_misc.c
@@ -1,0 +1,567 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+#define NUM_MIPS	4
+
+cvar_t	*sw_mipcap;
+cvar_t	*sw_mipscale;
+
+surfcache_t		*d_initial_rover;
+qboolean		d_roverwrapped;
+int				d_minmip;
+float			d_scalemip[NUM_MIPS-1];
+
+static float	basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8};
+
+extern int			d_aflatcolor;
+
+int	d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
+
+int	d_pix_min, d_pix_max, d_pix_shift;
+
+int		d_scantable[MAXHEIGHT];
+short	*zspantable[MAXHEIGHT]; 
+
+/*
+================
+D_Patch
+================
+*/
+void D_Patch (void)
+{
+}
+/*
+================
+D_ViewChanged
+================
+*/
+unsigned char *alias_colormap;
+
+void D_ViewChanged (void)
+{
+	int		i;
+
+	scale_for_mip = xscale;
+	if (yscale > xscale)
+		scale_for_mip = yscale;
+
+	d_zrowbytes = vid.width * 2;
+	d_zwidth = vid.width;
+
+	d_pix_min = r_refdef.vrect.width / 320;
+	if (d_pix_min < 1)
+		d_pix_min = 1;
+
+	d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5);
+	d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5);
+	if (d_pix_max < 1)
+		d_pix_max = 1;
+
+	d_vrectx = r_refdef.vrect.x;
+	d_vrecty = r_refdef.vrect.y;
+	d_vrectright_particle = r_refdef.vrectright - d_pix_max;
+	d_vrectbottom_particle =
+			r_refdef.vrectbottom - d_pix_max;
+
+	for (i=0 ; i<vid.height; i++)
+	{
+		d_scantable[i] = i*r_screenwidth;
+		zspantable[i] = d_pzbuffer + i*d_zwidth;
+	}
+
+	/*
+	** clear Z-buffer and color-buffers if we're doing the gallery
+	*/
+	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
+	{
+		memset( d_pzbuffer, 0xff, vid.width * vid.height * sizeof( d_pzbuffer[0] ) );
+		Draw_Fill( r_newrefdef.x, r_newrefdef.y, r_newrefdef.width, r_newrefdef.height,( int ) sw_clearcolor->value & 0xff );
+	}
+
+	alias_colormap = vid.colormap;
+
+	D_Patch ();
+}
+
+
+
+/*
+=============
+R_PrintTimes
+=============
+*/
+void R_PrintTimes (void)
+{
+	int		r_time2;
+	int		ms;
+
+	r_time2 = Sys_Milliseconds ();
+
+	ms = r_time2 - r_time1;
+	
+	ri.Con_Printf (PRINT_ALL,"%5i ms %3i/%3i/%3i poly %3i surf\n",
+				ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf);
+	c_surf = 0;
+}
+
+
+/*
+=============
+R_PrintDSpeeds
+=============
+*/
+void R_PrintDSpeeds (void)
+{
+	int	ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, da_time;
+
+	r_time2 = Sys_Milliseconds ();
+
+	da_time = (da_time2 - da_time1);
+	dp_time = (dp_time2 - dp_time1);
+	rw_time = (rw_time2 - rw_time1);
+	db_time = (db_time2 - db_time1);
+	se_time = (se_time2 - se_time1);
+	de_time = (de_time2 - de_time1);
+	ms = (r_time2 - r_time1);
+
+	ri.Con_Printf (PRINT_ALL,"%3i %2ip %2iw %2ib %2is %2ie %2ia\n",
+				ms, dp_time, rw_time, db_time, se_time, de_time, da_time);
+}
+
+
+/*
+=============
+R_PrintAliasStats
+=============
+*/
+void R_PrintAliasStats (void)
+{
+	ri.Con_Printf (PRINT_ALL,"%3i polygon model drawn\n", r_amodels_drawn);
+}
+
+
+
+/*
+===================
+R_TransformFrustum
+===================
+*/
+void R_TransformFrustum (void)
+{
+	int		i;
+	vec3_t	v, v2;
+	
+	for (i=0 ; i<4 ; i++)
+	{
+		v[0] = screenedge[i].normal[2];
+		v[1] = -screenedge[i].normal[0];
+		v[2] = screenedge[i].normal[1];
+
+		v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0];
+		v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1];
+		v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2];
+
+		VectorCopy (v2, view_clipplanes[i].normal);
+
+		view_clipplanes[i].dist = DotProduct (modelorg, v2);
+	}
+}
+
+
+/*
+================
+TransformVector
+================
+*/
+void TransformVector (vec3_t in, vec3_t out)
+{
+	out[0] = DotProduct(in,vright);
+	out[1] = DotProduct(in,vup);
+	out[2] = DotProduct(in,vpn);		
+}
+
+
+/*
+================
+R_TransformPlane
+================
+*/
+void R_TransformPlane (mplane_t *p, float *normal, float *dist)
+{
+	float	d;
+	
+	d = DotProduct (r_origin, p->normal);
+	*dist = p->dist - d;
+// TODO: when we have rotating entities, this will need to use the view matrix
+	TransformVector (p->normal, normal);
+}
+
+
+/*
+===============
+R_SetUpFrustumIndexes
+===============
+*/
+void R_SetUpFrustumIndexes (void)
+{
+	int		i, j, *pindex;
+
+	pindex = r_frustum_indexes;
+
+	for (i=0 ; i<4 ; i++)
+	{
+		for (j=0 ; j<3 ; j++)
+		{
+			if (view_clipplanes[i].normal[j] < 0)
+			{
+				pindex[j] = j;
+				pindex[j+3] = j+3;
+			}
+			else
+			{
+				pindex[j] = j+3;
+				pindex[j+3] = j;
+			}
+		}
+
+	// FIXME: do just once at start
+		pfrustum_indexes[i] = pindex;
+		pindex += 6;
+	}
+}
+
+/*
+===============
+R_ViewChanged
+
+Called every time the vid structure or r_refdef changes.
+Guaranteed to be called before the first refresh
+===============
+*/
+void R_ViewChanged (vrect_t *vr)
+{
+	int		i;
+
+	r_refdef.vrect = *vr;
+
+	r_refdef.horizontalFieldOfView = 2*tan((float)r_newrefdef.fov_x/360*M_PI);;
+	verticalFieldOfView = 2*tan((float)r_newrefdef.fov_y/360*M_PI);
+
+	r_refdef.fvrectx = (float)r_refdef.vrect.x;
+	r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5;
+	r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1;
+	r_refdef.fvrecty = (float)r_refdef.vrect.y;
+	r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5;
+	r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width;
+	r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1;
+	r_refdef.fvrectright = (float)r_refdef.vrectright;
+	r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5;
+	r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99;
+	r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height;
+	r_refdef.fvrectbottom = (float)r_refdef.vrectbottom;
+	r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5;
+
+	r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale);
+	r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale);
+	r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale);
+	r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale);
+	r_refdef.aliasvrectright = r_refdef.aliasvrect.x +
+			r_refdef.aliasvrect.width;
+	r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y +
+			r_refdef.aliasvrect.height;
+
+	xOrigin = r_refdef.xOrigin;
+	yOrigin = r_refdef.yOrigin;
+	
+// values for perspective projection
+// if math were exact, the values would range from 0.5 to to range+0.5
+// hopefully they wll be in the 0.000001 to range+.999999 and truncate
+// the polygon rasterization will never render in the first row or column
+// but will definately render in the [range] row and column, so adjust the
+// buffer origin to get an exact edge to edge fill
+	xcenter = ((float)r_refdef.vrect.width * XCENTERING) +
+			r_refdef.vrect.x - 0.5;
+	aliasxcenter = xcenter * r_aliasuvscale;
+	ycenter = ((float)r_refdef.vrect.height * YCENTERING) +
+			r_refdef.vrect.y - 0.5;
+	aliasycenter = ycenter * r_aliasuvscale;
+
+	xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView;
+	aliasxscale = xscale * r_aliasuvscale;
+	xscaleinv = 1.0 / xscale;
+
+	yscale = xscale;
+	aliasyscale = yscale * r_aliasuvscale;
+	yscaleinv = 1.0 / yscale;
+	xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView;
+	yscaleshrink = xscaleshrink;
+
+// left side clip
+	screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView);
+	screenedge[0].normal[1] = 0;
+	screenedge[0].normal[2] = 1;
+	screenedge[0].type = PLANE_ANYZ;
+	
+// right side clip
+	screenedge[1].normal[0] =
+			1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView);
+	screenedge[1].normal[1] = 0;
+	screenedge[1].normal[2] = 1;
+	screenedge[1].type = PLANE_ANYZ;
+	
+// top side clip
+	screenedge[2].normal[0] = 0;
+	screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView);
+	screenedge[2].normal[2] = 1;
+	screenedge[2].type = PLANE_ANYZ;
+	
+// bottom side clip
+	screenedge[3].normal[0] = 0;
+	screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView);
+	screenedge[3].normal[2] = 1;	
+	screenedge[3].type = PLANE_ANYZ;
+	
+	for (i=0 ; i<4 ; i++)
+		VectorNormalize (screenedge[i].normal);
+
+	D_ViewChanged ();
+}
+
+
+/*
+===============
+R_SetupFrame
+===============
+*/
+void R_SetupFrame (void)
+{
+	int			i;
+	vrect_t		vrect;
+
+	if (r_fullbright->modified)
+	{
+		r_fullbright->modified = false;
+		D_FlushCaches ();	// so all lighting changes
+	}
+	
+	r_framecount++;
+
+
+// build the transformation matrix for the given view angles
+	VectorCopy (r_refdef.vieworg, modelorg);
+	VectorCopy (r_refdef.vieworg, r_origin);
+
+	AngleVectors (r_refdef.viewangles, vpn, vright, vup);
+
+// current viewleaf
+	if ( !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
+	{
+		r_viewleaf = Mod_PointInLeaf (r_origin, r_worldmodel);
+		r_viewcluster = r_viewleaf->cluster;
+	}
+
+	if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) )
+		r_dowarp = true;
+	else
+		r_dowarp = false;
+
+	if (r_dowarp)
+	{	// warp into off screen buffer
+		vrect.x = 0;
+		vrect.y = 0;
+		vrect.width = r_newrefdef.width < WARP_WIDTH ? r_newrefdef.width : WARP_WIDTH;
+		vrect.height = r_newrefdef.height < WARP_HEIGHT ? r_newrefdef.height : WARP_HEIGHT;
+
+		d_viewbuffer = r_warpbuffer;
+		r_screenwidth = WARP_WIDTH;
+	}
+	else
+	{
+		vrect.x = r_newrefdef.x;
+		vrect.y = r_newrefdef.y;
+		vrect.width = r_newrefdef.width;
+		vrect.height = r_newrefdef.height;
+
+		d_viewbuffer = (void *)vid.buffer;
+		r_screenwidth = vid.rowbytes;
+	}
+	
+	R_ViewChanged (&vrect);
+
+// start off with just the four screen edge clip planes
+	R_TransformFrustum ();
+	R_SetUpFrustumIndexes ();
+
+// save base values
+	VectorCopy (vpn, base_vpn);
+	VectorCopy (vright, base_vright);
+	VectorCopy (vup, base_vup);
+
+// clear frame counts
+	c_faceclip = 0;
+	d_spanpixcount = 0;
+	r_polycount = 0;
+	r_drawnpolycount = 0;
+	r_wholepolycount = 0;
+	r_amodels_drawn = 0;
+	r_outofsurfaces = 0;
+	r_outofedges = 0;
+
+// d_setup
+	d_roverwrapped = false;
+	d_initial_rover = sc_rover;
+
+	d_minmip = sw_mipcap->value;
+	if (d_minmip > 3)
+		d_minmip = 3;
+	else if (d_minmip < 0)
+		d_minmip = 0;
+
+	for (i=0 ; i<(NUM_MIPS-1) ; i++)
+		d_scalemip[i] = basemip[i] * sw_mipscale->value;
+
+	d_aflatcolor = 0;
+}
+
+
+/* 
+============================================================================== 
+ 
+						SCREEN SHOTS 
+ 
+============================================================================== 
+*/ 
+
+
+/* 
+============== 
+WritePCXfile 
+============== 
+*/ 
+void WritePCXfile (char *filename, byte *data, int width, int height,
+	int rowbytes, byte *palette) 
+{
+	int			i, j, length;
+	pcx_t		*pcx;
+	byte		*pack;
+	FILE		*f;
+
+	pcx = (pcx_t *)malloc (width*height*2+1000);
+	if (!pcx)
+		return;
+
+	pcx->manufacturer = 0x0a;	// PCX id
+	pcx->version = 5;			// 256 color
+ 	pcx->encoding = 1;		// uncompressed
+	pcx->bits_per_pixel = 8;		// 256 color
+	pcx->xmin = 0;
+	pcx->ymin = 0;
+	pcx->xmax = LittleShort((short)(width-1));
+	pcx->ymax = LittleShort((short)(height-1));
+	pcx->hres = LittleShort((short)width);
+	pcx->vres = LittleShort((short)height);
+	memset (pcx->palette,0,sizeof(pcx->palette));
+	pcx->color_planes = 1;		// chunky image
+	pcx->bytes_per_line = LittleShort((short)width);
+	pcx->palette_type = LittleShort(2);		// not a grey scale
+	memset (pcx->filler,0,sizeof(pcx->filler));
+
+// pack the image
+	pack = &pcx->data;
+	
+	for (i=0 ; i<height ; i++)
+	{
+		for (j=0 ; j<width ; j++)
+		{
+			if ( (*data & 0xc0) != 0xc0)
+				*pack++ = *data++;
+			else
+			{
+				*pack++ = 0xc1;
+				*pack++ = *data++;
+			}
+		}
+
+		data += rowbytes - width;
+	}
+			
+// write the palette
+	*pack++ = 0x0c;	// palette ID byte
+	for (i=0 ; i<768 ; i++)
+		*pack++ = *palette++;
+		
+// write output file 
+	length = pack - (byte *)pcx;
+	f = fopen (filename, "wb");
+	if (!f)
+		ri.Con_Printf (PRINT_ALL, "Failed to open to %s\n", filename);
+	else
+	{
+		fwrite ((void *)pcx, 1, length, f);
+		fclose (f);
+	}
+
+	free (pcx);
+} 
+ 
+
+
+/* 
+================== 
+R_ScreenShot_f
+================== 
+*/  
+void R_ScreenShot_f (void) 
+{ 
+	int			i; 
+	char		pcxname[80]; 
+	char		checkname[MAX_OSPATH];
+	FILE		*f;
+	byte		palette[768];
+
+	// create the scrnshots directory if it doesn't exist
+	Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
+	Sys_Mkdir (checkname);
+
+// 
+// find a file name to save it to 
+// 
+	strcpy(pcxname,"quake00.pcx");
+		
+	for (i=0 ; i<=99 ; i++) 
+	{ 
+		pcxname[5] = i/10 + '0'; 
+		pcxname[6] = i%10 + '0'; 
+		Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), pcxname);
+		f = fopen (checkname, "r");
+		if (!f)
+			break;	// file doesn't exist
+		fclose (f);
+	} 
+	if (i==100) 
+	{
+		ri.Con_Printf (PRINT_ALL, "R_ScreenShot_f: Couldn't create a PCX"); 
+		return;
+	}
+
+	// turn the current 32 bit palette into a 24 bit palette
+	for (i=0 ; i<256 ; i++)
+	{
+		palette[i*3+0] = sw_state.currentpalette[i*4+0];
+		palette[i*3+1] = sw_state.currentpalette[i*4+1];
+		palette[i*3+2] = sw_state.currentpalette[i*4+2];
+	}
+
+// 
+// save the pcx file 
+// 
+
+	WritePCXfile (checkname, vid.buffer, vid.width, vid.height, vid.rowbytes,
+				  palette);
+
+	ri.Con_Printf (PRINT_ALL, "Wrote %s\n", checkname);
+} 
+
--- /dev/null
+++ b/r_model.c
@@ -1,0 +1,1205 @@
+// models.c -- model loading and caching
+
+// models are the only shared resource between a client and server running
+// on the same machine.
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+model_t	*loadmodel;
+char	loadname[32];	// for hunk tags
+
+void Mod_LoadSpriteModel (model_t *mod, void *buffer);
+void Mod_LoadBrushModel (model_t *mod, void *buffer);
+void Mod_LoadAliasModel (model_t *mod, void *buffer);
+model_t *Mod_LoadModel (model_t *mod, qboolean crash);
+
+byte	mod_novis[MAX_MAP_LEAFS/8];
+
+#define	MAX_MOD_KNOWN	256
+model_t	mod_known[MAX_MOD_KNOWN];
+int		mod_numknown;
+
+// the inline * models from the current map are kept seperate
+model_t	mod_inline[MAX_MOD_KNOWN];
+
+int		registration_sequence;
+int		modfilelen;
+
+//===============================================================================
+
+
+/*
+================
+Mod_Modellist_f
+================
+*/
+void Mod_Modellist_f (void)
+{
+	int		i;
+	model_t	*mod;
+	int		total;
+
+	total = 0;
+	ri.Con_Printf (PRINT_ALL,"Loaded models:\n");
+	for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
+	{
+		if (!mod->name[0])
+			continue;
+		ri.Con_Printf (PRINT_ALL, "%8i : %s\n",mod->extradatasize, mod->name);
+		total += mod->extradatasize;
+	}
+	ri.Con_Printf (PRINT_ALL, "Total resident: %i\n", total);
+}
+
+/*
+===============
+Mod_Init
+===============
+*/
+void Mod_Init (void)
+{
+	memset (mod_novis, 0xff, sizeof(mod_novis));
+}
+
+/*
+==================
+Mod_ForName
+
+Loads in a model for the given name
+==================
+*/
+model_t *Mod_ForName (char *name, qboolean crash)
+{
+	model_t	*mod;
+	unsigned *buf;
+	int		i;
+	
+	if (!name[0])
+		ri.Sys_Error (ERR_DROP,"Mod_ForName: NULL name");
+
+	//
+	// inline models are grabbed only from worldmodel
+	//
+	if (name[0] == '*')
+	{
+		i = atoi(name+1);
+		if (i < 1 || !r_worldmodel || i >= r_worldmodel->numsubmodels)
+			ri.Sys_Error (ERR_DROP, "bad inline model number");
+		return &mod_inline[i];
+	}
+
+	//
+	// search the currently loaded models
+	//
+	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
+		if (!strcmp (mod->name, name) )
+			return mod;
+			
+	//
+	// find a free model slot spot
+	//
+	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
+	{
+		if (!mod->name[0])
+			break;	// free spot
+	}
+	if (i == mod_numknown)
+	{
+		if (mod_numknown == MAX_MOD_KNOWN)
+			ri.Sys_Error (ERR_DROP, "mod_numknown == MAX_MOD_KNOWN");
+		mod_numknown++;
+	}
+	strcpy (mod->name, name);
+	
+	//
+	// load the file
+	//
+	modfilelen = ri.FS_LoadFile (mod->name, (void **)&buf);
+	if (!buf)
+	{
+		if (crash)
+			ri.Sys_Error (ERR_DROP,"Mod_NumForName: %s not found", mod->name);
+		memset (mod->name, 0, sizeof(mod->name));
+		return NULL;
+	}
+	
+	loadmodel = mod;
+
+	//
+	// fill it in
+	//
+
+	// call the apropriate loader
+	
+	switch (LittleLong(*(unsigned *)buf))
+	{
+	case IDALIASHEADER:
+		loadmodel->extradata = Hunk_Begin (0x200000);
+		Mod_LoadAliasModel (mod, buf);
+		break;
+		
+	case IDSPRITEHEADER:
+		loadmodel->extradata = Hunk_Begin (0x10000);
+		Mod_LoadSpriteModel (mod, buf);
+		break;
+	
+	case IDBSPHEADER:
+		loadmodel->extradata = Hunk_Begin (0x1000000);
+		Mod_LoadBrushModel (mod, buf);
+		break;
+
+	default:
+		ri.Sys_Error (ERR_DROP,"Mod_NumForName: unknown fileid for %s", mod->name);
+		break;
+	}
+
+	loadmodel->extradatasize = Hunk_End ();
+
+	ri.FS_FreeFile (buf);
+
+	return mod;
+}
+
+
+/*
+===============
+Mod_PointInLeaf
+===============
+*/
+mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
+{
+	mnode_t		*node;
+	float		d;
+	mplane_t	*plane;
+	
+	if (!model || !model->nodes)
+		ri.Sys_Error (ERR_DROP, "Mod_PointInLeaf: bad model");
+
+	node = model->nodes;
+	while (1)
+	{
+		if (node->contents != -1)
+			return (mleaf_t *)node;
+		plane = node->plane;
+		d = DotProduct (p,plane->normal) - plane->dist;
+		if (d > 0)
+			node = node->children[0];
+		else
+			node = node->children[1];
+	}
+}
+
+
+/*
+===================
+Mod_DecompressVis
+===================
+*/
+byte *Mod_DecompressVis (byte *in, model_t *model)
+{
+	static byte	decompressed[MAX_MAP_LEAFS/8];
+	int		c;
+	byte	*out;
+	int		row;
+
+	row = (model->vis->numclusters+7)>>3;	
+	out = decompressed;
+
+	/*
+	memcpy (out, in, row);
+	*/
+	if (!in)
+	{	// no vis info, so make all visible
+		while (row)
+		{
+			*out++ = 0xff;
+			row--;
+		}
+		return decompressed;		
+	}
+
+	do
+	{
+		if (*in)
+		{
+			*out++ = *in++;
+			continue;
+		}
+	
+		c = in[1];
+		in += 2;
+		while (c)
+		{
+			*out++ = 0;
+			c--;
+		}
+	} while (out - decompressed < row);
+	
+	return decompressed;
+}
+
+/*
+==============
+Mod_ClusterPVS
+==============
+*/
+byte *Mod_ClusterPVS (int cluster, model_t *model)
+{
+	if (cluster == -1 || !model->vis)
+		return mod_novis;
+	return Mod_DecompressVis ( (byte *)model->vis + model->vis->bitofs[cluster][DVIS_PVS],
+		model);
+}
+
+/*
+===============================================================================
+
+					BRUSHMODEL LOADING
+
+===============================================================================
+*/
+
+byte	*mod_base;
+
+
+/*
+=================
+Mod_LoadLighting
+
+Converts the 24 bit lighting down to 8 bit
+by taking the brightest component
+=================
+*/
+void Mod_LoadLighting (lump_t *l)
+{
+	int		i, size;
+	byte	*in;
+
+	if (!l->filelen)
+	{
+		loadmodel->lightdata = NULL;
+		return;
+	}
+	size = l->filelen/3;
+	loadmodel->lightdata = Hunk_Alloc (size);
+	in = (void *)(mod_base + l->fileofs);
+	for (i=0 ; i<size ; i++, in+=3)
+	{
+		if (in[0] > in[1] && in[0] > in[2])
+			loadmodel->lightdata[i] = in[0];
+		else if (in[1] > in[0] && in[1] > in[2])
+			loadmodel->lightdata[i] = in[1];
+		else
+			loadmodel->lightdata[i] = in[2];
+	}
+}
+
+
+int		r_leaftovis[MAX_MAP_LEAFS];
+int		r_vistoleaf[MAX_MAP_LEAFS];
+int		r_numvisleafs;
+
+void	R_NumberLeafs (mnode_t *node)
+{
+	mleaf_t	*leaf;
+	int		leafnum;
+
+	if (node->contents != -1)
+	{
+		leaf = (mleaf_t *)node;
+		leafnum = leaf - loadmodel->leafs;
+		if (leaf->contents & CONTENTS_SOLID)
+			return;
+		r_leaftovis[leafnum] = r_numvisleafs;
+		r_vistoleaf[r_numvisleafs] = leafnum;
+		r_numvisleafs++;
+		return;
+	}
+
+	R_NumberLeafs (node->children[0]);
+	R_NumberLeafs (node->children[1]);
+}
+
+
+/*
+=================
+Mod_LoadVisibility
+=================
+*/
+void Mod_LoadVisibility (lump_t *l)
+{
+	int		i;
+
+	if (!l->filelen)
+	{
+		loadmodel->vis = NULL;
+		return;
+	}
+	loadmodel->vis = Hunk_Alloc ( l->filelen);	
+	memcpy (loadmodel->vis, mod_base + l->fileofs, l->filelen);
+
+	loadmodel->vis->numclusters = LittleLong (loadmodel->vis->numclusters);
+	for (i=0 ; i<loadmodel->vis->numclusters ; i++)
+	{
+		loadmodel->vis->bitofs[i][0] = LittleLong (loadmodel->vis->bitofs[i][0]);
+		loadmodel->vis->bitofs[i][1] = LittleLong (loadmodel->vis->bitofs[i][1]);
+	}
+}
+
+
+/*
+=================
+Mod_LoadVertexes
+=================
+*/
+void Mod_LoadVertexes (lump_t *l)
+{
+	dvertex_t	*in;
+	mvertex_t	*out;
+	int			i, count;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count+8)*sizeof(*out));		// extra for skybox
+
+	loadmodel->vertexes = out;
+	loadmodel->numvertexes = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		out->position[0] = LittleFloat (in->point[0]);
+		out->position[1] = LittleFloat (in->point[1]);
+		out->position[2] = LittleFloat (in->point[2]);
+	}
+}
+
+/*
+=================
+Mod_LoadSubmodels
+=================
+*/
+void Mod_LoadSubmodels (lump_t *l)
+{
+	dmodel_t	*in;
+	dmodel_t	*out;
+	int			i, j, count;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	loadmodel->submodels = out;
+	loadmodel->numsubmodels = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		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);
+		out->firstface = LittleLong (in->firstface);
+		out->numfaces = LittleLong (in->numfaces);
+	}
+}
+
+/*
+=================
+Mod_LoadEdges
+=================
+*/
+void Mod_LoadEdges (lump_t *l)
+{
+	dedge_t *in;
+	medge_t *out;
+	int 	i, count;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count + 13) * sizeof(*out));	// extra for skybox
+
+	loadmodel->edges = out;
+	loadmodel->numedges = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		out->v[0] = (unsigned short)LittleShort(in->v[0]);
+		out->v[1] = (unsigned short)LittleShort(in->v[1]);
+	}
+}
+
+/*
+=================
+Mod_LoadTexinfo
+=================
+*/
+void Mod_LoadTexinfo (lump_t *l)
+{
+	texinfo_t *in;
+	mtexinfo_t *out, *step;
+	int 	i, j, count;
+	float	len1, len2;
+	char	name[MAX_QPATH];
+	int		next;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count+6)*sizeof(*out));	// extra for skybox
+
+	loadmodel->texinfo = out;
+	loadmodel->numtexinfo = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		for (j=0 ; j<8 ; j++)
+			out->vecs[0][j] = LittleFloat (in->vecs[0][j]);
+		len1 = VectorLength (out->vecs[0]);
+		len2 = VectorLength (out->vecs[1]);
+		len1 = (len1 + len2)/2;
+		if (len1 < 0.32)
+			out->mipadjust = 4;
+		else if (len1 < 0.49)
+			out->mipadjust = 3;
+		else if (len1 < 0.99)
+			out->mipadjust = 2;
+		else
+			out->mipadjust = 1;
+		/*
+		if (len1 + len2 < 0.001)
+			out->mipadjust = 1;		// don't crash
+		else
+			out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 );
+		*/
+
+		out->flags = LittleLong (in->flags);
+
+		next = LittleLong (in->nexttexinfo);
+		if (next > 0)
+			out->next = loadmodel->texinfo + next;
+
+		Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture);
+		out->image = R_FindImage (name, it_wall);
+		if (!out->image)
+		{
+			out->image = r_notexture_mip; // texture not found
+			out->flags = 0;
+		}
+	}
+
+	// count animation frames
+	for (i=0 ; i<count ; i++)
+	{
+		out = &loadmodel->texinfo[i];
+		out->numframes = 1;
+		for (step = out->next ; step && step != out ; step=step->next)
+			out->numframes++;
+	}
+}
+
+/*
+================
+CalcSurfaceExtents
+
+Fills in s->texturemins[] and s->extents[]
+================
+*/
+void CalcSurfaceExtents (msurface_t *s)
+{
+	float	mins[2], maxs[2], val;
+	int		i,j, e;
+	mvertex_t	*v;
+	mtexinfo_t	*tex;
+	int		bmins[2], bmaxs[2];
+
+	mins[0] = mins[1] = 999999;
+	maxs[0] = maxs[1] = -99999;
+
+	tex = s->texinfo;
+	
+	for (i=0 ; i<s->numedges ; i++)
+	{
+		e = loadmodel->surfedges[s->firstedge+i];
+		if (e >= 0)
+			v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
+		else
+			v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
+		
+		for (j=0 ; j<2 ; j++)
+		{
+			val = v->position[0] * tex->vecs[j][0] + 
+				v->position[1] * tex->vecs[j][1] +
+				v->position[2] * tex->vecs[j][2] +
+				tex->vecs[j][3];
+			if (val < mins[j])
+				mins[j] = val;
+			if (val > maxs[j])
+				maxs[j] = val;
+		}
+	}
+
+	for (i=0 ; i<2 ; i++)
+	{	
+		bmins[i] = floor(mins[i]/16);
+		bmaxs[i] = ceil(maxs[i]/16);
+
+		s->texturemins[i] = bmins[i] * 16;
+		s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
+		if (s->extents[i] < 16)
+			s->extents[i] = 16;	// take at least one cache block
+		if ( !(tex->flags & (SURF_WARP|SURF_SKY)) && s->extents[i] > 256)
+			ri.Sys_Error (ERR_DROP,"Bad surface extents");
+	}
+}
+
+
+/*
+=================
+Mod_LoadFaces
+=================
+*/
+void Mod_LoadFaces (lump_t *l)
+{
+	dface_t		*in;
+	msurface_t 	*out;
+	int			i, count, surfnum;
+	int			planenum, side;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count+6)*sizeof(*out));	// extra for skybox
+
+	loadmodel->surfaces = out;
+	loadmodel->numsurfaces = count;
+
+	for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
+	{
+		out->firstedge = LittleLong(in->firstedge);
+		out->numedges = LittleShort(in->numedges);		
+		if (out->numedges < 3)
+			ri.Sys_Error (ERR_DROP,"Surface with %s edges", out->numedges);
+		out->flags = 0;
+
+		planenum = LittleShort(in->planenum);
+		side = LittleShort(in->side);
+		if (side)
+			out->flags |= SURF_PLANEBACK;			
+
+		out->plane = loadmodel->planes + planenum;
+
+		out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
+
+		CalcSurfaceExtents (out);
+				
+	// lighting info is converted from 24 bit on disk to 8 bit
+
+		for (i=0 ; i<MAXLIGHTMAPS ; i++)
+			out->styles[i] = in->styles[i];
+		i = LittleLong(in->lightofs);
+		if (i == -1)
+			out->samples = NULL;
+		else
+			out->samples = loadmodel->lightdata + i/3;
+		
+	// set the drawing flags flag
+		
+		if (!out->texinfo->image)
+			continue;
+		if (out->texinfo->flags & SURF_SKY)
+		{
+			out->flags |= SURF_DRAWSKY;
+			continue;
+		}
+		
+		if (out->texinfo->flags & SURF_WARP)
+		{
+			out->flags |= SURF_DRAWTURB;
+			for (i=0 ; i<2 ; i++)
+			{
+				out->extents[i] = 16384;
+				out->texturemins[i] = -8192;
+			}
+			continue;
+		}
+//==============
+//PGM
+		// this marks flowing surfaces as turbulent, but with the new
+		// SURF_FLOW flag.
+		if (out->texinfo->flags & SURF_FLOWING)
+		{
+			out->flags |= SURF_DRAWTURB | SURF_FLOW;
+			for (i=0 ; i<2 ; i++)
+			{
+				out->extents[i] = 16384;
+				out->texturemins[i] = -8192;
+			}
+			continue;
+		}
+//PGM
+//==============
+	}
+}
+
+
+/*
+=================
+Mod_SetParent
+=================
+*/
+void Mod_SetParent (mnode_t *node, mnode_t *parent)
+{
+	node->parent = parent;
+	if (node->contents != -1)
+		return;
+	Mod_SetParent (node->children[0], node);
+	Mod_SetParent (node->children[1], node);
+}
+
+/*
+=================
+Mod_LoadNodes
+=================
+*/
+void Mod_LoadNodes (lump_t *l)
+{
+	int			i, j, count, p;
+	dnode_t		*in;
+	mnode_t 	*out;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	loadmodel->nodes = out;
+	loadmodel->numnodes = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		for (j=0 ; j<3 ; j++)
+		{
+			out->minmaxs[j] = LittleShort (in->mins[j]);
+			out->minmaxs[3+j] = LittleShort (in->maxs[j]);
+		}
+	
+		p = LittleLong(in->planenum);
+		out->plane = loadmodel->planes + p;
+
+		out->firstsurface = LittleShort (in->firstface);
+		out->numsurfaces = LittleShort (in->numfaces);
+		out->contents = CONTENTS_NODE;	// differentiate from leafs
+		
+		for (j=0 ; j<2 ; j++)
+		{
+			p = LittleLong (in->children[j]);
+			if (p >= 0)
+				out->children[j] = loadmodel->nodes + p;
+			else
+				out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
+		}
+	}
+	
+	Mod_SetParent (loadmodel->nodes, NULL);	// sets nodes and leafs
+}
+
+/*
+=================
+Mod_LoadLeafs
+=================
+*/
+void Mod_LoadLeafs (lump_t *l)
+{
+	dleaf_t 	*in;
+	mleaf_t 	*out;
+	int			i, j, count;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));
+
+	loadmodel->leafs = out;
+	loadmodel->numleafs = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		for (j=0 ; j<3 ; j++)
+		{
+			out->minmaxs[j] = LittleShort (in->mins[j]);
+			out->minmaxs[3+j] = LittleShort (in->maxs[j]);
+		}
+
+		out->contents = LittleLong(in->contents);
+		out->cluster = LittleShort(in->cluster);
+		out->area = LittleShort(in->area);
+
+		out->firstmarksurface = loadmodel->marksurfaces +
+			LittleShort(in->firstleafface);
+		out->nummarksurfaces = LittleShort(in->numleaffaces);
+	}	
+}
+
+
+/*
+=================
+Mod_LoadMarksurfaces
+=================
+*/
+void Mod_LoadMarksurfaces (lump_t *l)
+{	
+	int		i, j, count;
+	short		*in;
+	msurface_t **out;
+	
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	loadmodel->marksurfaces = out;
+	loadmodel->nummarksurfaces = count;
+
+	for ( i=0 ; i<count ; i++)
+	{
+		j = LittleShort(in[i]);
+		if (j >= loadmodel->numsurfaces)
+			ri.Sys_Error (ERR_DROP,"Mod_ParseMarksurfaces: bad surface number");
+		out[i] = loadmodel->surfaces + j;
+	}
+}
+
+/*
+=================
+Mod_LoadSurfedges
+=================
+*/
+void Mod_LoadSurfedges (lump_t *l)
+{	
+	int		i, count;
+	int		*in, *out;
+	
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count+24)*sizeof(*out));	// extra for skybox
+
+	loadmodel->surfedges = out;
+	loadmodel->numsurfedges = count;
+
+	for ( i=0 ; i<count ; i++)
+		out[i] = LittleLong (in[i]);
+}
+
+/*
+=================
+Mod_LoadPlanes
+=================
+*/
+void Mod_LoadPlanes (lump_t *l)
+{
+	int			i, j;
+	mplane_t	*out;
+	dplane_t 	*in;
+	int			count;
+	int			bits;
+	
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count+6)*sizeof(*out));		// extra for skybox
+	
+	loadmodel->planes = out;
+	loadmodel->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;
+	}
+}
+
+
+/*
+=================
+Mod_LoadBrushModel
+=================
+*/
+void Mod_LoadBrushModel (model_t *mod, void *buffer)
+{
+	int			i;
+	dheader_t	*header;
+	dmodel_t 	*bm;
+	
+	loadmodel->type = mod_brush;
+	if (loadmodel != mod_known)
+		ri.Sys_Error (ERR_DROP, "Loaded a brush model after the world");
+	
+	header = (dheader_t *)buffer;
+
+	i = LittleLong (header->version);
+	if (i != BSPVERSION)
+		ri.Sys_Error (ERR_DROP,"Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
+
+// swap all the lumps
+	mod_base = (byte *)header;
+
+	for (i=0 ; i<sizeof(dheader_t)/sizeof(int) ; i++)
+		((int *)header)[i] = LittleLong ( ((int *)header)[i]);
+
+// load into heap
+	
+	Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
+	Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
+	Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
+	Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
+	Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
+	Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
+	Mod_LoadFaces (&header->lumps[LUMP_FACES]);
+	Mod_LoadMarksurfaces (&header->lumps[LUMP_LEAFFACES]);
+	Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
+	Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
+	Mod_LoadNodes (&header->lumps[LUMP_NODES]);
+	Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
+	r_numvisleafs = 0;
+	R_NumberLeafs (loadmodel->nodes);
+	
+//
+// set up the submodels
+//
+	for (i=0 ; i<mod->numsubmodels ; i++)
+	{
+		model_t	*starmod;
+
+		bm = &mod->submodels[i];
+		starmod = &mod_inline[i];
+
+		*starmod = *loadmodel;
+		
+		starmod->firstmodelsurface = bm->firstface;
+		starmod->nummodelsurfaces = bm->numfaces;
+		starmod->firstnode = bm->headnode;
+		if (starmod->firstnode >= loadmodel->numnodes)
+			ri.Sys_Error (ERR_DROP, "Inline model %i has bad firstnode", i);
+
+		VectorCopy (bm->maxs, starmod->maxs);
+		VectorCopy (bm->mins, starmod->mins);
+	
+		if (i == 0)
+			*loadmodel = *starmod;
+	}
+
+	R_InitSkyBox ();
+}
+
+/*
+==============================================================================
+
+ALIAS MODELS
+
+==============================================================================
+*/
+
+/*
+=================
+Mod_LoadAliasModel
+=================
+*/
+void Mod_LoadAliasModel (model_t *mod, void *buffer)
+{
+	int					i, j;
+	dmdl_t				*pinmodel, *pheader;
+	dstvert_t			*pinst, *poutst;
+	dtriangle_t			*pintri, *pouttri;
+	daliasframe_t		*pinframe, *poutframe;
+	int					*pincmd, *poutcmd;
+	int					version;
+
+	pinmodel = (dmdl_t *)buffer;
+
+	version = LittleLong (pinmodel->version);
+	if (version != ALIAS_VERSION)
+		ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
+				 mod->name, version, ALIAS_VERSION);
+
+	pheader = Hunk_Alloc (LittleLong(pinmodel->ofs_end));
+	
+	// byte swap the header fields and sanity check
+	for (i=0 ; i<sizeof(dmdl_t)/sizeof(int) ; i++)
+		((int *)pheader)[i] = LittleLong (((int *)buffer)[i]);
+
+	if (pheader->skinheight > MAX_LBM_HEIGHT)
+		ri.Sys_Error (ERR_DROP, "model %s has a skin taller than %d", mod->name,
+				   MAX_LBM_HEIGHT);
+
+	if (pheader->num_xyz <= 0)
+		ri.Sys_Error (ERR_DROP, "model %s has no vertices", mod->name);
+
+	if (pheader->num_xyz > MAX_VERTS)
+		ri.Sys_Error (ERR_DROP, "model %s has too many vertices", mod->name);
+
+	if (pheader->num_st <= 0)
+		ri.Sys_Error (ERR_DROP, "model %s has no st vertices", mod->name);
+
+	if (pheader->num_tris <= 0)
+		ri.Sys_Error (ERR_DROP, "model %s has no triangles", mod->name);
+
+	if (pheader->num_frames <= 0)
+		ri.Sys_Error (ERR_DROP, "model %s has no frames", mod->name);
+
+//
+// load base s and t vertices (not used in gl version)
+//
+	pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st);
+	poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st);
+
+	for (i=0 ; i<pheader->num_st ; i++)
+	{
+		poutst[i].s = LittleShort (pinst[i].s);
+		poutst[i].t = LittleShort (pinst[i].t);
+	}
+
+//
+// load triangle lists
+//
+	pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris);
+	pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris);
+
+	for (i=0 ; i<pheader->num_tris ; i++)
+	{
+		for (j=0 ; j<3 ; j++)
+		{
+			pouttri[i].index_xyz[j] = LittleShort (pintri[i].index_xyz[j]);
+			pouttri[i].index_st[j] = LittleShort (pintri[i].index_st[j]);
+		}
+	}
+
+//
+// load the frames
+//
+	for (i=0 ; i<pheader->num_frames ; i++)
+	{
+		pinframe = (daliasframe_t *) ((byte *)pinmodel 
+			+ pheader->ofs_frames + i * pheader->framesize);
+		poutframe = (daliasframe_t *) ((byte *)pheader 
+			+ pheader->ofs_frames + i * pheader->framesize);
+
+		memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name));
+		for (j=0 ; j<3 ; j++)
+		{
+			poutframe->scale[j] = LittleFloat (pinframe->scale[j]);
+			poutframe->translate[j] = LittleFloat (pinframe->translate[j]);
+		}
+		// verts are all 8 bit, so no swapping needed
+		memcpy (poutframe->verts, pinframe->verts, 
+			pheader->num_xyz*sizeof(dtrivertx_t));
+
+	}
+
+	mod->type = mod_alias;
+
+	//
+	// load the glcmds
+	//
+	pincmd = (int *) ((byte *)pinmodel + pheader->ofs_glcmds);
+	poutcmd = (int *) ((byte *)pheader + pheader->ofs_glcmds);
+	for (i=0 ; i<pheader->num_glcmds ; i++)
+		poutcmd[i] = LittleLong (pincmd[i]);
+
+
+	// register all skins
+	memcpy ((char *)pheader + pheader->ofs_skins, (char *)pinmodel + pheader->ofs_skins,
+		pheader->num_skins*MAX_SKINNAME);
+	for (i=0 ; i<pheader->num_skins ; i++)
+	{
+		mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
+	}
+}
+
+/*
+==============================================================================
+
+SPRITE MODELS
+
+==============================================================================
+*/
+
+/*
+=================
+Mod_LoadSpriteModel
+=================
+*/
+void Mod_LoadSpriteModel (model_t *mod, void *buffer)
+{
+	dsprite_t	*sprin, *sprout;
+	int			i;
+
+	sprin = (dsprite_t *)buffer;
+	sprout = Hunk_Alloc (modfilelen);
+
+	sprout->ident = LittleLong (sprin->ident);
+	sprout->version = LittleLong (sprin->version);
+	sprout->numframes = LittleLong (sprin->numframes);
+
+	if (sprout->version != SPRITE_VERSION)
+		ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
+				 mod->name, sprout->version, SPRITE_VERSION);
+
+	if (sprout->numframes > MAX_MD2SKINS)
+		ri.Sys_Error (ERR_DROP, "%s has too many frames (%i > %i)",
+				 mod->name, sprout->numframes, MAX_MD2SKINS);
+
+	// byte swap everything
+	for (i=0 ; i<sprout->numframes ; i++)
+	{
+		sprout->frames[i].width = LittleLong (sprin->frames[i].width);
+		sprout->frames[i].height = LittleLong (sprin->frames[i].height);
+		sprout->frames[i].origin_x = LittleLong (sprin->frames[i].origin_x);
+		sprout->frames[i].origin_y = LittleLong (sprin->frames[i].origin_y);
+		memcpy (sprout->frames[i].name, sprin->frames[i].name, MAX_SKINNAME);
+		mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite);
+	}
+
+	mod->type = mod_sprite;
+}
+
+//=============================================================================
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_BeginRegistration
+
+Specifies the model that will be used as the world
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void R_BeginRegistration (char *model)
+{
+	char	fullname[MAX_QPATH];
+	cvar_t	*flushmap;
+
+	registration_sequence++;
+	r_oldviewcluster = -1;		// force markleafs
+	Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model);
+
+	D_FlushCaches ();
+	// explicitly free the old map if different
+	// this guarantees that mod_known[0] is the world map
+	flushmap = ri.Cvar_Get ("flushmap", "0", 0);
+	if ( strcmp(mod_known[0].name, fullname) || flushmap->value)
+		Mod_Free (&mod_known[0]);
+	r_worldmodel = R_RegisterModel (fullname);
+	R_NewMap ();
+}
+
+model_t *
+R_RegisterModel(char *name)
+{
+	model_t	*mod;
+	int		i;
+	dsprite_t	*sprout;
+	dmdl_t		*pheader;
+
+	mod = Mod_ForName (name, false);
+	if (mod)
+	{
+		mod->registration_sequence = registration_sequence;
+
+		// register any images used by the models
+		if (mod->type == mod_sprite)
+		{
+			sprout = (dsprite_t *)mod->extradata;
+			for (i=0 ; i<sprout->numframes ; i++)
+				mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite);
+		}
+		else if (mod->type == mod_alias)
+		{
+			pheader = (dmdl_t *)mod->extradata;
+			for (i=0 ; i<pheader->num_skins ; i++)
+				mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
+//PGM
+			mod->numframes = pheader->num_frames;
+//PGM
+		}
+		else if (mod->type == mod_brush)
+		{
+			for (i=0 ; i<mod->numtexinfo ; i++)
+				mod->texinfo[i].image->registration_sequence = registration_sequence;
+		}
+	}
+	return mod;
+}
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_EndRegistration
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void R_EndRegistration (void)
+{
+	int		i;
+	model_t	*mod;
+
+	for (i=0, mod=mod_known ; i<mod_numknown ; i++, mod++)
+	{
+		if (!mod->name[0])
+			continue;
+		if (mod->registration_sequence != registration_sequence)
+		{	// don't need this model
+			Hunk_Free (mod->extradata);
+			memset (mod, 0, sizeof(*mod));
+		}
+		else
+		{	// make sure it is paged in
+			Com_PageInMemory (mod->extradata, mod->extradatasize);
+		}
+	}
+
+	R_FreeUnusedImages ();
+}
+
+void
+Mod_Free(model_t *mod)
+{
+	Hunk_Free(mod->extradata);
+	memset(mod, 0, sizeof *mod);
+}
+
+void
+Mod_FreeAll(void)
+{
+	int i;
+
+	for(i=0; i<mod_numknown; i++){
+		if(mod_known[i].extradatasize)
+			Mod_Free(&mod_known[i]);
+	}
+}
--- /dev/null
+++ b/r_part.c
@@ -1,0 +1,204 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+vec3_t r_pright, r_pup, r_ppn;
+
+#define PARTICLE_33     0
+#define PARTICLE_66     1
+#define PARTICLE_OPAQUE 2
+
+typedef struct
+{
+	particle_t *particle;
+	int         level;
+	int         color;
+} partparms_t;
+
+static partparms_t partparms;
+
+static byte BlendParticle33( int pcolor, int dstcolor )
+{
+	return vid.alphamap[pcolor + dstcolor*256];
+}
+
+static byte BlendParticle66( int pcolor, int dstcolor )
+{
+	return vid.alphamap[pcolor*256+dstcolor];
+}
+
+static byte BlendParticle100( int pcolor, int /*dstcolor*/ )
+{
+	return pcolor;
+}
+
+/*
+** R_DrawParticle
+**
+** Yes, this is amazingly slow, but it's the C reference
+** implementation and should be both robust and vaguely
+** understandable.  The only time this path should be
+** executed is if we're debugging on x86 or if we're
+** recompiling and deploying on a non-x86 platform.
+**
+** To minimize error and improve readability I went the 
+** function pointer route.  This exacts some overhead, but
+** it pays off in clean and easy to understand code.
+*/
+void R_DrawParticle( void )
+{
+	particle_t *pparticle = partparms.particle;
+	int         level     = partparms.level;
+	vec3_t	local, transformed;
+	float	zi;
+	byte	*pdest;
+	short	*pz;
+	int      color = pparticle->color;
+	int		i, izi, pix, count, u, v;
+
+	/*
+	** transform the particle
+	*/
+	VectorSubtract (pparticle->origin, r_origin, local);
+
+	transformed[0] = DotProduct(local, r_pright);
+	transformed[1] = DotProduct(local, r_pup);
+	transformed[2] = DotProduct(local, r_ppn);		
+
+	if (transformed[2] < PARTICLE_Z_CLIP)
+		return;
+
+	/*
+	** bind the blend function pointer to the appropriate blender
+	*/
+	/*
+	byte  (*blendparticle)( int, int );
+	if ( level == PARTICLE_33 )
+		blendparticle = BlendParticle33;
+	else if ( level == PARTICLE_66 )
+		blendparticle = BlendParticle66;
+	else 
+		blendparticle = BlendParticle100;
+	*/
+
+	/*
+	** project the point
+	*/
+	// FIXME: preadjust xcenter and ycenter
+	zi = 1.0 / transformed[2];
+	u = (int)(xcenter + zi * transformed[0] + 0.5);
+	v = (int)(ycenter - zi * transformed[1] + 0.5);
+
+	if ((v > d_vrectbottom_particle) || 
+		(u > d_vrectright_particle) ||
+		(v < d_vrecty) ||
+		(u < d_vrectx))
+	{
+		return;
+	}
+
+	/*
+	** compute addresses of zbuffer, framebuffer, and 
+	** compute the Z-buffer reference value.
+	*/
+	pz = d_pzbuffer + (d_zwidth * v) + u;
+	pdest = d_viewbuffer + d_scantable[v] + u;
+	izi = (int)(zi * 0x8000);
+
+	/*
+	** determine the screen area covered by the particle,
+	** which also means clamping to a min and max
+	*/
+	pix = izi >> d_pix_shift;
+	if (pix < d_pix_min)
+		pix = d_pix_min;
+	else if (pix > d_pix_max)
+		pix = d_pix_max;
+
+	/*
+	** render the appropriate pixels
+	*/
+	count = pix;
+
+    switch (level) {
+    case PARTICLE_33 :
+        for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
+        {
+//FIXME--do it in blocks of 8?
+            for (i=0 ; i<pix ; i++)
+            {
+                if (pz[i] <= izi)
+                {
+                    pz[i]    = izi;
+                    pdest[i] = vid.alphamap[color + ((int)pdest[i]<<8)];
+                }
+            }
+        }
+        break;
+
+    case PARTICLE_66 :
+        for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
+        {
+            for (i=0 ; i<pix ; i++)
+            {
+                if (pz[i] <= izi)
+                {
+                    pz[i]    = izi;
+                    pdest[i] = vid.alphamap[(color<<8) + (int)pdest[i]];
+                }
+            }
+        }
+        break;
+
+    default:  //100
+        for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
+        {
+            for (i=0 ; i<pix ; i++)
+            {
+                if (pz[i] <= izi)
+                {
+                    pz[i]    = izi;
+                    pdest[i] = color;
+                }
+            }
+        }
+        break;
+    }
+}
+
+/*
+** R_DrawParticles
+**
+** Responsible for drawing all of the particles in the particle list
+** throughout the world.  Doesn't care if we're using the C path or
+** if we're using the asm path, it simply assigns a function pointer
+** and goes.
+*/
+void R_DrawParticles (void)
+{
+	particle_t *p;
+	int         i;
+	extern unsigned long fpu_sp24_cw, fpu_chop_cw;
+
+	VectorScale( vright, xscaleshrink, r_pright );
+	VectorScale( vup, yscaleshrink, r_pup );
+	VectorCopy( vpn, r_ppn );
+
+	for (p=r_newrefdef.particles, i=0 ; i<r_newrefdef.num_particles ; i++,p++)
+	{
+
+		if ( p->alpha > 0.66 )
+			partparms.level = PARTICLE_OPAQUE;
+		else if ( p->alpha > 0.33 )
+			partparms.level = PARTICLE_66;
+		else
+			partparms.level = PARTICLE_33;
+
+		partparms.particle = p;
+		partparms.color    = p->color;
+
+		R_DrawParticle();
+	}
+}
--- /dev/null
+++ b/r_poly.c
@@ -1,0 +1,1226 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+#define AFFINE_SPANLET_SIZE      16
+#define AFFINE_SPANLET_SIZE_BITS 4
+
+typedef struct
+{
+	byte     *pbase, *pdest;
+	short	 *pz;
+	fixed16_t s, t;
+	fixed16_t sstep, tstep;
+	int       izi, izistep, izistep_times_2;
+	int       spancount;
+	unsigned  u, v;
+} spanletvars_t;
+
+spanletvars_t s_spanletvars;
+
+static int r_polyblendcolor;
+
+static espan_t	*s_polygon_spans;
+
+polydesc_t	r_polydesc;
+
+msurface_t *r_alpha_surfaces;
+
+extern int *r_turb_turb;
+
+static int		clip_current;
+vec5_t	r_clip_verts[2][MAXWORKINGVERTS+2];
+
+static int		s_minindex, s_maxindex;
+
+static void R_DrawPoly( qboolean iswater );
+
+/*
+** R_DrawSpanletOpaque
+*/
+void R_DrawSpanletOpaque( void )
+{
+	unsigned btemp;
+
+	do
+	{
+		unsigned ts, tt;
+
+		ts = s_spanletvars.s >> 16;
+		tt = s_spanletvars.t >> 16;
+
+		btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
+		if (btemp != 255)
+		{
+			if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
+			{
+				*s_spanletvars.pz    = s_spanletvars.izi >> 16;
+				*s_spanletvars.pdest = btemp;
+			}
+		}
+
+		s_spanletvars.izi += s_spanletvars.izistep;
+		s_spanletvars.pdest++;
+		s_spanletvars.pz++;
+		s_spanletvars.s += s_spanletvars.sstep;
+		s_spanletvars.t += s_spanletvars.tstep;
+	} while (--s_spanletvars.spancount > 0);
+}
+
+/*
+** R_DrawSpanletTurbulentStipple33
+*/
+void R_DrawSpanletTurbulentStipple33( void )
+{
+	unsigned btemp;
+	int	     sturb, tturb;
+	byte    *pdest = s_spanletvars.pdest;
+	short   *pz    = s_spanletvars.pz;
+	int      izi   = s_spanletvars.izi;
+	
+	if ( s_spanletvars.v & 1 )
+	{
+		s_spanletvars.pdest += s_spanletvars.spancount;
+		s_spanletvars.pz    += s_spanletvars.spancount;
+
+		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+		else
+			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+		
+		if ( s_spanletvars.u & 1 )
+		{
+			izi += s_spanletvars.izistep;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+
+			pdest++;
+			pz++;
+			s_spanletvars.spancount--;
+		}
+
+		s_spanletvars.sstep   *= 2;
+		s_spanletvars.tstep   *= 2;
+
+		while ( s_spanletvars.spancount > 0 )
+		{
+			sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+			tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+			
+			btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+			
+			if ( *pz <= ( izi >> 16 ) )
+				*pdest = btemp;
+			
+			izi               += s_spanletvars.izistep_times_2;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+			
+			pdest += 2;
+			pz    += 2;
+			
+			s_spanletvars.spancount -= 2;
+		}
+	}
+}
+
+/*
+** R_DrawSpanletTurbulentStipple66
+*/
+void R_DrawSpanletTurbulentStipple66( void )
+{
+	unsigned btemp;
+	int	     sturb, tturb;
+	byte    *pdest = s_spanletvars.pdest;
+	short   *pz    = s_spanletvars.pz;
+	int      izi   = s_spanletvars.izi;
+	
+	if ( !( s_spanletvars.v & 1 ) )
+	{
+		s_spanletvars.pdest += s_spanletvars.spancount;
+		s_spanletvars.pz    += s_spanletvars.spancount;
+
+		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+		else
+			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+		
+		if ( s_spanletvars.u & 1 )
+		{
+			izi += s_spanletvars.izistep;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+
+			pdest++;
+			pz++;
+			s_spanletvars.spancount--;
+		}
+
+		s_spanletvars.sstep   *= 2;
+		s_spanletvars.tstep   *= 2;
+
+		while ( s_spanletvars.spancount > 0 )
+		{
+			sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+			tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+			
+			btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+			
+			if ( *pz <= ( izi >> 16 ) )
+				*pdest = btemp;
+			
+			izi               += s_spanletvars.izistep_times_2;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+			
+			pdest += 2;
+			pz    += 2;
+			
+			s_spanletvars.spancount -= 2;
+		}
+	}
+	else
+	{
+		s_spanletvars.pdest += s_spanletvars.spancount;
+		s_spanletvars.pz    += s_spanletvars.spancount;
+
+		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+		else
+			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+		
+		while ( s_spanletvars.spancount > 0 )
+		{
+			sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+			tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+			
+			btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+			
+			if ( *pz <= ( izi >> 16 ) )
+				*pdest = btemp;
+			
+			izi               += s_spanletvars.izistep;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+			
+			pdest++;
+			pz++;
+			
+			s_spanletvars.spancount--;
+		}
+	}
+}
+
+/*
+** R_DrawSpanletTurbulentBlended
+*/
+void R_DrawSpanletTurbulentBlended66( void )
+{
+	unsigned btemp;
+	int	     sturb, tturb;
+
+	do
+	{
+		sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+		tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+
+		btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+
+		if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) )
+			*s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest];
+
+		s_spanletvars.izi += s_spanletvars.izistep;
+		s_spanletvars.pdest++;
+		s_spanletvars.pz++;
+		s_spanletvars.s += s_spanletvars.sstep;
+		s_spanletvars.t += s_spanletvars.tstep;
+
+	} while ( --s_spanletvars.spancount > 0 );
+}
+
+void R_DrawSpanletTurbulentBlended33( void )
+{
+	unsigned btemp;
+	int	     sturb, tturb;
+
+	do
+	{
+		sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+		tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+
+		btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+
+		if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) )
+			*s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256];
+
+		s_spanletvars.izi += s_spanletvars.izistep;
+		s_spanletvars.pdest++;
+		s_spanletvars.pz++;
+		s_spanletvars.s += s_spanletvars.sstep;
+		s_spanletvars.t += s_spanletvars.tstep;
+
+	} while ( --s_spanletvars.spancount > 0 );
+}
+
+/*
+** R_DrawSpanlet33
+*/
+void R_DrawSpanlet33( void )
+{
+	unsigned btemp;
+
+	do
+	{
+		unsigned ts, tt;
+
+		ts = s_spanletvars.s >> 16;
+		tt = s_spanletvars.t >> 16;
+
+		btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
+
+		if ( btemp != 255 )
+		{
+			if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
+			{
+				*s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256];
+			}
+		}
+
+		s_spanletvars.izi += s_spanletvars.izistep;
+		s_spanletvars.pdest++;
+		s_spanletvars.pz++;
+		s_spanletvars.s += s_spanletvars.sstep;
+		s_spanletvars.t += s_spanletvars.tstep;
+	} while (--s_spanletvars.spancount > 0);
+}
+
+void R_DrawSpanletConstant33( void )
+{
+	do
+	{
+		if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
+		{
+			*s_spanletvars.pdest = vid.alphamap[r_polyblendcolor+*s_spanletvars.pdest*256];
+		}
+
+		s_spanletvars.izi += s_spanletvars.izistep;
+		s_spanletvars.pdest++;
+		s_spanletvars.pz++;
+	} while (--s_spanletvars.spancount > 0);
+}
+
+/*
+** R_DrawSpanlet66
+*/
+void R_DrawSpanlet66( void )
+{
+	unsigned btemp;
+
+	do
+	{
+		unsigned ts, tt;
+
+		ts = s_spanletvars.s >> 16;
+		tt = s_spanletvars.t >> 16;
+
+		btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
+
+		if ( btemp != 255 )
+		{
+			if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
+			{
+				*s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest];
+			}
+		}
+
+		s_spanletvars.izi += s_spanletvars.izistep;
+		s_spanletvars.pdest++;
+		s_spanletvars.pz++;
+		s_spanletvars.s += s_spanletvars.sstep;
+		s_spanletvars.t += s_spanletvars.tstep;
+	} while (--s_spanletvars.spancount > 0);
+}
+
+/*
+** R_DrawSpanlet33Stipple
+*/
+void R_DrawSpanlet33Stipple( void )
+{
+	unsigned btemp;
+	byte    *pdest = s_spanletvars.pdest;
+	short   *pz    = s_spanletvars.pz;
+	int      izi   = s_spanletvars.izi;
+	
+	if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) )
+	{
+		s_spanletvars.pdest += s_spanletvars.spancount;
+		s_spanletvars.pz    += s_spanletvars.spancount;
+
+		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+		else
+			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+		
+		if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) )
+		{
+			izi += s_spanletvars.izistep;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+
+			pdest++;
+			pz++;
+			s_spanletvars.spancount--;
+		}
+
+		s_spanletvars.sstep *= 2;
+		s_spanletvars.tstep *= 2;
+
+		while ( s_spanletvars.spancount > 0 )
+		{
+			unsigned s = s_spanletvars.s >> 16;
+			unsigned t = s_spanletvars.t >> 16;
+
+			btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
+			
+			if ( btemp != 255 )
+			{
+				if ( *pz <= ( izi >> 16 ) )
+					*pdest = btemp;
+			}
+			
+			izi               += s_spanletvars.izistep_times_2;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+			
+			pdest += 2;
+			pz    += 2;
+			
+			s_spanletvars.spancount -= 2;
+		}
+	}
+}
+
+/*
+** R_DrawSpanlet66Stipple
+*/
+void R_DrawSpanlet66Stipple( void )
+{
+	unsigned btemp;
+	byte    *pdest = s_spanletvars.pdest;
+	short   *pz    = s_spanletvars.pz;
+	int      izi   = s_spanletvars.izi;
+
+	s_spanletvars.pdest += s_spanletvars.spancount;
+	s_spanletvars.pz    += s_spanletvars.spancount;
+
+	if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+		s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+	else
+		s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+
+	if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) )
+	{
+		if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) )
+		{
+			izi += s_spanletvars.izistep;
+			s_spanletvars.s += s_spanletvars.sstep;
+			s_spanletvars.t += s_spanletvars.tstep;
+
+			pdest++;
+			pz++;
+			s_spanletvars.spancount--;
+		}
+
+		s_spanletvars.sstep *= 2;
+		s_spanletvars.tstep *= 2;
+
+		while ( s_spanletvars.spancount > 0 )
+		{
+			unsigned s = s_spanletvars.s >> 16;
+			unsigned t = s_spanletvars.t >> 16;
+			
+			btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
+
+			if ( btemp != 255 )
+			{
+				if ( *pz <= ( izi >> 16 ) )
+					*pdest = btemp;
+			}
+			
+			izi             += s_spanletvars.izistep_times_2;
+			s_spanletvars.s += s_spanletvars.sstep;
+			s_spanletvars.t += s_spanletvars.tstep;
+			
+			pdest += 2;
+			pz    += 2;
+			
+			s_spanletvars.spancount -= 2;
+		}
+	}
+	else
+	{
+		while ( s_spanletvars.spancount > 0 )
+		{
+			unsigned s = s_spanletvars.s >> 16;
+			unsigned t = s_spanletvars.t >> 16;
+			
+			btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
+			
+			if ( btemp != 255 )
+			{
+				if ( *pz <= ( izi >> 16 ) )
+					*pdest = btemp;
+			}
+			
+			izi             += s_spanletvars.izistep;
+			s_spanletvars.s += s_spanletvars.sstep;
+			s_spanletvars.t += s_spanletvars.tstep;
+			
+			pdest++;
+			pz++;
+			
+			s_spanletvars.spancount--;
+		}
+	}
+}
+
+/*
+** R_ClipPolyFace
+**
+** Clips the winding at clip_verts[clip_current] and changes clip_current
+** Throws out the back side
+*/
+int R_ClipPolyFace (int nump, clipplane_t *pclipplane)
+{
+	int		i, outcount;
+	float	dists[MAXWORKINGVERTS+3];
+	float	frac, clipdist, *pclipnormal;
+	float	*in, *instep, *outstep, *vert2;
+
+	clipdist = pclipplane->dist;
+	pclipnormal = pclipplane->normal;
+	
+// calc dists
+	if (clip_current)
+	{
+		in = r_clip_verts[1][0];
+		outstep = r_clip_verts[0][0];
+		clip_current = 0;
+	}
+	else
+	{
+		in = r_clip_verts[0][0];
+		outstep = r_clip_verts[1][0];
+		clip_current = 1;
+	}
+	
+	instep = in;
+	for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
+	{
+		dists[i] = DotProduct (instep, pclipnormal) - clipdist;
+	}
+	
+// handle wraparound case
+	dists[nump] = dists[0];
+	memcpy (instep, in, sizeof (vec5_t));
+
+
+// clip the winding
+	instep = in;
+	outcount = 0;
+
+	for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
+	{
+		if (dists[i] >= 0)
+		{
+			memcpy (outstep, instep, sizeof (vec5_t));
+			outstep += sizeof (vec5_t) / sizeof (float);
+			outcount++;
+		}
+
+		if (dists[i] == 0 || dists[i+1] == 0)
+			continue;
+
+		if ( (dists[i] > 0) == (dists[i+1] > 0) )
+			continue;
+			
+	// split it into a new vertex
+		frac = dists[i] / (dists[i] - dists[i+1]);
+			
+		vert2 = instep + sizeof (vec5_t) / sizeof (float);
+		
+		outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
+		outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
+		outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
+		outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
+		outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
+
+		outstep += sizeof (vec5_t) / sizeof (float);
+		outcount++;
+	}	
+	
+	return outcount;
+}
+
+/*
+** R_PolygonDrawSpans
+*/
+void R_PolygonDrawSpans(espan_t *pspan, qboolean iswater )
+{
+	int			count;
+	fixed16_t	snext, tnext;
+	float		sdivz, tdivz, zi, z, du, dv, spancountminus1;
+	float		sdivzspanletstepu, tdivzspanletstepu, zispanletstepu;
+
+	s_spanletvars.pbase = cacheblock;
+
+	if ( iswater )
+		r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
+
+	sdivzspanletstepu = d_sdivzstepu * AFFINE_SPANLET_SIZE;
+	tdivzspanletstepu = d_tdivzstepu * AFFINE_SPANLET_SIZE;
+	zispanletstepu = d_zistepu * AFFINE_SPANLET_SIZE;
+
+// we count on FP exceptions being turned off to avoid range problems
+	s_spanletvars.izistep = (int)(d_zistepu * 0x8000 * 0x10000);
+	s_spanletvars.izistep_times_2 = s_spanletvars.izistep * 2;
+
+	s_spanletvars.pz = 0;
+
+	do
+	{
+		s_spanletvars.pdest   = (byte *)d_viewbuffer + ( d_scantable[pspan->v] /*r_screenwidth * pspan->v*/) + pspan->u;
+		s_spanletvars.pz      = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
+		s_spanletvars.u       = pspan->u;
+		s_spanletvars.v       = pspan->v;
+
+		count = pspan->count;
+
+		if (count <= 0)
+			goto NextSpan;
+
+	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
+		du = (float)pspan->u;
+		dv = (float)pspan->v;
+
+		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+
+		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+	// we count on FP exceptions being turned off to avoid range problems
+		s_spanletvars.izi = (int)(zi * 0x8000 * 0x10000);
+
+		s_spanletvars.s = (int)(sdivz * z) + sadjust;
+		s_spanletvars.t = (int)(tdivz * z) + tadjust;
+
+		if ( !iswater )
+		{
+			if (s_spanletvars.s > bbextents)
+				s_spanletvars.s = bbextents;
+			else if (s_spanletvars.s < 0)
+				s_spanletvars.s = 0;
+
+			if (s_spanletvars.t > bbextentt)
+				s_spanletvars.t = bbextentt;
+			else if (s_spanletvars.t < 0)
+				s_spanletvars.t = 0;
+		}
+
+		do
+		{
+		// calculate s and t at the far end of the span
+			if (count >= AFFINE_SPANLET_SIZE )
+				s_spanletvars.spancount = AFFINE_SPANLET_SIZE;
+			else
+				s_spanletvars.spancount = count;
+
+			count -= s_spanletvars.spancount;
+
+			if (count)
+			{
+			// calculate s/z, t/z, zi->fixed s and t at far end of span,
+			// calculate s and t steps across span by shifting
+				sdivz += sdivzspanletstepu;
+				tdivz += tdivzspanletstepu;
+				zi += zispanletstepu;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+				snext = (int)(sdivz * z) + sadjust;
+				tnext = (int)(tdivz * z) + tadjust;
+
+				if ( !iswater )
+				{
+					if (snext > bbextents)
+						snext = bbextents;
+					else if (snext < AFFINE_SPANLET_SIZE)
+						snext = AFFINE_SPANLET_SIZE;	// prevent round-off error on <0 steps from
+									//  from causing overstepping & running off the
+									//  edge of the texture
+
+					if (tnext > bbextentt)
+						tnext = bbextentt;
+					else if (tnext < AFFINE_SPANLET_SIZE)
+						tnext = AFFINE_SPANLET_SIZE;	// guard against round-off error on <0 steps
+				}
+
+				s_spanletvars.sstep = (snext - s_spanletvars.s) >> AFFINE_SPANLET_SIZE_BITS;
+				s_spanletvars.tstep = (tnext - s_spanletvars.t) >> AFFINE_SPANLET_SIZE_BITS;
+			}
+			else
+			{
+			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+			// can't step off polygon), clamp, calculate s and t steps across
+			// span by division, biasing steps low so we don't run off the
+			// texture
+				spancountminus1 = (float)(s_spanletvars.spancount - 1);
+				sdivz += d_sdivzstepu * spancountminus1;
+				tdivz += d_tdivzstepu * spancountminus1;
+				zi += d_zistepu * spancountminus1;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+				snext = (int)(sdivz * z) + sadjust;
+				tnext = (int)(tdivz * z) + tadjust;
+
+				if ( !iswater )
+				{
+					if (snext > bbextents)
+						snext = bbextents;
+					else if (snext < AFFINE_SPANLET_SIZE)
+						snext = AFFINE_SPANLET_SIZE;	// prevent round-off error on <0 steps from
+									//  from causing overstepping & running off the
+									//  edge of the texture
+
+					if (tnext > bbextentt)
+						tnext = bbextentt;
+					else if (tnext < AFFINE_SPANLET_SIZE)
+						tnext = AFFINE_SPANLET_SIZE;	// guard against round-off error on <0 steps
+				}
+
+				if (s_spanletvars.spancount > 1)
+				{
+					s_spanletvars.sstep = (snext - s_spanletvars.s) / (s_spanletvars.spancount - 1);
+					s_spanletvars.tstep = (tnext - s_spanletvars.t) / (s_spanletvars.spancount - 1);
+				}
+			}
+
+			if ( iswater )
+			{
+				s_spanletvars.s = s_spanletvars.s & ((CYCLE<<16)-1);
+				s_spanletvars.t = s_spanletvars.t & ((CYCLE<<16)-1);
+			}
+
+			r_polydesc.drawspanlet();
+
+			s_spanletvars.s = snext;
+			s_spanletvars.t = tnext;
+
+		} while (count > 0);
+
+NextSpan:
+		pspan++;
+
+	} while (pspan->count != DS_SPAN_LIST_END);
+}
+
+/*
+**
+** R_PolygonScanLeftEdge
+**
+** Goes through the polygon and scans the left edge, filling in 
+** screen coordinate data for the spans
+*/
+void R_PolygonScanLeftEdge (void)
+{
+	int			i, v, itop, ibottom, lmaxindex;
+	emitpoint_t	*pvert, *pnext;
+	espan_t		*pspan;
+	float		du, dv, vtop, vbottom, slope;
+	fixed16_t	u, u_step;
+
+	pspan = s_polygon_spans;
+	i = s_minindex;
+	if (i == 0)
+		i = r_polydesc.nump;
+
+	lmaxindex = s_maxindex;
+	if (lmaxindex == 0)
+		lmaxindex = r_polydesc.nump;
+
+	vtop = ceil (r_polydesc.pverts[i].v);
+
+	do
+	{
+		pvert = &r_polydesc.pverts[i];
+		pnext = pvert - 1;
+
+		vbottom = ceil (pnext->v);
+
+		if (vtop < vbottom)
+		{
+			du = pnext->u - pvert->u;
+			dv = pnext->v - pvert->v;
+
+			slope = du / dv;
+			u_step = (int)(slope * 0x10000);
+		// adjust u to ceil the integer portion
+			u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
+					(0x10000 - 1);
+			itop = (int)vtop;
+			ibottom = (int)vbottom;
+
+			for (v=itop ; v<ibottom ; v++)
+			{
+				pspan->u = u >> 16;
+				pspan->v = v;
+				u += u_step;
+				pspan++;
+			}
+		}
+
+		vtop = vbottom;
+
+		i--;
+		if (i == 0)
+			i = r_polydesc.nump;
+
+	} while (i != lmaxindex);
+}
+
+/*
+** R_PolygonScanRightEdge
+**
+** Goes through the polygon and scans the right edge, filling in
+** count values.
+*/
+void R_PolygonScanRightEdge (void)
+{
+	int			i, v, itop, ibottom;
+	emitpoint_t	*pvert, *pnext;
+	espan_t		*pspan;
+	float		du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
+	fixed16_t	u, u_step;
+
+	pspan = s_polygon_spans;
+	i = s_minindex;
+
+	vvert = r_polydesc.pverts[i].v;
+	if (vvert < r_refdef.fvrecty_adj)
+		vvert = r_refdef.fvrecty_adj;
+	if (vvert > r_refdef.fvrectbottom_adj)
+		vvert = r_refdef.fvrectbottom_adj;
+
+	vtop = ceil (vvert);
+
+	do
+	{
+		pvert = &r_polydesc.pverts[i];
+		pnext = pvert + 1;
+
+		vnext = pnext->v;
+		if (vnext < r_refdef.fvrecty_adj)
+			vnext = r_refdef.fvrecty_adj;
+		if (vnext > r_refdef.fvrectbottom_adj)
+			vnext = r_refdef.fvrectbottom_adj;
+
+		vbottom = ceil (vnext);
+
+		if (vtop < vbottom)
+		{
+			uvert = pvert->u;
+			if (uvert < r_refdef.fvrectx_adj)
+				uvert = r_refdef.fvrectx_adj;
+			if (uvert > r_refdef.fvrectright_adj)
+				uvert = r_refdef.fvrectright_adj;
+
+			unext = pnext->u;
+			if (unext < r_refdef.fvrectx_adj)
+				unext = r_refdef.fvrectx_adj;
+			if (unext > r_refdef.fvrectright_adj)
+				unext = r_refdef.fvrectright_adj;
+
+			du = unext - uvert;
+			dv = vnext - vvert;
+			slope = du / dv;
+			u_step = (int)(slope * 0x10000);
+		// adjust u to ceil the integer portion
+			u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
+					(0x10000 - 1);
+			itop = (int)vtop;
+			ibottom = (int)vbottom;
+
+			for (v=itop ; v<ibottom ; v++)
+			{
+				pspan->count = (u >> 16) - pspan->u;
+				u += u_step;
+				pspan++;
+			}
+		}
+
+		vtop = vbottom;
+		vvert = vnext;
+
+		i++;
+		if (i == r_polydesc.nump)
+			i = 0;
+
+	} while (i != s_maxindex);
+
+	pspan->count = DS_SPAN_LIST_END;	// mark the end of the span list
+}
+
+/*
+** R_ClipAndDrawPoly
+*/
+void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured )
+{
+	emitpoint_t	outverts[MAXWORKINGVERTS+3], *pout;
+	float		*pv;
+	int			i, nump;
+	float		scale;
+	vec3_t		transformed, local;
+
+	if ( !textured )
+	{
+		r_polydesc.drawspanlet = R_DrawSpanletConstant33;
+	}
+	else
+	{
+
+		/*
+		** choose the correct spanlet routine based on alpha
+		*/
+		if ( alpha == 1 )
+		{
+			// isturbulent is ignored because we know that turbulent surfaces
+			// can't be opaque
+			r_polydesc.drawspanlet = R_DrawSpanletOpaque;
+		}
+		else
+		{
+			if ( sw_stipplealpha->value )
+			{
+				if ( isturbulent )
+				{
+					if ( alpha > 0.33 )
+						r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple66;
+					else 
+						r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple33;
+				}
+				else
+				{
+					if ( alpha > 0.33 )
+						r_polydesc.drawspanlet = R_DrawSpanlet66Stipple;
+					else 
+						r_polydesc.drawspanlet = R_DrawSpanlet33Stipple;
+				}
+			}
+			else
+			{
+				if ( isturbulent )
+				{
+					if ( alpha > 0.33 )
+						r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended66;
+					else
+						r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended33;
+				}
+				else
+				{
+					if ( alpha > 0.33 )
+						r_polydesc.drawspanlet = R_DrawSpanlet66;
+					else 
+						r_polydesc.drawspanlet = R_DrawSpanlet33;
+				}
+			}
+		}
+	}
+
+	// clip to the frustum in worldspace
+	nump = r_polydesc.nump;
+	clip_current = 0;
+
+	for (i=0 ; i<4 ; i++)
+	{
+		nump = R_ClipPolyFace (nump, &view_clipplanes[i]);
+		if (nump < 3)
+			return;
+		if (nump > MAXWORKINGVERTS)
+			ri.Sys_Error(ERR_DROP, "R_ClipAndDrawPoly: too many points: %d", nump );
+	}
+
+// transform vertices into viewspace and project
+	pv = &r_clip_verts[clip_current][0][0];
+
+	for (i=0 ; i<nump ; i++)
+	{
+		VectorSubtract (pv, r_origin, local);
+		TransformVector (local, transformed);
+
+		if (transformed[2] < NEAR_CLIP)
+			transformed[2] = NEAR_CLIP;
+
+		pout = &outverts[i];
+		pout->zi = 1.0 / transformed[2];
+
+		pout->s = pv[3];
+		pout->t = pv[4];
+		
+		scale = xscale * pout->zi;
+		pout->u = (xcenter + scale * transformed[0]);
+
+		scale = yscale * pout->zi;
+		pout->v = (ycenter - scale * transformed[1]);
+
+		pv += sizeof (vec5_t) / sizeof (*pv);
+	}
+
+// draw it
+	r_polydesc.nump = nump;
+	r_polydesc.pverts = outverts;
+
+	R_DrawPoly( isturbulent );
+}
+
+/*
+** R_BuildPolygonFromSurface
+*/
+void R_BuildPolygonFromSurface(msurface_t *fa)
+{
+	int			i, lindex, lnumverts;
+	medge_t		*pedges, *r_pedge;
+	float		*vec;
+	vec5_t     *pverts;
+	float       tmins[2] = { 0, 0 };
+
+	r_polydesc.nump = 0;
+
+	// reconstruct the polygon
+	pedges = currentmodel->edges;
+	lnumverts = fa->numedges;
+
+	pverts = r_clip_verts[0];
+
+	for (i=0 ; i<lnumverts ; i++)
+	{
+		lindex = currentmodel->surfedges[fa->firstedge + i];
+
+		if (lindex > 0)
+		{
+			r_pedge = &pedges[lindex];
+			vec = currentmodel->vertexes[r_pedge->v[0]].position;
+		}
+		else
+		{
+			r_pedge = &pedges[-lindex];
+			vec = currentmodel->vertexes[r_pedge->v[1]].position;
+		}
+
+		VectorCopy (vec, pverts[i] );
+	}
+
+	VectorCopy( fa->texinfo->vecs[0], r_polydesc.vright );
+	VectorCopy( fa->texinfo->vecs[1], r_polydesc.vup );
+	VectorCopy( fa->plane->normal, r_polydesc.vpn );
+	VectorCopy( r_origin, r_polydesc.viewer_position );
+
+	if ( fa->flags & SURF_PLANEBACK )
+	{
+		VectorSubtract( vec3_origin, r_polydesc.vpn, r_polydesc.vpn );
+	}
+
+	if ( fa->texinfo->flags & SURF_WARP )
+	{
+		r_polydesc.pixels       = fa->texinfo->image->pixels[0];
+		r_polydesc.pixel_width  = fa->texinfo->image->width;
+		r_polydesc.pixel_height = fa->texinfo->image->height;
+	}
+	else
+	{
+		surfcache_t *scache;
+
+		scache = D_CacheSurface( fa, 0 );
+
+		r_polydesc.pixels       = scache->data;
+		r_polydesc.pixel_width  = scache->width;
+		r_polydesc.pixel_height = scache->height;
+
+		tmins[0] = fa->texturemins[0];
+		tmins[1] = fa->texturemins[1];
+	}
+
+	r_polydesc.dist = DotProduct( r_polydesc.vpn, pverts[0] );
+
+	r_polydesc.s_offset = fa->texinfo->vecs[0][3] - tmins[0];
+	r_polydesc.t_offset = fa->texinfo->vecs[1][3] - tmins[1];
+
+	// scrolling texture addition
+	if (fa->texinfo->flags & SURF_FLOWING)
+	{
+		r_polydesc.s_offset += -128 * ( (r_newrefdef.time*0.25) - (int)(r_newrefdef.time*0.25) );
+	}
+
+	r_polydesc.nump = lnumverts;
+}
+
+/*
+** R_PolygonCalculateGradients
+*/
+void R_PolygonCalculateGradients (void)
+{
+	vec3_t		p_normal, p_saxis, p_taxis;
+	float		distinv;
+
+	TransformVector (r_polydesc.vpn, p_normal);
+	TransformVector (r_polydesc.vright, p_saxis);
+	TransformVector (r_polydesc.vup, p_taxis);
+
+	distinv = 1.0 / (-(DotProduct (r_polydesc.viewer_position, r_polydesc.vpn)) + r_polydesc.dist );
+
+	d_sdivzstepu  =  p_saxis[0] * xscaleinv;
+	d_sdivzstepv  = -p_saxis[1] * yscaleinv;
+	d_sdivzorigin =  p_saxis[2] - xcenter * d_sdivzstepu - ycenter * d_sdivzstepv;
+
+	d_tdivzstepu  =  p_taxis[0] * xscaleinv;
+	d_tdivzstepv  = -p_taxis[1] * yscaleinv;
+	d_tdivzorigin =  p_taxis[2] - xcenter * d_tdivzstepu - ycenter * d_tdivzstepv;
+
+	d_zistepu =   p_normal[0] * xscaleinv * distinv;
+	d_zistepv =  -p_normal[1] * yscaleinv * distinv;
+	d_ziorigin =  p_normal[2] * distinv - xcenter * d_zistepu - ycenter * d_zistepv;
+
+	sadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vright) + r_polydesc.s_offset ) * 0x10000 );
+	tadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vup   ) + r_polydesc.t_offset ) * 0x10000 );
+
+// -1 (-epsilon) so we never wander off the edge of the texture
+	bbextents = (r_polydesc.pixel_width << 16) - 1;
+	bbextentt = (r_polydesc.pixel_height << 16) - 1;
+}
+
+/*
+** R_DrawPoly
+**
+** Polygon drawing function.  Uses the polygon described in r_polydesc
+** to calculate edges and gradients, then renders the resultant spans.
+**
+** This should NOT be called externally since it doesn't do clipping!
+*/
+static void R_DrawPoly( qboolean iswater )
+{
+	int			i, nump;
+	float		ymin, ymax;
+	emitpoint_t	*pverts;
+	espan_t	spans[MAXHEIGHT+1];
+
+	s_polygon_spans = spans;
+
+// find the top and bottom vertices, and make sure there's at least one scan to
+// draw
+	ymin = 999999.9;
+	ymax = -999999.9;
+	pverts = r_polydesc.pverts;
+
+	for (i=0 ; i<r_polydesc.nump ; i++)
+	{
+		if (pverts->v < ymin)
+		{
+			ymin = pverts->v;
+			s_minindex = i;
+		}
+
+		if (pverts->v > ymax)
+		{
+			ymax = pverts->v;
+			s_maxindex = i;
+		}
+
+		pverts++;
+	}
+
+	ymin = ceil (ymin);
+	ymax = ceil (ymax);
+
+	if (ymin >= ymax)
+		return;		// doesn't cross any scans at all
+
+	cachewidth = r_polydesc.pixel_width;
+	cacheblock = r_polydesc.pixels;
+
+// copy the first vertex to the last vertex, so we don't have to deal with
+// wrapping
+	nump = r_polydesc.nump;
+	pverts = r_polydesc.pverts;
+	pverts[nump] = pverts[0];
+
+	R_PolygonCalculateGradients ();
+	R_PolygonScanLeftEdge ();
+	R_PolygonScanRightEdge ();
+
+	R_PolygonDrawSpans( s_polygon_spans, iswater );
+}
+
+/*
+** R_DrawAlphaSurfaces
+*/
+void R_DrawAlphaSurfaces( void )
+{
+	msurface_t *s = r_alpha_surfaces;
+
+	currentmodel = r_worldmodel;
+
+	modelorg[0] = -r_origin[0];
+	modelorg[1] = -r_origin[1];
+	modelorg[2] = -r_origin[2];
+
+	while ( s )
+	{
+		R_BuildPolygonFromSurface( s );
+
+		if (s->texinfo->flags & SURF_TRANS66)
+			R_ClipAndDrawPoly( 0.60f, ( s->texinfo->flags & SURF_WARP) != 0, true );
+		else
+			R_ClipAndDrawPoly( 0.30f, ( s->texinfo->flags & SURF_WARP) != 0, true );
+
+		s = s->nextalphasurface;
+	}
+	
+	r_alpha_surfaces = NULL;
+}
+
+/*
+** R_IMFlatShadedQuad
+*/
+void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha )
+{
+	vec3_t s0, s1;
+
+	r_polydesc.nump = 4;
+	VectorCopy( r_origin, r_polydesc.viewer_position );
+
+	VectorCopy( a, r_clip_verts[0][0] );
+	VectorCopy( b, r_clip_verts[0][1] );
+	VectorCopy( c, r_clip_verts[0][2] );
+	VectorCopy( d, r_clip_verts[0][3] );
+
+	r_clip_verts[0][0][3] = 0;
+	r_clip_verts[0][1][3] = 0;
+	r_clip_verts[0][2][3] = 0;
+	r_clip_verts[0][3][3] = 0;
+
+	r_clip_verts[0][0][4] = 0;
+	r_clip_verts[0][1][4] = 0;
+	r_clip_verts[0][2][4] = 0;
+	r_clip_verts[0][3][4] = 0;
+
+	VectorSubtract( d, c, s0 );
+	VectorSubtract( c, b, s1 );
+	CrossProduct( s0, s1, r_polydesc.vpn );
+	VectorNormalize( r_polydesc.vpn );
+
+	r_polydesc.dist = DotProduct( r_polydesc.vpn, r_clip_verts[0][0] );
+
+	r_polyblendcolor = color;
+
+	R_ClipAndDrawPoly( alpha, false, false );
+}
+
--- /dev/null
+++ b/r_polyse.c
@@ -1,0 +1,1147 @@
+// d_polyset.c: routines for drawing sets of polygons sharing the same
+// texture (used for Alias models)
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+int	rand1k[] = {
+#include "rand1k.h"
+};
+
+#define MASK_1K	0x3FF
+
+int		rand1k_index = 0;
+
+// TODO: put in span spilling to shrink list size
+// !!! if this is changed, it must be changed in d_polysa.s too !!!
+#define DPS_MAXSPANS			MAXHEIGHT+1	
+									// 1 extra for spanpackage that marks end
+
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct {
+	void			*pdest;
+	short			*pz;
+	int				count;
+	byte			*ptex;
+	int				sfrac, tfrac, light, zi;
+} spanpackage_t;
+
+typedef struct {
+	int		isflattop;
+	int		numleftedges;
+	int		*pleftedgevert0;
+	int		*pleftedgevert1;
+	int		*pleftedgevert2;
+	int		numrightedges;
+	int		*prightedgevert0;
+	int		*prightedgevert1;
+	int		*prightedgevert2;
+} edgetable;
+
+aliastriangleparms_t aliastriangleparms;
+
+int	r_p0[6], r_p1[6], r_p2[6];
+
+byte		*d_pcolormap;
+
+int			d_aflatcolor;
+int			d_xdenom;
+
+edgetable	*pedgetable;
+
+edgetable	edgetables[12] = {
+	{0, 1, r_p0, r_p2, NULL, 2, r_p0, r_p1, r_p2 },
+	{0, 2, r_p1, r_p0, r_p2,   1, r_p1, r_p2, NULL},
+	{1, 1, r_p0, r_p2, NULL, 1, r_p1, r_p2, NULL},
+	{0, 1, r_p1, r_p0, NULL, 2, r_p1, r_p2, r_p0 },
+	{0, 2, r_p0, r_p2, r_p1,   1, r_p0, r_p1, NULL},
+	{0, 1, r_p2, r_p1, NULL, 1, r_p2, r_p0, NULL},
+	{0, 1, r_p2, r_p1, NULL, 2, r_p2, r_p0, r_p1 },
+	{0, 2, r_p2, r_p1, r_p0,   1, r_p2, r_p0, NULL},
+	{0, 1, r_p1, r_p0, NULL, 1, r_p1, r_p2, NULL},
+	{1, 1, r_p2, r_p1, NULL, 1, r_p0, r_p1, NULL},
+	{1, 1, r_p1, r_p0, NULL, 1, r_p2, r_p0, NULL},
+	{0, 1, r_p0, r_p2, NULL, 1, r_p0, r_p1, NULL},
+};
+
+// FIXME: some of these can become statics
+int				a_sstepxfrac, a_tstepxfrac, r_lstepx, a_ststepxwhole;
+int				r_sstepx, r_tstepx, r_lstepy, r_sstepy, r_tstepy;
+int				r_zistepx, r_zistepy;
+int				d_aspancount, d_countextrastep;
+
+spanpackage_t			*a_spans;
+spanpackage_t			*d_pedgespanpackage;
+static int				ystart;
+byte					*d_pdest, *d_ptex;
+short					*d_pz;
+int						d_sfrac, d_tfrac, d_light, d_zi;
+int						d_ptexextrastep, d_sfracextrastep;
+int						d_tfracextrastep, d_lightextrastep, d_pdestextrastep;
+int						d_lightbasestep, d_pdestbasestep, d_ptexbasestep;
+int						d_sfracbasestep, d_tfracbasestep;
+int						d_ziextrastep, d_zibasestep;
+int						d_pzextrastep, d_pzbasestep;
+
+typedef struct {
+	int		quotient;
+	int		remainder;
+} adivtab_t;
+
+static adivtab_t	adivtab[32*32] = {
+#include "adivtab.h"
+};
+
+byte	*skintable[MAX_LBM_HEIGHT];
+int		skinwidth;
+byte	*skinstart;
+
+void	(*d_pdrawspans)(spanpackage_t *pspanpackage);
+
+void R_PolysetDrawSpans8_33 (spanpackage_t *pspanpackage);
+void R_PolysetDrawSpans8_66 (spanpackage_t *pspanpackage);
+void R_PolysetDrawSpans8_Opaque (spanpackage_t *pspanpackage);
+
+void R_PolysetDrawThreshSpans8 (spanpackage_t *pspanpackage);
+void R_PolysetCalcGradients (int skinwidth);
+void R_DrawNonSubdiv (void);
+void R_PolysetSetEdgeTable (void);
+void R_RasterizeAliasPolySmooth (void);
+void R_PolysetScanLeftEdge(int height);
+void R_PolysetScanLeftEdge_C(int height);
+
+// ======================
+// PGM
+// 64 65 66 67 68 69 70 71   72 73 74 75 76 77 78 79
+byte iractive = 0;
+byte irtable[256] = { 79, 78, 77, 76, 75, 74, 73, 72,		// black/white
+					  71, 70, 69, 68, 67, 66, 65, 64,
+					  64, 65, 66, 67, 68, 69, 70, 71,		// dark taupe
+					  72, 73, 74, 75, 76, 77, 78, 79,
+
+					  64, 65, 66, 67, 68, 69, 70, 71,		// slate grey
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  208, 208, 208, 208, 208, 208, 208, 208,	// unused?'
+					  64, 66, 68, 70, 72, 74, 76, 78,		// dark yellow
+					  
+					  64, 65, 66, 67, 68, 69, 70, 71,		// dark red
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  64, 65, 66, 67, 68, 69, 70, 71,		// grey/tan
+					  72, 73, 74, 75, 76, 77, 78, 79,
+
+					  64, 66, 68, 70, 72, 74, 76, 78,		// chocolate
+					  68, 67, 66, 65, 64, 65, 66, 67,		// mauve / teal
+					  68, 69, 70, 71, 72, 73, 74, 75,
+					  76, 76, 77, 77, 78, 78, 79, 79,		
+
+					  64, 65, 66, 67, 68, 69, 70, 71,		// more mauve
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  64, 65, 66, 67, 68, 69, 70, 71,		// olive
+					  72, 73, 74, 75, 76, 77, 78, 79,
+
+					  64, 65, 66, 67, 68, 69, 70, 71,		// maroon
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  64, 65, 66, 67, 68, 69, 70, 71,		// sky blue
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  
+					  64, 65, 66, 67, 68, 69, 70, 71,		// olive again
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  64, 65, 66, 67, 68, 69, 70, 71,		// nuclear green
+					  64, 65, 66, 67, 68, 69, 70, 71,		// bright yellow
+
+					  64, 65, 66, 67, 68, 69, 70, 71,		// fire colors
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  208, 208, 64, 64, 70, 71, 72, 64,		// mishmash1
+					  66, 68, 70, 64, 65, 66, 67, 68};		// mishmash2
+// PGM
+// ======================
+
+/*
+================
+R_PolysetUpdateTables
+================
+*/
+void R_PolysetUpdateTables (void)
+{
+	int		i;
+	byte	*s;
+	
+	if (r_affinetridesc.skinwidth != skinwidth ||
+		r_affinetridesc.pskin != skinstart)
+	{
+		skinwidth = r_affinetridesc.skinwidth;
+		skinstart = r_affinetridesc.pskin;
+		s = skinstart;
+		for (i=0 ; i<MAX_LBM_HEIGHT ; i++, s+=skinwidth)
+			skintable[i] = s;
+	}
+}
+
+
+/*
+================
+R_DrawTriangle
+================
+*/
+void R_DrawTriangle( void )
+{
+	spanpackage_t spans[DPS_MAXSPANS];
+
+	int dv1_ab, dv0_ac;
+	int dv0_ab, dv1_ac;
+
+	/*
+	d_xdenom = ( aliastriangleparms.a->v[1] - aliastriangleparms.b->v[1] ) * ( aliastriangleparms.a->v[0] - aliastriangleparms.c->v[0] ) -
+			   ( aliastriangleparms.a->v[0] - aliastriangleparms.b->v[0] ) * ( aliastriangleparms.a->v[1] - aliastriangleparms.c->v[1] );
+	*/
+
+	dv0_ab = aliastriangleparms.a->u - aliastriangleparms.b->u;
+	dv1_ab = aliastriangleparms.a->v - aliastriangleparms.b->v;
+
+	if ( !( dv0_ab | dv1_ab ) )
+		return;
+
+	dv0_ac = aliastriangleparms.a->u - aliastriangleparms.c->u;
+	dv1_ac = aliastriangleparms.a->v - aliastriangleparms.c->v;
+
+	if ( !( dv0_ac | dv1_ac ) )
+		return;
+
+	d_xdenom = ( dv0_ac * dv1_ab ) - ( dv0_ab * dv1_ac );
+
+	if ( d_xdenom < 0 )
+	{
+		a_spans = spans;
+
+		r_p0[0] = aliastriangleparms.a->u;		// u
+		r_p0[1] = aliastriangleparms.a->v;		// v
+		r_p0[2] = aliastriangleparms.a->s;		// s
+		r_p0[3] = aliastriangleparms.a->t;		// t
+		r_p0[4] = aliastriangleparms.a->l;		// light
+		r_p0[5] = aliastriangleparms.a->zi;		// iz
+
+		r_p1[0] = aliastriangleparms.b->u;
+		r_p1[1] = aliastriangleparms.b->v;
+		r_p1[2] = aliastriangleparms.b->s;
+		r_p1[3] = aliastriangleparms.b->t;
+		r_p1[4] = aliastriangleparms.b->l;
+		r_p1[5] = aliastriangleparms.b->zi;
+
+		r_p2[0] = aliastriangleparms.c->u;
+		r_p2[1] = aliastriangleparms.c->v;
+		r_p2[2] = aliastriangleparms.c->s;
+		r_p2[3] = aliastriangleparms.c->t;
+		r_p2[4] = aliastriangleparms.c->l;
+		r_p2[5] = aliastriangleparms.c->zi;
+
+		R_PolysetSetEdgeTable ();
+		R_RasterizeAliasPolySmooth ();
+	}
+}
+
+
+/*
+===================
+R_PolysetScanLeftEdge_C
+====================
+*/
+void R_PolysetScanLeftEdge_C(int height)
+{
+	do
+	{
+		d_pedgespanpackage->pdest = d_pdest;
+		d_pedgespanpackage->pz = d_pz;
+		d_pedgespanpackage->count = d_aspancount;
+		d_pedgespanpackage->ptex = d_ptex;
+
+		d_pedgespanpackage->sfrac = d_sfrac;
+		d_pedgespanpackage->tfrac = d_tfrac;
+
+	// FIXME: need to clamp l, s, t, at both ends?
+		d_pedgespanpackage->light = d_light;
+		d_pedgespanpackage->zi = d_zi;
+
+		d_pedgespanpackage++;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_pdest += d_pdestextrastep;
+			d_pz += d_pzextrastep;
+			d_aspancount += d_countextrastep;
+			d_ptex += d_ptexextrastep;
+			d_sfrac += d_sfracextrastep;
+			d_ptex += d_sfrac >> 16;
+
+			d_sfrac &= 0xFFFF;
+			d_tfrac += d_tfracextrastep;
+			if (d_tfrac & 0x10000)
+			{
+				d_ptex += r_affinetridesc.skinwidth;
+				d_tfrac &= 0xFFFF;
+			}
+			d_light += d_lightextrastep;
+			d_zi += d_ziextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_pdest += d_pdestbasestep;
+			d_pz += d_pzbasestep;
+			d_aspancount += ubasestep;
+			d_ptex += d_ptexbasestep;
+			d_sfrac += d_sfracbasestep;
+			d_ptex += d_sfrac >> 16;
+			d_sfrac &= 0xFFFF;
+			d_tfrac += d_tfracbasestep;
+			if (d_tfrac & 0x10000)
+			{
+				d_ptex += r_affinetridesc.skinwidth;
+				d_tfrac &= 0xFFFF;
+			}
+			d_light += d_lightbasestep;
+			d_zi += d_zibasestep;
+		}
+	} while (--height);
+}
+
+/*
+===================
+FloorDivMod
+
+Returns mathematically correct (floor-based) quotient and remainder for
+numer and denom, both of which should contain no fractional part. The
+quotient must fit in 32 bits.
+FIXME: GET RID OF THIS! (FloorDivMod)
+====================
+*/
+void FloorDivMod (float numer, float denom, int *quotient,
+		int *rem)
+{
+	int		q, r;
+	float	x;
+
+	if (numer >= 0.0)
+	{
+
+		x = floor(numer / denom);
+		q = (int)x;
+		r = (int)floor(numer - (x * denom));
+	}
+	else
+	{
+	//
+	// perform operations with positive values, and fix mod to make floor-based
+	//
+		x = floor(-numer / denom);
+		q = -(int)x;
+		r = (int)floor(-numer - (x * denom));
+		if (r != 0)
+		{
+			q--;
+			r = (int)denom - r;
+		}
+	}
+
+	*quotient = q;
+	*rem = r;
+}
+
+
+/*
+===================
+R_PolysetSetUpForLineScan
+====================
+*/
+void R_PolysetSetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
+		fixed8_t endvertu, fixed8_t endvertv)
+{
+	float		dm, dn;
+	int			tm, tn;
+	adivtab_t	*ptemp;
+
+// TODO: implement x86 version
+
+	errorterm = -1;
+
+	tm = endvertu - startvertu;
+	tn = endvertv - startvertv;
+
+	if (((tm <= 16) && (tm >= -15)) &&
+		((tn <= 16) && (tn >= -15)))
+	{
+		ptemp = &adivtab[((tm+15) << 5) + (tn+15)];
+		ubasestep = ptemp->quotient;
+		erroradjustup = ptemp->remainder;
+		erroradjustdown = tn;
+	}
+	else
+	{
+		dm = tm;
+		dn = tn;
+
+		FloorDivMod (dm, dn, &ubasestep, &erroradjustup);
+
+		erroradjustdown = dn;
+	}
+}
+
+
+
+/*
+================
+R_PolysetCalcGradients
+================
+*/
+void R_PolysetCalcGradients (int skinwidth)
+{
+	float	xstepdenominv, ystepdenominv, t0, t1;
+	float	p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20;
+
+	p00_minus_p20 = r_p0[0] - r_p2[0];
+	p01_minus_p21 = r_p0[1] - r_p2[1];
+	p10_minus_p20 = r_p1[0] - r_p2[0];
+	p11_minus_p21 = r_p1[1] - r_p2[1];
+
+	xstepdenominv = 1.0 / (float)d_xdenom;
+
+	ystepdenominv = -xstepdenominv;
+
+// ceil () for light so positive steps are exaggerated, negative steps
+// diminished,  pushing us away from underflow toward overflow. Underflow is
+// very visible, overflow is very unlikely, because of ambient lighting
+	t0 = r_p0[4] - r_p2[4];
+	t1 = r_p1[4] - r_p2[4];
+	r_lstepx = (int)
+			ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv);
+	r_lstepy = (int)
+			ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv);
+
+	t0 = r_p0[2] - r_p2[2];
+	t1 = r_p1[2] - r_p2[2];
+	r_sstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+			xstepdenominv);
+	r_sstepy = (int)((t1 * p00_minus_p20 - t0* p10_minus_p20) *
+			ystepdenominv);
+
+	t0 = r_p0[3] - r_p2[3];
+	t1 = r_p1[3] - r_p2[3];
+	r_tstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+			xstepdenominv);
+	r_tstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
+			ystepdenominv);
+
+	t0 = r_p0[5] - r_p2[5];
+	t1 = r_p1[5] - r_p2[5];
+	r_zistepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+			xstepdenominv);
+	r_zistepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
+			ystepdenominv);
+
+	a_sstepxfrac = r_sstepx & 0xFFFF;
+	a_tstepxfrac = r_tstepx & 0xFFFF;
+
+	a_ststepxwhole = skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16);
+}
+
+/*
+================
+R_PolysetDrawThreshSpans8
+
+Random fizzle fade rasterizer
+================
+*/
+void R_PolysetDrawThreshSpans8 (spanpackage_t *pspanpackage)
+{
+	int		lcount;
+	byte	*lpdest;
+	byte	*lptex;
+	int		lsfrac, ltfrac;
+	int		llight;
+	int		lzi;
+	short	*lpz;
+
+	do
+	{
+		lcount = d_aspancount - pspanpackage->count;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_aspancount += d_countextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_aspancount += ubasestep;
+		}
+
+		if (lcount)
+		{
+			lpdest = pspanpackage->pdest;
+			lptex = pspanpackage->ptex;
+			lpz = pspanpackage->pz;
+			lsfrac = pspanpackage->sfrac;
+			ltfrac = pspanpackage->tfrac;
+			llight = pspanpackage->light;
+			lzi = pspanpackage->zi;
+
+			do
+			{
+				if ((lzi >> 16) >= *lpz)
+				{
+					rand1k_index = (rand1k_index + 1) & MASK_1K;
+
+					if (rand1k[rand1k_index] <= r_affinetridesc.vis_thresh)
+					{
+						*lpdest = ((byte *)vid.colormap)[*lptex + (llight & 0xFF00)];
+						*lpz = lzi >> 16;
+					}
+				}
+
+				lpdest++;
+				lzi += r_zistepx;
+				lpz++;
+				llight += r_lstepx;
+				lptex += a_ststepxwhole;
+				lsfrac += a_sstepxfrac;
+				lptex += lsfrac >> 16;
+				lsfrac &= 0xFFFF;
+				ltfrac += a_tstepxfrac;
+				if (ltfrac & 0x10000)
+				{
+					lptex += r_affinetridesc.skinwidth;
+					ltfrac &= 0xFFFF;
+				}
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	} while (pspanpackage->count != -999999);
+}
+
+
+/*
+================
+R_PolysetDrawSpans8
+================
+*/
+void R_PolysetDrawSpans8_33( spanpackage_t *pspanpackage)
+{
+	int		lcount;
+	byte	*lpdest;
+	byte	*lptex;
+	int		lsfrac, ltfrac;
+	int		llight;
+	int		lzi;
+	short	*lpz;
+
+	do
+	{
+		lcount = d_aspancount - pspanpackage->count;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_aspancount += d_countextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_aspancount += ubasestep;
+		}
+
+		if (lcount)
+		{
+			lpdest = pspanpackage->pdest;
+			lptex = pspanpackage->ptex;
+			lpz = pspanpackage->pz;
+			lsfrac = pspanpackage->sfrac;
+			ltfrac = pspanpackage->tfrac;
+			llight = pspanpackage->light;
+			lzi = pspanpackage->zi;
+
+			do
+			{
+				if ((lzi >> 16) >= *lpz)
+				{
+					int temp = vid.colormap[*lptex + ( llight & 0xFF00 )];
+
+					*lpdest = vid.alphamap[temp+ *lpdest*256];
+				}
+				lpdest++;
+				lzi += r_zistepx;
+				lpz++;
+				llight += r_lstepx;
+				lptex += a_ststepxwhole;
+				lsfrac += a_sstepxfrac;
+				lptex += lsfrac >> 16;
+				lsfrac &= 0xFFFF;
+				ltfrac += a_tstepxfrac;
+				if (ltfrac & 0x10000)
+				{
+					lptex += r_affinetridesc.skinwidth;
+					ltfrac &= 0xFFFF;
+				}
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	} while (pspanpackage->count != -999999);
+}
+
+void R_PolysetDrawSpansConstant8_33( spanpackage_t *pspanpackage)
+{
+	int		lcount;
+	byte	*lpdest;
+	int		lzi;
+	short	*lpz;
+
+	do
+	{
+		lcount = d_aspancount - pspanpackage->count;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_aspancount += d_countextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_aspancount += ubasestep;
+		}
+
+		if (lcount)
+		{
+			lpdest = pspanpackage->pdest;
+			lpz = pspanpackage->pz;
+			lzi = pspanpackage->zi;
+
+			do
+			{
+				if ((lzi >> 16) >= *lpz)
+				{
+					*lpdest = vid.alphamap[r_aliasblendcolor + *lpdest*256];
+				}
+				lpdest++;
+				lzi += r_zistepx;
+				lpz++;
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	} while (pspanpackage->count != -999999);
+}
+
+void R_PolysetDrawSpans8_66(spanpackage_t *pspanpackage)
+{
+	int		lcount;
+	byte	*lpdest;
+	byte	*lptex;
+	int		lsfrac, ltfrac;
+	int		llight;
+	int		lzi;
+	short	*lpz;
+
+	do
+	{
+		lcount = d_aspancount - pspanpackage->count;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_aspancount += d_countextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_aspancount += ubasestep;
+		}
+
+		if (lcount)
+		{
+			lpdest = pspanpackage->pdest;
+			lptex = pspanpackage->ptex;
+			lpz = pspanpackage->pz;
+			lsfrac = pspanpackage->sfrac;
+			ltfrac = pspanpackage->tfrac;
+			llight = pspanpackage->light;
+			lzi = pspanpackage->zi;
+
+			do
+			{
+				if ((lzi >> 16) >= *lpz)
+				{
+					int temp = vid.colormap[*lptex + ( llight & 0xFF00 )];
+
+					*lpdest = vid.alphamap[temp*256 + *lpdest];
+					*lpz = lzi >> 16;
+				}
+				lpdest++;
+				lzi += r_zistepx;
+				lpz++;
+				llight += r_lstepx;
+				lptex += a_ststepxwhole;
+				lsfrac += a_sstepxfrac;
+				lptex += lsfrac >> 16;
+				lsfrac &= 0xFFFF;
+				ltfrac += a_tstepxfrac;
+				if (ltfrac & 0x10000)
+				{
+					lptex += r_affinetridesc.skinwidth;
+					ltfrac &= 0xFFFF;
+				}
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	} while (pspanpackage->count != -999999);
+}
+
+void R_PolysetDrawSpansConstant8_66( spanpackage_t *pspanpackage)
+{
+	int		lcount;
+	byte	*lpdest;
+	int		lzi;
+	short	*lpz;
+
+	do
+	{
+		lcount = d_aspancount - pspanpackage->count;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_aspancount += d_countextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_aspancount += ubasestep;
+		}
+
+		if (lcount)
+		{
+			lpdest = pspanpackage->pdest;
+			lpz = pspanpackage->pz;
+			lzi = pspanpackage->zi;
+
+			do
+			{
+				if ((lzi >> 16) >= *lpz)
+				{
+					*lpdest = vid.alphamap[r_aliasblendcolor*256 + *lpdest];
+				}
+				lpdest++;
+				lzi += r_zistepx;
+				lpz++;
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	} while (pspanpackage->count != -999999);
+}
+
+void R_PolysetDrawSpans8_Opaque (spanpackage_t *pspanpackage)
+{
+	int		lcount;
+
+	do
+	{
+		lcount = d_aspancount - pspanpackage->count;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_aspancount += d_countextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_aspancount += ubasestep;
+		}
+
+		if (lcount)
+		{
+			int		lsfrac, ltfrac;
+			byte	*lpdest;
+			byte	*lptex;
+			int		llight;
+			int		lzi;
+			short	*lpz;
+
+			lpdest = pspanpackage->pdest;
+			lptex = pspanpackage->ptex;
+			lpz = pspanpackage->pz;
+			lsfrac = pspanpackage->sfrac;
+			ltfrac = pspanpackage->tfrac;
+			llight = pspanpackage->light;
+			lzi = pspanpackage->zi;
+
+			do
+			{
+				if ((lzi >> 16) >= *lpz)
+				{
+//PGM
+					if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
+						*lpdest = ((byte *)vid.colormap)[irtable[*lptex]];
+					else
+					*lpdest = ((byte *)vid.colormap)[*lptex + (llight & 0xFF00)];
+//PGM
+					*lpz = lzi >> 16;
+				}
+				lpdest++;
+				lzi += r_zistepx;
+				lpz++;
+				llight += r_lstepx;
+				lptex += a_ststepxwhole;
+				lsfrac += a_sstepxfrac;
+				lptex += lsfrac >> 16;
+				lsfrac &= 0xFFFF;
+				ltfrac += a_tstepxfrac;
+				if (ltfrac & 0x10000)
+				{
+					lptex += r_affinetridesc.skinwidth;
+					ltfrac &= 0xFFFF;
+				}
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	} while (pspanpackage->count != -999999);
+}
+
+
+/*
+================
+R_PolysetFillSpans8
+================
+*/
+void R_PolysetFillSpans8 (spanpackage_t *pspanpackage)
+{
+	int				color;
+
+// FIXME: do z buffering
+
+	color = d_aflatcolor++;
+
+	while (1)
+	{
+		int		lcount;
+		byte	*lpdest;
+
+		lcount = pspanpackage->count;
+
+		if (lcount == -1)
+			return;
+
+		if (lcount)
+		{
+			lpdest = pspanpackage->pdest;
+
+			do
+			{
+				*lpdest++ = color;
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	}
+}
+
+/*
+================
+R_RasterizeAliasPolySmooth
+================
+*/
+void R_RasterizeAliasPolySmooth (void)
+{
+	int				initialleftheight, initialrightheight;
+	int				*plefttop, *prighttop, *pleftbottom, *prightbottom;
+	int				working_lstepx, originalcount;
+
+	plefttop = pedgetable->pleftedgevert0;
+	prighttop = pedgetable->prightedgevert0;
+
+	pleftbottom = pedgetable->pleftedgevert1;
+	prightbottom = pedgetable->prightedgevert1;
+
+	initialleftheight = pleftbottom[1] - plefttop[1];
+	initialrightheight = prightbottom[1] - prighttop[1];
+
+//
+// set the s, t, and light gradients, which are consistent across the triangle
+// because being a triangle, things are affine
+//
+	R_PolysetCalcGradients (r_affinetridesc.skinwidth);
+//
+// rasterize the polygon
+//
+
+//
+// scan out the top (and possibly only) part of the left edge
+//
+	d_pedgespanpackage = a_spans;
+
+	ystart = plefttop[1];
+	d_aspancount = plefttop[0] - prighttop[0];
+
+	d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
+			(plefttop[3] >> 16) * r_affinetridesc.skinwidth;
+
+	d_sfrac = plefttop[2] & 0xFFFF;
+	d_tfrac = plefttop[3] & 0xFFFF;
+
+	d_light = plefttop[4];
+	d_zi = plefttop[5];
+
+	d_pdest = (byte *)d_viewbuffer +
+			ystart * r_screenwidth + plefttop[0];
+	d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
+
+	if (initialleftheight == 1)
+	{
+		d_pedgespanpackage->pdest = d_pdest;
+		d_pedgespanpackage->pz = d_pz;
+		d_pedgespanpackage->count = d_aspancount;
+		d_pedgespanpackage->ptex = d_ptex;
+
+		d_pedgespanpackage->sfrac = d_sfrac;
+		d_pedgespanpackage->tfrac = d_tfrac;
+
+	// FIXME: need to clamp l, s, t, at both ends?
+		d_pedgespanpackage->light = d_light;
+		d_pedgespanpackage->zi = d_zi;
+
+		d_pedgespanpackage++;
+	}
+	else
+	{
+		R_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
+							  pleftbottom[0], pleftbottom[1]);
+
+		d_pzbasestep = d_zwidth + ubasestep;
+		d_pzextrastep = d_pzbasestep + 1;
+
+		d_pdestbasestep = r_screenwidth + ubasestep;
+		d_pdestextrastep = d_pdestbasestep + 1;
+
+	// TODO: can reuse partial expressions here
+
+	// for negative steps in x along left edge, bias toward overflow rather than
+	// underflow (sort of turning the floor () we did in the gradient calcs into
+	// ceil (), but plus a little bit)
+		if (ubasestep < 0)
+			working_lstepx = r_lstepx - 1;
+		else
+			working_lstepx = r_lstepx;
+
+		d_countextrastep = ubasestep + 1;
+		d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
+				((r_tstepy + r_tstepx * ubasestep) >> 16) *
+				r_affinetridesc.skinwidth;
+
+		d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
+		d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
+
+		d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
+		d_zibasestep = r_zistepy + r_zistepx * ubasestep;
+
+		d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
+				((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
+				r_affinetridesc.skinwidth;
+
+		d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) & 0xFFFF;
+		d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) & 0xFFFF;
+
+		d_lightextrastep = d_lightbasestep + working_lstepx;
+		d_ziextrastep = d_zibasestep + r_zistepx;
+
+		R_PolysetScanLeftEdge_C(initialleftheight);
+	}
+
+//
+// scan out the bottom part of the left edge, if it exists
+//
+	if (pedgetable->numleftedges == 2)
+	{
+		int		height;
+
+		plefttop = pleftbottom;
+		pleftbottom = pedgetable->pleftedgevert2;
+
+		height = pleftbottom[1] - plefttop[1];
+
+// TODO: make this a function; modularize this function in general
+
+		ystart = plefttop[1];
+		d_aspancount = plefttop[0] - prighttop[0];
+		d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
+				(plefttop[3] >> 16) * r_affinetridesc.skinwidth;
+		d_sfrac = 0;
+		d_tfrac = 0;
+		d_light = plefttop[4];
+		d_zi = plefttop[5];
+
+		d_pdest = (byte *)d_viewbuffer + ystart * r_screenwidth + plefttop[0];
+		d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
+
+		if (height == 1)
+		{
+			d_pedgespanpackage->pdest = d_pdest;
+			d_pedgespanpackage->pz = d_pz;
+			d_pedgespanpackage->count = d_aspancount;
+			d_pedgespanpackage->ptex = d_ptex;
+
+			d_pedgespanpackage->sfrac = d_sfrac;
+			d_pedgespanpackage->tfrac = d_tfrac;
+
+		// FIXME: need to clamp l, s, t, at both ends?
+			d_pedgespanpackage->light = d_light;
+			d_pedgespanpackage->zi = d_zi;
+		}
+		else
+		{
+			R_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
+								  pleftbottom[0], pleftbottom[1]);
+
+			d_pdestbasestep = r_screenwidth + ubasestep;
+			d_pdestextrastep = d_pdestbasestep + 1;
+
+			d_pzbasestep = d_zwidth + ubasestep;
+			d_pzextrastep = d_pzbasestep + 1;
+
+			if (ubasestep < 0)
+				working_lstepx = r_lstepx - 1;
+			else
+				working_lstepx = r_lstepx;
+
+			d_countextrastep = ubasestep + 1;
+			d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
+					((r_tstepy + r_tstepx * ubasestep) >> 16) *
+					r_affinetridesc.skinwidth;
+
+			d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
+			d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
+
+			d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
+			d_zibasestep = r_zistepy + r_zistepx * ubasestep;
+
+			d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
+					((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
+					r_affinetridesc.skinwidth;
+
+
+			d_sfracextrastep = (r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF;
+			d_tfracextrastep = (r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF;
+
+			d_lightextrastep = d_lightbasestep + working_lstepx;
+			d_ziextrastep = d_zibasestep + r_zistepx;
+
+			R_PolysetScanLeftEdge_C(height);
+		}
+	}
+
+// scan out the top (and possibly only) part of the right edge, updating the
+// count field
+	d_pedgespanpackage = a_spans;
+
+	R_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
+						  prightbottom[0], prightbottom[1]);
+	d_aspancount = 0;
+	d_countextrastep = ubasestep + 1;
+	originalcount = a_spans[initialrightheight].count;
+	a_spans[initialrightheight].count = -999999; // mark end of the spanpackages
+	(*d_pdrawspans) (a_spans);
+
+// scan out the bottom part of the right edge, if it exists
+	if (pedgetable->numrightedges == 2)
+	{
+		int				height;
+		spanpackage_t	*pstart;
+
+		pstart = a_spans + initialrightheight;
+		pstart->count = originalcount;
+
+		d_aspancount = prightbottom[0] - prighttop[0];
+
+		prighttop = prightbottom;
+		prightbottom = pedgetable->prightedgevert2;
+
+		height = prightbottom[1] - prighttop[1];
+
+		R_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
+							  prightbottom[0], prightbottom[1]);
+
+		d_countextrastep = ubasestep + 1;
+		a_spans[initialrightheight + height].count = -999999;
+											// mark end of the spanpackages
+		(*d_pdrawspans) (pstart);
+	}
+}
+
+
+/*
+================
+R_PolysetSetEdgeTable
+================
+*/
+void R_PolysetSetEdgeTable (void)
+{
+	int			edgetableindex;
+
+	edgetableindex = 0;	// assume the vertices are already in
+						//  top to bottom order
+
+//
+// determine which edges are right & left, and the order in which
+// to rasterize them
+//
+	if (r_p0[1] >= r_p1[1])
+	{
+		if (r_p0[1] == r_p1[1])
+		{
+			if (r_p0[1] < r_p2[1])
+				pedgetable = &edgetables[2];
+			else
+				pedgetable = &edgetables[5];
+
+			return;
+		}
+		else
+		{
+			edgetableindex = 1;
+		}
+	}
+
+	if (r_p0[1] == r_p2[1])
+	{
+		if (edgetableindex)
+			pedgetable = &edgetables[8];
+		else
+			pedgetable = &edgetables[9];
+
+		return;
+	}
+	else if (r_p1[1] == r_p2[1])
+	{
+		if (edgetableindex)
+			pedgetable = &edgetables[10];
+		else
+			pedgetable = &edgetables[11];
+
+		return;
+	}
+
+	if (r_p0[1] > r_p2[1])
+		edgetableindex += 2;
+
+	if (r_p1[1] > r_p2[1])
+		edgetableindex += 4;
+
+	pedgetable = &edgetables[edgetableindex];
+}
--- /dev/null
+++ b/r_rast.c
@@ -1,0 +1,829 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+#define MAXLEFTCLIPEDGES		100
+
+// !!! if these are changed, they must be changed in asm_draw.h too !!!
+#define FULLY_CLIPPED_CACHED	0x80000000
+#define FRAMECOUNT_MASK			0x7FFFFFFF
+
+unsigned int	cacheoffset;
+
+int			c_faceclip;					// number of faces clipped
+
+
+clipplane_t	*entity_clipplanes;
+clipplane_t	view_clipplanes[4];
+clipplane_t	world_clipplanes[16];
+
+medge_t			*r_pedge;
+
+qboolean		r_leftclipped, r_rightclipped;
+static qboolean	makeleftedge, makerightedge;
+qboolean		r_nearzionly;
+
+int		sintable[1280];
+int		intsintable[1280];
+int		blanktable[1280];		// PGM
+
+mvertex_t	r_leftenter, r_leftexit;
+mvertex_t	r_rightenter, r_rightexit;
+
+typedef struct
+{
+	float	u,v;
+	int		ceilv;
+} evert_t;
+
+int				r_emitted;
+float			r_nearzi;
+float			r_u1, r_v1, r_lzi1;
+int				r_ceilv1;
+
+qboolean		r_lastvertvalid;
+int				r_skyframe;
+
+msurface_t		*r_skyfaces;
+mplane_t		r_skyplanes[6];
+mtexinfo_t		r_skytexinfo[6];
+mvertex_t		*r_skyverts;
+medge_t			*r_skyedges;
+int				*r_skysurfedges;
+
+// I just copied this data from a box map...
+int skybox_planes[12] = {2,-128, 0,-128, 2,128, 1,128, 0,128, 1,-128};
+
+int box_surfedges[24] = { 1,2,3,4,  -1,5,6,7,  8,9,-6,10,  -2,-7,-9,11,
+  12,-3,-11,-8,  -12,-10,-5,-4};
+int box_edges[24] = { 1,2, 2,3, 3,4, 4,1, 1,5, 5,6, 6,2, 7,8, 8,6, 5,7, 8,3, 7,4};
+
+int	box_faces[6] = {0,0,2,2,2,0};
+
+vec3_t	box_vecs[6][2] = {
+	{	{0,-1,0}, {-1,0,0} },
+	{ {0,1,0}, {0,0,-1} },
+	{	{0,-1,0}, {1,0,0} },
+	{ {1,0,0}, {0,0,-1} },
+	{ {0,-1,0}, {0,0,-1} },
+	{ {-1,0,0}, {0,0,-1} }
+};
+
+float	box_verts[8][3] = {
+	{-1,-1,-1},
+	{-1,1,-1},
+	{1,1,-1},
+	{1,-1,-1},
+	{-1,-1,1},
+	{-1,1,1},
+	{1,-1,1},
+	{1,1,1}
+};
+
+// down, west, up, north, east, south
+// {"rt", "bk", "lf", "ft", "up", "dn"};
+
+/*
+================
+R_InitSkyBox
+
+================
+*/
+void R_InitSkyBox (void)
+{
+	int		i;
+	extern model_t *loadmodel;
+
+	r_skyfaces = loadmodel->surfaces + loadmodel->numsurfaces;
+	loadmodel->numsurfaces += 6;
+	r_skyverts = loadmodel->vertexes + loadmodel->numvertexes;
+	loadmodel->numvertexes += 8;
+	r_skyedges = loadmodel->edges + loadmodel->numedges;
+	loadmodel->numedges += 12;
+	r_skysurfedges = loadmodel->surfedges + loadmodel->numsurfedges;
+	loadmodel->numsurfedges += 24;
+	if (loadmodel->numsurfaces > MAX_MAP_FACES
+		|| loadmodel->numvertexes > MAX_MAP_VERTS
+		|| loadmodel->numedges > MAX_MAP_EDGES)
+		ri.Sys_Error (ERR_DROP, "InitSkyBox: map overflow");
+
+	memset (r_skyfaces, 0, 6*sizeof(*r_skyfaces));
+	for (i=0 ; i<6 ; i++)
+	{
+		r_skyplanes[i].normal[skybox_planes[i*2]] = 1;
+		r_skyplanes[i].dist = skybox_planes[i*2+1];
+
+		VectorCopy (box_vecs[i][0], r_skytexinfo[i].vecs[0]);
+		VectorCopy (box_vecs[i][1], r_skytexinfo[i].vecs[1]);
+
+		r_skyfaces[i].plane = &r_skyplanes[i];
+		r_skyfaces[i].numedges = 4;
+		r_skyfaces[i].flags = box_faces[i] | SURF_DRAWSKYBOX;
+		r_skyfaces[i].firstedge = loadmodel->numsurfedges-24+i*4;
+		r_skyfaces[i].texinfo = &r_skytexinfo[i];
+		r_skyfaces[i].texturemins[0] = -128;
+		r_skyfaces[i].texturemins[1] = -128;
+		r_skyfaces[i].extents[0] = 256;
+		r_skyfaces[i].extents[1] = 256;
+	}
+
+	for (i=0 ; i<24 ; i++)
+		if (box_surfedges[i] > 0)
+			r_skysurfedges[i] = loadmodel->numedges-13 + box_surfedges[i];
+		else
+			r_skysurfedges[i] = - (loadmodel->numedges-13 + -box_surfedges[i]);
+
+	for(i=0 ; i<12 ; i++)
+	{
+		r_skyedges[i].v[0] = loadmodel->numvertexes-9+box_edges[i*2+0];
+		r_skyedges[i].v[1] = loadmodel->numvertexes-9+box_edges[i*2+1];
+		r_skyedges[i].cachededgeoffset = 0;
+	}
+}
+
+/*
+================
+R_EmitSkyBox
+================
+*/
+void R_EmitSkyBox (void)
+{
+	int		i, j;
+	int		oldkey;
+
+	if (insubmodel)
+		return;		// submodels should never have skies
+	if (r_skyframe == r_framecount)
+		return;		// already set this frame
+
+	r_skyframe = r_framecount;
+
+	// set the eight fake vertexes
+	for (i=0 ; i<8 ; i++)
+		for (j=0 ; j<3 ; j++)
+			r_skyverts[i].position[j] = r_origin[j] + box_verts[i][j]*128;
+
+	// set the six fake planes
+	for (i=0 ; i<6 ; i++)
+		if (skybox_planes[i*2+1] > 0)
+			r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]+128;
+		else
+			r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]-128;
+
+	// fix texture offseets
+	for (i=0 ; i<6 ; i++)
+	{
+		r_skytexinfo[i].vecs[0][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[0]);
+		r_skytexinfo[i].vecs[1][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[1]);
+	}
+
+	// emit the six faces
+	oldkey = r_currentkey;
+	r_currentkey = 0x7ffffff0;
+ 	for (i=0 ; i<6 ; i++)
+	{
+		R_RenderFace (r_skyfaces + i, 15);
+	}
+	r_currentkey = oldkey;		// bsp sorting order
+}
+
+
+/*
+================
+R_EmitEdge
+================
+*/
+void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
+{
+	edge_t	*edge, *pcheck;
+	int		u_check;
+	float	u, u_step;
+	vec3_t	local, transformed;
+	float	*world;
+	int		v, v2, ceilv0;
+	float	scale, lzi0, u0, v0;
+	int		side;
+
+	if (r_lastvertvalid)
+	{
+		u0 = r_u1;
+		v0 = r_v1;
+		lzi0 = r_lzi1;
+		ceilv0 = r_ceilv1;
+	}
+	else
+	{
+		world = &pv0->position[0];
+	
+	// transform and project
+		VectorSubtract (world, modelorg, local);
+		TransformVector (local, transformed);
+	
+		if (transformed[2] < NEAR_CLIP)
+			transformed[2] = NEAR_CLIP;
+	
+		lzi0 = 1.0 / transformed[2];
+	
+	// FIXME: build x/yscale into transform?
+		scale = xscale * lzi0;
+		u0 = (xcenter + scale*transformed[0]);
+		if (u0 < r_refdef.fvrectx_adj)
+			u0 = r_refdef.fvrectx_adj;
+		if (u0 > r_refdef.fvrectright_adj)
+			u0 = r_refdef.fvrectright_adj;
+	
+		scale = yscale * lzi0;
+		v0 = (ycenter - scale*transformed[1]);
+		if (v0 < r_refdef.fvrecty_adj)
+			v0 = r_refdef.fvrecty_adj;
+		if (v0 > r_refdef.fvrectbottom_adj)
+			v0 = r_refdef.fvrectbottom_adj;
+	
+		ceilv0 = (int) ceil(v0);
+	}
+
+	world = &pv1->position[0];
+
+// transform and project
+	VectorSubtract (world, modelorg, local);
+	TransformVector (local, transformed);
+
+	if (transformed[2] < NEAR_CLIP)
+		transformed[2] = NEAR_CLIP;
+
+	r_lzi1 = 1.0 / transformed[2];
+
+	scale = xscale * r_lzi1;
+	r_u1 = (xcenter + scale*transformed[0]);
+	if (r_u1 < r_refdef.fvrectx_adj)
+		r_u1 = r_refdef.fvrectx_adj;
+	if (r_u1 > r_refdef.fvrectright_adj)
+		r_u1 = r_refdef.fvrectright_adj;
+
+	scale = yscale * r_lzi1;
+	r_v1 = (ycenter - scale*transformed[1]);
+	if (r_v1 < r_refdef.fvrecty_adj)
+		r_v1 = r_refdef.fvrecty_adj;
+	if (r_v1 > r_refdef.fvrectbottom_adj)
+		r_v1 = r_refdef.fvrectbottom_adj;
+
+	if (r_lzi1 > lzi0)
+		lzi0 = r_lzi1;
+
+	if (lzi0 > r_nearzi)	// for mipmap finding
+		r_nearzi = lzi0;
+
+// for right edges, all we want is the effect on 1/z
+	if (r_nearzionly)
+		return;
+
+	r_emitted = 1;
+
+	r_ceilv1 = (int) ceil(r_v1);
+
+
+// create the edge
+	if (ceilv0 == r_ceilv1)
+	{
+	// we cache unclipped horizontal edges as fully clipped
+		if (cacheoffset != 0x7FFFFFFF)
+		{
+			cacheoffset = FULLY_CLIPPED_CACHED |
+					(r_framecount & FRAMECOUNT_MASK);
+		}
+
+		return;		// horizontal edge
+	}
+
+	side = ceilv0 > r_ceilv1;
+
+	edge = edge_p++;
+
+	edge->owner = r_pedge;
+
+	edge->nearzi = lzi0;
+
+	if (side == 0)
+	{
+	// trailing edge (go from p1 to p2)
+		v = ceilv0;
+		v2 = r_ceilv1 - 1;
+
+		edge->surfs[0] = surface_p - surfaces;
+		edge->surfs[1] = 0;
+
+		u_step = ((r_u1 - u0) / (r_v1 - v0));
+		u = u0 + ((float)v - v0) * u_step;
+	}
+	else
+	{
+	// leading edge (go from p2 to p1)
+		v2 = ceilv0 - 1;
+		v = r_ceilv1;
+
+		edge->surfs[0] = 0;
+		edge->surfs[1] = surface_p - surfaces;
+
+		u_step = ((u0 - r_u1) / (v0 - r_v1));
+		u = r_u1 + ((float)v - r_v1) * u_step;
+	}
+
+	edge->u_step = u_step*0x100000;
+	edge->u = u*0x100000 + 0xFFFFF;
+
+// we need to do this to avoid stepping off the edges if a very nearly
+// horizontal edge is less than epsilon above a scan, and numeric error causes
+// it to incorrectly extend to the scan, and the extension of the line goes off
+// the edge of the screen
+// FIXME: is this actually needed?
+	if (edge->u < r_refdef.vrect_x_adj_shift20)
+		edge->u = r_refdef.vrect_x_adj_shift20;
+	if (edge->u > r_refdef.vrectright_adj_shift20)
+		edge->u = r_refdef.vrectright_adj_shift20;
+
+//
+// sort the edge in normally
+//
+	u_check = edge->u;
+	if (edge->surfs[0])
+		u_check++;	// sort trailers after leaders
+
+	if (!newedges[v] || newedges[v]->u >= u_check)
+	{
+		edge->next = newedges[v];
+		newedges[v] = edge;
+	}
+	else
+	{
+		pcheck = newedges[v];
+		while (pcheck->next && pcheck->next->u < u_check)
+			pcheck = pcheck->next;
+		edge->next = pcheck->next;
+		pcheck->next = edge;
+	}
+
+	edge->nextremove = removeedges[v2];
+	removeedges[v2] = edge;
+}
+
+
+/*
+================
+R_ClipEdge
+================
+*/
+void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
+{
+	float		d0, d1, f;
+	mvertex_t	clipvert;
+
+	if (clip)
+	{
+		do
+		{
+			d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
+			d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
+
+			if (d0 >= 0)
+			{
+			// point 0 is unclipped
+				if (d1 >= 0)
+				{
+				// both points are unclipped
+					continue;
+				}
+
+			// only point 1 is clipped
+
+			// we don't cache clipped edges
+				cacheoffset = 0x7FFFFFFF;
+
+				f = d0 / (d0 - d1);
+				clipvert.position[0] = pv0->position[0] +
+						f * (pv1->position[0] - pv0->position[0]);
+				clipvert.position[1] = pv0->position[1] +
+						f * (pv1->position[1] - pv0->position[1]);
+				clipvert.position[2] = pv0->position[2] +
+						f * (pv1->position[2] - pv0->position[2]);
+
+				if (clip->leftedge)
+				{
+					r_leftclipped = true;
+					r_leftexit = clipvert;
+				}
+				else if (clip->rightedge)
+				{
+					r_rightclipped = true;
+					r_rightexit = clipvert;
+				}
+
+				R_ClipEdge (pv0, &clipvert, clip->next);
+				return;
+			}
+			else
+			{
+			// point 0 is clipped
+				if (d1 < 0)
+				{
+				// both points are clipped
+				// we do cache fully clipped edges
+					if (!r_leftclipped)
+						cacheoffset = FULLY_CLIPPED_CACHED |
+								(r_framecount & FRAMECOUNT_MASK);
+					return;
+				}
+
+			// only point 0 is clipped
+				r_lastvertvalid = false;
+
+			// we don't cache partially clipped edges
+				cacheoffset = 0x7FFFFFFF;
+
+				f = d0 / (d0 - d1);
+				clipvert.position[0] = pv0->position[0] +
+						f * (pv1->position[0] - pv0->position[0]);
+				clipvert.position[1] = pv0->position[1] +
+						f * (pv1->position[1] - pv0->position[1]);
+				clipvert.position[2] = pv0->position[2] +
+						f * (pv1->position[2] - pv0->position[2]);
+
+				if (clip->leftedge)
+				{
+					r_leftclipped = true;
+					r_leftenter = clipvert;
+				}
+				else if (clip->rightedge)
+				{
+					r_rightclipped = true;
+					r_rightenter = clipvert;
+				}
+
+				R_ClipEdge (&clipvert, pv1, clip->next);
+				return;
+			}
+		} while ((clip = clip->next) != NULL);
+	}
+
+// add the edge
+	R_EmitEdge (pv0, pv1);
+}
+
+
+/*
+================
+R_EmitCachedEdge
+================
+*/
+void R_EmitCachedEdge (void)
+{
+	edge_t		*pedge_t;
+
+	pedge_t = (edge_t *)((uintptr)r_edges + r_pedge->cachededgeoffset);
+
+	if (!pedge_t->surfs[0])
+		pedge_t->surfs[0] = surface_p - surfaces;
+	else
+		pedge_t->surfs[1] = surface_p - surfaces;
+
+	if (pedge_t->nearzi > r_nearzi)	// for mipmap finding
+		r_nearzi = pedge_t->nearzi;
+
+	r_emitted = 1;
+}
+
+
+/*
+================
+R_RenderFace
+================
+*/
+void R_RenderFace (msurface_t *fa, int clipflags)
+{
+	int			i, lindex;
+	unsigned	mask;
+	mplane_t	*pplane;
+	float		distinv;
+	vec3_t		p_normal;
+	medge_t		*pedges, tedge;
+	clipplane_t	*pclip;
+
+	// translucent surfaces are not drawn by the edge renderer
+	if (fa->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
+	{
+		fa->nextalphasurface = r_alpha_surfaces;
+		r_alpha_surfaces = fa;
+		return;
+	}
+
+	// sky surfaces encountered in the world will cause the
+	// environment box surfaces to be emited
+	if ( fa->texinfo->flags & SURF_SKY )
+	{
+		R_EmitSkyBox ();	
+		return;
+	}
+
+// skip out if no more surfs
+	if ((surface_p) >= surf_max)
+	{
+		r_outofsurfaces++;
+		return;
+	}
+
+// ditto if not enough edges left, or switch to auxedges if possible
+	if ((edge_p + fa->numedges + 4) >= edge_max)
+	{
+		r_outofedges += fa->numedges;
+		return;
+	}
+
+	c_faceclip++;
+
+// set up clip planes
+	pclip = NULL;
+
+	for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
+	{
+		if (clipflags & mask)
+		{
+			view_clipplanes[i].next = pclip;
+			pclip = &view_clipplanes[i];
+		}
+	}
+
+// push the edges through
+	r_emitted = 0;
+	r_nearzi = 0;
+	r_nearzionly = false;
+	makeleftedge = makerightedge = false;
+	pedges = currentmodel->edges;
+	r_lastvertvalid = false;
+
+	for (i=0 ; i<fa->numedges ; i++)
+	{
+		lindex = currentmodel->surfedges[fa->firstedge + i];
+
+		if (lindex > 0)
+		{
+			r_pedge = &pedges[lindex];
+
+		// if the edge is cached, we can just reuse the edge
+			if (!insubmodel)
+			{
+				if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
+				{
+					if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
+						r_framecount)
+					{
+						r_lastvertvalid = false;
+						continue;
+					}
+				}
+				else
+				{
+					if ((((uintptr)edge_p - (uintptr)r_edges) >
+						 r_pedge->cachededgeoffset) &&
+						(((edge_t *)((uintptr)r_edges +
+						 r_pedge->cachededgeoffset))->owner == r_pedge))
+					{
+						R_EmitCachedEdge ();
+						r_lastvertvalid = false;
+						continue;
+					}
+				}
+			}
+
+		// assume it's cacheable
+			cacheoffset = (byte *)edge_p - (byte *)r_edges;
+			r_leftclipped = r_rightclipped = false;
+			R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
+						&r_pcurrentvertbase[r_pedge->v[1]],
+						pclip);
+			r_pedge->cachededgeoffset = cacheoffset;
+
+			if (r_leftclipped)
+				makeleftedge = true;
+			if (r_rightclipped)
+				makerightedge = true;
+			r_lastvertvalid = true;
+		}
+		else
+		{
+			lindex = -lindex;
+			r_pedge = &pedges[lindex];
+		// if the edge is cached, we can just reuse the edge
+			if (!insubmodel)
+			{
+				if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
+				{
+					if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
+						r_framecount)
+					{
+						r_lastvertvalid = false;
+						continue;
+					}
+				}
+				else
+				{
+				// it's cached if the cached edge is valid and is owned
+				// by this medge_t
+					if ((((uintptr)edge_p - (uintptr)r_edges) >
+						 r_pedge->cachededgeoffset) &&
+						(((edge_t *)((uintptr)r_edges +
+						 r_pedge->cachededgeoffset))->owner == r_pedge))
+					{
+						R_EmitCachedEdge ();
+						r_lastvertvalid = false;
+						continue;
+					}
+				}
+			}
+
+		// assume it's cacheable
+			cacheoffset = (byte *)edge_p - (byte *)r_edges;
+			r_leftclipped = r_rightclipped = false;
+			R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
+						&r_pcurrentvertbase[r_pedge->v[0]],
+						pclip);
+			r_pedge->cachededgeoffset = cacheoffset;
+
+			if (r_leftclipped)
+				makeleftedge = true;
+			if (r_rightclipped)
+				makerightedge = true;
+			r_lastvertvalid = true;
+		}
+	}
+
+// if there was a clip off the left edge, add that edge too
+// FIXME: faster to do in screen space?
+// FIXME: share clipped edges?
+	if (makeleftedge)
+	{
+		r_pedge = &tedge;
+		r_lastvertvalid = false;
+		R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
+	}
+
+// if there was a clip off the right edge, get the right r_nearzi
+	if (makerightedge)
+	{
+		r_pedge = &tedge;
+		r_lastvertvalid = false;
+		r_nearzionly = true;
+		R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
+	}
+
+// if no edges made it out, return without posting the surface
+	if (!r_emitted)
+		return;
+
+	r_polycount++;
+
+	surface_p->msurf = fa;
+	surface_p->nearzi = r_nearzi;
+	surface_p->flags = fa->flags;
+	surface_p->insubmodel = insubmodel;
+	surface_p->spanstate = 0;
+	surface_p->entity = currententity;
+	surface_p->key = r_currentkey++;
+	surface_p->spans = NULL;
+
+	pplane = fa->plane;
+// FIXME: cache this?
+	TransformVector (pplane->normal, p_normal);
+// FIXME: cache this?
+	distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
+
+	surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
+	surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
+	surface_p->d_ziorigin = p_normal[2] * distinv -
+			xcenter * surface_p->d_zistepu -
+			ycenter * surface_p->d_zistepv;
+
+	surface_p++;
+}
+
+
+/*
+================
+R_RenderBmodelFace
+================
+*/
+void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
+{
+	int			i;
+	unsigned	mask;
+	mplane_t	*pplane;
+	float		distinv;
+	vec3_t		p_normal;
+	medge_t		tedge;
+	clipplane_t	*pclip;
+
+	if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
+	{
+		psurf->nextalphasurface = r_alpha_surfaces;
+		r_alpha_surfaces = psurf;
+		return;
+	}
+
+// skip out if no more surfs
+	if (surface_p >= surf_max)
+	{
+		r_outofsurfaces++;
+		return;
+	}
+
+// ditto if not enough edges left, or switch to auxedges if possible
+	if ((edge_p + psurf->numedges + 4) >= edge_max)
+	{
+		r_outofedges += psurf->numedges;
+		return;
+	}
+
+	c_faceclip++;
+
+// this is a dummy to give the caching mechanism someplace to write to
+	r_pedge = &tedge;
+
+// set up clip planes
+	pclip = NULL;
+
+	for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
+	{
+		if (r_clipflags & mask)
+		{
+			view_clipplanes[i].next = pclip;
+			pclip = &view_clipplanes[i];
+		}
+	}
+
+// push the edges through
+	r_emitted = 0;
+	r_nearzi = 0;
+	r_nearzionly = false;
+	makeleftedge = makerightedge = false;
+// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
+// can be used?
+	r_lastvertvalid = false;
+
+	for ( ; pedges ; pedges = pedges->pnext)
+	{
+		r_leftclipped = r_rightclipped = false;
+		R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
+
+		if (r_leftclipped)
+			makeleftedge = true;
+		if (r_rightclipped)
+			makerightedge = true;
+	}
+
+// if there was a clip off the left edge, add that edge too
+// FIXME: faster to do in screen space?
+// FIXME: share clipped edges?
+	if (makeleftedge)
+	{
+		r_pedge = &tedge;
+		R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
+	}
+
+// if there was a clip off the right edge, get the right r_nearzi
+	if (makerightedge)
+	{
+		r_pedge = &tedge;
+		r_nearzionly = true;
+		R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
+	}
+
+// if no edges made it out, return without posting the surface
+	if (!r_emitted)
+		return;
+
+	r_polycount++;
+
+	surface_p->msurf = psurf;
+	surface_p->nearzi = r_nearzi;
+	surface_p->flags = psurf->flags;
+	surface_p->insubmodel = true;
+	surface_p->spanstate = 0;
+	surface_p->entity = currententity;
+	surface_p->key = r_currentbkey;
+	surface_p->spans = NULL;
+
+	pplane = psurf->plane;
+// FIXME: cache this?
+	TransformVector (pplane->normal, p_normal);
+// FIXME: cache this?
+	distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
+
+	surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
+	surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
+	surface_p->d_ziorigin = p_normal[2] * distinv -
+			xcenter * surface_p->d_zistepu -
+			ycenter * surface_p->d_zistepv;
+
+	surface_p++;
+}
+
--- /dev/null
+++ b/r_scan.c
@@ -1,0 +1,561 @@
+// Portable C scan-level rasterization code, all pixel depths.
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+unsigned char	*r_turb_pbase, *r_turb_pdest;
+fixed16_t		r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
+int				*r_turb_turb;
+int				r_turb_spancount;
+
+void D_DrawTurbulent8Span (void);
+
+
+/*
+=============
+D_WarpScreen
+
+this performs a slight compression of the screen at the same time as
+the sine warp, to keep the edges from wrapping
+=============
+*/
+void D_WarpScreen (void)
+{
+	int		w, h;
+	int		u,v, u2, v2;
+	byte	*dest;
+	int		*turb;
+	int		*col;
+	byte	**row;
+
+	static int	cached_width, cached_height;
+	static byte	*rowptr[1200+AMP2*2];
+	static int	column[1600+AMP2*2];
+
+	//
+	// these are constant over resolutions, and can be saved
+	//
+	w = r_newrefdef.width;
+	h = r_newrefdef.height;
+	if (w != cached_width || h != cached_height)
+	{
+		cached_width = w;
+		cached_height = h;
+		for (v=0 ; v<h+AMP2*2 ; v++)
+		{
+			v2 = (int)((float)v/(h + AMP2 * 2) * r_refdef.vrect.height);
+			rowptr[v] = r_warpbuffer + (WARP_WIDTH * v2);
+		}
+
+		for (u=0 ; u<w+AMP2*2 ; u++)
+		{
+			u2 = (int)((float)u/(w + AMP2 * 2) * r_refdef.vrect.width);
+			column[u] = u2;
+		}
+	}
+
+	turb = intsintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
+	dest = vid.buffer + r_newrefdef.y * vid.rowbytes + r_newrefdef.x;
+
+	for (v=0 ; v<h ; v++, dest += vid.rowbytes)
+	{
+		col = &column[turb[v]];
+		row = &rowptr[v];
+		for (u=0 ; u<w ; u+=4)
+		{
+			dest[u+0] = row[turb[u+0]][col[u+0]];
+			dest[u+1] = row[turb[u+1]][col[u+1]];
+			dest[u+2] = row[turb[u+2]][col[u+2]];
+			dest[u+3] = row[turb[u+3]][col[u+3]];
+		}
+	}
+}
+
+
+/*
+=============
+D_DrawTurbulent8Span
+=============
+*/
+void D_DrawTurbulent8Span (void)
+{
+	int		sturb, tturb;
+
+	do
+	{
+		sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
+		tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
+		*r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb);
+		r_turb_s += r_turb_sstep;
+		r_turb_t += r_turb_tstep;
+	} while (--r_turb_spancount > 0);
+}
+
+
+/*
+=============
+Turbulent8
+=============
+*/
+void Turbulent8 (espan_t *pspan)
+{
+	int				count;
+	fixed16_t		snext, tnext;
+	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
+	float			sdivz16stepu, tdivz16stepu, zi16stepu;
+	
+	r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
+
+	r_turb_sstep = 0;	// keep compiler happy
+	r_turb_tstep = 0;	// ditto
+
+	r_turb_pbase = (unsigned char *)cacheblock;
+
+	sdivz16stepu = d_sdivzstepu * 16;
+	tdivz16stepu = d_tdivzstepu * 16;
+	zi16stepu = d_zistepu * 16;
+
+	do
+	{
+		r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
+				(r_screenwidth * pspan->v) + pspan->u);
+
+		count = pspan->count;
+
+	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
+		du = (float)pspan->u;
+		dv = (float)pspan->v;
+
+		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+		r_turb_s = (int)(sdivz * z) + sadjust;
+		if (r_turb_s > bbextents)
+			r_turb_s = bbextents;
+		else if (r_turb_s < 0)
+			r_turb_s = 0;
+
+		r_turb_t = (int)(tdivz * z) + tadjust;
+		if (r_turb_t > bbextentt)
+			r_turb_t = bbextentt;
+		else if (r_turb_t < 0)
+			r_turb_t = 0;
+
+		do
+		{
+		// calculate s and t at the far end of the span
+			if (count >= 16)
+				r_turb_spancount = 16;
+			else
+				r_turb_spancount = count;
+
+			count -= r_turb_spancount;
+
+			if (count)
+			{
+			// calculate s/z, t/z, zi->fixed s and t at far end of span,
+			// calculate s and t steps across span by shifting
+				sdivz += sdivz16stepu;
+				tdivz += tdivz16stepu;
+				zi += zi16stepu;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+				snext = (int)(sdivz * z) + sadjust;
+				if (snext > bbextents)
+					snext = bbextents;
+				else if (snext < 16)
+					snext = 16;	// prevent round-off error on <0 steps from
+								//  from causing overstepping & running off the
+								//  edge of the texture
+
+				tnext = (int)(tdivz * z) + tadjust;
+				if (tnext > bbextentt)
+					tnext = bbextentt;
+				else if (tnext < 16)
+					tnext = 16;	// guard against round-off error on <0 steps
+
+				r_turb_sstep = (snext - r_turb_s) >> 4;
+				r_turb_tstep = (tnext - r_turb_t) >> 4;
+			}
+			else
+			{
+			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+			// can't step off polygon), clamp, calculate s and t steps across
+			// span by division, biasing steps low so we don't run off the
+			// texture
+				spancountminus1 = (float)(r_turb_spancount - 1);
+				sdivz += d_sdivzstepu * spancountminus1;
+				tdivz += d_tdivzstepu * spancountminus1;
+				zi += d_zistepu * spancountminus1;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+				snext = (int)(sdivz * z) + sadjust;
+				if (snext > bbextents)
+					snext = bbextents;
+				else if (snext < 16)
+					snext = 16;	// prevent round-off error on <0 steps from
+								//  from causing overstepping & running off the
+								//  edge of the texture
+
+				tnext = (int)(tdivz * z) + tadjust;
+				if (tnext > bbextentt)
+					tnext = bbextentt;
+				else if (tnext < 16)
+					tnext = 16;	// guard against round-off error on <0 steps
+
+				if (r_turb_spancount > 1)
+				{
+					r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
+					r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
+				}
+			}
+
+			r_turb_s = r_turb_s & ((CYCLE<<16)-1);
+			r_turb_t = r_turb_t & ((CYCLE<<16)-1);
+
+			D_DrawTurbulent8Span ();
+
+			r_turb_s = snext;
+			r_turb_t = tnext;
+
+		} while (count > 0);
+
+	} while ((pspan = pspan->pnext) != NULL);
+}
+
+//====================
+//PGM
+/*
+=============
+NonTurbulent8 - this is for drawing scrolling textures. they're warping water textures
+	but the turbulence is automatically 0.
+=============
+*/
+void NonTurbulent8 (espan_t *pspan)
+{
+	int				count;
+	fixed16_t		snext, tnext;
+	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
+	float			sdivz16stepu, tdivz16stepu, zi16stepu;
+	
+//	r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
+	r_turb_turb = blanktable;
+
+	r_turb_sstep = 0;	// keep compiler happy
+	r_turb_tstep = 0;	// ditto
+
+	r_turb_pbase = (unsigned char *)cacheblock;
+
+	sdivz16stepu = d_sdivzstepu * 16;
+	tdivz16stepu = d_tdivzstepu * 16;
+	zi16stepu = d_zistepu * 16;
+
+	do
+	{
+		r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
+				(r_screenwidth * pspan->v) + pspan->u);
+
+		count = pspan->count;
+
+	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
+		du = (float)pspan->u;
+		dv = (float)pspan->v;
+
+		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+		r_turb_s = (int)(sdivz * z) + sadjust;
+		if (r_turb_s > bbextents)
+			r_turb_s = bbextents;
+		else if (r_turb_s < 0)
+			r_turb_s = 0;
+
+		r_turb_t = (int)(tdivz * z) + tadjust;
+		if (r_turb_t > bbextentt)
+			r_turb_t = bbextentt;
+		else if (r_turb_t < 0)
+			r_turb_t = 0;
+
+		do
+		{
+		// calculate s and t at the far end of the span
+			if (count >= 16)
+				r_turb_spancount = 16;
+			else
+				r_turb_spancount = count;
+
+			count -= r_turb_spancount;
+
+			if (count)
+			{
+			// calculate s/z, t/z, zi->fixed s and t at far end of span,
+			// calculate s and t steps across span by shifting
+				sdivz += sdivz16stepu;
+				tdivz += tdivz16stepu;
+				zi += zi16stepu;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+				snext = (int)(sdivz * z) + sadjust;
+				if (snext > bbextents)
+					snext = bbextents;
+				else if (snext < 16)
+					snext = 16;	// prevent round-off error on <0 steps from
+								//  from causing overstepping & running off the
+								//  edge of the texture
+
+				tnext = (int)(tdivz * z) + tadjust;
+				if (tnext > bbextentt)
+					tnext = bbextentt;
+				else if (tnext < 16)
+					tnext = 16;	// guard against round-off error on <0 steps
+
+				r_turb_sstep = (snext - r_turb_s) >> 4;
+				r_turb_tstep = (tnext - r_turb_t) >> 4;
+			}
+			else
+			{
+			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+			// can't step off polygon), clamp, calculate s and t steps across
+			// span by division, biasing steps low so we don't run off the
+			// texture
+				spancountminus1 = (float)(r_turb_spancount - 1);
+				sdivz += d_sdivzstepu * spancountminus1;
+				tdivz += d_tdivzstepu * spancountminus1;
+				zi += d_zistepu * spancountminus1;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+				snext = (int)(sdivz * z) + sadjust;
+				if (snext > bbextents)
+					snext = bbextents;
+				else if (snext < 16)
+					snext = 16;	// prevent round-off error on <0 steps from
+								//  from causing overstepping & running off the
+								//  edge of the texture
+
+				tnext = (int)(tdivz * z) + tadjust;
+				if (tnext > bbextentt)
+					tnext = bbextentt;
+				else if (tnext < 16)
+					tnext = 16;	// guard against round-off error on <0 steps
+
+				if (r_turb_spancount > 1)
+				{
+					r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
+					r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
+				}
+			}
+
+			r_turb_s = r_turb_s & ((CYCLE<<16)-1);
+			r_turb_t = r_turb_t & ((CYCLE<<16)-1);
+
+			D_DrawTurbulent8Span ();
+
+			r_turb_s = snext;
+			r_turb_t = tnext;
+
+		} while (count > 0);
+
+	} while ((pspan = pspan->pnext) != NULL);
+}
+//PGM
+//====================
+
+
+/*
+=============
+D_DrawSpans16
+
+  FIXME: actually make this subdivide by 16 instead of 8!!!
+=============
+*/
+void D_DrawSpans16 (espan_t *pspan)
+{
+	int				count, spancount;
+	unsigned char	*pbase, *pdest;
+	fixed16_t		s, t, snext, tnext, sstep, tstep;
+	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
+	float			sdivz8stepu, tdivz8stepu, zi8stepu;
+
+	sstep = 0;	// keep compiler happy
+	tstep = 0;	// ditto
+
+	pbase = (unsigned char *)cacheblock;
+
+	sdivz8stepu = d_sdivzstepu * 8;
+	tdivz8stepu = d_tdivzstepu * 8;
+	zi8stepu = d_zistepu * 8;
+
+	do
+	{
+		pdest = (unsigned char *)((byte *)d_viewbuffer +
+				(r_screenwidth * pspan->v) + pspan->u);
+
+		count = pspan->count;
+
+	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
+		du = (float)pspan->u;
+		dv = (float)pspan->v;
+
+		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+		s = (int)(sdivz * z) + sadjust;
+		if (s > bbextents)
+			s = bbextents;
+		else if (s < 0)
+			s = 0;
+
+		t = (int)(tdivz * z) + tadjust;
+		if (t > bbextentt)
+			t = bbextentt;
+		else if (t < 0)
+			t = 0;
+
+		do
+		{
+		// calculate s and t at the far end of the span
+			if (count >= 8)
+				spancount = 8;
+			else
+				spancount = count;
+
+			count -= spancount;
+
+			if (count)
+			{
+			// calculate s/z, t/z, zi->fixed s and t at far end of span,
+			// calculate s and t steps across span by shifting
+				sdivz += sdivz8stepu;
+				tdivz += tdivz8stepu;
+				zi += zi8stepu;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+				snext = (int)(sdivz * z) + sadjust;
+				if (snext > bbextents)
+					snext = bbextents;
+				else if (snext < 8)
+					snext = 8;	// prevent round-off error on <0 steps from
+								//  from causing overstepping & running off the
+								//  edge of the texture
+
+				tnext = (int)(tdivz * z) + tadjust;
+				if (tnext > bbextentt)
+					tnext = bbextentt;
+				else if (tnext < 8)
+					tnext = 8;	// guard against round-off error on <0 steps
+
+				sstep = (snext - s) >> 3;
+				tstep = (tnext - t) >> 3;
+			}
+			else
+			{
+			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+			// can't step off polygon), clamp, calculate s and t steps across
+			// span by division, biasing steps low so we don't run off the
+			// texture
+				spancountminus1 = (float)(spancount - 1);
+				sdivz += d_sdivzstepu * spancountminus1;
+				tdivz += d_tdivzstepu * spancountminus1;
+				zi += d_zistepu * spancountminus1;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+				snext = (int)(sdivz * z) + sadjust;
+				if (snext > bbextents)
+					snext = bbextents;
+				else if (snext < 8)
+					snext = 8;	// prevent round-off error on <0 steps from
+								//  from causing overstepping & running off the
+								//  edge of the texture
+
+				tnext = (int)(tdivz * z) + tadjust;
+				if (tnext > bbextentt)
+					tnext = bbextentt;
+				else if (tnext < 8)
+					tnext = 8;	// guard against round-off error on <0 steps
+
+				if (spancount > 1)
+				{
+					sstep = (snext - s) / (spancount - 1);
+					tstep = (tnext - t) / (spancount - 1);
+				}
+			}
+
+			do
+			{
+				*pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
+				s += sstep;
+				t += tstep;
+			} while (--spancount > 0);
+
+			s = snext;
+			t = tnext;
+
+		} while (count > 0);
+
+	} while ((pspan = pspan->pnext) != NULL);
+}
+
+
+/*
+=============
+D_DrawZSpans
+=============
+*/
+void D_DrawZSpans (espan_t *pspan)
+{
+	int				count, doublecount, izistep;
+	int				izi;
+	short			*pdest;
+	unsigned		ltemp;
+	float			zi;
+	float			du, dv;
+
+// FIXME: check for clamping/range problems
+// we count on FP exceptions being turned off to avoid range problems
+	izistep = (int)(d_zistepu * 0x8000 * 0x10000);
+
+	do
+	{
+		pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
+
+		count = pspan->count;
+
+	// calculate the initial 1/z
+		du = (float)pspan->u;
+		dv = (float)pspan->v;
+
+		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+	// we count on FP exceptions being turned off to avoid range problems
+		izi = (int)(zi * 0x8000 * 0x10000);
+
+		if ((uintptr)pdest & 0x02)
+		{
+			*pdest++ = (short)(izi >> 16);
+			izi += izistep;
+			count--;
+		}
+
+		if ((doublecount = count >> 1) > 0)
+		{
+			do
+			{
+				ltemp = izi >> 16;
+				izi += izistep;
+				ltemp |= izi & 0xFFFF0000;
+				izi += izistep;
+				*(int *)pdest = ltemp;
+				pdest += 2;
+			} while (--doublecount > 0);
+		}
+
+		if (count & 1)
+			*pdest = (short)(izi >> 16);
+
+	} while ((pspan = pspan->pnext) != NULL);
+}
--- /dev/null
+++ b/r_sprite.c
@@ -1,0 +1,107 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+extern polydesc_t r_polydesc;
+
+void R_BuildPolygonFromSurface(msurface_t *fa);
+void R_PolygonCalculateGradients (void);
+
+extern void R_PolyChooseSpanletRoutine( float alpha, qboolean isturbulent );
+
+extern vec5_t r_clip_verts[2][MAXWORKINGVERTS+2];
+
+extern void	R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured );
+
+/*
+** R_DrawSprite
+**
+** Draw currententity / currentmodel as a single texture
+** mapped polygon
+*/
+void R_DrawSprite (void)
+{
+	vec5_t		*pverts;
+	vec3_t		left, up, right, down;
+	dsprite_t	*s_psprite;
+	dsprframe_t	*s_psprframe;
+
+
+	s_psprite = (dsprite_t *)currentmodel->extradata;
+/*
+	if (currententity->frame >= s_psprite->numframes
+		|| currententity->frame < 0)
+	{
+		ri.Con_Printf (PRINT_ALL, "No such sprite frame %i\n", 
+			currententity->frame);
+		currententity->frame = 0;
+	}
+*/
+	currententity->frame %= s_psprite->numframes;
+
+	s_psprframe = &s_psprite->frames[currententity->frame];
+
+	r_polydesc.pixels       = currentmodel->skins[currententity->frame]->pixels[0];
+	r_polydesc.pixel_width  = s_psprframe->width;
+	r_polydesc.pixel_height = s_psprframe->height;
+	r_polydesc.dist         = 0;
+
+	// generate the sprite's axes, completely parallel to the viewplane.
+	VectorCopy (vup, r_polydesc.vup);
+	VectorCopy (vright, r_polydesc.vright);
+	VectorCopy (vpn, r_polydesc.vpn);
+
+// build the sprite poster in worldspace
+	VectorScale (r_polydesc.vright, 
+		s_psprframe->width - s_psprframe->origin_x, right);
+	VectorScale (r_polydesc.vup, 
+		s_psprframe->height - s_psprframe->origin_y, up);
+	VectorScale (r_polydesc.vright,
+		-s_psprframe->origin_x, left);
+	VectorScale (r_polydesc.vup,
+		-s_psprframe->origin_y, down);
+
+	// invert UP vector for sprites
+	VectorInverse( r_polydesc.vup );
+
+	pverts = r_clip_verts[0];
+
+	pverts[0][0] = r_entorigin[0] + up[0] + left[0];
+	pverts[0][1] = r_entorigin[1] + up[1] + left[1];
+	pverts[0][2] = r_entorigin[2] + up[2] + left[2];
+	pverts[0][3] = 0;
+	pverts[0][4] = 0;
+
+	pverts[1][0] = r_entorigin[0] + up[0] + right[0];
+	pverts[1][1] = r_entorigin[1] + up[1] + right[1];
+	pverts[1][2] = r_entorigin[2] + up[2] + right[2];
+	pverts[1][3] = s_psprframe->width;
+	pverts[1][4] = 0;
+
+	pverts[2][0] = r_entorigin[0] + down[0] + right[0];
+	pverts[2][1] = r_entorigin[1] + down[1] + right[1];
+	pverts[2][2] = r_entorigin[2] + down[2] + right[2];
+	pverts[2][3] = s_psprframe->width;
+	pverts[2][4] = s_psprframe->height;
+
+	pverts[3][0] = r_entorigin[0] + down[0] + left[0];
+	pverts[3][1] = r_entorigin[1] + down[1] + left[1];
+	pverts[3][2] = r_entorigin[2] + down[2] + left[2];
+	pverts[3][3] = 0;
+	pverts[3][4] = s_psprframe->height;
+
+	r_polydesc.nump = 4;
+	r_polydesc.s_offset = ( r_polydesc.pixel_width  >> 1);
+	r_polydesc.t_offset = ( r_polydesc.pixel_height >> 1);
+	VectorCopy( modelorg, r_polydesc.viewer_position );
+
+	r_polydesc.stipple_parity = 1;
+	if ( currententity->flags & RF_TRANSLUCENT )
+		R_ClipAndDrawPoly ( currententity->alpha, false, true );
+	else
+		R_ClipAndDrawPoly ( 1.0F, false, true );
+	r_polydesc.stipple_parity = 0;
+}
+
--- /dev/null
+++ b/r_surf.c
@@ -1,0 +1,633 @@
+// r_surf.c: surface-related refresh code
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+drawsurf_t	r_drawsurf;
+
+int				lightleft, sourcesstep, blocksize, sourcetstep;
+int				lightdelta, lightdeltastep;
+int				lightright, lightleftstep, lightrightstep, blockdivshift;
+unsigned		blockdivmask;
+void			*prowdestbase;
+unsigned char	*pbasesource;
+int				surfrowbytes;	// used by ASM files
+unsigned		*r_lightptr;
+int				r_stepback;
+int				r_lightwidth;
+int				r_numhblocks, r_numvblocks;
+unsigned char	*r_source, *r_sourcemax;
+
+void R_DrawSurfaceBlock8_mip0 (void);
+void R_DrawSurfaceBlock8_mip1 (void);
+void R_DrawSurfaceBlock8_mip2 (void);
+void R_DrawSurfaceBlock8_mip3 (void);
+
+static void	(*surfmiptable[4])(void) = {
+	R_DrawSurfaceBlock8_mip0,
+	R_DrawSurfaceBlock8_mip1,
+	R_DrawSurfaceBlock8_mip2,
+	R_DrawSurfaceBlock8_mip3
+};
+
+void R_BuildLightMap (void);
+extern	unsigned		blocklights[1024];	// allow some very large lightmaps
+
+float           surfscale;
+qboolean        r_cache_thrash;         // set if surface cache is thrashing
+
+int         sc_size;
+surfcache_t	*sc_rover, *sc_base;
+
+/*
+===============
+R_TextureAnimation
+
+Returns the proper texture for a given time and base texture
+===============
+*/
+image_t *R_TextureAnimation (mtexinfo_t *tex)
+{
+	int		c;
+
+	if (!tex->next)
+		return tex->image;
+
+	c = currententity->frame % tex->numframes;
+	while (c)
+	{
+		tex = tex->next;
+		c--;
+	}
+
+	return tex->image;
+}
+
+
+/*
+===============
+R_DrawSurface
+===============
+*/
+void R_DrawSurface (void)
+{
+	unsigned char	*basetptr;
+	int				smax, tmax, twidth;
+	int				u;
+	int				soffset, basetoffset, texwidth;
+	int				horzblockstep;
+	unsigned char	*pcolumndest;
+	void			(*pblockdrawer)(void);
+	image_t			*mt;
+
+	surfrowbytes = r_drawsurf.rowbytes;
+
+	mt = r_drawsurf.image;
+	
+	r_source = mt->pixels[r_drawsurf.surfmip];
+	
+// the fractional light values should range from 0 to (VID_GRADES - 1) << 16
+// from a source range of 0 - 255
+	
+	texwidth = mt->width >> r_drawsurf.surfmip;
+
+	blocksize = 16 >> r_drawsurf.surfmip;
+	blockdivshift = 4 - r_drawsurf.surfmip;
+	blockdivmask = (1 << blockdivshift) - 1;
+	
+	r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1;
+
+	r_numhblocks = r_drawsurf.surfwidth >> blockdivshift;
+	r_numvblocks = r_drawsurf.surfheight >> blockdivshift;
+
+//==============================
+
+	pblockdrawer = surfmiptable[r_drawsurf.surfmip];
+// TODO: only needs to be set when there is a display settings change
+	horzblockstep = blocksize;
+
+	smax = mt->width >> r_drawsurf.surfmip;
+	twidth = texwidth;
+	tmax = mt->height >> r_drawsurf.surfmip;
+	sourcetstep = texwidth;
+	r_stepback = tmax * twidth;
+
+	r_sourcemax = r_source + (tmax * smax);
+
+	soffset = r_drawsurf.surf->texturemins[0];
+	basetoffset = r_drawsurf.surf->texturemins[1];
+
+// << 16 components are to guarantee positive values for %
+	soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax;
+	basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip) 
+		+ (tmax << 16)) % tmax) * twidth)];
+
+	pcolumndest = r_drawsurf.surfdat;
+
+	for (u=0 ; u<r_numhblocks; u++)
+	{
+		r_lightptr = blocklights + u;
+
+		prowdestbase = pcolumndest;
+
+		pbasesource = basetptr + soffset;
+
+		(*pblockdrawer)();
+
+		soffset = soffset + blocksize;
+		if (soffset >= smax)
+			soffset = 0;
+
+		pcolumndest += horzblockstep;
+	}
+}
+
+
+//=============================================================================
+
+
+/*
+================
+R_DrawSurfaceBlock8_mip0
+================
+*/
+void R_DrawSurfaceBlock8_mip0 (void)
+{
+	int				v, i, b, lightstep, lighttemp, light;
+	unsigned char	pix, *psource, *prowdest;
+
+	psource = pbasesource;
+	prowdest = prowdestbase;
+
+	for (v=0 ; v<r_numvblocks ; v++)
+	{
+	// FIXME: make these locals?
+	// FIXME: use delta rather than both right and left, like ASM?
+		lightleft = r_lightptr[0];
+		lightright = r_lightptr[1];
+		r_lightptr += r_lightwidth;
+		lightleftstep = (r_lightptr[0] - lightleft) >> 4;
+		lightrightstep = (r_lightptr[1] - lightright) >> 4;
+
+		for (i=0 ; i<16 ; i++)
+		{
+			lighttemp = lightleft - lightright;
+			lightstep = lighttemp >> 4;
+
+			light = lightright;
+
+			for (b=15; b>=0; b--)
+			{
+				pix = psource[b];
+				prowdest[b] = ((unsigned char *)vid.colormap)
+						[(light & 0xFF00) + pix];
+				light += lightstep;
+			}
+	
+			psource += sourcetstep;
+			lightright += lightrightstep;
+			lightleft += lightleftstep;
+			prowdest += surfrowbytes;
+		}
+
+		if (psource >= r_sourcemax)
+			psource -= r_stepback;
+	}
+}
+
+
+/*
+================
+R_DrawSurfaceBlock8_mip1
+================
+*/
+void R_DrawSurfaceBlock8_mip1 (void)
+{
+	int				v, i, b, lightstep, lighttemp, light;
+	unsigned char	pix, *psource, *prowdest;
+
+	psource = pbasesource;
+	prowdest = prowdestbase;
+
+	for (v=0 ; v<r_numvblocks ; v++)
+	{
+	// FIXME: make these locals?
+	// FIXME: use delta rather than both right and left, like ASM?
+		lightleft = r_lightptr[0];
+		lightright = r_lightptr[1];
+		r_lightptr += r_lightwidth;
+		lightleftstep = (r_lightptr[0] - lightleft) >> 3;
+		lightrightstep = (r_lightptr[1] - lightright) >> 3;
+
+		for (i=0 ; i<8 ; i++)
+		{
+			lighttemp = lightleft - lightright;
+			lightstep = lighttemp >> 3;
+
+			light = lightright;
+
+			for (b=7; b>=0; b--)
+			{
+				pix = psource[b];
+				prowdest[b] = ((unsigned char *)vid.colormap)
+						[(light & 0xFF00) + pix];
+				light += lightstep;
+			}
+	
+			psource += sourcetstep;
+			lightright += lightrightstep;
+			lightleft += lightleftstep;
+			prowdest += surfrowbytes;
+		}
+
+		if (psource >= r_sourcemax)
+			psource -= r_stepback;
+	}
+}
+
+
+/*
+================
+R_DrawSurfaceBlock8_mip2
+================
+*/
+void R_DrawSurfaceBlock8_mip2 (void)
+{
+	int				v, i, b, lightstep, lighttemp, light;
+	unsigned char	pix, *psource, *prowdest;
+
+	psource = pbasesource;
+	prowdest = prowdestbase;
+
+	for (v=0 ; v<r_numvblocks ; v++)
+	{
+	// FIXME: make these locals?
+	// FIXME: use delta rather than both right and left, like ASM?
+		lightleft = r_lightptr[0];
+		lightright = r_lightptr[1];
+		r_lightptr += r_lightwidth;
+		lightleftstep = (r_lightptr[0] - lightleft) >> 2;
+		lightrightstep = (r_lightptr[1] - lightright) >> 2;
+
+		for (i=0 ; i<4 ; i++)
+		{
+			lighttemp = lightleft - lightright;
+			lightstep = lighttemp >> 2;
+
+			light = lightright;
+
+			for (b=3; b>=0; b--)
+			{
+				pix = psource[b];
+				prowdest[b] = ((unsigned char *)vid.colormap)
+						[(light & 0xFF00) + pix];
+				light += lightstep;
+			}
+	
+			psource += sourcetstep;
+			lightright += lightrightstep;
+			lightleft += lightleftstep;
+			prowdest += surfrowbytes;
+		}
+
+		if (psource >= r_sourcemax)
+			psource -= r_stepback;
+	}
+}
+
+
+/*
+================
+R_DrawSurfaceBlock8_mip3
+================
+*/
+void R_DrawSurfaceBlock8_mip3 (void)
+{
+	int				v, i, b, lightstep, lighttemp, light;
+	unsigned char	pix, *psource, *prowdest;
+
+	psource = pbasesource;
+	prowdest = prowdestbase;
+
+	for (v=0 ; v<r_numvblocks ; v++)
+	{
+	// FIXME: make these locals?
+	// FIXME: use delta rather than both right and left, like ASM?
+		lightleft = r_lightptr[0];
+		lightright = r_lightptr[1];
+		r_lightptr += r_lightwidth;
+		lightleftstep = (r_lightptr[0] - lightleft) >> 1;
+		lightrightstep = (r_lightptr[1] - lightright) >> 1;
+
+		for (i=0 ; i<2 ; i++)
+		{
+			lighttemp = lightleft - lightright;
+			lightstep = lighttemp >> 1;
+
+			light = lightright;
+
+			for (b=1; b>=0; b--)
+			{
+				pix = psource[b];
+				prowdest[b] = ((unsigned char *)vid.colormap)
+						[(light & 0xFF00) + pix];
+				light += lightstep;
+			}
+	
+			psource += sourcetstep;
+			lightright += lightrightstep;
+			lightleft += lightleftstep;
+			prowdest += surfrowbytes;
+		}
+
+		if (psource >= r_sourcemax)
+			psource -= r_stepback;
+	}
+}
+
+
+//============================================================================
+
+
+/*
+================
+R_InitCaches
+
+================
+*/
+void R_InitCaches (void)
+{
+	int		size;
+	int		pix;
+
+	// calculate size to allocate
+	if (sw_surfcacheoverride->value)
+	{
+		size = sw_surfcacheoverride->value;
+	}
+	else
+	{
+		size = SURFCACHE_SIZE_AT_320X240;
+
+		pix = vid.width*vid.height;
+		if (pix > 64000)
+			size += (pix-64000)*3;
+	}		
+
+	// round up to page size
+	size = (size + 8191) & ~8191;
+
+	ri.Con_Printf (PRINT_ALL,"%ik surface cache\n", size/1024);
+
+	sc_size = size;
+	sc_base = (surfcache_t *)malloc(size);
+	sc_rover = sc_base;
+	
+	sc_base->next = NULL;
+	sc_base->owner = NULL;
+	sc_base->size = sc_size;
+}
+
+
+/*
+==================
+D_FlushCaches
+==================
+*/
+void D_FlushCaches (void)
+{
+	surfcache_t     *c;
+	
+	if (!sc_base)
+		return;
+
+	for (c = sc_base ; c ; c = c->next)
+	{
+		if (c->owner)
+			*c->owner = NULL;
+	}
+	
+	sc_rover = sc_base;
+	sc_base->next = NULL;
+	sc_base->owner = NULL;
+	sc_base->size = sc_size;
+}
+
+/*
+=================
+D_SCAlloc
+=================
+*/
+surfcache_t     *D_SCAlloc (int width, int size)
+{
+	surfcache_t             *new;
+	qboolean                wrapped_this_time;
+
+	if ((width < 0) || (width > 256))
+		ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache width %d\n", width);
+
+	if ((size <= 0) || (size > 0x10000))
+		ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache size %d\n", size);
+	
+	size = (int)(uintptr)&((surfcache_t *)0)->data[size];
+	size = (size + 3) & ~3;
+	if (size > sc_size)
+		ri.Sys_Error (ERR_FATAL,"D_SCAlloc: %i > cache size of %i",size, sc_size);
+
+// if there is not size bytes after the rover, reset to the start
+	wrapped_this_time = false;
+
+	if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size)
+	{
+		if (sc_rover)
+		{
+			wrapped_this_time = true;
+		}
+		sc_rover = sc_base;
+	}
+		
+// colect and free surfcache_t blocks until the rover block is large enough
+	new = sc_rover;
+	if (sc_rover->owner)
+		*sc_rover->owner = NULL;
+	
+	while (new->size < size)
+	{
+	// free another
+		sc_rover = sc_rover->next;
+		if (!sc_rover)
+			ri.Sys_Error (ERR_FATAL,"D_SCAlloc: hit the end of memory");
+		if (sc_rover->owner)
+			*sc_rover->owner = NULL;
+			
+		new->size += sc_rover->size;
+		new->next = sc_rover->next;
+	}
+
+// create a fragment out of any leftovers
+	if (new->size - size > 256)
+	{
+		sc_rover = (surfcache_t *)( (byte *)new + size);
+		sc_rover->size = new->size - size;
+		sc_rover->next = new->next;
+		sc_rover->width = 0;
+		sc_rover->owner = NULL;
+		new->next = sc_rover;
+		new->size = size;
+	}
+	else
+		sc_rover = new->next;
+	
+	new->width = width;
+// DEBUG
+	if (width > 0)
+		new->height = (size - sizeof(*new) + sizeof(new->data)) / width;
+
+	new->owner = NULL;              // should be set properly after return
+
+	if (d_roverwrapped)
+	{
+		if (wrapped_this_time || (sc_rover >= d_initial_rover))
+			r_cache_thrash = true;
+	}
+	else if (wrapped_this_time)
+	{       
+		d_roverwrapped = true;
+	}
+
+	return new;
+}
+
+
+/*
+=================
+D_SCDump
+=================
+*/
+void D_SCDump (void)
+{
+	surfcache_t             *test;
+
+	for (test = sc_base ; test ; test = test->next)
+	{
+		if (test == sc_rover)
+			ri.Con_Printf (PRINT_ALL,"ROVER:\n");
+		ri.Con_Printf (PRINT_ALL,"%p : %i bytes     %i width\n",test, test->size, test->width);
+	}
+}
+
+//=============================================================================
+
+// if the num is not a power of 2, assume it will not repeat
+
+int     MaskForNum (int num)
+{
+	if (num==128)
+		return 127;
+	if (num==64)
+		return 63;
+	if (num==32)
+		return 31;
+	if (num==16)
+		return 15;
+	return 255;
+}
+
+int D_log2 (int num)
+{
+	int     c;
+	
+	c = 0;
+	
+	while (num>>=1)
+		c++;
+	return c;
+}
+
+//=============================================================================
+
+/*
+================
+D_CacheSurface
+================
+*/
+surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
+{
+	surfcache_t     *cache;
+
+//
+// if the surface is animating or flashing, flush the cache
+//
+	r_drawsurf.image = R_TextureAnimation (surface->texinfo);
+	r_drawsurf.lightadj[0] = r_newrefdef.lightstyles[surface->styles[0]].white*128;
+	r_drawsurf.lightadj[1] = r_newrefdef.lightstyles[surface->styles[1]].white*128;
+	r_drawsurf.lightadj[2] = r_newrefdef.lightstyles[surface->styles[2]].white*128;
+	r_drawsurf.lightadj[3] = r_newrefdef.lightstyles[surface->styles[3]].white*128;
+	
+//
+// see if the cache holds apropriate data
+//
+	cache = surface->cachespots[miplevel];
+
+	if (cache && !cache->dlight && surface->dlightframe != r_framecount
+			&& cache->image == r_drawsurf.image
+			&& cache->lightadj[0] == r_drawsurf.lightadj[0]
+			&& cache->lightadj[1] == r_drawsurf.lightadj[1]
+			&& cache->lightadj[2] == r_drawsurf.lightadj[2]
+			&& cache->lightadj[3] == r_drawsurf.lightadj[3] )
+		return cache;
+
+//
+// determine shape of surface
+//
+	surfscale = 1.0 / (1<<miplevel);
+	r_drawsurf.surfmip = miplevel;
+	r_drawsurf.surfwidth = surface->extents[0] >> miplevel;
+	r_drawsurf.rowbytes = r_drawsurf.surfwidth;
+	r_drawsurf.surfheight = surface->extents[1] >> miplevel;
+	
+//
+// allocate memory if needed
+//
+	if (!cache)     // if a texture just animated, don't reallocate it
+	{
+		cache = D_SCAlloc (r_drawsurf.surfwidth,
+						   r_drawsurf.surfwidth * r_drawsurf.surfheight);
+		surface->cachespots[miplevel] = cache;
+		cache->owner = &surface->cachespots[miplevel];
+		cache->mipscale = surfscale;
+	}
+	
+	if (surface->dlightframe == r_framecount)
+		cache->dlight = 1;
+	else
+		cache->dlight = 0;
+
+	r_drawsurf.surfdat = (pixel_t *)cache->data;
+	
+	cache->image = r_drawsurf.image;
+	cache->lightadj[0] = r_drawsurf.lightadj[0];
+	cache->lightadj[1] = r_drawsurf.lightadj[1];
+	cache->lightadj[2] = r_drawsurf.lightadj[2];
+	cache->lightadj[3] = r_drawsurf.lightadj[3];
+
+//
+// draw and light the surface texture
+//
+	r_drawsurf.surf = surface;
+
+	c_surf++;
+
+	// calculate the lightings
+	R_BuildLightMap ();
+	
+	// rasterize the surface into the cache
+	R_DrawSurface ();
+
+	return cache;
+}
+
+
--- /dev/null
+++ b/rand1k.h
@@ -1,0 +1,104 @@
+// 1K random numbers in the range 0-255
+0, 144, 49, 207, 149, 122, 89, 229, 210, 191,
+44, 219, 181, 131, 77, 3, 23, 93, 37, 42,
+253, 114, 30, 1, 2, 96, 136, 146, 154, 155,
+42, 169, 115, 90, 14, 155, 200, 205, 133, 77,
+224, 186, 244, 236, 138, 36, 118, 60, 220, 53,
+199, 215, 255, 255, 156, 100, 68, 76, 215, 6,
+96, 23, 173, 14, 2, 235, 70, 69, 150, 176,
+214, 185, 124, 52, 190, 119, 117, 242, 190, 27,
+153, 98, 188, 155, 146, 92, 38, 57, 108, 205,
+132, 253, 192, 88, 43, 168, 125, 16, 179, 129,
+37, 243, 36, 231, 177, 77, 109, 18, 247, 174,
+39, 224, 210, 149, 48, 45, 209, 121, 39, 129,
+187, 103, 71, 145, 174, 193, 184, 121, 31, 94,
+213, 8, 132, 169, 109, 26, 243, 235, 140, 88,
+120, 95, 216, 81, 116, 69, 251, 76, 189, 145,
+50, 194, 214, 101, 128, 227, 7, 254, 146, 12,
+136, 49, 215, 160, 168, 50, 215, 31, 28, 190,
+80, 240, 73, 86, 35, 187, 213, 181, 153, 191,
+64, 36, 0, 15, 206, 218, 53, 29, 141, 3,
+29, 116, 192, 175, 139, 18, 111, 51, 178, 74,
+111, 59, 147, 136, 160, 41, 129, 246, 178, 236,
+48, 86, 45, 254, 117, 255, 24, 160, 24, 112,
+238, 12, 229, 74, 58, 196, 105, 51, 160, 154,
+115, 119, 153, 162, 218, 212, 159, 184, 144, 96,
+47, 188, 142, 231, 62, 48, 154, 178, 149, 89,
+126, 20, 189, 156, 158, 176, 205, 38, 147, 222,
+233, 157, 186, 11, 170, 249, 80, 145, 78, 44,
+27, 222, 217, 190, 39, 83, 20, 19, 164, 209,
+139, 114, 104, 76, 119, 128, 39, 82, 188, 80,
+211, 245, 223, 185, 76, 241, 32, 16, 200, 134,
+156, 244, 18, 224, 167, 82, 26, 129, 58, 74,
+235, 141, 169, 29, 126, 97, 127, 203, 130, 97,
+176, 136, 155, 101, 1, 181, 25, 159, 220, 125,
+191, 127, 97, 201, 141, 91, 244, 161, 45, 95,
+33, 190, 243, 156, 7, 84, 14, 163, 33, 216,
+221, 152, 184, 218, 3, 32, 181, 157, 55, 16,
+43, 159, 87, 81, 94, 169, 205, 206, 134, 156,
+204, 230, 37, 161, 103, 64, 34, 218, 16, 109,
+146, 77, 140, 57, 79, 28, 206, 34, 72, 201,
+229, 202, 190, 157, 92, 219, 58, 221, 58, 63,
+138, 252, 13, 20, 134, 109, 24, 66, 228, 59,
+37, 32, 238, 20, 12, 15, 86, 234, 102, 110,
+242, 214, 136, 215, 177, 101, 66, 1, 134, 244,
+102, 61, 149, 65, 175, 241, 111, 227, 1, 240,
+153, 201, 147, 36, 56, 98, 1, 106, 21, 168,
+218, 16, 207, 169, 177, 205, 135, 175, 36, 176,
+186, 199, 7, 222, 164, 180, 21, 141, 242, 15,
+70, 37, 251, 158, 74, 236, 94, 177, 55, 39,
+61, 133, 230, 27, 231, 113, 20, 200, 43, 249,
+198, 222, 53, 116, 0, 192, 29, 103, 79, 254,
+9, 64, 48, 63, 39, 158, 226, 240, 50, 199,
+165, 168, 232, 116, 235, 170, 38, 162, 145, 108,
+241, 138, 148, 137, 65, 101, 89, 9, 203, 50,
+17, 99, 151, 18, 50, 39, 164, 116, 154, 178,
+112, 175, 101, 213, 151, 51, 243, 224, 100, 252,
+47, 229, 147, 113, 160, 181, 12, 73, 66, 104,
+229, 181, 186, 229, 100, 101, 231, 79, 99, 146,
+90, 187, 190, 188, 189, 35, 51, 69, 174, 233,
+94, 132, 28, 232, 51, 132, 167, 112, 176, 23,
+20, 19, 7, 90, 78, 178, 36, 101, 17, 172,
+185, 50, 177, 157, 167, 139, 25, 139, 12, 249,
+118, 248, 186, 135, 174, 177, 95, 99, 12, 207,
+43, 15, 79, 200, 54, 82, 124, 2, 112, 130,
+155, 194, 102, 89, 215, 241, 159, 255, 13, 144,
+221, 99, 78, 72, 6, 156, 100, 4, 7, 116,
+219, 239, 102, 186, 156, 206, 224, 149, 152, 20,
+203, 118, 151, 150, 145, 208, 172, 87, 2, 68,
+87, 59, 197, 95, 222, 29, 185, 161, 228, 46,
+137, 230, 199, 247, 50, 230, 204, 244, 217, 227,
+160, 47, 157, 67, 64, 187, 201, 43, 182, 123,
+20, 206, 218, 31, 78, 146, 121, 195, 49, 186,
+254, 3, 165, 177, 44, 18, 70, 173, 214, 142,
+95, 199, 59, 163, 59, 52, 248, 72, 5, 196,
+38, 12, 2, 89, 164, 87, 106, 106, 23, 139,
+179, 86, 168, 224, 137, 145, 13, 119, 66, 109,
+221, 124, 22, 144, 181, 199, 221, 217, 75, 221,
+165, 191, 212, 195, 223, 232, 233, 133, 112, 27,
+90, 210, 109, 43, 0, 168, 198, 16, 22, 98,
+175, 206, 39, 36, 12, 88, 4, 250, 165, 13,
+234, 163, 110, 5, 62, 100, 167, 200, 5, 211,
+35, 162, 140, 251, 118, 54, 76, 200, 87, 123,
+155, 26, 252, 193, 38, 116, 182, 255, 198, 164,
+159, 242, 176, 74, 145, 74, 140, 182, 63, 139,
+126, 243, 171, 195, 159, 114, 204, 190, 253, 52,
+161, 232, 151, 235, 129, 125, 115, 227, 240, 46,
+64, 51, 187, 240, 160, 10, 164, 8, 142, 139,
+114, 15, 254, 32, 153, 12, 44, 169, 85, 80,
+167, 105, 109, 56, 173, 42, 127, 129, 205, 111,
+1, 86, 96, 32, 211, 187, 228, 164, 166, 131,
+187, 188, 245, 119, 92, 28, 231, 210, 116, 27,
+222, 194, 10, 106, 239, 17, 42, 54, 29, 151,
+30, 158, 148, 176, 187, 234, 171, 76, 207, 96,
+255, 197, 52, 43, 99, 46, 148, 50, 245, 48,
+97, 77, 30, 50, 11, 197, 194, 225, 0, 114,
+109, 205, 118, 126, 191, 61, 143, 23, 236, 228,
+219, 15, 125, 161, 191, 193, 65, 232, 202, 51,
+141, 13, 133, 202, 180, 6, 187, 141, 234, 224,
+204, 78, 101, 123, 13, 166, 0, 196, 193, 56,
+39, 14, 171, 8, 88, 178, 204, 111, 251, 162,
+75, 122, 223, 20, 25, 36, 36, 235, 79, 95,
+208, 11, 208, 61, 229, 65, 68, 53, 58, 216,
+223, 227, 216, 155, 10, 44, 47, 91, 115, 47,
+228, 159, 139, 233
--- a/ref/adivtab.h
+++ /dev/null
@@ -1,1058 +1,0 @@
-// 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},
--- a/ref/r_aclip.c
+++ /dev/null
@@ -1,303 +1,0 @@
-// r_aclip.c: clip routines for drawing Alias models directly to the screen
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-static finalvert_t		fv[2][8];
-
-void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
-void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1,
-	finalvert_t *out);
-void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
-	finalvert_t *out);
-void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1,
-	finalvert_t *out);
-void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1,
-	finalvert_t *out);
-
-
-/*
-================
-R_Alias_clip_z
-
-pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex
-================
-*/
-void R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
-{
-	float		scale;
-
-	scale = (ALIAS_Z_CLIP_PLANE - pfv0->xyz[2]) /
-			(pfv1->xyz[2] - pfv0->xyz[2]);
-
-	out->xyz[0] = pfv0->xyz[0] + (pfv1->xyz[0] - pfv0->xyz[0]) * scale;
-	out->xyz[1] = pfv0->xyz[1] + (pfv1->xyz[1] - pfv0->xyz[1]) * scale;
-	out->xyz[2] = ALIAS_Z_CLIP_PLANE;
-
-	out->s =	pfv0->s + (pfv1->s - pfv0->s) * scale;
-	out->t =	pfv0->t + (pfv1->t - pfv0->t) * scale;
-	out->l =	pfv0->l + (pfv1->l - pfv0->l) * scale;
-
-	R_AliasProjectAndClipTestFinalVert (out);
-}
-
-
-void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
-{
-	float		scale;
-
-	if (pfv0->v >= pfv1->v )
-	{
-		scale = (float)(r_refdef.aliasvrect.x - pfv0->u) /
-				(pfv1->u - pfv0->u);
-		out->u  = pfv0->u  + ( pfv1->u  - pfv0->u ) * scale + 0.5;
-		out->v  = pfv0->v  + ( pfv1->v  - pfv0->v ) * scale + 0.5;
-		out->s  = pfv0->s  + ( pfv1->s  - pfv0->s ) * scale + 0.5;
-		out->t  = pfv0->t  + ( pfv1->t  - pfv0->t ) * scale + 0.5;
-		out->l  = pfv0->l  + ( pfv1->l  - pfv0->l ) * scale + 0.5;
-		out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
-	}
-	else
-	{
-		scale = (float)(r_refdef.aliasvrect.x - pfv1->u) /
-				(pfv0->u - pfv1->u);
-		out->u  = pfv1->u  + ( pfv0->u  - pfv1->u ) * scale + 0.5;
-		out->v  = pfv1->v  + ( pfv0->v  - pfv1->v ) * scale + 0.5;
-		out->s  = pfv1->s  + ( pfv0->s  - pfv1->s ) * scale + 0.5;
-		out->t  = pfv1->t  + ( pfv0->t  - pfv1->t ) * scale + 0.5;
-		out->l  = pfv1->l  + ( pfv0->l  - pfv1->l ) * scale + 0.5;
-		out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
-	}
-}
-
-
-void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
-{
-	float		scale;
-
-	if ( pfv0->v >= pfv1->v )
-	{
-		scale = (float)(r_refdef.aliasvrectright - pfv0->u ) /
-				(pfv1->u - pfv0->u );
-		out->u  = pfv0->u  + ( pfv1->u  - pfv0->u ) * scale + 0.5;
-		out->v  = pfv0->v  + ( pfv1->v  - pfv0->v ) * scale + 0.5;
-		out->s  = pfv0->s  + ( pfv1->s  - pfv0->s ) * scale + 0.5;
-		out->t  = pfv0->t  + ( pfv1->t  - pfv0->t ) * scale + 0.5;
-		out->l  = pfv0->l  + ( pfv1->l  - pfv0->l ) * scale + 0.5;
-		out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
-	}
-	else
-	{
-		scale = (float)(r_refdef.aliasvrectright - pfv1->u ) /
-				(pfv0->u - pfv1->u );
-		out->u  = pfv1->u  + ( pfv0->u  - pfv1->u ) * scale + 0.5;
-		out->v  = pfv1->v  + ( pfv0->v  - pfv1->v ) * scale + 0.5;
-		out->s  = pfv1->s  + ( pfv0->s  - pfv1->s ) * scale + 0.5;
-		out->t  = pfv1->t  + ( pfv0->t  - pfv1->t ) * scale + 0.5;
-		out->l  = pfv1->l  + ( pfv0->l  - pfv1->l ) * scale + 0.5;
-		out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
-	}
-}
-
-
-void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
-{
-	float		scale;
-
-	if (pfv0->v >= pfv1->v)
-	{
-		scale = (float)(r_refdef.aliasvrect.y - pfv0->v) /
-				(pfv1->v - pfv0->v);
-		out->u  = pfv0->u  + ( pfv1->u  - pfv0->u ) * scale + 0.5;
-		out->v  = pfv0->v  + ( pfv1->v  - pfv0->v ) * scale + 0.5;
-		out->s  = pfv0->s  + ( pfv1->s  - pfv0->s ) * scale + 0.5;
-		out->t  = pfv0->t  + ( pfv1->t  - pfv0->t ) * scale + 0.5;
-		out->l  = pfv0->l  + ( pfv1->l  - pfv0->l ) * scale + 0.5;
-		out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
-	}
-	else
-	{
-		scale = (float)(r_refdef.aliasvrect.y - pfv1->v) /
-				(pfv0->v - pfv1->v);
-		out->u  = pfv1->u  + ( pfv0->u  - pfv1->u ) * scale + 0.5;
-		out->v  = pfv1->v  + ( pfv0->v  - pfv1->v ) * scale + 0.5;
-		out->s  = pfv1->s  + ( pfv0->s  - pfv1->s ) * scale + 0.5;
-		out->t  = pfv1->t  + ( pfv0->t  - pfv1->t ) * scale + 0.5;
-		out->l  = pfv1->l  + ( pfv0->l  - pfv1->l ) * scale + 0.5;
-		out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
-	}
-}
-
-
-void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
-	finalvert_t *out)
-{
-	float		scale;
-
-	if (pfv0->v >= pfv1->v)
-	{
-		scale = (float)(r_refdef.aliasvrectbottom - pfv0->v) /
-				(pfv1->v - pfv0->v);
-
-		out->u  = pfv0->u  + ( pfv1->u  - pfv0->u ) * scale + 0.5;
-		out->v  = pfv0->v  + ( pfv1->v  - pfv0->v ) * scale + 0.5;
-		out->s  = pfv0->s  + ( pfv1->s  - pfv0->s ) * scale + 0.5;
-		out->t  = pfv0->t  + ( pfv1->t  - pfv0->t ) * scale + 0.5;
-		out->l  = pfv0->l  + ( pfv1->l  - pfv0->l ) * scale + 0.5;
-		out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
-	}
-	else
-	{
-		scale = (float)(r_refdef.aliasvrectbottom - pfv1->v) /
-				(pfv0->v - pfv1->v);
-
-		out->u  = pfv1->u  + ( pfv0->u  - pfv1->u ) * scale + 0.5;
-		out->v  = pfv1->v  + ( pfv0->v  - pfv1->v ) * scale + 0.5;
-		out->s  = pfv1->s  + ( pfv0->s  - pfv1->s ) * scale + 0.5;
-		out->t  = pfv1->t  + ( pfv0->t  - pfv1->t ) * scale + 0.5;
-		out->l  = pfv1->l  + ( pfv0->l  - pfv1->l ) * scale + 0.5;
-		out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
-	}
-}
-
-
-int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count,
-	void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) )
-{
-	int			i,j,k;
-	int			flags, oldflags;
-	
-	j = count-1;
-	k = 0;
-	for (i=0 ; i<count ; j = i, i++)
-	{
-		oldflags = in[j].flags & flag;
-		flags = in[i].flags & flag;
-
-		if (flags && oldflags)
-			continue;
-		if (oldflags ^ flags)
-		{
-			clip (&in[j], &in[i], &out[k]);
-			out[k].flags = 0;
-			if (out[k].u < r_refdef.aliasvrect.x)
-				out[k].flags |= ALIAS_LEFT_CLIP;
-			if (out[k].v < r_refdef.aliasvrect.y)
-				out[k].flags |= ALIAS_TOP_CLIP;
-			if (out[k].u > r_refdef.aliasvrectright)
-				out[k].flags |= ALIAS_RIGHT_CLIP;
-			if (out[k].v > r_refdef.aliasvrectbottom)
-				out[k].flags |= ALIAS_BOTTOM_CLIP;	
-			k++;
-		}
-		if (!flags)
-		{
-			out[k] = in[i];
-			k++;
-		}
-	}
-	
-	return k;
-}
-
-
-/*
-================
-R_AliasClipTriangle
-================
-*/
-void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2)
-{
-	int				i, k, pingpong;
-	unsigned		clipflags;
-
-// copy vertexes and fix seam texture coordinates
-	fv[0][0] = *index0;
-	fv[0][1] = *index1;
-	fv[0][2] = *index2;
-
-// clip
-	clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags;
-
-	if (clipflags & ALIAS_Z_CLIP)
-	{
-		k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z);
-		if (k == 0)
-			return;
-
-		pingpong = 1;
-		clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags;
-	}
-	else
-	{
-		pingpong = 0;
-		k = 3;
-	}
-
-	if (clipflags & ALIAS_LEFT_CLIP)
-	{
-		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
-							ALIAS_LEFT_CLIP, k, R_Alias_clip_left);
-		if (k == 0)
-			return;
-
-		pingpong ^= 1;
-	}
-
-	if (clipflags & ALIAS_RIGHT_CLIP)
-	{
-		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
-							ALIAS_RIGHT_CLIP, k, R_Alias_clip_right);
-		if (k == 0)
-			return;
-
-		pingpong ^= 1;
-	}
-
-	if (clipflags & ALIAS_BOTTOM_CLIP)
-	{
-		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
-							ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom);
-		if (k == 0)
-			return;
-
-		pingpong ^= 1;
-	}
-
-	if (clipflags & ALIAS_TOP_CLIP)
-	{
-		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
-							ALIAS_TOP_CLIP, k, R_Alias_clip_top);
-		if (k == 0)
-			return;
-
-		pingpong ^= 1;
-	}
-
-	for (i=0 ; i<k ; i++)
-	{
-		if (fv[pingpong][i].u < r_refdef.aliasvrect.x)
-			fv[pingpong][i].u = r_refdef.aliasvrect.x;
-		else if (fv[pingpong][i].u > r_refdef.aliasvrectright)
-			fv[pingpong][i].u = r_refdef.aliasvrectright;
-
-		if (fv[pingpong][i].v < r_refdef.aliasvrect.y)
-			fv[pingpong][i].v = r_refdef.aliasvrect.y;
-		else if (fv[pingpong][i].v > r_refdef.aliasvrectbottom)
-			fv[pingpong][i].v = r_refdef.aliasvrectbottom;
-
-		fv[pingpong][i].flags = 0;
-	}
-
-// draw triangles
-	for (i=1 ; i<k-1 ; i++)
-	{
-		aliastriangleparms.a = &fv[pingpong][0];
-		aliastriangleparms.b = &fv[pingpong][i];
-		aliastriangleparms.c = &fv[pingpong][i+1];
-		R_DrawTriangle();
-	}
-}
-
--- a/ref/r_alias.c
+++ /dev/null
@@ -1,860 +1,0 @@
-// r_alias.c: routines for setting up to draw alias models
-
-/*
-** use a real variable to control lerping
-*/
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-#define LIGHT_MIN	5		// lowest light value we'll allow, to avoid the
-							//  need for inner-loop light clamping
-
-//PGM
-extern byte iractive;
-//PGM
-
-int				r_amodels_drawn;
-
-affinetridesc_t	r_affinetridesc;
-
-vec3_t			r_plightvec;
-vec3_t          r_lerped[1024];
-vec3_t          r_lerp_frontv, r_lerp_backv, r_lerp_move;
-
-int				r_ambientlight;
-int				r_aliasblendcolor;
-float			r_shadelight;
-
-
-daliasframe_t	*r_thisframe, *r_lastframe;
-dmdl_t			*s_pmdl;
-
-float	aliastransform[3][4];
-float   aliasworldtransform[3][4];
-float   aliasoldworldtransform[3][4];
-
-static float	s_ziscale;
-static vec3_t	s_alias_forward, s_alias_right, s_alias_up;
-
-
-float	r_avertexnormals[NUMVERTEXNORMALS][3] = {
-#include "../anorms.h"
-};
-
-
-void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp );
-void R_AliasSetUpTransform (void);
-void R_AliasTransformVector (vec3_t in, vec3_t out, float m[3][4] );
-void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
-
-void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv );
-
-void R_AliasLerpFrames( dmdl_t *paliashdr, float backlerp );
-
-/*
-================
-R_AliasCheckBBox
-================
-*/
-typedef struct {
-	int	index0;
-	int	index1;
-} aedge_t;
-
-static aedge_t	aedges[12] = {
-{0, 1}, {1, 2}, {2, 3}, {3, 0},
-{4, 5}, {5, 6}, {6, 7}, {7, 4},
-{0, 5}, {1, 4}, {2, 7}, {3, 6}
-};
-
-#define BBOX_TRIVIAL_ACCEPT 0
-#define BBOX_MUST_CLIP_XY   1
-#define BBOX_MUST_CLIP_Z    2
-#define BBOX_TRIVIAL_REJECT 8
-
-/*
-** R_AliasCheckFrameBBox
-**
-** Checks a specific alias frame bounding box
-*/
-unsigned long R_AliasCheckFrameBBox( daliasframe_t *frame, float worldxf[3][4] )
-{
-	unsigned long aggregate_and_clipcode = ~0U, 
-		          aggregate_or_clipcode = 0;
-	int           i;
-	vec3_t        mins, maxs;
-	vec3_t        transformed_min, transformed_max;
-	qboolean      zclipped = false, zfullyclipped = true;
-	//float         minz = 9999.0F;
-
-	/*
-	** get the exact frame bounding box
-	*/
-	for (i=0 ; i<3 ; i++)
-	{
-		mins[i] = frame->translate[i];
-		maxs[i] = mins[i] + frame->scale[i]*255;
-	}
-
-	/*
-	** transform the min and max values into view space
-	*/
-	R_AliasTransformVector( mins, transformed_min, aliastransform );
-	R_AliasTransformVector( maxs, transformed_max, aliastransform );
-
-	if ( transformed_min[2] >= ALIAS_Z_CLIP_PLANE )
-		zfullyclipped = false;
-	if ( transformed_max[2] >= ALIAS_Z_CLIP_PLANE )
-		zfullyclipped = false;
-
-	if ( zfullyclipped )
-	{
-		return BBOX_TRIVIAL_REJECT;
-	}
-	if ( zclipped )
-	{
-		return ( BBOX_MUST_CLIP_XY | BBOX_MUST_CLIP_Z );
-	}
-
-	/*
-	** build a transformed bounding box from the given min and max
-	*/
-	for ( i = 0; i < 8; i++ )
-	{
-		int      j;
-		vec3_t   tmp, transformed;
-		unsigned long clipcode = 0;
-
-		if ( i & 1 )
-			tmp[0] = mins[0];
-		else
-			tmp[0] = maxs[0];
-
-		if ( i & 2 )
-			tmp[1] = mins[1];
-		else
-			tmp[1] = maxs[1];
-
-		if ( i & 4 )
-			tmp[2] = mins[2];
-		else
-			tmp[2] = maxs[2];
-
-		R_AliasTransformVector( tmp, transformed, worldxf );
-
-		for ( j = 0; j < 4; j++ )
-		{
-			float dp = DotProduct( transformed, view_clipplanes[j].normal );
-
-			if ( ( dp - view_clipplanes[j].dist ) < 0.0F )
-				clipcode |= 1 << j;
-		}
-
-		aggregate_and_clipcode &= clipcode;
-		aggregate_or_clipcode  |= clipcode;
-	}
-
-	if ( aggregate_and_clipcode )
-	{
-		return BBOX_TRIVIAL_REJECT;
-	}
-	if ( !aggregate_or_clipcode )
-	{
-		return BBOX_TRIVIAL_ACCEPT;
-	}
-
-	return BBOX_MUST_CLIP_XY;
-}
-
-qboolean R_AliasCheckBBox (void)
-{
-	unsigned long ccodes[2] = { 0, 0 };
-
-	ccodes[0] = R_AliasCheckFrameBBox( r_thisframe, aliasworldtransform );
-
-	/*
-	** non-lerping model
-	*/
-	if ( currententity->backlerp == 0 )
-	{
-		if ( ccodes[0] == BBOX_TRIVIAL_ACCEPT )
-			return BBOX_TRIVIAL_ACCEPT;
-		else if ( ccodes[0] & BBOX_TRIVIAL_REJECT )
-			return BBOX_TRIVIAL_REJECT;
-		else
-			return ( ccodes[0] & ~BBOX_TRIVIAL_REJECT );
-	}
-
-	ccodes[1] = R_AliasCheckFrameBBox( r_lastframe, aliasoldworldtransform );
-
-	if ( ( ccodes[0] | ccodes[1] ) == BBOX_TRIVIAL_ACCEPT )
-		return BBOX_TRIVIAL_ACCEPT;
-	else if ( ( ccodes[0] & ccodes[1] ) & BBOX_TRIVIAL_REJECT )
-		return BBOX_TRIVIAL_REJECT;
-	else
-		return ( ccodes[0] | ccodes[1] ) & ~BBOX_TRIVIAL_REJECT;
-}
-
-
-/*
-================
-R_AliasTransformVector
-================
-*/
-void R_AliasTransformVector(vec3_t in, vec3_t out, float xf[3][4] )
-{
-	out[0] = DotProduct(in, xf[0]) + xf[0][3];
-	out[1] = DotProduct(in, xf[1]) + xf[1][3];
-	out[2] = DotProduct(in, xf[2]) + xf[2][3];
-}
-
-
-/*
-================
-R_AliasPreparePoints
-
-General clipped case
-================
-*/
-typedef struct
-{
-	int          num_points;
-	dtrivertx_t *last_verts;   // verts from the last frame
-	dtrivertx_t *this_verts;   // verts from this frame
-	finalvert_t *dest_verts;   // destination for transformed verts
-} aliasbatchedtransformdata_t;
-
-aliasbatchedtransformdata_t aliasbatchedtransformdata;
-
-void R_AliasPreparePoints (void)
-{
-	int			i;
-	dstvert_t	*pstverts;
-	dtriangle_t	*ptri;
-	finalvert_t	*pfv[3];
-	finalvert_t	finalverts[MAXALIASVERTS +
-						((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 3];
-	finalvert_t	*pfinalverts;
-
-//PGM
-	iractive = (r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE);
-//	iractive = 0;
-//	if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
-//		iractive = 1;
-//PGM
-
-	// put work vertexes on stack, cache aligned
-	pfinalverts = (finalvert_t *)
-			(((uintptr)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
-
-	aliasbatchedtransformdata.num_points = s_pmdl->num_xyz;
-	aliasbatchedtransformdata.last_verts = r_lastframe->verts;
-	aliasbatchedtransformdata.this_verts = r_thisframe->verts;
-	aliasbatchedtransformdata.dest_verts = pfinalverts;
-
-	R_AliasTransformFinalVerts( aliasbatchedtransformdata.num_points,
-		                        aliasbatchedtransformdata.dest_verts,
-								aliasbatchedtransformdata.last_verts,
-								aliasbatchedtransformdata.this_verts );
-
-// clip and draw all triangles
-//
-	pstverts = (dstvert_t *)((byte *)s_pmdl + s_pmdl->ofs_st);
-	ptri = (dtriangle_t *)((byte *)s_pmdl + s_pmdl->ofs_tris);
-
-	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
-	{
-		for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
-		{
-			pfv[0] = &pfinalverts[ptri->index_xyz[0]];
-			pfv[1] = &pfinalverts[ptri->index_xyz[1]];
-			pfv[2] = &pfinalverts[ptri->index_xyz[2]];
-
-			if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
-				continue;		// completely clipped
-
-			// insert s/t coordinates
-			pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
-			pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
-
-			pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
-			pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
-
-			pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
-			pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
-
-			if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
-			{	// totally unclipped
-				aliastriangleparms.a = pfv[2];
-				aliastriangleparms.b = pfv[1];
-				aliastriangleparms.c = pfv[0];
-
-				R_DrawTriangle();
-			}
-			else
-			{
-				R_AliasClipTriangle (pfv[2], pfv[1], pfv[0]);
-			}
-		}
-	}
-	else
-	{
-		for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
-		{
-			pfv[0] = &pfinalverts[ptri->index_xyz[0]];
-			pfv[1] = &pfinalverts[ptri->index_xyz[1]];
-			pfv[2] = &pfinalverts[ptri->index_xyz[2]];
-
-			if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
-				continue;		// completely clipped
-
-			// insert s/t coordinates
-			pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
-			pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
-
-			pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
-			pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
-
-			pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
-			pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
-
-			if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
-			{	// totally unclipped
-				aliastriangleparms.a = pfv[0];
-				aliastriangleparms.b = pfv[1];
-				aliastriangleparms.c = pfv[2];
-
-				R_DrawTriangle();
-			}
-			else		
-			{	// partially clipped
-				R_AliasClipTriangle (pfv[0], pfv[1], pfv[2]);
-			}
-		}
-	}
-}
-
-
-/*
-================
-R_AliasSetUpTransform
-================
-*/
-void R_AliasSetUpTransform (void)
-{
-	int				i;
-	static float	viewmatrix[3][4];
-	vec3_t			angles;
-
-// TODO: should really be stored with the entity instead of being reconstructed
-// TODO: should use a look-up table
-// TODO: could cache lazily, stored in the entity
-// 
-	angles[ROLL] = currententity->angles[ROLL];
-	angles[PITCH] = currententity->angles[PITCH];
-	angles[YAW] = currententity->angles[YAW];
-	AngleVectors( angles, s_alias_forward, s_alias_right, s_alias_up );
-
-// TODO: can do this with simple matrix rearrangement
-
-	memset( aliasworldtransform, 0, sizeof( aliasworldtransform ) );
-	memset( aliasoldworldtransform, 0, sizeof( aliasworldtransform ) );
-
-	for (i=0 ; i<3 ; i++)
-	{
-		aliasoldworldtransform[i][0] = aliasworldtransform[i][0] =  s_alias_forward[i];
-		aliasoldworldtransform[i][0] = aliasworldtransform[i][1] = -s_alias_right[i];
-		aliasoldworldtransform[i][0] = aliasworldtransform[i][2] =  s_alias_up[i];
-	}
-
-	aliasworldtransform[0][3] = currententity->origin[0]-r_origin[0];
-	aliasworldtransform[1][3] = currententity->origin[1]-r_origin[1];
-	aliasworldtransform[2][3] = currententity->origin[2]-r_origin[2];
-
-	aliasoldworldtransform[0][3] = currententity->oldorigin[0]-r_origin[0];
-	aliasoldworldtransform[1][3] = currententity->oldorigin[1]-r_origin[1];
-	aliasoldworldtransform[2][3] = currententity->oldorigin[2]-r_origin[2];
-
-// FIXME: can do more efficiently than full concatenation
-//	memcpy( rotationmatrix, t2matrix, sizeof( rotationmatrix ) );
-
-//	R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
-
-// TODO: should be global, set when vright, etc., set
-	VectorCopy (vright, viewmatrix[0]);
-	VectorCopy (vup, viewmatrix[1]);
-	VectorInverse (viewmatrix[1]);
-	VectorCopy (vpn, viewmatrix[2]);
-
-	viewmatrix[0][3] = 0;
-	viewmatrix[1][3] = 0;
-	viewmatrix[2][3] = 0;
-
-//	memcpy( aliasworldtransform, rotationmatrix, sizeof( aliastransform ) );
-
-	R_ConcatTransforms (viewmatrix, aliasworldtransform, aliastransform);
-
-	aliasworldtransform[0][3] = currententity->origin[0];
-	aliasworldtransform[1][3] = currententity->origin[1];
-	aliasworldtransform[2][3] = currententity->origin[2];
-
-	aliasoldworldtransform[0][3] = currententity->oldorigin[0];
-	aliasoldworldtransform[1][3] = currententity->oldorigin[1];
-	aliasoldworldtransform[2][3] = currententity->oldorigin[2];
-}
-
-
-/*
-================
-R_AliasTransformFinalVerts
-================
-*/
-void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv )
-{
-	int i;
-
-	for ( i = 0; i < numpoints; i++, fv++, oldv++, newv++ )
-	{
-		int		temp;
-		float	lightcos, *plightnormal;
-		vec3_t  lerped_vert;
-
-		lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0];
-		lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1];
-		lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2];
-
-		plightnormal = r_avertexnormals[newv->lightnormalindex];
-
-		// PMM - added double damage shell
-		if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
-		{
-			lerped_vert[0] += plightnormal[0] * POWERSUIT_SCALE;
-			lerped_vert[1] += plightnormal[1] * POWERSUIT_SCALE;
-			lerped_vert[2] += plightnormal[2] * POWERSUIT_SCALE;
-		}
-
-		fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3];
-		fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3];
-		fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3];
-
-		fv->flags = 0;
-
-		// lighting
-		lightcos = DotProduct (plightnormal, r_plightvec);
-		temp = r_ambientlight;
-
-		if (lightcos < 0)
-		{
-			temp += (int)(r_shadelight * lightcos);
-
-			// clamp; because we limited the minimum ambient and shading light, we
-			// don't have to clamp low light, just bright
-			if (temp < 0)
-				temp = 0;
-		}
-
-		fv->l = temp;
-
-		if ( fv->xyz[2] < ALIAS_Z_CLIP_PLANE )
-		{
-			fv->flags |= ALIAS_Z_CLIP;
-		}
-		else
-		{
-			R_AliasProjectAndClipTestFinalVert( fv );
-		}
-	}
-}
-
-/*
-================
-R_AliasProjectAndClipTestFinalVert
-================
-*/
-void R_AliasProjectAndClipTestFinalVert( finalvert_t *fv )
-{
-	float	zi;
-	float	x, y, z;
-
-	// project points
-	x = fv->xyz[0];
-	y = fv->xyz[1];
-	z = fv->xyz[2];
-	zi = 1.0 / z;
-
-	fv->zi = zi * s_ziscale;
-
-	fv->u = (x * aliasxscale * zi) + aliasxcenter;
-	fv->v = (y * aliasyscale * zi) + aliasycenter;
-
-	if (fv->u < r_refdef.aliasvrect.x)
-		fv->flags |= ALIAS_LEFT_CLIP;
-	if (fv->v < r_refdef.aliasvrect.y)
-		fv->flags |= ALIAS_TOP_CLIP;
-	if (fv->u > r_refdef.aliasvrectright)
-		fv->flags |= ALIAS_RIGHT_CLIP;
-	if (fv->v > r_refdef.aliasvrectbottom)
-		fv->flags |= ALIAS_BOTTOM_CLIP;	
-}
-
-/*
-===============
-R_AliasSetupSkin
-===============
-*/
-static qboolean R_AliasSetupSkin (void)
-{
-	int				skinnum;
-	image_t			*pskindesc;
-
-	if (currententity->skin)
-		pskindesc = currententity->skin;
-	else
-	{
-		skinnum = currententity->skinnum;
-		if ((skinnum >= s_pmdl->num_skins) || (skinnum < 0))
-		{
-			ri.Con_Printf (PRINT_ALL, "R_AliasSetupSkin %s: no such skin # %d\n", 
-				currentmodel->name, skinnum);
-			skinnum = 0;
-		}
-
-		pskindesc = currentmodel->skins[skinnum];
-	}
-
-	if ( !pskindesc )
-		return false;
-
-	r_affinetridesc.pskin = pskindesc->pixels[0];
-	r_affinetridesc.skinwidth = pskindesc->width;
-	r_affinetridesc.skinheight = pskindesc->height;
-
-	R_PolysetUpdateTables ();		// FIXME: precalc edge lookups
-
-	return true;
-}
-
-
-/*
-================
-R_AliasSetupLighting
-
-  FIXME: put lighting into tables
-================
-*/
-void R_AliasSetupLighting (void)
-{
-	alight_t		lighting;
-	float			lightvec[3] = {-1, 0, 0};
-	vec3_t			light;
-	int				i, j;
-
-	// all components of light should be identical in software
-	if ( currententity->flags & RF_FULLBRIGHT )
-	{
-		for (i=0 ; i<3 ; i++)
-			light[i] = 1.0;
-	}
-	else
-	{
-		R_LightPoint (currententity->origin, light);
-	}
-
-	// save off light value for server to look at (BIG HACK!)
-	if ( currententity->flags & RF_WEAPONMODEL )
-		r_lightlevel->value = 150.0 * light[0];
-
-
-	if ( currententity->flags & RF_MINLIGHT )
-	{
-		for (i=0 ; i<3 ; i++)
-			if (light[i] < 0.1)
-				light[i] = 0.1;
-	}
-
-	if ( currententity->flags & RF_GLOW )
-	{	// bonus items will pulse with time
-		float	scale;
-		float	min;
-
-		scale = 0.1 * sin(r_newrefdef.time*7);
-		for (i=0 ; i<3 ; i++)
-		{
-			min = light[i] * 0.8;
-			light[i] += scale;
-			if (light[i] < min)
-				light[i] = min;
-		}
-	}
-
-	j = (light[0] + light[1] + light[2])*0.3333*255;
-
-	lighting.ambientlight = j;
-	lighting.shadelight = j;
-
-	lighting.plightvec = lightvec;
-
-// clamp lighting so it doesn't overbright as much
-	if (lighting.ambientlight > 128)
-		lighting.ambientlight = 128;
-	if (lighting.ambientlight + lighting.shadelight > 192)
-		lighting.shadelight = 192 - lighting.ambientlight;
-
-// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have
-// to clamp off the bottom
-	r_ambientlight = lighting.ambientlight;
-
-	if (r_ambientlight < LIGHT_MIN)
-		r_ambientlight = LIGHT_MIN;
-
-	r_ambientlight = (255 - r_ambientlight) << VID_CBITS;
-
-	if (r_ambientlight < LIGHT_MIN)
-		r_ambientlight = LIGHT_MIN;
-
-	r_shadelight = lighting.shadelight;
-
-	if (r_shadelight < 0)
-		r_shadelight = 0;
-
-	r_shadelight *= VID_GRADES;
-
-// rotate the lighting vector into the model's frame of reference
-	r_plightvec[0] =  DotProduct( lighting.plightvec, s_alias_forward );
-	r_plightvec[1] = -DotProduct( lighting.plightvec, s_alias_right );
-	r_plightvec[2] =  DotProduct( lighting.plightvec, s_alias_up );
-}
-
-
-/*
-=================
-R_AliasSetupFrames
-
-=================
-*/
-void R_AliasSetupFrames( dmdl_t *pmdl )
-{
-	int thisframe = currententity->frame;
-	int lastframe = currententity->oldframe;
-
-	if ( ( thisframe >= pmdl->num_frames ) || ( thisframe < 0 ) )
-	{
-		ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such thisframe %d\n", 
-			currentmodel->name, thisframe);
-		thisframe = 0;
-	}
-	if ( ( lastframe >= pmdl->num_frames ) || ( lastframe < 0 ) )
-	{
-		ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such lastframe %d\n", 
-			currentmodel->name, lastframe);
-		lastframe = 0;
-	}
-
-	r_thisframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames 
-		+ thisframe * pmdl->framesize);
-
-	r_lastframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames 
-		+ lastframe * pmdl->framesize);
-}
-
-/*
-** R_AliasSetUpLerpData
-**
-** Precomputes lerp coefficients used for the whole frame.
-*/
-void R_AliasSetUpLerpData( dmdl_t */*pmdl*/, float backlerp )
-{
-	float	frontlerp;
-	vec3_t	translation, vectors[3];
-	int		i;
-
-	frontlerp = 1.0F - backlerp;
-
-	/*
-	** convert entity's angles into discrete vectors for R, U, and F
-	*/
-	AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]);
-
-	/*
-	** translation is the vector from last position to this position
-	*/
-	VectorSubtract (currententity->oldorigin, currententity->origin, translation);
-
-	/*
-	** move should be the delta back to the previous frame * backlerp
-	*/
-	r_lerp_move[0] =  DotProduct(translation, vectors[0]);	// forward
-	r_lerp_move[1] = -DotProduct(translation, vectors[1]);	// left
-	r_lerp_move[2] =  DotProduct(translation, vectors[2]);	// up
-
-	VectorAdd( r_lerp_move, r_lastframe->translate, r_lerp_move );
-
-	for (i=0 ; i<3 ; i++)
-	{
-		r_lerp_move[i] = backlerp*r_lerp_move[i] + frontlerp * r_thisframe->translate[i];
-	}
-
-	for (i=0 ; i<3 ; i++)
-	{
-		r_lerp_frontv[i] = frontlerp * r_thisframe->scale[i];
-		r_lerp_backv[i]  = backlerp  * r_lastframe->scale[i];
-	}
-}
-
-/*
-================
-R_AliasDrawModel
-================
-*/
-void R_AliasDrawModel (void)
-{
-	extern void	(*d_pdrawspans)(void *);
-	extern void R_PolysetDrawSpans8_Opaque( void * );
-	extern void R_PolysetDrawSpans8_33( void * );
-	extern void R_PolysetDrawSpans8_66( void * );
-	extern void R_PolysetDrawSpansConstant8_33( void * );
-	extern void R_PolysetDrawSpansConstant8_66( void * );
-
-	s_pmdl = (dmdl_t *)currentmodel->extradata;
-
-	if ( r_lerpmodels->value == 0 )
-		currententity->backlerp = 0;
-
-	if ( currententity->flags & RF_WEAPONMODEL )
-	{
-		if ( r_lefthand->value == 1.0F )
-			aliasxscale = -aliasxscale;
-		else if ( r_lefthand->value == 2.0F )
-			return;
-	}
-
-	/*
-	** we have to set our frame pointers and transformations before
-	** doing any real work
-	*/
-	R_AliasSetupFrames( s_pmdl );
-	R_AliasSetUpTransform();
-
-	// see if the bounding box lets us trivially reject, also sets
-	// trivial accept status
-	if ( R_AliasCheckBBox() == BBOX_TRIVIAL_REJECT )
-	{
-		if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
-		{
-			aliasxscale = -aliasxscale;
-		}
-		return;
-	}
-
-	// set up the skin and verify it exists
-	if ( !R_AliasSetupSkin () )
-	{
-		ri.Con_Printf( PRINT_ALL, "R_AliasDrawModel %s: NULL skin found\n",
-			currentmodel->name);
-		return;
-	}
-
-	r_amodels_drawn++;
-	R_AliasSetupLighting ();
-
-	/*
-	** select the proper span routine based on translucency
-	*/
-	// PMM - added double damage shell
-	// PMM - reordered to handle blending
-	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
-	{
-		int		color;
-
-		// PMM - added double
-		color = currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM);
-		// PMM - reordered, old code first
-/*
-		if ( color == RF_SHELL_RED )
-			r_aliasblendcolor = SHELL_RED_COLOR;
-		else if ( color == RF_SHELL_GREEN )
-			r_aliasblendcolor = SHELL_GREEN_COLOR;
-		else if ( color == RF_SHELL_BLUE )
-			r_aliasblendcolor = SHELL_BLUE_COLOR;
-		else if ( color == (RF_SHELL_RED | RF_SHELL_GREEN) )
-			r_aliasblendcolor = SHELL_RG_COLOR;
-		else if ( color == (RF_SHELL_RED | RF_SHELL_BLUE) )
-			r_aliasblendcolor = SHELL_RB_COLOR;
-		else if ( color == (RF_SHELL_BLUE | RF_SHELL_GREEN) )
-			r_aliasblendcolor = SHELL_BG_COLOR;
-		// PMM - added this .. it's yellowish
-		else if ( color == (RF_SHELL_DOUBLE) )
-			r_aliasblendcolor = SHELL_DOUBLE_COLOR;
-		else if ( color == (RF_SHELL_HALF_DAM) )
-			r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
-		// pmm
-		else
-			r_aliasblendcolor = SHELL_WHITE_COLOR;
-*/
-		if ( color & RF_SHELL_RED )
-		{
-			if ( ( color & RF_SHELL_BLUE) && ( color & RF_SHELL_GREEN) )
-				r_aliasblendcolor = SHELL_WHITE_COLOR;
-			else if ( color & (RF_SHELL_BLUE | RF_SHELL_DOUBLE))
-				r_aliasblendcolor = SHELL_RB_COLOR;
-			else
-				r_aliasblendcolor = SHELL_RED_COLOR;
-		}
-		else if ( color & RF_SHELL_BLUE)
-		{
-			if ( color & RF_SHELL_DOUBLE )
-				r_aliasblendcolor = SHELL_CYAN_COLOR;
-			else
-				r_aliasblendcolor = SHELL_BLUE_COLOR;
-		}
-		else if ( color & (RF_SHELL_DOUBLE) )
-			r_aliasblendcolor = SHELL_DOUBLE_COLOR;
-		else if ( color & (RF_SHELL_HALF_DAM) )
-			r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
-		else if ( color & RF_SHELL_GREEN )
-			r_aliasblendcolor = SHELL_GREEN_COLOR;
-		else
-			r_aliasblendcolor = SHELL_WHITE_COLOR;
-
-
-		if ( currententity->alpha > 0.33 )
-			d_pdrawspans = R_PolysetDrawSpansConstant8_66;
-		else
-			d_pdrawspans = R_PolysetDrawSpansConstant8_33;
-	}
-	else if ( currententity->flags & RF_TRANSLUCENT )
-	{
-		if ( currententity->alpha > 0.66 )
-			d_pdrawspans = R_PolysetDrawSpans8_Opaque;
-		else if ( currententity->alpha > 0.33 )
-			d_pdrawspans = R_PolysetDrawSpans8_66;
-		else
-			d_pdrawspans = R_PolysetDrawSpans8_33;
-	}
-	else
-	{
-		d_pdrawspans = R_PolysetDrawSpans8_Opaque;
-	}
-
-	/*
-	** compute this_frame and old_frame addresses
-	*/
-	R_AliasSetUpLerpData( s_pmdl, currententity->backlerp );
-
-	if (currententity->flags & RF_DEPTHHACK)
-		s_ziscale = (float)0x8000 * (float)0x10000 * 3.0;
-	else
-		s_ziscale = (float)0x8000 * (float)0x10000;
-
-	R_AliasPreparePoints ();
-
-	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
-	{
-		aliasxscale = -aliasxscale;
-	}
-}
-
-
-
--- a/ref/r_bsp.c
+++ /dev/null
@@ -1,619 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-//
-// current entity info
-//
-qboolean		insubmodel;
-entity_t		*currententity;
-vec3_t			modelorg;		// modelorg is the viewpoint reletive to
-								// the currently rendering entity
-vec3_t			r_entorigin;	// the currently rendering entity in world
-								// coordinates
-
-float			entity_rotation[3][3];
-
-int				r_currentbkey;
-
-typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t;
-
-#define MAX_BMODEL_VERTS	500			// 6K
-#define MAX_BMODEL_EDGES	1000		// 12K
-
-static mvertex_t	*pbverts;
-static bedge_t		*pbedges;
-static int			numbverts, numbedges;
-
-static mvertex_t	*pfrontenter, *pfrontexit;
-
-static qboolean		makeclippededge;
-
-
-//===========================================================================
-
-/*
-================
-R_EntityRotate
-================
-*/
-void R_EntityRotate (vec3_t vec)
-{
-	vec3_t	tvec;
-
-	VectorCopy (vec, tvec);
-	vec[0] = DotProduct (entity_rotation[0], tvec);
-	vec[1] = DotProduct (entity_rotation[1], tvec);
-	vec[2] = DotProduct (entity_rotation[2], tvec);
-}
-
-
-/*
-================
-R_RotateBmodel
-================
-*/
-void R_RotateBmodel (void)
-{
-	float	angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
-
-// TODO: should use a look-up table
-// TODO: should really be stored with the entity instead of being reconstructed
-// TODO: could cache lazily, stored in the entity
-// TODO: share work with R_SetUpAliasTransform
-
-// yaw
-	angle = currententity->angles[YAW];		
-	angle = angle * M_PI*2 / 360;
-	s = sin(angle);
-	c = cos(angle);
-
-	temp1[0][0] = c;
-	temp1[0][1] = s;
-	temp1[0][2] = 0;
-	temp1[1][0] = -s;
-	temp1[1][1] = c;
-	temp1[1][2] = 0;
-	temp1[2][0] = 0;
-	temp1[2][1] = 0;
-	temp1[2][2] = 1;
-
-
-// pitch
-	angle = currententity->angles[PITCH];		
-	angle = angle * M_PI*2 / 360;
-	s = sin(angle);
-	c = cos(angle);
-
-	temp2[0][0] = c;
-	temp2[0][1] = 0;
-	temp2[0][2] = -s;
-	temp2[1][0] = 0;
-	temp2[1][1] = 1;
-	temp2[1][2] = 0;
-	temp2[2][0] = s;
-	temp2[2][1] = 0;
-	temp2[2][2] = c;
-
-	R_ConcatRotations (temp2, temp1, temp3);
-
-// roll
-	angle = currententity->angles[ROLL];		
-	angle = angle * M_PI*2 / 360;
-	s = sin(angle);
-	c = cos(angle);
-
-	temp1[0][0] = 1;
-	temp1[0][1] = 0;
-	temp1[0][2] = 0;
-	temp1[1][0] = 0;
-	temp1[1][1] = c;
-	temp1[1][2] = s;
-	temp1[2][0] = 0;
-	temp1[2][1] = -s;
-	temp1[2][2] = c;
-
-	R_ConcatRotations (temp1, temp3, entity_rotation);
-
-//
-// rotate modelorg and the transformation matrix
-//
-	R_EntityRotate (modelorg);
-	R_EntityRotate (vpn);
-	R_EntityRotate (vright);
-	R_EntityRotate (vup);
-
-	R_TransformFrustum ();
-}
-
-
-/*
-================
-R_RecursiveClipBPoly
-
-Clip a bmodel poly down the world bsp tree
-================
-*/
-void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
-{
-	bedge_t		*psideedges[2], *pnextedge, *ptedge;
-	int			i, side, lastside;
-	float		dist, frac, lastdist;
-	mplane_t	*splitplane, tplane;
-	mvertex_t	*pvert, *plastvert, *ptvert;
-	mnode_t		*pn;
-	int			area;
-
-	psideedges[0] = psideedges[1] = NULL;
-
-	makeclippededge = false;
-
-// transform the BSP plane into model space
-// FIXME: cache these?
-	splitplane = pnode->plane;
-	tplane.dist = splitplane->dist -
-			DotProduct(r_entorigin, splitplane->normal);
-	tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal);
-	tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal);
-	tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal);
-
-// clip edges to BSP plane
-	for ( ; pedges ; pedges = pnextedge)
-	{
-		pnextedge = pedges->pnext;
-
-	// set the status for the last point as the previous point
-	// FIXME: cache this stuff somehow?
-		plastvert = pedges->v[0];
-		lastdist = DotProduct (plastvert->position, tplane.normal) -
-				   tplane.dist;
-
-		if (lastdist > 0)
-			lastside = 0;
-		else
-			lastside = 1;
-
-		pvert = pedges->v[1];
-
-		dist = DotProduct (pvert->position, tplane.normal) - tplane.dist;
-
-		if (dist > 0)
-			side = 0;
-		else
-			side = 1;
-
-		if (side != lastside)
-		{
-		// clipped
-			if (numbverts >= MAX_BMODEL_VERTS)
-				return;
-
-		// generate the clipped vertex
-			frac = lastdist / (lastdist - dist);
-			ptvert = &pbverts[numbverts++];
-			ptvert->position[0] = plastvert->position[0] +
-					frac * (pvert->position[0] -
-					plastvert->position[0]);
-			ptvert->position[1] = plastvert->position[1] +
-					frac * (pvert->position[1] -
-					plastvert->position[1]);
-			ptvert->position[2] = plastvert->position[2] +
-					frac * (pvert->position[2] -
-					plastvert->position[2]);
-
-		// split into two edges, one on each side, and remember entering
-		// and exiting points
-		// FIXME: share the clip edge by having a winding direction flag?
-			if (numbedges >= (MAX_BMODEL_EDGES - 1))
-			{
-				ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n");
-				return;
-			}
-
-			ptedge = &pbedges[numbedges];
-			ptedge->pnext = psideedges[lastside];
-			psideedges[lastside] = ptedge;
-			ptedge->v[0] = plastvert;
-			ptedge->v[1] = ptvert;
-
-			ptedge = &pbedges[numbedges + 1];
-			ptedge->pnext = psideedges[side];
-			psideedges[side] = ptedge;
-			ptedge->v[0] = ptvert;
-			ptedge->v[1] = pvert;
-
-			numbedges += 2;
-
-			if (side == 0)
-			{
-			// entering for front, exiting for back
-				pfrontenter = ptvert;
-				makeclippededge = true;
-			}
-			else
-			{
-				pfrontexit = ptvert;
-				makeclippededge = true;
-			}
-		}
-		else
-		{
-		// add the edge to the appropriate side
-			pedges->pnext = psideedges[side];
-			psideedges[side] = pedges;
-		}
-	}
-
-// if anything was clipped, reconstitute and add the edges along the clip
-// plane to both sides (but in opposite directions)
-	if (makeclippededge)
-	{
-		if (numbedges >= (MAX_BMODEL_EDGES - 2))
-		{
-			ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n");
-			return;
-		}
-
-		ptedge = &pbedges[numbedges];
-		ptedge->pnext = psideedges[0];
-		psideedges[0] = ptedge;
-		ptedge->v[0] = pfrontexit;
-		ptedge->v[1] = pfrontenter;
-
-		ptedge = &pbedges[numbedges + 1];
-		ptedge->pnext = psideedges[1];
-		psideedges[1] = ptedge;
-		ptedge->v[0] = pfrontenter;
-		ptedge->v[1] = pfrontexit;
-
-		numbedges += 2;
-	}
-
-// draw or recurse further
-	for (i=0 ; i<2 ; i++)
-	{
-		if (psideedges[i])
-		{
-		// draw if we've reached a non-solid leaf, done if all that's left is a
-		// solid leaf, and continue down the tree if it's not a leaf
-			pn = pnode->children[i];
-
-		// we're done with this branch if the node or leaf isn't in the PVS
-			if (pn->visframe == r_visframecount)
-			{
-				if (pn->contents != CONTENTS_NODE)
-				{
-					if (pn->contents != CONTENTS_SOLID)
-					{
-						if (r_newrefdef.areabits)
-						{
-							area = ((mleaf_t *)pn)->area;
-							if (! (r_newrefdef.areabits[area>>3] & (1<<(area&7)) ) )
-								continue;		// not visible
-						}
-
-						r_currentbkey = ((mleaf_t *)pn)->key;
-						R_RenderBmodelFace (psideedges[i], psurf);
-					}
-				}
-				else
-				{
-					R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
-									  psurf);
-				}
-			}
-		}
-	}
-}
-
-
-/*
-================
-R_DrawSolidClippedSubmodelPolygons
-
-Bmodel crosses multiple leafs
-================
-*/
-void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode)
-{
-	int			i, j, lindex;
-	vec_t		dot;
-	msurface_t	*psurf;
-	int			numsurfaces;
-	mplane_t	*pplane;
-	mvertex_t	bverts[MAX_BMODEL_VERTS];
-	bedge_t		bedges[MAX_BMODEL_EDGES], *pbedge;
-	medge_t		*pedge, *pedges;
-
-// FIXME: use bounding-box-based frustum clipping info?
-
-	psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
-	numsurfaces = pmodel->nummodelsurfaces;
-	pedges = pmodel->edges;
-
-	for (i=0 ; i<numsurfaces ; i++, psurf++)
-	{
-	// find which side of the node we are on
-		pplane = psurf->plane;
-
-		dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
-
-	// draw the polygon
-		if (( !(psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
-			((psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
-			continue;
-
-	// FIXME: use bounding-box-based frustum clipping info?
-
-	// copy the edges to bedges, flipping if necessary so always
-	// clockwise winding
-	// FIXME: if edges and vertices get caches, these assignments must move
-	// outside the loop, and overflow checking must be done here
-		pbverts = bverts;
-		pbedges = bedges;
-		numbverts = numbedges = 0;
-		pbedge = &bedges[numbedges];
-		numbedges += psurf->numedges;
-
-		for (j=0 ; j<psurf->numedges ; j++)
-		{
-		   lindex = pmodel->surfedges[psurf->firstedge+j];
-
-			if (lindex > 0)
-			{
-				pedge = &pedges[lindex];
-				pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
-				pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
-			}
-			else
-			{
-				lindex = -lindex;
-				pedge = &pedges[lindex];
-				pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
-				pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
-			}
-
-			pbedge[j].pnext = &pbedge[j+1];
-		}
-
-		pbedge[j-1].pnext = NULL;	// mark end of edges
-
-		if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) )
-			R_RecursiveClipBPoly (pbedge, topnode, psurf);
-		else
-			R_RenderBmodelFace( pbedge, psurf );
-	}
-}
-
-
-/*
-================
-R_DrawSubmodelPolygons
-
-All in one leaf
-================
-*/
-void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode)
-{
-	int			i;
-	vec_t		dot;
-	msurface_t	*psurf;
-	int			numsurfaces;
-	mplane_t	*pplane;
-
-// FIXME: use bounding-box-based frustum clipping info?
-
-	psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
-	numsurfaces = pmodel->nummodelsurfaces;
-
-	for (i=0 ; i<numsurfaces ; i++, psurf++)
-	{
-	// find which side of the node we are on
-		pplane = psurf->plane;
-
-		dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
-
-	// draw the polygon
-		if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
-			(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
-		{
-			r_currentkey = ((mleaf_t *)topnode)->key;
-
-		// FIXME: use bounding-box-based frustum clipping info?
-			R_RenderFace (psurf, clipflags);
-		}
-	}
-}
-
-
-int c_drawnode;
-
-/*
-================
-R_RecursiveWorldNode
-================
-*/
-void R_RecursiveWorldNode (mnode_t *node, int clipflags)
-{
-	int			i, c, side, *pindex;
-	vec3_t		acceptpt, rejectpt;
-	mplane_t	*plane;
-	msurface_t	*surf, **mark;
-	float		d, dot;
-	mleaf_t		*pleaf;
-
-	if (node->contents == CONTENTS_SOLID)
-		return;		// solid
-
-	if (node->visframe != r_visframecount)
-		return;
-
-// cull the clipping planes if not trivial accept
-// FIXME: the compiler is doing a lousy job of optimizing here; it could be
-//  twice as fast in ASM
-	if (clipflags)
-	{
-		for (i=0 ; i<4 ; i++)
-		{
-			if (! (clipflags & (1<<i)) )
-				continue;	// don't need to clip against it
-
-		// generate accept and reject points
-		// FIXME: do with fast look-ups or integer tests based on the sign bit
-		// of the floating point values
-
-			pindex = pfrustum_indexes[i];
-
-			rejectpt[0] = (float)node->minmaxs[pindex[0]];
-			rejectpt[1] = (float)node->minmaxs[pindex[1]];
-			rejectpt[2] = (float)node->minmaxs[pindex[2]];
-			
-			d = DotProduct (rejectpt, view_clipplanes[i].normal);
-			d -= view_clipplanes[i].dist;
-			if (d <= 0)
-				return;
-			acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
-			acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
-			acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
-
-			d = DotProduct (acceptpt, view_clipplanes[i].normal);
-			d -= view_clipplanes[i].dist;
-
-			if (d >= 0)
-				clipflags &= ~(1<<i);	// node is entirely on screen
-		}
-	}
-
-c_drawnode++;
-
-// if a leaf node, draw stuff
-	if (node->contents != -1)
-	{
-		pleaf = (mleaf_t *)node;
-
-		// check for door connected areas
-		if (r_newrefdef.areabits)
-		{
-			if (! (r_newrefdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
-				return;		// not visible
-		}
-
-		mark = pleaf->firstmarksurface;
-		c = pleaf->nummarksurfaces;
-
-		if (c)
-		{
-			do
-			{
-				(*mark)->visframe = r_framecount;
-				mark++;
-			} while (--c);
-		}
-
-		pleaf->key = r_currentkey;
-		r_currentkey++;		// all bmodels in a leaf share the same key
-	}
-	else
-	{
-	// node is just a decision point, so go down the apropriate sides
-
-	// find which side of the node we are on
-		plane = node->plane;
-
-		switch (plane->type)
-		{
-		case PLANE_X:
-			dot = modelorg[0] - plane->dist;
-			break;
-		case PLANE_Y:
-			dot = modelorg[1] - plane->dist;
-			break;
-		case PLANE_Z:
-			dot = modelorg[2] - plane->dist;
-			break;
-		default:
-			dot = DotProduct (modelorg, plane->normal) - plane->dist;
-			break;
-		}
-	
-		if (dot >= 0)
-			side = 0;
-		else
-			side = 1;
-
-	// recurse down the children, front side first
-		R_RecursiveWorldNode (node->children[side], clipflags);
-
-	// draw stuff
-		c = node->numsurfaces;
-
-		if (c)
-		{
-			surf = r_worldmodel->surfaces + node->firstsurface;
-
-			if (dot < -BACKFACE_EPSILON)
-			{
-				do
-				{
-					if ((surf->flags & SURF_PLANEBACK) &&
-						(surf->visframe == r_framecount))
-					{
-						R_RenderFace (surf, clipflags);
-					}
-
-					surf++;
-				} while (--c);
-			}
-			else if (dot > BACKFACE_EPSILON)
-			{
-				do
-				{
-					if (!(surf->flags & SURF_PLANEBACK) &&
-						(surf->visframe == r_framecount))
-					{
-						R_RenderFace (surf, clipflags);
-					}
-
-					surf++;
-				} while (--c);
-			}
-
-		// all surfaces on the same node share the same sequence number
-			r_currentkey++;
-		}
-
-	// recurse down the back side
-		R_RecursiveWorldNode (node->children[!side], clipflags);
-	}
-}
-
-
-
-/*
-================
-R_RenderWorld
-================
-*/
-void R_RenderWorld (void)
-{
-
-	if (!r_drawworld->value)
-		return;
-	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
-		return;
-
-	c_drawnode=0;
-
-	// auto cycle the world frame for texture animation
-	r_worldentity.frame = (int)(r_newrefdef.time*2);
-	currententity = &r_worldentity;
-
-	VectorCopy (r_origin, modelorg);
-	currentmodel = r_worldmodel;
-	r_pcurrentvertbase = currentmodel->vertexes;
-
-	R_RecursiveWorldNode (currentmodel->nodes, 15);
-}
-
-
--- a/ref/r_draw.c
+++ /dev/null
@@ -1,426 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-
-image_t		*draw_chars;				// 8*8 graphic characters
-
-//=============================================================================
-
-/*
-================
-Draw_FindPic
-================
-*/
-image_t *Draw_FindPic (char *name)
-{
-	image_t	*image;
-	char	fullname[MAX_QPATH];
-
-	if (name[0] != '/' && name[0] != '\\')
-	{
-		Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name);
-		image = R_FindImage (fullname, it_pic);
-	}
-	else
-		image = R_FindImage (name+1, it_pic);
-
-	return image;
-}
-
-
-
-/*
-===============
-Draw_InitLocal
-===============
-*/
-void Draw_InitLocal (void)
-{
-	draw_chars = Draw_FindPic ("conchars");
-}
-
-
-
-/*
-================
-Draw_Char
-
-Draws one 8*8 graphics character
-It can be clipped to the top of the screen to allow the console to be
-smoothly scrolled off.
-================
-*/
-void Draw_Char (int x, int y, int num)
-{
-	byte			*dest;
-	byte			*source;
-	int				drawline;	
-	int				row, col;
-
-	num &= 255;
-
-	if (num == 32 || num == 32+128)
-		return;
-
-	if (y <= -8)
-		return;			// totally off screen
-
-//	if ( ( y + 8 ) >= vid.height )
-	if ( ( y + 8 ) > vid.height )		// PGM - status text was missing in sw...
-		return;
-
-#ifdef PARANOID
-	if (y > vid.height - 8 || x < 0 || x > vid.width - 8)
-		ri.Sys_Error (ERR_FATAL,"Con_DrawCharacter: (%i, %i)", x, y);
-	if (num < 0 || num > 255)
-		ri.Sys_Error (ERR_FATAL,"Con_DrawCharacter: char %i", num);
-#endif
-
-	row = num>>4;
-	col = num&15;
-	source = draw_chars->pixels[0] + (row<<10) + (col<<3);
-
-	if (y < 0)
-	{	// clipped
-		drawline = 8 + y;
-		source -= 128*y;
-		y = 0;
-	}
-	else
-		drawline = 8;
-
-
-	dest = vid.buffer + y*vid.rowbytes + x;
-
-	while (drawline--)
-	{
-		if (source[0] != TRANSPARENT_COLOR)
-			dest[0] = source[0];
-		if (source[1] != TRANSPARENT_COLOR)
-			dest[1] = source[1];
-		if (source[2] != TRANSPARENT_COLOR)
-			dest[2] = source[2];
-		if (source[3] != TRANSPARENT_COLOR)
-			dest[3] = source[3];
-		if (source[4] != TRANSPARENT_COLOR)
-			dest[4] = source[4];
-		if (source[5] != TRANSPARENT_COLOR)
-			dest[5] = source[5];
-		if (source[6] != TRANSPARENT_COLOR)
-			dest[6] = source[6];
-		if (source[7] != TRANSPARENT_COLOR)
-			dest[7] = source[7];
-		source += 128;
-		dest += vid.rowbytes;
-	}
-}
-
-/*
-=============
-Draw_GetPicSize
-=============
-*/
-void Draw_GetPicSize (int *w, int *h, char *pic)
-{
-	image_t *gl;
-
-	gl = Draw_FindPic (pic);
-	if (!gl)
-	{
-		*w = *h = -1;
-		return;
-	}
-	*w = gl->width;
-	*h = gl->height;
-}
-
-/*
-=============
-Draw_StretchPicImplementation
-=============
-*/
-void Draw_StretchPicImplementation (int x, int y, int w, int h, image_t	*pic)
-{
-	byte			*dest, *source;
-	int				v, u, sv;
-	int				height;
-	int				f, fstep;
-	int				skip;
-
-	if ((x < 0) ||
-		(x + w > vid.width) ||
-		(y + h > vid.height))
-	{
-		ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates");
-	}
-
-	height = h;
-	if (y < 0)
-	{
-		skip = -y;
-		height += y;
-		y = 0;
-	}
-	else
-		skip = 0;
-
-	dest = vid.buffer + y * vid.rowbytes + x;
-
-	for (v=0 ; v<height ; v++, dest += vid.rowbytes)
-	{
-		sv = (skip + v)*pic->height/h;
-		source = pic->pixels[0] + sv*pic->width;
-		if (w == pic->width)
-			memcpy (dest, source, w);
-		else
-		{
-			f = 0;
-			fstep = pic->width*0x10000/w;
-			for (u=0 ; u<w ; u+=4)
-			{
-				dest[u] = source[f>>16];
-				f += fstep;
-				dest[u+1] = source[f>>16];
-				f += fstep;
-				dest[u+2] = source[f>>16];
-				f += fstep;
-				dest[u+3] = source[f>>16];
-				f += fstep;
-			}
-		}
-	}
-}
-
-/*
-=============
-Draw_StretchPic
-=============
-*/
-void Draw_StretchPic (int x, int y, int w, int h, char *name)
-{
-	image_t	*pic;
-
-	pic = Draw_FindPic (name);
-	if (!pic)
-	{
-		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
-		return;
-	}
-	Draw_StretchPicImplementation (x, y, w, h, pic);
-}
-
-/*
-=============
-Draw_StretchRaw
-=============
-*/
-void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data)
-{
-	image_t	pic;
-
-	pic.pixels[0] = data;
-	pic.width = cols;
-	pic.height = rows;
-	Draw_StretchPicImplementation (x, y, w, h, &pic);
-}
-
-/*
-=============
-Draw_Pic
-=============
-*/
-void Draw_Pic (int x, int y, char *name)
-{
-	image_t			*pic;
-	byte			*dest, *source;
-	int				v, u;
-	int				tbyte;
-	int				height;
-
-	pic = Draw_FindPic (name);
-	if (!pic)
-	{
-		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
-		return;
-	}
-
-	if ((x < 0) ||
-		(x + pic->width > vid.width) ||
-		(y + pic->height > vid.height))
-		return;	//	ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates");
-
-	height = pic->height;
-	source = pic->pixels[0];
-	if (y < 0)
-	{
-		height += y;
-		source += pic->width*-y;
-		y = 0;
-	}
-
-	dest = vid.buffer + y * vid.rowbytes + x;
-
-	if (!pic->transparent)
-	{
-		for (v=0 ; v<height ; v++)
-		{
-			memcpy (dest, source, pic->width);
-			dest += vid.rowbytes;
-			source += pic->width;
-		}
-	}
-	else
-	{
-		if (pic->width & 7)
-		{	// general
-			for (v=0 ; v<height ; v++)
-			{
-				for (u=0 ; u<pic->width ; u++)
-					if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
-						dest[u] = tbyte;
-
-				dest += vid.rowbytes;
-				source += pic->width;
-			}
-		}
-		else
-		{	// unwound
-			for (v=0 ; v<height ; v++)
-			{
-				for (u=0 ; u<pic->width ; u+=8)
-				{
-					if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
-						dest[u] = tbyte;
-					if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
-						dest[u+1] = tbyte;
-					if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
-						dest[u+2] = tbyte;
-					if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
-						dest[u+3] = tbyte;
-					if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
-						dest[u+4] = tbyte;
-					if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
-						dest[u+5] = tbyte;
-					if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
-						dest[u+6] = tbyte;
-					if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
-						dest[u+7] = tbyte;
-				}
-				dest += vid.rowbytes;
-				source += pic->width;
-			}
-		}
-	}
-}
-
-/*
-=============
-Draw_TileClear
-
-This repeats a 64*64 tile graphic to fill the screen around a sized down
-refresh window.
-=============
-*/
-void Draw_TileClear (int x, int y, int w, int h, char *name)
-{
-	int			i, j;
-	byte		*psrc;
-	byte		*pdest;
-	image_t		*pic;
-	int			x2;
-
-	if (x < 0)
-	{
-		w += x;
-		x = 0;
-	}
-	if (y < 0)
-	{
-		h += y;
-		y = 0;
-	}
-	if (x + w > vid.width)
-		w = vid.width - x;
-	if (y + h > vid.height)
-		h = vid.height - y;
-	if (w <= 0 || h <= 0)
-		return;
-
-	pic = Draw_FindPic (name);
-	if (!pic)
-	{
-		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
-		return;
-	}
-	x2 = x + w;
-	pdest = vid.buffer + y*vid.rowbytes;
-	for (i=0 ; i<h ; i++, pdest += vid.rowbytes)
-	{
-		psrc = pic->pixels[0] + pic->width * ((i+y)&63);
-		for (j=x ; j<x2 ; j++)
-			pdest[j] = psrc[j&63];
-	}
-}
-
-
-/*
-=============
-Draw_Fill
-
-Fills a box of pixels with a single color
-=============
-*/
-void Draw_Fill (int x, int y, int w, int h, int c)
-{
-	byte			*dest;
-	int				u, v;
-
-	if (x+w > vid.width)
-		w = vid.width - x;
-	if (y+h > vid.height)
-		h = vid.height - y;
-	if (x < 0)
-	{
-		w += x;
-		x = 0;
-	}
-	if (y < 0)
-	{
-		h += y;
-		y = 0;
-	}
-	if (w < 0 || h < 0)
-		return;
-	dest = vid.buffer + y*vid.rowbytes + x;
-	for (v=0 ; v<h ; v++, dest += vid.rowbytes)
-		for (u=0 ; u<w ; u++)
-			dest[u] = c;
-}
-//=============================================================================
-
-/*
-================
-Draw_FadeScreen
-
-================
-*/
-void Draw_FadeScreen (void)
-{
-	int			x,y;
-	byte		*pbuf;
-	int	t;
-
-	for (y=0 ; y<vid.height ; y++)
-	{
-		pbuf = (byte *)(vid.buffer + vid.rowbytes*y);
-		t = (y & 1) << 1;
-
-		for (x=0 ; x<vid.width ; x++)
-		{
-			if ((x & 3) != t)
-				pbuf[x] = 0;
-		}
-	}
-}
--- a/ref/r_edge.c
+++ /dev/null
@@ -1,1084 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-void R_SurfacePatch (void)
-{
-}
-
-void R_EdgeCodeStart (void)
-{
-}
-
-void R_EdgeCodeEnd (void)
-{
-}
-
-
-/*
-the complex cases add new polys on most lines, so dont optimize for keeping them the same
-have multiple free span lists to try to get better coherence?
-low depth complexity -- 1 to 3 or so
-
-have a sentinal at both ends?
-*/
-
-
-edge_t	*auxedges;
-edge_t	*r_edges, *edge_p, *edge_max;
-
-surf_t	*surfaces, *surface_p, *surf_max;
-
-// 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
-
-edge_t	*newedges[MAXHEIGHT];
-edge_t	*removeedges[MAXHEIGHT];
-
-espan_t	*span_p, *max_span_p;
-
-int		r_currentkey;
-
-int	current_iv;
-
-int	edge_head_u_shift20, edge_tail_u_shift20;
-
-static void (*pdrawfunc)(void);
-
-edge_t	edge_head;
-edge_t	edge_tail;
-edge_t	edge_aftertail;
-edge_t	edge_sentinel;
-
-float	fv;
-
-static int	miplevel;
-
-float		scale_for_mip;
-int			ubasestep, errorterm, erroradjustup, erroradjustdown;
-
-// FIXME: should go away
-extern void			R_RotateBmodel (void);
-extern void			R_TransformFrustum (void);
-
-
-
-void R_GenerateSpans (void);
-void R_GenerateSpansBackward (void);
-
-void R_LeadingEdge (edge_t *edge);
-void R_LeadingEdgeBackwards (edge_t *edge);
-void R_TrailingEdge (surf_t *surf, edge_t *edge);
-
-
-/*
-===============================================================================
-
-EDGE SCANNING
-
-===============================================================================
-*/
-
-/*
-==============
-R_BeginEdgeFrame
-==============
-*/
-void R_BeginEdgeFrame (void)
-{
-	int		v;
-
-	edge_p = r_edges;
-	edge_max = &r_edges[r_numallocatededges];
-
-	surface_p = &surfaces[2];	// background is surface 1,
-								//  surface 0 is a dummy
-	surfaces[1].spans = NULL;	// no background spans yet
-	surfaces[1].flags = SURF_DRAWBACKGROUND;
-
-// put the background behind everything in the world
-	if (sw_draworder->value)
-	{
-		pdrawfunc = R_GenerateSpansBackward;
-		surfaces[1].key = 0;
-		r_currentkey = 1;
-	}
-	else
-	{
-		pdrawfunc = R_GenerateSpans;
-		surfaces[1].key = 0x7FFfFFFF;
-		r_currentkey = 0;
-	}
-
-// FIXME: set with memset
-	for (v=r_refdef.vrect.y ; v<r_refdef.vrectbottom ; v++)
-	{
-		newedges[v] = removeedges[v] = NULL;
-	}
-}
-
-/*
-==============
-R_InsertNewEdges
-
-Adds the edges in the linked list edgestoadd, adding them to the edges in the
-linked list edgelist.  edgestoadd is assumed to be sorted on u, and non-empty (this is actually newedges[v]).  edgelist is assumed to be sorted on u, with a
-sentinel at the end (actually, this is the active edge table starting at
-edge_head.next).
-==============
-*/
-void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist)
-{
-	edge_t	*next_edge;
-
-	do
-	{
-		next_edge = edgestoadd->next;
-edgesearch:
-		if (edgelist->u >= edgestoadd->u)
-			goto addedge;
-		edgelist=edgelist->next;
-		if (edgelist->u >= edgestoadd->u)
-			goto addedge;
-		edgelist=edgelist->next;
-		if (edgelist->u >= edgestoadd->u)
-			goto addedge;
-		edgelist=edgelist->next;
-		if (edgelist->u >= edgestoadd->u)
-			goto addedge;
-		edgelist=edgelist->next;
-		goto edgesearch;
-
-	// insert edgestoadd before edgelist
-addedge:
-		edgestoadd->next = edgelist;
-		edgestoadd->prev = edgelist->prev;
-		edgelist->prev->next = edgestoadd;
-		edgelist->prev = edgestoadd;
-	} while ((edgestoadd = next_edge) != NULL);
-}
-
-
-/*
-==============
-R_RemoveEdges
-==============
-*/
-void R_RemoveEdges (edge_t *pedge)
-{
-
-	do
-	{
-		pedge->next->prev = pedge->prev;
-		pedge->prev->next = pedge->next;
-	} while ((pedge = pedge->nextremove) != NULL);
-}
-
-
-/*
-==============
-R_StepActiveU
-==============
-*/
-void R_StepActiveU (edge_t *pedge)
-{
-	edge_t		*pnext_edge, *pwedge;
-
-	while (1)
-	{
-nextedge:
-		pedge->u += pedge->u_step;
-		if (pedge->u < pedge->prev->u)
-			goto pushback;
-		pedge = pedge->next;
-			
-		pedge->u += pedge->u_step;
-		if (pedge->u < pedge->prev->u)
-			goto pushback;
-		pedge = pedge->next;
-			
-		pedge->u += pedge->u_step;
-		if (pedge->u < pedge->prev->u)
-			goto pushback;
-		pedge = pedge->next;
-			
-		pedge->u += pedge->u_step;
-		if (pedge->u < pedge->prev->u)
-			goto pushback;
-		pedge = pedge->next;
-			
-		goto nextedge;		
-		
-pushback:
-		if (pedge == &edge_aftertail)
-			return;
-			
-	// push it back to keep it sorted		
-		pnext_edge = pedge->next;
-
-	// pull the edge out of the edge list
-		pedge->next->prev = pedge->prev;
-		pedge->prev->next = pedge->next;
-
-	// find out where the edge goes in the edge list
-		pwedge = pedge->prev->prev;
-
-		while (pwedge->u > pedge->u)
-		{
-			pwedge = pwedge->prev;
-		}
-
-	// put the edge back into the edge list
-		pedge->next = pwedge->next;
-		pedge->prev = pwedge;
-		pedge->next->prev = pedge;
-		pwedge->next = pedge;
-
-		pedge = pnext_edge;
-		if (pedge == &edge_tail)
-			return;
-	}
-}
-
-
-/*
-==============
-R_CleanupSpan
-==============
-*/
-void R_CleanupSpan (void)
-{
-	surf_t	*surf;
-	int		iu;
-	espan_t	*span;
-
-// now that we've reached the right edge of the screen, we're done with any
-// unfinished surfaces, so emit a span for whatever's on top
-	surf = surfaces[1].next;
-	iu = edge_tail_u_shift20;
-	if (iu > surf->last_u)
-	{
-		span = span_p++;
-		span->u = surf->last_u;
-		span->count = iu - span->u;
-		span->v = current_iv;
-		span->pnext = surf->spans;
-		surf->spans = span;
-	}
-
-// reset spanstate for all surfaces in the surface stack
-	do
-	{
-		surf->spanstate = 0;
-		surf = surf->next;
-	} while (surf != &surfaces[1]);
-}
-
-
-/*
-==============
-R_LeadingEdgeBackwards
-==============
-*/
-void R_LeadingEdgeBackwards (edge_t *edge)
-{
-	espan_t			*span;
-	surf_t			*surf, *surf2;
-	int				iu;
-
-// it's adding a new surface in, so find the correct place
-	surf = &surfaces[edge->surfs[1]];
-
-// don't start a span if this is an inverted span, with the end
-// edge preceding the start edge (that is, we've already seen the
-// end edge)
-	if (++surf->spanstate == 1)
-	{
-		surf2 = surfaces[1].next;
-
-		if (surf->key > surf2->key)
-			goto newtop;
-
-	// if it's two surfaces on the same plane, the one that's already
-	// active is in front, so keep going unless it's a bmodel
-		if (surf->insubmodel && (surf->key == surf2->key))
-		{
-		// must be two bmodels in the same leaf; don't care, because they'll
-		// never be farthest anyway
-			goto newtop;
-		}
-
-continue_search:
-
-		do
-		{
-			surf2 = surf2->next;
-		} while (surf->key < surf2->key);
-
-		if (surf->key == surf2->key)
-		{
-		// if it's two surfaces on the same plane, the one that's already
-		// active is in front, so keep going unless it's a bmodel
-			if (!surf->insubmodel)
-				goto continue_search;
-
-		// must be two bmodels in the same leaf; don't care which is really
-		// in front, because they'll never be farthest anyway
-		}
-
-		goto gotposition;
-
-newtop:
-	// emit a span (obscures current top)
-		iu = edge->u >> 20;
-
-		if (iu > surf2->last_u)
-		{
-			span = span_p++;
-			span->u = surf2->last_u;
-			span->count = iu - span->u;
-			span->v = current_iv;
-			span->pnext = surf2->spans;
-			surf2->spans = span;
-		}
-
-		// set last_u on the new span
-		surf->last_u = iu;
-				
-gotposition:
-	// insert before surf2
-		surf->next = surf2;
-		surf->prev = surf2->prev;
-		surf2->prev->next = surf;
-		surf2->prev = surf;
-	}
-}
-
-
-/*
-==============
-R_TrailingEdge
-==============
-*/
-void R_TrailingEdge (surf_t *surf, edge_t *edge)
-{
-	espan_t			*span;
-	int				iu;
-
-// don't generate a span if this is an inverted span, with the end
-// edge preceding the start edge (that is, we haven't seen the
-// start edge yet)
-	if (--surf->spanstate == 0)
-	{
-		if (surf == surfaces[1].next)
-		{
-		// emit a span (current top going away)
-			iu = edge->u >> 20;
-			if (iu > surf->last_u)
-			{
-				span = span_p++;
-				span->u = surf->last_u;
-				span->count = iu - span->u;
-				span->v = current_iv;
-				span->pnext = surf->spans;
-				surf->spans = span;
-			}
-
-		// set last_u on the surface below
-			surf->next->last_u = iu;
-		}
-
-		surf->prev->next = surf->next;
-		surf->next->prev = surf->prev;
-	}
-}
-
-
-/*
-==============
-R_LeadingEdge
-==============
-*/
-void R_LeadingEdge (edge_t *edge)
-{
-	espan_t			*span;
-	surf_t			*surf, *surf2;
-	int				iu;
-	float			fu, newzi, testzi, newzitop, newzibottom;
-
-	if (edge->surfs[1])
-	{
-	// it's adding a new surface in, so find the correct place
-		surf = &surfaces[edge->surfs[1]];
-
-	// don't start a span if this is an inverted span, with the end
-	// edge preceding the start edge (that is, we've already seen the
-	// end edge)
-		if (++surf->spanstate == 1)
-		{
-			surf2 = surfaces[1].next;
-
-			if (surf->key < surf2->key)
-				goto newtop;
-
-		// if it's two surfaces on the same plane, the one that's already
-		// active is in front, so keep going unless it's a bmodel
-			if (surf->insubmodel && (surf->key == surf2->key))
-			{
-			// must be two bmodels in the same leaf; sort on 1/z
-				fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
-				newzi = surf->d_ziorigin + fv*surf->d_zistepv +
-						fu*surf->d_zistepu;
-				newzibottom = newzi * 0.99;
-
-				testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
-						fu*surf2->d_zistepu;
-
-				if (newzibottom >= testzi)
-				{
-					goto newtop;
-				}
-
-				newzitop = newzi * 1.01;
-				if (newzitop >= testzi)
-				{
-					if (surf->d_zistepu >= surf2->d_zistepu)
-					{
-						goto newtop;
-					}
-				}
-			}
-
-continue_search:
-
-			do
-			{
-				surf2 = surf2->next;
-			} while (surf->key > surf2->key);
-
-			if (surf->key == surf2->key)
-			{
-			// if it's two surfaces on the same plane, the one that's already
-			// active is in front, so keep going unless it's a bmodel
-				if (!surf->insubmodel)
-					goto continue_search;
-
-			// must be two bmodels in the same leaf; sort on 1/z
-				fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
-				newzi = surf->d_ziorigin + fv*surf->d_zistepv +
-						fu*surf->d_zistepu;
-				newzibottom = newzi * 0.99;
-
-				testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
-						fu*surf2->d_zistepu;
-
-				if (newzibottom >= testzi)
-				{
-					goto gotposition;
-				}
-
-				newzitop = newzi * 1.01;
-				if (newzitop >= testzi)
-				{
-					if (surf->d_zistepu >= surf2->d_zistepu)
-					{
-						goto gotposition;
-					}
-				}
-
-				goto continue_search;
-			}
-
-			goto gotposition;
-
-newtop:
-		// emit a span (obscures current top)
-			iu = edge->u >> 20;
-
-			if (iu > surf2->last_u)
-			{
-				span = span_p++;
-				span->u = surf2->last_u;
-				span->count = iu - span->u;
-				span->v = current_iv;
-				span->pnext = surf2->spans;
-				surf2->spans = span;
-			}
-
-			// set last_u on the new span
-			surf->last_u = iu;
-				
-gotposition:
-		// insert before surf2
-			surf->next = surf2;
-			surf->prev = surf2->prev;
-			surf2->prev->next = surf;
-			surf2->prev = surf;
-		}
-	}
-}
-
-
-/*
-==============
-R_GenerateSpans
-==============
-*/
-void R_GenerateSpans (void)
-{
-	edge_t			*edge;
-	surf_t			*surf;
-
-// clear active surfaces to just the background surface
-	surfaces[1].next = surfaces[1].prev = &surfaces[1];
-	surfaces[1].last_u = edge_head_u_shift20;
-
-// generate spans
-	for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
-	{			
-		if (edge->surfs[0])
-		{
-		// it has a left surface, so a surface is going away for this span
-			surf = &surfaces[edge->surfs[0]];
-
-			R_TrailingEdge (surf, edge);
-
-			if (!edge->surfs[1])
-				continue;
-		}
-
-		R_LeadingEdge (edge);
-	}
-
-	R_CleanupSpan ();
-}
-
-
-/*
-==============
-R_GenerateSpansBackward
-==============
-*/
-void R_GenerateSpansBackward (void)
-{
-	edge_t			*edge;
-
-// clear active surfaces to just the background surface
-	surfaces[1].next = surfaces[1].prev = &surfaces[1];
-	surfaces[1].last_u = edge_head_u_shift20;
-
-// generate spans
-	for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
-	{			
-		if (edge->surfs[0])
-			R_TrailingEdge (&surfaces[edge->surfs[0]], edge);
-
-		if (edge->surfs[1])
-			R_LeadingEdgeBackwards (edge);
-	}
-
-	R_CleanupSpan ();
-}
-
-
-/*
-==============
-R_ScanEdges
-
-Input: 
-newedges[] array
-	this has links to edges, which have links to surfaces
-
-Output:
-Each surface has a linked list of its visible spans
-==============
-*/
-void R_ScanEdges (void)
-{
-	int		iv, bottom;
-	byte	basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
-	espan_t	*basespan_p;
-	surf_t	*s;
-
-	basespan_p = (espan_t *)
-			((uintptr)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
-	max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width];
-
-	span_p = basespan_p;
-
-// clear active edges to just the background edges around the whole screen
-// FIXME: most of this only needs to be set up once
-	edge_head.u = r_refdef.vrect.x << 20;
-	edge_head_u_shift20 = edge_head.u >> 20;
-	edge_head.u_step = 0;
-	edge_head.prev = NULL;
-	edge_head.next = &edge_tail;
-	edge_head.surfs[0] = 0;
-	edge_head.surfs[1] = 1;
-	
-	edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF;
-	edge_tail_u_shift20 = edge_tail.u >> 20;
-	edge_tail.u_step = 0;
-	edge_tail.prev = &edge_head;
-	edge_tail.next = &edge_aftertail;
-	edge_tail.surfs[0] = 1;
-	edge_tail.surfs[1] = 0;
-	
-	edge_aftertail.u = -1;		// force a move
-	edge_aftertail.u_step = 0;
-	edge_aftertail.next = &edge_sentinel;
-	edge_aftertail.prev = &edge_tail;
-
-// FIXME: do we need this now that we clamp x in r_draw.c?
-	edge_sentinel.u = 2000 << 24;		// make sure nothing sorts past this
-	edge_sentinel.prev = &edge_aftertail;
-
-//	
-// process all scan lines
-//
-	bottom = r_refdef.vrectbottom - 1;
-
-	for (iv=r_refdef.vrect.y ; iv<bottom ; iv++)
-	{
-		current_iv = iv;
-		fv = (float)iv;
-
-	// mark that the head (background start) span is pre-included
-		surfaces[1].spanstate = 1;
-
-		if (newedges[iv])
-		{
-			R_InsertNewEdges (newedges[iv], edge_head.next);
-		}
-
-		(*pdrawfunc) ();
-
-	// flush the span list if we can't be sure we have enough spans left for
-	// the next scan
-		if (span_p > max_span_p)
-		{
-			D_DrawSurfaces ();
-
-		// clear the surface span pointers
-			for (s = &surfaces[1] ; s<surface_p ; s++)
-				s->spans = NULL;
-
-			span_p = basespan_p;
-		}
-
-		if (removeedges[iv])
-			R_RemoveEdges (removeedges[iv]);
-
-		if (edge_head.next != &edge_tail)
-			R_StepActiveU (edge_head.next);
-	}
-
-// do the last scan (no need to step or sort or remove on the last scan)
-
-	current_iv = iv;
-	fv = (float)iv;
-
-// mark that the head (background start) span is pre-included
-	surfaces[1].spanstate = 1;
-
-	if (newedges[iv])
-		R_InsertNewEdges (newedges[iv], edge_head.next);
-
-	(*pdrawfunc) ();
-
-// draw whatever's left in the span list
-	D_DrawSurfaces ();
-}
-
-
-/*
-=========================================================================
-
-SURFACE FILLING
-
-=========================================================================
-*/
-
-msurface_t		*pface;
-surfcache_t		*pcurrentcache;
-vec3_t			transformed_modelorg;
-vec3_t			world_transformed_modelorg;
-vec3_t			local_modelorg;
-
-/*
-=============
-D_MipLevelForScale
-=============
-*/
-int D_MipLevelForScale (float scale)
-{
-	int		lmiplevel;
-
-	if (scale >= d_scalemip[0] )
-		lmiplevel = 0;
-	else if (scale >= d_scalemip[1] )
-		lmiplevel = 1;
-	else if (scale >= d_scalemip[2] )
-		lmiplevel = 2;
-	else
-		lmiplevel = 3;
-
-	if (lmiplevel < d_minmip)
-		lmiplevel = d_minmip;
-
-	return lmiplevel;
-}
-
-
-/*
-==============
-D_FlatFillSurface
-
-Simple single color fill with no texture mapping
-==============
-*/
-void D_FlatFillSurface (surf_t *surf, int color)
-{
-	espan_t	*span;
-	byte	*pdest;
-	int		u, u2;
-	
-	for (span=surf->spans ; span ; span=span->pnext)
-	{
-		pdest = (byte *)d_viewbuffer + r_screenwidth*span->v;
-		u = span->u;
-		u2 = span->u + span->count - 1;
-		for ( ; u <= u2 ; u++)
-			pdest[u] = color;
-	}
-}
-
-
-/*
-==============
-D_CalcGradients
-==============
-*/
-void D_CalcGradients (msurface_t *pface)
-{
-	float		mipscale;
-	vec3_t		p_temp1;
-	vec3_t		p_saxis, p_taxis;
-	float		t;
-
-	mipscale = 1.0 / (float)(1 << miplevel);
-
-	TransformVector (pface->texinfo->vecs[0], p_saxis);
-	TransformVector (pface->texinfo->vecs[1], p_taxis);
-
-	t = xscaleinv * mipscale;
-	d_sdivzstepu = p_saxis[0] * t;
-	d_tdivzstepu = p_taxis[0] * t;
-
-	t = yscaleinv * mipscale;
-	d_sdivzstepv = -p_saxis[1] * t;
-	d_tdivzstepv = -p_taxis[1] * t;
-
-	d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu -
-			ycenter * d_sdivzstepv;
-	d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu -
-			ycenter * d_tdivzstepv;
-
-	VectorScale (transformed_modelorg, mipscale, p_temp1);
-
-	t = 0x10000*mipscale;
-	sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
-			((pface->texturemins[0] << 16) >> miplevel)
-			+ pface->texinfo->vecs[0][3]*t;
-	tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
-			((pface->texturemins[1] << 16) >> miplevel)
-			+ pface->texinfo->vecs[1][3]*t;
-
-	// PGM - changing flow speed for non-warping textures.
-	if (pface->texinfo->flags & SURF_FLOWING)
-	{
-		if(pface->texinfo->flags & SURF_WARP)
-			sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.25) - (int)(r_newrefdef.time * 0.25) ));
-		else
-			sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.77) - (int)(r_newrefdef.time * 0.77) ));
-	}
-	// PGM
-
-//
-// -1 (-epsilon) so we never wander off the edge of the texture
-//
-	bbextents = ((pface->extents[0] << 16) >> miplevel) - 1;
-	bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1;
-}
-
-
-/*
-==============
-D_BackgroundSurf
-
-The grey background filler seen when there is a hole in the map
-==============
-*/
-void D_BackgroundSurf (surf_t *s)
-{
-// set up a gradient for the background surface that places it
-// effectively at infinity distance from the viewpoint
-	d_zistepu = 0;
-	d_zistepv = 0;
-	d_ziorigin = -0.9;
-
-	D_FlatFillSurface (s, (int)sw_clearcolor->value & 0xFF);
-	D_DrawZSpans (s->spans);
-}
-
-/*
-=================
-D_TurbulentSurf
-=================
-*/
-void D_TurbulentSurf (surf_t *s)
-{
-	d_zistepu = s->d_zistepu;
-	d_zistepv = s->d_zistepv;
-	d_ziorigin = s->d_ziorigin;
-
-	pface = s->msurf;
-	miplevel = 0;
-	cacheblock = pface->texinfo->image->pixels[0];
-	cachewidth = 64;
-
-	if (s->insubmodel)
-	{
-	// FIXME: we don't want to do all this for every polygon!
-	// TODO: store once at start of frame
-		currententity = s->entity;	//FIXME: make this passed in to
-									// R_RotateBmodel ()
-		VectorSubtract (r_origin, currententity->origin,
-				local_modelorg);
-		TransformVector (local_modelorg, transformed_modelorg);
-
-		R_RotateBmodel ();	// FIXME: don't mess with the frustum,
-							// make entity passed in
-	}
-
-	D_CalcGradients (pface);
-
-//============
-//PGM
-	// textures that aren't warping are just flowing. Use NonTurbulent8 instead
-	if(!(pface->texinfo->flags & SURF_WARP))
-		NonTurbulent8 (s->spans);
-	else
-		Turbulent8 (s->spans);
-//PGM
-//============
-
-	D_DrawZSpans (s->spans);
-
-	if (s->insubmodel)
-	{
-	//
-	// restore the old drawing state
-	// FIXME: we don't want to do this every time!
-	// TODO: speed up
-	//
-		currententity = NULL;	// &r_worldentity;
-		VectorCopy (world_transformed_modelorg,
-					transformed_modelorg);
-		VectorCopy (base_vpn, vpn);
-		VectorCopy (base_vup, vup);
-		VectorCopy (base_vright, vright);
-		R_TransformFrustum ();
-	}
-}
-
-/*
-==============
-D_SkySurf
-==============
-*/
-void D_SkySurf (surf_t *s)
-{
-	pface = s->msurf;
-	miplevel = 0;
-	if (!pface->texinfo->image)
-		return;
-	cacheblock = pface->texinfo->image->pixels[0];
-	cachewidth = 256;
-
-	d_zistepu = s->d_zistepu;
-	d_zistepv = s->d_zistepv;
-	d_ziorigin = s->d_ziorigin;
-
-	D_CalcGradients (pface);
-
-	D_DrawSpans16 (s->spans);
-
-// set up a gradient for the background surface that places it
-// effectively at infinity distance from the viewpoint
-	d_zistepu = 0;
-	d_zistepv = 0;
-	d_ziorigin = -0.9;
-
-	D_DrawZSpans (s->spans);
-}
-
-/*
-==============
-D_SolidSurf
-
-Normal surface cached, texture mapped surface
-==============
-*/
-void D_SolidSurf (surf_t *s)
-{
-	d_zistepu = s->d_zistepu;
-	d_zistepv = s->d_zistepv;
-	d_ziorigin = s->d_ziorigin;
-
-	if (s->insubmodel)
-	{
-	// FIXME: we don't want to do all this for every polygon!
-	// TODO: store once at start of frame
-		currententity = s->entity;	//FIXME: make this passed in to
-									// R_RotateBmodel ()
-		VectorSubtract (r_origin, currententity->origin, local_modelorg);
-		TransformVector (local_modelorg, transformed_modelorg);
-
-		R_RotateBmodel ();	// FIXME: don't mess with the frustum,
-							// make entity passed in
-	}
-	else
-		currententity = &r_worldentity;
-
-	pface = s->msurf;
-/* commented out in release
-	{
-		float dot;
-		float normal[3];
-
-		if ( s->insubmodel )
-		{
-			VectorCopy( pface->plane->normal, normal );
-//			TransformVector( pface->plane->normal, normal);
-			dot = DotProduct( normal, vpn );
-		}
-		else
-		{
-			VectorCopy( pface->plane->normal, normal );
-			dot = DotProduct( normal, vpn );
-		}
-
-		if ( pface->flags & SURF_PLANEBACK )
-			dot = -dot;
-
-		if ( dot > 0 )
-			printf( "blah" );
-
-		miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust);
-	}
-*/
-	miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust);
-
-// FIXME: make this passed in to D_CacheSurface
-	pcurrentcache = D_CacheSurface (pface, miplevel);
-
-	cacheblock = (pixel_t *)pcurrentcache->data;
-	cachewidth = pcurrentcache->width;
-
-	D_CalcGradients (pface);
-
-	D_DrawSpans16 (s->spans);
-
-	D_DrawZSpans (s->spans);
-
-	if (s->insubmodel)
-	{
-	//
-	// restore the old drawing state
-	// FIXME: we don't want to do this every time!
-	// TODO: speed up
-	//
-		VectorCopy (world_transformed_modelorg,
-					transformed_modelorg);
-		VectorCopy (base_vpn, vpn);
-		VectorCopy (base_vup, vup);
-		VectorCopy (base_vright, vright);
-		R_TransformFrustum ();
-		currententity = NULL;	//&r_worldentity;
-	}
-}
-
-/*
-=============
-D_DrawflatSurfaces
-
-To allow developers to see the polygon carving of the world
-=============
-*/
-void D_DrawflatSurfaces (void)
-{
-	surf_t			*s;
-
-	for (s = &surfaces[1] ; s<surface_p ; s++)
-	{
-		if (!s->spans)
-			continue;
-
-		d_zistepu = s->d_zistepu;
-		d_zistepv = s->d_zistepv;
-		d_ziorigin = s->d_ziorigin;
-
-		// make a stable color for each surface by taking the low
-		// bits of the msurface pointer
-		D_FlatFillSurface (s, (uintptr)s->msurf & 0xFF);
-		D_DrawZSpans (s->spans);
-	}
-}
-
-/*
-==============
-D_DrawSurfaces
-
-Rasterize all the span lists.  Guaranteed zero overdraw.
-May be called more than once a frame if the surf list overflows (higher res)
-==============
-*/
-void D_DrawSurfaces (void)
-{
-	surf_t			*s;
-
-//	currententity = NULL;	//&r_worldentity;
-	VectorSubtract (r_origin, vec3_origin, modelorg);
-	TransformVector (modelorg, transformed_modelorg);
-	VectorCopy (transformed_modelorg, world_transformed_modelorg);
-
-	if (!sw_drawflat->value)
-	{
-		for (s = &surfaces[1] ; s<surface_p ; s++)
-		{
-			if (!s->spans)
-				continue;
-
-			r_drawnpolycount++;
-
-			if (! (s->flags & (SURF_DRAWSKYBOX|SURF_DRAWBACKGROUND|SURF_DRAWTURB) ) )
-				D_SolidSurf (s);
-			else if (s->flags & SURF_DRAWSKYBOX)
-				D_SkySurf (s);
-			else if (s->flags & SURF_DRAWBACKGROUND)
-				D_BackgroundSurf (s);
-			else if (s->flags & SURF_DRAWTURB)
-				D_TurbulentSurf (s);
-		}
-	}
-	else
-		D_DrawflatSurfaces ();
-
-	currententity = NULL;	//&r_worldentity;
-	VectorSubtract (r_origin, vec3_origin, modelorg);
-	R_TransformFrustum ();
-}
-
--- a/ref/r_image.c
+++ /dev/null
@@ -1,586 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-
-#define	MAX_RIMAGES	1024
-image_t		r_images[MAX_RIMAGES];
-int			numr_images;
-
-
-/*
-===============
-R_ImageList_f
-===============
-*/
-void	R_ImageList_f (void)
-{
-	int		i;
-	image_t	*image;
-	int		texels;
-
-	ri.Con_Printf (PRINT_ALL, "------------------\n");
-	texels = 0;
-
-	for (i=0, image=r_images ; i<numr_images ; i++, image++)
-	{
-		if (image->registration_sequence <= 0)
-			continue;
-		texels += image->width*image->height;
-		switch (image->type)
-		{
-		case it_skin:
-			ri.Con_Printf (PRINT_ALL, "M");
-			break;
-		case it_sprite:
-			ri.Con_Printf (PRINT_ALL, "S");
-			break;
-		case it_wall:
-			ri.Con_Printf (PRINT_ALL, "W");
-			break;
-		case it_pic:
-			ri.Con_Printf (PRINT_ALL, "P");
-			break;
-		default:
-			ri.Con_Printf (PRINT_ALL, " ");
-			break;
-		}
-
-		ri.Con_Printf (PRINT_ALL,  " %3i %3i : %s\n",
-			image->width, image->height, image->name);
-	}
-	ri.Con_Printf (PRINT_ALL, "Total texel count: %i\n", texels);
-}
-
-
-/*
-=================================================================
-
-PCX LOADING
-
-=================================================================
-*/
-
-/*
-==============
-LoadPCX
-==============
-*/
-void 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 = ri.FS_LoadFile (filename, (void **)&raw);
-	if (!raw)
-	{
-		ri.Con_Printf (PRINT_DEVELOPER, "Bad pcx file %s\n", filename);
-		return;
-	}
-
-	//
-	// parse the PCX file
-	//
-	pcx = (pcx_t *)raw;
-
-    pcx->xmin = LittleShort(pcx->xmin);
-    pcx->ymin = LittleShort(pcx->ymin);
-    pcx->xmax = LittleShort(pcx->xmax);
-    pcx->ymax = LittleShort(pcx->ymax);
-    pcx->hres = LittleShort(pcx->hres);
-    pcx->vres = LittleShort(pcx->vres);
-    pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
-    pcx->palette_type = LittleShort(pcx->palette_type);
-
-	raw = &pcx->data;
-
-	if (pcx->manufacturer != 0x0a
-		|| pcx->version != 5
-		|| pcx->encoding != 1
-		|| pcx->bits_per_pixel != 8
-		|| pcx->xmax >= 640
-		|| pcx->ymax >= 480)
-	{
-		ri.Con_Printf (PRINT_ALL, "Bad pcx file %s\n", filename);
-		return;
-	}
-
-	out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
-
-	*pic = out;
-
-	pix = out;
-
-	if (palette)
-	{
-		*palette = 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)
-	{
-		ri.Con_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
-		free (*pic);
-		*pic = NULL;
-	}
-
-	ri.FS_FreeFile (pcx);
-}
-
-/*
-=========================================================
-
-TARGA LOADING
-
-=========================================================
-*/
-
-typedef struct _TargaHeader {
-	unsigned char 	id_length, colormap_type, image_type;
-	unsigned short	colormap_index, colormap_length;
-	unsigned char	colormap_size;
-	unsigned short	x_origin, y_origin, width, height;
-	unsigned char	pixel_size, attributes;
-} TargaHeader;
-
-
-/*
-=============
-LoadTGA
-=============
-*/
-void LoadTGA (char *name, byte **pic, int *width, int *height)
-{
-	int		columns, rows, numPixels;
-	byte	*pixbuf;
-	int		row, column;
-	byte	*buf_p;
-	byte	*buffer;
-	TargaHeader		targa_header;
-	byte			*targa_rgba;
-	uchar	red = 0, green = 0, blue = 0, alphabyte = 0, packetHeader, packetSize, j;
-
-	*pic = NULL;
-
-	//
-	// load the file
-	//
-	ri.FS_LoadFile (name, (void **)&buffer);	/* int length = */
-	if (!buffer)
-	{
-		ri.Con_Printf (PRINT_DEVELOPER, "Bad tga file %s\n", name);
-		return;
-	}
-
-	buf_p = buffer;
-
-	targa_header.id_length = *buf_p++;
-	targa_header.colormap_type = *buf_p++;
-	targa_header.image_type = *buf_p++;
-	
-	targa_header.colormap_index = LittleShort ( *((short *)buf_p) );
-	buf_p+=2;
-	targa_header.colormap_length = LittleShort ( *((short *)buf_p) );
-	buf_p+=2;
-	targa_header.colormap_size = *buf_p++;
-	targa_header.x_origin = LittleShort ( *((short *)buf_p) );
-	buf_p+=2;
-	targa_header.y_origin = LittleShort ( *((short *)buf_p) );
-	buf_p+=2;
-	targa_header.width = LittleShort ( *((short *)buf_p) );
-	buf_p+=2;
-	targa_header.height = LittleShort ( *((short *)buf_p) );
-	buf_p+=2;
-	targa_header.pixel_size = *buf_p++;
-	targa_header.attributes = *buf_p++;
-
-	if (targa_header.image_type!=2 
-		&& targa_header.image_type!=10) 
-		ri.Sys_Error (ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n");
-
-	if (targa_header.colormap_type !=0 
-		|| (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
-		ri.Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
-
-	columns = targa_header.width;
-	rows = targa_header.height;
-	numPixels = columns * rows;
-
-	if (width)
-		*width = columns;
-	if (height)
-		*height = rows;
-
-	targa_rgba = malloc (numPixels*4);
-	*pic = targa_rgba;
-
-	if (targa_header.id_length != 0)
-		buf_p += targa_header.id_length;  // skip TARGA image comment
-	
-	if (targa_header.image_type==2) {  // Uncompressed, RGB images
-		for(row=rows-1; row>=0; row--) {
-			pixbuf = targa_rgba + row*columns*4;
-			for(column=0; column<columns; column++) {
-				switch (targa_header.pixel_size) {
-					case 24:
-							
-							blue = *buf_p++;
-							green = *buf_p++;
-							red = *buf_p++;
-							*pixbuf++ = red;
-							*pixbuf++ = green;
-							*pixbuf++ = blue;
-							*pixbuf++ = 255;
-							break;
-					case 32:
-							blue = *buf_p++;
-							green = *buf_p++;
-							red = *buf_p++;
-							alphabyte = *buf_p++;
-							*pixbuf++ = red;
-							*pixbuf++ = green;
-							*pixbuf++ = blue;
-							*pixbuf++ = alphabyte;
-							break;
-				}
-			}
-		}
-	}
-	else if (targa_header.image_type==10) {   // Runlength encoded RGB images
-		for(row=rows-1; row>=0; row--) {
-			pixbuf = targa_rgba + row*columns*4;
-			for(column=0; column<columns; ) {
-				packetHeader= *buf_p++;
-				packetSize = 1 + (packetHeader & 0x7f);
-				if (packetHeader & 0x80) {        // run-length packet
-					switch (targa_header.pixel_size) {
-						case 24:
-								blue = *buf_p++;
-								green = *buf_p++;
-								red = *buf_p++;
-								alphabyte = 255;
-								break;
-						case 32:
-								blue = *buf_p++;
-								green = *buf_p++;
-								red = *buf_p++;
-								alphabyte = *buf_p++;
-								break;
-					}
-	
-					for(j=0;j<packetSize;j++) {
-						*pixbuf++=red;
-						*pixbuf++=green;
-						*pixbuf++=blue;
-						*pixbuf++=alphabyte;
-						column++;
-						if (column==columns) { // run spans across rows
-							column=0;
-							if (row>0)
-								row--;
-							else
-								goto breakOut;
-							pixbuf = targa_rgba + row*columns*4;
-						}
-					}
-				}
-				else {                            // non run-length packet
-					for(j=0;j<packetSize;j++) {
-						switch (targa_header.pixel_size) {
-							case 24:
-									blue = *buf_p++;
-									green = *buf_p++;
-									red = *buf_p++;
-									*pixbuf++ = red;
-									*pixbuf++ = green;
-									*pixbuf++ = blue;
-									*pixbuf++ = 255;
-									break;
-							case 32:
-									blue = *buf_p++;
-									green = *buf_p++;
-									red = *buf_p++;
-									alphabyte = *buf_p++;
-									*pixbuf++ = red;
-									*pixbuf++ = green;
-									*pixbuf++ = blue;
-									*pixbuf++ = alphabyte;
-									break;
-						}
-						column++;
-						if (column==columns) { // pixel packet run spans across rows
-							column=0;
-							if (row>0)
-								row--;
-							else
-								goto breakOut;
-							pixbuf = targa_rgba + row*columns*4;
-						}						
-					}
-				}
-			}
-			breakOut:;
-		}
-	}
-
-	ri.FS_FreeFile (buffer);
-}
-
-
-//=======================================================
-
-image_t *R_FindFreeImage (void)
-{
-	image_t		*image;
-	int			i;
-
-	// find a free image_t
-	for (i=0, image=r_images ; i<numr_images ; i++,image++)
-	{
-		if (!image->registration_sequence)
-			break;
-	}
-	if (i == numr_images)
-	{
-		if (numr_images == MAX_RIMAGES)
-			ri.Sys_Error (ERR_DROP, "MAX_RIMAGES");
-		numr_images++;
-	}
-	image = &r_images[i];
-
-	return image;
-}
-
-/*
-================
-GL_LoadPic
-
-================
-*/
-image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type)
-{
-	image_t		*image;
-	int			i, c, b;
-
-	image = R_FindFreeImage ();
-	if (strlen(name) >= sizeof(image->name))
-		ri.Sys_Error (ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name);
-	strcpy (image->name, name);
-	image->registration_sequence = registration_sequence;
-
-	image->width = width;
-	image->height = height;
-	image->type = type;
-
-	c = width*height;
-	image->pixels[0] = malloc (c);
-	image->transparent = false;
-	for (i=0 ; i<c ; i++)
-	{
-		b = pic[i];
-		if (b == 255)
-			image->transparent = true;
-		image->pixels[0][i] = b;
-	}
-
-	return image;
-}
-
-/*
-================
-R_LoadWal
-================
-*/
-image_t *R_LoadWal (char *name)
-{
-	miptex_t	*mt;
-	int			ofs;
-	image_t		*image;
-	int			size;
-
-	ri.FS_LoadFile (name, (void **)&mt);
-	if (!mt)
-	{
-		ri.Con_Printf (PRINT_ALL, "R_LoadWal: can't load %s\n", name);
-		return r_notexture_mip;
-	}
-
-	image = R_FindFreeImage ();
-	strcpy (image->name, name);
-	image->width = LittleLong (mt->width);
-	image->height = LittleLong (mt->height);
-	image->type = it_wall;
-	image->registration_sequence = registration_sequence;
-
-	size = image->width*image->height * (256+64+16+4)/256;
-	image->pixels[0] = malloc (size);
-	image->pixels[1] = image->pixels[0] + image->width*image->height;
-	image->pixels[2] = image->pixels[1] + image->width*image->height/4;
-	image->pixels[3] = image->pixels[2] + image->width*image->height/16;
-
-	ofs = LittleLong (mt->offsets[0]);
-	memcpy ( image->pixels[0], (byte *)mt + ofs, size);
-
-	ri.FS_FreeFile ((void *)mt);
-
-	return image;
-}
-
-
-/*
-===============
-R_FindImage
-
-Finds or loads the given image
-===============
-*/
-image_t	*R_FindImage (char *name, imagetype_t type)
-{
-	image_t	*image;
-	int		i, len;
-	byte	*pic, *palette;
-	int		width, height;
-
-	if (!name)
-		return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: NULL name");
-	len = strlen(name);
-	if (len<5)
-		return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: bad name: %s", name);
-
-	// look for it
-	for (i=0, image=r_images ; i<numr_images ; i++,image++)
-	{
-		if (!strcmp(name, image->name))
-		{
-			image->registration_sequence = registration_sequence;
-			return image;
-		}
-	}
-
-	//
-	// load the pic from disk
-	//
-	pic = NULL;
-	palette = NULL;
-	if (!strcmp(name+len-4, ".pcx"))
-	{
-		LoadPCX (name, &pic, &palette, &width, &height);
-		if (!pic)
-			return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s", name);
-		image = GL_LoadPic (name, pic, width, height, type);
-	}
-	else if (!strcmp(name+len-4, ".wal"))
-	{
-		image = R_LoadWal (name);
-	}
-	else if (!strcmp(name+len-4, ".tga"))
-		return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s in software renderer", name);
-	else
-		return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: bad extension on: %s", name);
-
-	if (pic)
-		free(pic);
-	if (palette)
-		free(palette);
-
-	return image;
-}
-
-
-
-/*
-===============
-R_RegisterSkin
-===============
-*/
-struct image_s *R_RegisterSkin (char *name)
-{
-	return R_FindImage (name, it_skin);
-}
-
-
-/*
-================
-R_FreeUnusedImages
-
-Any image that was not touched on this registration sequence
-will be freed.
-================
-*/
-void R_FreeUnusedImages (void)
-{
-	int		i;
-	image_t	*image;
-
-	for (i=0, image=r_images ; i<numr_images ; i++, image++)
-	{
-		if (image->registration_sequence == registration_sequence)
-		{
-			Com_PageInMemory ((byte *)image->pixels[0], image->width*image->height);
-			continue;		// used this sequence
-		}
-		if (!image->registration_sequence)
-			continue;		// free texture
-		if (image->type == it_pic)
-			continue;		// don't free pics
-		// free it
-		free (image->pixels[0]);	// the other mip levels just follow
-		memset (image, 0, sizeof(*image));
-	}
-}
-
-void
-R_InitImages(void)
-{
-	registration_sequence = 1;
-}
-
-void
-R_ShutdownImages(void)
-{
-	int i;
-	image_t *image;
-
-	for(i=0, image=r_images; i<numr_images; i++, image++){
-		if(!image->registration_sequence)
-			continue;		// free texture
-		// free it
-		free(image->pixels[0]);	// the other mip levels just follow
-		memset(image, 0, sizeof *image);
-	}
-}
--- a/ref/r_light.c
+++ /dev/null
@@ -1,422 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-int	r_dlightframecount;
-
-
-/*
-=============================================================================
-
-DYNAMIC LIGHTS
-
-=============================================================================
-*/
-
-/*
-=============
-R_MarkLights
-=============
-*/
-void R_MarkLights (dlight_t *light, int bit, mnode_t *node)
-{
-	mplane_t	*splitplane;
-	float		dist;
-	msurface_t	*surf;
-	int			i;
-	
-	if (node->contents != -1)
-		return;
-
-	splitplane = node->plane;
-	dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
-	
-//=====
-//PGM
-	i=light->intensity;
-	if(i<0)
-		i=-i;
-//PGM
-//=====
-
-	if (dist > i)	// PGM (dist > light->intensity)
-	{
-		R_MarkLights (light, bit, node->children[0]);
-		return;
-	}
-	if (dist < -i)	// PGM (dist < -light->intensity)
-	{
-		R_MarkLights (light, bit, node->children[1]);
-		return;
-	}
-		
-// mark the polygons
-	surf = r_worldmodel->surfaces + node->firstsurface;
-	for (i=0 ; i<node->numsurfaces ; i++, surf++)
-	{
-		if (surf->dlightframe != r_dlightframecount)
-		{
-			surf->dlightbits = 0;
-			surf->dlightframe = r_dlightframecount;
-		}
-		surf->dlightbits |= bit;
-	}
-
-	R_MarkLights (light, bit, node->children[0]);
-	R_MarkLights (light, bit, node->children[1]);
-}
-
-
-/*
-=============
-R_PushDlights
-=============
-*/
-void R_PushDlights (model_t *model)
-{
-	int		i;
-	dlight_t	*l;
-
-	r_dlightframecount = r_framecount;
-	for (i=0, l = r_newrefdef.dlights ; i<r_newrefdef.num_dlights ; i++, l++)
-	{
-		R_MarkLights ( l, 1<<i, 
-			model->nodes + model->firstnode);
-	}
-}
-
-
-/*
-=============================================================================
-
-LIGHT SAMPLING
-
-=============================================================================
-*/
-
-vec3_t	pointcolor;
-mplane_t		*lightplane;		// used as shadow plane
-vec3_t			lightspot;
-
-int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
-{
-	float		front, back, frac;
-	int			side;
-	mplane_t	*plane;
-	vec3_t		mid;
-	msurface_t	*surf;
-	int			s, t, ds, dt;
-	int			i;
-	mtexinfo_t	*tex;
-	byte		*lightmap;
-	float		*scales;
-	int			maps;
-	float		samp;
-	int			r;
-
-	if (node->contents != -1)
-		return -1;		// didn't hit anything
-	
-// calculate mid point
-
-// FIXME: optimize for axial
-	plane = node->plane;
-	front = DotProduct (start, plane->normal) - plane->dist;
-	back = DotProduct (end, plane->normal) - plane->dist;
-	side = front < 0;
-	
-	if ( (back < 0) == side)
-		return RecursiveLightPoint (node->children[side], start, end);
-	
-	frac = front / (front-back);
-	mid[0] = start[0] + (end[0] - start[0])*frac;
-	mid[1] = start[1] + (end[1] - start[1])*frac;
-	mid[2] = start[2] + (end[2] - start[2])*frac;
-	if (plane->type < 3)	// axial planes
-		mid[plane->type] = plane->dist;
-
-// go down front side	
-	r = RecursiveLightPoint (node->children[side], start, mid);
-	if (r >= 0)
-		return r;		// hit something
-		
-	if ( (back < 0) == side )
-		return -1;		// didn't hit anuthing
-		
-// check for impact on this node
-	VectorCopy (mid, lightspot);
-	lightplane = plane;
-
-	surf = r_worldmodel->surfaces + node->firstsurface;
-	for (i=0 ; i<node->numsurfaces ; i++, surf++)
-	{
-		if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY)) 
-			continue;	// no lightmaps
-
-		tex = surf->texinfo;
-		
-		s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3];
-		t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];
-		if (s < surf->texturemins[0] ||
-		t < surf->texturemins[1])
-			continue;
-		
-		ds = s - surf->texturemins[0];
-		dt = t - surf->texturemins[1];
-		
-		if ( ds > surf->extents[0] || dt > surf->extents[1] )
-			continue;
-
-		if (!surf->samples)
-			return 0;
-
-		ds >>= 4;
-		dt >>= 4;
-
-		lightmap = surf->samples;
-		VectorCopy (vec3_origin, pointcolor);
-		if (lightmap)
-		{
-			lightmap += dt * ((surf->extents[0]>>4)+1) + ds;
-
-			for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
-					maps++)
-			{
-				samp = *lightmap * /* 0.5 * */ (1.0/255);	// adjust for gl scale
-				scales = r_newrefdef.lightstyles[surf->styles[maps]].rgb;
-				VectorMA (pointcolor, samp, scales, pointcolor);
-				lightmap += ((surf->extents[0]>>4)+1) *
-						((surf->extents[1]>>4)+1);
-			}
-		}
-		
-		return 1;
-	}
-
-// go down back side
-	return RecursiveLightPoint (node->children[!side], mid, end);
-}
-
-/*
-===============
-R_LightPoint
-===============
-*/
-void R_LightPoint (vec3_t p, vec3_t color)
-{
-	vec3_t		end;
-	float		r;
-	int			lnum;
-	dlight_t	*dl;
-	vec3_t		dist;
-	float		add;
-	
-	if (!r_worldmodel->lightdata)
-	{
-		color[0] = color[1] = color[2] = 1.0;
-		return;
-	}
-	
-	end[0] = p[0];
-	end[1] = p[1];
-	end[2] = p[2] - 2048;
-	
-	r = RecursiveLightPoint (r_worldmodel->nodes, p, end);
-	
-	if (r == -1)
-	{
-		VectorCopy (vec3_origin, color);
-	}
-	else
-	{
-		VectorCopy (pointcolor, color);
-	}
-
-	//
-	// add dynamic lights
-	//
-	for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
-	{
-		dl = &r_newrefdef.dlights[lnum];
-		VectorSubtract (currententity->origin,
-						dl->origin,
-						dist);
-		add = dl->intensity - VectorLength(dist);
-		add *= (1.0/256);
-		if (add > 0)
-		{
-			VectorMA (color, add, dl->color, color);
-		}
-	}
-}
-
-//===================================================================
-
-
-unsigned		blocklights[1024];	// allow some very large lightmaps
-
-/*
-===============
-R_AddDynamicLights
-===============
-*/
-void R_AddDynamicLights (void)
-{
-	msurface_t *surf;
-	int			lnum;
-	int			sd, td;
-	float		dist, rad, minlight;
-	vec3_t		impact, local;
-	int			s, t;
-	int			i;
-	int			smax, tmax;
-	mtexinfo_t	*tex;
-	dlight_t	*dl;
-	int			negativeLight;	//PGM
-
-	surf = r_drawsurf.surf;
-	smax = (surf->extents[0]>>4)+1;
-	tmax = (surf->extents[1]>>4)+1;
-	tex = surf->texinfo;
-
-	for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
-	{
-		if ( !(surf->dlightbits & (1<<lnum) ) )
-			continue;		// not lit by this light
-
-		dl = &r_newrefdef.dlights[lnum];
-		rad = dl->intensity;
-
-//=====
-//PGM
-		negativeLight = 0;
-		if(rad < 0)
-		{
-			negativeLight = 1;
-			rad = -rad;
-		}
-//PGM
-//=====
-
-		dist = DotProduct (dl->origin, surf->plane->normal) -
-				surf->plane->dist;
-		rad -= fabs(dist);
-		minlight = 32;		// dl->minlight;
-		if (rad < minlight)
-			continue;
-		minlight = rad - minlight;
-
-		for (i=0 ; i<3 ; i++)
-		{
-			impact[i] = dl->origin[i] -
-					surf->plane->normal[i]*dist;
-		}
-
-		local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
-		local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
-
-		local[0] -= surf->texturemins[0];
-		local[1] -= surf->texturemins[1];
-		
-		for (t = 0 ; t<tmax ; t++)
-		{
-			td = local[1] - t*16;
-			if (td < 0)
-				td = -td;
-			for (s=0 ; s<smax ; s++)
-			{
-				sd = local[0] - s*16;
-				if (sd < 0)
-					sd = -sd;
-				if (sd > td)
-					dist = sd + (td>>1);
-				else
-					dist = td + (sd>>1);
-//====
-//PGM
-				if(!negativeLight)
-				{
-					if (dist < minlight)
-						blocklights[t*smax + s] += (rad - dist)*256;
-				}
-				else
-				{
-					if (dist < minlight)
-						blocklights[t*smax + s] -= (rad - dist)*256;
-					if(blocklights[t*smax + s] < minlight)
-						blocklights[t*smax + s] = minlight;
-				}
-//PGM
-//====
-			}
-		}
-	}
-}
-
-/*
-===============
-R_BuildLightMap
-
-Combine and scale multiple lightmaps into the 8.8 format in blocklights
-===============
-*/
-void R_BuildLightMap (void)
-{
-	int			smax, tmax;
-	int			t;
-	int			i, size;
-	byte		*lightmap;
-	unsigned	scale;
-	int			maps;
-	msurface_t	*surf;
-
-	surf = r_drawsurf.surf;
-
-	smax = (surf->extents[0]>>4)+1;
-	tmax = (surf->extents[1]>>4)+1;
-	size = smax*tmax;
-
-	if (r_fullbright->value || !r_worldmodel->lightdata)
-	{
-		for (i=0 ; i<size ; i++)
-			blocklights[i] = 0;
-		return;
-	}
-
-// clear to no light
-	for (i=0 ; i<size ; i++)
-		blocklights[i] = 0;
-
-
-// add all the lightmaps
-	lightmap = surf->samples;
-	if (lightmap)
-		for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
-			 maps++)
-		{
-			scale = r_drawsurf.lightadj[maps];	// 8.8 fraction		
-			for (i=0 ; i<size ; i++)
-				blocklights[i] += lightmap[i] * scale;
-			lightmap += size;	// skip to next lightmap
-		}
-
-// add all the dynamic lights
-	if (surf->dlightframe == r_framecount)
-		R_AddDynamicLights ();
-
-// bound, invert, and shift
-	for (i=0 ; i<size ; i++)
-	{
-		t = (int)blocklights[i];
-		if (t < 0)
-			t = 0;
-		t = (255*256 - t) >> (8 - VID_CBITS);
-
-		if (t < (1 << 6))
-			t = (1 << 6);
-
-		blocklights[i] = t;
-	}
-}
-
--- a/ref/r_local.h
+++ /dev/null
@@ -1,1017 +1,0 @@
-#define REF_VERSION     "SOFT 0.01"
-
-/* macro redefinitions
-// up / down
-#define PITCH   0
-
-// left / right
-#define YAW             1
-
-// fall over
-#define ROLL    2
-*/
-
-/*
-
-  skins will be outline flood filled and mip mapped
-  pics and sprites with alpha will be outline flood filled
-  pic won't be mip mapped
-
-  model skin
-  sprite frame
-  wall texture
-  pic
-
-*/
-
-typedef enum 
-{
-	it_skin,
-	it_sprite,
-	it_wall,
-	it_pic,
-	it_sky
-} imagetype_t;
-
-typedef struct image_s
-{
-	char    name[MAX_QPATH];        // game path, including extension
-	imagetype_t     type;
-	int             width, height;
-	qboolean        transparent;    // true if any 255 pixels in image
-	int             registration_sequence;  // 0 = free
-	byte		*pixels[4];				// mip levels
-} image_t;
-
-typedef enum
-{
-	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 !!!
-typedef struct
-{
-	vrect_t         vrect;                          // subwindow in video for refresh
-									// FIXME: not need vrect next field here?
-	vrect_t         aliasvrect;                     // scaled Alias version
-	int                     vrectright, vrectbottom;        // right & bottom screen coords
-	int                     aliasvrectright, aliasvrectbottom;      // scaled Alias versions
-	float           vrectrightedge;                 // rightmost right edge we care about,
-										//  for use in edge list
-	float           fvrectx, fvrecty;               // for floating-point compares
-	float           fvrectx_adj, 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, fvrectbottom_adj;
-										// right and bottom edges, for clamping
-	float           fvrectright;                    // rightmost edge, for Alias clamping
-	float           fvrectbottom;                   // bottommost edge, for Alias clamping
-	float           horizontalFieldOfView;  // at Z = 1.0, this many X is visible 
-										// 2.0 = 90 degrees
-	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;
-} oldrefdef_t;
-
-extern oldrefdef_t      r_refdef;
-
-/* r_model.h */
-
-/*
-d*_t structures are on-disk representations
-m*_t structures are in-memory
-*/
-
-
-/*
-==============================================================================
-
-BRUSH MODELS
-
-==============================================================================
-*/
-
-
-//
-// in memory representation
-//
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct
-{
-	vec3_t		position;
-} mvertex_t;
-
-#define	SIDE_FRONT	0
-#define	SIDE_BACK	1
-#define	SIDE_ON		2
-
-
-// plane_t structure
-// !!! if this is changed, it must be changed in asm_i386.h too !!!
-typedef struct mplane_s
-{
-	vec3_t	normal;
-	float	dist;
-	byte	type;			// for texture axis selection and fast side tests
-	byte	signbits;		// signx + signy<<1 + signz<<1
-	byte	pad[2];
-} mplane_t;
-
-
-// FIXME: differentiate from texinfo SURF_ flags
-#define	SURF_PLANEBACK		2
-#define	SURF_DRAWSKY		4			// sky brush face
-#define SURF_DRAWTURB		0x10
-#define SURF_DRAWBACKGROUND	0x40
-#define SURF_DRAWSKYBOX		0x80		// sky box
-
-#define SURF_FLOW			0x100		//PGM
-
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct
-{
-	unsigned short	v[2];
-	unsigned int	cachededgeoffset;
-} medge_t;
-
-typedef struct mtexinfo_s
-{
-	float		vecs[2][4];
-	float		mipadjust;
-	image_t		*image;
-	int			flags;
-	int			numframes;
-	struct mtexinfo_s	*next;		// animation chain
-} mtexinfo_t;
-
-typedef struct msurface_s
-{
-	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
-	struct surfcache_s	*cachespots[MIPLEVELS];
-
-	short		texturemins[2];
-	short		extents[2];
-
-	mtexinfo_t	*texinfo;
-	
-// lighting info
-	byte		styles[MAXLIGHTMAPS];
-	byte		*samples;		// [numstyles*surfsize]
-
-	struct msurface_s *nextalphasurface;
-} msurface_t;
-
-
-#define	CONTENTS_NODE	-1
-typedef struct mnode_s
-{
-// 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
-
-	struct mnode_s	*parent;
-
-// node specific
-	mplane_t	*plane;
-	struct mnode_s	*children[2];	
-
-	unsigned short		firstsurface;
-	unsigned short		numsurfaces;
-} mnode_t;
-
-
-
-typedef struct mleaf_s
-{
-// 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
-
-	struct mnode_s	*parent;
-
-// leaf specific
-	int			cluster;
-	int			area;
-
-	msurface_t	**firstmarksurface;
-	int			nummarksurfaces;
-	int			key;			// BSP sequence number for leaf's contents
-} mleaf_t;
-
-
-//===================================================================
-
-//
-// Whole model
-//
-
-typedef enum {mod_bad, mod_brush, mod_sprite, mod_alias } modtype_t;
-
-typedef struct model_s
-{
-	char		name[MAX_QPATH];
-
-	int			registration_sequence;
-
-	modtype_t	type;
-	int			numframes;
-	
-	int			flags;
-
-//
-// volume occupied by the model graphics
-//		
-	vec3_t		mins, maxs;
-
-//
-// solid volume for clipping (sent from server)
-//
-	qboolean	clipbox;
-	vec3_t		clipmins, clipmaxs;
-
-//
-// brush model
-//
-	int			firstmodelsurface, 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;
-
-	byte		*lightdata;
-
-	// for alias models and sprites
-	image_t		*skins[MAX_MD2SKINS];
-	void		*extradata;
-	int			extradatasize;
-} model_t;
-
-//============================================================================
-
-void	Mod_Init (void);
-void	Mod_ClearAll (void);
-model_t *Mod_ForName (char *name, qboolean crash);
-void	*Mod_Extradata (model_t *mod);	// handles caching
-void	Mod_TouchModel (char *name);
-
-mleaf_t *Mod_PointInLeaf (float *p, model_t *model);
-byte	*Mod_ClusterPVS (int cluster, model_t *model);
-
-void Mod_Modellist_f (void);
-void Mod_FreeAll (void);
-void Mod_Free (model_t *mod);
-
-extern	int		registration_sequence;
-
-/* end r_model.h */
-
-
-#define CACHE_SIZE      32
-
-/*
-====================================================
-
-  CONSTANTS
-
-====================================================
-*/
-
-#define VID_CBITS       6
-#define VID_GRADES      (1 << VID_CBITS)
-
-
-// r_shared.h: general refresh-related stuff shared between the refresh and the
-// driver
-
-
-#define MAXVERTS        64              // max points in a surface polygon
-#define MAXWORKINGVERTS (MAXVERTS+4)    // max points in an intermediate
-										//  polygon (while processing)
-// !!! if this is changed, it must be changed in d_ifacea.h too !!!
-#define MAXHEIGHT       4096
-#define MAXWIDTH        4096
-
-#define INFINITE_DISTANCE       0x10000         // distance that's always guaranteed to
-										//  be farther away than anything in
-										//  the scene
-
-
-// d_iface.h: interface header file for rasterization driver modules
-
-#define WARP_WIDTH              320
-#define WARP_HEIGHT             240
-
-#define MAX_LBM_HEIGHT  480
-
-
-#define PARTICLE_Z_CLIP 8.0
-
-// !!! must be kept the same as in quakeasm.h !!!
-#define TRANSPARENT_COLOR       0xFF
-
-
-// !!! if this is changed, it must be changed in d_ifacea.h too !!!
-#define TURB_TEX_SIZE   64              // base turbulent texture size
-
-// !!! if this is changed, it must be changed in d_ifacea.h too !!!
-#define CYCLE                   128             // turbulent cycle size
-
-#define SCANBUFFERPAD           0x1000
-
-#define DS_SPAN_LIST_END        -128
-
-#define NUMSTACKEDGES           2000
-#define MINEDGES                        NUMSTACKEDGES
-#define NUMSTACKSURFACES        1000
-#define MINSURFACES                     NUMSTACKSURFACES
-#define MAXSPANS                        3000
-
-// flags in finalvert_t.flags
-#define ALIAS_LEFT_CLIP                         0x0001
-#define ALIAS_TOP_CLIP                          0x0002
-#define ALIAS_RIGHT_CLIP                        0x0004
-#define ALIAS_BOTTOM_CLIP                       0x0008
-#define ALIAS_Z_CLIP                            0x0010
-#define ALIAS_XY_CLIP_MASK                      0x000F
-
-#define SURFCACHE_SIZE_AT_320X240    1024*768
-
-#define BMODEL_FULLY_CLIPPED    0x10 // value returned by R_BmodelCheckBBox ()
-									 //  if bbox is trivially rejected
-
-#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
-
-
-#define MAXALIASVERTS           2000    // TODO: tune this
-#define ALIAS_Z_CLIP_PLANE      4
-
-// turbulence stuff
-
-#define AMP             8*0x10000
-#define AMP2    3
-#define SPEED   20
-
-
-/*
-====================================================
-
-TYPES
-
-====================================================
-*/
-
-typedef struct
-{
-	float   u, v;
-	float   s, t;
-	float   zi;
-} emitpoint_t;
-
-/*
-** if you change this structure be sure to change the #defines
-** listed after it!
-*/
-//#define SMALL_FINALVERT
-
-#ifdef SMALL_FINALVERT
-
-typedef struct finalvert_s {
-	short           u, v, s, t;
-	int             l;
-	int             zi;
-	int             flags;
-	float   xyz[3];         // eye space
-} finalvert_t;
-
-#define FINALVERT_V0     0
-#define FINALVERT_V1     2
-#define FINALVERT_V2     4
-#define FINALVERT_V3     6
-#define FINALVERT_V4     8
-#define FINALVERT_V5    12
-#define FINALVERT_FLAGS 16
-#define FINALVERT_X     20
-#define FINALVERT_Y     24
-#define FINALVERT_Z     28
-#define FINALVERT_SIZE  32
-
-#else
-
-typedef struct finalvert_s {
-	int             u, v, s, t;
-	int             l;
-	int             zi;
-	int             flags;
-	float   xyz[3];         // eye space
-} finalvert_t;
-
-#define FINALVERT_V0     0
-#define FINALVERT_V1     4
-#define FINALVERT_V2     8
-#define FINALVERT_V3    12
-#define FINALVERT_V4    16
-#define FINALVERT_V5    20
-#define FINALVERT_FLAGS 24
-#define FINALVERT_X     28
-#define FINALVERT_Y     32
-#define FINALVERT_Z     36
-#define FINALVERT_SIZE  40
-
-#endif
-
-typedef struct
-{
-	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;
-} affinetridesc_t;
-
-typedef struct
-{
-	byte            *surfdat;       // destination for generated surface
-	int                     rowbytes;       // destination logical width in bytes
-	msurface_t      *surf;          // description for surface to generate
-	fixed8_t        lightadj[MAXLIGHTMAPS];
-							// adjust for lightmap levels for dynamic lighting
-	image_t			*image;
-	int                     surfmip;        // mipmapped ratio of surface texels / world pixels
-	int                     surfwidth;      // in mipmapped texels
-	int                     surfheight;     // in mipmapped texels
-} drawsurf_t;
-
-
-
-typedef struct {
-	int                     ambientlight;
-	int                     shadelight;
-	float           *plightvec;
-} alight_t;
-
-// clipped bmodel edges
-
-typedef struct bedge_s
-{
-	mvertex_t               *v[2];
-	struct bedge_s  *pnext;
-} bedge_t;
-
-
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct clipplane_s
-{
-	vec3_t          normal;
-	float           dist;
-	struct          clipplane_s     *next;
-	byte            leftedge;
-	byte            rightedge;
-	byte            reserved[2];
-} clipplane_t;
-
-
-typedef struct surfcache_s
-{
-	struct surfcache_s      *next;
-	struct surfcache_s      **owner;                // NULL is an empty chunk of memory
-	int                                     lightadj[MAXLIGHTMAPS]; // checked for strobe flush
-	int                                     dlight;
-	int                                     size;           // including header
-	unsigned                        width;
-	unsigned                        height;         // DEBUG only needed for debug
-	float                           mipscale;
-	image_t							*image;
-	byte                            data[4];        // width*height elements
-} surfcache_t;
-
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct espan_s
-{
-	int                             u, v, count;
-	struct espan_s  *pnext;
-} espan_t;
-
-// used by the polygon drawer (R_POLY.C) and sprite setup code (R_SPRITE.C)
-typedef struct
-{
-	int                     nump;
-	emitpoint_t     *pverts;
-	byte            *pixels;                        // image
-	int                     pixel_width;            // image width
-	int         pixel_height;       // image height
-	vec3_t          vup, vright, vpn;       // in worldspace, for plane eq
-	float       dist;
-	float       s_offset, t_offset;
-	float       viewer_position[3];
-	void       (*drawspanlet)( void );
-	int         stipple_parity;
-} polydesc_t;
-
-// FIXME: compress, make a union if that will help
-// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte
-typedef struct surf_s
-{
-	struct surf_s   *next;                  // active surface stack in r_edge.c
-	struct surf_s   *prev;                  // used in r_edge.c for active surf stack
-	struct espan_s  *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, d_zistepu, d_zistepv;
-
-	int                     pad[2];                         // to 64 bytes
-} surf_t;
-
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct edge_s
-{
-	fixed16_t               u;
-	fixed16_t               u_step;
-	struct edge_s   *prev, *next;
-	unsigned short  surfs[2];
-	struct edge_s   *nextremove;
-	float                   nearzi;
-	medge_t                 *owner;
-} edge_t;
-
-
-/*
-====================================================
-
-VARS
-
-====================================================
-*/
-
-extern int              d_spanpixcount;
-extern int              r_framecount;           // sequence # of current frame since Quake
-									//  started
-extern float    r_aliasuvscale;         // scale-up factor for screen u and v
-									//  on Alias vertices passed to driver
-extern qboolean r_dowarp;
-
-extern affinetridesc_t  r_affinetridesc;
-
-extern vec3_t   r_pright, r_pup, r_ppn;
-
-void D_DrawSurfaces (void);
-void R_DrawParticle( void );
-void D_ViewChanged (void);
-void D_WarpScreen (void);
-void R_PolysetUpdateTables (void);
-
-extern void *acolormap; // FIXME: should go away
-
-//=======================================================================//
-
-// callbacks to Quake
-
-extern drawsurf_t       r_drawsurf;
-
-void R_DrawSurface (void);
-
-extern int              c_surf;
-
-extern byte             r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
-
-
-
-
-extern float    scale_for_mip;
-
-extern qboolean         d_roverwrapped;
-extern surfcache_t      *sc_rover;
-extern surfcache_t      *d_initial_rover;
-
-extern float    d_sdivzstepu, d_tdivzstepu, d_zistepu;
-extern float    d_sdivzstepv, d_tdivzstepv, d_zistepv;
-extern float    d_sdivzorigin, d_tdivzorigin, d_ziorigin;
-
-extern  fixed16_t       sadjust, tadjust;
-extern  fixed16_t       bbextents, bbextentt;
-
-
-void D_DrawSpans16 (espan_t *pspans);
-void D_DrawZSpans (espan_t *pspans);
-void Turbulent8 (espan_t *pspan);
-void NonTurbulent8 (espan_t *pspan);	//PGM
-
-surfcache_t     *D_CacheSurface (msurface_t *surface, int miplevel);
-
-extern int      d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
-
-extern int      d_pix_min, d_pix_max, d_pix_shift;
-
-extern pixel_t  *d_viewbuffer;
-extern short *d_pzbuffer;
-extern unsigned int d_zrowbytes, d_zwidth;
-extern short    *zspantable[MAXHEIGHT];
-extern int      d_scantable[MAXHEIGHT];
-
-extern int              d_minmip;
-extern float    d_scalemip[3];
-
-//===================================================================
-
-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];		// PGM
-
-extern  vec3_t  vup, base_vup;
-extern  vec3_t  vpn, base_vpn;
-extern  vec3_t  vright, base_vright;
-
-extern  surf_t  *surfaces, *surface_p, *surf_max;
-
-// 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 vec3_t   sxformaxis[4];  // s axis transformed into viewspace
-extern vec3_t   txformaxis[4];  // t axis transformed into viewspac
-
-extern  float   xcenter, ycenter;
-extern  float   xscale, yscale;
-extern  float   xscaleinv, yscaleinv;
-extern  float   xscaleshrink, yscaleshrink;
-
-extern void TransformVector (vec3_t in, vec3_t out);
-extern void SetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
-	fixed8_t endvertu, fixed8_t endvertv);
-
-extern int      ubasestep, errorterm, erroradjustup, erroradjustdown;
-
-//===========================================================================
-
-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
-
-extern  clipplane_t     view_clipplanes[4];
-extern int              *pfrustum_indexes[4];
-
-
-//=============================================================================
-
-void R_RenderWorld (void);
-
-//=============================================================================
-
-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, yOrigin;
-
-extern  int             r_visframecount;
-
-extern msurface_t *r_alpha_surfaces;
-
-//=============================================================================
-
-void R_ClearPolyList (void);
-void R_DrawPolyList (void);
-
-//
-// current entity info
-//
-extern  qboolean                insubmodel;
-
-void R_DrawAlphaSurfaces( void );
-
-void R_DrawSprite (void);
-void R_DrawBeam( entity_t *e );
-
-void R_RenderFace (msurface_t *fa, int clipflags);
-void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf);
-void R_TransformPlane (mplane_t *p, float *normal, float *dist);
-void R_TransformFrustum (void);
-void R_DrawSurfaceBlock16 (void);
-void R_DrawSurfaceBlock8 (void);
-
-void R_GenSkyTile (void *pdest);
-void R_GenSkyTile16 (void *pdest);
-void R_Surf8Patch (void);
-void R_Surf16Patch (void);
-void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode);
-void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode);
-
-void R_AddPolygonEdges (emitpoint_t *pverts, int numverts, int miplevel);
-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 *edgestoadd, edge_t *edgelist);
-void R_StepActiveU (edge_t *pedge);
-void R_RemoveEdges (edge_t *pedge);
-void R_PushDlights (model_t *model);
-
-extern void R_Surf8Start (void);
-extern void R_Surf8End (void);
-extern void R_Surf16Start (void);
-extern void R_Surf16End (void);
-extern void R_EdgeCodeStart (void);
-extern void R_EdgeCodeEnd (void);
-
-extern void R_RotateBmodel (void);
-
-extern int      c_faceclip;
-extern int      r_polycount;
-extern int      r_wholepolycount;
-
-extern int                      ubasestep, errorterm, erroradjustup, erroradjustdown;
-
-extern fixed16_t        sadjust, tadjust;
-extern fixed16_t        bbextents, bbextentt;
-
-extern mvertex_t        *r_ptverts, *r_ptvertsmax;
-
-extern float                    entity_rotation[3][3];
-
-extern int              r_currentkey;
-extern int              r_currentbkey;
-
-void    R_InitTurb (void);
-
-void R_DrawParticles (void);
-void R_SurfacePatch (void);
-
-extern int              r_amodels_drawn;
-extern edge_t   *auxedges;
-extern int              r_numallocatededges;
-extern edge_t   *r_edges, *edge_p, *edge_max;
-
-extern  edge_t  *newedges[MAXHEIGHT];
-extern  edge_t  *removeedges[MAXHEIGHT];
-
-// FIXME: make stack vars when debugging done
-extern  edge_t  edge_head;
-extern  edge_t  edge_tail;
-extern  edge_t  edge_aftertail;
-
-extern	int	r_aliasblendcolor;
-
-extern float    aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
-
-extern int              r_outofsurfaces;
-extern int              r_outofedges;
-
-extern mvertex_t        *r_pcurrentvertbase;
-extern int                      r_maxvalidedgeoffset;
-
-typedef struct
-{
-	finalvert_t *a, *b, *c;
-} aliastriangleparms_t;
-
-extern aliastriangleparms_t aliastriangleparms;
-
-void R_DrawTriangle( void );
-//void R_DrawTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2);
-void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2);
-
-
-extern float    r_time1;
-extern float	da_time1, da_time2;
-extern float	dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
-extern float	se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2;
-extern int              r_frustum_indexes[4*6];
-extern int              r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
-extern qboolean r_surfsonstack;
-
-extern	mleaf_t		*r_viewleaf;
-extern	int			r_viewcluster, 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;
-
-void R_PrintAliasStats (void);
-void R_PrintTimes (void);
-void R_PrintDSpeeds (void);
-void R_AnimateLight (void);
-void R_LightPoint (vec3_t p, vec3_t color);
-void R_SetupFrame (void);
-void R_cshift_f (void);
-void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1);
-void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip);
-void R_SplitEntityOnNode2 (mnode_t *node);
-
-extern  refdef_t        r_newrefdef;
-
-extern  surfcache_t     *sc_rover, *sc_base;
-
-extern  void            *colormap;
-
-//====================================================================
-
-float R_DLightPoint (vec3_t p);
-
-void R_NewMap (void);
-void R_Register (void);
-void R_UnRegister (void);
-void Draw_InitLocal (void);
-qboolean R_Init( void *hInstance, void *wndProc );
-void R_Shutdown (void);
-void R_InitCaches (void);
-void D_FlushCaches (void);
-
-void	R_ScreenShot_f( void );
-void    R_BeginRegistration (char *map);
-struct model_s  *R_RegisterModel (char *name);
-void    R_EndRegistration (void);
-
-void    R_RenderFrame (refdef_t *fd);
-
-struct image_s  *Draw_FindPic (char *name);
-
-void    Draw_GetPicSize (int *w, int *h, char *name);
-void    Draw_Pic (int x, int y, char *name);
-void    Draw_StretchPic (int x, int y, int w, int h, char *name);
-void    Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data);
-void    Draw_Char (int x, int y, int c);
-void    Draw_TileClear (int x, int y, int w, int h, char *name);
-void    Draw_Fill (int x, int y, int w, int h, int c);
-void    Draw_FadeScreen (void);
-
-void    Draw_GetPalette (void);
-
-void	 R_BeginFrame( float camera_separation );
-
-void	R_CinematicSetPalette( const unsigned char *palette );
-
-extern unsigned d_8to24table[256]; // base
-
-void    Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length);
-void    Sys_SetFPCW (void);
-
-void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height);
-
-void    R_InitImages (void);
-void	R_ShutdownImages (void);
-image_t *R_FindImage (char *name, imagetype_t type);
-void    R_FreeUnusedImages (void);
-
-void	R_GammaCorrectAndSetPalette( const unsigned char *pal );
-
-extern mtexinfo_t  *sky_texinfo[6];
-
-void R_InitSkyBox (void);
-
-typedef struct swstate_s
-{
-	qboolean fullscreen;
-	int      prev_mode;				// last valid SW mode
-
-	byte		gammatable[256];
-	byte		currentpalette[1024];
-
-} swstate_t;
-
-void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha );
-
-extern swstate_t sw_state;
-
-/*
-====================================================================
-
-IMPORTED FUNCTIONS
-
-====================================================================
-*/
-
-extern  refimport_t     ri;
-
-/*
-====================================================================
-
-IMPLEMENTATION FUNCTIONS
-
-====================================================================
-*/
-
-void		SWimp_BeginFrame( float camera_separation );
-void		SWimp_EndFrame (void);
-int			SWimp_Init( void *hInstance, void *wndProc );
-void		SWimp_SetPalette( const unsigned char *palette);
-void		SWimp_Shutdown( void );
-rserr_t		SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen );
-void		SWimp_AppActivate( qboolean active );
--- a/ref/r_main.c
+++ /dev/null
@@ -1,1355 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-viddef_t	vid;
-refimport_t	ri;
-
-unsigned	d_8to24table[256];
-
-entity_t	r_worldentity;
-
-char		skyname[MAX_QPATH];
-float		skyrotate;
-vec3_t		skyaxis;
-image_t		*sky_images[6];
-
-refdef_t	r_newrefdef;
-model_t		*currentmodel;
-
-model_t		*r_worldmodel;
-
-byte		r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
-
-swstate_t sw_state;
-
-void		*colormap;
-vec3_t		viewlightvec;
-alight_t	r_viewlighting = {128, 192, viewlightvec};
-float		r_time1;
-int			r_numallocatededges;
-float		r_aliasuvscale = 1.0;
-int			r_outofsurfaces;
-int			r_outofedges;
-
-qboolean	r_dowarp;
-
-mvertex_t	*r_pcurrentvertbase;
-
-int			c_surf;
-int			r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
-qboolean	r_surfsonstack;
-int			r_clipflags;
-
-//
-// view origin
-//
-vec3_t	vup, base_vup;
-vec3_t	vpn, base_vpn;
-vec3_t	vright, base_vright;
-vec3_t	r_origin;
-
-//
-// screen size info
-//
-oldrefdef_t	r_refdef;
-float		xcenter, ycenter;
-float		xscale, yscale;
-float		xscaleinv, yscaleinv;
-float		xscaleshrink, yscaleshrink;
-float		aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
-
-int		r_screenwidth;
-
-float	verticalFieldOfView;
-float	xOrigin, yOrigin;
-
-mplane_t	screenedge[4];
-
-//
-// refresh flags
-//
-int		r_framecount = 1;	// so frame counts initialized to 0 don't match
-int		r_visframecount;
-int		d_spanpixcount;
-int		r_polycount;
-int		r_drawnpolycount;
-int		r_wholepolycount;
-
-int			*pfrustum_indexes[4];
-int			r_frustum_indexes[4*6];
-
-mleaf_t		*r_viewleaf;
-int			r_viewcluster, r_oldviewcluster;
-
-image_t  	*r_notexture_mip;
-
-float	da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
-float	se_time1, se_time2, de_time1, de_time2;
-
-void R_MarkLeaves (void);
-
-cvar_t	*r_lefthand;
-cvar_t	*sw_aliasstats;
-cvar_t	*sw_allow_modex;
-cvar_t	*sw_clearcolor;
-cvar_t	*sw_drawflat;
-cvar_t	*sw_draworder;
-cvar_t	*sw_maxedges;
-cvar_t	*sw_maxsurfs;
-cvar_t  *sw_mode;
-cvar_t	*sw_reportedgeout;
-cvar_t	*sw_reportsurfout;
-cvar_t  *sw_stipplealpha;
-cvar_t	*sw_surfcacheoverride;
-cvar_t	*sw_waterwarp;
-
-cvar_t	*r_drawworld;
-cvar_t	*r_drawentities;
-cvar_t	*r_dspeeds;
-cvar_t	*r_fullbright;
-cvar_t  *r_lerpmodels;
-cvar_t  *r_novis;
-
-cvar_t	*r_speeds;
-cvar_t	*r_lightlevel;	//FIXME HACK
-
-cvar_t	*vid_fullscreen;
-cvar_t	*vid_gamma;
-
-//PGM
-cvar_t	*sw_lockpvs;
-//PGM
-
-#define	STRINGER(x) "x"
-
-
-// r_vars.c
-
-// all global and static refresh variables are collected in a contiguous block
-// to avoid cache conflicts.
-
-//-------------------------------------------------------
-// global refresh variables
-//-------------------------------------------------------
-
-// FIXME: make into one big structure, like cl or sv
-// FIXME: do separately for refresh engine and driver
-
-
-// d_vars.c
-
-// all global and static refresh variables are collected in a contiguous block
-// to avoid cache conflicts.
-
-//-------------------------------------------------------
-// global refresh variables
-//-------------------------------------------------------
-
-// FIXME: make into one big structure, like cl or sv
-// FIXME: do separately for refresh engine and driver
-
-float	d_sdivzstepu, d_tdivzstepu, d_zistepu;
-float	d_sdivzstepv, d_tdivzstepv, d_zistepv;
-float	d_sdivzorigin, d_tdivzorigin, d_ziorigin;
-
-fixed16_t	sadjust, tadjust, bbextents, bbextentt;
-
-pixel_t			*cacheblock;
-int				cachewidth;
-pixel_t			*d_viewbuffer;
-short			*d_pzbuffer;
-unsigned int	d_zrowbytes;
-unsigned int	d_zwidth;
-
-
-byte	r_notexture_buffer[1024];
-
-/*
-==================
-R_InitTextures
-==================
-*/
-void	R_InitTextures (void)
-{
-	int		x,y, m;
-	byte	*dest;
-	
-// create a simple checkerboard texture for the default
-	r_notexture_mip = (image_t *)r_notexture_buffer;
-	
-	r_notexture_mip->width = r_notexture_mip->height = 16;
-	r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)];
-	r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16;
-	r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8;
-	r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4;
-	
-	for (m=0 ; m<4 ; m++)
-	{
-		dest = r_notexture_mip->pixels[m];
-		for (y=0 ; y< (16>>m) ; y++)
-			for (x=0 ; x< (16>>m) ; x++)
-			{
-				if (  (y< (8>>m) ) ^ (x< (8>>m) ) )
-
-					*dest++ = 0;
-				else
-					*dest++ = 0xff;
-			}
-	}	
-}
-
-
-/*
-================
-R_InitTurb
-================
-*/
-void R_InitTurb (void)
-{
-	int		i;
-	
-	for (i=0 ; i<1280 ; i++)
-	{
-		sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
-		intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2;	// AMP2, not 20
-		blanktable[i] = 0;			//PGM
-	}
-}
-
-void R_ImageList_f( void );
-
-void R_Register (void)
-{
-	sw_aliasstats = Cvar_Get("sw_polymodelstats", "0", 0);
-	sw_allow_modex = Cvar_Get("sw_allow_modex", "1", CVAR_ARCHIVE);
-	sw_clearcolor = Cvar_Get("sw_clearcolor", "2", 0);
-	sw_drawflat = Cvar_Get("sw_drawflat", "0", 0);
-	sw_draworder = Cvar_Get("sw_draworder", "0", 0);
-	sw_maxedges = Cvar_Get("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0);
-	sw_maxsurfs = Cvar_Get("sw_maxsurfs", "0", 0);
-	sw_mipcap = Cvar_Get("sw_mipcap", "0", 0);
-	sw_mipscale = Cvar_Get("sw_mipscale", "1", 0);
-	sw_reportedgeout = Cvar_Get("sw_reportedgeout", "0", 0);
-	sw_reportsurfout = Cvar_Get("sw_reportsurfout", "0", 0);
-	sw_stipplealpha = Cvar_Get("sw_stipplealpha", "0", CVAR_ARCHIVE);
-	sw_surfcacheoverride = Cvar_Get("sw_surfcacheoverride", "0", 0);
-	sw_waterwarp = Cvar_Get ("sw_waterwarp", "1", 0);
-	sw_mode = Cvar_Get("sw_mode", "0", CVAR_ARCHIVE);
-
-	r_lefthand = Cvar_Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
-	r_speeds = Cvar_Get("r_speeds", "0", 0);
-	r_fullbright = Cvar_Get("r_fullbright", "0", 0);
-	r_drawentities = Cvar_Get("r_drawentities", "1", 0);
-	r_drawworld = Cvar_Get("r_drawworld", "1", 0);
-	r_dspeeds = Cvar_Get("r_dspeeds", "0", 0);
-	r_lightlevel = Cvar_Get("r_lightlevel", "0", 0);
-	r_lerpmodels = Cvar_Get("r_lerpmodels", "1", 0);
-	r_novis = Cvar_Get("r_novis", "0", 0);
-
-	vid_fullscreen = Cvar_Get("vid_fullscreen", "0", CVAR_ARCHIVE);
-	vid_gamma = Cvar_Get("vid_gamma", "1", CVAR_ARCHIVE);
-
-	Cmd_AddCommand("modellist", Mod_Modellist_f);
-	Cmd_AddCommand("screenshot", R_ScreenShot_f);
-	Cmd_AddCommand("imagelist", R_ImageList_f);
-
-	sw_mode->modified = true; // force us to do mode specific stuff later
-	vid_gamma->modified = true; // force us to rebuild the gamma table later
-
-//PGM
-	sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0);
-//PGM
-}
-
-void
-R_UnRegister(void)
-{
-	Cmd_RemoveCommand("screenshot");
-	Cmd_RemoveCommand("modellist");
-	Cmd_RemoveCommand("imagelist");
-}
-
-/*
-===============
-R_Init
-===============
-*/
-qboolean R_Init( void *hInstance, void *wndProc )
-{
-	R_InitImages ();
-	Mod_Init ();
-	Draw_InitLocal ();
-	R_InitTextures ();
-
-	R_InitTurb ();
-
-	view_clipplanes[0].leftedge = true;
-	view_clipplanes[1].rightedge = true;
-	view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
-			view_clipplanes[3].leftedge = false;
-	view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
-			view_clipplanes[3].rightedge = false;
-
-	r_refdef.xOrigin = XCENTERING;
-	r_refdef.yOrigin = YCENTERING;
-
-	r_aliasuvscale = 1.0;
-
-	R_Register ();
-	Draw_GetPalette ();
-	SWimp_Init( hInstance, wndProc );
-
-	// create the window
-	R_BeginFrame( 0 );
-
-	ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n");
-
-	return true;
-}
-
-void
-R_Shutdown(void)
-{
-	if(d_pzbuffer){
-		free(d_pzbuffer);
-		d_pzbuffer = nil;
-	}
-	if(sc_base){
-		D_FlushCaches();
-		free(sc_base);
-		sc_base = nil;
-	}
-	if(vid.colormap){
-		free(vid.colormap);
-		vid.colormap = nil;
-	}
-	R_UnRegister();
-	Mod_FreeAll();
-	R_ShutdownImages();
-
-	SWimp_Shutdown();
-}
-
-/*
-===============
-R_NewMap
-===============
-*/
-void R_NewMap (void)
-{
-	r_viewcluster = -1;
-
-	r_cnumsurfs = sw_maxsurfs->value;
-
-	if (r_cnumsurfs <= MINSURFACES)
-		r_cnumsurfs = MINSURFACES;
-
-	if (r_cnumsurfs > NUMSTACKSURFACES)
-	{
-		surfaces = malloc (r_cnumsurfs * sizeof(surf_t));
-		surface_p = surfaces;
-		surf_max = &surfaces[r_cnumsurfs];
-		r_surfsonstack = false;
-	// surface 0 doesn't really exist; it's just a dummy because index 0
-	// is used to indicate no edge attached to surface
-		surfaces--;
-		R_SurfacePatch ();
-	}
-	else
-	{
-		r_surfsonstack = true;
-	}
-
-	r_maxedgesseen = 0;
-	r_maxsurfsseen = 0;
-
-	r_numallocatededges = sw_maxedges->value;
-
-	if (r_numallocatededges < MINEDGES)
-		r_numallocatededges = MINEDGES;
-
-	if (r_numallocatededges <= NUMSTACKEDGES)
-	{
-		auxedges = NULL;
-	}
-	else
-	{
-		auxedges = malloc (r_numallocatededges * sizeof(edge_t));
-	}
-}
-
-
-/*
-===============
-R_MarkLeaves
-
-Mark the leaves and nodes that are in the PVS for the current
-cluster
-===============
-*/
-void R_MarkLeaves (void)
-{
-	byte	*vis;
-	mnode_t	*node;
-	int		i;
-	mleaf_t	*leaf;
-	int		cluster;
-
-	if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)
-		return;
-	
-	// development aid to let you run around and see exactly where
-	// the pvs ends
-	if (sw_lockpvs->value)
-		return;
-
-	r_visframecount++;
-	r_oldviewcluster = r_viewcluster;
-
-	if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)
-	{
-		// mark everything
-		for (i=0 ; i<r_worldmodel->numleafs ; i++)
-			r_worldmodel->leafs[i].visframe = r_visframecount;
-		for (i=0 ; i<r_worldmodel->numnodes ; i++)
-			r_worldmodel->nodes[i].visframe = r_visframecount;
-		return;
-	}
-
-	vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);
-	
-	for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)
-	{
-		cluster = leaf->cluster;
-		if (cluster == -1)
-			continue;
-		if (vis[cluster>>3] & (1<<(cluster&7)))
-		{
-			node = (mnode_t *)leaf;
-			do
-			{
-				if (node->visframe == r_visframecount)
-					break;
-				node->visframe = r_visframecount;
-				node = node->parent;
-			} while (node);
-		}
-	}
-
-/*
-	for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)
-	{
-		if (vis[i>>3] & (1<<(i&7)))
-		{
-			node = (mnode_t *)&r_worldmodel->leafs[i];	// FIXME: cluster
-			do
-			{
-				if (node->visframe == r_visframecount)
-					break;
-				node->visframe = r_visframecount;
-				node = node->parent;
-			} while (node);
-		}
-	}
-*/
-}
-
-/*
-** R_DrawNullModel
-**
-** IMPLEMENT THIS!
-*/
-void R_DrawNullModel( void )
-{
-}
-
-/*
-=============
-R_DrawEntitiesOnList
-=============
-*/
-void R_DrawEntitiesOnList (void)
-{
-	int			i;
-	qboolean	translucent_entities = false;
-
-	if (!r_drawentities->value)
-		return;
-
-	// all bmodels have already been drawn by the edge list
-	for (i=0 ; i<r_newrefdef.num_entities ; i++)
-	{
-		currententity = &r_newrefdef.entities[i];
-
-		if ( currententity->flags & RF_TRANSLUCENT )
-		{
-			translucent_entities = true;
-			continue;
-		}
-
-		if ( currententity->flags & RF_BEAM )
-		{
-			modelorg[0] = -r_origin[0];
-			modelorg[1] = -r_origin[1];
-			modelorg[2] = -r_origin[2];
-			VectorCopy( vec3_origin, r_entorigin );
-			R_DrawBeam( currententity );
-		}
-		else
-		{
-			currentmodel = currententity->model;
-			if (!currentmodel)
-			{
-				R_DrawNullModel();
-				continue;
-			}
-			VectorCopy (currententity->origin, r_entorigin);
-			VectorSubtract (r_origin, r_entorigin, modelorg);
-
-			switch (currentmodel->type)
-			{
-			case mod_sprite:
-				R_DrawSprite ();
-				break;
-
-			case mod_alias:
-				R_AliasDrawModel ();
-				break;
-
-			default:
-				break;
-			}
-		}
-	}
-
-	if ( !translucent_entities )
-		return;
-
-	for (i=0 ; i<r_newrefdef.num_entities ; i++)
-	{
-		currententity = &r_newrefdef.entities[i];
-
-		if ( !( currententity->flags & RF_TRANSLUCENT ) )
-			continue;
-
-		if ( currententity->flags & RF_BEAM )
-		{
-			modelorg[0] = -r_origin[0];
-			modelorg[1] = -r_origin[1];
-			modelorg[2] = -r_origin[2];
-			VectorCopy( vec3_origin, r_entorigin );
-			R_DrawBeam( currententity );
-		}
-		else
-		{
-			currentmodel = currententity->model;
-			if (!currentmodel)
-			{
-				R_DrawNullModel();
-				continue;
-			}
-			VectorCopy (currententity->origin, r_entorigin);
-			VectorSubtract (r_origin, r_entorigin, modelorg);
-
-			switch (currentmodel->type)
-			{
-			case mod_sprite:
-				R_DrawSprite ();
-				break;
-
-			case mod_alias:
-				R_AliasDrawModel ();
-				break;
-
-			default:
-				break;
-			}
-		}
-	}
-}
-
-
-/*
-=============
-R_BmodelCheckBBox
-=============
-*/
-int R_BmodelCheckBBox (float *minmaxs)
-{
-	int			i, *pindex, clipflags;
-	vec3_t		acceptpt, rejectpt;
-	float		d;
-
-	clipflags = 0;
-
-	for (i=0 ; i<4 ; i++)
-	{
-	// generate accept and reject points
-	// FIXME: do with fast look-ups or integer tests based on the sign bit
-	// of the floating point values
-
-		pindex = pfrustum_indexes[i];
-
-		rejectpt[0] = minmaxs[pindex[0]];
-		rejectpt[1] = minmaxs[pindex[1]];
-		rejectpt[2] = minmaxs[pindex[2]];
-		
-		d = DotProduct (rejectpt, view_clipplanes[i].normal);
-		d -= view_clipplanes[i].dist;
-
-		if (d <= 0)
-			return BMODEL_FULLY_CLIPPED;
-
-		acceptpt[0] = minmaxs[pindex[3+0]];
-		acceptpt[1] = minmaxs[pindex[3+1]];
-		acceptpt[2] = minmaxs[pindex[3+2]];
-
-		d = DotProduct (acceptpt, view_clipplanes[i].normal);
-		d -= view_clipplanes[i].dist;
-
-		if (d <= 0)
-			clipflags |= (1<<i);
-	}
-
-	return clipflags;
-}
-
-
-/*
-===================
-R_FindTopnode
-
-Find the first node that splits the given box
-===================
-*/
-mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
-{
-	mplane_t	*splitplane;
-	int			sides;
-	mnode_t *node;
-
-	node = r_worldmodel->nodes;
-
-	while (1)
-	{
-		if (node->visframe != r_visframecount)
-			return NULL;		// not visible at all
-		
-		if (node->contents != CONTENTS_NODE)
-		{
-			if (node->contents != CONTENTS_SOLID)
-				return	node; // we've reached a non-solid leaf, so it's
-							//  visible and not BSP clipped
-			return NULL;	// in solid, so not visible
-		}
-		
-		splitplane = node->plane;
-		sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane);
-		
-		if (sides == 3)
-			return node;	// this is the splitter
-		
-	// not split yet; recurse down the contacted side
-		if (sides & 1)
-			node = node->children[0];
-		else
-			node = node->children[1];
-	}
-}
-
-
-/*
-=============
-RotatedBBox
-
-Returns an axially aligned box that contains the input box at the given rotation
-=============
-*/
-void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs)
-{
-	vec3_t	tmp, v;
-	int		i, j;
-	vec3_t	forward, right, up;
-
-	if (!angles[0] && !angles[1] && !angles[2])
-	{
-		VectorCopy (mins, tmins);
-		VectorCopy (maxs, tmaxs);
-		return;
-	}
-
-	for (i=0 ; i<3 ; i++)
-	{
-		tmins[i] = 99999;
-		tmaxs[i] = -99999;
-	}
-
-	AngleVectors (angles, forward, right, up);
-
-	for ( i = 0; i < 8; i++ )
-	{
-		if ( i & 1 )
-			tmp[0] = mins[0];
-		else
-			tmp[0] = maxs[0];
-
-		if ( i & 2 )
-			tmp[1] = mins[1];
-		else
-			tmp[1] = maxs[1];
-
-		if ( i & 4 )
-			tmp[2] = mins[2];
-		else
-			tmp[2] = maxs[2];
-
-
-		VectorScale (forward, tmp[0], v);
-		VectorMA (v, -tmp[1], right, v);
-		VectorMA (v, tmp[2], up, v);
-
-		for (j=0 ; j<3 ; j++)
-		{
-			if (v[j] < tmins[j])
-				tmins[j] = v[j];
-			if (v[j] > tmaxs[j])
-				tmaxs[j] = v[j];
-		}
-	}
-}
-
-/*
-=============
-R_DrawBEntitiesOnList
-=============
-*/
-void R_DrawBEntitiesOnList (void)
-{
-	int			i, clipflags;
-	vec3_t		oldorigin;
-	vec3_t		mins, maxs;
-	float		minmaxs[6];
-	mnode_t		*topnode;
-
-	if (!r_drawentities->value)
-		return;
-
-	VectorCopy (modelorg, oldorigin);
-	insubmodel = true;
-	r_dlightframecount = r_framecount;
-
-	for (i=0 ; i<r_newrefdef.num_entities ; i++)
-	{
-		currententity = &r_newrefdef.entities[i];
-		currentmodel = currententity->model;
-		if (!currentmodel)
-			continue;
-		if (currentmodel->nummodelsurfaces == 0)
-			continue;	// clip brush only
-		if ( currententity->flags & RF_BEAM )
-			continue;
-		if (currentmodel->type != mod_brush)
-			continue;
-	// see if the bounding box lets us trivially reject, also sets
-	// trivial accept status
-		RotatedBBox (currentmodel->mins, currentmodel->maxs,
-			currententity->angles, mins, maxs);
-		VectorAdd (mins, currententity->origin, minmaxs);
-		VectorAdd (maxs, currententity->origin, (minmaxs+3));
-
-		clipflags = R_BmodelCheckBBox (minmaxs);
-		if (clipflags == BMODEL_FULLY_CLIPPED)
-			continue;	// off the edge of the screen
-
-		topnode = R_FindTopnode (minmaxs, minmaxs+3);
-		if (!topnode)
-			continue;	// no part in a visible leaf
-
-		VectorCopy (currententity->origin, r_entorigin);
-		VectorSubtract (r_origin, r_entorigin, modelorg);
-
-		r_pcurrentvertbase = currentmodel->vertexes;
-
-	// FIXME: stop transforming twice
-		R_RotateBmodel ();
-
-	// calculate dynamic lighting for bmodel
-		R_PushDlights (currentmodel);
-
-		if (topnode->contents == CONTENTS_NODE)
-		{
-		// not a leaf; has to be clipped to the world BSP
-			r_clipflags = clipflags;
-			R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode);
-		}
-		else
-		{
-		// falls entirely in one leaf, so we just put all the
-		// edges in the edge list and let 1/z sorting handle
-		// drawing order
-			R_DrawSubmodelPolygons (currentmodel, clipflags, topnode);
-		}
-
-	// put back world rotation and frustum clipping		
-	// FIXME: R_RotateBmodel should just work off base_vxx
-		VectorCopy (base_vpn, vpn);
-		VectorCopy (base_vup, vup);
-		VectorCopy (base_vright, vright);
-		VectorCopy (oldorigin, modelorg);
-		R_TransformFrustum ();
-	}
-
-	insubmodel = false;
-}
-
-
-/*
-================
-R_EdgeDrawing
-================
-*/
-void R_EdgeDrawing (void)
-{
-	edge_t	ledges[NUMSTACKEDGES +
-				((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
-	surf_t	lsurfs[NUMSTACKSURFACES +
-				((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
-
-	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
-		return;
-
-	if (auxedges)
-	{
-		r_edges = auxedges;
-	}
-	else
-	{
-		r_edges =  (edge_t *)
-				(((uintptr)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
-	}
-
-	if (r_surfsonstack)
-	{
-		surfaces =  (surf_t *)
-				(((uintptr)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
-		surf_max = &surfaces[r_cnumsurfs];
-	// surface 0 doesn't really exist; it's just a dummy because index 0
-	// is used to indicate no edge attached to surface
-		surfaces--;
-		R_SurfacePatch ();
-	}
-
-	R_BeginEdgeFrame ();
-
-	if (r_dspeeds->value)
-	{
-		rw_time1 = Sys_Milliseconds ();
-	}
-
-	R_RenderWorld ();
-
-	if (r_dspeeds->value)
-	{
-		rw_time2 = Sys_Milliseconds ();
-		db_time1 = rw_time2;
-	}
-
-	R_DrawBEntitiesOnList ();
-
-	if (r_dspeeds->value)
-	{
-		db_time2 = Sys_Milliseconds ();
-		se_time1 = db_time2;
-	}
-
-	R_ScanEdges ();
-}
-
-//=======================================================================
-
-
-/*
-=============
-R_CalcPalette
-
-=============
-*/
-void R_CalcPalette (void)
-{
-	static qboolean modified;
-	byte	palette[256][4], *in, *out;
-	int		i, j;
-	float	alpha, one_minus_alpha;
-	vec3_t	premult;
-	int		v;
-
-	alpha = r_newrefdef.blend[3];
-	if (alpha <= 0)
-	{
-		if (modified)
-		{	// set back to default
-			modified = false;
-			R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
-			return;
-		}
-		return;
-	}
-
-	modified = true;
-	if (alpha > 1)
-		alpha = 1;
-
-	premult[0] = r_newrefdef.blend[0]*alpha*255;
-	premult[1] = r_newrefdef.blend[1]*alpha*255;
-	premult[2] = r_newrefdef.blend[2]*alpha*255;
-
-	one_minus_alpha = (1.0 - alpha);
-
-	in = (byte *)d_8to24table;
-	out = palette[0];
-	for (i=0 ; i<256 ; i++, in+=4, out+=4)
-	{
-		for (j=0 ; j<3 ; j++)
-		{
-			v = premult[j] + one_minus_alpha * in[j];
-			if (v > 255)
-				v = 255;
-			out[j] = v;
-		}
-		out[3] = 255;
-	}
-
-	R_GammaCorrectAndSetPalette( ( const unsigned char * ) palette[0] );
-//	SWimp_SetPalette( palette[0] );
-}
-
-//=======================================================================
-
-void R_SetLightLevel (void)
-{
-	vec3_t		light;
-
-	if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity))
-	{
-		r_lightlevel->value = 150.0;
-		return;
-	}
-
-	// save off light value for server to look at (BIG HACK!)
-	R_LightPoint (r_newrefdef.vieworg, light);
-	r_lightlevel->value = 150.0 * light[0];
-}
-
-
-/*
-@@@@@@@@@@@@@@@@
-R_RenderFrame
-
-@@@@@@@@@@@@@@@@
-*/
-void R_RenderFrame (refdef_t *fd)
-{
-	r_newrefdef = *fd;
-
-	if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
-		ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel");
-
-	VectorCopy (fd->vieworg, r_refdef.vieworg);
-	VectorCopy (fd->viewangles, r_refdef.viewangles);
-
-	if (r_speeds->value || r_dspeeds->value)
-		r_time1 = Sys_Milliseconds ();
-
-	R_SetupFrame ();
-
-	R_MarkLeaves ();	// done here so we know if we're in water
-
-	R_PushDlights (r_worldmodel);
-
-	R_EdgeDrawing ();
-
-	if (r_dspeeds->value)
-	{
-		se_time2 = Sys_Milliseconds ();
-		de_time1 = se_time2;
-	}
-
-	R_DrawEntitiesOnList ();
-
-	if (r_dspeeds->value)
-	{
-		de_time2 = Sys_Milliseconds ();
-		dp_time1 = Sys_Milliseconds ();
-	}
-
-	R_DrawParticles ();
-
-	if (r_dspeeds->value)
-		dp_time2 = Sys_Milliseconds ();
-
-	R_DrawAlphaSurfaces();
-
-	R_SetLightLevel ();
-
-	if (r_dowarp)
-		D_WarpScreen ();
-
-	if (r_dspeeds->value)
-		da_time1 = Sys_Milliseconds ();
-
-	if (r_dspeeds->value)
-		da_time2 = Sys_Milliseconds ();
-
-	R_CalcPalette ();
-
-	if (sw_aliasstats->value)
-		R_PrintAliasStats ();
-		
-	if (r_speeds->value)
-		R_PrintTimes ();
-
-	if (r_dspeeds->value)
-		R_PrintDSpeeds ();
-
-	if (sw_reportsurfout->value && r_outofsurfaces)
-		ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces);
-
-	if (sw_reportedgeout->value && r_outofedges)
-		ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3);
-}
-
-/*
-** R_InitGraphics
-*/
-void R_InitGraphics( int width, int height )
-{
-	vid.width  = width;
-	vid.height = height;
-
-	// free z buffer
-	if ( d_pzbuffer )
-	{
-		free( d_pzbuffer );
-		d_pzbuffer = NULL;
-	}
-
-	// free surface cache
-	if ( sc_base )
-	{
-		D_FlushCaches ();
-		free( sc_base );
-		sc_base = NULL;
-	}
-
-	d_pzbuffer = malloc(vid.width*vid.height*2);
-
-	R_InitCaches ();
-
-	R_GammaCorrectAndSetPalette( ( const unsigned char *) d_8to24table );
-}
-
-/*
-** R_BeginFrame
-*/
-void R_BeginFrame( float /*camera_separation*/ )
-{
-	extern void Draw_BuildGammaTable( void );
-
-	/*
-	** rebuild the gamma correction palette if necessary
-	*/
-	if ( vid_gamma->modified )
-	{
-		Draw_BuildGammaTable();
-		R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
-
-		vid_gamma->modified = false;
-	}
-
-	while ( sw_mode->modified || vid_fullscreen->modified )
-	{
-		rserr_t err;
-
-		/*
-		** if this returns rserr_invalid_fullscreen then it set the mode but not as a
-		** fullscreen mode, e.g. 320x200 on a system that doesn't support that res
-		*/
-		if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok )
-		{
-			R_InitGraphics( vid.width, vid.height );
-
-			sw_state.prev_mode = sw_mode->value;
-			vid_fullscreen->modified = false;
-			sw_mode->modified = false;
-		}
-		else
-		{
-			if ( err == rserr_invalid_mode )
-			{
-				ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode );
-				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" );
-			}
-			else if ( err == rserr_invalid_fullscreen )
-			{
-				R_InitGraphics( vid.width, vid.height );
-
-				ri.Cvar_SetValue( "vid_fullscreen", 0);
-				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" );
-				sw_state.prev_mode = sw_mode->value;
-//				vid_fullscreen->modified = false;
-//				sw_mode->modified = false;
-			}
-			else
-			{
-				ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" );
-			}
-		}
-	}
-}
-
-/*
-** R_GammaCorrectAndSetPalette
-*/
-void R_GammaCorrectAndSetPalette( const unsigned char *palette )
-{
-	int i;
-
-	for ( i = 0; i < 256; i++ )
-	{
-		sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]];
-		sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]];
-		sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]];
-	}
-
-	SWimp_SetPalette( sw_state.currentpalette );
-}
-
-/*
-** R_CinematicSetPalette
-*/
-void R_CinematicSetPalette( const unsigned char *palette )
-{
-	byte palette32[1024];
-	int		i, j, w;
-	int		*d;
-
-	// clear screen to black to avoid any palette flash
-	w = abs(vid.rowbytes)>>2;	// stupid negative pitch win32 stuff...
-	for (i=0 ; i<vid.height ; i++)
-	{
-		d = (int *)(vid.buffer + i*vid.rowbytes);
-		for (j=0 ; j<w ; j++)
-			d[j] = 0;
-	}
-	// flush it to the screen
-	SWimp_EndFrame ();
-
-	if ( palette )
-	{
-		for ( i = 0; i < 256; i++ )
-		{
-			palette32[i*4+0] = palette[i*3+0];
-			palette32[i*4+1] = palette[i*3+1];
-			palette32[i*4+2] = palette[i*3+2];
-			palette32[i*4+3] = 0xFF;
-		}
-
-		R_GammaCorrectAndSetPalette( palette32 );
-	}
-	else
-	{
-		R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
-	}
-}
-
-/*
-================
-Draw_BuildGammaTable
-================
-*/
-void Draw_BuildGammaTable (void)
-{
-	int		i, inf;
-	float	g;
-
-	g = vid_gamma->value;
-
-	if (g == 1.0)
-	{
-		for (i=0 ; i<256 ; i++)
-			sw_state.gammatable[i] = i;
-		return;
-	}
-	
-	for (i=0 ; i<256 ; i++)
-	{
-		inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
-		if (inf < 0)
-			inf = 0;
-		if (inf > 255)
-			inf = 255;
-		sw_state.gammatable[i] = inf;
-	}
-}
-
-/*
-** R_DrawBeam
-*/
-void R_DrawBeam( entity_t *e )
-{
-#define NUM_BEAM_SEGS 6
-
-	int	i;
-
-	vec3_t perpvec;
-	vec3_t direction, normalized_direction;
-	vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
-	vec3_t oldorigin, origin;
-
-	oldorigin[0] = e->oldorigin[0];
-	oldorigin[1] = e->oldorigin[1];
-	oldorigin[2] = e->oldorigin[2];
-
-	origin[0] = e->origin[0];
-	origin[1] = e->origin[1];
-	origin[2] = e->origin[2];
-
-	normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
-	normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
-	normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
-
-	if ( VectorNormalize( normalized_direction ) == 0 )
-		return;
-
-	PerpendicularVector( perpvec, normalized_direction );
-	VectorScale( perpvec, e->frame / 2, perpvec );
-
-	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
-	{
-		RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
-		VectorAdd( start_points[i], origin, start_points[i] );
-		VectorAdd( start_points[i], direction, end_points[i] );
-	}
-
-	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
-	{
-		R_IMFlatShadedQuad( start_points[i],
-		                    end_points[i],
-							end_points[(i+1)%NUM_BEAM_SEGS],
-							start_points[(i+1)%NUM_BEAM_SEGS],
-							e->skinnum & 0xFF,
-							e->alpha );
-	}
-}
-
-
-//===================================================================
-
-/*
-============
-R_SetSky
-============
-*/
-// 3dstudio environment map names
-char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
-int	r_skysideimage[6] = {5, 2, 4, 1, 0, 3};
-extern	mtexinfo_t		r_skytexinfo[6];
-void R_SetSky (char *name, float rotate, vec3_t axis)
-{
-	int		i;
-	char	pathname[MAX_QPATH];
-
-	strncpy (skyname, name, sizeof(skyname)-1);
-	skyrotate = rotate;
-	VectorCopy (axis, skyaxis);
-
-	for (i=0 ; i<6 ; i++)
-	{
-		Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]);
-		r_skytexinfo[i].image = R_FindImage (pathname, it_sky);
-	}
-}
-
-
-/*
-===============
-Draw_GetPalette
-===============
-*/
-void Draw_GetPalette (void)
-{
-	byte	*pal, *out;
-	int		i;
-	int		r, g, b;
-
-	// get the palette and colormap
-	LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL);
-	if (!vid.colormap)
-		ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
-	vid.alphamap = vid.colormap + 64*256;
-
-	out = (byte *)d_8to24table;
-	for (i=0 ; i<256 ; i++, out+=4)
-	{
-		r = pal[i*3+0];
-		g = pal[i*3+1];
-		b = pal[i*3+2];
-
-        out[0] = r;
-        out[1] = g;
-        out[2] = b;
-	}
-
-	free (pal);
-}
-
-struct image_s *R_RegisterSkin (char *name);
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-GetRefAPI
-
-@@@@@@@@@@@@@@@@@@@@@
-*/
-refexport_t GetRefAPI (refimport_t rimp)
-{
-	refexport_t	re;
-
-	ri = rimp;
-
-	re.api_version = API_VERSION;
-
-	re.BeginRegistration = R_BeginRegistration;
-    re.RegisterModel = R_RegisterModel;
-    re.RegisterSkin = R_RegisterSkin;
-	re.RegisterPic = Draw_FindPic;
-	re.SetSky = R_SetSky;
-	re.EndRegistration = R_EndRegistration;
-
-	re.RenderFrame = R_RenderFrame;
-
-	re.DrawGetPicSize = Draw_GetPicSize;
-	re.DrawPic = Draw_Pic;
-	re.DrawStretchPic = Draw_StretchPic;
-	re.DrawChar = Draw_Char;
-	re.DrawTileClear = Draw_TileClear;
-	re.DrawFill = Draw_Fill;
-	re.DrawFadeScreen= Draw_FadeScreen;
-
-	re.DrawStretchRaw = Draw_StretchRaw;
-
-	re.Init = R_Init;
-	re.Shutdown = R_Shutdown;
-
-	re.CinematicSetPalette = R_CinematicSetPalette;
-	re.BeginFrame = R_BeginFrame;
-	re.EndFrame = SWimp_EndFrame;
-
-	re.AppActivate = SWimp_AppActivate;
-
-	Swap_Init ();
-
-	return re;
-}
--- a/ref/r_misc.c
+++ /dev/null
@@ -1,566 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-#define NUM_MIPS	4
-
-cvar_t	*sw_mipcap;
-cvar_t	*sw_mipscale;
-
-surfcache_t		*d_initial_rover;
-qboolean		d_roverwrapped;
-int				d_minmip;
-float			d_scalemip[NUM_MIPS-1];
-
-static float	basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8};
-
-extern int			d_aflatcolor;
-
-int	d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
-
-int	d_pix_min, d_pix_max, d_pix_shift;
-
-int		d_scantable[MAXHEIGHT];
-short	*zspantable[MAXHEIGHT]; 
-
-/*
-================
-D_Patch
-================
-*/
-void D_Patch (void)
-{
-}
-/*
-================
-D_ViewChanged
-================
-*/
-unsigned char *alias_colormap;
-
-void D_ViewChanged (void)
-{
-	int		i;
-
-	scale_for_mip = xscale;
-	if (yscale > xscale)
-		scale_for_mip = yscale;
-
-	d_zrowbytes = vid.width * 2;
-	d_zwidth = vid.width;
-
-	d_pix_min = r_refdef.vrect.width / 320;
-	if (d_pix_min < 1)
-		d_pix_min = 1;
-
-	d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5);
-	d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5);
-	if (d_pix_max < 1)
-		d_pix_max = 1;
-
-	d_vrectx = r_refdef.vrect.x;
-	d_vrecty = r_refdef.vrect.y;
-	d_vrectright_particle = r_refdef.vrectright - d_pix_max;
-	d_vrectbottom_particle =
-			r_refdef.vrectbottom - d_pix_max;
-
-	for (i=0 ; i<vid.height; i++)
-	{
-		d_scantable[i] = i*r_screenwidth;
-		zspantable[i] = d_pzbuffer + i*d_zwidth;
-	}
-
-	/*
-	** clear Z-buffer and color-buffers if we're doing the gallery
-	*/
-	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
-	{
-		memset( d_pzbuffer, 0xff, vid.width * vid.height * sizeof( d_pzbuffer[0] ) );
-		Draw_Fill( r_newrefdef.x, r_newrefdef.y, r_newrefdef.width, r_newrefdef.height,( int ) sw_clearcolor->value & 0xff );
-	}
-
-	alias_colormap = vid.colormap;
-
-	D_Patch ();
-}
-
-
-
-/*
-=============
-R_PrintTimes
-=============
-*/
-void R_PrintTimes (void)
-{
-	int		r_time2;
-	int		ms;
-
-	r_time2 = Sys_Milliseconds ();
-
-	ms = r_time2 - r_time1;
-	
-	ri.Con_Printf (PRINT_ALL,"%5i ms %3i/%3i/%3i poly %3i surf\n",
-				ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf);
-	c_surf = 0;
-}
-
-
-/*
-=============
-R_PrintDSpeeds
-=============
-*/
-void R_PrintDSpeeds (void)
-{
-	int	ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, da_time;
-
-	r_time2 = Sys_Milliseconds ();
-
-	da_time = (da_time2 - da_time1);
-	dp_time = (dp_time2 - dp_time1);
-	rw_time = (rw_time2 - rw_time1);
-	db_time = (db_time2 - db_time1);
-	se_time = (se_time2 - se_time1);
-	de_time = (de_time2 - de_time1);
-	ms = (r_time2 - r_time1);
-
-	ri.Con_Printf (PRINT_ALL,"%3i %2ip %2iw %2ib %2is %2ie %2ia\n",
-				ms, dp_time, rw_time, db_time, se_time, de_time, da_time);
-}
-
-
-/*
-=============
-R_PrintAliasStats
-=============
-*/
-void R_PrintAliasStats (void)
-{
-	ri.Con_Printf (PRINT_ALL,"%3i polygon model drawn\n", r_amodels_drawn);
-}
-
-
-
-/*
-===================
-R_TransformFrustum
-===================
-*/
-void R_TransformFrustum (void)
-{
-	int		i;
-	vec3_t	v, v2;
-	
-	for (i=0 ; i<4 ; i++)
-	{
-		v[0] = screenedge[i].normal[2];
-		v[1] = -screenedge[i].normal[0];
-		v[2] = screenedge[i].normal[1];
-
-		v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0];
-		v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1];
-		v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2];
-
-		VectorCopy (v2, view_clipplanes[i].normal);
-
-		view_clipplanes[i].dist = DotProduct (modelorg, v2);
-	}
-}
-
-
-/*
-================
-TransformVector
-================
-*/
-void TransformVector (vec3_t in, vec3_t out)
-{
-	out[0] = DotProduct(in,vright);
-	out[1] = DotProduct(in,vup);
-	out[2] = DotProduct(in,vpn);		
-}
-
-
-/*
-================
-R_TransformPlane
-================
-*/
-void R_TransformPlane (mplane_t *p, float *normal, float *dist)
-{
-	float	d;
-	
-	d = DotProduct (r_origin, p->normal);
-	*dist = p->dist - d;
-// TODO: when we have rotating entities, this will need to use the view matrix
-	TransformVector (p->normal, normal);
-}
-
-
-/*
-===============
-R_SetUpFrustumIndexes
-===============
-*/
-void R_SetUpFrustumIndexes (void)
-{
-	int		i, j, *pindex;
-
-	pindex = r_frustum_indexes;
-
-	for (i=0 ; i<4 ; i++)
-	{
-		for (j=0 ; j<3 ; j++)
-		{
-			if (view_clipplanes[i].normal[j] < 0)
-			{
-				pindex[j] = j;
-				pindex[j+3] = j+3;
-			}
-			else
-			{
-				pindex[j] = j+3;
-				pindex[j+3] = j;
-			}
-		}
-
-	// FIXME: do just once at start
-		pfrustum_indexes[i] = pindex;
-		pindex += 6;
-	}
-}
-
-/*
-===============
-R_ViewChanged
-
-Called every time the vid structure or r_refdef changes.
-Guaranteed to be called before the first refresh
-===============
-*/
-void R_ViewChanged (vrect_t *vr)
-{
-	int		i;
-
-	r_refdef.vrect = *vr;
-
-	r_refdef.horizontalFieldOfView = 2*tan((float)r_newrefdef.fov_x/360*M_PI);;
-	verticalFieldOfView = 2*tan((float)r_newrefdef.fov_y/360*M_PI);
-
-	r_refdef.fvrectx = (float)r_refdef.vrect.x;
-	r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5;
-	r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1;
-	r_refdef.fvrecty = (float)r_refdef.vrect.y;
-	r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5;
-	r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width;
-	r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1;
-	r_refdef.fvrectright = (float)r_refdef.vrectright;
-	r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5;
-	r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99;
-	r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height;
-	r_refdef.fvrectbottom = (float)r_refdef.vrectbottom;
-	r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5;
-
-	r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale);
-	r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale);
-	r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale);
-	r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale);
-	r_refdef.aliasvrectright = r_refdef.aliasvrect.x +
-			r_refdef.aliasvrect.width;
-	r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y +
-			r_refdef.aliasvrect.height;
-
-	xOrigin = r_refdef.xOrigin;
-	yOrigin = r_refdef.yOrigin;
-	
-// values for perspective projection
-// if math were exact, the values would range from 0.5 to to range+0.5
-// hopefully they wll be in the 0.000001 to range+.999999 and truncate
-// the polygon rasterization will never render in the first row or column
-// but will definately render in the [range] row and column, so adjust the
-// buffer origin to get an exact edge to edge fill
-	xcenter = ((float)r_refdef.vrect.width * XCENTERING) +
-			r_refdef.vrect.x - 0.5;
-	aliasxcenter = xcenter * r_aliasuvscale;
-	ycenter = ((float)r_refdef.vrect.height * YCENTERING) +
-			r_refdef.vrect.y - 0.5;
-	aliasycenter = ycenter * r_aliasuvscale;
-
-	xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView;
-	aliasxscale = xscale * r_aliasuvscale;
-	xscaleinv = 1.0 / xscale;
-
-	yscale = xscale;
-	aliasyscale = yscale * r_aliasuvscale;
-	yscaleinv = 1.0 / yscale;
-	xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView;
-	yscaleshrink = xscaleshrink;
-
-// left side clip
-	screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView);
-	screenedge[0].normal[1] = 0;
-	screenedge[0].normal[2] = 1;
-	screenedge[0].type = PLANE_ANYZ;
-	
-// right side clip
-	screenedge[1].normal[0] =
-			1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView);
-	screenedge[1].normal[1] = 0;
-	screenedge[1].normal[2] = 1;
-	screenedge[1].type = PLANE_ANYZ;
-	
-// top side clip
-	screenedge[2].normal[0] = 0;
-	screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView);
-	screenedge[2].normal[2] = 1;
-	screenedge[2].type = PLANE_ANYZ;
-	
-// bottom side clip
-	screenedge[3].normal[0] = 0;
-	screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView);
-	screenedge[3].normal[2] = 1;	
-	screenedge[3].type = PLANE_ANYZ;
-	
-	for (i=0 ; i<4 ; i++)
-		VectorNormalize (screenedge[i].normal);
-
-	D_ViewChanged ();
-}
-
-
-/*
-===============
-R_SetupFrame
-===============
-*/
-void R_SetupFrame (void)
-{
-	int			i;
-	vrect_t		vrect;
-
-	if (r_fullbright->modified)
-	{
-		r_fullbright->modified = false;
-		D_FlushCaches ();	// so all lighting changes
-	}
-	
-	r_framecount++;
-
-
-// build the transformation matrix for the given view angles
-	VectorCopy (r_refdef.vieworg, modelorg);
-	VectorCopy (r_refdef.vieworg, r_origin);
-
-	AngleVectors (r_refdef.viewangles, vpn, vright, vup);
-
-// current viewleaf
-	if ( !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
-	{
-		r_viewleaf = Mod_PointInLeaf (r_origin, r_worldmodel);
-		r_viewcluster = r_viewleaf->cluster;
-	}
-
-	if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) )
-		r_dowarp = true;
-	else
-		r_dowarp = false;
-
-	if (r_dowarp)
-	{	// warp into off screen buffer
-		vrect.x = 0;
-		vrect.y = 0;
-		vrect.width = r_newrefdef.width < WARP_WIDTH ? r_newrefdef.width : WARP_WIDTH;
-		vrect.height = r_newrefdef.height < WARP_HEIGHT ? r_newrefdef.height : WARP_HEIGHT;
-
-		d_viewbuffer = r_warpbuffer;
-		r_screenwidth = WARP_WIDTH;
-	}
-	else
-	{
-		vrect.x = r_newrefdef.x;
-		vrect.y = r_newrefdef.y;
-		vrect.width = r_newrefdef.width;
-		vrect.height = r_newrefdef.height;
-
-		d_viewbuffer = (void *)vid.buffer;
-		r_screenwidth = vid.rowbytes;
-	}
-	
-	R_ViewChanged (&vrect);
-
-// start off with just the four screen edge clip planes
-	R_TransformFrustum ();
-	R_SetUpFrustumIndexes ();
-
-// save base values
-	VectorCopy (vpn, base_vpn);
-	VectorCopy (vright, base_vright);
-	VectorCopy (vup, base_vup);
-
-// clear frame counts
-	c_faceclip = 0;
-	d_spanpixcount = 0;
-	r_polycount = 0;
-	r_drawnpolycount = 0;
-	r_wholepolycount = 0;
-	r_amodels_drawn = 0;
-	r_outofsurfaces = 0;
-	r_outofedges = 0;
-
-// d_setup
-	d_roverwrapped = false;
-	d_initial_rover = sc_rover;
-
-	d_minmip = sw_mipcap->value;
-	if (d_minmip > 3)
-		d_minmip = 3;
-	else if (d_minmip < 0)
-		d_minmip = 0;
-
-	for (i=0 ; i<(NUM_MIPS-1) ; i++)
-		d_scalemip[i] = basemip[i] * sw_mipscale->value;
-
-	d_aflatcolor = 0;
-}
-
-
-/* 
-============================================================================== 
- 
-						SCREEN SHOTS 
- 
-============================================================================== 
-*/ 
-
-
-/* 
-============== 
-WritePCXfile 
-============== 
-*/ 
-void WritePCXfile (char *filename, byte *data, int width, int height,
-	int rowbytes, byte *palette) 
-{
-	int			i, j, length;
-	pcx_t		*pcx;
-	byte		*pack;
-	FILE		*f;
-
-	pcx = (pcx_t *)malloc (width*height*2+1000);
-	if (!pcx)
-		return;
-
-	pcx->manufacturer = 0x0a;	// PCX id
-	pcx->version = 5;			// 256 color
- 	pcx->encoding = 1;		// uncompressed
-	pcx->bits_per_pixel = 8;		// 256 color
-	pcx->xmin = 0;
-	pcx->ymin = 0;
-	pcx->xmax = LittleShort((short)(width-1));
-	pcx->ymax = LittleShort((short)(height-1));
-	pcx->hres = LittleShort((short)width);
-	pcx->vres = LittleShort((short)height);
-	memset (pcx->palette,0,sizeof(pcx->palette));
-	pcx->color_planes = 1;		// chunky image
-	pcx->bytes_per_line = LittleShort((short)width);
-	pcx->palette_type = LittleShort(2);		// not a grey scale
-	memset (pcx->filler,0,sizeof(pcx->filler));
-
-// pack the image
-	pack = &pcx->data;
-	
-	for (i=0 ; i<height ; i++)
-	{
-		for (j=0 ; j<width ; j++)
-		{
-			if ( (*data & 0xc0) != 0xc0)
-				*pack++ = *data++;
-			else
-			{
-				*pack++ = 0xc1;
-				*pack++ = *data++;
-			}
-		}
-
-		data += rowbytes - width;
-	}
-			
-// write the palette
-	*pack++ = 0x0c;	// palette ID byte
-	for (i=0 ; i<768 ; i++)
-		*pack++ = *palette++;
-		
-// write output file 
-	length = pack - (byte *)pcx;
-	f = fopen (filename, "wb");
-	if (!f)
-		ri.Con_Printf (PRINT_ALL, "Failed to open to %s\n", filename);
-	else
-	{
-		fwrite ((void *)pcx, 1, length, f);
-		fclose (f);
-	}
-
-	free (pcx);
-} 
- 
-
-
-/* 
-================== 
-R_ScreenShot_f
-================== 
-*/  
-void R_ScreenShot_f (void) 
-{ 
-	int			i; 
-	char		pcxname[80]; 
-	char		checkname[MAX_OSPATH];
-	FILE		*f;
-	byte		palette[768];
-
-	// create the scrnshots directory if it doesn't exist
-	Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
-	Sys_Mkdir (checkname);
-
-// 
-// find a file name to save it to 
-// 
-	strcpy(pcxname,"quake00.pcx");
-		
-	for (i=0 ; i<=99 ; i++) 
-	{ 
-		pcxname[5] = i/10 + '0'; 
-		pcxname[6] = i%10 + '0'; 
-		Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), pcxname);
-		f = fopen (checkname, "r");
-		if (!f)
-			break;	// file doesn't exist
-		fclose (f);
-	} 
-	if (i==100) 
-	{
-		ri.Con_Printf (PRINT_ALL, "R_ScreenShot_f: Couldn't create a PCX"); 
-		return;
-	}
-
-	// turn the current 32 bit palette into a 24 bit palette
-	for (i=0 ; i<256 ; i++)
-	{
-		palette[i*3+0] = sw_state.currentpalette[i*4+0];
-		palette[i*3+1] = sw_state.currentpalette[i*4+1];
-		palette[i*3+2] = sw_state.currentpalette[i*4+2];
-	}
-
-// 
-// save the pcx file 
-// 
-
-	WritePCXfile (checkname, vid.buffer, vid.width, vid.height, vid.rowbytes,
-				  palette);
-
-	ri.Con_Printf (PRINT_ALL, "Wrote %s\n", checkname);
-} 
-
--- a/ref/r_model.c
+++ /dev/null
@@ -1,1210 +1,0 @@
-// models.c -- model loading and caching
-
-// models are the only shared resource between a client and server running
-// on the same machine.
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-model_t	*loadmodel;
-char	loadname[32];	// for hunk tags
-
-void Mod_LoadSpriteModel (model_t *mod, void *buffer);
-void Mod_LoadBrushModel (model_t *mod, void *buffer);
-void Mod_LoadAliasModel (model_t *mod, void *buffer);
-model_t *Mod_LoadModel (model_t *mod, qboolean crash);
-
-byte	mod_novis[MAX_MAP_LEAFS/8];
-
-#define	MAX_MOD_KNOWN	256
-model_t	mod_known[MAX_MOD_KNOWN];
-int		mod_numknown;
-
-// the inline * models from the current map are kept seperate
-model_t	mod_inline[MAX_MOD_KNOWN];
-
-int		registration_sequence;
-int		modfilelen;
-
-//===============================================================================
-
-
-/*
-================
-Mod_Modellist_f
-================
-*/
-void Mod_Modellist_f (void)
-{
-	int		i;
-	model_t	*mod;
-	int		total;
-
-	total = 0;
-	ri.Con_Printf (PRINT_ALL,"Loaded models:\n");
-	for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
-	{
-		if (!mod->name[0])
-			continue;
-		ri.Con_Printf (PRINT_ALL, "%8i : %s\n",mod->extradatasize, mod->name);
-		total += mod->extradatasize;
-	}
-	ri.Con_Printf (PRINT_ALL, "Total resident: %i\n", total);
-}
-
-/*
-===============
-Mod_Init
-===============
-*/
-void Mod_Init (void)
-{
-	memset (mod_novis, 0xff, sizeof(mod_novis));
-}
-
-/*
-==================
-Mod_ForName
-
-Loads in a model for the given name
-==================
-*/
-model_t *Mod_ForName (char *name, qboolean crash)
-{
-	model_t	*mod;
-	unsigned *buf;
-	int		i;
-	
-	if (!name[0])
-		ri.Sys_Error (ERR_DROP,"Mod_ForName: NULL name");
-
-	//
-	// inline models are grabbed only from worldmodel
-	//
-	if (name[0] == '*')
-	{
-		i = atoi(name+1);
-		if (i < 1 || !r_worldmodel || i >= r_worldmodel->numsubmodels)
-			ri.Sys_Error (ERR_DROP, "bad inline model number");
-		return &mod_inline[i];
-	}
-
-	//
-	// search the currently loaded models
-	//
-	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
-		if (!strcmp (mod->name, name) )
-			return mod;
-			
-	//
-	// find a free model slot spot
-	//
-	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
-	{
-		if (!mod->name[0])
-			break;	// free spot
-	}
-	if (i == mod_numknown)
-	{
-		if (mod_numknown == MAX_MOD_KNOWN)
-			ri.Sys_Error (ERR_DROP, "mod_numknown == MAX_MOD_KNOWN");
-		mod_numknown++;
-	}
-	strcpy (mod->name, name);
-	
-	//
-	// load the file
-	//
-	modfilelen = ri.FS_LoadFile (mod->name, (void **)&buf);
-	if (!buf)
-	{
-		if (crash)
-			ri.Sys_Error (ERR_DROP,"Mod_NumForName: %s not found", mod->name);
-		memset (mod->name, 0, sizeof(mod->name));
-		return NULL;
-	}
-	
-	loadmodel = mod;
-
-	//
-	// fill it in
-	//
-
-	// call the apropriate loader
-	
-	switch (LittleLong(*(unsigned *)buf))
-	{
-	case IDALIASHEADER:
-		loadmodel->extradata = Hunk_Begin (0x200000);
-		Mod_LoadAliasModel (mod, buf);
-		break;
-		
-	case IDSPRITEHEADER:
-		loadmodel->extradata = Hunk_Begin (0x10000);
-		Mod_LoadSpriteModel (mod, buf);
-		break;
-	
-	case IDBSPHEADER:
-		loadmodel->extradata = Hunk_Begin (0x1000000);
-		Mod_LoadBrushModel (mod, buf);
-		break;
-
-	default:
-		ri.Sys_Error (ERR_DROP,"Mod_NumForName: unknown fileid for %s", mod->name);
-		break;
-	}
-
-	loadmodel->extradatasize = Hunk_End ();
-
-	ri.FS_FreeFile (buf);
-
-	return mod;
-}
-
-
-/*
-===============
-Mod_PointInLeaf
-===============
-*/
-mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
-{
-	mnode_t		*node;
-	float		d;
-	mplane_t	*plane;
-	
-	if (!model || !model->nodes)
-		ri.Sys_Error (ERR_DROP, "Mod_PointInLeaf: bad model");
-
-	node = model->nodes;
-	while (1)
-	{
-		if (node->contents != -1)
-			return (mleaf_t *)node;
-		plane = node->plane;
-		d = DotProduct (p,plane->normal) - plane->dist;
-		if (d > 0)
-			node = node->children[0];
-		else
-			node = node->children[1];
-	}
-}
-
-
-/*
-===================
-Mod_DecompressVis
-===================
-*/
-byte *Mod_DecompressVis (byte *in, model_t *model)
-{
-	static byte	decompressed[MAX_MAP_LEAFS/8];
-	int		c;
-	byte	*out;
-	int		row;
-
-	row = (model->vis->numclusters+7)>>3;	
-	out = decompressed;
-
-	/*
-	memcpy (out, in, row);
-	*/
-	if (!in)
-	{	// no vis info, so make all visible
-		while (row)
-		{
-			*out++ = 0xff;
-			row--;
-		}
-		return decompressed;		
-	}
-
-	do
-	{
-		if (*in)
-		{
-			*out++ = *in++;
-			continue;
-		}
-	
-		c = in[1];
-		in += 2;
-		while (c)
-		{
-			*out++ = 0;
-			c--;
-		}
-	} while (out - decompressed < row);
-	
-	return decompressed;
-}
-
-/*
-==============
-Mod_ClusterPVS
-==============
-*/
-byte *Mod_ClusterPVS (int cluster, model_t *model)
-{
-	if (cluster == -1 || !model->vis)
-		return mod_novis;
-	return Mod_DecompressVis ( (byte *)model->vis + model->vis->bitofs[cluster][DVIS_PVS],
-		model);
-}
-
-/*
-===============================================================================
-
-					BRUSHMODEL LOADING
-
-===============================================================================
-*/
-
-byte	*mod_base;
-
-
-/*
-=================
-Mod_LoadLighting
-
-Converts the 24 bit lighting down to 8 bit
-by taking the brightest component
-=================
-*/
-void Mod_LoadLighting (lump_t *l)
-{
-	int		i, size;
-	byte	*in;
-
-	if (!l->filelen)
-	{
-		loadmodel->lightdata = NULL;
-		return;
-	}
-	size = l->filelen/3;
-	loadmodel->lightdata = Hunk_Alloc (size);
-	in = (void *)(mod_base + l->fileofs);
-	for (i=0 ; i<size ; i++, in+=3)
-	{
-		if (in[0] > in[1] && in[0] > in[2])
-			loadmodel->lightdata[i] = in[0];
-		else if (in[1] > in[0] && in[1] > in[2])
-			loadmodel->lightdata[i] = in[1];
-		else
-			loadmodel->lightdata[i] = in[2];
-	}
-}
-
-
-int		r_leaftovis[MAX_MAP_LEAFS];
-int		r_vistoleaf[MAX_MAP_LEAFS];
-int		r_numvisleafs;
-
-void	R_NumberLeafs (mnode_t *node)
-{
-	mleaf_t	*leaf;
-	int		leafnum;
-
-	if (node->contents != -1)
-	{
-		leaf = (mleaf_t *)node;
-		leafnum = leaf - loadmodel->leafs;
-		if (leaf->contents & CONTENTS_SOLID)
-			return;
-		r_leaftovis[leafnum] = r_numvisleafs;
-		r_vistoleaf[r_numvisleafs] = leafnum;
-		r_numvisleafs++;
-		return;
-	}
-
-	R_NumberLeafs (node->children[0]);
-	R_NumberLeafs (node->children[1]);
-}
-
-
-/*
-=================
-Mod_LoadVisibility
-=================
-*/
-void Mod_LoadVisibility (lump_t *l)
-{
-	int		i;
-
-	if (!l->filelen)
-	{
-		loadmodel->vis = NULL;
-		return;
-	}
-	loadmodel->vis = Hunk_Alloc ( l->filelen);	
-	memcpy (loadmodel->vis, mod_base + l->fileofs, l->filelen);
-
-	loadmodel->vis->numclusters = LittleLong (loadmodel->vis->numclusters);
-	for (i=0 ; i<loadmodel->vis->numclusters ; i++)
-	{
-		loadmodel->vis->bitofs[i][0] = LittleLong (loadmodel->vis->bitofs[i][0]);
-		loadmodel->vis->bitofs[i][1] = LittleLong (loadmodel->vis->bitofs[i][1]);
-	}
-}
-
-
-/*
-=================
-Mod_LoadVertexes
-=================
-*/
-void Mod_LoadVertexes (lump_t *l)
-{
-	dvertex_t	*in;
-	mvertex_t	*out;
-	int			i, count;
-
-	in = (void *)(mod_base + l->fileofs);
-	if (l->filelen % sizeof(*in))
-		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-	count = l->filelen / sizeof(*in);
-	out = Hunk_Alloc ( (count+8)*sizeof(*out));		// extra for skybox
-
-	loadmodel->vertexes = out;
-	loadmodel->numvertexes = count;
-
-	for ( i=0 ; i<count ; i++, in++, out++)
-	{
-		out->position[0] = LittleFloat (in->point[0]);
-		out->position[1] = LittleFloat (in->point[1]);
-		out->position[2] = LittleFloat (in->point[2]);
-	}
-}
-
-/*
-=================
-Mod_LoadSubmodels
-=================
-*/
-void Mod_LoadSubmodels (lump_t *l)
-{
-	dmodel_t	*in;
-	dmodel_t	*out;
-	int			i, j, count;
-
-	in = (void *)(mod_base + l->fileofs);
-	if (l->filelen % sizeof(*in))
-		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-	count = l->filelen / sizeof(*in);
-	out = Hunk_Alloc ( count*sizeof(*out));	
-
-	loadmodel->submodels = out;
-	loadmodel->numsubmodels = count;
-
-	for ( i=0 ; i<count ; i++, in++, out++)
-	{
-		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);
-		out->firstface = LittleLong (in->firstface);
-		out->numfaces = LittleLong (in->numfaces);
-	}
-}
-
-/*
-=================
-Mod_LoadEdges
-=================
-*/
-void Mod_LoadEdges (lump_t *l)
-{
-	dedge_t *in;
-	medge_t *out;
-	int 	i, count;
-
-	in = (void *)(mod_base + l->fileofs);
-	if (l->filelen % sizeof(*in))
-		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-	count = l->filelen / sizeof(*in);
-	out = Hunk_Alloc ( (count + 13) * sizeof(*out));	// extra for skybox
-
-	loadmodel->edges = out;
-	loadmodel->numedges = count;
-
-	for ( i=0 ; i<count ; i++, in++, out++)
-	{
-		out->v[0] = (unsigned short)LittleShort(in->v[0]);
-		out->v[1] = (unsigned short)LittleShort(in->v[1]);
-	}
-}
-
-/*
-=================
-Mod_LoadTexinfo
-=================
-*/
-void Mod_LoadTexinfo (lump_t *l)
-{
-	texinfo_t *in;
-	mtexinfo_t *out, *step;
-	int 	i, j, count;
-	float	len1, len2;
-	char	name[MAX_QPATH];
-	int		next;
-
-	in = (void *)(mod_base + l->fileofs);
-	if (l->filelen % sizeof(*in))
-		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-	count = l->filelen / sizeof(*in);
-	out = Hunk_Alloc ( (count+6)*sizeof(*out));	// extra for skybox
-
-	loadmodel->texinfo = out;
-	loadmodel->numtexinfo = count;
-
-	for ( i=0 ; i<count ; i++, in++, out++)
-	{
-		for (j=0 ; j<8 ; j++)
-			out->vecs[0][j] = LittleFloat (in->vecs[0][j]);
-		len1 = VectorLength (out->vecs[0]);
-		len2 = VectorLength (out->vecs[1]);
-		len1 = (len1 + len2)/2;
-		if (len1 < 0.32)
-			out->mipadjust = 4;
-		else if (len1 < 0.49)
-			out->mipadjust = 3;
-		else if (len1 < 0.99)
-			out->mipadjust = 2;
-		else
-			out->mipadjust = 1;
-		/*
-		if (len1 + len2 < 0.001)
-			out->mipadjust = 1;		// don't crash
-		else
-			out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 );
-		*/
-
-		out->flags = LittleLong (in->flags);
-
-		next = LittleLong (in->nexttexinfo);
-		if (next > 0)
-			out->next = loadmodel->texinfo + next;
-
-		Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture);
-		out->image = R_FindImage (name, it_wall);
-		if (!out->image)
-		{
-			out->image = r_notexture_mip; // texture not found
-			out->flags = 0;
-		}
-	}
-
-	// count animation frames
-	for (i=0 ; i<count ; i++)
-	{
-		out = &loadmodel->texinfo[i];
-		out->numframes = 1;
-		for (step = out->next ; step && step != out ; step=step->next)
-			out->numframes++;
-	}
-}
-
-/*
-================
-CalcSurfaceExtents
-
-Fills in s->texturemins[] and s->extents[]
-================
-*/
-void CalcSurfaceExtents (msurface_t *s)
-{
-	float	mins[2], maxs[2], val;
-	int		i,j, e;
-	mvertex_t	*v;
-	mtexinfo_t	*tex;
-	int		bmins[2], bmaxs[2];
-
-	mins[0] = mins[1] = 999999;
-	maxs[0] = maxs[1] = -99999;
-
-	tex = s->texinfo;
-	
-	for (i=0 ; i<s->numedges ; i++)
-	{
-		e = loadmodel->surfedges[s->firstedge+i];
-		if (e >= 0)
-			v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
-		else
-			v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
-		
-		for (j=0 ; j<2 ; j++)
-		{
-			val = v->position[0] * tex->vecs[j][0] + 
-				v->position[1] * tex->vecs[j][1] +
-				v->position[2] * tex->vecs[j][2] +
-				tex->vecs[j][3];
-			if (val < mins[j])
-				mins[j] = val;
-			if (val > maxs[j])
-				maxs[j] = val;
-		}
-	}
-
-	for (i=0 ; i<2 ; i++)
-	{	
-		bmins[i] = floor(mins[i]/16);
-		bmaxs[i] = ceil(maxs[i]/16);
-
-		s->texturemins[i] = bmins[i] * 16;
-		s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
-		if (s->extents[i] < 16)
-			s->extents[i] = 16;	// take at least one cache block
-		if ( !(tex->flags & (SURF_WARP|SURF_SKY)) && s->extents[i] > 256)
-			ri.Sys_Error (ERR_DROP,"Bad surface extents");
-	}
-}
-
-
-/*
-=================
-Mod_LoadFaces
-=================
-*/
-void Mod_LoadFaces (lump_t *l)
-{
-	dface_t		*in;
-	msurface_t 	*out;
-	int			i, count, surfnum;
-	int			planenum, side;
-
-	in = (void *)(mod_base + l->fileofs);
-	if (l->filelen % sizeof(*in))
-		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-	count = l->filelen / sizeof(*in);
-	out = Hunk_Alloc ( (count+6)*sizeof(*out));	// extra for skybox
-
-	loadmodel->surfaces = out;
-	loadmodel->numsurfaces = count;
-
-	for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
-	{
-		out->firstedge = LittleLong(in->firstedge);
-		out->numedges = LittleShort(in->numedges);		
-		if (out->numedges < 3)
-			ri.Sys_Error (ERR_DROP,"Surface with %s edges", out->numedges);
-		out->flags = 0;
-
-		planenum = LittleShort(in->planenum);
-		side = LittleShort(in->side);
-		if (side)
-			out->flags |= SURF_PLANEBACK;			
-
-		out->plane = loadmodel->planes + planenum;
-
-		out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
-
-		CalcSurfaceExtents (out);
-				
-	// lighting info is converted from 24 bit on disk to 8 bit
-
-		for (i=0 ; i<MAXLIGHTMAPS ; i++)
-			out->styles[i] = in->styles[i];
-		i = LittleLong(in->lightofs);
-		if (i == -1)
-			out->samples = NULL;
-		else
-			out->samples = loadmodel->lightdata + i/3;
-		
-	// set the drawing flags flag
-		
-		if (!out->texinfo->image)
-			continue;
-		if (out->texinfo->flags & SURF_SKY)
-		{
-			out->flags |= SURF_DRAWSKY;
-			continue;
-		}
-		
-		if (out->texinfo->flags & SURF_WARP)
-		{
-			out->flags |= SURF_DRAWTURB;
-			for (i=0 ; i<2 ; i++)
-			{
-				out->extents[i] = 16384;
-				out->texturemins[i] = -8192;
-			}
-			continue;
-		}
-//==============
-//PGM
-		// this marks flowing surfaces as turbulent, but with the new
-		// SURF_FLOW flag.
-		if (out->texinfo->flags & SURF_FLOWING)
-		{
-			out->flags |= SURF_DRAWTURB | SURF_FLOW;
-			for (i=0 ; i<2 ; i++)
-			{
-				out->extents[i] = 16384;
-				out->texturemins[i] = -8192;
-			}
-			continue;
-		}
-//PGM
-//==============
-	}
-}
-
-
-/*
-=================
-Mod_SetParent
-=================
-*/
-void Mod_SetParent (mnode_t *node, mnode_t *parent)
-{
-	node->parent = parent;
-	if (node->contents != -1)
-		return;
-	Mod_SetParent (node->children[0], node);
-	Mod_SetParent (node->children[1], node);
-}
-
-/*
-=================
-Mod_LoadNodes
-=================
-*/
-void Mod_LoadNodes (lump_t *l)
-{
-	int			i, j, count, p;
-	dnode_t		*in;
-	mnode_t 	*out;
-
-	in = (void *)(mod_base + l->fileofs);
-	if (l->filelen % sizeof(*in))
-		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-	count = l->filelen / sizeof(*in);
-	out = Hunk_Alloc ( count*sizeof(*out));	
-
-	loadmodel->nodes = out;
-	loadmodel->numnodes = count;
-
-	for ( i=0 ; i<count ; i++, in++, out++)
-	{
-		for (j=0 ; j<3 ; j++)
-		{
-			out->minmaxs[j] = LittleShort (in->mins[j]);
-			out->minmaxs[3+j] = LittleShort (in->maxs[j]);
-		}
-	
-		p = LittleLong(in->planenum);
-		out->plane = loadmodel->planes + p;
-
-		out->firstsurface = LittleShort (in->firstface);
-		out->numsurfaces = LittleShort (in->numfaces);
-		out->contents = CONTENTS_NODE;	// differentiate from leafs
-		
-		for (j=0 ; j<2 ; j++)
-		{
-			p = LittleLong (in->children[j]);
-			if (p >= 0)
-				out->children[j] = loadmodel->nodes + p;
-			else
-				out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
-		}
-	}
-	
-	Mod_SetParent (loadmodel->nodes, NULL);	// sets nodes and leafs
-}
-
-/*
-=================
-Mod_LoadLeafs
-=================
-*/
-void Mod_LoadLeafs (lump_t *l)
-{
-	dleaf_t 	*in;
-	mleaf_t 	*out;
-	int			i, j, count;
-
-	in = (void *)(mod_base + l->fileofs);
-	if (l->filelen % sizeof(*in))
-		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-	count = l->filelen / sizeof(*in);
-	out = Hunk_Alloc ( count*sizeof(*out));
-
-	loadmodel->leafs = out;
-	loadmodel->numleafs = count;
-
-	for ( i=0 ; i<count ; i++, in++, out++)
-	{
-		for (j=0 ; j<3 ; j++)
-		{
-			out->minmaxs[j] = LittleShort (in->mins[j]);
-			out->minmaxs[3+j] = LittleShort (in->maxs[j]);
-		}
-
-		out->contents = LittleLong(in->contents);
-		out->cluster = LittleShort(in->cluster);
-		out->area = LittleShort(in->area);
-
-		out->firstmarksurface = loadmodel->marksurfaces +
-			LittleShort(in->firstleafface);
-		out->nummarksurfaces = LittleShort(in->numleaffaces);
-	}	
-}
-
-
-/*
-=================
-Mod_LoadMarksurfaces
-=================
-*/
-void Mod_LoadMarksurfaces (lump_t *l)
-{	
-	int		i, j, count;
-	short		*in;
-	msurface_t **out;
-	
-	in = (void *)(mod_base + l->fileofs);
-	if (l->filelen % sizeof(*in))
-		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-	count = l->filelen / sizeof(*in);
-	out = Hunk_Alloc ( count*sizeof(*out));	
-
-	loadmodel->marksurfaces = out;
-	loadmodel->nummarksurfaces = count;
-
-	for ( i=0 ; i<count ; i++)
-	{
-		j = LittleShort(in[i]);
-		if (j >= loadmodel->numsurfaces)
-			ri.Sys_Error (ERR_DROP,"Mod_ParseMarksurfaces: bad surface number");
-		out[i] = loadmodel->surfaces + j;
-	}
-}
-
-/*
-=================
-Mod_LoadSurfedges
-=================
-*/
-void Mod_LoadSurfedges (lump_t *l)
-{	
-	int		i, count;
-	int		*in, *out;
-	
-	in = (void *)(mod_base + l->fileofs);
-	if (l->filelen % sizeof(*in))
-		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-	count = l->filelen / sizeof(*in);
-	out = Hunk_Alloc ( (count+24)*sizeof(*out));	// extra for skybox
-
-	loadmodel->surfedges = out;
-	loadmodel->numsurfedges = count;
-
-	for ( i=0 ; i<count ; i++)
-		out[i] = LittleLong (in[i]);
-}
-
-/*
-=================
-Mod_LoadPlanes
-=================
-*/
-void Mod_LoadPlanes (lump_t *l)
-{
-	int			i, j;
-	mplane_t	*out;
-	dplane_t 	*in;
-	int			count;
-	int			bits;
-	
-	in = (void *)(mod_base + l->fileofs);
-	if (l->filelen % sizeof(*in))
-		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-	count = l->filelen / sizeof(*in);
-	out = Hunk_Alloc ( (count+6)*sizeof(*out));		// extra for skybox
-	
-	loadmodel->planes = out;
-	loadmodel->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;
-	}
-}
-
-
-/*
-=================
-Mod_LoadBrushModel
-=================
-*/
-void Mod_LoadBrushModel (model_t *mod, void *buffer)
-{
-	int			i;
-	dheader_t	*header;
-	dmodel_t 	*bm;
-	
-	loadmodel->type = mod_brush;
-	if (loadmodel != mod_known)
-		ri.Sys_Error (ERR_DROP, "Loaded a brush model after the world");
-	
-	header = (dheader_t *)buffer;
-
-	i = LittleLong (header->version);
-	if (i != BSPVERSION)
-		ri.Sys_Error (ERR_DROP,"Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
-
-// swap all the lumps
-	mod_base = (byte *)header;
-
-	for (i=0 ; i<sizeof(dheader_t)/sizeof(int) ; i++)
-		((int *)header)[i] = LittleLong ( ((int *)header)[i]);
-
-// load into heap
-	
-	Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
-	Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
-	Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
-	Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
-	Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
-	Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
-	Mod_LoadFaces (&header->lumps[LUMP_FACES]);
-	Mod_LoadMarksurfaces (&header->lumps[LUMP_LEAFFACES]);
-	Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
-	Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
-	Mod_LoadNodes (&header->lumps[LUMP_NODES]);
-	Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
-	r_numvisleafs = 0;
-	R_NumberLeafs (loadmodel->nodes);
-	
-//
-// set up the submodels
-//
-	for (i=0 ; i<mod->numsubmodels ; i++)
-	{
-		model_t	*starmod;
-
-		bm = &mod->submodels[i];
-		starmod = &mod_inline[i];
-
-		*starmod = *loadmodel;
-		
-		starmod->firstmodelsurface = bm->firstface;
-		starmod->nummodelsurfaces = bm->numfaces;
-		starmod->firstnode = bm->headnode;
-		if (starmod->firstnode >= loadmodel->numnodes)
-			ri.Sys_Error (ERR_DROP, "Inline model %i has bad firstnode", i);
-
-		VectorCopy (bm->maxs, starmod->maxs);
-		VectorCopy (bm->mins, starmod->mins);
-	
-		if (i == 0)
-			*loadmodel = *starmod;
-	}
-
-	R_InitSkyBox ();
-}
-
-/*
-==============================================================================
-
-ALIAS MODELS
-
-==============================================================================
-*/
-
-/*
-=================
-Mod_LoadAliasModel
-=================
-*/
-void Mod_LoadAliasModel (model_t *mod, void *buffer)
-{
-	int					i, j;
-	dmdl_t				*pinmodel, *pheader;
-	dstvert_t			*pinst, *poutst;
-	dtriangle_t			*pintri, *pouttri;
-	daliasframe_t		*pinframe, *poutframe;
-	int					*pincmd, *poutcmd;
-	int					version;
-
-	pinmodel = (dmdl_t *)buffer;
-
-	version = LittleLong (pinmodel->version);
-	if (version != ALIAS_VERSION)
-		ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
-				 mod->name, version, ALIAS_VERSION);
-
-	pheader = Hunk_Alloc (LittleLong(pinmodel->ofs_end));
-	
-	// byte swap the header fields and sanity check
-	for (i=0 ; i<sizeof(dmdl_t)/sizeof(int) ; i++)
-		((int *)pheader)[i] = LittleLong (((int *)buffer)[i]);
-
-	if (pheader->skinheight > MAX_LBM_HEIGHT)
-		ri.Sys_Error (ERR_DROP, "model %s has a skin taller than %d", mod->name,
-				   MAX_LBM_HEIGHT);
-
-	if (pheader->num_xyz <= 0)
-		ri.Sys_Error (ERR_DROP, "model %s has no vertices", mod->name);
-
-	if (pheader->num_xyz > MAX_VERTS)
-		ri.Sys_Error (ERR_DROP, "model %s has too many vertices", mod->name);
-
-	if (pheader->num_st <= 0)
-		ri.Sys_Error (ERR_DROP, "model %s has no st vertices", mod->name);
-
-	if (pheader->num_tris <= 0)
-		ri.Sys_Error (ERR_DROP, "model %s has no triangles", mod->name);
-
-	if (pheader->num_frames <= 0)
-		ri.Sys_Error (ERR_DROP, "model %s has no frames", mod->name);
-
-//
-// load base s and t vertices (not used in gl version)
-//
-	pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st);
-	poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st);
-
-	for (i=0 ; i<pheader->num_st ; i++)
-	{
-		poutst[i].s = LittleShort (pinst[i].s);
-		poutst[i].t = LittleShort (pinst[i].t);
-	}
-
-//
-// load triangle lists
-//
-	pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris);
-	pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris);
-
-	for (i=0 ; i<pheader->num_tris ; i++)
-	{
-		for (j=0 ; j<3 ; j++)
-		{
-			pouttri[i].index_xyz[j] = LittleShort (pintri[i].index_xyz[j]);
-			pouttri[i].index_st[j] = LittleShort (pintri[i].index_st[j]);
-		}
-	}
-
-//
-// load the frames
-//
-	for (i=0 ; i<pheader->num_frames ; i++)
-	{
-		pinframe = (daliasframe_t *) ((byte *)pinmodel 
-			+ pheader->ofs_frames + i * pheader->framesize);
-		poutframe = (daliasframe_t *) ((byte *)pheader 
-			+ pheader->ofs_frames + i * pheader->framesize);
-
-		memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name));
-		for (j=0 ; j<3 ; j++)
-		{
-			poutframe->scale[j] = LittleFloat (pinframe->scale[j]);
-			poutframe->translate[j] = LittleFloat (pinframe->translate[j]);
-		}
-		// verts are all 8 bit, so no swapping needed
-		memcpy (poutframe->verts, pinframe->verts, 
-			pheader->num_xyz*sizeof(dtrivertx_t));
-
-	}
-
-	mod->type = mod_alias;
-
-	//
-	// load the glcmds
-	//
-	pincmd = (int *) ((byte *)pinmodel + pheader->ofs_glcmds);
-	poutcmd = (int *) ((byte *)pheader + pheader->ofs_glcmds);
-	for (i=0 ; i<pheader->num_glcmds ; i++)
-		poutcmd[i] = LittleLong (pincmd[i]);
-
-
-	// register all skins
-	memcpy ((char *)pheader + pheader->ofs_skins, (char *)pinmodel + pheader->ofs_skins,
-		pheader->num_skins*MAX_SKINNAME);
-	for (i=0 ; i<pheader->num_skins ; i++)
-	{
-		mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
-	}
-}
-
-/*
-==============================================================================
-
-SPRITE MODELS
-
-==============================================================================
-*/
-
-/*
-=================
-Mod_LoadSpriteModel
-=================
-*/
-void Mod_LoadSpriteModel (model_t *mod, void *buffer)
-{
-	dsprite_t	*sprin, *sprout;
-	int			i;
-
-	sprin = (dsprite_t *)buffer;
-	sprout = Hunk_Alloc (modfilelen);
-
-	sprout->ident = LittleLong (sprin->ident);
-	sprout->version = LittleLong (sprin->version);
-	sprout->numframes = LittleLong (sprin->numframes);
-
-	if (sprout->version != SPRITE_VERSION)
-		ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
-				 mod->name, sprout->version, SPRITE_VERSION);
-
-	if (sprout->numframes > MAX_MD2SKINS)
-		ri.Sys_Error (ERR_DROP, "%s has too many frames (%i > %i)",
-				 mod->name, sprout->numframes, MAX_MD2SKINS);
-
-	// byte swap everything
-	for (i=0 ; i<sprout->numframes ; i++)
-	{
-		sprout->frames[i].width = LittleLong (sprin->frames[i].width);
-		sprout->frames[i].height = LittleLong (sprin->frames[i].height);
-		sprout->frames[i].origin_x = LittleLong (sprin->frames[i].origin_x);
-		sprout->frames[i].origin_y = LittleLong (sprin->frames[i].origin_y);
-		memcpy (sprout->frames[i].name, sprin->frames[i].name, MAX_SKINNAME);
-		mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite);
-	}
-
-	mod->type = mod_sprite;
-}
-
-//=============================================================================
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-R_BeginRegistration
-
-Specifies the model that will be used as the world
-@@@@@@@@@@@@@@@@@@@@@
-*/
-void R_BeginRegistration (char *model)
-{
-	char	fullname[MAX_QPATH];
-	cvar_t	*flushmap;
-
-	registration_sequence++;
-	r_oldviewcluster = -1;		// force markleafs
-	Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model);
-
-	D_FlushCaches ();
-	// explicitly free the old map if different
-	// this guarantees that mod_known[0] is the world map
-	flushmap = ri.Cvar_Get ("flushmap", "0", 0);
-	if ( strcmp(mod_known[0].name, fullname) || flushmap->value)
-		Mod_Free (&mod_known[0]);
-	r_worldmodel = R_RegisterModel (fullname);
-	R_NewMap ();
-}
-
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-R_RegisterModel
-
-@@@@@@@@@@@@@@@@@@@@@
-*/
-struct model_s *R_RegisterModel (char *name)
-{
-	model_t	*mod;
-	int		i;
-	dsprite_t	*sprout;
-	dmdl_t		*pheader;
-
-	mod = Mod_ForName (name, false);
-	if (mod)
-	{
-		mod->registration_sequence = registration_sequence;
-
-		// register any images used by the models
-		if (mod->type == mod_sprite)
-		{
-			sprout = (dsprite_t *)mod->extradata;
-			for (i=0 ; i<sprout->numframes ; i++)
-				mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite);
-		}
-		else if (mod->type == mod_alias)
-		{
-			pheader = (dmdl_t *)mod->extradata;
-			for (i=0 ; i<pheader->num_skins ; i++)
-				mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
-//PGM
-			mod->numframes = pheader->num_frames;
-//PGM
-		}
-		else if (mod->type == mod_brush)
-		{
-			for (i=0 ; i<mod->numtexinfo ; i++)
-				mod->texinfo[i].image->registration_sequence = registration_sequence;
-		}
-	}
-	return mod;
-}
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-R_EndRegistration
-
-@@@@@@@@@@@@@@@@@@@@@
-*/
-void R_EndRegistration (void)
-{
-	int		i;
-	model_t	*mod;
-
-	for (i=0, mod=mod_known ; i<mod_numknown ; i++, mod++)
-	{
-		if (!mod->name[0])
-			continue;
-		if (mod->registration_sequence != registration_sequence)
-		{	// don't need this model
-			Hunk_Free (mod->extradata);
-			memset (mod, 0, sizeof(*mod));
-		}
-		else
-		{	// make sure it is paged in
-			Com_PageInMemory (mod->extradata, mod->extradatasize);
-		}
-	}
-
-	R_FreeUnusedImages ();
-}
-
-void
-Mod_Free(model_t *mod)
-{
-	Hunk_Free(mod->extradata);
-	memset(mod, 0, sizeof *mod);
-}
-
-void
-Mod_FreeAll(void)
-{
-	int i;
-
-	for(i=0; i<mod_numknown; i++){
-		if(mod_known[i].extradatasize)
-			Mod_Free(&mod_known[i]);
-	}
-}
--- a/ref/r_part.c
+++ /dev/null
@@ -1,203 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-vec3_t r_pright, r_pup, r_ppn;
-
-#define PARTICLE_33     0
-#define PARTICLE_66     1
-#define PARTICLE_OPAQUE 2
-
-typedef struct
-{
-	particle_t *particle;
-	int         level;
-	int         color;
-} partparms_t;
-
-static partparms_t partparms;
-
-static byte BlendParticle33( int pcolor, int dstcolor )
-{
-	return vid.alphamap[pcolor + dstcolor*256];
-}
-
-static byte BlendParticle66( int pcolor, int dstcolor )
-{
-	return vid.alphamap[pcolor*256+dstcolor];
-}
-
-static byte BlendParticle100( int pcolor, int /*dstcolor*/ )
-{
-	return pcolor;
-}
-
-/*
-** R_DrawParticle
-**
-** Yes, this is amazingly slow, but it's the C reference
-** implementation and should be both robust and vaguely
-** understandable.  The only time this path should be
-** executed is if we're debugging on x86 or if we're
-** recompiling and deploying on a non-x86 platform.
-**
-** To minimize error and improve readability I went the 
-** function pointer route.  This exacts some overhead, but
-** it pays off in clean and easy to understand code.
-*/
-void R_DrawParticle( void )
-{
-	particle_t *pparticle = partparms.particle;
-	int         level     = partparms.level;
-	vec3_t	local, transformed;
-	float	zi;
-	byte	*pdest;
-	short	*pz;
-	int      color = pparticle->color;
-	int		i, izi, pix, count, u, v;
-
-	/*
-	** transform the particle
-	*/
-	VectorSubtract (pparticle->origin, r_origin, local);
-
-	transformed[0] = DotProduct(local, r_pright);
-	transformed[1] = DotProduct(local, r_pup);
-	transformed[2] = DotProduct(local, r_ppn);		
-
-	if (transformed[2] < PARTICLE_Z_CLIP)
-		return;
-
-	/*
-	** bind the blend function pointer to the appropriate blender
-	*/
-	/*
-	byte  (*blendparticle)( int, int );
-	if ( level == PARTICLE_33 )
-		blendparticle = BlendParticle33;
-	else if ( level == PARTICLE_66 )
-		blendparticle = BlendParticle66;
-	else 
-		blendparticle = BlendParticle100;
-	*/
-
-	/*
-	** project the point
-	*/
-	// FIXME: preadjust xcenter and ycenter
-	zi = 1.0 / transformed[2];
-	u = (int)(xcenter + zi * transformed[0] + 0.5);
-	v = (int)(ycenter - zi * transformed[1] + 0.5);
-
-	if ((v > d_vrectbottom_particle) || 
-		(u > d_vrectright_particle) ||
-		(v < d_vrecty) ||
-		(u < d_vrectx))
-	{
-		return;
-	}
-
-	/*
-	** compute addresses of zbuffer, framebuffer, and 
-	** compute the Z-buffer reference value.
-	*/
-	pz = d_pzbuffer + (d_zwidth * v) + u;
-	pdest = d_viewbuffer + d_scantable[v] + u;
-	izi = (int)(zi * 0x8000);
-
-	/*
-	** determine the screen area covered by the particle,
-	** which also means clamping to a min and max
-	*/
-	pix = izi >> d_pix_shift;
-	if (pix < d_pix_min)
-		pix = d_pix_min;
-	else if (pix > d_pix_max)
-		pix = d_pix_max;
-
-	/*
-	** render the appropriate pixels
-	*/
-	count = pix;
-
-    switch (level) {
-    case PARTICLE_33 :
-        for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
-        {
-//FIXME--do it in blocks of 8?
-            for (i=0 ; i<pix ; i++)
-            {
-                if (pz[i] <= izi)
-                {
-                    pz[i]    = izi;
-                    pdest[i] = vid.alphamap[color + ((int)pdest[i]<<8)];
-                }
-            }
-        }
-        break;
-
-    case PARTICLE_66 :
-        for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
-        {
-            for (i=0 ; i<pix ; i++)
-            {
-                if (pz[i] <= izi)
-                {
-                    pz[i]    = izi;
-                    pdest[i] = vid.alphamap[(color<<8) + (int)pdest[i]];
-                }
-            }
-        }
-        break;
-
-    default:  //100
-        for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
-        {
-            for (i=0 ; i<pix ; i++)
-            {
-                if (pz[i] <= izi)
-                {
-                    pz[i]    = izi;
-                    pdest[i] = color;
-                }
-            }
-        }
-        break;
-    }
-}
-
-/*
-** R_DrawParticles
-**
-** Responsible for drawing all of the particles in the particle list
-** throughout the world.  Doesn't care if we're using the C path or
-** if we're using the asm path, it simply assigns a function pointer
-** and goes.
-*/
-void R_DrawParticles (void)
-{
-	particle_t *p;
-	int         i;
-	extern unsigned long fpu_sp24_cw, fpu_chop_cw;
-
-	VectorScale( vright, xscaleshrink, r_pright );
-	VectorScale( vup, yscaleshrink, r_pup );
-	VectorCopy( vpn, r_ppn );
-
-	for (p=r_newrefdef.particles, i=0 ; i<r_newrefdef.num_particles ; i++,p++)
-	{
-
-		if ( p->alpha > 0.66 )
-			partparms.level = PARTICLE_OPAQUE;
-		else if ( p->alpha > 0.33 )
-			partparms.level = PARTICLE_66;
-		else
-			partparms.level = PARTICLE_33;
-
-		partparms.particle = p;
-		partparms.color    = p->color;
-
-		R_DrawParticle();
-	}
-}
--- a/ref/r_poly.c
+++ /dev/null
@@ -1,1225 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-#define AFFINE_SPANLET_SIZE      16
-#define AFFINE_SPANLET_SIZE_BITS 4
-
-typedef struct
-{
-	byte     *pbase, *pdest;
-	short	 *pz;
-	fixed16_t s, t;
-	fixed16_t sstep, tstep;
-	int       izi, izistep, izistep_times_2;
-	int       spancount;
-	unsigned  u, v;
-} spanletvars_t;
-
-spanletvars_t s_spanletvars;
-
-static int r_polyblendcolor;
-
-static espan_t	*s_polygon_spans;
-
-polydesc_t	r_polydesc;
-
-msurface_t *r_alpha_surfaces;
-
-extern int *r_turb_turb;
-
-static int		clip_current;
-vec5_t	r_clip_verts[2][MAXWORKINGVERTS+2];
-
-static int		s_minindex, s_maxindex;
-
-static void R_DrawPoly( qboolean iswater );
-
-/*
-** R_DrawSpanletOpaque
-*/
-void R_DrawSpanletOpaque( void )
-{
-	unsigned btemp;
-
-	do
-	{
-		unsigned ts, tt;
-
-		ts = s_spanletvars.s >> 16;
-		tt = s_spanletvars.t >> 16;
-
-		btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
-		if (btemp != 255)
-		{
-			if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
-			{
-				*s_spanletvars.pz    = s_spanletvars.izi >> 16;
-				*s_spanletvars.pdest = btemp;
-			}
-		}
-
-		s_spanletvars.izi += s_spanletvars.izistep;
-		s_spanletvars.pdest++;
-		s_spanletvars.pz++;
-		s_spanletvars.s += s_spanletvars.sstep;
-		s_spanletvars.t += s_spanletvars.tstep;
-	} while (--s_spanletvars.spancount > 0);
-}
-
-/*
-** R_DrawSpanletTurbulentStipple33
-*/
-void R_DrawSpanletTurbulentStipple33( void )
-{
-	unsigned btemp;
-	int	     sturb, tturb;
-	byte    *pdest = s_spanletvars.pdest;
-	short   *pz    = s_spanletvars.pz;
-	int      izi   = s_spanletvars.izi;
-	
-	if ( s_spanletvars.v & 1 )
-	{
-		s_spanletvars.pdest += s_spanletvars.spancount;
-		s_spanletvars.pz    += s_spanletvars.spancount;
-
-		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
-			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
-		else
-			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
-		
-		if ( s_spanletvars.u & 1 )
-		{
-			izi += s_spanletvars.izistep;
-			s_spanletvars.s   += s_spanletvars.sstep;
-			s_spanletvars.t   += s_spanletvars.tstep;
-
-			pdest++;
-			pz++;
-			s_spanletvars.spancount--;
-		}
-
-		s_spanletvars.sstep   *= 2;
-		s_spanletvars.tstep   *= 2;
-
-		while ( s_spanletvars.spancount > 0 )
-		{
-			sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
-			tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
-			
-			btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
-			
-			if ( *pz <= ( izi >> 16 ) )
-				*pdest = btemp;
-			
-			izi               += s_spanletvars.izistep_times_2;
-			s_spanletvars.s   += s_spanletvars.sstep;
-			s_spanletvars.t   += s_spanletvars.tstep;
-			
-			pdest += 2;
-			pz    += 2;
-			
-			s_spanletvars.spancount -= 2;
-		}
-	}
-}
-
-/*
-** R_DrawSpanletTurbulentStipple66
-*/
-void R_DrawSpanletTurbulentStipple66( void )
-{
-	unsigned btemp;
-	int	     sturb, tturb;
-	byte    *pdest = s_spanletvars.pdest;
-	short   *pz    = s_spanletvars.pz;
-	int      izi   = s_spanletvars.izi;
-	
-	if ( !( s_spanletvars.v & 1 ) )
-	{
-		s_spanletvars.pdest += s_spanletvars.spancount;
-		s_spanletvars.pz    += s_spanletvars.spancount;
-
-		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
-			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
-		else
-			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
-		
-		if ( s_spanletvars.u & 1 )
-		{
-			izi += s_spanletvars.izistep;
-			s_spanletvars.s   += s_spanletvars.sstep;
-			s_spanletvars.t   += s_spanletvars.tstep;
-
-			pdest++;
-			pz++;
-			s_spanletvars.spancount--;
-		}
-
-		s_spanletvars.sstep   *= 2;
-		s_spanletvars.tstep   *= 2;
-
-		while ( s_spanletvars.spancount > 0 )
-		{
-			sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
-			tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
-			
-			btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
-			
-			if ( *pz <= ( izi >> 16 ) )
-				*pdest = btemp;
-			
-			izi               += s_spanletvars.izistep_times_2;
-			s_spanletvars.s   += s_spanletvars.sstep;
-			s_spanletvars.t   += s_spanletvars.tstep;
-			
-			pdest += 2;
-			pz    += 2;
-			
-			s_spanletvars.spancount -= 2;
-		}
-	}
-	else
-	{
-		s_spanletvars.pdest += s_spanletvars.spancount;
-		s_spanletvars.pz    += s_spanletvars.spancount;
-
-		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
-			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
-		else
-			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
-		
-		while ( s_spanletvars.spancount > 0 )
-		{
-			sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
-			tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
-			
-			btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
-			
-			if ( *pz <= ( izi >> 16 ) )
-				*pdest = btemp;
-			
-			izi               += s_spanletvars.izistep;
-			s_spanletvars.s   += s_spanletvars.sstep;
-			s_spanletvars.t   += s_spanletvars.tstep;
-			
-			pdest++;
-			pz++;
-			
-			s_spanletvars.spancount--;
-		}
-	}
-}
-
-/*
-** R_DrawSpanletTurbulentBlended
-*/
-void R_DrawSpanletTurbulentBlended66( void )
-{
-	unsigned btemp;
-	int	     sturb, tturb;
-
-	do
-	{
-		sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
-		tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
-
-		btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
-
-		if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) )
-			*s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest];
-
-		s_spanletvars.izi += s_spanletvars.izistep;
-		s_spanletvars.pdest++;
-		s_spanletvars.pz++;
-		s_spanletvars.s += s_spanletvars.sstep;
-		s_spanletvars.t += s_spanletvars.tstep;
-
-	} while ( --s_spanletvars.spancount > 0 );
-}
-
-void R_DrawSpanletTurbulentBlended33( void )
-{
-	unsigned btemp;
-	int	     sturb, tturb;
-
-	do
-	{
-		sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
-		tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
-
-		btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
-
-		if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) )
-			*s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256];
-
-		s_spanletvars.izi += s_spanletvars.izistep;
-		s_spanletvars.pdest++;
-		s_spanletvars.pz++;
-		s_spanletvars.s += s_spanletvars.sstep;
-		s_spanletvars.t += s_spanletvars.tstep;
-
-	} while ( --s_spanletvars.spancount > 0 );
-}
-
-/*
-** R_DrawSpanlet33
-*/
-void R_DrawSpanlet33( void )
-{
-	unsigned btemp;
-
-	do
-	{
-		unsigned ts, tt;
-
-		ts = s_spanletvars.s >> 16;
-		tt = s_spanletvars.t >> 16;
-
-		btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
-
-		if ( btemp != 255 )
-		{
-			if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
-			{
-				*s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256];
-			}
-		}
-
-		s_spanletvars.izi += s_spanletvars.izistep;
-		s_spanletvars.pdest++;
-		s_spanletvars.pz++;
-		s_spanletvars.s += s_spanletvars.sstep;
-		s_spanletvars.t += s_spanletvars.tstep;
-	} while (--s_spanletvars.spancount > 0);
-}
-
-void R_DrawSpanletConstant33( void )
-{
-	do
-	{
-		if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
-		{
-			*s_spanletvars.pdest = vid.alphamap[r_polyblendcolor+*s_spanletvars.pdest*256];
-		}
-
-		s_spanletvars.izi += s_spanletvars.izistep;
-		s_spanletvars.pdest++;
-		s_spanletvars.pz++;
-	} while (--s_spanletvars.spancount > 0);
-}
-
-/*
-** R_DrawSpanlet66
-*/
-void R_DrawSpanlet66( void )
-{
-	unsigned btemp;
-
-	do
-	{
-		unsigned ts, tt;
-
-		ts = s_spanletvars.s >> 16;
-		tt = s_spanletvars.t >> 16;
-
-		btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
-
-		if ( btemp != 255 )
-		{
-			if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
-			{
-				*s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest];
-			}
-		}
-
-		s_spanletvars.izi += s_spanletvars.izistep;
-		s_spanletvars.pdest++;
-		s_spanletvars.pz++;
-		s_spanletvars.s += s_spanletvars.sstep;
-		s_spanletvars.t += s_spanletvars.tstep;
-	} while (--s_spanletvars.spancount > 0);
-}
-
-/*
-** R_DrawSpanlet33Stipple
-*/
-void R_DrawSpanlet33Stipple( void )
-{
-	unsigned btemp;
-	byte    *pdest = s_spanletvars.pdest;
-	short   *pz    = s_spanletvars.pz;
-	int      izi   = s_spanletvars.izi;
-	
-	if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) )
-	{
-		s_spanletvars.pdest += s_spanletvars.spancount;
-		s_spanletvars.pz    += s_spanletvars.spancount;
-
-		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
-			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
-		else
-			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
-		
-		if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) )
-		{
-			izi += s_spanletvars.izistep;
-			s_spanletvars.s   += s_spanletvars.sstep;
-			s_spanletvars.t   += s_spanletvars.tstep;
-
-			pdest++;
-			pz++;
-			s_spanletvars.spancount--;
-		}
-
-		s_spanletvars.sstep *= 2;
-		s_spanletvars.tstep *= 2;
-
-		while ( s_spanletvars.spancount > 0 )
-		{
-			unsigned s = s_spanletvars.s >> 16;
-			unsigned t = s_spanletvars.t >> 16;
-
-			btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
-			
-			if ( btemp != 255 )
-			{
-				if ( *pz <= ( izi >> 16 ) )
-					*pdest = btemp;
-			}
-			
-			izi               += s_spanletvars.izistep_times_2;
-			s_spanletvars.s   += s_spanletvars.sstep;
-			s_spanletvars.t   += s_spanletvars.tstep;
-			
-			pdest += 2;
-			pz    += 2;
-			
-			s_spanletvars.spancount -= 2;
-		}
-	}
-}
-
-/*
-** R_DrawSpanlet66Stipple
-*/
-void R_DrawSpanlet66Stipple( void )
-{
-	unsigned btemp;
-	byte    *pdest = s_spanletvars.pdest;
-	short   *pz    = s_spanletvars.pz;
-	int      izi   = s_spanletvars.izi;
-
-	s_spanletvars.pdest += s_spanletvars.spancount;
-	s_spanletvars.pz    += s_spanletvars.spancount;
-
-	if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
-		s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
-	else
-		s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
-
-	if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) )
-	{
-		if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) )
-		{
-			izi += s_spanletvars.izistep;
-			s_spanletvars.s += s_spanletvars.sstep;
-			s_spanletvars.t += s_spanletvars.tstep;
-
-			pdest++;
-			pz++;
-			s_spanletvars.spancount--;
-		}
-
-		s_spanletvars.sstep *= 2;
-		s_spanletvars.tstep *= 2;
-
-		while ( s_spanletvars.spancount > 0 )
-		{
-			unsigned s = s_spanletvars.s >> 16;
-			unsigned t = s_spanletvars.t >> 16;
-			
-			btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
-
-			if ( btemp != 255 )
-			{
-				if ( *pz <= ( izi >> 16 ) )
-					*pdest = btemp;
-			}
-			
-			izi             += s_spanletvars.izistep_times_2;
-			s_spanletvars.s += s_spanletvars.sstep;
-			s_spanletvars.t += s_spanletvars.tstep;
-			
-			pdest += 2;
-			pz    += 2;
-			
-			s_spanletvars.spancount -= 2;
-		}
-	}
-	else
-	{
-		while ( s_spanletvars.spancount > 0 )
-		{
-			unsigned s = s_spanletvars.s >> 16;
-			unsigned t = s_spanletvars.t >> 16;
-			
-			btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
-			
-			if ( btemp != 255 )
-			{
-				if ( *pz <= ( izi >> 16 ) )
-					*pdest = btemp;
-			}
-			
-			izi             += s_spanletvars.izistep;
-			s_spanletvars.s += s_spanletvars.sstep;
-			s_spanletvars.t += s_spanletvars.tstep;
-			
-			pdest++;
-			pz++;
-			
-			s_spanletvars.spancount--;
-		}
-	}
-}
-
-/*
-** R_ClipPolyFace
-**
-** Clips the winding at clip_verts[clip_current] and changes clip_current
-** Throws out the back side
-*/
-int R_ClipPolyFace (int nump, clipplane_t *pclipplane)
-{
-	int		i, outcount;
-	float	dists[MAXWORKINGVERTS+3];
-	float	frac, clipdist, *pclipnormal;
-	float	*in, *instep, *outstep, *vert2;
-
-	clipdist = pclipplane->dist;
-	pclipnormal = pclipplane->normal;
-	
-// calc dists
-	if (clip_current)
-	{
-		in = r_clip_verts[1][0];
-		outstep = r_clip_verts[0][0];
-		clip_current = 0;
-	}
-	else
-	{
-		in = r_clip_verts[0][0];
-		outstep = r_clip_verts[1][0];
-		clip_current = 1;
-	}
-	
-	instep = in;
-	for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
-	{
-		dists[i] = DotProduct (instep, pclipnormal) - clipdist;
-	}
-	
-// handle wraparound case
-	dists[nump] = dists[0];
-	memcpy (instep, in, sizeof (vec5_t));
-
-
-// clip the winding
-	instep = in;
-	outcount = 0;
-
-	for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
-	{
-		if (dists[i] >= 0)
-		{
-			memcpy (outstep, instep, sizeof (vec5_t));
-			outstep += sizeof (vec5_t) / sizeof (float);
-			outcount++;
-		}
-
-		if (dists[i] == 0 || dists[i+1] == 0)
-			continue;
-
-		if ( (dists[i] > 0) == (dists[i+1] > 0) )
-			continue;
-			
-	// split it into a new vertex
-		frac = dists[i] / (dists[i] - dists[i+1]);
-			
-		vert2 = instep + sizeof (vec5_t) / sizeof (float);
-		
-		outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
-		outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
-		outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
-		outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
-		outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
-
-		outstep += sizeof (vec5_t) / sizeof (float);
-		outcount++;
-	}	
-	
-	return outcount;
-}
-
-/*
-** R_PolygonDrawSpans
-*/
-void R_PolygonDrawSpans(espan_t *pspan, qboolean iswater )
-{
-	int			count;
-	fixed16_t	snext, tnext;
-	float		sdivz, tdivz, zi, z, du, dv, spancountminus1;
-	float		sdivzspanletstepu, tdivzspanletstepu, zispanletstepu;
-
-	s_spanletvars.pbase = cacheblock;
-
-	if ( iswater )
-		r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
-
-	sdivzspanletstepu = d_sdivzstepu * AFFINE_SPANLET_SIZE;
-	tdivzspanletstepu = d_tdivzstepu * AFFINE_SPANLET_SIZE;
-	zispanletstepu = d_zistepu * AFFINE_SPANLET_SIZE;
-
-// we count on FP exceptions being turned off to avoid range problems
-	s_spanletvars.izistep = (int)(d_zistepu * 0x8000 * 0x10000);
-	s_spanletvars.izistep_times_2 = s_spanletvars.izistep * 2;
-
-	s_spanletvars.pz = 0;
-
-	do
-	{
-		s_spanletvars.pdest   = (byte *)d_viewbuffer + ( d_scantable[pspan->v] /*r_screenwidth * pspan->v*/) + pspan->u;
-		s_spanletvars.pz      = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
-		s_spanletvars.u       = pspan->u;
-		s_spanletvars.v       = pspan->v;
-
-		count = pspan->count;
-
-		if (count <= 0)
-			goto NextSpan;
-
-	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
-		du = (float)pspan->u;
-		dv = (float)pspan->v;
-
-		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
-		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
-
-		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
-		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
-	// we count on FP exceptions being turned off to avoid range problems
-		s_spanletvars.izi = (int)(zi * 0x8000 * 0x10000);
-
-		s_spanletvars.s = (int)(sdivz * z) + sadjust;
-		s_spanletvars.t = (int)(tdivz * z) + tadjust;
-
-		if ( !iswater )
-		{
-			if (s_spanletvars.s > bbextents)
-				s_spanletvars.s = bbextents;
-			else if (s_spanletvars.s < 0)
-				s_spanletvars.s = 0;
-
-			if (s_spanletvars.t > bbextentt)
-				s_spanletvars.t = bbextentt;
-			else if (s_spanletvars.t < 0)
-				s_spanletvars.t = 0;
-		}
-
-		do
-		{
-		// calculate s and t at the far end of the span
-			if (count >= AFFINE_SPANLET_SIZE )
-				s_spanletvars.spancount = AFFINE_SPANLET_SIZE;
-			else
-				s_spanletvars.spancount = count;
-
-			count -= s_spanletvars.spancount;
-
-			if (count)
-			{
-			// calculate s/z, t/z, zi->fixed s and t at far end of span,
-			// calculate s and t steps across span by shifting
-				sdivz += sdivzspanletstepu;
-				tdivz += tdivzspanletstepu;
-				zi += zispanletstepu;
-				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
-
-				snext = (int)(sdivz * z) + sadjust;
-				tnext = (int)(tdivz * z) + tadjust;
-
-				if ( !iswater )
-				{
-					if (snext > bbextents)
-						snext = bbextents;
-					else if (snext < AFFINE_SPANLET_SIZE)
-						snext = AFFINE_SPANLET_SIZE;	// prevent round-off error on <0 steps from
-									//  from causing overstepping & running off the
-									//  edge of the texture
-
-					if (tnext > bbextentt)
-						tnext = bbextentt;
-					else if (tnext < AFFINE_SPANLET_SIZE)
-						tnext = AFFINE_SPANLET_SIZE;	// guard against round-off error on <0 steps
-				}
-
-				s_spanletvars.sstep = (snext - s_spanletvars.s) >> AFFINE_SPANLET_SIZE_BITS;
-				s_spanletvars.tstep = (tnext - s_spanletvars.t) >> AFFINE_SPANLET_SIZE_BITS;
-			}
-			else
-			{
-			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
-			// can't step off polygon), clamp, calculate s and t steps across
-			// span by division, biasing steps low so we don't run off the
-			// texture
-				spancountminus1 = (float)(s_spanletvars.spancount - 1);
-				sdivz += d_sdivzstepu * spancountminus1;
-				tdivz += d_tdivzstepu * spancountminus1;
-				zi += d_zistepu * spancountminus1;
-				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
-				snext = (int)(sdivz * z) + sadjust;
-				tnext = (int)(tdivz * z) + tadjust;
-
-				if ( !iswater )
-				{
-					if (snext > bbextents)
-						snext = bbextents;
-					else if (snext < AFFINE_SPANLET_SIZE)
-						snext = AFFINE_SPANLET_SIZE;	// prevent round-off error on <0 steps from
-									//  from causing overstepping & running off the
-									//  edge of the texture
-
-					if (tnext > bbextentt)
-						tnext = bbextentt;
-					else if (tnext < AFFINE_SPANLET_SIZE)
-						tnext = AFFINE_SPANLET_SIZE;	// guard against round-off error on <0 steps
-				}
-
-				if (s_spanletvars.spancount > 1)
-				{
-					s_spanletvars.sstep = (snext - s_spanletvars.s) / (s_spanletvars.spancount - 1);
-					s_spanletvars.tstep = (tnext - s_spanletvars.t) / (s_spanletvars.spancount - 1);
-				}
-			}
-
-			if ( iswater )
-			{
-				s_spanletvars.s = s_spanletvars.s & ((CYCLE<<16)-1);
-				s_spanletvars.t = s_spanletvars.t & ((CYCLE<<16)-1);
-			}
-
-			r_polydesc.drawspanlet();
-
-			s_spanletvars.s = snext;
-			s_spanletvars.t = tnext;
-
-		} while (count > 0);
-
-NextSpan:
-		pspan++;
-
-	} while (pspan->count != DS_SPAN_LIST_END);
-}
-
-/*
-**
-** R_PolygonScanLeftEdge
-**
-** Goes through the polygon and scans the left edge, filling in 
-** screen coordinate data for the spans
-*/
-void R_PolygonScanLeftEdge (void)
-{
-	int			i, v, itop, ibottom, lmaxindex;
-	emitpoint_t	*pvert, *pnext;
-	espan_t		*pspan;
-	float		du, dv, vtop, vbottom, slope;
-	fixed16_t	u, u_step;
-
-	pspan = s_polygon_spans;
-	i = s_minindex;
-	if (i == 0)
-		i = r_polydesc.nump;
-
-	lmaxindex = s_maxindex;
-	if (lmaxindex == 0)
-		lmaxindex = r_polydesc.nump;
-
-	vtop = ceil (r_polydesc.pverts[i].v);
-
-	do
-	{
-		pvert = &r_polydesc.pverts[i];
-		pnext = pvert - 1;
-
-		vbottom = ceil (pnext->v);
-
-		if (vtop < vbottom)
-		{
-			du = pnext->u - pvert->u;
-			dv = pnext->v - pvert->v;
-
-			slope = du / dv;
-			u_step = (int)(slope * 0x10000);
-		// adjust u to ceil the integer portion
-			u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
-					(0x10000 - 1);
-			itop = (int)vtop;
-			ibottom = (int)vbottom;
-
-			for (v=itop ; v<ibottom ; v++)
-			{
-				pspan->u = u >> 16;
-				pspan->v = v;
-				u += u_step;
-				pspan++;
-			}
-		}
-
-		vtop = vbottom;
-
-		i--;
-		if (i == 0)
-			i = r_polydesc.nump;
-
-	} while (i != lmaxindex);
-}
-
-/*
-** R_PolygonScanRightEdge
-**
-** Goes through the polygon and scans the right edge, filling in
-** count values.
-*/
-void R_PolygonScanRightEdge (void)
-{
-	int			i, v, itop, ibottom;
-	emitpoint_t	*pvert, *pnext;
-	espan_t		*pspan;
-	float		du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
-	fixed16_t	u, u_step;
-
-	pspan = s_polygon_spans;
-	i = s_minindex;
-
-	vvert = r_polydesc.pverts[i].v;
-	if (vvert < r_refdef.fvrecty_adj)
-		vvert = r_refdef.fvrecty_adj;
-	if (vvert > r_refdef.fvrectbottom_adj)
-		vvert = r_refdef.fvrectbottom_adj;
-
-	vtop = ceil (vvert);
-
-	do
-	{
-		pvert = &r_polydesc.pverts[i];
-		pnext = pvert + 1;
-
-		vnext = pnext->v;
-		if (vnext < r_refdef.fvrecty_adj)
-			vnext = r_refdef.fvrecty_adj;
-		if (vnext > r_refdef.fvrectbottom_adj)
-			vnext = r_refdef.fvrectbottom_adj;
-
-		vbottom = ceil (vnext);
-
-		if (vtop < vbottom)
-		{
-			uvert = pvert->u;
-			if (uvert < r_refdef.fvrectx_adj)
-				uvert = r_refdef.fvrectx_adj;
-			if (uvert > r_refdef.fvrectright_adj)
-				uvert = r_refdef.fvrectright_adj;
-
-			unext = pnext->u;
-			if (unext < r_refdef.fvrectx_adj)
-				unext = r_refdef.fvrectx_adj;
-			if (unext > r_refdef.fvrectright_adj)
-				unext = r_refdef.fvrectright_adj;
-
-			du = unext - uvert;
-			dv = vnext - vvert;
-			slope = du / dv;
-			u_step = (int)(slope * 0x10000);
-		// adjust u to ceil the integer portion
-			u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
-					(0x10000 - 1);
-			itop = (int)vtop;
-			ibottom = (int)vbottom;
-
-			for (v=itop ; v<ibottom ; v++)
-			{
-				pspan->count = (u >> 16) - pspan->u;
-				u += u_step;
-				pspan++;
-			}
-		}
-
-		vtop = vbottom;
-		vvert = vnext;
-
-		i++;
-		if (i == r_polydesc.nump)
-			i = 0;
-
-	} while (i != s_maxindex);
-
-	pspan->count = DS_SPAN_LIST_END;	// mark the end of the span list
-}
-
-/*
-** R_ClipAndDrawPoly
-*/
-void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured )
-{
-	emitpoint_t	outverts[MAXWORKINGVERTS+3], *pout;
-	float		*pv;
-	int			i, nump;
-	float		scale;
-	vec3_t		transformed, local;
-
-	if ( !textured )
-	{
-		r_polydesc.drawspanlet = R_DrawSpanletConstant33;
-	}
-	else
-	{
-
-		/*
-		** choose the correct spanlet routine based on alpha
-		*/
-		if ( alpha == 1 )
-		{
-			// isturbulent is ignored because we know that turbulent surfaces
-			// can't be opaque
-			r_polydesc.drawspanlet = R_DrawSpanletOpaque;
-		}
-		else
-		{
-			if ( sw_stipplealpha->value )
-			{
-				if ( isturbulent )
-				{
-					if ( alpha > 0.33 )
-						r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple66;
-					else 
-						r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple33;
-				}
-				else
-				{
-					if ( alpha > 0.33 )
-						r_polydesc.drawspanlet = R_DrawSpanlet66Stipple;
-					else 
-						r_polydesc.drawspanlet = R_DrawSpanlet33Stipple;
-				}
-			}
-			else
-			{
-				if ( isturbulent )
-				{
-					if ( alpha > 0.33 )
-						r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended66;
-					else
-						r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended33;
-				}
-				else
-				{
-					if ( alpha > 0.33 )
-						r_polydesc.drawspanlet = R_DrawSpanlet66;
-					else 
-						r_polydesc.drawspanlet = R_DrawSpanlet33;
-				}
-			}
-		}
-	}
-
-	// clip to the frustum in worldspace
-	nump = r_polydesc.nump;
-	clip_current = 0;
-
-	for (i=0 ; i<4 ; i++)
-	{
-		nump = R_ClipPolyFace (nump, &view_clipplanes[i]);
-		if (nump < 3)
-			return;
-		if (nump > MAXWORKINGVERTS)
-			ri.Sys_Error(ERR_DROP, "R_ClipAndDrawPoly: too many points: %d", nump );
-	}
-
-// transform vertices into viewspace and project
-	pv = &r_clip_verts[clip_current][0][0];
-
-	for (i=0 ; i<nump ; i++)
-	{
-		VectorSubtract (pv, r_origin, local);
-		TransformVector (local, transformed);
-
-		if (transformed[2] < NEAR_CLIP)
-			transformed[2] = NEAR_CLIP;
-
-		pout = &outverts[i];
-		pout->zi = 1.0 / transformed[2];
-
-		pout->s = pv[3];
-		pout->t = pv[4];
-		
-		scale = xscale * pout->zi;
-		pout->u = (xcenter + scale * transformed[0]);
-
-		scale = yscale * pout->zi;
-		pout->v = (ycenter - scale * transformed[1]);
-
-		pv += sizeof (vec5_t) / sizeof (*pv);
-	}
-
-// draw it
-	r_polydesc.nump = nump;
-	r_polydesc.pverts = outverts;
-
-	R_DrawPoly( isturbulent );
-}
-
-/*
-** R_BuildPolygonFromSurface
-*/
-void R_BuildPolygonFromSurface(msurface_t *fa)
-{
-	int			i, lindex, lnumverts;
-	medge_t		*pedges, *r_pedge;
-	float		*vec;
-	vec5_t     *pverts;
-	float       tmins[2] = { 0, 0 };
-
-	r_polydesc.nump = 0;
-
-	// reconstruct the polygon
-	pedges = currentmodel->edges;
-	lnumverts = fa->numedges;
-
-	pverts = r_clip_verts[0];
-
-	for (i=0 ; i<lnumverts ; i++)
-	{
-		lindex = currentmodel->surfedges[fa->firstedge + i];
-
-		if (lindex > 0)
-		{
-			r_pedge = &pedges[lindex];
-			vec = currentmodel->vertexes[r_pedge->v[0]].position;
-		}
-		else
-		{
-			r_pedge = &pedges[-lindex];
-			vec = currentmodel->vertexes[r_pedge->v[1]].position;
-		}
-
-		VectorCopy (vec, pverts[i] );
-	}
-
-	VectorCopy( fa->texinfo->vecs[0], r_polydesc.vright );
-	VectorCopy( fa->texinfo->vecs[1], r_polydesc.vup );
-	VectorCopy( fa->plane->normal, r_polydesc.vpn );
-	VectorCopy( r_origin, r_polydesc.viewer_position );
-
-	if ( fa->flags & SURF_PLANEBACK )
-	{
-		VectorSubtract( vec3_origin, r_polydesc.vpn, r_polydesc.vpn );
-	}
-
-	if ( fa->texinfo->flags & SURF_WARP )
-	{
-		r_polydesc.pixels       = fa->texinfo->image->pixels[0];
-		r_polydesc.pixel_width  = fa->texinfo->image->width;
-		r_polydesc.pixel_height = fa->texinfo->image->height;
-	}
-	else
-	{
-		surfcache_t *scache;
-
-		scache = D_CacheSurface( fa, 0 );
-
-		r_polydesc.pixels       = scache->data;
-		r_polydesc.pixel_width  = scache->width;
-		r_polydesc.pixel_height = scache->height;
-
-		tmins[0] = fa->texturemins[0];
-		tmins[1] = fa->texturemins[1];
-	}
-
-	r_polydesc.dist = DotProduct( r_polydesc.vpn, pverts[0] );
-
-	r_polydesc.s_offset = fa->texinfo->vecs[0][3] - tmins[0];
-	r_polydesc.t_offset = fa->texinfo->vecs[1][3] - tmins[1];
-
-	// scrolling texture addition
-	if (fa->texinfo->flags & SURF_FLOWING)
-	{
-		r_polydesc.s_offset += -128 * ( (r_newrefdef.time*0.25) - (int)(r_newrefdef.time*0.25) );
-	}
-
-	r_polydesc.nump = lnumverts;
-}
-
-/*
-** R_PolygonCalculateGradients
-*/
-void R_PolygonCalculateGradients (void)
-{
-	vec3_t		p_normal, p_saxis, p_taxis;
-	float		distinv;
-
-	TransformVector (r_polydesc.vpn, p_normal);
-	TransformVector (r_polydesc.vright, p_saxis);
-	TransformVector (r_polydesc.vup, p_taxis);
-
-	distinv = 1.0 / (-(DotProduct (r_polydesc.viewer_position, r_polydesc.vpn)) + r_polydesc.dist );
-
-	d_sdivzstepu  =  p_saxis[0] * xscaleinv;
-	d_sdivzstepv  = -p_saxis[1] * yscaleinv;
-	d_sdivzorigin =  p_saxis[2] - xcenter * d_sdivzstepu - ycenter * d_sdivzstepv;
-
-	d_tdivzstepu  =  p_taxis[0] * xscaleinv;
-	d_tdivzstepv  = -p_taxis[1] * yscaleinv;
-	d_tdivzorigin =  p_taxis[2] - xcenter * d_tdivzstepu - ycenter * d_tdivzstepv;
-
-	d_zistepu =   p_normal[0] * xscaleinv * distinv;
-	d_zistepv =  -p_normal[1] * yscaleinv * distinv;
-	d_ziorigin =  p_normal[2] * distinv - xcenter * d_zistepu - ycenter * d_zistepv;
-
-	sadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vright) + r_polydesc.s_offset ) * 0x10000 );
-	tadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vup   ) + r_polydesc.t_offset ) * 0x10000 );
-
-// -1 (-epsilon) so we never wander off the edge of the texture
-	bbextents = (r_polydesc.pixel_width << 16) - 1;
-	bbextentt = (r_polydesc.pixel_height << 16) - 1;
-}
-
-/*
-** R_DrawPoly
-**
-** Polygon drawing function.  Uses the polygon described in r_polydesc
-** to calculate edges and gradients, then renders the resultant spans.
-**
-** This should NOT be called externally since it doesn't do clipping!
-*/
-static void R_DrawPoly( qboolean iswater )
-{
-	int			i, nump;
-	float		ymin, ymax;
-	emitpoint_t	*pverts;
-	espan_t	spans[MAXHEIGHT+1];
-
-	s_polygon_spans = spans;
-
-// find the top and bottom vertices, and make sure there's at least one scan to
-// draw
-	ymin = 999999.9;
-	ymax = -999999.9;
-	pverts = r_polydesc.pverts;
-
-	for (i=0 ; i<r_polydesc.nump ; i++)
-	{
-		if (pverts->v < ymin)
-		{
-			ymin = pverts->v;
-			s_minindex = i;
-		}
-
-		if (pverts->v > ymax)
-		{
-			ymax = pverts->v;
-			s_maxindex = i;
-		}
-
-		pverts++;
-	}
-
-	ymin = ceil (ymin);
-	ymax = ceil (ymax);
-
-	if (ymin >= ymax)
-		return;		// doesn't cross any scans at all
-
-	cachewidth = r_polydesc.pixel_width;
-	cacheblock = r_polydesc.pixels;
-
-// copy the first vertex to the last vertex, so we don't have to deal with
-// wrapping
-	nump = r_polydesc.nump;
-	pverts = r_polydesc.pverts;
-	pverts[nump] = pverts[0];
-
-	R_PolygonCalculateGradients ();
-	R_PolygonScanLeftEdge ();
-	R_PolygonScanRightEdge ();
-
-	R_PolygonDrawSpans( s_polygon_spans, iswater );
-}
-
-/*
-** R_DrawAlphaSurfaces
-*/
-void R_DrawAlphaSurfaces( void )
-{
-	msurface_t *s = r_alpha_surfaces;
-
-	currentmodel = r_worldmodel;
-
-	modelorg[0] = -r_origin[0];
-	modelorg[1] = -r_origin[1];
-	modelorg[2] = -r_origin[2];
-
-	while ( s )
-	{
-		R_BuildPolygonFromSurface( s );
-
-		if (s->texinfo->flags & SURF_TRANS66)
-			R_ClipAndDrawPoly( 0.60f, ( s->texinfo->flags & SURF_WARP) != 0, true );
-		else
-			R_ClipAndDrawPoly( 0.30f, ( s->texinfo->flags & SURF_WARP) != 0, true );
-
-		s = s->nextalphasurface;
-	}
-	
-	r_alpha_surfaces = NULL;
-}
-
-/*
-** R_IMFlatShadedQuad
-*/
-void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha )
-{
-	vec3_t s0, s1;
-
-	r_polydesc.nump = 4;
-	VectorCopy( r_origin, r_polydesc.viewer_position );
-
-	VectorCopy( a, r_clip_verts[0][0] );
-	VectorCopy( b, r_clip_verts[0][1] );
-	VectorCopy( c, r_clip_verts[0][2] );
-	VectorCopy( d, r_clip_verts[0][3] );
-
-	r_clip_verts[0][0][3] = 0;
-	r_clip_verts[0][1][3] = 0;
-	r_clip_verts[0][2][3] = 0;
-	r_clip_verts[0][3][3] = 0;
-
-	r_clip_verts[0][0][4] = 0;
-	r_clip_verts[0][1][4] = 0;
-	r_clip_verts[0][2][4] = 0;
-	r_clip_verts[0][3][4] = 0;
-
-	VectorSubtract( d, c, s0 );
-	VectorSubtract( c, b, s1 );
-	CrossProduct( s0, s1, r_polydesc.vpn );
-	VectorNormalize( r_polydesc.vpn );
-
-	r_polydesc.dist = DotProduct( r_polydesc.vpn, r_clip_verts[0][0] );
-
-	r_polyblendcolor = color;
-
-	R_ClipAndDrawPoly( alpha, false, false );
-}
-
--- a/ref/r_polyse.c
+++ /dev/null
@@ -1,1146 +1,0 @@
-// d_polyset.c: routines for drawing sets of polygons sharing the same
-// texture (used for Alias models)
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-int	rand1k[] = {
-#include "rand1k.h"
-};
-
-#define MASK_1K	0x3FF
-
-int		rand1k_index = 0;
-
-// TODO: put in span spilling to shrink list size
-// !!! if this is changed, it must be changed in d_polysa.s too !!!
-#define DPS_MAXSPANS			MAXHEIGHT+1	
-									// 1 extra for spanpackage that marks end
-
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct {
-	void			*pdest;
-	short			*pz;
-	int				count;
-	byte			*ptex;
-	int				sfrac, tfrac, light, zi;
-} spanpackage_t;
-
-typedef struct {
-	int		isflattop;
-	int		numleftedges;
-	int		*pleftedgevert0;
-	int		*pleftedgevert1;
-	int		*pleftedgevert2;
-	int		numrightedges;
-	int		*prightedgevert0;
-	int		*prightedgevert1;
-	int		*prightedgevert2;
-} edgetable;
-
-aliastriangleparms_t aliastriangleparms;
-
-int	r_p0[6], r_p1[6], r_p2[6];
-
-byte		*d_pcolormap;
-
-int			d_aflatcolor;
-int			d_xdenom;
-
-edgetable	*pedgetable;
-
-edgetable	edgetables[12] = {
-	{0, 1, r_p0, r_p2, NULL, 2, r_p0, r_p1, r_p2 },
-	{0, 2, r_p1, r_p0, r_p2,   1, r_p1, r_p2, NULL},
-	{1, 1, r_p0, r_p2, NULL, 1, r_p1, r_p2, NULL},
-	{0, 1, r_p1, r_p0, NULL, 2, r_p1, r_p2, r_p0 },
-	{0, 2, r_p0, r_p2, r_p1,   1, r_p0, r_p1, NULL},
-	{0, 1, r_p2, r_p1, NULL, 1, r_p2, r_p0, NULL},
-	{0, 1, r_p2, r_p1, NULL, 2, r_p2, r_p0, r_p1 },
-	{0, 2, r_p2, r_p1, r_p0,   1, r_p2, r_p0, NULL},
-	{0, 1, r_p1, r_p0, NULL, 1, r_p1, r_p2, NULL},
-	{1, 1, r_p2, r_p1, NULL, 1, r_p0, r_p1, NULL},
-	{1, 1, r_p1, r_p0, NULL, 1, r_p2, r_p0, NULL},
-	{0, 1, r_p0, r_p2, NULL, 1, r_p0, r_p1, NULL},
-};
-
-// FIXME: some of these can become statics
-int				a_sstepxfrac, a_tstepxfrac, r_lstepx, a_ststepxwhole;
-int				r_sstepx, r_tstepx, r_lstepy, r_sstepy, r_tstepy;
-int				r_zistepx, r_zistepy;
-int				d_aspancount, d_countextrastep;
-
-spanpackage_t			*a_spans;
-spanpackage_t			*d_pedgespanpackage;
-static int				ystart;
-byte					*d_pdest, *d_ptex;
-short					*d_pz;
-int						d_sfrac, d_tfrac, d_light, d_zi;
-int						d_ptexextrastep, d_sfracextrastep;
-int						d_tfracextrastep, d_lightextrastep, d_pdestextrastep;
-int						d_lightbasestep, d_pdestbasestep, d_ptexbasestep;
-int						d_sfracbasestep, d_tfracbasestep;
-int						d_ziextrastep, d_zibasestep;
-int						d_pzextrastep, d_pzbasestep;
-
-typedef struct {
-	int		quotient;
-	int		remainder;
-} adivtab_t;
-
-static adivtab_t	adivtab[32*32] = {
-#include "adivtab.h"
-};
-
-byte	*skintable[MAX_LBM_HEIGHT];
-int		skinwidth;
-byte	*skinstart;
-
-void	(*d_pdrawspans)(spanpackage_t *pspanpackage);
-
-void R_PolysetDrawSpans8_33 (spanpackage_t *pspanpackage);
-void R_PolysetDrawSpans8_66 (spanpackage_t *pspanpackage);
-void R_PolysetDrawSpans8_Opaque (spanpackage_t *pspanpackage);
-
-void R_PolysetDrawThreshSpans8 (spanpackage_t *pspanpackage);
-void R_PolysetCalcGradients (int skinwidth);
-void R_DrawNonSubdiv (void);
-void R_PolysetSetEdgeTable (void);
-void R_RasterizeAliasPolySmooth (void);
-void R_PolysetScanLeftEdge(int height);
-void R_PolysetScanLeftEdge_C(int height);
-
-// ======================
-// PGM
-// 64 65 66 67 68 69 70 71   72 73 74 75 76 77 78 79
-byte iractive = 0;
-byte irtable[256] = { 79, 78, 77, 76, 75, 74, 73, 72,		// black/white
-					  71, 70, 69, 68, 67, 66, 65, 64,
-					  64, 65, 66, 67, 68, 69, 70, 71,		// dark taupe
-					  72, 73, 74, 75, 76, 77, 78, 79,
-
-					  64, 65, 66, 67, 68, 69, 70, 71,		// slate grey
-					  72, 73, 74, 75, 76, 77, 78, 79,
-					  208, 208, 208, 208, 208, 208, 208, 208,	// unused?'
-					  64, 66, 68, 70, 72, 74, 76, 78,		// dark yellow
-					  
-					  64, 65, 66, 67, 68, 69, 70, 71,		// dark red
-					  72, 73, 74, 75, 76, 77, 78, 79,
-					  64, 65, 66, 67, 68, 69, 70, 71,		// grey/tan
-					  72, 73, 74, 75, 76, 77, 78, 79,
-
-					  64, 66, 68, 70, 72, 74, 76, 78,		// chocolate
-					  68, 67, 66, 65, 64, 65, 66, 67,		// mauve / teal
-					  68, 69, 70, 71, 72, 73, 74, 75,
-					  76, 76, 77, 77, 78, 78, 79, 79,		
-
-					  64, 65, 66, 67, 68, 69, 70, 71,		// more mauve
-					  72, 73, 74, 75, 76, 77, 78, 79,
-					  64, 65, 66, 67, 68, 69, 70, 71,		// olive
-					  72, 73, 74, 75, 76, 77, 78, 79,
-
-					  64, 65, 66, 67, 68, 69, 70, 71,		// maroon
-					  72, 73, 74, 75, 76, 77, 78, 79,
-					  64, 65, 66, 67, 68, 69, 70, 71,		// sky blue
-					  72, 73, 74, 75, 76, 77, 78, 79,
-					  
-					  64, 65, 66, 67, 68, 69, 70, 71,		// olive again
-					  72, 73, 74, 75, 76, 77, 78, 79,
-					  64, 65, 66, 67, 68, 69, 70, 71,		// nuclear green
-					  64, 65, 66, 67, 68, 69, 70, 71,		// bright yellow
-
-					  64, 65, 66, 67, 68, 69, 70, 71,		// fire colors
-					  72, 73, 74, 75, 76, 77, 78, 79,
-					  208, 208, 64, 64, 70, 71, 72, 64,		// mishmash1
-					  66, 68, 70, 64, 65, 66, 67, 68};		// mishmash2
-// PGM
-// ======================
-
-/*
-================
-R_PolysetUpdateTables
-================
-*/
-void R_PolysetUpdateTables (void)
-{
-	int		i;
-	byte	*s;
-	
-	if (r_affinetridesc.skinwidth != skinwidth ||
-		r_affinetridesc.pskin != skinstart)
-	{
-		skinwidth = r_affinetridesc.skinwidth;
-		skinstart = r_affinetridesc.pskin;
-		s = skinstart;
-		for (i=0 ; i<MAX_LBM_HEIGHT ; i++, s+=skinwidth)
-			skintable[i] = s;
-	}
-}
-
-
-/*
-================
-R_DrawTriangle
-================
-*/
-void R_DrawTriangle( void )
-{
-	spanpackage_t spans[DPS_MAXSPANS];
-
-	int dv1_ab, dv0_ac;
-	int dv0_ab, dv1_ac;
-
-	/*
-	d_xdenom = ( aliastriangleparms.a->v[1] - aliastriangleparms.b->v[1] ) * ( aliastriangleparms.a->v[0] - aliastriangleparms.c->v[0] ) -
-			   ( aliastriangleparms.a->v[0] - aliastriangleparms.b->v[0] ) * ( aliastriangleparms.a->v[1] - aliastriangleparms.c->v[1] );
-	*/
-
-	dv0_ab = aliastriangleparms.a->u - aliastriangleparms.b->u;
-	dv1_ab = aliastriangleparms.a->v - aliastriangleparms.b->v;
-
-	if ( !( dv0_ab | dv1_ab ) )
-		return;
-
-	dv0_ac = aliastriangleparms.a->u - aliastriangleparms.c->u;
-	dv1_ac = aliastriangleparms.a->v - aliastriangleparms.c->v;
-
-	if ( !( dv0_ac | dv1_ac ) )
-		return;
-
-	d_xdenom = ( dv0_ac * dv1_ab ) - ( dv0_ab * dv1_ac );
-
-	if ( d_xdenom < 0 )
-	{
-		a_spans = spans;
-
-		r_p0[0] = aliastriangleparms.a->u;		// u
-		r_p0[1] = aliastriangleparms.a->v;		// v
-		r_p0[2] = aliastriangleparms.a->s;		// s
-		r_p0[3] = aliastriangleparms.a->t;		// t
-		r_p0[4] = aliastriangleparms.a->l;		// light
-		r_p0[5] = aliastriangleparms.a->zi;		// iz
-
-		r_p1[0] = aliastriangleparms.b->u;
-		r_p1[1] = aliastriangleparms.b->v;
-		r_p1[2] = aliastriangleparms.b->s;
-		r_p1[3] = aliastriangleparms.b->t;
-		r_p1[4] = aliastriangleparms.b->l;
-		r_p1[5] = aliastriangleparms.b->zi;
-
-		r_p2[0] = aliastriangleparms.c->u;
-		r_p2[1] = aliastriangleparms.c->v;
-		r_p2[2] = aliastriangleparms.c->s;
-		r_p2[3] = aliastriangleparms.c->t;
-		r_p2[4] = aliastriangleparms.c->l;
-		r_p2[5] = aliastriangleparms.c->zi;
-
-		R_PolysetSetEdgeTable ();
-		R_RasterizeAliasPolySmooth ();
-	}
-}
-
-
-/*
-===================
-R_PolysetScanLeftEdge_C
-====================
-*/
-void R_PolysetScanLeftEdge_C(int height)
-{
-	do
-	{
-		d_pedgespanpackage->pdest = d_pdest;
-		d_pedgespanpackage->pz = d_pz;
-		d_pedgespanpackage->count = d_aspancount;
-		d_pedgespanpackage->ptex = d_ptex;
-
-		d_pedgespanpackage->sfrac = d_sfrac;
-		d_pedgespanpackage->tfrac = d_tfrac;
-
-	// FIXME: need to clamp l, s, t, at both ends?
-		d_pedgespanpackage->light = d_light;
-		d_pedgespanpackage->zi = d_zi;
-
-		d_pedgespanpackage++;
-
-		errorterm += erroradjustup;
-		if (errorterm >= 0)
-		{
-			d_pdest += d_pdestextrastep;
-			d_pz += d_pzextrastep;
-			d_aspancount += d_countextrastep;
-			d_ptex += d_ptexextrastep;
-			d_sfrac += d_sfracextrastep;
-			d_ptex += d_sfrac >> 16;
-
-			d_sfrac &= 0xFFFF;
-			d_tfrac += d_tfracextrastep;
-			if (d_tfrac & 0x10000)
-			{
-				d_ptex += r_affinetridesc.skinwidth;
-				d_tfrac &= 0xFFFF;
-			}
-			d_light += d_lightextrastep;
-			d_zi += d_ziextrastep;
-			errorterm -= erroradjustdown;
-		}
-		else
-		{
-			d_pdest += d_pdestbasestep;
-			d_pz += d_pzbasestep;
-			d_aspancount += ubasestep;
-			d_ptex += d_ptexbasestep;
-			d_sfrac += d_sfracbasestep;
-			d_ptex += d_sfrac >> 16;
-			d_sfrac &= 0xFFFF;
-			d_tfrac += d_tfracbasestep;
-			if (d_tfrac & 0x10000)
-			{
-				d_ptex += r_affinetridesc.skinwidth;
-				d_tfrac &= 0xFFFF;
-			}
-			d_light += d_lightbasestep;
-			d_zi += d_zibasestep;
-		}
-	} while (--height);
-}
-
-/*
-===================
-FloorDivMod
-
-Returns mathematically correct (floor-based) quotient and remainder for
-numer and denom, both of which should contain no fractional part. The
-quotient must fit in 32 bits.
-FIXME: GET RID OF THIS! (FloorDivMod)
-====================
-*/
-void FloorDivMod (float numer, float denom, int *quotient,
-		int *rem)
-{
-	int		q, r;
-	float	x;
-
-	if (numer >= 0.0)
-	{
-
-		x = floor(numer / denom);
-		q = (int)x;
-		r = (int)floor(numer - (x * denom));
-	}
-	else
-	{
-	//
-	// perform operations with positive values, and fix mod to make floor-based
-	//
-		x = floor(-numer / denom);
-		q = -(int)x;
-		r = (int)floor(-numer - (x * denom));
-		if (r != 0)
-		{
-			q--;
-			r = (int)denom - r;
-		}
-	}
-
-	*quotient = q;
-	*rem = r;
-}
-
-
-/*
-===================
-R_PolysetSetUpForLineScan
-====================
-*/
-void R_PolysetSetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
-		fixed8_t endvertu, fixed8_t endvertv)
-{
-	float		dm, dn;
-	int			tm, tn;
-	adivtab_t	*ptemp;
-
-// TODO: implement x86 version
-
-	errorterm = -1;
-
-	tm = endvertu - startvertu;
-	tn = endvertv - startvertv;
-
-	if (((tm <= 16) && (tm >= -15)) &&
-		((tn <= 16) && (tn >= -15)))
-	{
-		ptemp = &adivtab[((tm+15) << 5) + (tn+15)];
-		ubasestep = ptemp->quotient;
-		erroradjustup = ptemp->remainder;
-		erroradjustdown = tn;
-	}
-	else
-	{
-		dm = tm;
-		dn = tn;
-
-		FloorDivMod (dm, dn, &ubasestep, &erroradjustup);
-
-		erroradjustdown = dn;
-	}
-}
-
-
-
-/*
-================
-R_PolysetCalcGradients
-================
-*/
-void R_PolysetCalcGradients (int skinwidth)
-{
-	float	xstepdenominv, ystepdenominv, t0, t1;
-	float	p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20;
-
-	p00_minus_p20 = r_p0[0] - r_p2[0];
-	p01_minus_p21 = r_p0[1] - r_p2[1];
-	p10_minus_p20 = r_p1[0] - r_p2[0];
-	p11_minus_p21 = r_p1[1] - r_p2[1];
-
-	xstepdenominv = 1.0 / (float)d_xdenom;
-
-	ystepdenominv = -xstepdenominv;
-
-// ceil () for light so positive steps are exaggerated, negative steps
-// diminished,  pushing us away from underflow toward overflow. Underflow is
-// very visible, overflow is very unlikely, because of ambient lighting
-	t0 = r_p0[4] - r_p2[4];
-	t1 = r_p1[4] - r_p2[4];
-	r_lstepx = (int)
-			ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv);
-	r_lstepy = (int)
-			ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv);
-
-	t0 = r_p0[2] - r_p2[2];
-	t1 = r_p1[2] - r_p2[2];
-	r_sstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
-			xstepdenominv);
-	r_sstepy = (int)((t1 * p00_minus_p20 - t0* p10_minus_p20) *
-			ystepdenominv);
-
-	t0 = r_p0[3] - r_p2[3];
-	t1 = r_p1[3] - r_p2[3];
-	r_tstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
-			xstepdenominv);
-	r_tstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
-			ystepdenominv);
-
-	t0 = r_p0[5] - r_p2[5];
-	t1 = r_p1[5] - r_p2[5];
-	r_zistepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
-			xstepdenominv);
-	r_zistepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
-			ystepdenominv);
-
-	a_sstepxfrac = r_sstepx & 0xFFFF;
-	a_tstepxfrac = r_tstepx & 0xFFFF;
-
-	a_ststepxwhole = skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16);
-}
-
-/*
-================
-R_PolysetDrawThreshSpans8
-
-Random fizzle fade rasterizer
-================
-*/
-void R_PolysetDrawThreshSpans8 (spanpackage_t *pspanpackage)
-{
-	int		lcount;
-	byte	*lpdest;
-	byte	*lptex;
-	int		lsfrac, ltfrac;
-	int		llight;
-	int		lzi;
-	short	*lpz;
-
-	do
-	{
-		lcount = d_aspancount - pspanpackage->count;
-
-		errorterm += erroradjustup;
-		if (errorterm >= 0)
-		{
-			d_aspancount += d_countextrastep;
-			errorterm -= erroradjustdown;
-		}
-		else
-		{
-			d_aspancount += ubasestep;
-		}
-
-		if (lcount)
-		{
-			lpdest = pspanpackage->pdest;
-			lptex = pspanpackage->ptex;
-			lpz = pspanpackage->pz;
-			lsfrac = pspanpackage->sfrac;
-			ltfrac = pspanpackage->tfrac;
-			llight = pspanpackage->light;
-			lzi = pspanpackage->zi;
-
-			do
-			{
-				if ((lzi >> 16) >= *lpz)
-				{
-					rand1k_index = (rand1k_index + 1) & MASK_1K;
-
-					if (rand1k[rand1k_index] <= r_affinetridesc.vis_thresh)
-					{
-						*lpdest = ((byte *)vid.colormap)[*lptex + (llight & 0xFF00)];
-						*lpz = lzi >> 16;
-					}
-				}
-
-				lpdest++;
-				lzi += r_zistepx;
-				lpz++;
-				llight += r_lstepx;
-				lptex += a_ststepxwhole;
-				lsfrac += a_sstepxfrac;
-				lptex += lsfrac >> 16;
-				lsfrac &= 0xFFFF;
-				ltfrac += a_tstepxfrac;
-				if (ltfrac & 0x10000)
-				{
-					lptex += r_affinetridesc.skinwidth;
-					ltfrac &= 0xFFFF;
-				}
-			} while (--lcount);
-		}
-
-		pspanpackage++;
-	} while (pspanpackage->count != -999999);
-}
-
-
-/*
-================
-R_PolysetDrawSpans8
-================
-*/
-void R_PolysetDrawSpans8_33( spanpackage_t *pspanpackage)
-{
-	int		lcount;
-	byte	*lpdest;
-	byte	*lptex;
-	int		lsfrac, ltfrac;
-	int		llight;
-	int		lzi;
-	short	*lpz;
-
-	do
-	{
-		lcount = d_aspancount - pspanpackage->count;
-
-		errorterm += erroradjustup;
-		if (errorterm >= 0)
-		{
-			d_aspancount += d_countextrastep;
-			errorterm -= erroradjustdown;
-		}
-		else
-		{
-			d_aspancount += ubasestep;
-		}
-
-		if (lcount)
-		{
-			lpdest = pspanpackage->pdest;
-			lptex = pspanpackage->ptex;
-			lpz = pspanpackage->pz;
-			lsfrac = pspanpackage->sfrac;
-			ltfrac = pspanpackage->tfrac;
-			llight = pspanpackage->light;
-			lzi = pspanpackage->zi;
-
-			do
-			{
-				if ((lzi >> 16) >= *lpz)
-				{
-					int temp = vid.colormap[*lptex + ( llight & 0xFF00 )];
-
-					*lpdest = vid.alphamap[temp+ *lpdest*256];
-				}
-				lpdest++;
-				lzi += r_zistepx;
-				lpz++;
-				llight += r_lstepx;
-				lptex += a_ststepxwhole;
-				lsfrac += a_sstepxfrac;
-				lptex += lsfrac >> 16;
-				lsfrac &= 0xFFFF;
-				ltfrac += a_tstepxfrac;
-				if (ltfrac & 0x10000)
-				{
-					lptex += r_affinetridesc.skinwidth;
-					ltfrac &= 0xFFFF;
-				}
-			} while (--lcount);
-		}
-
-		pspanpackage++;
-	} while (pspanpackage->count != -999999);
-}
-
-void R_PolysetDrawSpansConstant8_33( spanpackage_t *pspanpackage)
-{
-	int		lcount;
-	byte	*lpdest;
-	int		lzi;
-	short	*lpz;
-
-	do
-	{
-		lcount = d_aspancount - pspanpackage->count;
-
-		errorterm += erroradjustup;
-		if (errorterm >= 0)
-		{
-			d_aspancount += d_countextrastep;
-			errorterm -= erroradjustdown;
-		}
-		else
-		{
-			d_aspancount += ubasestep;
-		}
-
-		if (lcount)
-		{
-			lpdest = pspanpackage->pdest;
-			lpz = pspanpackage->pz;
-			lzi = pspanpackage->zi;
-
-			do
-			{
-				if ((lzi >> 16) >= *lpz)
-				{
-					*lpdest = vid.alphamap[r_aliasblendcolor + *lpdest*256];
-				}
-				lpdest++;
-				lzi += r_zistepx;
-				lpz++;
-			} while (--lcount);
-		}
-
-		pspanpackage++;
-	} while (pspanpackage->count != -999999);
-}
-
-void R_PolysetDrawSpans8_66(spanpackage_t *pspanpackage)
-{
-	int		lcount;
-	byte	*lpdest;
-	byte	*lptex;
-	int		lsfrac, ltfrac;
-	int		llight;
-	int		lzi;
-	short	*lpz;
-
-	do
-	{
-		lcount = d_aspancount - pspanpackage->count;
-
-		errorterm += erroradjustup;
-		if (errorterm >= 0)
-		{
-			d_aspancount += d_countextrastep;
-			errorterm -= erroradjustdown;
-		}
-		else
-		{
-			d_aspancount += ubasestep;
-		}
-
-		if (lcount)
-		{
-			lpdest = pspanpackage->pdest;
-			lptex = pspanpackage->ptex;
-			lpz = pspanpackage->pz;
-			lsfrac = pspanpackage->sfrac;
-			ltfrac = pspanpackage->tfrac;
-			llight = pspanpackage->light;
-			lzi = pspanpackage->zi;
-
-			do
-			{
-				if ((lzi >> 16) >= *lpz)
-				{
-					int temp = vid.colormap[*lptex + ( llight & 0xFF00 )];
-
-					*lpdest = vid.alphamap[temp*256 + *lpdest];
-					*lpz = lzi >> 16;
-				}
-				lpdest++;
-				lzi += r_zistepx;
-				lpz++;
-				llight += r_lstepx;
-				lptex += a_ststepxwhole;
-				lsfrac += a_sstepxfrac;
-				lptex += lsfrac >> 16;
-				lsfrac &= 0xFFFF;
-				ltfrac += a_tstepxfrac;
-				if (ltfrac & 0x10000)
-				{
-					lptex += r_affinetridesc.skinwidth;
-					ltfrac &= 0xFFFF;
-				}
-			} while (--lcount);
-		}
-
-		pspanpackage++;
-	} while (pspanpackage->count != -999999);
-}
-
-void R_PolysetDrawSpansConstant8_66( spanpackage_t *pspanpackage)
-{
-	int		lcount;
-	byte	*lpdest;
-	int		lzi;
-	short	*lpz;
-
-	do
-	{
-		lcount = d_aspancount - pspanpackage->count;
-
-		errorterm += erroradjustup;
-		if (errorterm >= 0)
-		{
-			d_aspancount += d_countextrastep;
-			errorterm -= erroradjustdown;
-		}
-		else
-		{
-			d_aspancount += ubasestep;
-		}
-
-		if (lcount)
-		{
-			lpdest = pspanpackage->pdest;
-			lpz = pspanpackage->pz;
-			lzi = pspanpackage->zi;
-
-			do
-			{
-				if ((lzi >> 16) >= *lpz)
-				{
-					*lpdest = vid.alphamap[r_aliasblendcolor*256 + *lpdest];
-				}
-				lpdest++;
-				lzi += r_zistepx;
-				lpz++;
-			} while (--lcount);
-		}
-
-		pspanpackage++;
-	} while (pspanpackage->count != -999999);
-}
-
-void R_PolysetDrawSpans8_Opaque (spanpackage_t *pspanpackage)
-{
-	int		lcount;
-
-	do
-	{
-		lcount = d_aspancount - pspanpackage->count;
-
-		errorterm += erroradjustup;
-		if (errorterm >= 0)
-		{
-			d_aspancount += d_countextrastep;
-			errorterm -= erroradjustdown;
-		}
-		else
-		{
-			d_aspancount += ubasestep;
-		}
-
-		if (lcount)
-		{
-			int		lsfrac, ltfrac;
-			byte	*lpdest;
-			byte	*lptex;
-			int		llight;
-			int		lzi;
-			short	*lpz;
-
-			lpdest = pspanpackage->pdest;
-			lptex = pspanpackage->ptex;
-			lpz = pspanpackage->pz;
-			lsfrac = pspanpackage->sfrac;
-			ltfrac = pspanpackage->tfrac;
-			llight = pspanpackage->light;
-			lzi = pspanpackage->zi;
-
-			do
-			{
-				if ((lzi >> 16) >= *lpz)
-				{
-//PGM
-					if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
-						*lpdest = ((byte *)vid.colormap)[irtable[*lptex]];
-					else
-					*lpdest = ((byte *)vid.colormap)[*lptex + (llight & 0xFF00)];
-//PGM
-					*lpz = lzi >> 16;
-				}
-				lpdest++;
-				lzi += r_zistepx;
-				lpz++;
-				llight += r_lstepx;
-				lptex += a_ststepxwhole;
-				lsfrac += a_sstepxfrac;
-				lptex += lsfrac >> 16;
-				lsfrac &= 0xFFFF;
-				ltfrac += a_tstepxfrac;
-				if (ltfrac & 0x10000)
-				{
-					lptex += r_affinetridesc.skinwidth;
-					ltfrac &= 0xFFFF;
-				}
-			} while (--lcount);
-		}
-
-		pspanpackage++;
-	} while (pspanpackage->count != -999999);
-}
-
-
-/*
-================
-R_PolysetFillSpans8
-================
-*/
-void R_PolysetFillSpans8 (spanpackage_t *pspanpackage)
-{
-	int				color;
-
-// FIXME: do z buffering
-
-	color = d_aflatcolor++;
-
-	while (1)
-	{
-		int		lcount;
-		byte	*lpdest;
-
-		lcount = pspanpackage->count;
-
-		if (lcount == -1)
-			return;
-
-		if (lcount)
-		{
-			lpdest = pspanpackage->pdest;
-
-			do
-			{
-				*lpdest++ = color;
-			} while (--lcount);
-		}
-
-		pspanpackage++;
-	}
-}
-
-/*
-================
-R_RasterizeAliasPolySmooth
-================
-*/
-void R_RasterizeAliasPolySmooth (void)
-{
-	int				initialleftheight, initialrightheight;
-	int				*plefttop, *prighttop, *pleftbottom, *prightbottom;
-	int				working_lstepx, originalcount;
-
-	plefttop = pedgetable->pleftedgevert0;
-	prighttop = pedgetable->prightedgevert0;
-
-	pleftbottom = pedgetable->pleftedgevert1;
-	prightbottom = pedgetable->prightedgevert1;
-
-	initialleftheight = pleftbottom[1] - plefttop[1];
-	initialrightheight = prightbottom[1] - prighttop[1];
-
-//
-// set the s, t, and light gradients, which are consistent across the triangle
-// because being a triangle, things are affine
-//
-	R_PolysetCalcGradients (r_affinetridesc.skinwidth);
-//
-// rasterize the polygon
-//
-
-//
-// scan out the top (and possibly only) part of the left edge
-//
-	d_pedgespanpackage = a_spans;
-
-	ystart = plefttop[1];
-	d_aspancount = plefttop[0] - prighttop[0];
-
-	d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
-			(plefttop[3] >> 16) * r_affinetridesc.skinwidth;
-
-	d_sfrac = plefttop[2] & 0xFFFF;
-	d_tfrac = plefttop[3] & 0xFFFF;
-
-	d_light = plefttop[4];
-	d_zi = plefttop[5];
-
-	d_pdest = (byte *)d_viewbuffer +
-			ystart * r_screenwidth + plefttop[0];
-	d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
-
-	if (initialleftheight == 1)
-	{
-		d_pedgespanpackage->pdest = d_pdest;
-		d_pedgespanpackage->pz = d_pz;
-		d_pedgespanpackage->count = d_aspancount;
-		d_pedgespanpackage->ptex = d_ptex;
-
-		d_pedgespanpackage->sfrac = d_sfrac;
-		d_pedgespanpackage->tfrac = d_tfrac;
-
-	// FIXME: need to clamp l, s, t, at both ends?
-		d_pedgespanpackage->light = d_light;
-		d_pedgespanpackage->zi = d_zi;
-
-		d_pedgespanpackage++;
-	}
-	else
-	{
-		R_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
-							  pleftbottom[0], pleftbottom[1]);
-
-		d_pzbasestep = d_zwidth + ubasestep;
-		d_pzextrastep = d_pzbasestep + 1;
-
-		d_pdestbasestep = r_screenwidth + ubasestep;
-		d_pdestextrastep = d_pdestbasestep + 1;
-
-	// TODO: can reuse partial expressions here
-
-	// for negative steps in x along left edge, bias toward overflow rather than
-	// underflow (sort of turning the floor () we did in the gradient calcs into
-	// ceil (), but plus a little bit)
-		if (ubasestep < 0)
-			working_lstepx = r_lstepx - 1;
-		else
-			working_lstepx = r_lstepx;
-
-		d_countextrastep = ubasestep + 1;
-		d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
-				((r_tstepy + r_tstepx * ubasestep) >> 16) *
-				r_affinetridesc.skinwidth;
-
-		d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
-		d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
-
-		d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
-		d_zibasestep = r_zistepy + r_zistepx * ubasestep;
-
-		d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
-				((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
-				r_affinetridesc.skinwidth;
-
-		d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) & 0xFFFF;
-		d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) & 0xFFFF;
-
-		d_lightextrastep = d_lightbasestep + working_lstepx;
-		d_ziextrastep = d_zibasestep + r_zistepx;
-
-		R_PolysetScanLeftEdge_C(initialleftheight);
-	}
-
-//
-// scan out the bottom part of the left edge, if it exists
-//
-	if (pedgetable->numleftedges == 2)
-	{
-		int		height;
-
-		plefttop = pleftbottom;
-		pleftbottom = pedgetable->pleftedgevert2;
-
-		height = pleftbottom[1] - plefttop[1];
-
-// TODO: make this a function; modularize this function in general
-
-		ystart = plefttop[1];
-		d_aspancount = plefttop[0] - prighttop[0];
-		d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
-				(plefttop[3] >> 16) * r_affinetridesc.skinwidth;
-		d_sfrac = 0;
-		d_tfrac = 0;
-		d_light = plefttop[4];
-		d_zi = plefttop[5];
-
-		d_pdest = (byte *)d_viewbuffer + ystart * r_screenwidth + plefttop[0];
-		d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
-
-		if (height == 1)
-		{
-			d_pedgespanpackage->pdest = d_pdest;
-			d_pedgespanpackage->pz = d_pz;
-			d_pedgespanpackage->count = d_aspancount;
-			d_pedgespanpackage->ptex = d_ptex;
-
-			d_pedgespanpackage->sfrac = d_sfrac;
-			d_pedgespanpackage->tfrac = d_tfrac;
-
-		// FIXME: need to clamp l, s, t, at both ends?
-			d_pedgespanpackage->light = d_light;
-			d_pedgespanpackage->zi = d_zi;
-		}
-		else
-		{
-			R_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
-								  pleftbottom[0], pleftbottom[1]);
-
-			d_pdestbasestep = r_screenwidth + ubasestep;
-			d_pdestextrastep = d_pdestbasestep + 1;
-
-			d_pzbasestep = d_zwidth + ubasestep;
-			d_pzextrastep = d_pzbasestep + 1;
-
-			if (ubasestep < 0)
-				working_lstepx = r_lstepx - 1;
-			else
-				working_lstepx = r_lstepx;
-
-			d_countextrastep = ubasestep + 1;
-			d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
-					((r_tstepy + r_tstepx * ubasestep) >> 16) *
-					r_affinetridesc.skinwidth;
-
-			d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
-			d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
-
-			d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
-			d_zibasestep = r_zistepy + r_zistepx * ubasestep;
-
-			d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
-					((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
-					r_affinetridesc.skinwidth;
-
-
-			d_sfracextrastep = (r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF;
-			d_tfracextrastep = (r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF;
-
-			d_lightextrastep = d_lightbasestep + working_lstepx;
-			d_ziextrastep = d_zibasestep + r_zistepx;
-
-			R_PolysetScanLeftEdge_C(height);
-		}
-	}
-
-// scan out the top (and possibly only) part of the right edge, updating the
-// count field
-	d_pedgespanpackage = a_spans;
-
-	R_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
-						  prightbottom[0], prightbottom[1]);
-	d_aspancount = 0;
-	d_countextrastep = ubasestep + 1;
-	originalcount = a_spans[initialrightheight].count;
-	a_spans[initialrightheight].count = -999999; // mark end of the spanpackages
-	(*d_pdrawspans) (a_spans);
-
-// scan out the bottom part of the right edge, if it exists
-	if (pedgetable->numrightedges == 2)
-	{
-		int				height;
-		spanpackage_t	*pstart;
-
-		pstart = a_spans + initialrightheight;
-		pstart->count = originalcount;
-
-		d_aspancount = prightbottom[0] - prighttop[0];
-
-		prighttop = prightbottom;
-		prightbottom = pedgetable->prightedgevert2;
-
-		height = prightbottom[1] - prighttop[1];
-
-		R_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
-							  prightbottom[0], prightbottom[1]);
-
-		d_countextrastep = ubasestep + 1;
-		a_spans[initialrightheight + height].count = -999999;
-											// mark end of the spanpackages
-		(*d_pdrawspans) (pstart);
-	}
-}
-
-
-/*
-================
-R_PolysetSetEdgeTable
-================
-*/
-void R_PolysetSetEdgeTable (void)
-{
-	int			edgetableindex;
-
-	edgetableindex = 0;	// assume the vertices are already in
-						//  top to bottom order
-
-//
-// determine which edges are right & left, and the order in which
-// to rasterize them
-//
-	if (r_p0[1] >= r_p1[1])
-	{
-		if (r_p0[1] == r_p1[1])
-		{
-			if (r_p0[1] < r_p2[1])
-				pedgetable = &edgetables[2];
-			else
-				pedgetable = &edgetables[5];
-
-			return;
-		}
-		else
-		{
-			edgetableindex = 1;
-		}
-	}
-
-	if (r_p0[1] == r_p2[1])
-	{
-		if (edgetableindex)
-			pedgetable = &edgetables[8];
-		else
-			pedgetable = &edgetables[9];
-
-		return;
-	}
-	else if (r_p1[1] == r_p2[1])
-	{
-		if (edgetableindex)
-			pedgetable = &edgetables[10];
-		else
-			pedgetable = &edgetables[11];
-
-		return;
-	}
-
-	if (r_p0[1] > r_p2[1])
-		edgetableindex += 2;
-
-	if (r_p1[1] > r_p2[1])
-		edgetableindex += 4;
-
-	pedgetable = &edgetables[edgetableindex];
-}
--- a/ref/r_rast.c
+++ /dev/null
@@ -1,828 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-#define MAXLEFTCLIPEDGES		100
-
-// !!! if these are changed, they must be changed in asm_draw.h too !!!
-#define FULLY_CLIPPED_CACHED	0x80000000
-#define FRAMECOUNT_MASK			0x7FFFFFFF
-
-unsigned int	cacheoffset;
-
-int			c_faceclip;					// number of faces clipped
-
-
-clipplane_t	*entity_clipplanes;
-clipplane_t	view_clipplanes[4];
-clipplane_t	world_clipplanes[16];
-
-medge_t			*r_pedge;
-
-qboolean		r_leftclipped, r_rightclipped;
-static qboolean	makeleftedge, makerightedge;
-qboolean		r_nearzionly;
-
-int		sintable[1280];
-int		intsintable[1280];
-int		blanktable[1280];		// PGM
-
-mvertex_t	r_leftenter, r_leftexit;
-mvertex_t	r_rightenter, r_rightexit;
-
-typedef struct
-{
-	float	u,v;
-	int		ceilv;
-} evert_t;
-
-int				r_emitted;
-float			r_nearzi;
-float			r_u1, r_v1, r_lzi1;
-int				r_ceilv1;
-
-qboolean		r_lastvertvalid;
-int				r_skyframe;
-
-msurface_t		*r_skyfaces;
-mplane_t		r_skyplanes[6];
-mtexinfo_t		r_skytexinfo[6];
-mvertex_t		*r_skyverts;
-medge_t			*r_skyedges;
-int				*r_skysurfedges;
-
-// I just copied this data from a box map...
-int skybox_planes[12] = {2,-128, 0,-128, 2,128, 1,128, 0,128, 1,-128};
-
-int box_surfedges[24] = { 1,2,3,4,  -1,5,6,7,  8,9,-6,10,  -2,-7,-9,11,
-  12,-3,-11,-8,  -12,-10,-5,-4};
-int box_edges[24] = { 1,2, 2,3, 3,4, 4,1, 1,5, 5,6, 6,2, 7,8, 8,6, 5,7, 8,3, 7,4};
-
-int	box_faces[6] = {0,0,2,2,2,0};
-
-vec3_t	box_vecs[6][2] = {
-	{	{0,-1,0}, {-1,0,0} },
-	{ {0,1,0}, {0,0,-1} },
-	{	{0,-1,0}, {1,0,0} },
-	{ {1,0,0}, {0,0,-1} },
-	{ {0,-1,0}, {0,0,-1} },
-	{ {-1,0,0}, {0,0,-1} }
-};
-
-float	box_verts[8][3] = {
-	{-1,-1,-1},
-	{-1,1,-1},
-	{1,1,-1},
-	{1,-1,-1},
-	{-1,-1,1},
-	{-1,1,1},
-	{1,-1,1},
-	{1,1,1}
-};
-
-// down, west, up, north, east, south
-// {"rt", "bk", "lf", "ft", "up", "dn"};
-
-/*
-================
-R_InitSkyBox
-
-================
-*/
-void R_InitSkyBox (void)
-{
-	int		i;
-	extern model_t *loadmodel;
-
-	r_skyfaces = loadmodel->surfaces + loadmodel->numsurfaces;
-	loadmodel->numsurfaces += 6;
-	r_skyverts = loadmodel->vertexes + loadmodel->numvertexes;
-	loadmodel->numvertexes += 8;
-	r_skyedges = loadmodel->edges + loadmodel->numedges;
-	loadmodel->numedges += 12;
-	r_skysurfedges = loadmodel->surfedges + loadmodel->numsurfedges;
-	loadmodel->numsurfedges += 24;
-	if (loadmodel->numsurfaces > MAX_MAP_FACES
-		|| loadmodel->numvertexes > MAX_MAP_VERTS
-		|| loadmodel->numedges > MAX_MAP_EDGES)
-		ri.Sys_Error (ERR_DROP, "InitSkyBox: map overflow");
-
-	memset (r_skyfaces, 0, 6*sizeof(*r_skyfaces));
-	for (i=0 ; i<6 ; i++)
-	{
-		r_skyplanes[i].normal[skybox_planes[i*2]] = 1;
-		r_skyplanes[i].dist = skybox_planes[i*2+1];
-
-		VectorCopy (box_vecs[i][0], r_skytexinfo[i].vecs[0]);
-		VectorCopy (box_vecs[i][1], r_skytexinfo[i].vecs[1]);
-
-		r_skyfaces[i].plane = &r_skyplanes[i];
-		r_skyfaces[i].numedges = 4;
-		r_skyfaces[i].flags = box_faces[i] | SURF_DRAWSKYBOX;
-		r_skyfaces[i].firstedge = loadmodel->numsurfedges-24+i*4;
-		r_skyfaces[i].texinfo = &r_skytexinfo[i];
-		r_skyfaces[i].texturemins[0] = -128;
-		r_skyfaces[i].texturemins[1] = -128;
-		r_skyfaces[i].extents[0] = 256;
-		r_skyfaces[i].extents[1] = 256;
-	}
-
-	for (i=0 ; i<24 ; i++)
-		if (box_surfedges[i] > 0)
-			r_skysurfedges[i] = loadmodel->numedges-13 + box_surfedges[i];
-		else
-			r_skysurfedges[i] = - (loadmodel->numedges-13 + -box_surfedges[i]);
-
-	for(i=0 ; i<12 ; i++)
-	{
-		r_skyedges[i].v[0] = loadmodel->numvertexes-9+box_edges[i*2+0];
-		r_skyedges[i].v[1] = loadmodel->numvertexes-9+box_edges[i*2+1];
-		r_skyedges[i].cachededgeoffset = 0;
-	}
-}
-
-/*
-================
-R_EmitSkyBox
-================
-*/
-void R_EmitSkyBox (void)
-{
-	int		i, j;
-	int		oldkey;
-
-	if (insubmodel)
-		return;		// submodels should never have skies
-	if (r_skyframe == r_framecount)
-		return;		// already set this frame
-
-	r_skyframe = r_framecount;
-
-	// set the eight fake vertexes
-	for (i=0 ; i<8 ; i++)
-		for (j=0 ; j<3 ; j++)
-			r_skyverts[i].position[j] = r_origin[j] + box_verts[i][j]*128;
-
-	// set the six fake planes
-	for (i=0 ; i<6 ; i++)
-		if (skybox_planes[i*2+1] > 0)
-			r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]+128;
-		else
-			r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]-128;
-
-	// fix texture offseets
-	for (i=0 ; i<6 ; i++)
-	{
-		r_skytexinfo[i].vecs[0][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[0]);
-		r_skytexinfo[i].vecs[1][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[1]);
-	}
-
-	// emit the six faces
-	oldkey = r_currentkey;
-	r_currentkey = 0x7ffffff0;
- 	for (i=0 ; i<6 ; i++)
-	{
-		R_RenderFace (r_skyfaces + i, 15);
-	}
-	r_currentkey = oldkey;		// bsp sorting order
-}
-
-
-/*
-================
-R_EmitEdge
-================
-*/
-void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
-{
-	edge_t	*edge, *pcheck;
-	int		u_check;
-	float	u, u_step;
-	vec3_t	local, transformed;
-	float	*world;
-	int		v, v2, ceilv0;
-	float	scale, lzi0, u0, v0;
-	int		side;
-
-	if (r_lastvertvalid)
-	{
-		u0 = r_u1;
-		v0 = r_v1;
-		lzi0 = r_lzi1;
-		ceilv0 = r_ceilv1;
-	}
-	else
-	{
-		world = &pv0->position[0];
-	
-	// transform and project
-		VectorSubtract (world, modelorg, local);
-		TransformVector (local, transformed);
-	
-		if (transformed[2] < NEAR_CLIP)
-			transformed[2] = NEAR_CLIP;
-	
-		lzi0 = 1.0 / transformed[2];
-	
-	// FIXME: build x/yscale into transform?
-		scale = xscale * lzi0;
-		u0 = (xcenter + scale*transformed[0]);
-		if (u0 < r_refdef.fvrectx_adj)
-			u0 = r_refdef.fvrectx_adj;
-		if (u0 > r_refdef.fvrectright_adj)
-			u0 = r_refdef.fvrectright_adj;
-	
-		scale = yscale * lzi0;
-		v0 = (ycenter - scale*transformed[1]);
-		if (v0 < r_refdef.fvrecty_adj)
-			v0 = r_refdef.fvrecty_adj;
-		if (v0 > r_refdef.fvrectbottom_adj)
-			v0 = r_refdef.fvrectbottom_adj;
-	
-		ceilv0 = (int) ceil(v0);
-	}
-
-	world = &pv1->position[0];
-
-// transform and project
-	VectorSubtract (world, modelorg, local);
-	TransformVector (local, transformed);
-
-	if (transformed[2] < NEAR_CLIP)
-		transformed[2] = NEAR_CLIP;
-
-	r_lzi1 = 1.0 / transformed[2];
-
-	scale = xscale * r_lzi1;
-	r_u1 = (xcenter + scale*transformed[0]);
-	if (r_u1 < r_refdef.fvrectx_adj)
-		r_u1 = r_refdef.fvrectx_adj;
-	if (r_u1 > r_refdef.fvrectright_adj)
-		r_u1 = r_refdef.fvrectright_adj;
-
-	scale = yscale * r_lzi1;
-	r_v1 = (ycenter - scale*transformed[1]);
-	if (r_v1 < r_refdef.fvrecty_adj)
-		r_v1 = r_refdef.fvrecty_adj;
-	if (r_v1 > r_refdef.fvrectbottom_adj)
-		r_v1 = r_refdef.fvrectbottom_adj;
-
-	if (r_lzi1 > lzi0)
-		lzi0 = r_lzi1;
-
-	if (lzi0 > r_nearzi)	// for mipmap finding
-		r_nearzi = lzi0;
-
-// for right edges, all we want is the effect on 1/z
-	if (r_nearzionly)
-		return;
-
-	r_emitted = 1;
-
-	r_ceilv1 = (int) ceil(r_v1);
-
-
-// create the edge
-	if (ceilv0 == r_ceilv1)
-	{
-	// we cache unclipped horizontal edges as fully clipped
-		if (cacheoffset != 0x7FFFFFFF)
-		{
-			cacheoffset = FULLY_CLIPPED_CACHED |
-					(r_framecount & FRAMECOUNT_MASK);
-		}
-
-		return;		// horizontal edge
-	}
-
-	side = ceilv0 > r_ceilv1;
-
-	edge = edge_p++;
-
-	edge->owner = r_pedge;
-
-	edge->nearzi = lzi0;
-
-	if (side == 0)
-	{
-	// trailing edge (go from p1 to p2)
-		v = ceilv0;
-		v2 = r_ceilv1 - 1;
-
-		edge->surfs[0] = surface_p - surfaces;
-		edge->surfs[1] = 0;
-
-		u_step = ((r_u1 - u0) / (r_v1 - v0));
-		u = u0 + ((float)v - v0) * u_step;
-	}
-	else
-	{
-	// leading edge (go from p2 to p1)
-		v2 = ceilv0 - 1;
-		v = r_ceilv1;
-
-		edge->surfs[0] = 0;
-		edge->surfs[1] = surface_p - surfaces;
-
-		u_step = ((u0 - r_u1) / (v0 - r_v1));
-		u = r_u1 + ((float)v - r_v1) * u_step;
-	}
-
-	edge->u_step = u_step*0x100000;
-	edge->u = u*0x100000 + 0xFFFFF;
-
-// we need to do this to avoid stepping off the edges if a very nearly
-// horizontal edge is less than epsilon above a scan, and numeric error causes
-// it to incorrectly extend to the scan, and the extension of the line goes off
-// the edge of the screen
-// FIXME: is this actually needed?
-	if (edge->u < r_refdef.vrect_x_adj_shift20)
-		edge->u = r_refdef.vrect_x_adj_shift20;
-	if (edge->u > r_refdef.vrectright_adj_shift20)
-		edge->u = r_refdef.vrectright_adj_shift20;
-
-//
-// sort the edge in normally
-//
-	u_check = edge->u;
-	if (edge->surfs[0])
-		u_check++;	// sort trailers after leaders
-
-	if (!newedges[v] || newedges[v]->u >= u_check)
-	{
-		edge->next = newedges[v];
-		newedges[v] = edge;
-	}
-	else
-	{
-		pcheck = newedges[v];
-		while (pcheck->next && pcheck->next->u < u_check)
-			pcheck = pcheck->next;
-		edge->next = pcheck->next;
-		pcheck->next = edge;
-	}
-
-	edge->nextremove = removeedges[v2];
-	removeedges[v2] = edge;
-}
-
-
-/*
-================
-R_ClipEdge
-================
-*/
-void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
-{
-	float		d0, d1, f;
-	mvertex_t	clipvert;
-
-	if (clip)
-	{
-		do
-		{
-			d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
-			d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
-
-			if (d0 >= 0)
-			{
-			// point 0 is unclipped
-				if (d1 >= 0)
-				{
-				// both points are unclipped
-					continue;
-				}
-
-			// only point 1 is clipped
-
-			// we don't cache clipped edges
-				cacheoffset = 0x7FFFFFFF;
-
-				f = d0 / (d0 - d1);
-				clipvert.position[0] = pv0->position[0] +
-						f * (pv1->position[0] - pv0->position[0]);
-				clipvert.position[1] = pv0->position[1] +
-						f * (pv1->position[1] - pv0->position[1]);
-				clipvert.position[2] = pv0->position[2] +
-						f * (pv1->position[2] - pv0->position[2]);
-
-				if (clip->leftedge)
-				{
-					r_leftclipped = true;
-					r_leftexit = clipvert;
-				}
-				else if (clip->rightedge)
-				{
-					r_rightclipped = true;
-					r_rightexit = clipvert;
-				}
-
-				R_ClipEdge (pv0, &clipvert, clip->next);
-				return;
-			}
-			else
-			{
-			// point 0 is clipped
-				if (d1 < 0)
-				{
-				// both points are clipped
-				// we do cache fully clipped edges
-					if (!r_leftclipped)
-						cacheoffset = FULLY_CLIPPED_CACHED |
-								(r_framecount & FRAMECOUNT_MASK);
-					return;
-				}
-
-			// only point 0 is clipped
-				r_lastvertvalid = false;
-
-			// we don't cache partially clipped edges
-				cacheoffset = 0x7FFFFFFF;
-
-				f = d0 / (d0 - d1);
-				clipvert.position[0] = pv0->position[0] +
-						f * (pv1->position[0] - pv0->position[0]);
-				clipvert.position[1] = pv0->position[1] +
-						f * (pv1->position[1] - pv0->position[1]);
-				clipvert.position[2] = pv0->position[2] +
-						f * (pv1->position[2] - pv0->position[2]);
-
-				if (clip->leftedge)
-				{
-					r_leftclipped = true;
-					r_leftenter = clipvert;
-				}
-				else if (clip->rightedge)
-				{
-					r_rightclipped = true;
-					r_rightenter = clipvert;
-				}
-
-				R_ClipEdge (&clipvert, pv1, clip->next);
-				return;
-			}
-		} while ((clip = clip->next) != NULL);
-	}
-
-// add the edge
-	R_EmitEdge (pv0, pv1);
-}
-
-
-/*
-================
-R_EmitCachedEdge
-================
-*/
-void R_EmitCachedEdge (void)
-{
-	edge_t		*pedge_t;
-
-	pedge_t = (edge_t *)((uintptr)r_edges + r_pedge->cachededgeoffset);
-
-	if (!pedge_t->surfs[0])
-		pedge_t->surfs[0] = surface_p - surfaces;
-	else
-		pedge_t->surfs[1] = surface_p - surfaces;
-
-	if (pedge_t->nearzi > r_nearzi)	// for mipmap finding
-		r_nearzi = pedge_t->nearzi;
-
-	r_emitted = 1;
-}
-
-
-/*
-================
-R_RenderFace
-================
-*/
-void R_RenderFace (msurface_t *fa, int clipflags)
-{
-	int			i, lindex;
-	unsigned	mask;
-	mplane_t	*pplane;
-	float		distinv;
-	vec3_t		p_normal;
-	medge_t		*pedges, tedge;
-	clipplane_t	*pclip;
-
-	// translucent surfaces are not drawn by the edge renderer
-	if (fa->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
-	{
-		fa->nextalphasurface = r_alpha_surfaces;
-		r_alpha_surfaces = fa;
-		return;
-	}
-
-	// sky surfaces encountered in the world will cause the
-	// environment box surfaces to be emited
-	if ( fa->texinfo->flags & SURF_SKY )
-	{
-		R_EmitSkyBox ();	
-		return;
-	}
-
-// skip out if no more surfs
-	if ((surface_p) >= surf_max)
-	{
-		r_outofsurfaces++;
-		return;
-	}
-
-// ditto if not enough edges left, or switch to auxedges if possible
-	if ((edge_p + fa->numedges + 4) >= edge_max)
-	{
-		r_outofedges += fa->numedges;
-		return;
-	}
-
-	c_faceclip++;
-
-// set up clip planes
-	pclip = NULL;
-
-	for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
-	{
-		if (clipflags & mask)
-		{
-			view_clipplanes[i].next = pclip;
-			pclip = &view_clipplanes[i];
-		}
-	}
-
-// push the edges through
-	r_emitted = 0;
-	r_nearzi = 0;
-	r_nearzionly = false;
-	makeleftedge = makerightedge = false;
-	pedges = currentmodel->edges;
-	r_lastvertvalid = false;
-
-	for (i=0 ; i<fa->numedges ; i++)
-	{
-		lindex = currentmodel->surfedges[fa->firstedge + i];
-
-		if (lindex > 0)
-		{
-			r_pedge = &pedges[lindex];
-
-		// if the edge is cached, we can just reuse the edge
-			if (!insubmodel)
-			{
-				if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
-				{
-					if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
-						r_framecount)
-					{
-						r_lastvertvalid = false;
-						continue;
-					}
-				}
-				else
-				{
-					if ((((uintptr)edge_p - (uintptr)r_edges) >
-						 r_pedge->cachededgeoffset) &&
-						(((edge_t *)((uintptr)r_edges +
-						 r_pedge->cachededgeoffset))->owner == r_pedge))
-					{
-						R_EmitCachedEdge ();
-						r_lastvertvalid = false;
-						continue;
-					}
-				}
-			}
-
-		// assume it's cacheable
-			cacheoffset = (byte *)edge_p - (byte *)r_edges;
-			r_leftclipped = r_rightclipped = false;
-			R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
-						&r_pcurrentvertbase[r_pedge->v[1]],
-						pclip);
-			r_pedge->cachededgeoffset = cacheoffset;
-
-			if (r_leftclipped)
-				makeleftedge = true;
-			if (r_rightclipped)
-				makerightedge = true;
-			r_lastvertvalid = true;
-		}
-		else
-		{
-			lindex = -lindex;
-			r_pedge = &pedges[lindex];
-		// if the edge is cached, we can just reuse the edge
-			if (!insubmodel)
-			{
-				if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
-				{
-					if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
-						r_framecount)
-					{
-						r_lastvertvalid = false;
-						continue;
-					}
-				}
-				else
-				{
-				// it's cached if the cached edge is valid and is owned
-				// by this medge_t
-					if ((((uintptr)edge_p - (uintptr)r_edges) >
-						 r_pedge->cachededgeoffset) &&
-						(((edge_t *)((uintptr)r_edges +
-						 r_pedge->cachededgeoffset))->owner == r_pedge))
-					{
-						R_EmitCachedEdge ();
-						r_lastvertvalid = false;
-						continue;
-					}
-				}
-			}
-
-		// assume it's cacheable
-			cacheoffset = (byte *)edge_p - (byte *)r_edges;
-			r_leftclipped = r_rightclipped = false;
-			R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
-						&r_pcurrentvertbase[r_pedge->v[0]],
-						pclip);
-			r_pedge->cachededgeoffset = cacheoffset;
-
-			if (r_leftclipped)
-				makeleftedge = true;
-			if (r_rightclipped)
-				makerightedge = true;
-			r_lastvertvalid = true;
-		}
-	}
-
-// if there was a clip off the left edge, add that edge too
-// FIXME: faster to do in screen space?
-// FIXME: share clipped edges?
-	if (makeleftedge)
-	{
-		r_pedge = &tedge;
-		r_lastvertvalid = false;
-		R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
-	}
-
-// if there was a clip off the right edge, get the right r_nearzi
-	if (makerightedge)
-	{
-		r_pedge = &tedge;
-		r_lastvertvalid = false;
-		r_nearzionly = true;
-		R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
-	}
-
-// if no edges made it out, return without posting the surface
-	if (!r_emitted)
-		return;
-
-	r_polycount++;
-
-	surface_p->msurf = fa;
-	surface_p->nearzi = r_nearzi;
-	surface_p->flags = fa->flags;
-	surface_p->insubmodel = insubmodel;
-	surface_p->spanstate = 0;
-	surface_p->entity = currententity;
-	surface_p->key = r_currentkey++;
-	surface_p->spans = NULL;
-
-	pplane = fa->plane;
-// FIXME: cache this?
-	TransformVector (pplane->normal, p_normal);
-// FIXME: cache this?
-	distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
-
-	surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
-	surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
-	surface_p->d_ziorigin = p_normal[2] * distinv -
-			xcenter * surface_p->d_zistepu -
-			ycenter * surface_p->d_zistepv;
-
-	surface_p++;
-}
-
-
-/*
-================
-R_RenderBmodelFace
-================
-*/
-void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
-{
-	int			i;
-	unsigned	mask;
-	mplane_t	*pplane;
-	float		distinv;
-	vec3_t		p_normal;
-	medge_t		tedge;
-	clipplane_t	*pclip;
-
-	if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
-	{
-		psurf->nextalphasurface = r_alpha_surfaces;
-		r_alpha_surfaces = psurf;
-		return;
-	}
-
-// skip out if no more surfs
-	if (surface_p >= surf_max)
-	{
-		r_outofsurfaces++;
-		return;
-	}
-
-// ditto if not enough edges left, or switch to auxedges if possible
-	if ((edge_p + psurf->numedges + 4) >= edge_max)
-	{
-		r_outofedges += psurf->numedges;
-		return;
-	}
-
-	c_faceclip++;
-
-// this is a dummy to give the caching mechanism someplace to write to
-	r_pedge = &tedge;
-
-// set up clip planes
-	pclip = NULL;
-
-	for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
-	{
-		if (r_clipflags & mask)
-		{
-			view_clipplanes[i].next = pclip;
-			pclip = &view_clipplanes[i];
-		}
-	}
-
-// push the edges through
-	r_emitted = 0;
-	r_nearzi = 0;
-	r_nearzionly = false;
-	makeleftedge = makerightedge = false;
-// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
-// can be used?
-	r_lastvertvalid = false;
-
-	for ( ; pedges ; pedges = pedges->pnext)
-	{
-		r_leftclipped = r_rightclipped = false;
-		R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
-
-		if (r_leftclipped)
-			makeleftedge = true;
-		if (r_rightclipped)
-			makerightedge = true;
-	}
-
-// if there was a clip off the left edge, add that edge too
-// FIXME: faster to do in screen space?
-// FIXME: share clipped edges?
-	if (makeleftedge)
-	{
-		r_pedge = &tedge;
-		R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
-	}
-
-// if there was a clip off the right edge, get the right r_nearzi
-	if (makerightedge)
-	{
-		r_pedge = &tedge;
-		r_nearzionly = true;
-		R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
-	}
-
-// if no edges made it out, return without posting the surface
-	if (!r_emitted)
-		return;
-
-	r_polycount++;
-
-	surface_p->msurf = psurf;
-	surface_p->nearzi = r_nearzi;
-	surface_p->flags = psurf->flags;
-	surface_p->insubmodel = true;
-	surface_p->spanstate = 0;
-	surface_p->entity = currententity;
-	surface_p->key = r_currentbkey;
-	surface_p->spans = NULL;
-
-	pplane = psurf->plane;
-// FIXME: cache this?
-	TransformVector (pplane->normal, p_normal);
-// FIXME: cache this?
-	distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
-
-	surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
-	surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
-	surface_p->d_ziorigin = p_normal[2] * distinv -
-			xcenter * surface_p->d_zistepu -
-			ycenter * surface_p->d_zistepv;
-
-	surface_p++;
-}
-
--- a/ref/r_scan.c
+++ /dev/null
@@ -1,560 +1,0 @@
-// Portable C scan-level rasterization code, all pixel depths.
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-unsigned char	*r_turb_pbase, *r_turb_pdest;
-fixed16_t		r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
-int				*r_turb_turb;
-int				r_turb_spancount;
-
-void D_DrawTurbulent8Span (void);
-
-
-/*
-=============
-D_WarpScreen
-
-this performs a slight compression of the screen at the same time as
-the sine warp, to keep the edges from wrapping
-=============
-*/
-void D_WarpScreen (void)
-{
-	int		w, h;
-	int		u,v, u2, v2;
-	byte	*dest;
-	int		*turb;
-	int		*col;
-	byte	**row;
-
-	static int	cached_width, cached_height;
-	static byte	*rowptr[1200+AMP2*2];
-	static int	column[1600+AMP2*2];
-
-	//
-	// these are constant over resolutions, and can be saved
-	//
-	w = r_newrefdef.width;
-	h = r_newrefdef.height;
-	if (w != cached_width || h != cached_height)
-	{
-		cached_width = w;
-		cached_height = h;
-		for (v=0 ; v<h+AMP2*2 ; v++)
-		{
-			v2 = (int)((float)v/(h + AMP2 * 2) * r_refdef.vrect.height);
-			rowptr[v] = r_warpbuffer + (WARP_WIDTH * v2);
-		}
-
-		for (u=0 ; u<w+AMP2*2 ; u++)
-		{
-			u2 = (int)((float)u/(w + AMP2 * 2) * r_refdef.vrect.width);
-			column[u] = u2;
-		}
-	}
-
-	turb = intsintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
-	dest = vid.buffer + r_newrefdef.y * vid.rowbytes + r_newrefdef.x;
-
-	for (v=0 ; v<h ; v++, dest += vid.rowbytes)
-	{
-		col = &column[turb[v]];
-		row = &rowptr[v];
-		for (u=0 ; u<w ; u+=4)
-		{
-			dest[u+0] = row[turb[u+0]][col[u+0]];
-			dest[u+1] = row[turb[u+1]][col[u+1]];
-			dest[u+2] = row[turb[u+2]][col[u+2]];
-			dest[u+3] = row[turb[u+3]][col[u+3]];
-		}
-	}
-}
-
-
-/*
-=============
-D_DrawTurbulent8Span
-=============
-*/
-void D_DrawTurbulent8Span (void)
-{
-	int		sturb, tturb;
-
-	do
-	{
-		sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
-		tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
-		*r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb);
-		r_turb_s += r_turb_sstep;
-		r_turb_t += r_turb_tstep;
-	} while (--r_turb_spancount > 0);
-}
-
-
-/*
-=============
-Turbulent8
-=============
-*/
-void Turbulent8 (espan_t *pspan)
-{
-	int				count;
-	fixed16_t		snext, tnext;
-	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
-	float			sdivz16stepu, tdivz16stepu, zi16stepu;
-	
-	r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
-
-	r_turb_sstep = 0;	// keep compiler happy
-	r_turb_tstep = 0;	// ditto
-
-	r_turb_pbase = (unsigned char *)cacheblock;
-
-	sdivz16stepu = d_sdivzstepu * 16;
-	tdivz16stepu = d_tdivzstepu * 16;
-	zi16stepu = d_zistepu * 16;
-
-	do
-	{
-		r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
-				(r_screenwidth * pspan->v) + pspan->u);
-
-		count = pspan->count;
-
-	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
-		du = (float)pspan->u;
-		dv = (float)pspan->v;
-
-		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
-		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
-		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
-		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
-
-		r_turb_s = (int)(sdivz * z) + sadjust;
-		if (r_turb_s > bbextents)
-			r_turb_s = bbextents;
-		else if (r_turb_s < 0)
-			r_turb_s = 0;
-
-		r_turb_t = (int)(tdivz * z) + tadjust;
-		if (r_turb_t > bbextentt)
-			r_turb_t = bbextentt;
-		else if (r_turb_t < 0)
-			r_turb_t = 0;
-
-		do
-		{
-		// calculate s and t at the far end of the span
-			if (count >= 16)
-				r_turb_spancount = 16;
-			else
-				r_turb_spancount = count;
-
-			count -= r_turb_spancount;
-
-			if (count)
-			{
-			// calculate s/z, t/z, zi->fixed s and t at far end of span,
-			// calculate s and t steps across span by shifting
-				sdivz += sdivz16stepu;
-				tdivz += tdivz16stepu;
-				zi += zi16stepu;
-				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
-
-				snext = (int)(sdivz * z) + sadjust;
-				if (snext > bbextents)
-					snext = bbextents;
-				else if (snext < 16)
-					snext = 16;	// prevent round-off error on <0 steps from
-								//  from causing overstepping & running off the
-								//  edge of the texture
-
-				tnext = (int)(tdivz * z) + tadjust;
-				if (tnext > bbextentt)
-					tnext = bbextentt;
-				else if (tnext < 16)
-					tnext = 16;	// guard against round-off error on <0 steps
-
-				r_turb_sstep = (snext - r_turb_s) >> 4;
-				r_turb_tstep = (tnext - r_turb_t) >> 4;
-			}
-			else
-			{
-			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
-			// can't step off polygon), clamp, calculate s and t steps across
-			// span by division, biasing steps low so we don't run off the
-			// texture
-				spancountminus1 = (float)(r_turb_spancount - 1);
-				sdivz += d_sdivzstepu * spancountminus1;
-				tdivz += d_tdivzstepu * spancountminus1;
-				zi += d_zistepu * spancountminus1;
-				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
-				snext = (int)(sdivz * z) + sadjust;
-				if (snext > bbextents)
-					snext = bbextents;
-				else if (snext < 16)
-					snext = 16;	// prevent round-off error on <0 steps from
-								//  from causing overstepping & running off the
-								//  edge of the texture
-
-				tnext = (int)(tdivz * z) + tadjust;
-				if (tnext > bbextentt)
-					tnext = bbextentt;
-				else if (tnext < 16)
-					tnext = 16;	// guard against round-off error on <0 steps
-
-				if (r_turb_spancount > 1)
-				{
-					r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
-					r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
-				}
-			}
-
-			r_turb_s = r_turb_s & ((CYCLE<<16)-1);
-			r_turb_t = r_turb_t & ((CYCLE<<16)-1);
-
-			D_DrawTurbulent8Span ();
-
-			r_turb_s = snext;
-			r_turb_t = tnext;
-
-		} while (count > 0);
-
-	} while ((pspan = pspan->pnext) != NULL);
-}
-
-//====================
-//PGM
-/*
-=============
-NonTurbulent8 - this is for drawing scrolling textures. they're warping water textures
-	but the turbulence is automatically 0.
-=============
-*/
-void NonTurbulent8 (espan_t *pspan)
-{
-	int				count;
-	fixed16_t		snext, tnext;
-	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
-	float			sdivz16stepu, tdivz16stepu, zi16stepu;
-	
-//	r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
-	r_turb_turb = blanktable;
-
-	r_turb_sstep = 0;	// keep compiler happy
-	r_turb_tstep = 0;	// ditto
-
-	r_turb_pbase = (unsigned char *)cacheblock;
-
-	sdivz16stepu = d_sdivzstepu * 16;
-	tdivz16stepu = d_tdivzstepu * 16;
-	zi16stepu = d_zistepu * 16;
-
-	do
-	{
-		r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
-				(r_screenwidth * pspan->v) + pspan->u);
-
-		count = pspan->count;
-
-	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
-		du = (float)pspan->u;
-		dv = (float)pspan->v;
-
-		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
-		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
-		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
-		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
-
-		r_turb_s = (int)(sdivz * z) + sadjust;
-		if (r_turb_s > bbextents)
-			r_turb_s = bbextents;
-		else if (r_turb_s < 0)
-			r_turb_s = 0;
-
-		r_turb_t = (int)(tdivz * z) + tadjust;
-		if (r_turb_t > bbextentt)
-			r_turb_t = bbextentt;
-		else if (r_turb_t < 0)
-			r_turb_t = 0;
-
-		do
-		{
-		// calculate s and t at the far end of the span
-			if (count >= 16)
-				r_turb_spancount = 16;
-			else
-				r_turb_spancount = count;
-
-			count -= r_turb_spancount;
-
-			if (count)
-			{
-			// calculate s/z, t/z, zi->fixed s and t at far end of span,
-			// calculate s and t steps across span by shifting
-				sdivz += sdivz16stepu;
-				tdivz += tdivz16stepu;
-				zi += zi16stepu;
-				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
-
-				snext = (int)(sdivz * z) + sadjust;
-				if (snext > bbextents)
-					snext = bbextents;
-				else if (snext < 16)
-					snext = 16;	// prevent round-off error on <0 steps from
-								//  from causing overstepping & running off the
-								//  edge of the texture
-
-				tnext = (int)(tdivz * z) + tadjust;
-				if (tnext > bbextentt)
-					tnext = bbextentt;
-				else if (tnext < 16)
-					tnext = 16;	// guard against round-off error on <0 steps
-
-				r_turb_sstep = (snext - r_turb_s) >> 4;
-				r_turb_tstep = (tnext - r_turb_t) >> 4;
-			}
-			else
-			{
-			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
-			// can't step off polygon), clamp, calculate s and t steps across
-			// span by division, biasing steps low so we don't run off the
-			// texture
-				spancountminus1 = (float)(r_turb_spancount - 1);
-				sdivz += d_sdivzstepu * spancountminus1;
-				tdivz += d_tdivzstepu * spancountminus1;
-				zi += d_zistepu * spancountminus1;
-				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
-				snext = (int)(sdivz * z) + sadjust;
-				if (snext > bbextents)
-					snext = bbextents;
-				else if (snext < 16)
-					snext = 16;	// prevent round-off error on <0 steps from
-								//  from causing overstepping & running off the
-								//  edge of the texture
-
-				tnext = (int)(tdivz * z) + tadjust;
-				if (tnext > bbextentt)
-					tnext = bbextentt;
-				else if (tnext < 16)
-					tnext = 16;	// guard against round-off error on <0 steps
-
-				if (r_turb_spancount > 1)
-				{
-					r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
-					r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
-				}
-			}
-
-			r_turb_s = r_turb_s & ((CYCLE<<16)-1);
-			r_turb_t = r_turb_t & ((CYCLE<<16)-1);
-
-			D_DrawTurbulent8Span ();
-
-			r_turb_s = snext;
-			r_turb_t = tnext;
-
-		} while (count > 0);
-
-	} while ((pspan = pspan->pnext) != NULL);
-}
-//PGM
-//====================
-
-
-/*
-=============
-D_DrawSpans16
-
-  FIXME: actually make this subdivide by 16 instead of 8!!!
-=============
-*/
-void D_DrawSpans16 (espan_t *pspan)
-{
-	int				count, spancount;
-	unsigned char	*pbase, *pdest;
-	fixed16_t		s, t, snext, tnext, sstep, tstep;
-	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
-	float			sdivz8stepu, tdivz8stepu, zi8stepu;
-
-	sstep = 0;	// keep compiler happy
-	tstep = 0;	// ditto
-
-	pbase = (unsigned char *)cacheblock;
-
-	sdivz8stepu = d_sdivzstepu * 8;
-	tdivz8stepu = d_tdivzstepu * 8;
-	zi8stepu = d_zistepu * 8;
-
-	do
-	{
-		pdest = (unsigned char *)((byte *)d_viewbuffer +
-				(r_screenwidth * pspan->v) + pspan->u);
-
-		count = pspan->count;
-
-	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
-		du = (float)pspan->u;
-		dv = (float)pspan->v;
-
-		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
-		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
-		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
-		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
-
-		s = (int)(sdivz * z) + sadjust;
-		if (s > bbextents)
-			s = bbextents;
-		else if (s < 0)
-			s = 0;
-
-		t = (int)(tdivz * z) + tadjust;
-		if (t > bbextentt)
-			t = bbextentt;
-		else if (t < 0)
-			t = 0;
-
-		do
-		{
-		// calculate s and t at the far end of the span
-			if (count >= 8)
-				spancount = 8;
-			else
-				spancount = count;
-
-			count -= spancount;
-
-			if (count)
-			{
-			// calculate s/z, t/z, zi->fixed s and t at far end of span,
-			// calculate s and t steps across span by shifting
-				sdivz += sdivz8stepu;
-				tdivz += tdivz8stepu;
-				zi += zi8stepu;
-				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
-
-				snext = (int)(sdivz * z) + sadjust;
-				if (snext > bbextents)
-					snext = bbextents;
-				else if (snext < 8)
-					snext = 8;	// prevent round-off error on <0 steps from
-								//  from causing overstepping & running off the
-								//  edge of the texture
-
-				tnext = (int)(tdivz * z) + tadjust;
-				if (tnext > bbextentt)
-					tnext = bbextentt;
-				else if (tnext < 8)
-					tnext = 8;	// guard against round-off error on <0 steps
-
-				sstep = (snext - s) >> 3;
-				tstep = (tnext - t) >> 3;
-			}
-			else
-			{
-			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
-			// can't step off polygon), clamp, calculate s and t steps across
-			// span by division, biasing steps low so we don't run off the
-			// texture
-				spancountminus1 = (float)(spancount - 1);
-				sdivz += d_sdivzstepu * spancountminus1;
-				tdivz += d_tdivzstepu * spancountminus1;
-				zi += d_zistepu * spancountminus1;
-				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
-				snext = (int)(sdivz * z) + sadjust;
-				if (snext > bbextents)
-					snext = bbextents;
-				else if (snext < 8)
-					snext = 8;	// prevent round-off error on <0 steps from
-								//  from causing overstepping & running off the
-								//  edge of the texture
-
-				tnext = (int)(tdivz * z) + tadjust;
-				if (tnext > bbextentt)
-					tnext = bbextentt;
-				else if (tnext < 8)
-					tnext = 8;	// guard against round-off error on <0 steps
-
-				if (spancount > 1)
-				{
-					sstep = (snext - s) / (spancount - 1);
-					tstep = (tnext - t) / (spancount - 1);
-				}
-			}
-
-			do
-			{
-				*pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
-				s += sstep;
-				t += tstep;
-			} while (--spancount > 0);
-
-			s = snext;
-			t = tnext;
-
-		} while (count > 0);
-
-	} while ((pspan = pspan->pnext) != NULL);
-}
-
-
-/*
-=============
-D_DrawZSpans
-=============
-*/
-void D_DrawZSpans (espan_t *pspan)
-{
-	int				count, doublecount, izistep;
-	int				izi;
-	short			*pdest;
-	unsigned		ltemp;
-	float			zi;
-	float			du, dv;
-
-// FIXME: check for clamping/range problems
-// we count on FP exceptions being turned off to avoid range problems
-	izistep = (int)(d_zistepu * 0x8000 * 0x10000);
-
-	do
-	{
-		pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
-
-		count = pspan->count;
-
-	// calculate the initial 1/z
-		du = (float)pspan->u;
-		dv = (float)pspan->v;
-
-		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
-	// we count on FP exceptions being turned off to avoid range problems
-		izi = (int)(zi * 0x8000 * 0x10000);
-
-		if ((uintptr)pdest & 0x02)
-		{
-			*pdest++ = (short)(izi >> 16);
-			izi += izistep;
-			count--;
-		}
-
-		if ((doublecount = count >> 1) > 0)
-		{
-			do
-			{
-				ltemp = izi >> 16;
-				izi += izistep;
-				ltemp |= izi & 0xFFFF0000;
-				izi += izistep;
-				*(int *)pdest = ltemp;
-				pdest += 2;
-			} while (--doublecount > 0);
-		}
-
-		if (count & 1)
-			*pdest = (short)(izi >> 16);
-
-	} while ((pspan = pspan->pnext) != NULL);
-}
--- a/ref/r_sprite.c
+++ /dev/null
@@ -1,106 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-extern polydesc_t r_polydesc;
-
-void R_BuildPolygonFromSurface(msurface_t *fa);
-void R_PolygonCalculateGradients (void);
-
-extern void R_PolyChooseSpanletRoutine( float alpha, qboolean isturbulent );
-
-extern vec5_t r_clip_verts[2][MAXWORKINGVERTS+2];
-
-extern void	R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured );
-
-/*
-** R_DrawSprite
-**
-** Draw currententity / currentmodel as a single texture
-** mapped polygon
-*/
-void R_DrawSprite (void)
-{
-	vec5_t		*pverts;
-	vec3_t		left, up, right, down;
-	dsprite_t	*s_psprite;
-	dsprframe_t	*s_psprframe;
-
-
-	s_psprite = (dsprite_t *)currentmodel->extradata;
-/*
-	if (currententity->frame >= s_psprite->numframes
-		|| currententity->frame < 0)
-	{
-		ri.Con_Printf (PRINT_ALL, "No such sprite frame %i\n", 
-			currententity->frame);
-		currententity->frame = 0;
-	}
-*/
-	currententity->frame %= s_psprite->numframes;
-
-	s_psprframe = &s_psprite->frames[currententity->frame];
-
-	r_polydesc.pixels       = currentmodel->skins[currententity->frame]->pixels[0];
-	r_polydesc.pixel_width  = s_psprframe->width;
-	r_polydesc.pixel_height = s_psprframe->height;
-	r_polydesc.dist         = 0;
-
-	// generate the sprite's axes, completely parallel to the viewplane.
-	VectorCopy (vup, r_polydesc.vup);
-	VectorCopy (vright, r_polydesc.vright);
-	VectorCopy (vpn, r_polydesc.vpn);
-
-// build the sprite poster in worldspace
-	VectorScale (r_polydesc.vright, 
-		s_psprframe->width - s_psprframe->origin_x, right);
-	VectorScale (r_polydesc.vup, 
-		s_psprframe->height - s_psprframe->origin_y, up);
-	VectorScale (r_polydesc.vright,
-		-s_psprframe->origin_x, left);
-	VectorScale (r_polydesc.vup,
-		-s_psprframe->origin_y, down);
-
-	// invert UP vector for sprites
-	VectorInverse( r_polydesc.vup );
-
-	pverts = r_clip_verts[0];
-
-	pverts[0][0] = r_entorigin[0] + up[0] + left[0];
-	pverts[0][1] = r_entorigin[1] + up[1] + left[1];
-	pverts[0][2] = r_entorigin[2] + up[2] + left[2];
-	pverts[0][3] = 0;
-	pverts[0][4] = 0;
-
-	pverts[1][0] = r_entorigin[0] + up[0] + right[0];
-	pverts[1][1] = r_entorigin[1] + up[1] + right[1];
-	pverts[1][2] = r_entorigin[2] + up[2] + right[2];
-	pverts[1][3] = s_psprframe->width;
-	pverts[1][4] = 0;
-
-	pverts[2][0] = r_entorigin[0] + down[0] + right[0];
-	pverts[2][1] = r_entorigin[1] + down[1] + right[1];
-	pverts[2][2] = r_entorigin[2] + down[2] + right[2];
-	pverts[2][3] = s_psprframe->width;
-	pverts[2][4] = s_psprframe->height;
-
-	pverts[3][0] = r_entorigin[0] + down[0] + left[0];
-	pverts[3][1] = r_entorigin[1] + down[1] + left[1];
-	pverts[3][2] = r_entorigin[2] + down[2] + left[2];
-	pverts[3][3] = 0;
-	pverts[3][4] = s_psprframe->height;
-
-	r_polydesc.nump = 4;
-	r_polydesc.s_offset = ( r_polydesc.pixel_width  >> 1);
-	r_polydesc.t_offset = ( r_polydesc.pixel_height >> 1);
-	VectorCopy( modelorg, r_polydesc.viewer_position );
-
-	r_polydesc.stipple_parity = 1;
-	if ( currententity->flags & RF_TRANSLUCENT )
-		R_ClipAndDrawPoly ( currententity->alpha, false, true );
-	else
-		R_ClipAndDrawPoly ( 1.0F, false, true );
-	r_polydesc.stipple_parity = 0;
-}
-
--- a/ref/r_surf.c
+++ /dev/null
@@ -1,632 +1,0 @@
-// r_surf.c: surface-related refresh code
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-drawsurf_t	r_drawsurf;
-
-int				lightleft, sourcesstep, blocksize, sourcetstep;
-int				lightdelta, lightdeltastep;
-int				lightright, lightleftstep, lightrightstep, blockdivshift;
-unsigned		blockdivmask;
-void			*prowdestbase;
-unsigned char	*pbasesource;
-int				surfrowbytes;	// used by ASM files
-unsigned		*r_lightptr;
-int				r_stepback;
-int				r_lightwidth;
-int				r_numhblocks, r_numvblocks;
-unsigned char	*r_source, *r_sourcemax;
-
-void R_DrawSurfaceBlock8_mip0 (void);
-void R_DrawSurfaceBlock8_mip1 (void);
-void R_DrawSurfaceBlock8_mip2 (void);
-void R_DrawSurfaceBlock8_mip3 (void);
-
-static void	(*surfmiptable[4])(void) = {
-	R_DrawSurfaceBlock8_mip0,
-	R_DrawSurfaceBlock8_mip1,
-	R_DrawSurfaceBlock8_mip2,
-	R_DrawSurfaceBlock8_mip3
-};
-
-void R_BuildLightMap (void);
-extern	unsigned		blocklights[1024];	// allow some very large lightmaps
-
-float           surfscale;
-qboolean        r_cache_thrash;         // set if surface cache is thrashing
-
-int         sc_size;
-surfcache_t	*sc_rover, *sc_base;
-
-/*
-===============
-R_TextureAnimation
-
-Returns the proper texture for a given time and base texture
-===============
-*/
-image_t *R_TextureAnimation (mtexinfo_t *tex)
-{
-	int		c;
-
-	if (!tex->next)
-		return tex->image;
-
-	c = currententity->frame % tex->numframes;
-	while (c)
-	{
-		tex = tex->next;
-		c--;
-	}
-
-	return tex->image;
-}
-
-
-/*
-===============
-R_DrawSurface
-===============
-*/
-void R_DrawSurface (void)
-{
-	unsigned char	*basetptr;
-	int				smax, tmax, twidth;
-	int				u;
-	int				soffset, basetoffset, texwidth;
-	int				horzblockstep;
-	unsigned char	*pcolumndest;
-	void			(*pblockdrawer)(void);
-	image_t			*mt;
-
-	surfrowbytes = r_drawsurf.rowbytes;
-
-	mt = r_drawsurf.image;
-	
-	r_source = mt->pixels[r_drawsurf.surfmip];
-	
-// the fractional light values should range from 0 to (VID_GRADES - 1) << 16
-// from a source range of 0 - 255
-	
-	texwidth = mt->width >> r_drawsurf.surfmip;
-
-	blocksize = 16 >> r_drawsurf.surfmip;
-	blockdivshift = 4 - r_drawsurf.surfmip;
-	blockdivmask = (1 << blockdivshift) - 1;
-	
-	r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1;
-
-	r_numhblocks = r_drawsurf.surfwidth >> blockdivshift;
-	r_numvblocks = r_drawsurf.surfheight >> blockdivshift;
-
-//==============================
-
-	pblockdrawer = surfmiptable[r_drawsurf.surfmip];
-// TODO: only needs to be set when there is a display settings change
-	horzblockstep = blocksize;
-
-	smax = mt->width >> r_drawsurf.surfmip;
-	twidth = texwidth;
-	tmax = mt->height >> r_drawsurf.surfmip;
-	sourcetstep = texwidth;
-	r_stepback = tmax * twidth;
-
-	r_sourcemax = r_source + (tmax * smax);
-
-	soffset = r_drawsurf.surf->texturemins[0];
-	basetoffset = r_drawsurf.surf->texturemins[1];
-
-// << 16 components are to guarantee positive values for %
-	soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax;
-	basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip) 
-		+ (tmax << 16)) % tmax) * twidth)];
-
-	pcolumndest = r_drawsurf.surfdat;
-
-	for (u=0 ; u<r_numhblocks; u++)
-	{
-		r_lightptr = blocklights + u;
-
-		prowdestbase = pcolumndest;
-
-		pbasesource = basetptr + soffset;
-
-		(*pblockdrawer)();
-
-		soffset = soffset + blocksize;
-		if (soffset >= smax)
-			soffset = 0;
-
-		pcolumndest += horzblockstep;
-	}
-}
-
-
-//=============================================================================
-
-
-/*
-================
-R_DrawSurfaceBlock8_mip0
-================
-*/
-void R_DrawSurfaceBlock8_mip0 (void)
-{
-	int				v, i, b, lightstep, lighttemp, light;
-	unsigned char	pix, *psource, *prowdest;
-
-	psource = pbasesource;
-	prowdest = prowdestbase;
-
-	for (v=0 ; v<r_numvblocks ; v++)
-	{
-	// FIXME: make these locals?
-	// FIXME: use delta rather than both right and left, like ASM?
-		lightleft = r_lightptr[0];
-		lightright = r_lightptr[1];
-		r_lightptr += r_lightwidth;
-		lightleftstep = (r_lightptr[0] - lightleft) >> 4;
-		lightrightstep = (r_lightptr[1] - lightright) >> 4;
-
-		for (i=0 ; i<16 ; i++)
-		{
-			lighttemp = lightleft - lightright;
-			lightstep = lighttemp >> 4;
-
-			light = lightright;
-
-			for (b=15; b>=0; b--)
-			{
-				pix = psource[b];
-				prowdest[b] = ((unsigned char *)vid.colormap)
-						[(light & 0xFF00) + pix];
-				light += lightstep;
-			}
-	
-			psource += sourcetstep;
-			lightright += lightrightstep;
-			lightleft += lightleftstep;
-			prowdest += surfrowbytes;
-		}
-
-		if (psource >= r_sourcemax)
-			psource -= r_stepback;
-	}
-}
-
-
-/*
-================
-R_DrawSurfaceBlock8_mip1
-================
-*/
-void R_DrawSurfaceBlock8_mip1 (void)
-{
-	int				v, i, b, lightstep, lighttemp, light;
-	unsigned char	pix, *psource, *prowdest;
-
-	psource = pbasesource;
-	prowdest = prowdestbase;
-
-	for (v=0 ; v<r_numvblocks ; v++)
-	{
-	// FIXME: make these locals?
-	// FIXME: use delta rather than both right and left, like ASM?
-		lightleft = r_lightptr[0];
-		lightright = r_lightptr[1];
-		r_lightptr += r_lightwidth;
-		lightleftstep = (r_lightptr[0] - lightleft) >> 3;
-		lightrightstep = (r_lightptr[1] - lightright) >> 3;
-
-		for (i=0 ; i<8 ; i++)
-		{
-			lighttemp = lightleft - lightright;
-			lightstep = lighttemp >> 3;
-
-			light = lightright;
-
-			for (b=7; b>=0; b--)
-			{
-				pix = psource[b];
-				prowdest[b] = ((unsigned char *)vid.colormap)
-						[(light & 0xFF00) + pix];
-				light += lightstep;
-			}
-	
-			psource += sourcetstep;
-			lightright += lightrightstep;
-			lightleft += lightleftstep;
-			prowdest += surfrowbytes;
-		}
-
-		if (psource >= r_sourcemax)
-			psource -= r_stepback;
-	}
-}
-
-
-/*
-================
-R_DrawSurfaceBlock8_mip2
-================
-*/
-void R_DrawSurfaceBlock8_mip2 (void)
-{
-	int				v, i, b, lightstep, lighttemp, light;
-	unsigned char	pix, *psource, *prowdest;
-
-	psource = pbasesource;
-	prowdest = prowdestbase;
-
-	for (v=0 ; v<r_numvblocks ; v++)
-	{
-	// FIXME: make these locals?
-	// FIXME: use delta rather than both right and left, like ASM?
-		lightleft = r_lightptr[0];
-		lightright = r_lightptr[1];
-		r_lightptr += r_lightwidth;
-		lightleftstep = (r_lightptr[0] - lightleft) >> 2;
-		lightrightstep = (r_lightptr[1] - lightright) >> 2;
-
-		for (i=0 ; i<4 ; i++)
-		{
-			lighttemp = lightleft - lightright;
-			lightstep = lighttemp >> 2;
-
-			light = lightright;
-
-			for (b=3; b>=0; b--)
-			{
-				pix = psource[b];
-				prowdest[b] = ((unsigned char *)vid.colormap)
-						[(light & 0xFF00) + pix];
-				light += lightstep;
-			}
-	
-			psource += sourcetstep;
-			lightright += lightrightstep;
-			lightleft += lightleftstep;
-			prowdest += surfrowbytes;
-		}
-
-		if (psource >= r_sourcemax)
-			psource -= r_stepback;
-	}
-}
-
-
-/*
-================
-R_DrawSurfaceBlock8_mip3
-================
-*/
-void R_DrawSurfaceBlock8_mip3 (void)
-{
-	int				v, i, b, lightstep, lighttemp, light;
-	unsigned char	pix, *psource, *prowdest;
-
-	psource = pbasesource;
-	prowdest = prowdestbase;
-
-	for (v=0 ; v<r_numvblocks ; v++)
-	{
-	// FIXME: make these locals?
-	// FIXME: use delta rather than both right and left, like ASM?
-		lightleft = r_lightptr[0];
-		lightright = r_lightptr[1];
-		r_lightptr += r_lightwidth;
-		lightleftstep = (r_lightptr[0] - lightleft) >> 1;
-		lightrightstep = (r_lightptr[1] - lightright) >> 1;
-
-		for (i=0 ; i<2 ; i++)
-		{
-			lighttemp = lightleft - lightright;
-			lightstep = lighttemp >> 1;
-
-			light = lightright;
-
-			for (b=1; b>=0; b--)
-			{
-				pix = psource[b];
-				prowdest[b] = ((unsigned char *)vid.colormap)
-						[(light & 0xFF00) + pix];
-				light += lightstep;
-			}
-	
-			psource += sourcetstep;
-			lightright += lightrightstep;
-			lightleft += lightleftstep;
-			prowdest += surfrowbytes;
-		}
-
-		if (psource >= r_sourcemax)
-			psource -= r_stepback;
-	}
-}
-
-
-//============================================================================
-
-
-/*
-================
-R_InitCaches
-
-================
-*/
-void R_InitCaches (void)
-{
-	int		size;
-	int		pix;
-
-	// calculate size to allocate
-	if (sw_surfcacheoverride->value)
-	{
-		size = sw_surfcacheoverride->value;
-	}
-	else
-	{
-		size = SURFCACHE_SIZE_AT_320X240;
-
-		pix = vid.width*vid.height;
-		if (pix > 64000)
-			size += (pix-64000)*3;
-	}		
-
-	// round up to page size
-	size = (size + 8191) & ~8191;
-
-	ri.Con_Printf (PRINT_ALL,"%ik surface cache\n", size/1024);
-
-	sc_size = size;
-	sc_base = (surfcache_t *)malloc(size);
-	sc_rover = sc_base;
-	
-	sc_base->next = NULL;
-	sc_base->owner = NULL;
-	sc_base->size = sc_size;
-}
-
-
-/*
-==================
-D_FlushCaches
-==================
-*/
-void D_FlushCaches (void)
-{
-	surfcache_t     *c;
-	
-	if (!sc_base)
-		return;
-
-	for (c = sc_base ; c ; c = c->next)
-	{
-		if (c->owner)
-			*c->owner = NULL;
-	}
-	
-	sc_rover = sc_base;
-	sc_base->next = NULL;
-	sc_base->owner = NULL;
-	sc_base->size = sc_size;
-}
-
-/*
-=================
-D_SCAlloc
-=================
-*/
-surfcache_t     *D_SCAlloc (int width, int size)
-{
-	surfcache_t             *new;
-	qboolean                wrapped_this_time;
-
-	if ((width < 0) || (width > 256))
-		ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache width %d\n", width);
-
-	if ((size <= 0) || (size > 0x10000))
-		ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache size %d\n", size);
-	
-	size = (int)(uintptr)&((surfcache_t *)0)->data[size];
-	size = (size + 3) & ~3;
-	if (size > sc_size)
-		ri.Sys_Error (ERR_FATAL,"D_SCAlloc: %i > cache size of %i",size, sc_size);
-
-// if there is not size bytes after the rover, reset to the start
-	wrapped_this_time = false;
-
-	if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size)
-	{
-		if (sc_rover)
-		{
-			wrapped_this_time = true;
-		}
-		sc_rover = sc_base;
-	}
-		
-// colect and free surfcache_t blocks until the rover block is large enough
-	new = sc_rover;
-	if (sc_rover->owner)
-		*sc_rover->owner = NULL;
-	
-	while (new->size < size)
-	{
-	// free another
-		sc_rover = sc_rover->next;
-		if (!sc_rover)
-			ri.Sys_Error (ERR_FATAL,"D_SCAlloc: hit the end of memory");
-		if (sc_rover->owner)
-			*sc_rover->owner = NULL;
-			
-		new->size += sc_rover->size;
-		new->next = sc_rover->next;
-	}
-
-// create a fragment out of any leftovers
-	if (new->size - size > 256)
-	{
-		sc_rover = (surfcache_t *)( (byte *)new + size);
-		sc_rover->size = new->size - size;
-		sc_rover->next = new->next;
-		sc_rover->width = 0;
-		sc_rover->owner = NULL;
-		new->next = sc_rover;
-		new->size = size;
-	}
-	else
-		sc_rover = new->next;
-	
-	new->width = width;
-// DEBUG
-	if (width > 0)
-		new->height = (size - sizeof(*new) + sizeof(new->data)) / width;
-
-	new->owner = NULL;              // should be set properly after return
-
-	if (d_roverwrapped)
-	{
-		if (wrapped_this_time || (sc_rover >= d_initial_rover))
-			r_cache_thrash = true;
-	}
-	else if (wrapped_this_time)
-	{       
-		d_roverwrapped = true;
-	}
-
-	return new;
-}
-
-
-/*
-=================
-D_SCDump
-=================
-*/
-void D_SCDump (void)
-{
-	surfcache_t             *test;
-
-	for (test = sc_base ; test ; test = test->next)
-	{
-		if (test == sc_rover)
-			ri.Con_Printf (PRINT_ALL,"ROVER:\n");
-		ri.Con_Printf (PRINT_ALL,"%p : %i bytes     %i width\n",test, test->size, test->width);
-	}
-}
-
-//=============================================================================
-
-// if the num is not a power of 2, assume it will not repeat
-
-int     MaskForNum (int num)
-{
-	if (num==128)
-		return 127;
-	if (num==64)
-		return 63;
-	if (num==32)
-		return 31;
-	if (num==16)
-		return 15;
-	return 255;
-}
-
-int D_log2 (int num)
-{
-	int     c;
-	
-	c = 0;
-	
-	while (num>>=1)
-		c++;
-	return c;
-}
-
-//=============================================================================
-
-/*
-================
-D_CacheSurface
-================
-*/
-surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
-{
-	surfcache_t     *cache;
-
-//
-// if the surface is animating or flashing, flush the cache
-//
-	r_drawsurf.image = R_TextureAnimation (surface->texinfo);
-	r_drawsurf.lightadj[0] = r_newrefdef.lightstyles[surface->styles[0]].white*128;
-	r_drawsurf.lightadj[1] = r_newrefdef.lightstyles[surface->styles[1]].white*128;
-	r_drawsurf.lightadj[2] = r_newrefdef.lightstyles[surface->styles[2]].white*128;
-	r_drawsurf.lightadj[3] = r_newrefdef.lightstyles[surface->styles[3]].white*128;
-	
-//
-// see if the cache holds apropriate data
-//
-	cache = surface->cachespots[miplevel];
-
-	if (cache && !cache->dlight && surface->dlightframe != r_framecount
-			&& cache->image == r_drawsurf.image
-			&& cache->lightadj[0] == r_drawsurf.lightadj[0]
-			&& cache->lightadj[1] == r_drawsurf.lightadj[1]
-			&& cache->lightadj[2] == r_drawsurf.lightadj[2]
-			&& cache->lightadj[3] == r_drawsurf.lightadj[3] )
-		return cache;
-
-//
-// determine shape of surface
-//
-	surfscale = 1.0 / (1<<miplevel);
-	r_drawsurf.surfmip = miplevel;
-	r_drawsurf.surfwidth = surface->extents[0] >> miplevel;
-	r_drawsurf.rowbytes = r_drawsurf.surfwidth;
-	r_drawsurf.surfheight = surface->extents[1] >> miplevel;
-	
-//
-// allocate memory if needed
-//
-	if (!cache)     // if a texture just animated, don't reallocate it
-	{
-		cache = D_SCAlloc (r_drawsurf.surfwidth,
-						   r_drawsurf.surfwidth * r_drawsurf.surfheight);
-		surface->cachespots[miplevel] = cache;
-		cache->owner = &surface->cachespots[miplevel];
-		cache->mipscale = surfscale;
-	}
-	
-	if (surface->dlightframe == r_framecount)
-		cache->dlight = 1;
-	else
-		cache->dlight = 0;
-
-	r_drawsurf.surfdat = (pixel_t *)cache->data;
-	
-	cache->image = r_drawsurf.image;
-	cache->lightadj[0] = r_drawsurf.lightadj[0];
-	cache->lightadj[1] = r_drawsurf.lightadj[1];
-	cache->lightadj[2] = r_drawsurf.lightadj[2];
-	cache->lightadj[3] = r_drawsurf.lightadj[3];
-
-//
-// draw and light the surface texture
-//
-	r_drawsurf.surf = surface;
-
-	c_surf++;
-
-	// calculate the lightings
-	R_BuildLightMap ();
-	
-	// rasterize the surface into the cache
-	R_DrawSurface ();
-
-	return cache;
-}
-
-
--- a/ref/rand1k.h
+++ /dev/null
@@ -1,104 +1,0 @@
-// 1K random numbers in the range 0-255
-0, 144, 49, 207, 149, 122, 89, 229, 210, 191,
-44, 219, 181, 131, 77, 3, 23, 93, 37, 42,
-253, 114, 30, 1, 2, 96, 136, 146, 154, 155,
-42, 169, 115, 90, 14, 155, 200, 205, 133, 77,
-224, 186, 244, 236, 138, 36, 118, 60, 220, 53,
-199, 215, 255, 255, 156, 100, 68, 76, 215, 6,
-96, 23, 173, 14, 2, 235, 70, 69, 150, 176,
-214, 185, 124, 52, 190, 119, 117, 242, 190, 27,
-153, 98, 188, 155, 146, 92, 38, 57, 108, 205,
-132, 253, 192, 88, 43, 168, 125, 16, 179, 129,
-37, 243, 36, 231, 177, 77, 109, 18, 247, 174,
-39, 224, 210, 149, 48, 45, 209, 121, 39, 129,
-187, 103, 71, 145, 174, 193, 184, 121, 31, 94,
-213, 8, 132, 169, 109, 26, 243, 235, 140, 88,
-120, 95, 216, 81, 116, 69, 251, 76, 189, 145,
-50, 194, 214, 101, 128, 227, 7, 254, 146, 12,
-136, 49, 215, 160, 168, 50, 215, 31, 28, 190,
-80, 240, 73, 86, 35, 187, 213, 181, 153, 191,
-64, 36, 0, 15, 206, 218, 53, 29, 141, 3,
-29, 116, 192, 175, 139, 18, 111, 51, 178, 74,
-111, 59, 147, 136, 160, 41, 129, 246, 178, 236,
-48, 86, 45, 254, 117, 255, 24, 160, 24, 112,
-238, 12, 229, 74, 58, 196, 105, 51, 160, 154,
-115, 119, 153, 162, 218, 212, 159, 184, 144, 96,
-47, 188, 142, 231, 62, 48, 154, 178, 149, 89,
-126, 20, 189, 156, 158, 176, 205, 38, 147, 222,
-233, 157, 186, 11, 170, 249, 80, 145, 78, 44,
-27, 222, 217, 190, 39, 83, 20, 19, 164, 209,
-139, 114, 104, 76, 119, 128, 39, 82, 188, 80,
-211, 245, 223, 185, 76, 241, 32, 16, 200, 134,
-156, 244, 18, 224, 167, 82, 26, 129, 58, 74,
-235, 141, 169, 29, 126, 97, 127, 203, 130, 97,
-176, 136, 155, 101, 1, 181, 25, 159, 220, 125,
-191, 127, 97, 201, 141, 91, 244, 161, 45, 95,
-33, 190, 243, 156, 7, 84, 14, 163, 33, 216,
-221, 152, 184, 218, 3, 32, 181, 157, 55, 16,
-43, 159, 87, 81, 94, 169, 205, 206, 134, 156,
-204, 230, 37, 161, 103, 64, 34, 218, 16, 109,
-146, 77, 140, 57, 79, 28, 206, 34, 72, 201,
-229, 202, 190, 157, 92, 219, 58, 221, 58, 63,
-138, 252, 13, 20, 134, 109, 24, 66, 228, 59,
-37, 32, 238, 20, 12, 15, 86, 234, 102, 110,
-242, 214, 136, 215, 177, 101, 66, 1, 134, 244,
-102, 61, 149, 65, 175, 241, 111, 227, 1, 240,
-153, 201, 147, 36, 56, 98, 1, 106, 21, 168,
-218, 16, 207, 169, 177, 205, 135, 175, 36, 176,
-186, 199, 7, 222, 164, 180, 21, 141, 242, 15,
-70, 37, 251, 158, 74, 236, 94, 177, 55, 39,
-61, 133, 230, 27, 231, 113, 20, 200, 43, 249,
-198, 222, 53, 116, 0, 192, 29, 103, 79, 254,
-9, 64, 48, 63, 39, 158, 226, 240, 50, 199,
-165, 168, 232, 116, 235, 170, 38, 162, 145, 108,
-241, 138, 148, 137, 65, 101, 89, 9, 203, 50,
-17, 99, 151, 18, 50, 39, 164, 116, 154, 178,
-112, 175, 101, 213, 151, 51, 243, 224, 100, 252,
-47, 229, 147, 113, 160, 181, 12, 73, 66, 104,
-229, 181, 186, 229, 100, 101, 231, 79, 99, 146,
-90, 187, 190, 188, 189, 35, 51, 69, 174, 233,
-94, 132, 28, 232, 51, 132, 167, 112, 176, 23,
-20, 19, 7, 90, 78, 178, 36, 101, 17, 172,
-185, 50, 177, 157, 167, 139, 25, 139, 12, 249,
-118, 248, 186, 135, 174, 177, 95, 99, 12, 207,
-43, 15, 79, 200, 54, 82, 124, 2, 112, 130,
-155, 194, 102, 89, 215, 241, 159, 255, 13, 144,
-221, 99, 78, 72, 6, 156, 100, 4, 7, 116,
-219, 239, 102, 186, 156, 206, 224, 149, 152, 20,
-203, 118, 151, 150, 145, 208, 172, 87, 2, 68,
-87, 59, 197, 95, 222, 29, 185, 161, 228, 46,
-137, 230, 199, 247, 50, 230, 204, 244, 217, 227,
-160, 47, 157, 67, 64, 187, 201, 43, 182, 123,
-20, 206, 218, 31, 78, 146, 121, 195, 49, 186,
-254, 3, 165, 177, 44, 18, 70, 173, 214, 142,
-95, 199, 59, 163, 59, 52, 248, 72, 5, 196,
-38, 12, 2, 89, 164, 87, 106, 106, 23, 139,
-179, 86, 168, 224, 137, 145, 13, 119, 66, 109,
-221, 124, 22, 144, 181, 199, 221, 217, 75, 221,
-165, 191, 212, 195, 223, 232, 233, 133, 112, 27,
-90, 210, 109, 43, 0, 168, 198, 16, 22, 98,
-175, 206, 39, 36, 12, 88, 4, 250, 165, 13,
-234, 163, 110, 5, 62, 100, 167, 200, 5, 211,
-35, 162, 140, 251, 118, 54, 76, 200, 87, 123,
-155, 26, 252, 193, 38, 116, 182, 255, 198, 164,
-159, 242, 176, 74, 145, 74, 140, 182, 63, 139,
-126, 243, 171, 195, 159, 114, 204, 190, 253, 52,
-161, 232, 151, 235, 129, 125, 115, 227, 240, 46,
-64, 51, 187, 240, 160, 10, 164, 8, 142, 139,
-114, 15, 254, 32, 153, 12, 44, 169, 85, 80,
-167, 105, 109, 56, 173, 42, 127, 129, 205, 111,
-1, 86, 96, 32, 211, 187, 228, 164, 166, 131,
-187, 188, 245, 119, 92, 28, 231, 210, 116, 27,
-222, 194, 10, 106, 239, 17, 42, 54, 29, 151,
-30, 158, 148, 176, 187, 234, 171, 76, 207, 96,
-255, 197, 52, 43, 99, 46, 148, 50, 245, 48,
-97, 77, 30, 50, 11, 197, 194, 225, 0, 114,
-109, 205, 118, 126, 191, 61, 143, 23, 236, 228,
-219, 15, 125, 161, 191, 193, 65, 232, 202, 51,
-141, 13, 133, 202, 180, 6, 187, 141, 234, 224,
-204, 78, 101, 123, 13, 166, 0, 196, 193, 56,
-39, 14, 171, 8, 88, 178, 204, 111, 251, 162,
-75, 122, 223, 20, 25, 36, 36, 235, 79, 95,
-208, 11, 208, 61, 229, 65, 68, 53, 58, 216,
-223, 227, 216, 155, 10, 44, 47, 91, 115, 47,
-228, 159, 139, 233
--- a/server/server.h
+++ /dev/null
@@ -1,314 +1,0 @@
-//#define PARANOID			// speed sapping error checking
-
-#define	MAX_MASTERS	8				// max recipients for heartbeat packets
-
-typedef enum {
-	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)
-
-typedef struct
-{
-	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
-
-	unsigned	time;				// always sv.framenum * 100 msec
-	int			framenum;
-
-	char		name[MAX_QPATH];			// map name, or cinematic name
-	struct cmodel_s		*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;
-	byte		multicast_buf[MAX_MSGLEN];
-
-	// demo server information
-	FILE		*demofile;
-	qboolean	timedemo;		// don't time sync
-} server_t;
-
-#define EDICT_NUM(n) ((edict_t *)((byte *)ge->edicts + ge->edict_size*(n)))
-#define NUM_FOR_EDICT(e) ( ((byte *)(e)-(byte *)ge->edicts ) / ge->edict_size)
-
-
-typedef enum
-{
-	cs_free,		// can be reused for a new connection
-	cs_zombie,		// client has been disconnected, but don't reuse
-					// connection for a couple seconds
-	cs_connected,	// has been assigned to a client_t, but not in game yet
-	cs_spawned		// client is fully in game
-} clstate_t;
-
-typedef struct
-{
-	int					areabytes;
-	byte				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
-} client_frame_t;
-
-#define	LATENCY_COUNTS	16
-#define	RATE_MESSAGES	10
-
-typedef struct client_s
-{
-	clstate_t	state;
-
-	char			userinfo[MAX_INFO_STRING];		// name, etc
-
-	int				lastframe;			// for delta compression
-	usercmd_t		lastcmd;			// for filling in big drops
-
-	int				commandMsec;		// every seconds this is reset, if user
-										// commands exhaust it, assume time cheating
-
-	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;
-	byte			datagram_buf[MAX_MSGLEN];
-
-	client_frame_t	frames[UPDATE_BACKUP];	// updates can be delta'd from here
-
-	byte			*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;
-} client_t;
-
-// 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
-
-//=============================================================================
-
-// MAX_CHALLENGES is made large to prevent a denial
-// of service attack that could cycle all of them
-// out before legitimate users connected
-#define	MAX_CHALLENGES	1024
-
-typedef struct
-{
-	netadr_t	adr;
-	int			challenge;
-	int			time;
-} challenge_t;
-
-
-typedef struct
-{
-	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;
-	byte		demo_multicast_buf[MAX_MSGLEN];
-} server_static_t;
-
-//=============================================================================
-
-extern	netadr_t	net_from;
-extern	sizebuf_t	net_message;
-
-extern	netadr_t	master_adr[MAX_MASTERS];	// address of the master server
-
-extern	server_static_t	svs;				// persistant server info
-extern	server_t		sv;					// local server
-
-extern	cvar_t		*sv_paused;
-extern	cvar_t		*maxclients;
-extern	cvar_t		*sv_noreload;			// don't reload level state when reentering
-extern	cvar_t		*sv_airaccelerate;		// don't reload level state when reentering
-											// development tool
-extern	cvar_t		*sv_enforcetime;
-
-extern	client_t	*sv_client;
-extern	edict_t		*sv_player;
-
-//===========================================================
-
-//
-// sv_main.c
-//
-void SV_FinalMessage (char *message, qboolean reconnect);
-void SV_DropClient (client_t *drop);
-
-int SV_ModelIndex (char *name);
-int SV_SoundIndex (char *name);
-int SV_ImageIndex (char *name);
-
-void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg);
-
-void SV_ExecuteUserCommand (char *s);
-void SV_InitOperatorCommands (void);
-
-void SV_SendServerinfo (client_t *client);
-void SV_UserinfoChanged (client_t *cl);
-
-
-void Master_Heartbeat (void);
-void Master_Packet (void);
-
-//
-// sv_init.c
-//
-void SV_InitGame (void);
-void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame);
-
-
-//
-// sv_phys.c
-//
-void SV_PrepWorldFrame (void);
-
-//
-// sv_send.c
-//
-typedef enum {RD_NONE, RD_CLIENT, RD_PACKET} redirect_t;
-#define	SV_OUTPUTBUF_LENGTH	(MAX_MSGLEN - 16)
-
-extern	char	sv_outputbuf[SV_OUTPUTBUF_LENGTH];
-
-void SV_FlushRedirect (int sv_redirected, char *outputbuf);
-
-void SV_DemoCompleted (void);
-void SV_SendClientMessages (void);
-
-void SV_Multicast (vec3_t origin, multicast_t to);
-void SV_StartSound (vec3_t origin, edict_t *entity, int channel,
-					int soundindex, float volume,
-					float attenuation, float timeofs);
-void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...);
-void SV_BroadcastPrintf (int level, char *fmt, ...);
-void SV_BroadcastCommand (char *fmt, ...);
-
-//
-// sv_user.c
-//
-void SV_Nextserver (void);
-void SV_ExecuteClientMessage (client_t *cl);
-
-//
-// sv_ccmds.c
-//
-void SV_ReadLevelFile (void);
-void SV_Status_f (void);
-
-//
-// sv_ents.c
-//
-void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg);
-void SV_RecordDemoMessage (void);
-void SV_BuildClientFrame (client_t *client);
-
-
-void SV_Error (char *error, ...);
-
-//
-// sv_game.c
-//
-extern	game_export_t	*ge;
-
-void SV_InitGameProgs (void);
-void SV_ShutdownGameProgs (void);
-void SV_InitEdict (edict_t *e);
-
-
-
-//============================================================
-
-//
-// high level object sorting to reduce interaction tests
-//
-
-void SV_ClearWorld (void);
-// called after the world model has been loaded, before linking any entities
-
-void SV_UnlinkEdict (edict_t *ent);
-// call before removing an entity, and before trying to move one,
-// so it doesn't clip against itself
-
-void SV_LinkEdict (edict_t *ent);
-// Needs to be called any time an entity changes origin, mins, maxs,
-// or solid.  Automatically unlinks if needed.
-// sets ent->v.absmin and ent->v.absmax
-// sets ent->leafnums[] for pvs determination even if the entity
-// is not solid
-
-int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype);
-// fills in a table of edict pointers with edicts that have bounding boxes
-// that intersect the given area.  It is possible for a non-axial bmodel
-// to be returned that doesn't actually intersect the area on an exact
-// test.
-// returns the number of pointers filled in
-// ??? does this always return the world?
-
-//===================================================================
-
-//
-// functions that interact with everything apropriate
-//
-int SV_PointContents (vec3_t p);
-// returns the CONTENTS_* value from the world at the given point.
-// Quake 2 extends this to also check entities, to allow moving liquids
-
-
-trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask);
-// mins and maxs are relative
-
-// if the entire move stays in a solid volume, trace.allsolid will be set,
-// trace.startsolid will be set, and trace.fraction will be 0
-
-// if the starting point is in a solid, it will be allowed to move out
-// to an open area
-
-// passedict is explicitly excluded from clipping checks (normally NULL)
-
--- a/server/sv_ccmds.c
+++ /dev/null
@@ -1,1030 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-===============================================================================
-
-OPERATOR CONSOLE ONLY COMMANDS
-
-These commands can only be entered from stdin or by a remote operator datagram
-===============================================================================
-*/
-
-/*
-====================
-SV_SetMaster_f
-
-Specify a list of master servers
-====================
-*/
-void SV_SetMaster_f (void)
-{
-	int		i, slot;
-
-	// only dedicated servers send heartbeats
-	if (!dedicated->value)
-	{
-		Com_Printf ("Only dedicated servers use masters.\n");
-		return;
-	}
-
-	// make sure the server is listed public
-	Cvar_Set ("public", "1");
-
-	for (i=1 ; i<MAX_MASTERS ; i++)
-		memset (&master_adr[i], 0, sizeof(master_adr[i]));
-
-	slot = 1;		// slot 0 will always contain the id master
-	for (i=1 ; i<Cmd_Argc() ; i++)
-	{
-		if (slot == MAX_MASTERS)
-			break;
-
-		if (!NET_StringToAdr (Cmd_Argv(i), &master_adr[i]))
-		{
-			Com_Printf ("Bad address: %s\n", Cmd_Argv(i));
-			continue;
-		}
-		if (master_adr[slot].port == 0)
-			master_adr[slot].port = BigShort (PORT_MASTER);
-
-		Com_Printf ("Master server at %s\n", NET_AdrToString (master_adr[slot]));
-
-		Com_Printf ("Sending a ping.\n");
-
-		Netchan_OutOfBandPrint (NS_SERVER, master_adr[slot], "ping");
-
-		slot++;
-	}
-
-	svs.last_heartbeat = -9999999;
-}
-
-
-
-/*
-==================
-SV_SetPlayer
-
-Sets sv_client and sv_player to the player with idnum Cmd_Argv(1)
-==================
-*/
-qboolean SV_SetPlayer (void)
-{
-	client_t	*cl;
-	int			i;
-	int			idnum;
-	char		*s;
-
-	if (Cmd_Argc() < 2)
-		return false;
-
-	s = Cmd_Argv(1);
-
-	// numeric values are just slot numbers
-	if (s[0] >= '0' && s[0] <= '9')
-	{
-		idnum = atoi(Cmd_Argv(1));
-		if (idnum < 0 || idnum >= maxclients->value)
-		{
-			Com_Printf ("Bad client slot: %i\n", idnum);
-			return false;
-		}
-
-		sv_client = &svs.clients[idnum];
-		sv_player = sv_client->edict;
-		if (!sv_client->state)
-		{
-			Com_Printf ("Client %i is not active\n", idnum);
-			return false;
-		}
-		return true;
-	}
-
-	// check for a name match
-	for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
-	{
-		if (!cl->state)
-			continue;
-		if (!strcmp(cl->name, s))
-		{
-			sv_client = cl;
-			sv_player = sv_client->edict;
-			return true;
-		}
-	}
-
-	Com_Printf ("Userid %s is not on the server\n", s);
-	return false;
-}
-
-
-/*
-===============================================================================
-
-SAVEGAME FILES
-
-===============================================================================
-*/
-
-/*
-=====================
-SV_WipeSavegame
-
-Delete save/<XXX>/
-=====================
-*/
-void SV_WipeSavegame (char *savename)
-{
-	char	name[MAX_OSPATH];
-	char	*s;
-
-	Com_DPrintf("SV_WipeSaveGame(%s)\n", savename);
-
-	Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir (), savename);
-	remove (name);
-	Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir (), savename);
-	remove (name);
-
-	Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir (), savename);
-	s = Sys_FindFirst( name, 0, 0 );
-	while (s)
-	{
-		remove (s);
-		s = Sys_FindNext( 0, 0 );
-	}
-	Sys_FindClose ();
-	Com_sprintf (name, sizeof(name), "%s/save/%s/*.sv2", FS_Gamedir (), savename);
-	s = Sys_FindFirst(name, 0, 0 );
-	while (s)
-	{
-		remove (s);
-		s = Sys_FindNext( 0, 0 );
-	}
-	Sys_FindClose ();
-}
-
-
-/*
-================
-CopyFile
-================
-*/
-void CopyFile (char *src, char *dst)
-{
-	FILE	*f1, *f2;
-	int		l;
-	byte	buffer[65536];
-
-	Com_DPrintf ("CopyFile (%s, %s)\n", src, dst);
-
-	f1 = fopen (src, "rb");
-	if (!f1)
-		return;
-	f2 = fopen (dst, "wb");
-	if (!f2)
-	{
-		fclose (f1);
-		return;
-	}
-
-	while (1)
-	{
-		l = fread (buffer, 1, sizeof(buffer), f1);
-		if (!l)
-			break;
-		fwrite (buffer, 1, l, f2);
-	}
-
-	fclose (f1);
-	fclose (f2);
-}
-
-
-/*
-================
-SV_CopySaveGame
-================
-*/
-void SV_CopySaveGame (char *src, char *dst)
-{
-	char	name[MAX_OSPATH], name2[MAX_OSPATH];
-	int		l, len;
-	char	*found;
-
-	Com_DPrintf("SV_CopySaveGame(%s, %s)\n", src, dst);
-
-	SV_WipeSavegame (dst);
-
-	// copy the savegame over
-	Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir(), src);
-	Com_sprintf (name2, sizeof(name2), "%s/save/%s/server.ssv", FS_Gamedir(), dst);
-	FS_CreatePath (name2);
-	CopyFile (name, name2);
-
-	Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir(), src);
-	Com_sprintf (name2, sizeof(name2), "%s/save/%s/game.ssv", FS_Gamedir(), dst);
-	CopyFile (name, name2);
-
-	Com_sprintf (name, sizeof(name), "%s/save/%s/", FS_Gamedir(), src);
-	len = strlen(name);
-	Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir(), src);
-	found = Sys_FindFirst(name, 0, 0 );
-	while (found)
-	{
-		strcpy (name+len, found+len);
-
-		Com_sprintf (name2, sizeof(name2), "%s/save/%s/%s", FS_Gamedir(), dst, found+len);
-		CopyFile (name, name2);
-
-		// change sav to sv2
-		l = strlen(name);
-		strcpy (name+l-3, "sv2");
-		l = strlen(name2);
-		strcpy (name2+l-3, "sv2");
-		CopyFile (name, name2);
-
-		found = Sys_FindNext( 0, 0 );
-	}
-	Sys_FindClose ();
-}
-
-
-/*
-==============
-SV_WriteLevelFile
-
-==============
-*/
-void SV_WriteLevelFile (void)
-{
-	char	name[MAX_OSPATH];
-	FILE	*f;
-
-	Com_DPrintf("SV_WriteLevelFile()\n");
-
-	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name);
-	f = fopen(name, "wb");
-	if (!f)
-	{
-		Com_Printf ("Failed to open %s\n", name);
-		return;
-	}
-	fwrite (sv.configstrings, sizeof(sv.configstrings), 1, f);
-	CM_WritePortalState (f);
-	fclose (f);
-
-	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
-	ge->WriteLevel (name);
-}
-
-/*
-==============
-SV_ReadLevelFile
-
-==============
-*/
-void SV_ReadLevelFile (void)
-{
-	char	name[MAX_OSPATH];
-	FILE	*f;
-
-	Com_DPrintf("SV_ReadLevelFile()\n");
-
-	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name);
-	f = fopen(name, "rb");
-	if (!f)
-	{
-		Com_Printf ("Failed to open %s\n", name);
-		return;
-	}
-	FS_Read (sv.configstrings, sizeof(sv.configstrings), f);
-	CM_ReadPortalState (f);
-	fclose (f);
-
-	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
-	ge->ReadLevel (name);
-}
-
-/*
-==============
-SV_WriteServerFile
-
-==============
-*/
-void SV_WriteServerFile (qboolean autosave)
-{
-	FILE	*f;
-	cvar_t	*var;
-	char	name[MAX_OSPATH], string[128];
-	char	comment[32];
-	Tm	*newtime;
-
-	Com_DPrintf("SV_WriteServerFile(%s)\n", autosave ? "true" : "false");
-
-	Com_sprintf (name, sizeof(name), "%s/save/current/server.ssv", FS_Gamedir());
-	f = fopen (name, "wb");
-	if (!f)
-	{
-		Com_Printf ("Couldn't write %s\n", name);
-		return;
-	}
-	// write the comment field
-	memset (comment, 0, sizeof(comment));
-
-	if (!autosave)
-	{
-		newtime = localtime (time(nil));
-		Com_sprintf (comment,sizeof(comment), "%2i:%i%i %2i/%2i  ", newtime->hour
-			, newtime->min/10, newtime->min%10, newtime->mon+1, newtime->mday);
-		strncat (comment, sv.configstrings[CS_NAME], sizeof(comment)-1-strlen(comment) );
-	}
-	else
-	{	// autosaved
-		Com_sprintf (comment, sizeof(comment), "ENTERING %s", sv.configstrings[CS_NAME]);
-	}
-
-	fwrite (comment, 1, sizeof(comment), f);
-
-	// write the mapcmd
-	fwrite (svs.mapcmd, 1, sizeof(svs.mapcmd), f);
-
-	// write all CVAR_LATCH cvars
-	// these will be things like coop, skill, deathmatch, etc
-	for (var = cvar_vars ; var ; var=var->next)
-	{
-		if (!(var->flags & CVAR_LATCH))
-			continue;
-		if (strlen(var->name) >= sizeof(name)-1
-			|| strlen(var->string) >= sizeof(string)-1)
-		{
-			Com_Printf ("Cvar too long: %s = %s\n", var->name, var->string);
-			continue;
-		}
-		memset (name, 0, sizeof(name));
-		memset (string, 0, sizeof(string));
-		strcpy (name, var->name);
-		strcpy (string, var->string);
-		fwrite (name, 1, sizeof(name), f);
-		fwrite (string, 1, sizeof(string), f);
-	}
-
-	fclose (f);
-
-	// write game state
-	Com_sprintf (name, sizeof(name), "%s/save/current/game.ssv", FS_Gamedir());
-	ge->WriteGame (name, autosave);
-}
-
-/*
-==============
-SV_ReadServerFile
-
-==============
-*/
-void SV_ReadServerFile (void)
-{
-	FILE	*f;
-	char	name[MAX_OSPATH], string[128];
-	char	comment[32];
-	char	mapcmd[MAX_TOKEN_CHARS];
-
-	Com_DPrintf("SV_ReadServerFile()\n");
-
-	Com_sprintf (name, sizeof(name), "%s/save/current/server.ssv", FS_Gamedir());
-	f = fopen (name, "rb");
-	if (!f)
-	{
-		Com_Printf ("Couldn't read %s\n", name);
-		return;
-	}
-	// read the comment field
-	FS_Read (comment, sizeof(comment), f);
-
-	// read the mapcmd
-	FS_Read (mapcmd, sizeof(mapcmd), f);
-
-	// read all CVAR_LATCH cvars
-	// these will be things like coop, skill, deathmatch, etc
-	while (1)
-	{
-		if (!fread (name, 1, sizeof(name), f))
-			break;
-		FS_Read (string, sizeof(string), f);
-		Com_DPrintf ("Set %s = %s\n", name, string);
-		Cvar_ForceSet (name, string);
-	}
-
-	fclose (f);
-
-	// start a new game fresh with new cvars
-	SV_InitGame ();
-
-	strcpy (svs.mapcmd, mapcmd);
-
-	// read game state
-	Com_sprintf (name, sizeof(name), "%s/save/current/game.ssv", FS_Gamedir());
-	ge->ReadGame (name);
-}
-
-
-//=========================================================
-
-
-
-
-/*
-==================
-SV_DemoMap_f
-
-Puts the server in demo mode on a specific map/cinematic
-==================
-*/
-void SV_DemoMap_f (void)
-{
-	SV_Map (true, Cmd_Argv(1), false );
-}
-
-/*
-==================
-SV_GameMap_f
-
-Saves the state of the map just being exited and goes to a new map.
-
-If the initial character of the map string is '*', the next map is
-in a new unit, so the current savegame directory is cleared of
-map files.
-
-Example:
-
-*inter.cin+jail
-
-Clears the archived maps, plays the inter.cin cinematic, then
-goes to map jail.bsp.
-==================
-*/
-void SV_GameMap_f (void)
-{
-	char		*map;
-	int			i;
-	client_t	*cl;
-	qboolean	*savedInuse;
-
-	if (Cmd_Argc() != 2)
-	{
-		Com_Printf ("USAGE: gamemap <map>\n");
-		return;
-	}
-
-	Com_DPrintf("SV_GameMap(%s)\n", Cmd_Argv(1));
-
-	FS_CreatePath (va("%s/save/current/", FS_Gamedir()));
-
-	// check for clearing the current savegame
-	map = Cmd_Argv(1);
-	if (map[0] == '*')
-	{
-		// wipe all the *.sav files
-		SV_WipeSavegame ("current");
-	}
-	else
-	{	// save the map just exited
-		if (sv.state == ss_game)
-		{
-			// clear all the client inuse flags before saving so that
-			// when the level is re-entered, the clients will spawn
-			// at spawn points instead of occupying body shells
-			savedInuse = malloc(maxclients->value * sizeof(qboolean));
-			for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
-			{
-				savedInuse[i] = cl->edict->inuse;
-				cl->edict->inuse = false;
-			}
-
-			SV_WriteLevelFile ();
-
-			// we must restore these for clients to transfer over correctly
-			for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
-				cl->edict->inuse = savedInuse[i];
-			free (savedInuse);
-		}
-	}
-
-	// start up the next map
-	SV_Map (false, Cmd_Argv(1), false );
-
-	// archive server state
-	strncpy (svs.mapcmd, Cmd_Argv(1), sizeof(svs.mapcmd)-1);
-
-	// copy off the level to the autosave slot
-	if (!dedicated->value)
-	{
-		SV_WriteServerFile (true);
-		SV_CopySaveGame ("current", "save0");
-	}
-}
-
-/*
-==================
-SV_Map_f
-
-Goes directly to a given map without any savegame archiving.
-For development work
-==================
-*/
-void SV_Map_f (void)
-{
-	char	*map;
-	char	expanded[MAX_QPATH];
-
-	// if not a pcx, demo, or cinematic, check to make sure the level exists
-	map = Cmd_Argv(1);
-	if (!strstr (map, "."))
-	{
-		Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map);
-		if (FS_LoadFile (expanded, NULL) == -1)
-		{
-			Com_Printf ("Can't find %s\n", expanded);
-			return;
-		}
-	}
-
-	sv.state = ss_dead;		// don't save current level when changing
-	SV_WipeSavegame("current");
-	SV_GameMap_f ();
-}
-
-/*
-=====================================================================
-
-  SAVEGAMES
-
-=====================================================================
-*/
-
-
-/*
-==============
-SV_Loadgame_f
-
-==============
-*/
-void SV_Loadgame_f (void)
-{
-	char	name[MAX_OSPATH];
-	FILE	*f;
-	char	*dir;
-
-	if (Cmd_Argc() != 2)
-	{
-		Com_Printf ("USAGE: loadgame <directory>\n");
-		return;
-	}
-
-	Com_Printf ("Loading game...\n");
-
-	dir = Cmd_Argv(1);
-	if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") )
-	{
-		Com_Printf ("Bad savedir.\n");
-	}
-
-	// make sure the server.ssv file exists
-	Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir(), Cmd_Argv(1));
-	f = fopen (name, "rb");
-	if (!f)
-	{
-		Com_Printf ("No such savegame: %s\n", name);
-		return;
-	}
-	fclose (f);
-
-	SV_CopySaveGame (Cmd_Argv(1), "current");
-
-	SV_ReadServerFile ();
-
-	// go to the map
-	sv.state = ss_dead;		// don't save current level when changing
-	SV_Map (false, svs.mapcmd, true);
-}
-
-
-
-/*
-==============
-SV_Savegame_f
-
-==============
-*/
-void SV_Savegame_f (void)
-{
-	char	*dir;
-
-	if (sv.state != ss_game)
-	{
-		Com_Printf ("You must be in a game to save.\n");
-		return;
-	}
-
-	if (Cmd_Argc() != 2)
-	{
-		Com_Printf ("USAGE: savegame <directory>\n");
-		return;
-	}
-
-	if (Cvar_VariableValue("deathmatch"))
-	{
-		Com_Printf ("Can't savegame in a deathmatch\n");
-		return;
-	}
-
-	if (!strcmp (Cmd_Argv(1), "current"))
-	{
-		Com_Printf ("Can't save to 'current'\n");
-		return;
-	}
-
-	if (maxclients->value == 1 && svs.clients[0].edict->client->ps.stats[STAT_HEALTH] <= 0)
-	{
-		Com_Printf ("\nCan't savegame while dead!\n");
-		return;
-	}
-
-	dir = Cmd_Argv(1);
-	if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") )
-	{
-		Com_Printf ("Bad savedir.\n");
-	}
-
-	Com_Printf ("Saving game...\n");
-
-	// archive current level, including all client edicts.
-	// when the level is reloaded, they will be shells awaiting
-	// a connecting client
-	SV_WriteLevelFile ();
-
-	// save server state
-	SV_WriteServerFile (false);
-
-	// copy it off
-	SV_CopySaveGame ("current", dir);
-
-	Com_Printf ("Done.\n");
-}
-
-//===============================================================
-
-/*
-==================
-SV_Kick_f
-
-Kick a user off of the server
-==================
-*/
-void SV_Kick_f (void)
-{
-	if (!svs.initialized)
-	{
-		Com_Printf ("No server running.\n");
-		return;
-	}
-
-	if (Cmd_Argc() != 2)
-	{
-		Com_Printf ("Usage: kick <userid>\n");
-		return;
-	}
-
-	if (!SV_SetPlayer ())
-		return;
-
-	SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked\n", sv_client->name);
-	// print directly, because the dropped client won't get the
-	// SV_BroadcastPrintf message
-	SV_ClientPrintf (sv_client, PRINT_HIGH, "You were kicked from the game\n");
-	SV_DropClient (sv_client);
-	sv_client->lastmessage = svs.realtime;	// min case there is a funny zombie
-}
-
-
-/*
-================
-SV_Status_f
-================
-*/
-void SV_Status_f (void)
-{
-	int			i, j, l;
-	client_t	*cl;
-	char		*s;
-	int			ping;
-	if (!svs.clients)
-	{
-		Com_Printf ("No server running.\n");
-		return;
-	}
-	Com_Printf ("map              : %s\n", sv.name);
-
-	Com_Printf ("num score ping name            lastmsg address               qport \n");
-	Com_Printf ("--- ----- ---- --------------- ------- --------------------- ------\n");
-	for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
-	{
-		if (!cl->state)
-			continue;
-		Com_Printf ("%3i ", i);
-		Com_Printf ("%5i ", cl->edict->client->ps.stats[STAT_FRAGS]);
-
-		if (cl->state == cs_connected)
-			Com_Printf ("CNCT ");
-		else if (cl->state == cs_zombie)
-			Com_Printf ("ZMBI ");
-		else
-		{
-			ping = cl->ping < 9999 ? cl->ping : 9999;
-			Com_Printf ("%4i ", ping);
-		}
-
-		Com_Printf ("%s", cl->name);
-		l = 16 - strlen(cl->name);
-		for (j=0 ; j<l ; j++)
-			Com_Printf (" ");
-
-		Com_Printf ("%7i ", svs.realtime - cl->lastmessage );
-
-		s = NET_AdrToString ( cl->netchan.remote_address);
-		Com_Printf ("%s", s);
-		l = 22 - strlen(s);
-		for (j=0 ; j<l ; j++)
-			Com_Printf (" ");
-		
-		Com_Printf ("%5i", cl->netchan.qport);
-
-		Com_Printf ("\n");
-	}
-	Com_Printf ("\n");
-}
-
-/*
-==================
-SV_ConSay_f
-==================
-*/
-void SV_ConSay_f(void)
-{
-	client_t *client;
-	int		j;
-	char	*p;
-	char	text[1024];
-
-	if (Cmd_Argc () < 2)
-		return;
-
-	strcpy (text, "console: ");
-	p = Cmd_Args();
-
-	if (*p == '"')
-	{
-		p++;
-		p[strlen(p)-1] = 0;
-	}
-
-	strcat(text, p);
-
-	for (j = 0, client = svs.clients; j < maxclients->value; j++, client++)
-	{
-		if (client->state != cs_spawned)
-			continue;
-		SV_ClientPrintf(client, PRINT_CHAT, "%s\n", text);
-	}
-}
-
-
-/*
-==================
-SV_Heartbeat_f
-==================
-*/
-void SV_Heartbeat_f (void)
-{
-	svs.last_heartbeat = -9999999;
-}
-
-
-/*
-===========
-SV_Serverinfo_f
-
-  Examine or change the serverinfo string
-===========
-*/
-void SV_Serverinfo_f (void)
-{
-	Com_Printf ("Server info settings:\n");
-	Info_Print (Cvar_Serverinfo());
-}
-
-
-/*
-===========
-SV_DumpUser_f
-
-Examine all a users info strings
-===========
-*/
-void SV_DumpUser_f (void)
-{
-	if (Cmd_Argc() != 2)
-	{
-		Com_Printf ("Usage: info <userid>\n");
-		return;
-	}
-
-	if (!SV_SetPlayer ())
-		return;
-
-	Com_Printf ("userinfo\n");
-	Com_Printf ("--------\n");
-	Info_Print (sv_client->userinfo);
-
-}
-
-
-/*
-==============
-SV_ServerRecord_f
-
-Begins server demo recording.  Every entity and every message will be
-recorded, but no playerinfo will be stored.  Primarily for demo merging.
-==============
-*/
-void SV_ServerRecord_f (void)
-{
-	char	name[MAX_OSPATH];
-	char	buf_data[32768];
-	sizebuf_t	buf;
-	int		len;
-	int		i;
-
-	if (Cmd_Argc() != 2)
-	{
-		Com_Printf ("serverrecord <demoname>\n");
-		return;
-	}
-
-	if (svs.demofile)
-	{
-		Com_Printf ("Already recording.\n");
-		return;
-	}
-
-	if (sv.state != ss_game)
-	{
-		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);
-	svs.demofile = fopen (name, "wb");
-	if (!svs.demofile)
-	{
-		Com_Printf ("ERROR: couldn't open.\n");
-		return;
-	}
-
-	// setup a buffer to catch all multicasts
-	SZ_Init (&svs.demo_multicast, svs.demo_multicast_buf, sizeof(svs.demo_multicast_buf));
-
-	//
-	// write a single giant fake message with all the startup info
-	//
-	SZ_Init (&buf, (byte *)buf_data, sizeof(buf_data));
-
-	//
-	// serverdata needs to go over for all types of servers
-	// to make sure the protocol is right, and to set the gamedir
-	//
-	// send the serverdata
-	MSG_WriteByte (&buf, svc_serverdata);
-	MSG_WriteLong (&buf, PROTOCOL_VERSION);
-	MSG_WriteLong (&buf, svs.spawncount);
-	// 2 means server demo
-	MSG_WriteByte (&buf, 2);	// demos are always attract loops
-	MSG_WriteString (&buf, Cvar_VariableString ("gamedir"));
-	MSG_WriteShort (&buf, -1);
-	// send full levelname
-	MSG_WriteString (&buf, sv.configstrings[CS_NAME]);
-
-	for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
-		if (sv.configstrings[i][0])
-		{
-			MSG_WriteByte (&buf, svc_configstring);
-			MSG_WriteShort (&buf, i);
-			MSG_WriteString (&buf, sv.configstrings[i]);
-		}
-
-	// write it to the demo file
-	Com_DPrintf ("signon message length: %i\n", buf.cursize);
-	len = LittleLong (buf.cursize);
-	fwrite (&len, 4, 1, svs.demofile);
-	fwrite (buf.data, buf.cursize, 1, svs.demofile);
-
-	// the rest of the demo file will be individual frames
-}
-
-
-/*
-==============
-SV_ServerStop_f
-
-Ends server demo recording
-==============
-*/
-void SV_ServerStop_f (void)
-{
-	if (!svs.demofile)
-	{
-		Com_Printf ("Not doing a serverrecord.\n");
-		return;
-	}
-	fclose (svs.demofile);
-	svs.demofile = NULL;
-	Com_Printf ("Recording completed.\n");
-}
-
-
-/*
-===============
-SV_KillServer_f
-
-Kick everyone off, possibly in preparation for a new game
-
-===============
-*/
-void SV_KillServer_f (void)
-{
-	if (!svs.initialized)
-		return;
-	SV_Shutdown ("Server was killed.\n", false);
-	NET_Config ( false );	// close network sockets
-}
-
-/*
-===============
-SV_ServerCommand_f
-
-Let the game dll handle a command
-===============
-*/
-void SV_ServerCommand_f (void)
-{
-	if (!ge)
-	{
-		Com_Printf ("No game loaded.\n");
-		return;
-	}
-
-	ge->ServerCommand();
-}
-
-//===========================================================
-
-/*
-==================
-SV_InitOperatorCommands
-==================
-*/
-void SV_InitOperatorCommands (void)
-{
-	Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
-	Cmd_AddCommand ("kick", SV_Kick_f);
-	Cmd_AddCommand ("status", SV_Status_f);
-	Cmd_AddCommand ("serverinfo", SV_Serverinfo_f);
-	Cmd_AddCommand ("dumpuser", SV_DumpUser_f);
-
-	Cmd_AddCommand ("map", SV_Map_f);
-	Cmd_AddCommand ("demomap", SV_DemoMap_f);
-	Cmd_AddCommand ("gamemap", SV_GameMap_f);
-	Cmd_AddCommand ("setmaster", SV_SetMaster_f);
-
-	if ( dedicated->value )
-		Cmd_AddCommand ("say", SV_ConSay_f);
-
-	Cmd_AddCommand ("serverrecord", SV_ServerRecord_f);
-	Cmd_AddCommand ("serverstop", SV_ServerStop_f);
-
-	Cmd_AddCommand ("save", SV_Savegame_f);
-	Cmd_AddCommand ("load", SV_Loadgame_f);
-
-	Cmd_AddCommand ("killserver", SV_KillServer_f);
-
-	Cmd_AddCommand ("sv", SV_ServerCommand_f);
-}
-
--- a/server/sv_ents.c
+++ /dev/null
@@ -1,708 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-=============================================================================
-
-Encode a client frame onto the network channel
-
-=============================================================================
-*/
-
-/* commented out in release
-
-// because there can be a lot of projectiles, there is a special
-// network protocol for them
-#define	MAX_PROJECTILES		64
-edict_t	*projectiles[MAX_PROJECTILES];
-int		numprojs;
-cvar_t  *sv_projectiles;
-
-qboolean SV_AddProjectileUpdate (edict_t *ent)
-{
-	if (!sv_projectiles)
-		sv_projectiles = Cvar_Get("sv_projectiles", "1", 0);
-
-	if (!sv_projectiles->value)
-		return false;
-
-	if (!(ent->svflags & SVF_PROJECTILE))
-		return false;
-	if (numprojs == MAX_PROJECTILES)
-		return true;
-
-	projectiles[numprojs++] = ent;
-	return true;
-}
-
-void SV_EmitProjectileUpdate (sizebuf_t *msg)
-{
-	byte	bits[16];	// [modelindex] [48 bits] xyz p y 12 12 12 8 8 [entitynum] [e2]
-	int		n, i;
-	edict_t	*ent;
-	int		x, y, z, p, yaw;
-	int len;
-
-	if (!numprojs)
-		return;
-
-	MSG_WriteByte (msg, numprojs);
-
-	for (n=0 ; n<numprojs ; n++)
-	{
-		ent = projectiles[n];
-		x = (int)(ent->s.origin[0]+4096)>>1;
-		y = (int)(ent->s.origin[1]+4096)>>1;
-		z = (int)(ent->s.origin[2]+4096)>>1;
-		p = (int)(256*ent->s.angles[0]/360)&255;
-		yaw = (int)(256*ent->s.angles[1]/360)&255;
-
-		len = 0;
-		bits[len++] = x;
-		bits[len++] = (x>>8) | (y<<4);
-		bits[len++] = (y>>4);
-		bits[len++] = z;
-		bits[len++] = (z>>8);
-		if (ent->s.effects & EF_BLASTER)
-			bits[len-1] |= 64;
-
-		if (ent->s.old_origin[0] != ent->s.origin[0] ||
-			ent->s.old_origin[1] != ent->s.origin[1] ||
-			ent->s.old_origin[2] != ent->s.origin[2]) {
-			bits[len-1] |= 128;
-			x = (int)(ent->s.old_origin[0]+4096)>>1;
-			y = (int)(ent->s.old_origin[1]+4096)>>1;
-			z = (int)(ent->s.old_origin[2]+4096)>>1;
-			bits[len++] = x;
-			bits[len++] = (x>>8) | (y<<4);
-			bits[len++] = (y>>4);
-			bits[len++] = z;
-			bits[len++] = (z>>8);
-		}
-
-		bits[len++] = p;
-		bits[len++] = yaw;
-		bits[len++] = ent->s.modelindex;
-
-		bits[len++] = (ent->s.number & 0x7f);
-		if (ent->s.number > 255) {
-			bits[len-1] |= 128;
-			bits[len++] = (ent->s.number >> 7);
-		}
-
-		for (i=0 ; i<len ; i++)
-			MSG_WriteByte (msg, bits[i]);
-	}
-}
-*/
-
-/*
-=============
-SV_EmitPacketEntities
-
-Writes a delta update of an entity_state_t list to the message.
-=============
-*/
-void SV_EmitPacketEntities (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
-{
-	entity_state_t	*oldent = nil, *newent = nil;
-	int		oldindex, newindex;
-	int		oldnum, newnum;
-	int		from_num_entities;
-	int		bits;
-
-/*
-	if (numprojs)
-		MSG_WriteByte (msg, svc_packetentities2);
-	else
-*/
-		MSG_WriteByte (msg, svc_packetentities);
-
-	if (!from)
-		from_num_entities = 0;
-	else
-		from_num_entities = from->num_entities;
-
-	newindex = 0;
-	oldindex = 0;
-	while (newindex < to->num_entities || oldindex < from_num_entities)
-	{
-		if (newindex >= to->num_entities)
-			newnum = 9999;
-		else
-		{
-			newent = &svs.client_entities[(to->first_entity+newindex)%svs.num_client_entities];
-			newnum = newent->number;
-		}
-
-		if (oldindex >= from_num_entities)
-			oldnum = 9999;
-		else
-		{
-			oldent = &svs.client_entities[(from->first_entity+oldindex)%svs.num_client_entities];
-			oldnum = oldent->number;
-		}
-
-		if (newnum == oldnum)
-		{	// delta update from old position
-			// because the force parm is false, this will not result
-			// in any bytes being emited if the entity has not changed at all
-			// note that players are always 'newentities', this updates their oldorigin always
-			// and prevents warping
-			MSG_WriteDeltaEntity (oldent, newent, msg, false, newent->number <= maxclients->value);
-			oldindex++;
-			newindex++;
-			continue;
-		}
-
-		if (newnum < oldnum)
-		{	// this is a new entity, send it from the baseline
-			MSG_WriteDeltaEntity (&sv.baselines[newnum], newent, msg, true, true);
-			newindex++;
-			continue;
-		}
-
-		if (newnum > oldnum)
-		{	// the old entity isn't present in the new message
-			bits = U_REMOVE;
-			if (oldnum >= 256)
-				bits |= U_NUMBER16 | U_MOREBITS1;
-
-			MSG_WriteByte (msg,	bits&255 );
-			if (bits & 0x0000ff00)
-				MSG_WriteByte (msg,	(bits>>8)&255 );
-
-			if (bits & U_NUMBER16)
-				MSG_WriteShort (msg, oldnum);
-			else
-				MSG_WriteByte (msg, oldnum);
-
-			oldindex++;
-			continue;
-		}
-	}
-
-	MSG_WriteShort (msg, 0);	// end of packetentities
-
-/*
-	if (numprojs)
-		SV_EmitProjectileUpdate(msg);
-*/
-}
-
-
-
-/*
-=============
-SV_WritePlayerstateToClient
-
-=============
-*/
-void SV_WritePlayerstateToClient (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
-{
-	int				i;
-	int				pflags;
-	player_state_t	*ps, *ops;
-	player_state_t	dummy;
-	int				statbits;
-
-	ps = &to->ps;
-	if (!from)
-	{
-		memset (&dummy, 0, sizeof(dummy));
-		ops = &dummy;
-	}
-	else
-		ops = &from->ps;
-
-	//
-	// determine what needs to be sent
-	//
-	pflags = 0;
-
-	if (ps->pmove.pm_type != ops->pmove.pm_type)
-		pflags |= PS_M_TYPE;
-
-	if (ps->pmove.origin[0] != ops->pmove.origin[0]
-		|| ps->pmove.origin[1] != ops->pmove.origin[1]
-		|| ps->pmove.origin[2] != ops->pmove.origin[2] )
-		pflags |= PS_M_ORIGIN;
-
-	if (ps->pmove.velocity[0] != ops->pmove.velocity[0]
-		|| ps->pmove.velocity[1] != ops->pmove.velocity[1]
-		|| ps->pmove.velocity[2] != ops->pmove.velocity[2] )
-		pflags |= PS_M_VELOCITY;
-
-	if (ps->pmove.pm_time != ops->pmove.pm_time)
-		pflags |= PS_M_TIME;
-
-	if (ps->pmove.pm_flags != ops->pmove.pm_flags)
-		pflags |= PS_M_FLAGS;
-
-	if (ps->pmove.gravity != ops->pmove.gravity)
-		pflags |= PS_M_GRAVITY;
-
-	if (ps->pmove.delta_angles[0] != ops->pmove.delta_angles[0]
-		|| ps->pmove.delta_angles[1] != ops->pmove.delta_angles[1]
-		|| ps->pmove.delta_angles[2] != ops->pmove.delta_angles[2] )
-		pflags |= PS_M_DELTA_ANGLES;
-
-
-	if (ps->viewoffset[0] != ops->viewoffset[0]
-		|| ps->viewoffset[1] != ops->viewoffset[1]
-		|| ps->viewoffset[2] != ops->viewoffset[2] )
-		pflags |= PS_VIEWOFFSET;
-
-	if (ps->viewangles[0] != ops->viewangles[0]
-		|| ps->viewangles[1] != ops->viewangles[1]
-		|| ps->viewangles[2] != ops->viewangles[2] )
-		pflags |= PS_VIEWANGLES;
-
-	if (ps->kick_angles[0] != ops->kick_angles[0]
-		|| ps->kick_angles[1] != ops->kick_angles[1]
-		|| ps->kick_angles[2] != ops->kick_angles[2] )
-		pflags |= PS_KICKANGLES;
-
-	if (ps->blend[0] != ops->blend[0]
-		|| ps->blend[1] != ops->blend[1]
-		|| ps->blend[2] != ops->blend[2]
-		|| ps->blend[3] != ops->blend[3] )
-		pflags |= PS_BLEND;
-
-	if (ps->fov != ops->fov)
-		pflags |= PS_FOV;
-
-	if (ps->rdflags != ops->rdflags)
-		pflags |= PS_RDFLAGS;
-
-	if (ps->gunframe != ops->gunframe)
-		pflags |= PS_WEAPONFRAME;
-
-	pflags |= PS_WEAPONINDEX;
-
-	//
-	// write it
-	//
-	MSG_WriteByte (msg, svc_playerinfo);
-	MSG_WriteShort (msg, pflags);
-
-	//
-	// write the pmove_state_t
-	//
-	if (pflags & PS_M_TYPE)
-		MSG_WriteByte (msg, ps->pmove.pm_type);
-
-	if (pflags & PS_M_ORIGIN)
-	{
-		MSG_WriteShort (msg, ps->pmove.origin[0]);
-		MSG_WriteShort (msg, ps->pmove.origin[1]);
-		MSG_WriteShort (msg, ps->pmove.origin[2]);
-	}
-
-	if (pflags & PS_M_VELOCITY)
-	{
-		MSG_WriteShort (msg, ps->pmove.velocity[0]);
-		MSG_WriteShort (msg, ps->pmove.velocity[1]);
-		MSG_WriteShort (msg, ps->pmove.velocity[2]);
-	}
-
-	if (pflags & PS_M_TIME)
-		MSG_WriteByte (msg, ps->pmove.pm_time);
-
-	if (pflags & PS_M_FLAGS)
-		MSG_WriteByte (msg, ps->pmove.pm_flags);
-
-	if (pflags & PS_M_GRAVITY)
-		MSG_WriteShort (msg, ps->pmove.gravity);
-
-	if (pflags & PS_M_DELTA_ANGLES)
-	{
-		MSG_WriteShort (msg, ps->pmove.delta_angles[0]);
-		MSG_WriteShort (msg, ps->pmove.delta_angles[1]);
-		MSG_WriteShort (msg, ps->pmove.delta_angles[2]);
-	}
-
-	//
-	// write the rest of the player_state_t
-	//
-	if (pflags & PS_VIEWOFFSET)
-	{
-		MSG_WriteChar (msg, ps->viewoffset[0]*4);
-		MSG_WriteChar (msg, ps->viewoffset[1]*4);
-		MSG_WriteChar (msg, ps->viewoffset[2]*4);
-	}
-
-	if (pflags & PS_VIEWANGLES)
-	{
-		MSG_WriteAngle16 (msg, ps->viewangles[0]);
-		MSG_WriteAngle16 (msg, ps->viewangles[1]);
-		MSG_WriteAngle16 (msg, ps->viewangles[2]);
-	}
-
-	if (pflags & PS_KICKANGLES)
-	{
-		MSG_WriteChar (msg, ps->kick_angles[0]*4);
-		MSG_WriteChar (msg, ps->kick_angles[1]*4);
-		MSG_WriteChar (msg, ps->kick_angles[2]*4);
-	}
-
-	if (pflags & PS_WEAPONINDEX)
-	{
-		MSG_WriteByte (msg, ps->gunindex);
-	}
-
-	if (pflags & PS_WEAPONFRAME)
-	{
-		MSG_WriteByte (msg, ps->gunframe);
-		MSG_WriteChar (msg, ps->gunoffset[0]*4);
-		MSG_WriteChar (msg, ps->gunoffset[1]*4);
-		MSG_WriteChar (msg, ps->gunoffset[2]*4);
-		MSG_WriteChar (msg, ps->gunangles[0]*4);
-		MSG_WriteChar (msg, ps->gunangles[1]*4);
-		MSG_WriteChar (msg, ps->gunangles[2]*4);
-	}
-
-	if (pflags & PS_BLEND)
-	{
-		MSG_WriteByte (msg, ps->blend[0]*255);
-		MSG_WriteByte (msg, ps->blend[1]*255);
-		MSG_WriteByte (msg, ps->blend[2]*255);
-		MSG_WriteByte (msg, ps->blend[3]*255);
-	}
-	if (pflags & PS_FOV)
-		MSG_WriteByte (msg, ps->fov);
-	if (pflags & PS_RDFLAGS)
-		MSG_WriteByte (msg, ps->rdflags);
-
-	// send stats
-	statbits = 0;
-	for (i=0 ; i<MAX_STATS ; i++)
-		if (ps->stats[i] != ops->stats[i])
-			statbits |= 1<<i;
-	MSG_WriteLong (msg, statbits);
-	for (i=0 ; i<MAX_STATS ; i++)
-		if (statbits & (1<<i) )
-			MSG_WriteShort (msg, ps->stats[i]);
-}
-
-
-/*
-==================
-SV_WriteFrameToClient
-==================
-*/
-void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg)
-{
-	client_frame_t		*frame, *oldframe;
-	int					lastframe;
-
-//Com_Printf ("%i -> %i\n", client->lastframe, sv.framenum);
-	// this is the frame we are creating
-	frame = &client->frames[sv.framenum & UPDATE_MASK];
-
-	if (client->lastframe <= 0)
-	{	// client is asking for a retransmit
-		oldframe = NULL;
-		lastframe = -1;
-	}
-	else if (sv.framenum - client->lastframe >= (UPDATE_BACKUP - 3) )
-	{	// client hasn't gotten a good message through in a long time
-//		Com_Printf ("%s: Delta request from out-of-date packet.\n", client->name);
-		oldframe = NULL;
-		lastframe = -1;
-	}
-	else
-	{	// we have a valid message to delta from
-		oldframe = &client->frames[client->lastframe & UPDATE_MASK];
-		lastframe = client->lastframe;
-	}
-
-	MSG_WriteByte (msg, svc_frame);
-	MSG_WriteLong (msg, sv.framenum);
-	MSG_WriteLong (msg, lastframe);	// what we are delta'ing from
-	MSG_WriteByte (msg, client->surpressCount);	// rate dropped packets
-	client->surpressCount = 0;
-
-	// send over the areabits
-	MSG_WriteByte (msg, frame->areabytes);
-	SZ_Write (msg, frame->areabits, frame->areabytes);
-
-	// delta encode the playerstate
-	SV_WritePlayerstateToClient (oldframe, frame, msg);
-
-	// delta encode the entities
-	SV_EmitPacketEntities (oldframe, frame, msg);
-}
-
-
-/*
-=============================================================================
-
-Build a client frame structure
-
-=============================================================================
-*/
-
-byte		fatpvs[65536/8];	// 32767 is MAX_MAP_LEAFS
-
-/*
-============
-SV_FatPVS
-
-The client will interpolate the view position,
-so we can't use a single PVS point
-===========
-*/
-void SV_FatPVS (vec3_t org)
-{
-	int		leafs[64];
-	int		i, j, count;
-	int		longs;
-	byte	*src;
-	vec3_t	mins, maxs;
-
-	for (i=0 ; i<3 ; i++)
-	{
-		mins[i] = org[i] - 8;
-		maxs[i] = org[i] + 8;
-	}
-
-	count = CM_BoxLeafnums (mins, maxs, leafs, 64, NULL);
-	if (count < 1)
-		Com_Error (ERR_FATAL, "SV_FatPVS: count < 1");
-	longs = (CM_NumClusters()+31)>>5;
-
-	// convert leafs to clusters
-	for (i=0 ; i<count ; i++)
-		leafs[i] = CM_LeafCluster(leafs[i]);
-
-	memcpy (fatpvs, CM_ClusterPVS(leafs[0]), longs<<2);
-	// or in all the other leaf bits
-	for (i=1 ; i<count ; i++)
-	{
-		for (j=0 ; j<i ; j++)
-			if (leafs[i] == leafs[j])
-				break;
-		if (j != i)
-			continue;		// already have the cluster we want
-		src = CM_ClusterPVS(leafs[i]);
-		for (j=0 ; j<longs ; j++)
-			((long *)fatpvs)[j] |= ((long *)src)[j];
-	}
-}
-
-
-/*
-=============
-SV_BuildClientFrame
-
-Decides which entities are going to be visible to the client, and
-copies off the playerstat and areabits.
-=============
-*/
-void SV_BuildClientFrame (client_t *client)
-{
-	int		e, i;
-	vec3_t	org;
-	edict_t	*ent;
-	edict_t	*clent;
-	client_frame_t	*frame;
-	entity_state_t	*state;
-	int		l;
-	int		clientarea, clientcluster;
-	int		leafnum;
-	int		c_fullsend;
-	byte	*clientphs;
-	byte	*bitvector;
-
-	clent = client->edict;
-	if (!clent->client)
-		return;		// not in game yet
-
-	//numprojs = 0; // no projectiles yet
-
-	// this is the frame we are creating
-	frame = &client->frames[sv.framenum & UPDATE_MASK];
-
-	frame->senttime = svs.realtime; // save it for ping calc later
-
-	// find the client's PVS
-	for (i=0 ; i<3 ; i++)
-		org[i] = clent->client->ps.pmove.origin[i]*0.125 + clent->client->ps.viewoffset[i];
-
-	leafnum = CM_PointLeafnum (org);
-	clientarea = CM_LeafArea (leafnum);
-	clientcluster = CM_LeafCluster (leafnum);
-
-	// calculate the visible areas
-	frame->areabytes = CM_WriteAreaBits (frame->areabits, clientarea);
-
-	// grab the current player_state_t
-	frame->ps = clent->client->ps;
-
-
-	SV_FatPVS (org);
-	clientphs = CM_ClusterPHS (clientcluster);
-
-	// build up the list of visible entities
-	frame->num_entities = 0;
-	frame->first_entity = svs.next_client_entities;
-
-	c_fullsend = 0;
-
-	for (e=1 ; e<ge->num_edicts ; e++)
-	{
-		ent = EDICT_NUM(e);
-
-		// ignore ents without visible models
-		if (ent->svflags & SVF_NOCLIENT)
-			continue;
-
-		// ignore ents without visible models unless they have an effect
-		if (!ent->s.modelindex && !ent->s.effects && !ent->s.sound
-			&& !ent->s.event)
-			continue;
-
-		// ignore if not touching a PV leaf
-		if (ent != clent)
-		{
-			// check area
-			if (!CM_AreasConnected (clientarea, ent->areanum))
-			{	// doors can legally straddle two areas, so
-				// we may need to check another one
-				if (!ent->areanum2
-					|| !CM_AreasConnected (clientarea, ent->areanum2))
-					continue;		// blocked by a door
-			}
-
-			// beams just check one point for PHS
-			if (ent->s.renderfx & RF_BEAM)
-			{
-				l = ent->clusternums[0];
-				if ( !(clientphs[l >> 3] & (1 << (l&7) )) )
-					continue;
-			}
-			else
-			{
-				// FIXME: if an ent has a model and a sound, but isn't
-				// in the PVS, only the PHS, clear the model
-				if (ent->s.sound)
-				{
-					bitvector = fatpvs;	//clientphs;
-				}
-				else
-					bitvector = fatpvs;
-
-				if (ent->num_clusters == -1)
-				{	// too many leafs for individual check, go by headnode
-					if (!CM_HeadnodeVisible (ent->headnode, bitvector))
-						continue;
-					c_fullsend++;
-				}
-				else
-				{	// check individual leafs
-					for (i=0 ; i < ent->num_clusters ; i++)
-					{
-						l = ent->clusternums[i];
-						if (bitvector[l >> 3] & (1 << (l&7) ))
-							break;
-					}
-					if (i == ent->num_clusters)
-						continue;		// not visible
-				}
-
-				if (!ent->s.modelindex)
-				{	// don't send sounds if they will be attenuated away
-					vec3_t	delta;
-					float	len;
-
-					VectorSubtract (org, ent->s.origin, delta);
-					len = VectorLength (delta);
-					if (len > 400)
-						continue;
-				}
-			}
-		}
-
-/*
-		if (SV_AddProjectileUpdate(ent))
-			continue; // added as a special projectile
-*/
-
-		// add it to the circular client_entities array
-		state = &svs.client_entities[svs.next_client_entities%svs.num_client_entities];
-		if (ent->s.number != e)
-		{
-			Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n");
-			ent->s.number = e;
-		}
-		*state = ent->s;
-
-		// don't mark players missiles as solid
-		if (ent->owner == client->edict)
-			state->solid = 0;
-
-		svs.next_client_entities++;
-		frame->num_entities++;
-	}
-}
-
-
-/*
-==================
-SV_RecordDemoMessage
-
-Save everything in the world out without deltas.
-Used for recording footage for merged or assembled demos
-==================
-*/
-void SV_RecordDemoMessage (void)
-{
-	int			e;
-	edict_t		*ent;
-	entity_state_t	nostate;
-	sizebuf_t	buf;
-	byte		buf_data[32768];
-	int			len;
-
-	if (!svs.demofile)
-		return;
-
-	memset (&nostate, 0, sizeof(nostate));
-	SZ_Init (&buf, buf_data, sizeof(buf_data));
-
-	// write a frame message that doesn't contain a player_state_t
-	MSG_WriteByte (&buf, svc_frame);
-	MSG_WriteLong (&buf, sv.framenum);
-
-	MSG_WriteByte (&buf, svc_packetentities);
-
-	e = 1;
-	ent = EDICT_NUM(e);
-	while (e < ge->num_edicts) 
-	{
-		// ignore ents without visible models unless they have an effect
-		if (ent->inuse &&
-			ent->s.number && 
-			(ent->s.modelindex || ent->s.effects || ent->s.sound || ent->s.event) && 
-			!(ent->svflags & SVF_NOCLIENT))
-			MSG_WriteDeltaEntity (&nostate, &ent->s, &buf, false, true);
-
-		e++;
-		ent = EDICT_NUM(e);
-	}
-
-	MSG_WriteShort (&buf, 0);		// end of packetentities
-
-	// now add the accumulated multicast information
-	SZ_Write (&buf, svs.demo_multicast.data, svs.demo_multicast.cursize);
-	SZ_Clear (&svs.demo_multicast);
-
-	// now write the entire message to the file, prefixed by the length
-	len = LittleLong (buf.cursize);
-	fwrite (&len, 4, 1, svs.demofile);
-	fwrite (buf.data, buf.cursize, 1, svs.demofile);
-}
-
--- a/server/sv_game.c
+++ /dev/null
@@ -1,379 +1,0 @@
-// sv_game.c -- interface to the game dll
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-game_export_t	*ge;
-
-
-/*
-===============
-PF_Unicast
-
-Sends the contents of the mutlicast buffer to a single client
-===============
-*/
-void PF_Unicast (edict_t *ent, qboolean reliable)
-{
-	int		p;
-	client_t	*client;
-
-	if (!ent)
-		return;
-
-	p = NUM_FOR_EDICT(ent);
-	if (p < 1 || p > maxclients->value)
-		return;
-
-	client = svs.clients + (p-1);
-
-	if (reliable)
-		SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
-	else
-		SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
-
-	SZ_Clear (&sv.multicast);
-}
-
-
-/*
-===============
-PF_dprintf
-
-Debug print to server console
-===============
-*/
-void PF_dprintf (char *fmt, ...)
-{
-	char		msg[1024];
-	va_list		argptr;
-	
-	va_start (argptr,fmt);
-	vsprintf (msg, fmt, argptr);
-	va_end (argptr);
-
-	Com_Printf ("%s", msg);
-}
-
-
-/*
-===============
-PF_cprintf
-
-Print to a single client
-===============
-*/
-void PF_cprintf (edict_t *ent, int level, char *fmt, ...)
-{
-	char		msg[1024];
-	va_list		argptr;
-	int		n = 0;
-
-	if (ent)
-	{
-		n = NUM_FOR_EDICT(ent);
-		if (n < 1 || n > maxclients->value)
-			Com_Error (ERR_DROP, "cprintf to a non-client");
-	}
-
-	va_start (argptr,fmt);
-	vsprintf (msg, fmt, argptr);
-	va_end (argptr);
-
-	if (ent)
-		SV_ClientPrintf (svs.clients+(n-1), level, "%s", msg);
-	else
-		Com_Printf ("%s", msg);
-}
-
-
-/*
-===============
-PF_centerprintf
-
-centerprint to a single client
-===============
-*/
-void PF_centerprintf (edict_t *ent, char *fmt, ...)
-{
-	char		msg[1024];
-	va_list		argptr;
-	int			n;
-	
-	n = NUM_FOR_EDICT(ent);
-	if (n < 1 || n > maxclients->value)
-		return;	// Com_Error (ERR_DROP, "centerprintf to a non-client");
-
-	va_start (argptr,fmt);
-	vsprintf (msg, fmt, argptr);
-	va_end (argptr);
-
-	MSG_WriteByte (&sv.multicast,svc_centerprint);
-	MSG_WriteString (&sv.multicast,msg);
-	PF_Unicast (ent, true);
-}
-
-
-/*
-===============
-PF_error
-
-Abort the server with a game error
-===============
-*/
-void PF_error (char *fmt, ...)
-{
-	char		msg[1024];
-	va_list		argptr;
-	
-	va_start (argptr,fmt);
-	vsprintf (msg, fmt, argptr);
-	va_end (argptr);
-
-	Com_Error (ERR_DROP, "Game Error: %s", msg);
-}
-
-
-/*
-=================
-PF_setmodel
-
-Also sets mins and maxs for inline bmodels
-=================
-*/
-void PF_setmodel (edict_t *ent, char *name)
-{
-	int		i;
-	cmodel_t	*mod;
-
-	if (!name)
-		Com_Error (ERR_DROP, "PF_setmodel: NULL");
-
-	i = SV_ModelIndex (name);
-		
-//	ent->model = name;
-	ent->s.modelindex = i;
-
-// if it is an inline model, get the size information for it
-	if (name[0] == '*')
-	{
-		mod = CM_InlineModel (name);
-		VectorCopy (mod->mins, ent->mins);
-		VectorCopy (mod->maxs, ent->maxs);
-		SV_LinkEdict (ent);
-	}
-
-}
-
-/*
-===============
-PF_Configstring
-
-===============
-*/
-void PF_Configstring (int index, char *val)
-{
-	if (index < 0 || index >= MAX_CONFIGSTRINGS)
-		Com_Error (ERR_DROP, "configstring: bad index %i\n", index);
-
-	if (!val)
-		val = "";
-
-	// change the string in sv
-	strcpy (sv.configstrings[index], val);
-	
-	if (sv.state != ss_loading)
-	{	// send the update to everyone
-		SZ_Clear (&sv.multicast);
-		MSG_WriteChar (&sv.multicast, svc_configstring);
-		MSG_WriteShort (&sv.multicast, index);
-		MSG_WriteString (&sv.multicast, val);
-
-		SV_Multicast (vec3_origin, MULTICAST_ALL_R);
-	}
-}
-
-
-
-void PF_WriteChar (int c) {MSG_WriteChar (&sv.multicast, c);}
-void PF_WriteByte (int c) {MSG_WriteByte (&sv.multicast, c);}
-void PF_WriteShort (int c) {MSG_WriteShort (&sv.multicast, c);}
-void PF_WriteLong (int c) {MSG_WriteLong (&sv.multicast, c);}
-void PF_WriteFloat (float f) {MSG_WriteFloat (&sv.multicast, f);}
-void PF_WriteString (char *s) {MSG_WriteString (&sv.multicast, s);}
-void PF_WritePos (vec3_t pos) {MSG_WritePos (&sv.multicast, pos);}
-void PF_WriteDir (vec3_t dir) {MSG_WriteDir (&sv.multicast, dir);}
-void PF_WriteAngle (float f) {MSG_WriteAngle (&sv.multicast, f);}
-
-
-/*
-=================
-PF_inPVS
-
-Also checks portalareas so that doors block sight
-=================
-*/
-qboolean PF_inPVS (vec3_t p1, vec3_t p2)
-{
-	int		leafnum;
-	int		cluster;
-	int		area1, area2;
-	byte	*mask;
-
-	leafnum = CM_PointLeafnum (p1);
-	cluster = CM_LeafCluster (leafnum);
-	area1 = CM_LeafArea (leafnum);
-	mask = CM_ClusterPVS (cluster);
-
-	leafnum = CM_PointLeafnum (p2);
-	cluster = CM_LeafCluster (leafnum);
-	area2 = CM_LeafArea (leafnum);
-	if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
-		return false;
-	if (!CM_AreasConnected (area1, area2))
-		return false;		// a door blocks sight
-	return true;
-}
-
-
-/*
-=================
-PF_inPHS
-
-Also checks portalareas so that doors block sound
-=================
-*/
-qboolean PF_inPHS (vec3_t p1, vec3_t p2)
-{
-	int		leafnum;
-	int		cluster;
-	int		area1, area2;
-	byte	*mask;
-
-	leafnum = CM_PointLeafnum (p1);
-	cluster = CM_LeafCluster (leafnum);
-	area1 = CM_LeafArea (leafnum);
-	mask = CM_ClusterPHS (cluster);
-
-	leafnum = CM_PointLeafnum (p2);
-	cluster = CM_LeafCluster (leafnum);
-	area2 = CM_LeafArea (leafnum);
-	if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
-		return false;		// more than one bounce away
-	if (!CM_AreasConnected (area1, area2))
-		return false;		// a door blocks hearing
-
-	return true;
-}
-
-void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume,
-    float attenuation, float timeofs)
-{
-	if (!entity)
-		return;
-	SV_StartSound (NULL, entity, channel, sound_num, volume, attenuation, timeofs);
-}
-
-//==============================================
-
-/*
-===============
-SV_ShutdownGameProgs
-
-Called when either the entire server is being killed, or
-it is changing to a different game directory.
-===============
-*/
-void SV_ShutdownGameProgs (void)
-{
-	if (!ge)
-		return;
-	ge->Shutdown ();
-	Sys_UnloadGame ();
-	ge = NULL;
-}
-
-/*
-===============
-SV_InitGameProgs
-
-Init the game subsystem for a new map
-===============
-*/
-void SCR_DebugGraph (float value, int color);
-
-void SV_InitGameProgs (void)
-{
-	game_import_t	import;
-
-	// unload anything we have now
-	if (ge)
-		SV_ShutdownGameProgs ();
-
-
-	// load a new game dll
-	import.multicast = SV_Multicast;
-	import.unicast = PF_Unicast;
-	import.bprintf = SV_BroadcastPrintf;
-	import.dprintf = PF_dprintf;
-	import.cprintf = PF_cprintf;
-	import.centerprintf = PF_centerprintf;
-	import.error = PF_error;
-
-	import.linkentity = SV_LinkEdict;
-	import.unlinkentity = SV_UnlinkEdict;
-	import.BoxEdicts = SV_AreaEdicts;
-	import.trace = SV_Trace;
-	import.pointcontents = SV_PointContents;
-	import.setmodel = PF_setmodel;
-	import.inPVS = PF_inPVS;
-	import.inPHS = PF_inPHS;
-	import.Pmove = Pmove;
-
-	import.modelindex = SV_ModelIndex;
-	import.soundindex = SV_SoundIndex;
-	import.imageindex = SV_ImageIndex;
-
-	import.configstring = PF_Configstring;
-	import.sound = PF_StartSound;
-	import.positioned_sound = SV_StartSound;
-
-	import.WriteChar = PF_WriteChar;
-	import.WriteByte = PF_WriteByte;
-	import.WriteShort = PF_WriteShort;
-	import.WriteLong = PF_WriteLong;
-	import.WriteFloat = PF_WriteFloat;
-	import.WriteString = PF_WriteString;
-	import.WritePosition = PF_WritePos;
-	import.WriteDir = PF_WriteDir;
-	import.WriteAngle = PF_WriteAngle;
-
-	import.TagMalloc = Z_TagMalloc;
-	import.TagFree = Z_Free;
-	import.FreeTags = Z_FreeTags;
-
-	import.cvar = Cvar_Get;
-	import.cvar_set = Cvar_Set;
-	import.cvar_forceset = Cvar_ForceSet;
-
-	import.argc = Cmd_Argc;
-	import.argv = Cmd_Argv;
-	import.args = Cmd_Args;
-	import.AddCommandString = Cbuf_AddText;
-
-	import.DebugGraph = SCR_DebugGraph;
-	import.SetAreaPortalState = CM_SetAreaPortalState;
-	import.AreasConnected = CM_AreasConnected;
-
-	ge = GetGameAPI(&import);
-
-	if (!ge)
-		Com_Error (ERR_DROP, "failed to load game DLL");
-	if (ge->apiversion != GAME_API_VERSION)
-		Com_Error (ERR_DROP, "game is version %i, not %i", ge->apiversion,
-		GAME_API_VERSION);
-
-	ge->Init ();
-}
--- a/server/sv_init.c
+++ /dev/null
@@ -1,448 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-server_static_t	svs;				// persistant server info
-server_t		sv;					// local server
-
-/*
-================
-SV_FindIndex
-
-================
-*/
-int SV_FindIndex (char *name, int start, int max, qboolean create)
-{
-	int		i;
-	
-	if (!name || !name[0])
-		return 0;
-
-	for (i=1 ; i<max && sv.configstrings[start+i][0] ; i++)
-		if (!strcmp(sv.configstrings[start+i], name))
-			return i;
-
-	if (!create)
-		return 0;
-
-	if (i == max)
-		Com_Error (ERR_DROP, "*Index: overflow");
-
-	strncpy (sv.configstrings[start+i], name, sizeof(sv.configstrings[i]));
-
-	if (sv.state != ss_loading)
-	{	// send the update to everyone
-		SZ_Clear (&sv.multicast);
-		MSG_WriteChar (&sv.multicast, svc_configstring);
-		MSG_WriteShort (&sv.multicast, start+i);
-		MSG_WriteString (&sv.multicast, name);
-		SV_Multicast (vec3_origin, MULTICAST_ALL_R);
-	}
-
-	return i;
-}
-
-
-int SV_ModelIndex (char *name)
-{
-	return SV_FindIndex (name, CS_MODELS, MAX_MODELS, true);
-}
-
-int SV_SoundIndex (char *name)
-{
-	return SV_FindIndex (name, CS_SOUNDS, MAX_SOUNDS, true);
-}
-
-int SV_ImageIndex (char *name)
-{
-	return SV_FindIndex (name, CS_IMAGES, MAX_IMAGES, true);
-}
-
-
-/*
-================
-SV_CreateBaseline
-
-Entity baselines are used to compress the update messages
-to the clients -- only the fields that differ from the
-baseline will be transmitted
-================
-*/
-void SV_CreateBaseline (void)
-{
-	edict_t			*svent;
-	int				entnum;	
-
-	for (entnum = 1; entnum < ge->num_edicts ; entnum++)
-	{
-		svent = EDICT_NUM(entnum);
-		if (!svent->inuse)
-			continue;
-		if (!svent->s.modelindex && !svent->s.sound && !svent->s.effects)
-			continue;
-		svent->s.number = entnum;
-
-		//
-		// take current state as baseline
-		//
-		VectorCopy (svent->s.origin, svent->s.old_origin);
-		sv.baselines[entnum] = svent->s;
-	}
-}
-
-
-/*
-=================
-SV_CheckForSavegame
-=================
-*/
-void SV_CheckForSavegame (void)
-{
-	char		name[MAX_OSPATH];
-	FILE		*f;
-	int			i;
-
-	if (sv_noreload->value)
-		return;
-
-	if (Cvar_VariableValue ("deathmatch"))
-		return;
-
-	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
-	f = fopen (name, "rb");
-	if (!f)
-		return;		// no savegame
-
-	fclose (f);
-
-	SV_ClearWorld ();
-
-	// get configstrings and areaportals
-	SV_ReadLevelFile ();
-
-	if (!sv.loadgame)
-	{	// coming back to a level after being in a different
-		// level, so run it for ten seconds
-
-		// rlava2 was sending too many lightstyles, and overflowing the
-		// reliable data. temporarily changing the server state to loading
-		// prevents these from being passed down.
-		server_state_t		previousState;		// PGM
-
-		previousState = sv.state;				// PGM
-		sv.state = ss_loading;					// PGM
-		for (i=0 ; i<100 ; i++)
-			ge->RunFrame ();
-
-		sv.state = previousState;				// PGM
-	}
-}
-
-
-/*
-================
-SV_SpawnServer
-
-Change the server to a new map, taking all connected
-clients along with it.
-
-================
-*/
-void SV_SpawnServer (char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame)
-{
-	int			i;
-	unsigned	checksum;
-
-	if (attractloop)
-		Cvar_Set ("paused", "0");
-
-	Com_Printf ("------- Server Initialization -------\n");
-
-	Com_DPrintf ("SpawnServer: %s\n",server);
-	if (sv.demofile)
-		fclose (sv.demofile);
-
-	svs.spawncount++;		// any partially connected client will be
-							// restarted
-	sv.state = ss_dead;
-	Com_SetServerState (sv.state);
-
-	// wipe the entire per-level structure
-	memset (&sv, 0, sizeof(sv));
-	svs.realtime = 0;
-	sv.loadgame = loadgame;
-	sv.attractloop = attractloop;
-
-	// save name for levels that don't set message
-	strcpy (sv.configstrings[CS_NAME], server);
-	if (Cvar_VariableValue ("deathmatch"))
-	{
-		sprintf(sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value);
-		pm_airaccelerate = sv_airaccelerate->value;
-	}
-	else
-	{
-		strcpy(sv.configstrings[CS_AIRACCEL], "0");
-		pm_airaccelerate = 0;
-	}
-
-	SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf));
-
-	strcpy (sv.name, server);
-
-	// leave slots at start for clients only
-	for (i=0 ; i<maxclients->value ; i++)
-	{
-		// needs to reconnect
-		if (svs.clients[i].state > cs_connected)
-			svs.clients[i].state = cs_connected;
-		svs.clients[i].lastframe = -1;
-	}
-
-	sv.time = 1000;
-	
-	strcpy (sv.name, server);
-	strcpy (sv.configstrings[CS_NAME], server);
-
-	if (serverstate != ss_game)
-	{
-		sv.models[1] = CM_LoadMap ("", false, &checksum);	// no real map
-	}
-	else
-	{
-		Com_sprintf (sv.configstrings[CS_MODELS+1],sizeof(sv.configstrings[CS_MODELS+1]),
-			"maps/%s.bsp", server);
-		sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum);
-	}
-	Com_sprintf (sv.configstrings[CS_MAPCHECKSUM],sizeof(sv.configstrings[CS_MAPCHECKSUM]),
-		"%i", checksum);
-
-	//
-	// clear physics interaction links
-	//
-	SV_ClearWorld ();
-	
-	for (i=1 ; i< CM_NumInlineModels() ; i++)
-	{
-		Com_sprintf (sv.configstrings[CS_MODELS+1+i], sizeof(sv.configstrings[CS_MODELS+1+i]),
-			"*%i", i);
-		sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]);
-	}
-
-	//
-	// spawn the rest of the entities on the map
-	//	
-
-	// precache and static commands can be issued during
-	// map initialization
-	sv.state = ss_loading;
-	Com_SetServerState (sv.state);
-
-	// load and spawn all other entities
-	ge->SpawnEntities ( sv.name, CM_EntityString(), spawnpoint );
-
-	// run two frames to allow everything to settle
-	ge->RunFrame ();
-	ge->RunFrame ();
-
-	// all precaches are complete
-	sv.state = serverstate;
-	Com_SetServerState (sv.state);
-	
-	// create a baseline for more efficient communications
-	SV_CreateBaseline ();
-
-	// check for a savegame
-	SV_CheckForSavegame ();
-
-	// set serverinfo variable
-	Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET);
-
-	Com_Printf ("-------------------------------------\n");
-}
-
-/*
-==============
-SV_InitGame
-
-A brand new game has been started
-==============
-*/
-void SV_InitGame (void)
-{
-	int		i;
-	edict_t	*ent;
-	char	idmaster[32];
-
-	if (svs.initialized)
-	{
-		// cause any connected clients to reconnect
-		SV_Shutdown ("Server restarted\n", true);
-	}
-	else
-	{
-		// make sure the client is down
-		CL_Drop ();
-		SCR_BeginLoadingPlaque ();
-	}
-
-	// get any latched variable changes (maxclients, etc)
-	Cvar_GetLatchedVars ();
-
-	svs.initialized = true;
-
-	if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch"))
-	{
-		Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
-		Cvar_FullSet ("coop", "0",  CVAR_SERVERINFO | CVAR_LATCH);
-	}
-
-	// dedicated servers are can't be single player and are usually DM
-	// so unless they explicity set coop, force it to deathmatch
-	if (dedicated->value)
-	{
-		if (!Cvar_VariableValue ("coop"))
-			Cvar_FullSet ("deathmatch", "1",  CVAR_SERVERINFO | CVAR_LATCH);
-	}
-
-	// init clients
-	if (Cvar_VariableValue ("deathmatch"))
-	{
-		if (maxclients->value <= 1)
-			Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
-		else if (maxclients->value > MAX_CLIENTS)
-			Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
-	}
-	else if (Cvar_VariableValue ("coop"))
-	{
-		if (maxclients->value <= 1 || maxclients->value > 4)
-			Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
-#ifdef COPYPROTECT
-		if (!sv.attractloop && !dedicated->value)
-			Sys_CopyProtect ();
-#endif
-	}
-	else	// non-deathmatch, non-coop is one player
-	{
-		Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
-#ifdef COPYPROTECT
-		if (!sv.attractloop)
-			Sys_CopyProtect ();
-#endif
-	}
-
-	svs.spawncount = rand();
-	svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value);
-	svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64;
-	svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities);
-
-	// init network stuff
-	NET_Config ( (maxclients->value > 1) );
-
-	// heartbeats will always be sent to the id master
-	svs.last_heartbeat = -99999;		// send immediately
-	Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER);
-	NET_StringToAdr (idmaster, &master_adr[0]);
-
-	// init game
-	SV_InitGameProgs ();
-	for (i=0 ; i<maxclients->value ; i++)
-	{
-		ent = EDICT_NUM(i+1);
-		ent->s.number = i+1;
-		svs.clients[i].edict = ent;
-		memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd));
-	}
-}
-
-
-/*
-======================
-SV_Map
-
-  the full syntax is:
-
-  map [*]<map>$<startspot>+<nextserver>
-
-command from the console or progs.
-Map can also be a.cin, .pcx, or .dm2 file
-Nextserver is used to allow a cinematic to play, then proceed to
-another level:
-
-	map tram.cin+jail_e3
-======================
-*/
-void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame)
-{
-	char	level[MAX_QPATH];
-	char	*ch;
-	int		l;
-	char	spawnpoint[MAX_QPATH];
-
-	sv.loadgame = loadgame;
-	sv.attractloop = attractloop;
-
-	if (sv.state == ss_dead && !sv.loadgame)
-		SV_InitGame ();	// the game is just starting
-
-	strcpy (level, levelstring);
-
-	// if there is a + in the map, set nextserver to the remainder
-	ch = strstr(level, "+");
-	if (ch)
-	{
-		*ch = 0;
-			Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1));
-	}
-	else
-		Cvar_Set ("nextserver", "");
-
-	//ZOID special hack for end game screen in coop mode
-	if (Cvar_VariableValue ("coop") && !cistrcmp(level, "victory.pcx"))
-		Cvar_Set ("nextserver", "gamemap \"*base1\"");
-
-	// if there is a $, use the remainder as a spawnpoint
-	ch = strstr(level, "$");
-	if (ch)
-	{
-		*ch = 0;
-		strcpy (spawnpoint, ch+1);
-	}
-	else
-		spawnpoint[0] = 0;
-
-	// skip the end-of-unit flag if necessary
-	if (level[0] == '*')
-		strcpy (level, level+1);
-
-	l = strlen(level);
-	if (l > 4 && !strcmp (level+l-4, ".cin") )
-	{
-		SCR_BeginLoadingPlaque ();			// for local system
-		SV_BroadcastCommand ("changing\n");
-		SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame);
-	}
-	else if (l > 4 && !strcmp (level+l-4, ".dm2") )
-	{
-		SCR_BeginLoadingPlaque ();			// for local system
-		SV_BroadcastCommand ("changing\n");
-		SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame);
-	}
-	else if (l > 4 && !strcmp (level+l-4, ".pcx") )
-	{
-		SCR_BeginLoadingPlaque ();			// for local system
-		SV_BroadcastCommand ("changing\n");
-		SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame);
-	}
-	else
-	{
-		SCR_BeginLoadingPlaque ();			// for local system
-		SV_BroadcastCommand ("changing\n");
-		SV_SendClientMessages ();
-		SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame);
-		Cbuf_CopyToDefer ();
-	}
-
-	SV_BroadcastCommand ("reconnect\n");
-}
--- a/server/sv_main.c
+++ /dev/null
@@ -1,1035 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-netadr_t	master_adr[MAX_MASTERS];	// address of group servers
-
-client_t	*sv_client;			// current client
-
-cvar_t	*sv_paused;
-cvar_t	*sv_timedemo;
-
-cvar_t	*sv_enforcetime;
-
-cvar_t	*timeout;				// seconds without any message
-cvar_t	*zombietime;			// seconds to sink messages after disconnect
-
-cvar_t	*rcon_password;			// password for remote server commands
-
-cvar_t	*allow_download;
-cvar_t *allow_download_players;
-cvar_t *allow_download_models;
-cvar_t *allow_download_sounds;
-cvar_t *allow_download_maps;
-
-cvar_t *sv_airaccelerate;
-
-cvar_t	*sv_noreload;			// don't reload level state when reentering
-
-cvar_t	*maxclients;			// FIXME: rename sv_maxclients
-cvar_t	*sv_showclamp;
-
-cvar_t	*hostname;
-cvar_t	*public_server;			// should heartbeats be sent
-
-cvar_t	*sv_reconnect_limit;	// minimum seconds between connect messages
-
-void Master_Shutdown (void);
-
-
-//============================================================================
-
-
-/*
-=====================
-SV_DropClient
-
-Called when the player is totally leaving the server, either willingly
-or unwillingly.  This is NOT called if the entire server is quiting
-or crashing.
-=====================
-*/
-void SV_DropClient (client_t *drop)
-{
-	// add the disconnect
-	MSG_WriteByte (&drop->netchan.message, svc_disconnect);
-
-	if (drop->state == cs_spawned)
-	{
-		// call the prog function for removing a client
-		// this will remove the body, among other things
-		ge->ClientDisconnect (drop->edict);
-	}
-
-	if (drop->download)
-	{
-		FS_FreeFile (drop->download);
-		drop->download = NULL;
-	}
-
-	drop->state = cs_zombie;		// become free in a few seconds
-	drop->name[0] = 0;
-}
-
-
-
-/*
-==============================================================================
-
-CONNECTIONLESS COMMANDS
-
-==============================================================================
-*/
-
-/*
-===============
-SV_StatusString
-
-Builds the string that is sent as heartbeats and status replies
-===============
-*/
-char	*SV_StatusString (void)
-{
-	char	player[1024];
-	static char	status[MAX_MSGLEN - 16];
-	int		i;
-	client_t	*cl;
-	int		statusLength;
-	int		playerLength;
-
-	strcpy (status, Cvar_Serverinfo());
-	strcat (status, "\n");
-	statusLength = strlen(status);
-
-	for (i=0 ; i<maxclients->value ; i++)
-	{
-		cl = &svs.clients[i];
-		if (cl->state == cs_connected || cl->state == cs_spawned )
-		{
-			Com_sprintf (player, sizeof(player), "%i %i \"%s\"\n", 
-				cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, cl->name);
-			playerLength = strlen(player);
-			if (statusLength + playerLength >= sizeof(status) )
-				break;		// can't hold any more
-			strcpy (status + statusLength, player);
-			statusLength += playerLength;
-		}
-	}
-
-	return status;
-}
-
-/*
-================
-SVC_Status
-
-Responds with all the info that qplug or qspy can see
-================
-*/
-void SVC_Status (void)
-{
-	Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", SV_StatusString());
-/*
-	Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
-	Com_Printf (SV_StatusString());
-	Com_EndRedirect ();
-*/
-}
-
-/*
-================
-SVC_Ack
-
-================
-*/
-void SVC_Ack (void)
-{
-	Com_Printf ("Ping acknowledge from %s\n", NET_AdrToString(net_from));
-}
-
-/*
-================
-SVC_Info
-
-Responds with short info for broadcast scans
-The second parameter should be the current protocol version number.
-================
-*/
-void SVC_Info (void)
-{
-	char	string[64];
-	int		i, count;
-	int		version;
-
-	if (maxclients->value == 1)
-		return;		// ignore in single player
-
-	version = atoi (Cmd_Argv(1));
-
-	if (version != PROTOCOL_VERSION)
-		Com_sprintf (string, sizeof(string), "%s: wrong version\n", hostname->string, sizeof(string));
-	else
-	{
-		count = 0;
-		for (i=0 ; i<maxclients->value ; i++)
-			if (svs.clients[i].state >= cs_connected)
-				count++;
-
-		Com_sprintf (string, sizeof(string), "%16s %8s %2i/%2i\n", hostname->string, sv.name, count, (int)maxclients->value);
-	}
-
-	Netchan_OutOfBandPrint (NS_SERVER, net_from, "info\n%s", string);
-}
-
-/*
-================
-SVC_Ping
-
-Just responds with an acknowledgement
-================
-*/
-void SVC_Ping (void)
-{
-	Netchan_OutOfBandPrint (NS_SERVER, net_from, "ack");
-}
-
-
-/*
-=================
-SVC_GetChallenge
-
-Returns a challenge number that can be used
-in a subsequent client_connect command.
-We do this to prevent denial of service attacks that
-flood the server with invalid connection IPs.  With a
-challenge, they must give a valid IP address.
-=================
-*/
-void SVC_GetChallenge (void)
-{
-	int		i;
-	int		oldest;
-	int		oldestTime;
-
-	oldest = 0;
-	oldestTime = 0x7fffffff;
-
-	// see if we already have a challenge for this ip
-	for (i = 0 ; i < MAX_CHALLENGES ; i++)
-	{
-		if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
-			break;
-		if (svs.challenges[i].time < oldestTime)
-		{
-			oldestTime = svs.challenges[i].time;
-			oldest = i;
-		}
-	}
-
-	if (i == MAX_CHALLENGES)
-	{
-		// overwrite the oldest
-		svs.challenges[oldest].challenge = rand() & 0x7fff;
-		svs.challenges[oldest].adr = net_from;
-		svs.challenges[oldest].time = curtime;
-		i = oldest;
-	}
-
-	// send it back
-	Netchan_OutOfBandPrint (NS_SERVER, net_from, "challenge %i", svs.challenges[i].challenge);
-}
-
-/*
-==================
-SVC_DirectConnect
-
-A connection request that did not come from the master
-==================
-*/
-void SVC_DirectConnect (void)
-{
-	char		userinfo[MAX_INFO_STRING];
-	netadr_t	adr;
-	int			i;
-	client_t	*cl, *newcl;
-	client_t	temp;
-	edict_t		*ent;
-	int			edictnum;
-	int			version;
-	int			qport;
-	int			challenge;
-
-	adr = net_from;
-
-	Com_DPrintf ("SVC_DirectConnect ()\n");
-
-	version = atoi(Cmd_Argv(1));
-	if (version != PROTOCOL_VERSION)
-	{
-		Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is version %4.2f.\n", VERSION);
-		Com_DPrintf ("    rejected connect from version %i\n", version);
-		return;
-	}
-
-	qport = atoi(Cmd_Argv(2));
-
-	challenge = atoi(Cmd_Argv(3));
-
-	strncpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-1);
-	userinfo[sizeof(userinfo) - 1] = 0;
-
-	// force the IP key/value pair so the game can filter based on ip
-	Info_SetValueForKey (userinfo, "ip", NET_AdrToString(net_from));
-
-	// attractloop servers are ONLY for local clients
-	if (sv.attractloop)
-	{
-		if (!NET_IsLocalAddress (adr))
-		{
-			Com_Printf ("Remote connect in attract loop.  Ignored.\n");
-			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n");
-			return;
-		}
-	}
-
-	// see if the challenge is valid
-	if (!NET_IsLocalAddress (adr))
-	{
-		for (i=0 ; i<MAX_CHALLENGES ; i++)
-		{
-			if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
-			{
-				if (challenge == svs.challenges[i].challenge)
-					break;		// good
-				Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nBad challenge.\n");
-				return;
-			}
-		}
-		if (i == MAX_CHALLENGES)
-		{
-			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nNo challenge for address.\n");
-			return;
-		}
-	}
-
-	newcl = &temp;
-	memset (newcl, 0, sizeof(client_t));
-
-	// if there is already a slot for this ip, reuse it
-	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
-	{
-		if (cl->state == cs_free)
-			continue;
-		if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
-			&& ( cl->netchan.qport == qport 
-			|| adr.port == cl->netchan.remote_address.port ) )
-		{
-			if (!NET_IsLocalAddress (adr) && (svs.realtime - cl->lastconnect) < ((int)sv_reconnect_limit->value * 1000))
-			{
-				Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (adr));
-				return;
-			}
-			Com_Printf ("%s:reconnect\n", NET_AdrToString (adr));
-			newcl = cl;
-			goto gotnewcl;
-		}
-	}
-
-	// find a client slot
-	newcl = NULL;
-	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
-	{
-		if (cl->state == cs_free)
-		{
-			newcl = cl;
-			break;
-		}
-	}
-	if (!newcl)
-	{
-		Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is full.\n");
-		Com_DPrintf ("Rejected a connection.\n");
-		return;
-	}
-
-gotnewcl:	
-	// build a new connection
-	// accept the new client
-	// this is the only place a client_t is ever initialized
-	*newcl = temp;
-	sv_client = newcl;
-	edictnum = (newcl-svs.clients)+1;
-	ent = EDICT_NUM(edictnum);
-	newcl->edict = ent;
-	newcl->challenge = challenge; // save challenge for checksumming
-
-	// get the game a chance to reject this connection or modify the userinfo
-	if (!(ge->ClientConnect (ent, userinfo)))
-	{
-		if (*Info_ValueForKey (userinfo, "rejmsg")) 
-			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\n%s\nConnection refused.\n",  
-				Info_ValueForKey (userinfo, "rejmsg"));
-		else
-			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n" );
-		Com_DPrintf ("Game rejected a connection.\n");
-		return;
-	}
-
-	// parse some info from the info strings
-	strncpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)-1);
-	SV_UserinfoChanged (newcl);
-
-	// send the connect packet to the client
-	Netchan_OutOfBandPrint (NS_SERVER, adr, "client_connect");
-
-	Netchan_Setup (NS_SERVER, &newcl->netchan , adr, qport);
-
-	newcl->state = cs_connected;
-	
-	SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf) );
-	newcl->datagram.allowoverflow = true;
-	newcl->lastmessage = svs.realtime;	// don't timeout
-	newcl->lastconnect = svs.realtime;
-}
-
-int Rcon_Validate (void)
-{
-	if (!strlen (rcon_password->string))
-		return 0;
-
-	if (strcmp (Cmd_Argv(1), rcon_password->string) )
-		return 0;
-
-	return 1;
-}
-
-/*
-===============
-SVC_RemoteCommand
-
-A client issued an rcon command.
-Shift down the remaining args
-Redirect all printfs
-===============
-*/
-void SVC_RemoteCommand (void)
-{
-	int		i;
-	char	remaining[1024];
-
-	i = Rcon_Validate ();
-
-	if (i == 0)
-		Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
-	else
-		Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
-
-	Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
-
-	if (!Rcon_Validate ())
-	{
-		Com_Printf ("Bad rcon_password.\n");
-	}
-	else
-	{
-		remaining[0] = 0;
-
-		for (i=2 ; i<Cmd_Argc() ; i++)
-		{
-			strcat (remaining, Cmd_Argv(i) );
-			strcat (remaining, " ");
-		}
-
-		Cmd_ExecuteString (remaining);
-	}
-
-	Com_EndRedirect ();
-}
-
-/*
-=================
-SV_ConnectionlessPacket
-
-A connectionless packet has four leading 0xff
-characters to distinguish it from a game channel.
-Clients that are in the game can still send
-connectionless packets.
-=================
-*/
-void SV_ConnectionlessPacket (void)
-{
-	char	*s;
-	char	*c;
-
-	MSG_BeginReading (&net_message);
-	MSG_ReadLong (&net_message);		// skip the -1 marker
-
-	s = MSG_ReadStringLine (&net_message);
-
-	Cmd_TokenizeString (s, false);
-
-	c = Cmd_Argv(0);
-	Com_DPrintf ("Packet %s : %s\n", NET_AdrToString(net_from), c);
-
-	if (!strcmp(c, "ping"))
-		SVC_Ping ();
-	else if (!strcmp(c, "ack"))
-		SVC_Ack ();
-	else if (!strcmp(c,"status"))
-		SVC_Status ();
-	else if (!strcmp(c,"info"))
-		SVC_Info ();
-	else if (!strcmp(c,"getchallenge"))
-		SVC_GetChallenge ();
-	else if (!strcmp(c,"connect"))
-		SVC_DirectConnect ();
-	else if (!strcmp(c, "rcon"))
-		SVC_RemoteCommand ();
-	else
-		Com_Printf ("bad connectionless packet from %s:\n%s\n"
-		, NET_AdrToString (net_from), s);
-}
-
-
-//============================================================================
-
-/*
-===================
-SV_CalcPings
-
-Updates the cl->ping variables
-===================
-*/
-void SV_CalcPings (void)
-{
-	int			i, j;
-	client_t	*cl;
-	int			total, count;
-
-	for (i=0 ; i<maxclients->value ; i++)
-	{
-		cl = &svs.clients[i];
-		if (cl->state != cs_spawned )
-			continue;
-
-/*
-		if (cl->lastframe > 0)
-			cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = sv.framenum - cl->lastframe + 1;
-		else
-			cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = 0;
-*/
-
-		total = 0;
-		count = 0;
-		for (j=0 ; j<LATENCY_COUNTS ; j++)
-		{
-			if (cl->frame_latency[j] > 0)
-			{
-				count++;
-				total += cl->frame_latency[j];
-			}
-		}
-		if (!count)
-			cl->ping = 0;
-		else
-			//cl->ping = total*100/count - 100;
-			cl->ping = total / count;
-
-		// let the game dll know about the ping
-		cl->edict->client->ping = cl->ping;
-	}
-}
-
-
-/*
-===================
-SV_GiveMsec
-
-Every few frames, gives all clients an allotment of milliseconds
-for their command moves.  If they exceed it, assume cheating.
-===================
-*/
-void SV_GiveMsec (void)
-{
-	int			i;
-	client_t	*cl;
-
-	if (sv.framenum & 15)
-		return;
-
-	for (i=0 ; i<maxclients->value ; i++)
-	{
-		cl = &svs.clients[i];
-		if (cl->state == cs_free )
-			continue;
-		
-		cl->commandMsec = 1800;		// 1600 + some slop
-	}
-}
-
-
-/*
-=================
-SV_ReadPackets
-=================
-*/
-void SV_ReadPackets (void)
-{
-	int			i;
-	client_t	*cl;
-	int			qport;
-
-	while (NET_GetPacket (NS_SERVER, &net_from, &net_message))
-	{
-		// check for connectionless packet (0xffffffff) first
-		if (*(int *)net_message.data == -1)
-		{
-			SV_ConnectionlessPacket ();
-			continue;
-		}
-
-		// read the qport out of the message so we can fix up
-		// stupid address translating routers
-		MSG_BeginReading (&net_message);
-		MSG_ReadLong (&net_message);		// sequence number
-		MSG_ReadLong (&net_message);		// sequence number
-		qport = MSG_ReadShort (&net_message) & 0xffff;
-
-		// check for packets from connected clients
-		for (i=0, cl=svs.clients ; i<maxclients->value ; i++,cl++)
-		{
-			if (cl->state == cs_free)
-				continue;
-			if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
-				continue;
-			if (cl->netchan.qport != qport)
-				continue;
-			if (cl->netchan.remote_address.port != net_from.port)
-			{
-				Com_Printf ("SV_ReadPackets: fixing up a translated port\n");
-				cl->netchan.remote_address.port = net_from.port;
-			}
-
-			if (Netchan_Process(&cl->netchan, &net_message))
-			{	// this is a valid, sequenced packet, so process it
-				if (cl->state != cs_zombie)
-				{
-					cl->lastmessage = svs.realtime;	// don't timeout
-					SV_ExecuteClientMessage (cl);
-				}
-			}
-			break;
-		}
-		
-		if (i != maxclients->value)
-			continue;
-	}
-}
-
-/*
-==================
-SV_CheckTimeouts
-
-If a packet has not been received from a client for timeout->value
-seconds, drop the conneciton.  Server frames are used instead of
-realtime to avoid dropping the local client while debugging.
-
-When a client is normally dropped, the client_t goes into a zombie state
-for a few seconds to make sure any final reliable message gets resent
-if necessary
-==================
-*/
-void SV_CheckTimeouts (void)
-{
-	int		i;
-	client_t	*cl;
-	int			droppoint;
-	int			zombiepoint;
-
-	droppoint = svs.realtime - 1000*timeout->value;
-	zombiepoint = svs.realtime - 1000*zombietime->value;
-
-	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
-	{
-		// message times may be wrong across a changelevel
-		if (cl->lastmessage > svs.realtime)
-			cl->lastmessage = svs.realtime;
-
-		if (cl->state == cs_zombie
-		&& cl->lastmessage < zombiepoint)
-		{
-			cl->state = cs_free;	// can now be reused
-			continue;
-		}
-		if ( (cl->state == cs_connected || cl->state == cs_spawned) 
-			&& cl->lastmessage < droppoint)
-		{
-			SV_BroadcastPrintf (PRINT_HIGH, "%s timed out\n", cl->name);
-			SV_DropClient (cl); 
-			cl->state = cs_free;	// don't bother with zombie state
-		}
-	}
-}
-
-/*
-================
-SV_PrepWorldFrame
-
-This has to be done before the world logic, because
-player processing happens outside RunWorldFrame
-================
-*/
-void SV_PrepWorldFrame (void)
-{
-	edict_t	*ent;
-	int		i;
-
-	for (i=0 ; i<ge->num_edicts ; i++)
-	{
-		ent = EDICT_NUM(i);
-		// events only last for a single message
-		ent->s.event = 0;
-	}
-
-}
-
-
-/*
-=================
-SV_RunGameFrame
-=================
-*/
-void SV_RunGameFrame (void)
-{
-	if (host_speeds->value)
-		time_before_game = Sys_Milliseconds ();
-
-	// we always need to bump framenum, even if we
-	// don't run the world, otherwise the delta
-	// compression can get confused when a client
-	// has the "current" frame
-	sv.framenum++;
-	sv.time = sv.framenum*100;
-
-	// don't run if paused
-	if (!sv_paused->value || maxclients->value > 1)
-	{
-		ge->RunFrame ();
-
-		// never get more than one tic behind
-		if (sv.time < svs.realtime)
-		{
-			if (sv_showclamp->value)
-				Com_Printf ("sv highclamp\n");
-			svs.realtime = sv.time;
-		}
-	}
-
-	if (host_speeds->value)
-		time_after_game = Sys_Milliseconds ();
-
-}
-
-/*
-==================
-SV_Frame
-
-==================
-*/
-void SV_Frame (int msec)
-{
-	time_before_game = time_after_game = 0;
-
-	// if server is not active, do nothing
-	if (!svs.initialized)
-		return;
-
-    svs.realtime += msec;
-
-	// keep the random time dependent
-	rand ();
-
-	// check timeouts
-	SV_CheckTimeouts ();
-
-	// get packets from clients
-	SV_ReadPackets ();
-
-	// move autonomous things around if enough time has passed
-	if (!sv_timedemo->value && svs.realtime < sv.time)
-	{
-		// never let the time get too far off
-		if (sv.time - svs.realtime > 100)
-		{
-			if (sv_showclamp->value)
-				Com_Printf ("sv lowclamp\n");
-			svs.realtime = sv.time - 100;
-		}
-		NET_Sleep(sv.time - svs.realtime);
-		return;
-	}
-
-	// update ping based on the last known frame from all clients
-	SV_CalcPings ();
-
-	// give the clients some timeslices
-	SV_GiveMsec ();
-
-	// let everything in the world think and move
-	SV_RunGameFrame ();
-
-	// send messages back to the clients that had packets read this frame
-	SV_SendClientMessages ();
-
-	// save the entire world state if recording a serverdemo
-	SV_RecordDemoMessage ();
-
-	// send a heartbeat to the master if needed
-	Master_Heartbeat ();
-
-	// clear teleport flags, etc for next frame
-	SV_PrepWorldFrame ();
-
-}
-
-//============================================================================
-
-/*
-================
-Master_Heartbeat
-
-Send a message to the master every few minutes to
-let it know we are alive, and log information
-================
-*/
-#define	HEARTBEAT_SECONDS	300
-void Master_Heartbeat (void)
-{
-	char		*string;
-	int			i;
-
-	
-	if (!dedicated->value)
-		return;		// only dedicated servers send heartbeats
-
-	if (!public_server->value)
-		return;		// a private dedicated game
-
-	// check for time wraparound
-	if (svs.last_heartbeat > svs.realtime)
-		svs.last_heartbeat = svs.realtime;
-
-	if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS*1000)
-		return;		// not time to send yet
-
-	svs.last_heartbeat = svs.realtime;
-
-	// send the same string that we would give for a status OOB command
-	string = SV_StatusString();
-
-	// send to group master
-	for (i=0 ; i<MAX_MASTERS ; i++)
-		if (master_adr[i].port)
-		{
-			Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
-			Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "heartbeat\n%s", string);
-		}
-}
-
-/*
-=================
-Master_Shutdown
-
-Informs all masters that this server is going down
-=================
-*/
-void Master_Shutdown (void)
-{
-	int			i;
-
-	if (!dedicated->value)
-		return;		// only dedicated servers send heartbeats
-
-	if (!public_server->value)
-		return;		// a private dedicated game
-
-	// send to group master
-	for (i=0 ; i<MAX_MASTERS ; i++)
-		if (master_adr[i].port)
-		{
-			if (i > 0)
-				Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
-			Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "shutdown");
-		}
-}
-
-//============================================================================
-
-
-/*
-=================
-SV_UserinfoChanged
-
-Pull specific info from a newly changed userinfo string
-into a more C freindly form.
-=================
-*/
-void SV_UserinfoChanged (client_t *cl)
-{
-	char	*val;
-	int		i;
-
-	// call prog code to allow overrides
-	ge->ClientUserinfoChanged (cl->edict, cl->userinfo);
-	
-	// name for C code
-	strncpy (cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name)-1);
-	// mask off high bit
-	for (i=0 ; i<sizeof(cl->name) ; i++)
-		cl->name[i] &= 127;
-
-	// rate command
-	val = Info_ValueForKey (cl->userinfo, "rate");
-	if (strlen(val))
-	{
-		i = atoi(val);
-		cl->rate = i;
-		if (cl->rate < 100)
-			cl->rate = 100;
-		if (cl->rate > 15000)
-			cl->rate = 15000;
-	}
-	else
-		cl->rate = 5000;
-
-	// msg command
-	val = Info_ValueForKey (cl->userinfo, "msg");
-	if (strlen(val))
-	{
-		cl->messagelevel = atoi(val);
-	}
-
-}
-
-
-//============================================================================
-
-/*
-===============
-SV_Init
-
-Only called at quake2.exe startup, not for each game
-===============
-*/
-void SV_Init (void)
-{
-	SV_InitOperatorCommands	();
-
-	rcon_password = Cvar_Get ("rcon_password", "", 0);
-	Cvar_Get ("skill", "1", 0);
-	Cvar_Get ("deathmatch", "0", CVAR_LATCH);
-	Cvar_Get ("coop", "0", CVAR_LATCH);
-	Cvar_Get ("dmflags", va("%i", DF_INSTANT_ITEMS), CVAR_SERVERINFO);
-	Cvar_Get ("fraglimit", "0", CVAR_SERVERINFO);
-	Cvar_Get ("timelimit", "0", CVAR_SERVERINFO);
-	Cvar_Get ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
-	Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO|CVAR_NOSET);;
-	maxclients = Cvar_Get ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
-	hostname = Cvar_Get ("hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE);
-	timeout = Cvar_Get ("timeout", "125", 0);
-	zombietime = Cvar_Get ("zombietime", "2", 0);
-	sv_showclamp = Cvar_Get ("showclamp", "0", 0);
-	sv_paused = Cvar_Get ("paused", "0", 0);
-	sv_timedemo = Cvar_Get ("timedemo", "0", 0);
-	sv_enforcetime = Cvar_Get ("sv_enforcetime", "0", 0);
-	allow_download = Cvar_Get ("allow_download", "0", CVAR_ARCHIVE);
-	allow_download_players  = Cvar_Get ("allow_download_players", "0", CVAR_ARCHIVE);
-	allow_download_models = Cvar_Get ("allow_download_models", "1", CVAR_ARCHIVE);
-	allow_download_sounds = Cvar_Get ("allow_download_sounds", "1", CVAR_ARCHIVE);
-	allow_download_maps	  = Cvar_Get ("allow_download_maps", "1", CVAR_ARCHIVE);
-
-	sv_noreload = Cvar_Get ("sv_noreload", "0", 0);
-
-	sv_airaccelerate = Cvar_Get("sv_airaccelerate", "0", CVAR_LATCH);
-
-	public_server = Cvar_Get ("public", "0", 0);
-
-	sv_reconnect_limit = Cvar_Get ("sv_reconnect_limit", "3", CVAR_ARCHIVE);
-
-	SZ_Init (&net_message, net_message_buffer, sizeof(net_message_buffer));
-}
-
-/*
-==================
-SV_FinalMessage
-
-Used by SV_Shutdown to send a final message to all
-connected clients before the server goes down.  The messages are sent immediately,
-not just stuck on the outgoing message list, because the server is going
-to totally exit after returning from this function.
-==================
-*/
-void SV_FinalMessage (char *message, qboolean reconnect)
-{
-	int			i;
-	client_t	*cl;
-	
-	SZ_Clear (&net_message);
-	MSG_WriteByte (&net_message, svc_print);
-	MSG_WriteByte (&net_message, PRINT_HIGH);
-	MSG_WriteString (&net_message, message);
-
-	if (reconnect)
-		MSG_WriteByte (&net_message, svc_reconnect);
-	else
-		MSG_WriteByte (&net_message, svc_disconnect);
-
-	// send it twice
-	// stagger the packets to crutch operating system limited buffers
-
-	for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
-		if (cl->state >= cs_connected)
-			Netchan_Transmit (&cl->netchan, net_message.cursize
-			, net_message.data);
-
-	for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
-		if (cl->state >= cs_connected)
-			Netchan_Transmit (&cl->netchan, net_message.cursize
-			, net_message.data);
-}
-
-
-
-/*
-================
-SV_Shutdown
-
-Called when each game quits,
-before Sys_Quit or Sys_Error
-================
-*/
-void SV_Shutdown (char *finalmsg, qboolean reconnect)
-{
-	if (svs.clients)
-		SV_FinalMessage (finalmsg, reconnect);
-
-	Master_Shutdown ();
-	SV_ShutdownGameProgs ();
-
-	// free current level
-	if (sv.demofile)
-		fclose (sv.demofile);
-	memset (&sv, 0, sizeof(sv));
-	Com_SetServerState (sv.state);
-
-	// free server static data
-	if (svs.clients)
-		Z_Free (svs.clients);
-	if (svs.client_entities)
-		Z_Free (svs.client_entities);
-	if (svs.demofile)
-		fclose (svs.demofile);
-	memset (&svs, 0, sizeof(svs));
-}
-
--- a/server/sv_send.c
+++ /dev/null
@@ -1,547 +1,0 @@
-// sv_main.c -- server main program
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-=============================================================================
-
-Com_Printf redirection
-
-=============================================================================
-*/
-
-char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
-
-void SV_FlushRedirect (int sv_redirected, char *outputbuf)
-{
-	if (sv_redirected == RD_PACKET)
-	{
-		Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", outputbuf);
-	}
-	else if (sv_redirected == RD_CLIENT)
-	{
-		MSG_WriteByte (&sv_client->netchan.message, svc_print);
-		MSG_WriteByte (&sv_client->netchan.message, PRINT_HIGH);
-		MSG_WriteString (&sv_client->netchan.message, outputbuf);
-	}
-}
-
-
-/*
-=============================================================================
-
-EVENT MESSAGES
-
-=============================================================================
-*/
-
-
-/*
-=================
-SV_ClientPrintf
-
-Sends text across to be displayed if the level passes
-=================
-*/
-void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...)
-{
-	va_list		argptr;
-	char		string[1024];
-	
-	if (level < cl->messagelevel)
-		return;
-	
-	va_start (argptr,fmt);
-	vsprintf (string, fmt,argptr);
-	va_end (argptr);
-	
-	MSG_WriteByte (&cl->netchan.message, svc_print);
-	MSG_WriteByte (&cl->netchan.message, level);
-	MSG_WriteString (&cl->netchan.message, string);
-}
-
-/*
-=================
-SV_BroadcastPrintf
-
-Sends text to all active clients
-=================
-*/
-void SV_BroadcastPrintf (int level, char *fmt, ...)
-{
-	va_list		argptr;
-	char		string[2048];
-	client_t	*cl;
-	int			i;
-
-	va_start (argptr,fmt);
-	vsprintf (string, fmt,argptr);
-	va_end (argptr);
-	
-	// echo to console
-	if (dedicated->value)
-	{
-		char	copy[1024];
-		int		i;
-		
-		// mask off high bits
-		for (i=0 ; i<1023 && string[i] ; i++)
-			copy[i] = string[i]&127;
-		copy[i] = 0;
-		Com_Printf ("%s", copy);
-	}
-
-	for (i=0, cl = svs.clients ; i<maxclients->value; i++, cl++)
-	{
-		if (level < cl->messagelevel)
-			continue;
-		if (cl->state != cs_spawned)
-			continue;
-		MSG_WriteByte (&cl->netchan.message, svc_print);
-		MSG_WriteByte (&cl->netchan.message, level);
-		MSG_WriteString (&cl->netchan.message, string);
-	}
-}
-
-/*
-=================
-SV_BroadcastCommand
-
-Sends text to all active clients
-=================
-*/
-void SV_BroadcastCommand (char *fmt, ...)
-{
-	va_list		argptr;
-	char		string[1024];
-	
-	if (!sv.state)
-		return;
-	va_start (argptr,fmt);
-	vsprintf (string, fmt,argptr);
-	va_end (argptr);
-
-	MSG_WriteByte (&sv.multicast, svc_stufftext);
-	MSG_WriteString (&sv.multicast, string);
-	SV_Multicast (NULL, MULTICAST_ALL_R);
-}
-
-
-/*
-=================
-SV_Multicast
-
-Sends the contents of sv.multicast to a subset of the clients,
-then clears sv.multicast.
-
-MULTICAST_ALL	same as broadcast (origin can be NULL)
-MULTICAST_PVS	send to clients potentially visible from org
-MULTICAST_PHS	send to clients potentially hearable from org
-=================
-*/
-void SV_Multicast (vec3_t origin, multicast_t to)
-{
-	client_t	*client;
-	byte		*mask;
-	int			leafnum, cluster;
-	int			j;
-	qboolean	reliable;
-	int			area1, area2;
-
-	reliable = false;
-
-	if (to != MULTICAST_ALL_R && to != MULTICAST_ALL)
-	{
-		leafnum = CM_PointLeafnum (origin);
-		area1 = CM_LeafArea (leafnum);
-	}
-	else
-		area1 = 0;	// just to avoid compiler warnings
-
-	// if doing a serverrecord, store everything
-	if (svs.demofile)
-		SZ_Write (&svs.demo_multicast, sv.multicast.data, sv.multicast.cursize);
-	
-	switch (to)
-	{
-	case MULTICAST_ALL_R:
-		reliable = true;	// intentional fallthrough
-	case MULTICAST_ALL:
-		mask = NULL;
-		break;
-
-	case MULTICAST_PHS_R:
-		reliable = true;	// intentional fallthrough
-	case MULTICAST_PHS:
-		leafnum = CM_PointLeafnum (origin);
-		cluster = CM_LeafCluster (leafnum);
-		mask = CM_ClusterPHS (cluster);
-		break;
-
-	case MULTICAST_PVS_R:
-		reliable = true;	// intentional fallthrough
-	case MULTICAST_PVS:
-		leafnum = CM_PointLeafnum (origin);
-		cluster = CM_LeafCluster (leafnum);
-		mask = CM_ClusterPVS (cluster);
-		break;
-
-	default:
-		mask = NULL;
-		Com_Error (ERR_FATAL, "SV_Multicast: bad to:%i", to);
-	}
-
-	// send the data to all relevent clients
-	for (j = 0, client = svs.clients; j < maxclients->value; j++, client++)
-	{
-		if (client->state == cs_free || client->state == cs_zombie)
-			continue;
-		if (client->state != cs_spawned && !reliable)
-			continue;
-
-		if (mask)
-		{
-			leafnum = CM_PointLeafnum (client->edict->s.origin);
-			cluster = CM_LeafCluster (leafnum);
-			area2 = CM_LeafArea (leafnum);
-			if (!CM_AreasConnected (area1, area2))
-				continue;
-			if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
-				continue;
-		}
-
-		if (reliable)
-			SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
-		else
-			SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
-	}
-
-	SZ_Clear (&sv.multicast);
-}
-
-
-/*  
-==================
-SV_StartSound
-
-Each entity can have eight independant sound sources, like voice,
-weapon, feet, etc.
-
-If cahnnel & 8, the sound will be sent to everyone, not just
-things in the PHS.
-
-FIXME: if entity isn't in PHS, they must be forced to be sent or
-have the origin explicitly sent.
-
-Channel 0 is an auto-allocate channel, the others override anything
-already running on that entity/channel pair.
-
-An attenuation of 0 will play full volume everywhere in the level.
-Larger attenuations will drop off.  (max 4 attenuation)
-
-Timeofs can range from 0.0 to 0.1 to cause sounds to be started
-later in the frame than they normally would.
-
-If origin is NULL, the origin is determined from the entity origin
-or the midpoint of the entity box for bmodels.
-==================
-*/  
-void SV_StartSound (vec3_t origin, edict_t *entity, int channel,
-					int soundindex, float volume,
-					float attenuation, float timeofs)
-{       
-	int			sendchan;
-    int			flags;
-    int			i;
-	int			ent;
-	vec3_t		origin_v;
-	qboolean	use_phs;
-
-	if (volume < 0 || volume > 1.0)
-		Com_Error (ERR_FATAL, "SV_StartSound: volume = %f", volume);
-
-	if (attenuation < 0 || attenuation > 4)
-		Com_Error (ERR_FATAL, "SV_StartSound: attenuation = %f", attenuation);
-
-//	if (channel < 0 || channel > 15)
-//		Com_Error (ERR_FATAL, "SV_StartSound: channel = %i", channel);
-
-	if (timeofs < 0 || timeofs > 0.255)
-		Com_Error (ERR_FATAL, "SV_StartSound: timeofs = %f", timeofs);
-
-	ent = NUM_FOR_EDICT(entity);
-
-	if (channel & 8)	// no PHS flag
-	{
-		use_phs = false;
-		channel &= 7;
-	}
-	else
-		use_phs = true;
-
-	sendchan = (ent<<3) | (channel&7);
-
-	flags = 0;
-	if (volume != DEFAULT_SOUND_PACKET_VOLUME)
-		flags |= SND_VOLUME;
-	if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
-		flags |= SND_ATTENUATION;
-
-	// the client doesn't know that bmodels have weird origins
-	// the origin can also be explicitly set
-	if ( (entity->svflags & SVF_NOCLIENT)
-		|| (entity->solid == SOLID_BSP) 
-		|| origin )
-		flags |= SND_POS;
-
-	// always send the entity number for channel overrides
-	flags |= SND_ENT;
-
-	if (timeofs)
-		flags |= SND_OFFSET;
-
-	// use the entity origin unless it is a bmodel or explicitly specified
-	if (!origin)
-	{
-		origin = origin_v;
-		if (entity->solid == SOLID_BSP)
-		{
-			for (i=0 ; i<3 ; i++)
-				origin_v[i] = entity->s.origin[i]+0.5*(entity->mins[i]+entity->maxs[i]);
-		}
-		else
-		{
-			VectorCopy (entity->s.origin, origin_v);
-		}
-	}
-
-	MSG_WriteByte (&sv.multicast, svc_sound);
-	MSG_WriteByte (&sv.multicast, flags);
-	MSG_WriteByte (&sv.multicast, soundindex);
-
-	if (flags & SND_VOLUME)
-		MSG_WriteByte (&sv.multicast, volume*255);
-	if (flags & SND_ATTENUATION)
-		MSG_WriteByte (&sv.multicast, attenuation*64);
-	if (flags & SND_OFFSET)
-		MSG_WriteByte (&sv.multicast, timeofs*1000);
-
-	if (flags & SND_ENT)
-		MSG_WriteShort (&sv.multicast, sendchan);
-
-	if (flags & SND_POS)
-		MSG_WritePos (&sv.multicast, origin);
-
-	// if the sound doesn't attenuate,send it to everyone
-	// (global radio chatter, voiceovers, etc)
-	if (attenuation == ATTN_NONE)
-		use_phs = false;
-
-	if (channel & CHAN_RELIABLE)
-	{
-		if (use_phs)
-			SV_Multicast (origin, MULTICAST_PHS_R);
-		else
-			SV_Multicast (origin, MULTICAST_ALL_R);
-	}
-	else
-	{
-		if (use_phs)
-			SV_Multicast (origin, MULTICAST_PHS);
-		else
-			SV_Multicast (origin, MULTICAST_ALL);
-	}
-}           
-
-
-/*
-===============================================================================
-
-FRAME UPDATES
-
-===============================================================================
-*/
-
-
-
-/*
-=======================
-SV_SendClientDatagram
-=======================
-*/
-qboolean SV_SendClientDatagram (client_t *client)
-{
-	byte		msg_buf[MAX_MSGLEN];
-	sizebuf_t	msg;
-
-	SV_BuildClientFrame (client);
-
-	SZ_Init (&msg, msg_buf, sizeof(msg_buf));
-	msg.allowoverflow = true;
-
-	// send over all the relevant entity_state_t
-	// and the player_state_t
-	SV_WriteFrameToClient (client, &msg);
-
-	// copy the accumulated multicast datagram
-	// for this client out to the message
-	// it is necessary for this to be after the WriteEntities
-	// so that entity references will be current
-	if (client->datagram.overflowed)
-		Com_Printf ("WARNING: datagram overflowed for %s\n", client->name);
-	else
-		SZ_Write (&msg, client->datagram.data, client->datagram.cursize);
-	SZ_Clear (&client->datagram);
-
-	if (msg.overflowed)
-	{	// must have room left for the packet header
-		Com_Printf ("WARNING: msg overflowed for %s\n", client->name);
-		SZ_Clear (&msg);
-	}
-
-	// send the datagram
-	Netchan_Transmit (&client->netchan, msg.cursize, msg.data);
-
-	// record the size for rate estimation
-	client->message_size[sv.framenum % RATE_MESSAGES] = msg.cursize;
-
-	return true;
-}
-
-
-/*
-==================
-SV_DemoCompleted
-==================
-*/
-void SV_DemoCompleted (void)
-{
-	if (sv.demofile)
-	{
-		fclose (sv.demofile);
-		sv.demofile = NULL;
-	}
-	SV_Nextserver ();
-}
-
-
-/*
-=======================
-SV_RateDrop
-
-Returns true if the client is over its current
-bandwidth estimation and should not be sent another packet
-=======================
-*/
-qboolean SV_RateDrop (client_t *c)
-{
-	int		total;
-	int		i;
-
-	// never drop over the loopback
-	if (c->netchan.remote_address.type == NA_LOOPBACK)
-		return false;
-
-	total = 0;
-
-	for (i = 0 ; i < RATE_MESSAGES ; i++)
-	{
-		total += c->message_size[i];
-	}
-
-	if (total > c->rate)
-	{
-		c->surpressCount++;
-		c->message_size[sv.framenum % RATE_MESSAGES] = 0;
-		return true;
-	}
-
-	return false;
-}
-
-/*
-=======================
-SV_SendClientMessages
-=======================
-*/
-void SV_SendClientMessages (void)
-{
-	int			i;
-	client_t	*c;
-	int			msglen;
-	byte		msgbuf[MAX_MSGLEN];
-	int			r;
-
-	msglen = 0;
-
-	// read the next demo message if needed
-	if (sv.state == ss_demo && sv.demofile)
-	{
-		if (sv_paused->value)
-			msglen = 0;
-		else
-		{
-			// get the next message
-			r = fread (&msglen, 4, 1, sv.demofile);
-			if (r != 1)
-			{
-				SV_DemoCompleted ();
-				return;
-			}
-			msglen = LittleLong (msglen);
-			if (msglen == -1)
-			{
-				SV_DemoCompleted ();
-				return;
-			}
-			if (msglen > MAX_MSGLEN)
-				Com_Error (ERR_DROP, "SV_SendClientMessages: msglen > MAX_MSGLEN");
-			r = fread (msgbuf, msglen, 1, sv.demofile);
-			if (r != 1)
-			{
-				SV_DemoCompleted ();
-				return;
-			}
-		}
-	}
-
-	// send a message to each connected client
-	for (i=0, c = svs.clients ; i<maxclients->value; i++, c++)
-	{
-		if (!c->state)
-			continue;
-		// if the reliable message overflowed,
-		// drop the client
-		if (c->netchan.message.overflowed)
-		{
-			SZ_Clear (&c->netchan.message);
-			SZ_Clear (&c->datagram);
-			SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", c->name);
-			SV_DropClient (c);
-		}
-
-		if (sv.state == ss_cinematic 
-			|| sv.state == ss_demo 
-			|| sv.state == ss_pic
-			)
-			Netchan_Transmit (&c->netchan, msglen, msgbuf);
-		else if (c->state == cs_spawned)
-		{
-			// don't overrun bandwidth
-			if (SV_RateDrop (c))
-				continue;
-
-			SV_SendClientDatagram (c);
-		}
-		else
-		{
-	// just update reliable	if needed
-			if (c->netchan.message.cursize	|| curtime - c->netchan.last_sent > 1000 )
-				Netchan_Transmit (&c->netchan, 0, NULL);
-		}
-	}
-}
-
--- a/server/sv_user.c
+++ /dev/null
@@ -1,648 +1,0 @@
-// sv_user.c -- server code for moving users
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-edict_t	*sv_player;
-
-/*
-============================================================
-
-USER STRINGCMD EXECUTION
-
-sv_client and sv_player will be valid.
-============================================================
-*/
-
-/*
-==================
-SV_BeginDemoServer
-==================
-*/
-void SV_BeginDemoserver (void)
-{
-	char		name[MAX_OSPATH];
-
-	Com_sprintf (name, sizeof(name), "demos/%s", sv.name);
-	FS_FOpenFile (name, &sv.demofile);
-	if (!sv.demofile)
-		Com_Error (ERR_DROP, "Couldn't open %s\n", name);
-}
-
-/*
-================
-SV_New_f
-
-Sends the first message from the server to a connected client.
-This will be sent on the initial connection and upon each server load.
-================
-*/
-void SV_New_f (void)
-{
-	char		*gamedir;
-	int			playernum;
-	edict_t		*ent;
-
-	Com_DPrintf ("New() from %s\n", sv_client->name);
-
-	if (sv_client->state != cs_connected)
-	{
-		Com_Printf ("New not valid -- already spawned\n");
-		return;
-	}
-
-	// demo servers just dump the file message
-	if (sv.state == ss_demo)
-	{
-		SV_BeginDemoserver ();
-		return;
-	}
-
-	//
-	// serverdata needs to go over for all types of servers
-	// to make sure the protocol is right, and to set the gamedir
-	//
-	gamedir = Cvar_VariableString ("gamedir");
-
-	// send the serverdata
-	MSG_WriteByte (&sv_client->netchan.message, svc_serverdata);
-	MSG_WriteLong (&sv_client->netchan.message, PROTOCOL_VERSION);
-	MSG_WriteLong (&sv_client->netchan.message, svs.spawncount);
-	MSG_WriteByte (&sv_client->netchan.message, sv.attractloop);
-	MSG_WriteString (&sv_client->netchan.message, gamedir);
-
-	if (sv.state == ss_cinematic || sv.state == ss_pic)
-		playernum = -1;
-	else
-		playernum = sv_client - svs.clients;
-	MSG_WriteShort (&sv_client->netchan.message, playernum);
-
-	// send full levelname
-	MSG_WriteString (&sv_client->netchan.message, sv.configstrings[CS_NAME]);
-
-	//
-	// game server
-	// 
-	if (sv.state == ss_game)
-	{
-		// set up the entity for the client
-		ent = EDICT_NUM(playernum+1);
-		ent->s.number = playernum+1;
-		sv_client->edict = ent;
-		memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd));
-
-		// begin fetching configstrings
-		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
-		MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i 0\n",svs.spawncount) );
-	}
-
-}
-
-/*
-==================
-SV_Configstrings_f
-==================
-*/
-void SV_Configstrings_f (void)
-{
-	int			start;
-
-	Com_DPrintf ("Configstrings() from %s\n", sv_client->name);
-
-	if (sv_client->state != cs_connected)
-	{
-		Com_Printf ("configstrings not valid -- already spawned\n");
-		return;
-	}
-
-	// handle the case of a level changing while a client was connecting
-	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
-	{
-		Com_Printf ("SV_Configstrings_f from different level\n");
-		SV_New_f ();
-		return;
-	}
-	
-	start = atoi(Cmd_Argv(2));
-
-	// write a packet full of data
-
-	while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2 
-		&& start < MAX_CONFIGSTRINGS)
-	{
-		if (sv.configstrings[start][0])
-		{
-			MSG_WriteByte (&sv_client->netchan.message, svc_configstring);
-			MSG_WriteShort (&sv_client->netchan.message, start);
-			MSG_WriteString (&sv_client->netchan.message, sv.configstrings[start]);
-		}
-		start++;
-	}
-
-	// send next command
-
-	if (start == MAX_CONFIGSTRINGS)
-	{
-		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
-		MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i 0\n",svs.spawncount) );
-	}
-	else
-	{
-		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
-		MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i %i\n",svs.spawncount, start) );
-	}
-}
-
-/*
-==================
-SV_Baselines_f
-==================
-*/
-void SV_Baselines_f (void)
-{
-	int		start;
-	entity_state_t	nullstate;
-	entity_state_t	*base;
-
-	Com_DPrintf ("Baselines() from %s\n", sv_client->name);
-
-	if (sv_client->state != cs_connected)
-	{
-		Com_Printf ("baselines not valid -- already spawned\n");
-		return;
-	}
-	
-	// handle the case of a level changing while a client was connecting
-	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
-	{
-		Com_Printf ("SV_Baselines_f from different level\n");
-		SV_New_f ();
-		return;
-	}
-	
-	start = atoi(Cmd_Argv(2));
-
-	memset (&nullstate, 0, sizeof(nullstate));
-
-	// write a packet full of data
-
-	while ( sv_client->netchan.message.cursize <  MAX_MSGLEN/2
-		&& start < MAX_EDICTS)
-	{
-		base = &sv.baselines[start];
-		if (base->modelindex || base->sound || base->effects)
-		{
-			MSG_WriteByte (&sv_client->netchan.message, svc_spawnbaseline);
-			MSG_WriteDeltaEntity (&nullstate, base, &sv_client->netchan.message, true, true);
-		}
-		start++;
-	}
-
-	// send next command
-
-	if (start == MAX_EDICTS)
-	{
-		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
-		MSG_WriteString (&sv_client->netchan.message, va("precache %i\n", svs.spawncount) );
-	}
-	else
-	{
-		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
-		MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i %i\n",svs.spawncount, start) );
-	}
-}
-
-/*
-==================
-SV_Begin_f
-==================
-*/
-void SV_Begin_f (void)
-{
-	Com_DPrintf ("Begin() from %s\n", sv_client->name);
-
-	// handle the case of a level changing while a client was connecting
-	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
-	{
-		Com_Printf ("SV_Begin_f from different level\n");
-		SV_New_f ();
-		return;
-	}
-
-	sv_client->state = cs_spawned;
-
-	// call the game begin function
-	ge->ClientBegin (sv_player);
-
-	Cbuf_InsertFromDefer ();
-}
-
-//=============================================================================
-
-/*
-==================
-SV_NextDownload_f
-==================
-*/
-void SV_NextDownload_f (void)
-{
-	int		r;
-	int		percent;
-	int		size;
-
-	if (!sv_client->download)
-		return;
-
-	r = sv_client->downloadsize - sv_client->downloadcount;
-	if (r > 1024)
-		r = 1024;
-
-	MSG_WriteByte (&sv_client->netchan.message, svc_download);
-	MSG_WriteShort (&sv_client->netchan.message, r);
-
-	sv_client->downloadcount += r;
-	size = sv_client->downloadsize;
-	if (!size)
-		size = 1;
-	percent = sv_client->downloadcount*100/size;
-	MSG_WriteByte (&sv_client->netchan.message, percent);
-	SZ_Write (&sv_client->netchan.message,
-		sv_client->download + sv_client->downloadcount - r, r);
-
-	if (sv_client->downloadcount != sv_client->downloadsize)
-		return;
-
-	FS_FreeFile (sv_client->download);
-	sv_client->download = NULL;
-}
-
-/*
-==================
-SV_BeginDownload_f
-==================
-*/
-void SV_BeginDownload_f(void)
-{
-	char	*name;
-	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;
-	extern	int		file_from_pak; // ZOID did file come from pak?
-	int offset = 0;
-
-	name = Cmd_Argv(1);
-
-	if (Cmd_Argc() > 2)
-		offset = atoi(Cmd_Argv(2)); // downloaded offset
-
-	// hacked by zoid to allow more conrol over download
-	// first off, no .. or global allow check
-	if (strstr (name, "..") || !allow_download->value
-		// leading dot is no good
-		|| *name == '.' 
-		// leading slash bad as well, must be in subdir
-		|| *name == '/'
-		// next up, skin check
-		|| (strncmp(name, "players/", 6) == 0 && !allow_download_players->value)
-		// now models
-		|| (strncmp(name, "models/", 6) == 0 && !allow_download_models->value)
-		// now sounds
-		|| (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds->value)
-		// now maps (note special case for maps, must not be in pak)
-		|| (strncmp(name, "maps/", 6) == 0 && !allow_download_maps->value)
-		// MUST be in a subdirectory	
-		|| !strstr (name, "/") )	
-	{	// don't allow anything with .. path
-		MSG_WriteByte (&sv_client->netchan.message, svc_download);
-		MSG_WriteShort (&sv_client->netchan.message, -1);
-		MSG_WriteByte (&sv_client->netchan.message, 0);
-		return;
-	}
-
-
-	if (sv_client->download)
-		FS_FreeFile (sv_client->download);
-
-	sv_client->downloadsize = FS_LoadFile (name, (void **)&sv_client->download);
-	sv_client->downloadcount = offset;
-
-	if (offset > sv_client->downloadsize)
-		sv_client->downloadcount = sv_client->downloadsize;
-
-	if (!sv_client->download
-		// special check for maps, if it came from a pak file, don't allow
-		// download  ZOID
-		|| (strncmp(name, "maps/", 5) == 0 && file_from_pak))
-	{
-		Com_DPrintf ("Couldn't download %s to %s\n", name, sv_client->name);
-		if (sv_client->download) {
-			FS_FreeFile (sv_client->download);
-			sv_client->download = NULL;
-		}
-
-		MSG_WriteByte (&sv_client->netchan.message, svc_download);
-		MSG_WriteShort (&sv_client->netchan.message, -1);
-		MSG_WriteByte (&sv_client->netchan.message, 0);
-		return;
-	}
-
-	SV_NextDownload_f ();
-	Com_DPrintf ("Downloading %s to %s\n", name, sv_client->name);
-}
-
-
-
-//============================================================================
-
-
-/*
-=================
-SV_Disconnect_f
-
-The client is going to disconnect, so remove the connection immediately
-=================
-*/
-void SV_Disconnect_f (void)
-{
-//	SV_EndRedirect ();
-	SV_DropClient (sv_client);	
-}
-
-
-/*
-==================
-SV_ShowServerinfo_f
-
-Dumps the serverinfo info string
-==================
-*/
-void SV_ShowServerinfo_f (void)
-{
-	Info_Print (Cvar_Serverinfo());
-}
-
-
-void SV_Nextserver (void)
-{
-	char	*v;
-
-	//ZOID, ss_pic can be nextserver'd in coop mode
-	if (sv.state == ss_game || (sv.state == ss_pic && !Cvar_VariableValue("coop")))
-		return;		// can't nextserver while playing a normal game
-
-	svs.spawncount++;	// make sure another doesn't sneak in
-	v = Cvar_VariableString ("nextserver");
-	if (!v[0])
-		Cbuf_AddText ("killserver\n");
-	else
-	{
-		Cbuf_AddText (v);
-		Cbuf_AddText ("\n");
-	}
-	Cvar_Set ("nextserver","");
-}
-
-/*
-==================
-SV_Nextserver_f
-
-A cinematic has completed or been aborted by a client, so move
-to the next server,
-==================
-*/
-void SV_Nextserver_f (void)
-{
-	if ( atoi(Cmd_Argv(1)) != svs.spawncount ) {
-		Com_DPrintf ("Nextserver() from wrong level, from %s\n", sv_client->name);
-		return;		// leftover from last server
-	}
-
-	Com_DPrintf ("Nextserver() from %s\n", sv_client->name);
-
-	SV_Nextserver ();
-}
-
-typedef struct
-{
-	char	*name;
-	void	(*func) (void);
-} ucmd_t;
-
-ucmd_t ucmds[] =
-{
-	// auto issued
-	{"new", SV_New_f},
-	{"configstrings", SV_Configstrings_f},
-	{"baselines", SV_Baselines_f},
-	{"begin", SV_Begin_f},
-
-	{"nextserver", SV_Nextserver_f},
-
-	{"disconnect", SV_Disconnect_f},
-
-	// issued by hand at client consoles	
-	{"info", SV_ShowServerinfo_f},
-
-	{"download", SV_BeginDownload_f},
-	{"nextdl", SV_NextDownload_f},
-
-	{NULL, NULL}
-};
-
-/*
-==================
-SV_ExecuteUserCommand
-==================
-*/
-void SV_ExecuteUserCommand (char *s)
-{
-	ucmd_t	*u;
-	
-	Cmd_TokenizeString (s, true);
-	sv_player = sv_client->edict;
-
-//	SV_BeginRedirect (RD_CLIENT);
-
-	for (u=ucmds ; u->name ; u++)
-		if (!strcmp (Cmd_Argv(0), u->name) )
-		{
-			u->func ();
-			break;
-		}
-
-	if (!u->name && sv.state == ss_game)
-		ge->ClientCommand (sv_player);
-
-//	SV_EndRedirect ();
-}
-
-/*
-===========================================================================
-
-USER CMD EXECUTION
-
-===========================================================================
-*/
-
-
-
-void SV_ClientThink (client_t *cl, usercmd_t *cmd)
-
-{
-	cl->commandMsec -= cmd->msec;
-
-	if (cl->commandMsec < 0 && sv_enforcetime->value )
-	{
-		Com_DPrintf ("commandMsec underflow from %s\n", cl->name);
-		return;
-	}
-
-	ge->ClientThink (cl->edict, cmd);
-}
-
-
-
-#define	MAX_STRINGCMDS	8
-/*
-===================
-SV_ExecuteClientMessage
-
-The current net_message is parsed for the given client
-===================
-*/
-void SV_ExecuteClientMessage (client_t *cl)
-{
-	int		c;
-	char	*s;
-
-	usercmd_t	nullcmd;
-	usercmd_t	oldest, oldcmd, newcmd;
-	int		net_drop;
-	int		stringCmdCount;
-	int		checksum, calculatedChecksum;
-	int		checksumIndex;
-	qboolean	move_issued;
-	int		lastframe;
-
-	sv_client = cl;
-	sv_player = sv_client->edict;
-
-	// only allow one move command
-	move_issued = false;
-	stringCmdCount = 0;
-
-	while (1)
-	{
-		if (net_message.readcount > net_message.cursize)
-		{
-			Com_Printf ("SV_ReadClientMessage: badread\n");
-			SV_DropClient (cl);
-			return;
-		}	
-
-		c = MSG_ReadByte (&net_message);
-		if (c == -1)
-			break;
-				
-		switch (c)
-		{
-		default:
-			Com_Printf ("SV_ReadClientMessage: unknown command char\n");
-			SV_DropClient (cl);
-			return;
-						
-		case clc_nop:
-			break;
-
-		case clc_userinfo:
-			strncpy (cl->userinfo, MSG_ReadString (&net_message), sizeof(cl->userinfo)-1);
-			SV_UserinfoChanged (cl);
-			break;
-
-		case clc_move:
-			if (move_issued)
-				return;		// someone is trying to cheat...
-
-			move_issued = true;
-			checksumIndex = net_message.readcount;
-			checksum = MSG_ReadByte (&net_message);
-			lastframe = MSG_ReadLong (&net_message);
-			if (lastframe != cl->lastframe) {
-				cl->lastframe = lastframe;
-				if (cl->lastframe > 0) {
-					cl->frame_latency[cl->lastframe&(LATENCY_COUNTS-1)] = 
-						svs.realtime - cl->frames[cl->lastframe & UPDATE_MASK].senttime;
-				}
-			}
-
-			memset (&nullcmd, 0, sizeof(nullcmd));
-			MSG_ReadDeltaUsercmd (&net_message, &nullcmd, &oldest);
-			MSG_ReadDeltaUsercmd (&net_message, &oldest, &oldcmd);
-			MSG_ReadDeltaUsercmd (&net_message, &oldcmd, &newcmd);
-
-			if ( cl->state != cs_spawned )
-			{
-				cl->lastframe = -1;
-				break;
-			}
-
-			// if the checksum fails, ignore the rest of the packet
-			calculatedChecksum = COM_BlockSequenceCRCByte (
-				net_message.data + checksumIndex + 1,
-				net_message.readcount - checksumIndex - 1,
-				cl->netchan.incoming_sequence);
-
-			if (calculatedChecksum != checksum)
-			{
-				Com_DPrintf ("Failed command checksum for %s (%d != %d)/%d\n", 
-					cl->name, calculatedChecksum, checksum, 
-					cl->netchan.incoming_sequence);
-				return;
-			}
-
-			if (!sv_paused->value)
-			{
-				net_drop = cl->netchan.dropped;
-				if (net_drop < 20)
-				{
-
-//if (net_drop > 2)
-
-//	Com_Printf ("drop %i\n", net_drop);
-					while (net_drop > 2)
-					{
-						SV_ClientThink (cl, &cl->lastcmd);
-
-						net_drop--;
-					}
-					if (net_drop > 1)
-						SV_ClientThink (cl, &oldest);
-
-					if (net_drop > 0)
-						SV_ClientThink (cl, &oldcmd);
-
-				}
-				SV_ClientThink (cl, &newcmd);
-			}
-
-			cl->lastcmd = newcmd;
-			break;
-
-		case clc_stringcmd:	
-			s = MSG_ReadString (&net_message);
-
-			// malicious users may try using too many string commands
-			if (++stringCmdCount < MAX_STRINGCMDS)
-				SV_ExecuteUserCommand (s);
-
-			if (cl->state == cs_zombie)
-				return;	// disconnect command
-			break;
-		}
-	}
-}
-
--- a/server/sv_world.c
+++ /dev/null
@@ -1,642 +1,0 @@
-// world.c -- world query functions
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-===============================================================================
-
-ENTITY AREA CHECKING
-
-FIXME: this use of "area" is different from the bsp file use
-===============================================================================
-*/
-
-// (type *)STRUCT_FROM_LINK(link_t *link, type, member)
-// ent = STRUCT_FROM_LINK(link,entity_t,order)
-// FIXME: remove this mess!
-#define	STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (uintptr)&(((t *)0)->m)))
-
-#define	EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
-
-typedef struct areanode_s
-{
-	int		axis;		// -1 = leaf node
-	float	dist;
-	struct areanode_s	*children[2];
-	link_t	trigger_edicts;
-	link_t	solid_edicts;
-} areanode_t;
-
-#define	AREA_DEPTH	4
-#define	AREA_NODES	32
-
-areanode_t	sv_areanodes[AREA_NODES];
-int			sv_numareanodes;
-
-float	*area_mins, *area_maxs;
-edict_t	**area_list;
-int		area_count, area_maxcount;
-int		area_type;
-
-int SV_HullForEntity (edict_t *ent);
-
-
-// ClearLink is used for new headnodes
-void ClearLink (link_t *l)
-{
-	l->prev = l->next = l;
-}
-
-void RemoveLink (link_t *l)
-{
-	l->next->prev = l->prev;
-	l->prev->next = l->next;
-}
-
-void InsertLinkBefore (link_t *l, link_t *before)
-{
-	l->next = before;
-	l->prev = before->prev;
-	l->prev->next = l;
-	l->next->prev = l;
-}
-
-/*
-===============
-SV_CreateAreaNode
-
-Builds a uniformly subdivided tree for the given world size
-===============
-*/
-areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)
-{
-	areanode_t	*anode;
-	vec3_t		size;
-	vec3_t		mins1, maxs1, mins2, maxs2;
-
-	anode = &sv_areanodes[sv_numareanodes];
-	sv_numareanodes++;
-
-	ClearLink (&anode->trigger_edicts);
-	ClearLink (&anode->solid_edicts);
-	
-	if (depth == AREA_DEPTH)
-	{
-		anode->axis = -1;
-		anode->children[0] = anode->children[1] = NULL;
-		return anode;
-	}
-	
-	VectorSubtract (maxs, mins, size);
-	if (size[0] > size[1])
-		anode->axis = 0;
-	else
-		anode->axis = 1;
-	
-	anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
-	VectorCopy (mins, mins1);	
-	VectorCopy (mins, mins2);	
-	VectorCopy (maxs, maxs1);	
-	VectorCopy (maxs, maxs2);	
-	
-	maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
-	
-	anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);
-	anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1);
-
-	return anode;
-}
-
-/*
-===============
-SV_ClearWorld
-
-===============
-*/
-void SV_ClearWorld (void)
-{
-	memset (sv_areanodes, 0, sizeof(sv_areanodes));
-	sv_numareanodes = 0;
-	SV_CreateAreaNode (0, sv.models[1]->mins, sv.models[1]->maxs);
-}
-
-
-/*
-===============
-SV_UnlinkEdict
-
-===============
-*/
-void SV_UnlinkEdict (edict_t *ent)
-{
-	if (!ent->area.prev)
-		return;		// not linked in anywhere
-	RemoveLink (&ent->area);
-	ent->area.prev = ent->area.next = NULL;
-}
-
-
-/*
-===============
-SV_LinkEdict
-
-===============
-*/
-#define MAX_TOTAL_ENT_LEAFS		128
-void SV_LinkEdict (edict_t *ent)
-{
-	areanode_t	*node;
-	int			leafs[MAX_TOTAL_ENT_LEAFS];
-	int			clusters[MAX_TOTAL_ENT_LEAFS];
-	int			num_leafs;
-	int			i, j, k;
-	int			area;
-	int			topnode;
-
-	if (ent->area.prev)
-		SV_UnlinkEdict (ent);	// unlink from old position
-		
-	if (ent == ge->edicts)
-		return;		// don't add the world
-
-	if (!ent->inuse)
-		return;
-
-	// set the size
-	VectorSubtract (ent->maxs, ent->mins, ent->size);
-	
-	// encode the size into the entity_state for client prediction
-	if (ent->solid == SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER))
-	{	// assume that x/y are equal and symetric
-		i = ent->maxs[0]/8;
-		if (i<1)
-			i = 1;
-		if (i>31)
-			i = 31;
-
-		// z is not symetric
-		j = (-ent->mins[2])/8;
-		if (j<1)
-			j = 1;
-		if (j>31)
-			j = 31;
-
-		// and z maxs can be negative...
-		k = (ent->maxs[2]+32)/8;
-		if (k<1)
-			k = 1;
-		if (k>63)
-			k = 63;
-
-		ent->s.solid = (k<<10) | (j<<5) | i;
-	}
-	else if (ent->solid == SOLID_BSP)
-	{
-		ent->s.solid = 31;		// a solid_bbox will never create this value
-	}
-	else
-		ent->s.solid = 0;
-
-	// set the abs box
-	if (ent->solid == SOLID_BSP && 
-	(ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) )
-	{	// expand for rotation
-		float		max, v;
-		int			i;
-
-		max = 0;
-		for (i=0 ; i<3 ; i++)
-		{
-			v =fabs( ent->mins[i]);
-			if (v > max)
-				max = v;
-			v =fabs( ent->maxs[i]);
-			if (v > max)
-				max = v;
-		}
-		for (i=0 ; i<3 ; i++)
-		{
-			ent->absmin[i] = ent->s.origin[i] - max;
-			ent->absmax[i] = ent->s.origin[i] + max;
-		}
-	}
-	else
-	{	// normal
-		VectorAdd (ent->s.origin, ent->mins, ent->absmin);	
-		VectorAdd (ent->s.origin, ent->maxs, ent->absmax);
-	}
-
-	// because movement is clipped an epsilon away from an actual edge,
-	// we must fully check even when bounding boxes don't quite touch
-	ent->absmin[0] -= 1;
-	ent->absmin[1] -= 1;
-	ent->absmin[2] -= 1;
-	ent->absmax[0] += 1;
-	ent->absmax[1] += 1;
-	ent->absmax[2] += 1;
-
-// link to PVS leafs
-	ent->num_clusters = 0;
-	ent->areanum = 0;
-	ent->areanum2 = 0;
-
-	//get all leafs, including solids
-	num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax,
-		leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
-
-	// set areas
-	for (i=0 ; i<num_leafs ; i++)
-	{
-		clusters[i] = CM_LeafCluster (leafs[i]);
-		area = CM_LeafArea (leafs[i]);
-		if (area)
-		{	// doors may legally straggle two areas,
-			// but nothing should evern need more than that
-			if (ent->areanum && ent->areanum != area)
-			{
-				if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading)
-					Com_DPrintf ("Object touching 3 areas at %f %f %f\n",
-					ent->absmin[0], ent->absmin[1], ent->absmin[2]);
-				ent->areanum2 = area;
-			}
-			else
-				ent->areanum = area;
-		}
-	}
-
-	if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
-	{	// assume we missed some leafs, and mark by headnode
-		ent->num_clusters = -1;
-		ent->headnode = topnode;
-	}
-	else
-	{
-		ent->num_clusters = 0;
-		for (i=0 ; i<num_leafs ; i++)
-		{
-			if (clusters[i] == -1)
-				continue;		// not a visible leaf
-			for (j=0 ; j<i ; j++)
-				if (clusters[j] == clusters[i])
-					break;
-			if (j == i)
-			{
-				if (ent->num_clusters == MAX_ENT_CLUSTERS)
-				{	// assume we missed some leafs, and mark by headnode
-					ent->num_clusters = -1;
-					ent->headnode = topnode;
-					break;
-				}
-
-				ent->clusternums[ent->num_clusters++] = clusters[i];
-			}
-		}
-	}
-
-	// if first time, make sure old_origin is valid
-	if (!ent->linkcount)
-	{
-		VectorCopy (ent->s.origin, ent->s.old_origin);
-	}
-	ent->linkcount++;
-
-	if (ent->solid == SOLID_NOT)
-		return;
-
-// find the first node that the ent's box crosses
-	node = sv_areanodes;
-	while (1)
-	{
-		if (node->axis == -1)
-			break;
-		if (ent->absmin[node->axis] > node->dist)
-			node = node->children[0];
-		else if (ent->absmax[node->axis] < node->dist)
-			node = node->children[1];
-		else
-			break;		// crosses the node
-	}
-	
-	// link it in	
-	if (ent->solid == SOLID_TRIGGER)
-		InsertLinkBefore (&ent->area, &node->trigger_edicts);
-	else
-		InsertLinkBefore (&ent->area, &node->solid_edicts);
-
-}
-
-
-/*
-====================
-SV_AreaEdicts_r
-
-====================
-*/
-void SV_AreaEdicts_r (areanode_t *node)
-{
-	link_t		*l, *next, *start;
-	edict_t		*check;
-
-	// touch linked edicts
-	if (area_type == AREA_SOLID)
-		start = &node->solid_edicts;
-	else
-		start = &node->trigger_edicts;
-
-	for (l=start->next  ; l != start ; l = next)
-	{
-		next = l->next;
-		check = EDICT_FROM_AREA(l);
-
-		if (check->solid == SOLID_NOT)
-			continue;		// deactivated
-		if (check->absmin[0] > area_maxs[0]
-		|| check->absmin[1] > area_maxs[1]
-		|| check->absmin[2] > area_maxs[2]
-		|| check->absmax[0] < area_mins[0]
-		|| check->absmax[1] < area_mins[1]
-		|| check->absmax[2] < area_mins[2])
-			continue;		// not touching
-
-		if (area_count == area_maxcount)
-		{
-			Com_Printf ("SV_AreaEdicts: MAXCOUNT\n");
-			return;
-		}
-
-		area_list[area_count] = check;
-		area_count++;
-	}
-	
-	if (node->axis == -1)
-		return;		// terminal node
-
-	// recurse down both sides
-	if ( area_maxs[node->axis] > node->dist )
-		SV_AreaEdicts_r ( node->children[0] );
-	if ( area_mins[node->axis] < node->dist )
-		SV_AreaEdicts_r ( node->children[1] );
-}
-
-/*
-================
-SV_AreaEdicts
-================
-*/
-int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list,
-	int maxcount, int areatype)
-{
-	area_mins = mins;
-	area_maxs = maxs;
-	area_list = list;
-	area_count = 0;
-	area_maxcount = maxcount;
-	area_type = areatype;
-
-	SV_AreaEdicts_r (sv_areanodes);
-
-	return area_count;
-}
-
-
-//===========================================================================
-
-/*
-=============
-SV_PointContents
-=============
-*/
-int SV_PointContents (vec3_t p)
-{
-	edict_t		*touch[MAX_EDICTS], *hit;
-	int			i, num;
-	int			contents, c2;
-	int			headnode;
-
-	// get base contents from world
-	contents = CM_PointContents (p, sv.models[1]->headnode);
-
-	// or in contents from all the other entities
-	num = SV_AreaEdicts (p, p, touch, MAX_EDICTS, AREA_SOLID);
-
-	for (i=0 ; i<num ; i++)
-	{
-		hit = touch[i];
-
-		// might intersect, so do an exact clip
-		headnode = SV_HullForEntity (hit);
-
-		/* unused
-		float *angles;
-		angles = hit->s.angles;
-		if (hit->solid != SOLID_BSP)
-			angles = vec3_origin;	// boxes don't rotate
-		*/
-
-		c2 = CM_TransformedPointContents (p, headnode, hit->s.origin, hit->s.angles);
-
-		contents |= c2;
-	}
-
-	return contents;
-}
-
-
-
-typedef struct
-{
-	vec3_t		boxmins, boxmaxs;// enclose the test object along entire move
-	float		*mins, *maxs;	// size of the moving object
-	vec3_t		mins2, maxs2;	// size when clipping against mosnters
-	float		*start, *end;
-	trace_t		trace;
-	edict_t		*passedict;
-	int			contentmask;
-} moveclip_t;
-
-
-
-/*
-================
-SV_HullForEntity
-
-Returns a headnode that can be used for testing or clipping an
-object of mins/maxs size.
-Offset is filled in to contain the adjustment that must be added to the
-testing object's origin to get a point to use with the returned hull.
-================
-*/
-int SV_HullForEntity (edict_t *ent)
-{
-	cmodel_t	*model;
-
-// decide which clipping hull to use, based on the size
-	if (ent->solid == SOLID_BSP)
-	{	// explicit hulls in the BSP model
-		model = sv.models[ ent->s.modelindex ];
-
-		if (!model)
-			Com_Error (ERR_FATAL, "MOVETYPE_PUSH with a non bsp model");
-
-		return model->headnode;
-	}
-
-	// create a temp hull from bounding box sizes
-
-	return CM_HeadnodeForBox (ent->mins, ent->maxs);
-}
-
-
-//===========================================================================
-
-/*
-====================
-SV_ClipMoveToEntities
-
-====================
-*/
-void SV_ClipMoveToEntities ( moveclip_t *clip )
-{
-	int			i, num;
-	edict_t		*touchlist[MAX_EDICTS], *touch;
-	trace_t		trace;
-	int			headnode;
-	float		*angles;
-
-	num = SV_AreaEdicts (clip->boxmins, clip->boxmaxs, touchlist
-		, MAX_EDICTS, AREA_SOLID);
-
-	// be careful, it is possible to have an entity in this
-	// list removed before we get to it (killtriggered)
-	for (i=0 ; i<num ; i++)
-	{
-		touch = touchlist[i];
-		if (touch->solid == SOLID_NOT)
-			continue;
-		if (touch == clip->passedict)
-			continue;
-		if (clip->trace.allsolid)
-			return;
-		if (clip->passedict)
-		{
-		 	if (touch->owner == clip->passedict)
-				continue;	// don't clip against own missiles
-			if (clip->passedict->owner == touch)
-				continue;	// don't clip against owner
-		}
-
-		if ( !(clip->contentmask & CONTENTS_DEADMONSTER)
-		&& (touch->svflags & SVF_DEADMONSTER) )
-				continue;
-
-		// might intersect, so do an exact clip
-		headnode = SV_HullForEntity (touch);
-		angles = touch->s.angles;
-		if (touch->solid != SOLID_BSP)
-			angles = vec3_origin;	// boxes don't rotate
-
-		if (touch->svflags & SVF_MONSTER)
-			trace = CM_TransformedBoxTrace (clip->start, clip->end,
-				clip->mins2, clip->maxs2, headnode, clip->contentmask,
-				touch->s.origin, angles);
-		else
-			trace = CM_TransformedBoxTrace (clip->start, clip->end,
-				clip->mins, clip->maxs, headnode,  clip->contentmask,
-				touch->s.origin, angles);
-
-		if (trace.allsolid || trace.startsolid ||
-		trace.fraction < clip->trace.fraction)
-		{
-			trace.ent = touch;
-		 	if (clip->trace.startsolid)
-			{
-				clip->trace = trace;
-				clip->trace.startsolid = true;
-			}
-			else
-				clip->trace = trace;
-		}
-		else if (trace.startsolid)
-			clip->trace.startsolid = true;
-	}
-}
-
-
-/*
-==================
-SV_TraceBounds
-==================
-*/
-void SV_TraceBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
-{
-/*
-	// debug to test against everything
-	boxmins[0] = boxmins[1] = boxmins[2] = -9999;
-	boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999;
-*/
-	int		i;
-	
-	for (i=0 ; i<3 ; i++)
-	{
-		if (end[i] > start[i])
-		{
-			boxmins[i] = start[i] + mins[i] - 1;
-			boxmaxs[i] = end[i] + maxs[i] + 1;
-		}
-		else
-		{
-			boxmins[i] = end[i] + mins[i] - 1;
-			boxmaxs[i] = start[i] + maxs[i] + 1;
-		}
-	}
-}
-
-/*
-==================
-SV_Trace
-
-Moves the given mins/maxs volume through the world from start to end.
-
-Passedict and edicts owned by passedict are explicitly not checked.
-
-==================
-*/
-trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask)
-{
-	moveclip_t	clip;
-
-	if (!mins)
-		mins = vec3_origin;
-	if (!maxs)
-		maxs = vec3_origin;
-
-	memset ( &clip, 0, sizeof ( moveclip_t ) );
-
-	// clip to world
-	clip.trace = CM_BoxTrace (start, end, mins, maxs, 0, contentmask);
-	clip.trace.ent = ge->edicts;
-	if (clip.trace.fraction == 0)
-		return clip.trace;		// blocked by the world
-
-	clip.contentmask = contentmask;
-	clip.start = start;
-	clip.end = end;
-	clip.mins = mins;
-	clip.maxs = maxs;
-	clip.passedict = passedict;
-
-	VectorCopy (mins, clip.mins2);
-	VectorCopy (maxs, clip.maxs2);
-	
-	// create the bounding box of the entire move
-	SV_TraceBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
-
-	// clip to other solid entities
-	SV_ClipMoveToEntities ( &clip );
-
-	return clip.trace;
-}
-
--- /dev/null
+++ b/snd.c
@@ -1,0 +1,129 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.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)
+{
+}
--- /dev/null
+++ b/snd_dma.c
@@ -1,0 +1,1196 @@
+// snd_dma.c -- main control for any streaming sound output device
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.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);
+}
+
+sfx_t *
+S_RegisterSexedSound(entity_state_t *ent, char *base)
+{
+	int				n;
+	char			*p;
+	sfx_t *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);
+}
+
--- /dev/null
+++ b/snd_mem.c
@@ -1,0 +1,342 @@
+// snd_mem.c: sound caching
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.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;
+}
+
--- /dev/null
+++ b/snd_mix.c
@@ -1,0 +1,350 @@
+// snd_mix.c -- portable code to mix sounds for snd_dma.c
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.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;
+}
--- /dev/null
+++ b/sv_ccmds.c
@@ -1,0 +1,1031 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+===============================================================================
+
+OPERATOR CONSOLE ONLY COMMANDS
+
+These commands can only be entered from stdin or by a remote operator datagram
+===============================================================================
+*/
+
+/*
+====================
+SV_SetMaster_f
+
+Specify a list of master servers
+====================
+*/
+void SV_SetMaster_f (void)
+{
+	int		i, slot;
+
+	// only dedicated servers send heartbeats
+	if (!dedicated->value)
+	{
+		Com_Printf ("Only dedicated servers use masters.\n");
+		return;
+	}
+
+	// make sure the server is listed public
+	Cvar_Set ("public", "1");
+
+	for (i=1 ; i<MAX_MASTERS ; i++)
+		memset (&master_adr[i], 0, sizeof(master_adr[i]));
+
+	slot = 1;		// slot 0 will always contain the id master
+	for (i=1 ; i<Cmd_Argc() ; i++)
+	{
+		if (slot == MAX_MASTERS)
+			break;
+
+		if (!NET_StringToAdr (Cmd_Argv(i), &master_adr[i]))
+		{
+			Com_Printf ("Bad address: %s\n", Cmd_Argv(i));
+			continue;
+		}
+		if (master_adr[slot].port == 0)
+			master_adr[slot].port = BigShort (PORT_MASTER);
+
+		Com_Printf ("Master server at %s\n", NET_AdrToString (master_adr[slot]));
+
+		Com_Printf ("Sending a ping.\n");
+
+		Netchan_OutOfBandPrint (NS_SERVER, master_adr[slot], "ping");
+
+		slot++;
+	}
+
+	svs.last_heartbeat = -9999999;
+}
+
+
+
+/*
+==================
+SV_SetPlayer
+
+Sets sv_client and sv_player to the player with idnum Cmd_Argv(1)
+==================
+*/
+qboolean SV_SetPlayer (void)
+{
+	client_t	*cl;
+	int			i;
+	int			idnum;
+	char		*s;
+
+	if (Cmd_Argc() < 2)
+		return false;
+
+	s = Cmd_Argv(1);
+
+	// numeric values are just slot numbers
+	if (s[0] >= '0' && s[0] <= '9')
+	{
+		idnum = atoi(Cmd_Argv(1));
+		if (idnum < 0 || idnum >= maxclients->value)
+		{
+			Com_Printf ("Bad client slot: %i\n", idnum);
+			return false;
+		}
+
+		sv_client = &svs.clients[idnum];
+		sv_player = sv_client->edict;
+		if (!sv_client->state)
+		{
+			Com_Printf ("Client %i is not active\n", idnum);
+			return false;
+		}
+		return true;
+	}
+
+	// check for a name match
+	for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
+	{
+		if (!cl->state)
+			continue;
+		if (!strcmp(cl->name, s))
+		{
+			sv_client = cl;
+			sv_player = sv_client->edict;
+			return true;
+		}
+	}
+
+	Com_Printf ("Userid %s is not on the server\n", s);
+	return false;
+}
+
+
+/*
+===============================================================================
+
+SAVEGAME FILES
+
+===============================================================================
+*/
+
+/*
+=====================
+SV_WipeSavegame
+
+Delete save/<XXX>/
+=====================
+*/
+void SV_WipeSavegame (char *savename)
+{
+	char	name[MAX_OSPATH];
+	char	*s;
+
+	Com_DPrintf("SV_WipeSaveGame(%s)\n", savename);
+
+	Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir (), savename);
+	remove (name);
+	Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir (), savename);
+	remove (name);
+
+	Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir (), savename);
+	s = Sys_FindFirst( name, 0, 0 );
+	while (s)
+	{
+		remove (s);
+		s = Sys_FindNext( 0, 0 );
+	}
+	Sys_FindClose ();
+	Com_sprintf (name, sizeof(name), "%s/save/%s/*.sv2", FS_Gamedir (), savename);
+	s = Sys_FindFirst(name, 0, 0 );
+	while (s)
+	{
+		remove (s);
+		s = Sys_FindNext( 0, 0 );
+	}
+	Sys_FindClose ();
+}
+
+
+/*
+================
+CopyFile
+================
+*/
+void CopyFile (char *src, char *dst)
+{
+	FILE	*f1, *f2;
+	int		l;
+	byte	buffer[65536];
+
+	Com_DPrintf ("CopyFile (%s, %s)\n", src, dst);
+
+	f1 = fopen (src, "rb");
+	if (!f1)
+		return;
+	f2 = fopen (dst, "wb");
+	if (!f2)
+	{
+		fclose (f1);
+		return;
+	}
+
+	while (1)
+	{
+		l = fread (buffer, 1, sizeof(buffer), f1);
+		if (!l)
+			break;
+		fwrite (buffer, 1, l, f2);
+	}
+
+	fclose (f1);
+	fclose (f2);
+}
+
+
+/*
+================
+SV_CopySaveGame
+================
+*/
+void SV_CopySaveGame (char *src, char *dst)
+{
+	char	name[MAX_OSPATH], name2[MAX_OSPATH];
+	int		l, len;
+	char	*found;
+
+	Com_DPrintf("SV_CopySaveGame(%s, %s)\n", src, dst);
+
+	SV_WipeSavegame (dst);
+
+	// copy the savegame over
+	Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir(), src);
+	Com_sprintf (name2, sizeof(name2), "%s/save/%s/server.ssv", FS_Gamedir(), dst);
+	FS_CreatePath (name2);
+	CopyFile (name, name2);
+
+	Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir(), src);
+	Com_sprintf (name2, sizeof(name2), "%s/save/%s/game.ssv", FS_Gamedir(), dst);
+	CopyFile (name, name2);
+
+	Com_sprintf (name, sizeof(name), "%s/save/%s/", FS_Gamedir(), src);
+	len = strlen(name);
+	Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir(), src);
+	found = Sys_FindFirst(name, 0, 0 );
+	while (found)
+	{
+		strcpy (name+len, found+len);
+
+		Com_sprintf (name2, sizeof(name2), "%s/save/%s/%s", FS_Gamedir(), dst, found+len);
+		CopyFile (name, name2);
+
+		// change sav to sv2
+		l = strlen(name);
+		strcpy (name+l-3, "sv2");
+		l = strlen(name2);
+		strcpy (name2+l-3, "sv2");
+		CopyFile (name, name2);
+
+		found = Sys_FindNext( 0, 0 );
+	}
+	Sys_FindClose ();
+}
+
+
+/*
+==============
+SV_WriteLevelFile
+
+==============
+*/
+void SV_WriteLevelFile (void)
+{
+	char	name[MAX_OSPATH];
+	FILE	*f;
+
+	Com_DPrintf("SV_WriteLevelFile()\n");
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name);
+	f = fopen(name, "wb");
+	if (!f)
+	{
+		Com_Printf ("Failed to open %s\n", name);
+		return;
+	}
+	fwrite (sv.configstrings, sizeof(sv.configstrings), 1, f);
+	CM_WritePortalState (f);
+	fclose (f);
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
+	ge->WriteLevel (name);
+}
+
+/*
+==============
+SV_ReadLevelFile
+
+==============
+*/
+void SV_ReadLevelFile (void)
+{
+	char	name[MAX_OSPATH];
+	FILE	*f;
+
+	Com_DPrintf("SV_ReadLevelFile()\n");
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name);
+	f = fopen(name, "rb");
+	if (!f)
+	{
+		Com_Printf ("Failed to open %s\n", name);
+		return;
+	}
+	FS_Read (sv.configstrings, sizeof(sv.configstrings), f);
+	CM_ReadPortalState (f);
+	fclose (f);
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
+	ge->ReadLevel (name);
+}
+
+/*
+==============
+SV_WriteServerFile
+
+==============
+*/
+void SV_WriteServerFile (qboolean autosave)
+{
+	FILE	*f;
+	cvar_t	*var;
+	char	name[MAX_OSPATH], string[128];
+	char	comment[32];
+	Tm	*newtime;
+
+	Com_DPrintf("SV_WriteServerFile(%s)\n", autosave ? "true" : "false");
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/server.ssv", FS_Gamedir());
+	f = fopen (name, "wb");
+	if (!f)
+	{
+		Com_Printf ("Couldn't write %s\n", name);
+		return;
+	}
+	// write the comment field
+	memset (comment, 0, sizeof(comment));
+
+	if (!autosave)
+	{
+		newtime = localtime (time(nil));
+		Com_sprintf (comment,sizeof(comment), "%2i:%i%i %2i/%2i  ", newtime->hour
+			, newtime->min/10, newtime->min%10, newtime->mon+1, newtime->mday);
+		strncat (comment, sv.configstrings[CS_NAME], sizeof(comment)-1-strlen(comment) );
+	}
+	else
+	{	// autosaved
+		Com_sprintf (comment, sizeof(comment), "ENTERING %s", sv.configstrings[CS_NAME]);
+	}
+
+	fwrite (comment, 1, sizeof(comment), f);
+
+	// write the mapcmd
+	fwrite (svs.mapcmd, 1, sizeof(svs.mapcmd), f);
+
+	// write all CVAR_LATCH cvars
+	// these will be things like coop, skill, deathmatch, etc
+	for (var = cvar_vars ; var ; var=var->next)
+	{
+		if (!(var->flags & CVAR_LATCH))
+			continue;
+		if (strlen(var->name) >= sizeof(name)-1
+			|| strlen(var->string) >= sizeof(string)-1)
+		{
+			Com_Printf ("Cvar too long: %s = %s\n", var->name, var->string);
+			continue;
+		}
+		memset (name, 0, sizeof(name));
+		memset (string, 0, sizeof(string));
+		strcpy (name, var->name);
+		strcpy (string, var->string);
+		fwrite (name, 1, sizeof(name), f);
+		fwrite (string, 1, sizeof(string), f);
+	}
+
+	fclose (f);
+
+	// write game state
+	Com_sprintf (name, sizeof(name), "%s/save/current/game.ssv", FS_Gamedir());
+	ge->WriteGame (name, autosave);
+}
+
+/*
+==============
+SV_ReadServerFile
+
+==============
+*/
+void SV_ReadServerFile (void)
+{
+	FILE	*f;
+	char	name[MAX_OSPATH], string[128];
+	char	comment[32];
+	char	mapcmd[MAX_TOKEN_CHARS];
+
+	Com_DPrintf("SV_ReadServerFile()\n");
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/server.ssv", FS_Gamedir());
+	f = fopen (name, "rb");
+	if (!f)
+	{
+		Com_Printf ("Couldn't read %s\n", name);
+		return;
+	}
+	// read the comment field
+	FS_Read (comment, sizeof(comment), f);
+
+	// read the mapcmd
+	FS_Read (mapcmd, sizeof(mapcmd), f);
+
+	// read all CVAR_LATCH cvars
+	// these will be things like coop, skill, deathmatch, etc
+	while (1)
+	{
+		if (!fread (name, 1, sizeof(name), f))
+			break;
+		FS_Read (string, sizeof(string), f);
+		Com_DPrintf ("Set %s = %s\n", name, string);
+		Cvar_ForceSet (name, string);
+	}
+
+	fclose (f);
+
+	// start a new game fresh with new cvars
+	SV_InitGame ();
+
+	strcpy (svs.mapcmd, mapcmd);
+
+	// read game state
+	Com_sprintf (name, sizeof(name), "%s/save/current/game.ssv", FS_Gamedir());
+	ge->ReadGame (name);
+}
+
+
+//=========================================================
+
+
+
+
+/*
+==================
+SV_DemoMap_f
+
+Puts the server in demo mode on a specific map/cinematic
+==================
+*/
+void SV_DemoMap_f (void)
+{
+	SV_Map (true, Cmd_Argv(1), false );
+}
+
+/*
+==================
+SV_GameMap_f
+
+Saves the state of the map just being exited and goes to a new map.
+
+If the initial character of the map string is '*', the next map is
+in a new unit, so the current savegame directory is cleared of
+map files.
+
+Example:
+
+*inter.cin+jail
+
+Clears the archived maps, plays the inter.cin cinematic, then
+goes to map jail.bsp.
+==================
+*/
+void SV_GameMap_f (void)
+{
+	char		*map;
+	int			i;
+	client_t	*cl;
+	qboolean	*savedInuse;
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("USAGE: gamemap <map>\n");
+		return;
+	}
+
+	Com_DPrintf("SV_GameMap(%s)\n", Cmd_Argv(1));
+
+	FS_CreatePath (va("%s/save/current/", FS_Gamedir()));
+
+	// check for clearing the current savegame
+	map = Cmd_Argv(1);
+	if (map[0] == '*')
+	{
+		// wipe all the *.sav files
+		SV_WipeSavegame ("current");
+	}
+	else
+	{	// save the map just exited
+		if (sv.state == ss_game)
+		{
+			// clear all the client inuse flags before saving so that
+			// when the level is re-entered, the clients will spawn
+			// at spawn points instead of occupying body shells
+			savedInuse = malloc(maxclients->value * sizeof(qboolean));
+			for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
+			{
+				savedInuse[i] = cl->edict->inuse;
+				cl->edict->inuse = false;
+			}
+
+			SV_WriteLevelFile ();
+
+			// we must restore these for clients to transfer over correctly
+			for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
+				cl->edict->inuse = savedInuse[i];
+			free (savedInuse);
+		}
+	}
+
+	// start up the next map
+	SV_Map (false, Cmd_Argv(1), false );
+
+	// archive server state
+	strncpy (svs.mapcmd, Cmd_Argv(1), sizeof(svs.mapcmd)-1);
+
+	// copy off the level to the autosave slot
+	if (!dedicated->value)
+	{
+		SV_WriteServerFile (true);
+		SV_CopySaveGame ("current", "save0");
+	}
+}
+
+/*
+==================
+SV_Map_f
+
+Goes directly to a given map without any savegame archiving.
+For development work
+==================
+*/
+void SV_Map_f (void)
+{
+	char	*map;
+	char	expanded[MAX_QPATH];
+
+	// if not a pcx, demo, or cinematic, check to make sure the level exists
+	map = Cmd_Argv(1);
+	if (!strstr (map, "."))
+	{
+		Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map);
+		if (FS_LoadFile (expanded, NULL) == -1)
+		{
+			Com_Printf ("Can't find %s\n", expanded);
+			return;
+		}
+	}
+
+	sv.state = ss_dead;		// don't save current level when changing
+	SV_WipeSavegame("current");
+	SV_GameMap_f ();
+}
+
+/*
+=====================================================================
+
+  SAVEGAMES
+
+=====================================================================
+*/
+
+
+/*
+==============
+SV_Loadgame_f
+
+==============
+*/
+void SV_Loadgame_f (void)
+{
+	char	name[MAX_OSPATH];
+	FILE	*f;
+	char	*dir;
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("USAGE: loadgame <directory>\n");
+		return;
+	}
+
+	Com_Printf ("Loading game...\n");
+
+	dir = Cmd_Argv(1);
+	if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") )
+	{
+		Com_Printf ("Bad savedir.\n");
+	}
+
+	// make sure the server.ssv file exists
+	Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir(), Cmd_Argv(1));
+	f = fopen (name, "rb");
+	if (!f)
+	{
+		Com_Printf ("No such savegame: %s\n", name);
+		return;
+	}
+	fclose (f);
+
+	SV_CopySaveGame (Cmd_Argv(1), "current");
+
+	SV_ReadServerFile ();
+
+	// go to the map
+	sv.state = ss_dead;		// don't save current level when changing
+	SV_Map (false, svs.mapcmd, true);
+}
+
+
+
+/*
+==============
+SV_Savegame_f
+
+==============
+*/
+void SV_Savegame_f (void)
+{
+	char	*dir;
+
+	if (sv.state != ss_game)
+	{
+		Com_Printf ("You must be in a game to save.\n");
+		return;
+	}
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("USAGE: savegame <directory>\n");
+		return;
+	}
+
+	if (Cvar_VariableValue("deathmatch"))
+	{
+		Com_Printf ("Can't savegame in a deathmatch\n");
+		return;
+	}
+
+	if (!strcmp (Cmd_Argv(1), "current"))
+	{
+		Com_Printf ("Can't save to 'current'\n");
+		return;
+	}
+
+	if (maxclients->value == 1 && svs.clients[0].edict->client->ps.stats[STAT_HEALTH] <= 0)
+	{
+		Com_Printf ("\nCan't savegame while dead!\n");
+		return;
+	}
+
+	dir = Cmd_Argv(1);
+	if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") )
+	{
+		Com_Printf ("Bad savedir.\n");
+	}
+
+	Com_Printf ("Saving game...\n");
+
+	// archive current level, including all client edicts.
+	// when the level is reloaded, they will be shells awaiting
+	// a connecting client
+	SV_WriteLevelFile ();
+
+	// save server state
+	SV_WriteServerFile (false);
+
+	// copy it off
+	SV_CopySaveGame ("current", dir);
+
+	Com_Printf ("Done.\n");
+}
+
+//===============================================================
+
+/*
+==================
+SV_Kick_f
+
+Kick a user off of the server
+==================
+*/
+void SV_Kick_f (void)
+{
+	if (!svs.initialized)
+	{
+		Com_Printf ("No server running.\n");
+		return;
+	}
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("Usage: kick <userid>\n");
+		return;
+	}
+
+	if (!SV_SetPlayer ())
+		return;
+
+	SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked\n", sv_client->name);
+	// print directly, because the dropped client won't get the
+	// SV_BroadcastPrintf message
+	SV_ClientPrintf (sv_client, PRINT_HIGH, "You were kicked from the game\n");
+	SV_DropClient (sv_client);
+	sv_client->lastmessage = svs.realtime;	// min case there is a funny zombie
+}
+
+
+/*
+================
+SV_Status_f
+================
+*/
+void SV_Status_f (void)
+{
+	int			i, j, l;
+	client_t	*cl;
+	char		*s;
+	int			ping;
+	if (!svs.clients)
+	{
+		Com_Printf ("No server running.\n");
+		return;
+	}
+	Com_Printf ("map              : %s\n", sv.name);
+
+	Com_Printf ("num score ping name            lastmsg address               qport \n");
+	Com_Printf ("--- ----- ---- --------------- ------- --------------------- ------\n");
+	for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
+	{
+		if (!cl->state)
+			continue;
+		Com_Printf ("%3i ", i);
+		Com_Printf ("%5i ", cl->edict->client->ps.stats[STAT_FRAGS]);
+
+		if (cl->state == cs_connected)
+			Com_Printf ("CNCT ");
+		else if (cl->state == cs_zombie)
+			Com_Printf ("ZMBI ");
+		else
+		{
+			ping = cl->ping < 9999 ? cl->ping : 9999;
+			Com_Printf ("%4i ", ping);
+		}
+
+		Com_Printf ("%s", cl->name);
+		l = 16 - strlen(cl->name);
+		for (j=0 ; j<l ; j++)
+			Com_Printf (" ");
+
+		Com_Printf ("%7i ", svs.realtime - cl->lastmessage );
+
+		s = NET_AdrToString ( cl->netchan.remote_address);
+		Com_Printf ("%s", s);
+		l = 22 - strlen(s);
+		for (j=0 ; j<l ; j++)
+			Com_Printf (" ");
+		
+		Com_Printf ("%5i", cl->netchan.qport);
+
+		Com_Printf ("\n");
+	}
+	Com_Printf ("\n");
+}
+
+/*
+==================
+SV_ConSay_f
+==================
+*/
+void SV_ConSay_f(void)
+{
+	client_t *client;
+	int		j;
+	char	*p;
+	char	text[1024];
+
+	if (Cmd_Argc () < 2)
+		return;
+
+	strcpy (text, "console: ");
+	p = Cmd_Args();
+
+	if (*p == '"')
+	{
+		p++;
+		p[strlen(p)-1] = 0;
+	}
+
+	strcat(text, p);
+
+	for (j = 0, client = svs.clients; j < maxclients->value; j++, client++)
+	{
+		if (client->state != cs_spawned)
+			continue;
+		SV_ClientPrintf(client, PRINT_CHAT, "%s\n", text);
+	}
+}
+
+
+/*
+==================
+SV_Heartbeat_f
+==================
+*/
+void SV_Heartbeat_f (void)
+{
+	svs.last_heartbeat = -9999999;
+}
+
+
+/*
+===========
+SV_Serverinfo_f
+
+  Examine or change the serverinfo string
+===========
+*/
+void SV_Serverinfo_f (void)
+{
+	Com_Printf ("Server info settings:\n");
+	Info_Print (Cvar_Serverinfo());
+}
+
+
+/*
+===========
+SV_DumpUser_f
+
+Examine all a users info strings
+===========
+*/
+void SV_DumpUser_f (void)
+{
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("Usage: info <userid>\n");
+		return;
+	}
+
+	if (!SV_SetPlayer ())
+		return;
+
+	Com_Printf ("userinfo\n");
+	Com_Printf ("--------\n");
+	Info_Print (sv_client->userinfo);
+
+}
+
+
+/*
+==============
+SV_ServerRecord_f
+
+Begins server demo recording.  Every entity and every message will be
+recorded, but no playerinfo will be stored.  Primarily for demo merging.
+==============
+*/
+void SV_ServerRecord_f (void)
+{
+	char	name[MAX_OSPATH];
+	char	buf_data[32768];
+	sizebuf_t	buf;
+	int		len;
+	int		i;
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("serverrecord <demoname>\n");
+		return;
+	}
+
+	if (svs.demofile)
+	{
+		Com_Printf ("Already recording.\n");
+		return;
+	}
+
+	if (sv.state != ss_game)
+	{
+		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);
+	svs.demofile = fopen (name, "wb");
+	if (!svs.demofile)
+	{
+		Com_Printf ("ERROR: couldn't open.\n");
+		return;
+	}
+
+	// setup a buffer to catch all multicasts
+	SZ_Init (&svs.demo_multicast, svs.demo_multicast_buf, sizeof(svs.demo_multicast_buf));
+
+	//
+	// write a single giant fake message with all the startup info
+	//
+	SZ_Init (&buf, (byte *)buf_data, sizeof(buf_data));
+
+	//
+	// serverdata needs to go over for all types of servers
+	// to make sure the protocol is right, and to set the gamedir
+	//
+	// send the serverdata
+	MSG_WriteByte (&buf, svc_serverdata);
+	MSG_WriteLong (&buf, PROTOCOL_VERSION);
+	MSG_WriteLong (&buf, svs.spawncount);
+	// 2 means server demo
+	MSG_WriteByte (&buf, 2);	// demos are always attract loops
+	MSG_WriteString (&buf, Cvar_VariableString ("gamedir"));
+	MSG_WriteShort (&buf, -1);
+	// send full levelname
+	MSG_WriteString (&buf, sv.configstrings[CS_NAME]);
+
+	for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
+		if (sv.configstrings[i][0])
+		{
+			MSG_WriteByte (&buf, svc_configstring);
+			MSG_WriteShort (&buf, i);
+			MSG_WriteString (&buf, sv.configstrings[i]);
+		}
+
+	// write it to the demo file
+	Com_DPrintf ("signon message length: %i\n", buf.cursize);
+	len = LittleLong (buf.cursize);
+	fwrite (&len, 4, 1, svs.demofile);
+	fwrite (buf.data, buf.cursize, 1, svs.demofile);
+
+	// the rest of the demo file will be individual frames
+}
+
+
+/*
+==============
+SV_ServerStop_f
+
+Ends server demo recording
+==============
+*/
+void SV_ServerStop_f (void)
+{
+	if (!svs.demofile)
+	{
+		Com_Printf ("Not doing a serverrecord.\n");
+		return;
+	}
+	fclose (svs.demofile);
+	svs.demofile = NULL;
+	Com_Printf ("Recording completed.\n");
+}
+
+
+/*
+===============
+SV_KillServer_f
+
+Kick everyone off, possibly in preparation for a new game
+
+===============
+*/
+void SV_KillServer_f (void)
+{
+	if (!svs.initialized)
+		return;
+	SV_Shutdown ("Server was killed.\n", false);
+	NET_Config ( false );	// close network sockets
+}
+
+/*
+===============
+SV_ServerCommand_f
+
+Let the game dll handle a command
+===============
+*/
+void SV_ServerCommand_f (void)
+{
+	if (!ge)
+	{
+		Com_Printf ("No game loaded.\n");
+		return;
+	}
+
+	ge->ServerCommand();
+}
+
+//===========================================================
+
+/*
+==================
+SV_InitOperatorCommands
+==================
+*/
+void SV_InitOperatorCommands (void)
+{
+	Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
+	Cmd_AddCommand ("kick", SV_Kick_f);
+	Cmd_AddCommand ("status", SV_Status_f);
+	Cmd_AddCommand ("serverinfo", SV_Serverinfo_f);
+	Cmd_AddCommand ("dumpuser", SV_DumpUser_f);
+
+	Cmd_AddCommand ("map", SV_Map_f);
+	Cmd_AddCommand ("demomap", SV_DemoMap_f);
+	Cmd_AddCommand ("gamemap", SV_GameMap_f);
+	Cmd_AddCommand ("setmaster", SV_SetMaster_f);
+
+	if ( dedicated->value )
+		Cmd_AddCommand ("say", SV_ConSay_f);
+
+	Cmd_AddCommand ("serverrecord", SV_ServerRecord_f);
+	Cmd_AddCommand ("serverstop", SV_ServerStop_f);
+
+	Cmd_AddCommand ("save", SV_Savegame_f);
+	Cmd_AddCommand ("load", SV_Loadgame_f);
+
+	Cmd_AddCommand ("killserver", SV_KillServer_f);
+
+	Cmd_AddCommand ("sv", SV_ServerCommand_f);
+}
+
--- /dev/null
+++ b/sv_ents.c
@@ -1,0 +1,709 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+=============================================================================
+
+Encode a client frame onto the network channel
+
+=============================================================================
+*/
+
+/* commented out in release
+
+// because there can be a lot of projectiles, there is a special
+// network protocol for them
+#define	MAX_PROJECTILES		64
+edict_t	*projectiles[MAX_PROJECTILES];
+int		numprojs;
+cvar_t  *sv_projectiles;
+
+qboolean SV_AddProjectileUpdate (edict_t *ent)
+{
+	if (!sv_projectiles)
+		sv_projectiles = Cvar_Get("sv_projectiles", "1", 0);
+
+	if (!sv_projectiles->value)
+		return false;
+
+	if (!(ent->svflags & SVF_PROJECTILE))
+		return false;
+	if (numprojs == MAX_PROJECTILES)
+		return true;
+
+	projectiles[numprojs++] = ent;
+	return true;
+}
+
+void SV_EmitProjectileUpdate (sizebuf_t *msg)
+{
+	byte	bits[16];	// [modelindex] [48 bits] xyz p y 12 12 12 8 8 [entitynum] [e2]
+	int		n, i;
+	edict_t	*ent;
+	int		x, y, z, p, yaw;
+	int len;
+
+	if (!numprojs)
+		return;
+
+	MSG_WriteByte (msg, numprojs);
+
+	for (n=0 ; n<numprojs ; n++)
+	{
+		ent = projectiles[n];
+		x = (int)(ent->s.origin[0]+4096)>>1;
+		y = (int)(ent->s.origin[1]+4096)>>1;
+		z = (int)(ent->s.origin[2]+4096)>>1;
+		p = (int)(256*ent->s.angles[0]/360)&255;
+		yaw = (int)(256*ent->s.angles[1]/360)&255;
+
+		len = 0;
+		bits[len++] = x;
+		bits[len++] = (x>>8) | (y<<4);
+		bits[len++] = (y>>4);
+		bits[len++] = z;
+		bits[len++] = (z>>8);
+		if (ent->s.effects & EF_BLASTER)
+			bits[len-1] |= 64;
+
+		if (ent->s.old_origin[0] != ent->s.origin[0] ||
+			ent->s.old_origin[1] != ent->s.origin[1] ||
+			ent->s.old_origin[2] != ent->s.origin[2]) {
+			bits[len-1] |= 128;
+			x = (int)(ent->s.old_origin[0]+4096)>>1;
+			y = (int)(ent->s.old_origin[1]+4096)>>1;
+			z = (int)(ent->s.old_origin[2]+4096)>>1;
+			bits[len++] = x;
+			bits[len++] = (x>>8) | (y<<4);
+			bits[len++] = (y>>4);
+			bits[len++] = z;
+			bits[len++] = (z>>8);
+		}
+
+		bits[len++] = p;
+		bits[len++] = yaw;
+		bits[len++] = ent->s.modelindex;
+
+		bits[len++] = (ent->s.number & 0x7f);
+		if (ent->s.number > 255) {
+			bits[len-1] |= 128;
+			bits[len++] = (ent->s.number >> 7);
+		}
+
+		for (i=0 ; i<len ; i++)
+			MSG_WriteByte (msg, bits[i]);
+	}
+}
+*/
+
+/*
+=============
+SV_EmitPacketEntities
+
+Writes a delta update of an entity_state_t list to the message.
+=============
+*/
+void SV_EmitPacketEntities (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
+{
+	entity_state_t	*oldent = nil, *newent = nil;
+	int		oldindex, newindex;
+	int		oldnum, newnum;
+	int		from_num_entities;
+	int		bits;
+
+/*
+	if (numprojs)
+		MSG_WriteByte (msg, svc_packetentities2);
+	else
+*/
+		MSG_WriteByte (msg, svc_packetentities);
+
+	if (!from)
+		from_num_entities = 0;
+	else
+		from_num_entities = from->num_entities;
+
+	newindex = 0;
+	oldindex = 0;
+	while (newindex < to->num_entities || oldindex < from_num_entities)
+	{
+		if (newindex >= to->num_entities)
+			newnum = 9999;
+		else
+		{
+			newent = &svs.client_entities[(to->first_entity+newindex)%svs.num_client_entities];
+			newnum = newent->number;
+		}
+
+		if (oldindex >= from_num_entities)
+			oldnum = 9999;
+		else
+		{
+			oldent = &svs.client_entities[(from->first_entity+oldindex)%svs.num_client_entities];
+			oldnum = oldent->number;
+		}
+
+		if (newnum == oldnum)
+		{	// delta update from old position
+			// because the force parm is false, this will not result
+			// in any bytes being emited if the entity has not changed at all
+			// note that players are always 'newentities', this updates their oldorigin always
+			// and prevents warping
+			MSG_WriteDeltaEntity (oldent, newent, msg, false, newent->number <= maxclients->value);
+			oldindex++;
+			newindex++;
+			continue;
+		}
+
+		if (newnum < oldnum)
+		{	// this is a new entity, send it from the baseline
+			MSG_WriteDeltaEntity (&sv.baselines[newnum], newent, msg, true, true);
+			newindex++;
+			continue;
+		}
+
+		if (newnum > oldnum)
+		{	// the old entity isn't present in the new message
+			bits = U_REMOVE;
+			if (oldnum >= 256)
+				bits |= U_NUMBER16 | U_MOREBITS1;
+
+			MSG_WriteByte (msg,	bits&255 );
+			if (bits & 0x0000ff00)
+				MSG_WriteByte (msg,	(bits>>8)&255 );
+
+			if (bits & U_NUMBER16)
+				MSG_WriteShort (msg, oldnum);
+			else
+				MSG_WriteByte (msg, oldnum);
+
+			oldindex++;
+			continue;
+		}
+	}
+
+	MSG_WriteShort (msg, 0);	// end of packetentities
+
+/*
+	if (numprojs)
+		SV_EmitProjectileUpdate(msg);
+*/
+}
+
+
+
+/*
+=============
+SV_WritePlayerstateToClient
+
+=============
+*/
+void SV_WritePlayerstateToClient (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
+{
+	int				i;
+	int				pflags;
+	player_state_t	*ps, *ops;
+	player_state_t	dummy;
+	int				statbits;
+
+	ps = &to->ps;
+	if (!from)
+	{
+		memset (&dummy, 0, sizeof(dummy));
+		ops = &dummy;
+	}
+	else
+		ops = &from->ps;
+
+	//
+	// determine what needs to be sent
+	//
+	pflags = 0;
+
+	if (ps->pmove.pm_type != ops->pmove.pm_type)
+		pflags |= PS_M_TYPE;
+
+	if (ps->pmove.origin[0] != ops->pmove.origin[0]
+		|| ps->pmove.origin[1] != ops->pmove.origin[1]
+		|| ps->pmove.origin[2] != ops->pmove.origin[2] )
+		pflags |= PS_M_ORIGIN;
+
+	if (ps->pmove.velocity[0] != ops->pmove.velocity[0]
+		|| ps->pmove.velocity[1] != ops->pmove.velocity[1]
+		|| ps->pmove.velocity[2] != ops->pmove.velocity[2] )
+		pflags |= PS_M_VELOCITY;
+
+	if (ps->pmove.pm_time != ops->pmove.pm_time)
+		pflags |= PS_M_TIME;
+
+	if (ps->pmove.pm_flags != ops->pmove.pm_flags)
+		pflags |= PS_M_FLAGS;
+
+	if (ps->pmove.gravity != ops->pmove.gravity)
+		pflags |= PS_M_GRAVITY;
+
+	if (ps->pmove.delta_angles[0] != ops->pmove.delta_angles[0]
+		|| ps->pmove.delta_angles[1] != ops->pmove.delta_angles[1]
+		|| ps->pmove.delta_angles[2] != ops->pmove.delta_angles[2] )
+		pflags |= PS_M_DELTA_ANGLES;
+
+
+	if (ps->viewoffset[0] != ops->viewoffset[0]
+		|| ps->viewoffset[1] != ops->viewoffset[1]
+		|| ps->viewoffset[2] != ops->viewoffset[2] )
+		pflags |= PS_VIEWOFFSET;
+
+	if (ps->viewangles[0] != ops->viewangles[0]
+		|| ps->viewangles[1] != ops->viewangles[1]
+		|| ps->viewangles[2] != ops->viewangles[2] )
+		pflags |= PS_VIEWANGLES;
+
+	if (ps->kick_angles[0] != ops->kick_angles[0]
+		|| ps->kick_angles[1] != ops->kick_angles[1]
+		|| ps->kick_angles[2] != ops->kick_angles[2] )
+		pflags |= PS_KICKANGLES;
+
+	if (ps->blend[0] != ops->blend[0]
+		|| ps->blend[1] != ops->blend[1]
+		|| ps->blend[2] != ops->blend[2]
+		|| ps->blend[3] != ops->blend[3] )
+		pflags |= PS_BLEND;
+
+	if (ps->fov != ops->fov)
+		pflags |= PS_FOV;
+
+	if (ps->rdflags != ops->rdflags)
+		pflags |= PS_RDFLAGS;
+
+	if (ps->gunframe != ops->gunframe)
+		pflags |= PS_WEAPONFRAME;
+
+	pflags |= PS_WEAPONINDEX;
+
+	//
+	// write it
+	//
+	MSG_WriteByte (msg, svc_playerinfo);
+	MSG_WriteShort (msg, pflags);
+
+	//
+	// write the pmove_state_t
+	//
+	if (pflags & PS_M_TYPE)
+		MSG_WriteByte (msg, ps->pmove.pm_type);
+
+	if (pflags & PS_M_ORIGIN)
+	{
+		MSG_WriteShort (msg, ps->pmove.origin[0]);
+		MSG_WriteShort (msg, ps->pmove.origin[1]);
+		MSG_WriteShort (msg, ps->pmove.origin[2]);
+	}
+
+	if (pflags & PS_M_VELOCITY)
+	{
+		MSG_WriteShort (msg, ps->pmove.velocity[0]);
+		MSG_WriteShort (msg, ps->pmove.velocity[1]);
+		MSG_WriteShort (msg, ps->pmove.velocity[2]);
+	}
+
+	if (pflags & PS_M_TIME)
+		MSG_WriteByte (msg, ps->pmove.pm_time);
+
+	if (pflags & PS_M_FLAGS)
+		MSG_WriteByte (msg, ps->pmove.pm_flags);
+
+	if (pflags & PS_M_GRAVITY)
+		MSG_WriteShort (msg, ps->pmove.gravity);
+
+	if (pflags & PS_M_DELTA_ANGLES)
+	{
+		MSG_WriteShort (msg, ps->pmove.delta_angles[0]);
+		MSG_WriteShort (msg, ps->pmove.delta_angles[1]);
+		MSG_WriteShort (msg, ps->pmove.delta_angles[2]);
+	}
+
+	//
+	// write the rest of the player_state_t
+	//
+	if (pflags & PS_VIEWOFFSET)
+	{
+		MSG_WriteChar (msg, ps->viewoffset[0]*4);
+		MSG_WriteChar (msg, ps->viewoffset[1]*4);
+		MSG_WriteChar (msg, ps->viewoffset[2]*4);
+	}
+
+	if (pflags & PS_VIEWANGLES)
+	{
+		MSG_WriteAngle16 (msg, ps->viewangles[0]);
+		MSG_WriteAngle16 (msg, ps->viewangles[1]);
+		MSG_WriteAngle16 (msg, ps->viewangles[2]);
+	}
+
+	if (pflags & PS_KICKANGLES)
+	{
+		MSG_WriteChar (msg, ps->kick_angles[0]*4);
+		MSG_WriteChar (msg, ps->kick_angles[1]*4);
+		MSG_WriteChar (msg, ps->kick_angles[2]*4);
+	}
+
+	if (pflags & PS_WEAPONINDEX)
+	{
+		MSG_WriteByte (msg, ps->gunindex);
+	}
+
+	if (pflags & PS_WEAPONFRAME)
+	{
+		MSG_WriteByte (msg, ps->gunframe);
+		MSG_WriteChar (msg, ps->gunoffset[0]*4);
+		MSG_WriteChar (msg, ps->gunoffset[1]*4);
+		MSG_WriteChar (msg, ps->gunoffset[2]*4);
+		MSG_WriteChar (msg, ps->gunangles[0]*4);
+		MSG_WriteChar (msg, ps->gunangles[1]*4);
+		MSG_WriteChar (msg, ps->gunangles[2]*4);
+	}
+
+	if (pflags & PS_BLEND)
+	{
+		MSG_WriteByte (msg, ps->blend[0]*255);
+		MSG_WriteByte (msg, ps->blend[1]*255);
+		MSG_WriteByte (msg, ps->blend[2]*255);
+		MSG_WriteByte (msg, ps->blend[3]*255);
+	}
+	if (pflags & PS_FOV)
+		MSG_WriteByte (msg, ps->fov);
+	if (pflags & PS_RDFLAGS)
+		MSG_WriteByte (msg, ps->rdflags);
+
+	// send stats
+	statbits = 0;
+	for (i=0 ; i<MAX_STATS ; i++)
+		if (ps->stats[i] != ops->stats[i])
+			statbits |= 1<<i;
+	MSG_WriteLong (msg, statbits);
+	for (i=0 ; i<MAX_STATS ; i++)
+		if (statbits & (1<<i) )
+			MSG_WriteShort (msg, ps->stats[i]);
+}
+
+
+/*
+==================
+SV_WriteFrameToClient
+==================
+*/
+void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg)
+{
+	client_frame_t		*frame, *oldframe;
+	int					lastframe;
+
+//Com_Printf ("%i -> %i\n", client->lastframe, sv.framenum);
+	// this is the frame we are creating
+	frame = &client->frames[sv.framenum & UPDATE_MASK];
+
+	if (client->lastframe <= 0)
+	{	// client is asking for a retransmit
+		oldframe = NULL;
+		lastframe = -1;
+	}
+	else if (sv.framenum - client->lastframe >= (UPDATE_BACKUP - 3) )
+	{	// client hasn't gotten a good message through in a long time
+//		Com_Printf ("%s: Delta request from out-of-date packet.\n", client->name);
+		oldframe = NULL;
+		lastframe = -1;
+	}
+	else
+	{	// we have a valid message to delta from
+		oldframe = &client->frames[client->lastframe & UPDATE_MASK];
+		lastframe = client->lastframe;
+	}
+
+	MSG_WriteByte (msg, svc_frame);
+	MSG_WriteLong (msg, sv.framenum);
+	MSG_WriteLong (msg, lastframe);	// what we are delta'ing from
+	MSG_WriteByte (msg, client->surpressCount);	// rate dropped packets
+	client->surpressCount = 0;
+
+	// send over the areabits
+	MSG_WriteByte (msg, frame->areabytes);
+	SZ_Write (msg, frame->areabits, frame->areabytes);
+
+	// delta encode the playerstate
+	SV_WritePlayerstateToClient (oldframe, frame, msg);
+
+	// delta encode the entities
+	SV_EmitPacketEntities (oldframe, frame, msg);
+}
+
+
+/*
+=============================================================================
+
+Build a client frame structure
+
+=============================================================================
+*/
+
+byte		fatpvs[65536/8];	// 32767 is MAX_MAP_LEAFS
+
+/*
+============
+SV_FatPVS
+
+The client will interpolate the view position,
+so we can't use a single PVS point
+===========
+*/
+void SV_FatPVS (vec3_t org)
+{
+	int		leafs[64];
+	int		i, j, count;
+	int		longs;
+	byte	*src;
+	vec3_t	mins, maxs;
+
+	for (i=0 ; i<3 ; i++)
+	{
+		mins[i] = org[i] - 8;
+		maxs[i] = org[i] + 8;
+	}
+
+	count = CM_BoxLeafnums (mins, maxs, leafs, 64, NULL);
+	if (count < 1)
+		Com_Error (ERR_FATAL, "SV_FatPVS: count < 1");
+	longs = (CM_NumClusters()+31)>>5;
+
+	// convert leafs to clusters
+	for (i=0 ; i<count ; i++)
+		leafs[i] = CM_LeafCluster(leafs[i]);
+
+	memcpy (fatpvs, CM_ClusterPVS(leafs[0]), longs<<2);
+	// or in all the other leaf bits
+	for (i=1 ; i<count ; i++)
+	{
+		for (j=0 ; j<i ; j++)
+			if (leafs[i] == leafs[j])
+				break;
+		if (j != i)
+			continue;		// already have the cluster we want
+		src = CM_ClusterPVS(leafs[i]);
+		for (j=0 ; j<longs ; j++)
+			((long *)fatpvs)[j] |= ((long *)src)[j];
+	}
+}
+
+
+/*
+=============
+SV_BuildClientFrame
+
+Decides which entities are going to be visible to the client, and
+copies off the playerstat and areabits.
+=============
+*/
+void SV_BuildClientFrame (client_t *client)
+{
+	int		e, i;
+	vec3_t	org;
+	edict_t	*ent;
+	edict_t	*clent;
+	client_frame_t	*frame;
+	entity_state_t	*state;
+	int		l;
+	int		clientarea, clientcluster;
+	int		leafnum;
+	int		c_fullsend;
+	byte	*clientphs;
+	byte	*bitvector;
+
+	clent = client->edict;
+	if (!clent->client)
+		return;		// not in game yet
+
+	//numprojs = 0; // no projectiles yet
+
+	// this is the frame we are creating
+	frame = &client->frames[sv.framenum & UPDATE_MASK];
+
+	frame->senttime = svs.realtime; // save it for ping calc later
+
+	// find the client's PVS
+	for (i=0 ; i<3 ; i++)
+		org[i] = clent->client->ps.pmove.origin[i]*0.125 + clent->client->ps.viewoffset[i];
+
+	leafnum = CM_PointLeafnum (org);
+	clientarea = CM_LeafArea (leafnum);
+	clientcluster = CM_LeafCluster (leafnum);
+
+	// calculate the visible areas
+	frame->areabytes = CM_WriteAreaBits (frame->areabits, clientarea);
+
+	// grab the current player_state_t
+	frame->ps = clent->client->ps;
+
+
+	SV_FatPVS (org);
+	clientphs = CM_ClusterPHS (clientcluster);
+
+	// build up the list of visible entities
+	frame->num_entities = 0;
+	frame->first_entity = svs.next_client_entities;
+
+	c_fullsend = 0;
+
+	for (e=1 ; e<ge->num_edicts ; e++)
+	{
+		ent = EDICT_NUM(e);
+
+		// ignore ents without visible models
+		if (ent->svflags & SVF_NOCLIENT)
+			continue;
+
+		// ignore ents without visible models unless they have an effect
+		if (!ent->s.modelindex && !ent->s.effects && !ent->s.sound
+			&& !ent->s.event)
+			continue;
+
+		// ignore if not touching a PV leaf
+		if (ent != clent)
+		{
+			// check area
+			if (!CM_AreasConnected (clientarea, ent->areanum))
+			{	// doors can legally straddle two areas, so
+				// we may need to check another one
+				if (!ent->areanum2
+					|| !CM_AreasConnected (clientarea, ent->areanum2))
+					continue;		// blocked by a door
+			}
+
+			// beams just check one point for PHS
+			if (ent->s.renderfx & RF_BEAM)
+			{
+				l = ent->clusternums[0];
+				if ( !(clientphs[l >> 3] & (1 << (l&7) )) )
+					continue;
+			}
+			else
+			{
+				// FIXME: if an ent has a model and a sound, but isn't
+				// in the PVS, only the PHS, clear the model
+				if (ent->s.sound)
+				{
+					bitvector = fatpvs;	//clientphs;
+				}
+				else
+					bitvector = fatpvs;
+
+				if (ent->num_clusters == -1)
+				{	// too many leafs for individual check, go by headnode
+					if (!CM_HeadnodeVisible (ent->headnode, bitvector))
+						continue;
+					c_fullsend++;
+				}
+				else
+				{	// check individual leafs
+					for (i=0 ; i < ent->num_clusters ; i++)
+					{
+						l = ent->clusternums[i];
+						if (bitvector[l >> 3] & (1 << (l&7) ))
+							break;
+					}
+					if (i == ent->num_clusters)
+						continue;		// not visible
+				}
+
+				if (!ent->s.modelindex)
+				{	// don't send sounds if they will be attenuated away
+					vec3_t	delta;
+					float	len;
+
+					VectorSubtract (org, ent->s.origin, delta);
+					len = VectorLength (delta);
+					if (len > 400)
+						continue;
+				}
+			}
+		}
+
+/*
+		if (SV_AddProjectileUpdate(ent))
+			continue; // added as a special projectile
+*/
+
+		// add it to the circular client_entities array
+		state = &svs.client_entities[svs.next_client_entities%svs.num_client_entities];
+		if (ent->s.number != e)
+		{
+			Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n");
+			ent->s.number = e;
+		}
+		*state = ent->s;
+
+		// don't mark players missiles as solid
+		if (ent->owner == client->edict)
+			state->solid = 0;
+
+		svs.next_client_entities++;
+		frame->num_entities++;
+	}
+}
+
+
+/*
+==================
+SV_RecordDemoMessage
+
+Save everything in the world out without deltas.
+Used for recording footage for merged or assembled demos
+==================
+*/
+void SV_RecordDemoMessage (void)
+{
+	int			e;
+	edict_t		*ent;
+	entity_state_t	nostate;
+	sizebuf_t	buf;
+	byte		buf_data[32768];
+	int			len;
+
+	if (!svs.demofile)
+		return;
+
+	memset (&nostate, 0, sizeof(nostate));
+	SZ_Init (&buf, buf_data, sizeof(buf_data));
+
+	// write a frame message that doesn't contain a player_state_t
+	MSG_WriteByte (&buf, svc_frame);
+	MSG_WriteLong (&buf, sv.framenum);
+
+	MSG_WriteByte (&buf, svc_packetentities);
+
+	e = 1;
+	ent = EDICT_NUM(e);
+	while (e < ge->num_edicts) 
+	{
+		// ignore ents without visible models unless they have an effect
+		if (ent->inuse &&
+			ent->s.number && 
+			(ent->s.modelindex || ent->s.effects || ent->s.sound || ent->s.event) && 
+			!(ent->svflags & SVF_NOCLIENT))
+			MSG_WriteDeltaEntity (&nostate, &ent->s, &buf, false, true);
+
+		e++;
+		ent = EDICT_NUM(e);
+	}
+
+	MSG_WriteShort (&buf, 0);		// end of packetentities
+
+	// now add the accumulated multicast information
+	SZ_Write (&buf, svs.demo_multicast.data, svs.demo_multicast.cursize);
+	SZ_Clear (&svs.demo_multicast);
+
+	// now write the entire message to the file, prefixed by the length
+	len = LittleLong (buf.cursize);
+	fwrite (&len, 4, 1, svs.demofile);
+	fwrite (buf.data, buf.cursize, 1, svs.demofile);
+}
+
--- /dev/null
+++ b/sv_game.c
@@ -1,0 +1,380 @@
+// sv_game.c -- interface to the game dll
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+game_export_t	*ge;
+
+
+/*
+===============
+PF_Unicast
+
+Sends the contents of the mutlicast buffer to a single client
+===============
+*/
+void PF_Unicast (edict_t *ent, qboolean reliable)
+{
+	int		p;
+	client_t	*client;
+
+	if (!ent)
+		return;
+
+	p = NUM_FOR_EDICT(ent);
+	if (p < 1 || p > maxclients->value)
+		return;
+
+	client = svs.clients + (p-1);
+
+	if (reliable)
+		SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
+	else
+		SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
+
+	SZ_Clear (&sv.multicast);
+}
+
+
+/*
+===============
+PF_dprintf
+
+Debug print to server console
+===============
+*/
+void PF_dprintf (char *fmt, ...)
+{
+	char		msg[1024];
+	va_list		argptr;
+	
+	va_start (argptr,fmt);
+	vsprintf (msg, fmt, argptr);
+	va_end (argptr);
+
+	Com_Printf ("%s", msg);
+}
+
+
+/*
+===============
+PF_cprintf
+
+Print to a single client
+===============
+*/
+void PF_cprintf (edict_t *ent, int level, char *fmt, ...)
+{
+	char		msg[1024];
+	va_list		argptr;
+	int		n = 0;
+
+	if (ent)
+	{
+		n = NUM_FOR_EDICT(ent);
+		if (n < 1 || n > maxclients->value)
+			Com_Error (ERR_DROP, "cprintf to a non-client");
+	}
+
+	va_start (argptr,fmt);
+	vsprintf (msg, fmt, argptr);
+	va_end (argptr);
+
+	if (ent)
+		SV_ClientPrintf (svs.clients+(n-1), level, "%s", msg);
+	else
+		Com_Printf ("%s", msg);
+}
+
+
+/*
+===============
+PF_centerprintf
+
+centerprint to a single client
+===============
+*/
+void PF_centerprintf (edict_t *ent, char *fmt, ...)
+{
+	char		msg[1024];
+	va_list		argptr;
+	int			n;
+	
+	n = NUM_FOR_EDICT(ent);
+	if (n < 1 || n > maxclients->value)
+		return;	// Com_Error (ERR_DROP, "centerprintf to a non-client");
+
+	va_start (argptr,fmt);
+	vsprintf (msg, fmt, argptr);
+	va_end (argptr);
+
+	MSG_WriteByte (&sv.multicast,svc_centerprint);
+	MSG_WriteString (&sv.multicast,msg);
+	PF_Unicast (ent, true);
+}
+
+
+/*
+===============
+PF_error
+
+Abort the server with a game error
+===============
+*/
+void PF_error (char *fmt, ...)
+{
+	char		msg[1024];
+	va_list		argptr;
+	
+	va_start (argptr,fmt);
+	vsprintf (msg, fmt, argptr);
+	va_end (argptr);
+
+	Com_Error (ERR_DROP, "Game Error: %s", msg);
+}
+
+
+/*
+=================
+PF_setmodel
+
+Also sets mins and maxs for inline bmodels
+=================
+*/
+void PF_setmodel (edict_t *ent, char *name)
+{
+	int		i;
+	cmodel_t	*mod;
+
+	if (!name)
+		Com_Error (ERR_DROP, "PF_setmodel: NULL");
+
+	i = SV_ModelIndex (name);
+		
+//	ent->model = name;
+	ent->s.modelindex = i;
+
+// if it is an inline model, get the size information for it
+	if (name[0] == '*')
+	{
+		mod = CM_InlineModel (name);
+		VectorCopy (mod->mins, ent->mins);
+		VectorCopy (mod->maxs, ent->maxs);
+		SV_LinkEdict (ent);
+	}
+
+}
+
+/*
+===============
+PF_Configstring
+
+===============
+*/
+void PF_Configstring (int index, char *val)
+{
+	if (index < 0 || index >= MAX_CONFIGSTRINGS)
+		Com_Error (ERR_DROP, "configstring: bad index %i\n", index);
+
+	if (!val)
+		val = "";
+
+	// change the string in sv
+	strcpy (sv.configstrings[index], val);
+	
+	if (sv.state != ss_loading)
+	{	// send the update to everyone
+		SZ_Clear (&sv.multicast);
+		MSG_WriteChar (&sv.multicast, svc_configstring);
+		MSG_WriteShort (&sv.multicast, index);
+		MSG_WriteString (&sv.multicast, val);
+
+		SV_Multicast (vec3_origin, MULTICAST_ALL_R);
+	}
+}
+
+
+
+void PF_WriteChar (int c) {MSG_WriteChar (&sv.multicast, c);}
+void PF_WriteByte (int c) {MSG_WriteByte (&sv.multicast, c);}
+void PF_WriteShort (int c) {MSG_WriteShort (&sv.multicast, c);}
+void PF_WriteLong (int c) {MSG_WriteLong (&sv.multicast, c);}
+void PF_WriteFloat (float f) {MSG_WriteFloat (&sv.multicast, f);}
+void PF_WriteString (char *s) {MSG_WriteString (&sv.multicast, s);}
+void PF_WritePos (vec3_t pos) {MSG_WritePos (&sv.multicast, pos);}
+void PF_WriteDir (vec3_t dir) {MSG_WriteDir (&sv.multicast, dir);}
+void PF_WriteAngle (float f) {MSG_WriteAngle (&sv.multicast, f);}
+
+
+/*
+=================
+PF_inPVS
+
+Also checks portalareas so that doors block sight
+=================
+*/
+qboolean PF_inPVS (vec3_t p1, vec3_t p2)
+{
+	int		leafnum;
+	int		cluster;
+	int		area1, area2;
+	byte	*mask;
+
+	leafnum = CM_PointLeafnum (p1);
+	cluster = CM_LeafCluster (leafnum);
+	area1 = CM_LeafArea (leafnum);
+	mask = CM_ClusterPVS (cluster);
+
+	leafnum = CM_PointLeafnum (p2);
+	cluster = CM_LeafCluster (leafnum);
+	area2 = CM_LeafArea (leafnum);
+	if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
+		return false;
+	if (!CM_AreasConnected (area1, area2))
+		return false;		// a door blocks sight
+	return true;
+}
+
+
+/*
+=================
+PF_inPHS
+
+Also checks portalareas so that doors block sound
+=================
+*/
+qboolean PF_inPHS (vec3_t p1, vec3_t p2)
+{
+	int		leafnum;
+	int		cluster;
+	int		area1, area2;
+	byte	*mask;
+
+	leafnum = CM_PointLeafnum (p1);
+	cluster = CM_LeafCluster (leafnum);
+	area1 = CM_LeafArea (leafnum);
+	mask = CM_ClusterPHS (cluster);
+
+	leafnum = CM_PointLeafnum (p2);
+	cluster = CM_LeafCluster (leafnum);
+	area2 = CM_LeafArea (leafnum);
+	if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
+		return false;		// more than one bounce away
+	if (!CM_AreasConnected (area1, area2))
+		return false;		// a door blocks hearing
+
+	return true;
+}
+
+void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume,
+    float attenuation, float timeofs)
+{
+	if (!entity)
+		return;
+	SV_StartSound (NULL, entity, channel, sound_num, volume, attenuation, timeofs);
+}
+
+//==============================================
+
+/*
+===============
+SV_ShutdownGameProgs
+
+Called when either the entire server is being killed, or
+it is changing to a different game directory.
+===============
+*/
+void SV_ShutdownGameProgs (void)
+{
+	if (!ge)
+		return;
+	ge->Shutdown ();
+	Sys_UnloadGame ();
+	ge = NULL;
+}
+
+/*
+===============
+SV_InitGameProgs
+
+Init the game subsystem for a new map
+===============
+*/
+void SCR_DebugGraph (float value, int color);
+
+void SV_InitGameProgs (void)
+{
+	game_import_t	import;
+
+	// unload anything we have now
+	if (ge)
+		SV_ShutdownGameProgs ();
+
+
+	// load a new game dll
+	import.multicast = SV_Multicast;
+	import.unicast = PF_Unicast;
+	import.bprintf = SV_BroadcastPrintf;
+	import.dprintf = PF_dprintf;
+	import.cprintf = PF_cprintf;
+	import.centerprintf = PF_centerprintf;
+	import.error = PF_error;
+
+	import.linkentity = SV_LinkEdict;
+	import.unlinkentity = SV_UnlinkEdict;
+	import.BoxEdicts = SV_AreaEdicts;
+	import.trace = SV_Trace;
+	import.pointcontents = SV_PointContents;
+	import.setmodel = PF_setmodel;
+	import.inPVS = PF_inPVS;
+	import.inPHS = PF_inPHS;
+	import.Pmove = Pmove;
+
+	import.modelindex = SV_ModelIndex;
+	import.soundindex = SV_SoundIndex;
+	import.imageindex = SV_ImageIndex;
+
+	import.configstring = PF_Configstring;
+	import.sound = PF_StartSound;
+	import.positioned_sound = SV_StartSound;
+
+	import.WriteChar = PF_WriteChar;
+	import.WriteByte = PF_WriteByte;
+	import.WriteShort = PF_WriteShort;
+	import.WriteLong = PF_WriteLong;
+	import.WriteFloat = PF_WriteFloat;
+	import.WriteString = PF_WriteString;
+	import.WritePosition = PF_WritePos;
+	import.WriteDir = PF_WriteDir;
+	import.WriteAngle = PF_WriteAngle;
+
+	import.TagMalloc = Z_TagMalloc;
+	import.TagFree = Z_Free;
+	import.FreeTags = Z_FreeTags;
+
+	import.cvar = Cvar_Get;
+	import.cvar_set = Cvar_Set;
+	import.cvar_forceset = Cvar_ForceSet;
+
+	import.argc = Cmd_Argc;
+	import.argv = Cmd_Argv;
+	import.args = Cmd_Args;
+	import.AddCommandString = Cbuf_AddText;
+
+	import.DebugGraph = SCR_DebugGraph;
+	import.SetAreaPortalState = CM_SetAreaPortalState;
+	import.AreasConnected = CM_AreasConnected;
+
+	ge = GetGameAPI(&import);
+
+	if (!ge)
+		Com_Error (ERR_DROP, "failed to load game DLL");
+	if (ge->apiversion != GAME_API_VERSION)
+		Com_Error (ERR_DROP, "game is version %i, not %i", ge->apiversion,
+		GAME_API_VERSION);
+
+	ge->Init ();
+}
--- /dev/null
+++ b/sv_init.c
@@ -1,0 +1,449 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+server_static_t	svs;				// persistant server info
+server_t		sv;					// local server
+
+/*
+================
+SV_FindIndex
+
+================
+*/
+int SV_FindIndex (char *name, int start, int max, qboolean create)
+{
+	int		i;
+	
+	if (!name || !name[0])
+		return 0;
+
+	for (i=1 ; i<max && sv.configstrings[start+i][0] ; i++)
+		if (!strcmp(sv.configstrings[start+i], name))
+			return i;
+
+	if (!create)
+		return 0;
+
+	if (i == max)
+		Com_Error (ERR_DROP, "*Index: overflow");
+
+	strncpy (sv.configstrings[start+i], name, sizeof(sv.configstrings[i]));
+
+	if (sv.state != ss_loading)
+	{	// send the update to everyone
+		SZ_Clear (&sv.multicast);
+		MSG_WriteChar (&sv.multicast, svc_configstring);
+		MSG_WriteShort (&sv.multicast, start+i);
+		MSG_WriteString (&sv.multicast, name);
+		SV_Multicast (vec3_origin, MULTICAST_ALL_R);
+	}
+
+	return i;
+}
+
+
+int SV_ModelIndex (char *name)
+{
+	return SV_FindIndex (name, CS_MODELS, MAX_MODELS, true);
+}
+
+int SV_SoundIndex (char *name)
+{
+	return SV_FindIndex (name, CS_SOUNDS, MAX_SOUNDS, true);
+}
+
+int SV_ImageIndex (char *name)
+{
+	return SV_FindIndex (name, CS_IMAGES, MAX_IMAGES, true);
+}
+
+
+/*
+================
+SV_CreateBaseline
+
+Entity baselines are used to compress the update messages
+to the clients -- only the fields that differ from the
+baseline will be transmitted
+================
+*/
+void SV_CreateBaseline (void)
+{
+	edict_t			*svent;
+	int				entnum;	
+
+	for (entnum = 1; entnum < ge->num_edicts ; entnum++)
+	{
+		svent = EDICT_NUM(entnum);
+		if (!svent->inuse)
+			continue;
+		if (!svent->s.modelindex && !svent->s.sound && !svent->s.effects)
+			continue;
+		svent->s.number = entnum;
+
+		//
+		// take current state as baseline
+		//
+		VectorCopy (svent->s.origin, svent->s.old_origin);
+		sv.baselines[entnum] = svent->s;
+	}
+}
+
+
+/*
+=================
+SV_CheckForSavegame
+=================
+*/
+void SV_CheckForSavegame (void)
+{
+	char		name[MAX_OSPATH];
+	FILE		*f;
+	int			i;
+
+	if (sv_noreload->value)
+		return;
+
+	if (Cvar_VariableValue ("deathmatch"))
+		return;
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
+	f = fopen (name, "rb");
+	if (!f)
+		return;		// no savegame
+
+	fclose (f);
+
+	SV_ClearWorld ();
+
+	// get configstrings and areaportals
+	SV_ReadLevelFile ();
+
+	if (!sv.loadgame)
+	{	// coming back to a level after being in a different
+		// level, so run it for ten seconds
+
+		// rlava2 was sending too many lightstyles, and overflowing the
+		// reliable data. temporarily changing the server state to loading
+		// prevents these from being passed down.
+		server_state_t		previousState;		// PGM
+
+		previousState = sv.state;				// PGM
+		sv.state = ss_loading;					// PGM
+		for (i=0 ; i<100 ; i++)
+			ge->RunFrame ();
+
+		sv.state = previousState;				// PGM
+	}
+}
+
+
+/*
+================
+SV_SpawnServer
+
+Change the server to a new map, taking all connected
+clients along with it.
+
+================
+*/
+void SV_SpawnServer (char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame)
+{
+	int			i;
+	unsigned	checksum;
+
+	if (attractloop)
+		Cvar_Set ("paused", "0");
+
+	Com_Printf ("------- Server Initialization -------\n");
+
+	Com_DPrintf ("SpawnServer: %s\n",server);
+	if (sv.demofile)
+		fclose (sv.demofile);
+
+	svs.spawncount++;		// any partially connected client will be
+							// restarted
+	sv.state = ss_dead;
+	Com_SetServerState (sv.state);
+
+	// wipe the entire per-level structure
+	memset (&sv, 0, sizeof(sv));
+	svs.realtime = 0;
+	sv.loadgame = loadgame;
+	sv.attractloop = attractloop;
+
+	// save name for levels that don't set message
+	strcpy (sv.configstrings[CS_NAME], server);
+	if (Cvar_VariableValue ("deathmatch"))
+	{
+		sprintf(sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value);
+		pm_airaccelerate = sv_airaccelerate->value;
+	}
+	else
+	{
+		strcpy(sv.configstrings[CS_AIRACCEL], "0");
+		pm_airaccelerate = 0;
+	}
+
+	SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf));
+
+	strcpy (sv.name, server);
+
+	// leave slots at start for clients only
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		// needs to reconnect
+		if (svs.clients[i].state > cs_connected)
+			svs.clients[i].state = cs_connected;
+		svs.clients[i].lastframe = -1;
+	}
+
+	sv.time = 1000;
+	
+	strcpy (sv.name, server);
+	strcpy (sv.configstrings[CS_NAME], server);
+
+	if (serverstate != ss_game)
+	{
+		sv.models[1] = CM_LoadMap ("", false, &checksum);	// no real map
+	}
+	else
+	{
+		Com_sprintf (sv.configstrings[CS_MODELS+1],sizeof(sv.configstrings[CS_MODELS+1]),
+			"maps/%s.bsp", server);
+		sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum);
+	}
+	Com_sprintf (sv.configstrings[CS_MAPCHECKSUM],sizeof(sv.configstrings[CS_MAPCHECKSUM]),
+		"%i", checksum);
+
+	//
+	// clear physics interaction links
+	//
+	SV_ClearWorld ();
+	
+	for (i=1 ; i< CM_NumInlineModels() ; i++)
+	{
+		Com_sprintf (sv.configstrings[CS_MODELS+1+i], sizeof(sv.configstrings[CS_MODELS+1+i]),
+			"*%i", i);
+		sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]);
+	}
+
+	//
+	// spawn the rest of the entities on the map
+	//	
+
+	// precache and static commands can be issued during
+	// map initialization
+	sv.state = ss_loading;
+	Com_SetServerState (sv.state);
+
+	// load and spawn all other entities
+	ge->SpawnEntities ( sv.name, CM_EntityString(), spawnpoint );
+
+	// run two frames to allow everything to settle
+	ge->RunFrame ();
+	ge->RunFrame ();
+
+	// all precaches are complete
+	sv.state = serverstate;
+	Com_SetServerState (sv.state);
+	
+	// create a baseline for more efficient communications
+	SV_CreateBaseline ();
+
+	// check for a savegame
+	SV_CheckForSavegame ();
+
+	// set serverinfo variable
+	Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET);
+
+	Com_Printf ("-------------------------------------\n");
+}
+
+/*
+==============
+SV_InitGame
+
+A brand new game has been started
+==============
+*/
+void SV_InitGame (void)
+{
+	int		i;
+	edict_t	*ent;
+	char	idmaster[32];
+
+	if (svs.initialized)
+	{
+		// cause any connected clients to reconnect
+		SV_Shutdown ("Server restarted\n", true);
+	}
+	else
+	{
+		// make sure the client is down
+		CL_Drop ();
+		SCR_BeginLoadingPlaque ();
+	}
+
+	// get any latched variable changes (maxclients, etc)
+	Cvar_GetLatchedVars ();
+
+	svs.initialized = true;
+
+	if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch"))
+	{
+		Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
+		Cvar_FullSet ("coop", "0",  CVAR_SERVERINFO | CVAR_LATCH);
+	}
+
+	// dedicated servers are can't be single player and are usually DM
+	// so unless they explicity set coop, force it to deathmatch
+	if (dedicated->value)
+	{
+		if (!Cvar_VariableValue ("coop"))
+			Cvar_FullSet ("deathmatch", "1",  CVAR_SERVERINFO | CVAR_LATCH);
+	}
+
+	// init clients
+	if (Cvar_VariableValue ("deathmatch"))
+	{
+		if (maxclients->value <= 1)
+			Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
+		else if (maxclients->value > MAX_CLIENTS)
+			Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
+	}
+	else if (Cvar_VariableValue ("coop"))
+	{
+		if (maxclients->value <= 1 || maxclients->value > 4)
+			Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
+#ifdef COPYPROTECT
+		if (!sv.attractloop && !dedicated->value)
+			Sys_CopyProtect ();
+#endif
+	}
+	else	// non-deathmatch, non-coop is one player
+	{
+		Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
+#ifdef COPYPROTECT
+		if (!sv.attractloop)
+			Sys_CopyProtect ();
+#endif
+	}
+
+	svs.spawncount = rand();
+	svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value);
+	svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64;
+	svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities);
+
+	// init network stuff
+	NET_Config ( (maxclients->value > 1) );
+
+	// heartbeats will always be sent to the id master
+	svs.last_heartbeat = -99999;		// send immediately
+	Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER);
+	NET_StringToAdr (idmaster, &master_adr[0]);
+
+	// init game
+	SV_InitGameProgs ();
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		ent = EDICT_NUM(i+1);
+		ent->s.number = i+1;
+		svs.clients[i].edict = ent;
+		memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd));
+	}
+}
+
+
+/*
+======================
+SV_Map
+
+  the full syntax is:
+
+  map [*]<map>$<startspot>+<nextserver>
+
+command from the console or progs.
+Map can also be a.cin, .pcx, or .dm2 file
+Nextserver is used to allow a cinematic to play, then proceed to
+another level:
+
+	map tram.cin+jail_e3
+======================
+*/
+void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame)
+{
+	char	level[MAX_QPATH];
+	char	*ch;
+	int		l;
+	char	spawnpoint[MAX_QPATH];
+
+	sv.loadgame = loadgame;
+	sv.attractloop = attractloop;
+
+	if (sv.state == ss_dead && !sv.loadgame)
+		SV_InitGame ();	// the game is just starting
+
+	strcpy (level, levelstring);
+
+	// if there is a + in the map, set nextserver to the remainder
+	ch = strstr(level, "+");
+	if (ch)
+	{
+		*ch = 0;
+			Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1));
+	}
+	else
+		Cvar_Set ("nextserver", "");
+
+	//ZOID special hack for end game screen in coop mode
+	if (Cvar_VariableValue ("coop") && !cistrcmp(level, "victory.pcx"))
+		Cvar_Set ("nextserver", "gamemap \"*base1\"");
+
+	// if there is a $, use the remainder as a spawnpoint
+	ch = strstr(level, "$");
+	if (ch)
+	{
+		*ch = 0;
+		strcpy (spawnpoint, ch+1);
+	}
+	else
+		spawnpoint[0] = 0;
+
+	// skip the end-of-unit flag if necessary
+	if (level[0] == '*')
+		strcpy (level, level+1);
+
+	l = strlen(level);
+	if (l > 4 && !strcmp (level+l-4, ".cin") )
+	{
+		SCR_BeginLoadingPlaque ();			// for local system
+		SV_BroadcastCommand ("changing\n");
+		SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame);
+	}
+	else if (l > 4 && !strcmp (level+l-4, ".dm2") )
+	{
+		SCR_BeginLoadingPlaque ();			// for local system
+		SV_BroadcastCommand ("changing\n");
+		SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame);
+	}
+	else if (l > 4 && !strcmp (level+l-4, ".pcx") )
+	{
+		SCR_BeginLoadingPlaque ();			// for local system
+		SV_BroadcastCommand ("changing\n");
+		SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame);
+	}
+	else
+	{
+		SCR_BeginLoadingPlaque ();			// for local system
+		SV_BroadcastCommand ("changing\n");
+		SV_SendClientMessages ();
+		SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame);
+		Cbuf_CopyToDefer ();
+	}
+
+	SV_BroadcastCommand ("reconnect\n");
+}
--- /dev/null
+++ b/sv_main.c
@@ -1,0 +1,1036 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+netadr_t	master_adr[MAX_MASTERS];	// address of group servers
+
+client_t	*sv_client;			// current client
+
+cvar_t	*sv_paused;
+cvar_t	*sv_timedemo;
+
+cvar_t	*sv_enforcetime;
+
+cvar_t	*timeout;				// seconds without any message
+cvar_t	*zombietime;			// seconds to sink messages after disconnect
+
+cvar_t	*rcon_password;			// password for remote server commands
+
+cvar_t	*allow_download;
+cvar_t *allow_download_players;
+cvar_t *allow_download_models;
+cvar_t *allow_download_sounds;
+cvar_t *allow_download_maps;
+
+cvar_t *sv_airaccelerate;
+
+cvar_t	*sv_noreload;			// don't reload level state when reentering
+
+cvar_t	*maxclients;			// FIXME: rename sv_maxclients
+cvar_t	*sv_showclamp;
+
+cvar_t	*hostname;
+cvar_t	*public_server;			// should heartbeats be sent
+
+cvar_t	*sv_reconnect_limit;	// minimum seconds between connect messages
+
+void Master_Shutdown (void);
+
+
+//============================================================================
+
+
+/*
+=====================
+SV_DropClient
+
+Called when the player is totally leaving the server, either willingly
+or unwillingly.  This is NOT called if the entire server is quiting
+or crashing.
+=====================
+*/
+void SV_DropClient (client_t *drop)
+{
+	// add the disconnect
+	MSG_WriteByte (&drop->netchan.message, svc_disconnect);
+
+	if (drop->state == cs_spawned)
+	{
+		// call the prog function for removing a client
+		// this will remove the body, among other things
+		ge->ClientDisconnect (drop->edict);
+	}
+
+	if (drop->download)
+	{
+		FS_FreeFile (drop->download);
+		drop->download = NULL;
+	}
+
+	drop->state = cs_zombie;		// become free in a few seconds
+	drop->name[0] = 0;
+}
+
+
+
+/*
+==============================================================================
+
+CONNECTIONLESS COMMANDS
+
+==============================================================================
+*/
+
+/*
+===============
+SV_StatusString
+
+Builds the string that is sent as heartbeats and status replies
+===============
+*/
+char	*SV_StatusString (void)
+{
+	char	player[1024];
+	static char	status[MAX_MSGLEN - 16];
+	int		i;
+	client_t	*cl;
+	int		statusLength;
+	int		playerLength;
+
+	strcpy (status, Cvar_Serverinfo());
+	strcat (status, "\n");
+	statusLength = strlen(status);
+
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		cl = &svs.clients[i];
+		if (cl->state == cs_connected || cl->state == cs_spawned )
+		{
+			Com_sprintf (player, sizeof(player), "%i %i \"%s\"\n", 
+				cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, cl->name);
+			playerLength = strlen(player);
+			if (statusLength + playerLength >= sizeof(status) )
+				break;		// can't hold any more
+			strcpy (status + statusLength, player);
+			statusLength += playerLength;
+		}
+	}
+
+	return status;
+}
+
+/*
+================
+SVC_Status
+
+Responds with all the info that qplug or qspy can see
+================
+*/
+void SVC_Status (void)
+{
+	Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", SV_StatusString());
+/*
+	Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
+	Com_Printf (SV_StatusString());
+	Com_EndRedirect ();
+*/
+}
+
+/*
+================
+SVC_Ack
+
+================
+*/
+void SVC_Ack (void)
+{
+	Com_Printf ("Ping acknowledge from %s\n", NET_AdrToString(net_from));
+}
+
+/*
+================
+SVC_Info
+
+Responds with short info for broadcast scans
+The second parameter should be the current protocol version number.
+================
+*/
+void SVC_Info (void)
+{
+	char	string[64];
+	int		i, count;
+	int		version;
+
+	if (maxclients->value == 1)
+		return;		// ignore in single player
+
+	version = atoi (Cmd_Argv(1));
+
+	if (version != PROTOCOL_VERSION)
+		Com_sprintf (string, sizeof(string), "%s: wrong version\n", hostname->string, sizeof(string));
+	else
+	{
+		count = 0;
+		for (i=0 ; i<maxclients->value ; i++)
+			if (svs.clients[i].state >= cs_connected)
+				count++;
+
+		Com_sprintf (string, sizeof(string), "%16s %8s %2i/%2i\n", hostname->string, sv.name, count, (int)maxclients->value);
+	}
+
+	Netchan_OutOfBandPrint (NS_SERVER, net_from, "info\n%s", string);
+}
+
+/*
+================
+SVC_Ping
+
+Just responds with an acknowledgement
+================
+*/
+void SVC_Ping (void)
+{
+	Netchan_OutOfBandPrint (NS_SERVER, net_from, "ack");
+}
+
+
+/*
+=================
+SVC_GetChallenge
+
+Returns a challenge number that can be used
+in a subsequent client_connect command.
+We do this to prevent denial of service attacks that
+flood the server with invalid connection IPs.  With a
+challenge, they must give a valid IP address.
+=================
+*/
+void SVC_GetChallenge (void)
+{
+	int		i;
+	int		oldest;
+	int		oldestTime;
+
+	oldest = 0;
+	oldestTime = 0x7fffffff;
+
+	// see if we already have a challenge for this ip
+	for (i = 0 ; i < MAX_CHALLENGES ; i++)
+	{
+		if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
+			break;
+		if (svs.challenges[i].time < oldestTime)
+		{
+			oldestTime = svs.challenges[i].time;
+			oldest = i;
+		}
+	}
+
+	if (i == MAX_CHALLENGES)
+	{
+		// overwrite the oldest
+		svs.challenges[oldest].challenge = rand() & 0x7fff;
+		svs.challenges[oldest].adr = net_from;
+		svs.challenges[oldest].time = curtime;
+		i = oldest;
+	}
+
+	// send it back
+	Netchan_OutOfBandPrint (NS_SERVER, net_from, "challenge %i", svs.challenges[i].challenge);
+}
+
+/*
+==================
+SVC_DirectConnect
+
+A connection request that did not come from the master
+==================
+*/
+void SVC_DirectConnect (void)
+{
+	char		userinfo[MAX_INFO_STRING];
+	netadr_t	adr;
+	int			i;
+	client_t	*cl, *newcl;
+	client_t	temp;
+	edict_t		*ent;
+	int			edictnum;
+	int			version;
+	int			qport;
+	int			challenge;
+
+	adr = net_from;
+
+	Com_DPrintf ("SVC_DirectConnect ()\n");
+
+	version = atoi(Cmd_Argv(1));
+	if (version != PROTOCOL_VERSION)
+	{
+		Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is version %4.2f.\n", VERSION);
+		Com_DPrintf ("    rejected connect from version %i\n", version);
+		return;
+	}
+
+	qport = atoi(Cmd_Argv(2));
+
+	challenge = atoi(Cmd_Argv(3));
+
+	strncpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-1);
+	userinfo[sizeof(userinfo) - 1] = 0;
+
+	// force the IP key/value pair so the game can filter based on ip
+	Info_SetValueForKey (userinfo, "ip", NET_AdrToString(net_from));
+
+	// attractloop servers are ONLY for local clients
+	if (sv.attractloop)
+	{
+		if (!NET_IsLocalAddress (adr))
+		{
+			Com_Printf ("Remote connect in attract loop.  Ignored.\n");
+			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n");
+			return;
+		}
+	}
+
+	// see if the challenge is valid
+	if (!NET_IsLocalAddress (adr))
+	{
+		for (i=0 ; i<MAX_CHALLENGES ; i++)
+		{
+			if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
+			{
+				if (challenge == svs.challenges[i].challenge)
+					break;		// good
+				Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nBad challenge.\n");
+				return;
+			}
+		}
+		if (i == MAX_CHALLENGES)
+		{
+			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nNo challenge for address.\n");
+			return;
+		}
+	}
+
+	newcl = &temp;
+	memset (newcl, 0, sizeof(client_t));
+
+	// if there is already a slot for this ip, reuse it
+	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
+	{
+		if (cl->state == cs_free)
+			continue;
+		if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
+			&& ( cl->netchan.qport == qport 
+			|| adr.port == cl->netchan.remote_address.port ) )
+		{
+			if (!NET_IsLocalAddress (adr) && (svs.realtime - cl->lastconnect) < ((int)sv_reconnect_limit->value * 1000))
+			{
+				Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (adr));
+				return;
+			}
+			Com_Printf ("%s:reconnect\n", NET_AdrToString (adr));
+			newcl = cl;
+			goto gotnewcl;
+		}
+	}
+
+	// find a client slot
+	newcl = NULL;
+	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
+	{
+		if (cl->state == cs_free)
+		{
+			newcl = cl;
+			break;
+		}
+	}
+	if (!newcl)
+	{
+		Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is full.\n");
+		Com_DPrintf ("Rejected a connection.\n");
+		return;
+	}
+
+gotnewcl:	
+	// build a new connection
+	// accept the new client
+	// this is the only place a client_t is ever initialized
+	*newcl = temp;
+	sv_client = newcl;
+	edictnum = (newcl-svs.clients)+1;
+	ent = EDICT_NUM(edictnum);
+	newcl->edict = ent;
+	newcl->challenge = challenge; // save challenge for checksumming
+
+	// get the game a chance to reject this connection or modify the userinfo
+	if (!(ge->ClientConnect (ent, userinfo)))
+	{
+		if (*Info_ValueForKey (userinfo, "rejmsg")) 
+			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\n%s\nConnection refused.\n",  
+				Info_ValueForKey (userinfo, "rejmsg"));
+		else
+			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n" );
+		Com_DPrintf ("Game rejected a connection.\n");
+		return;
+	}
+
+	// parse some info from the info strings
+	strncpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)-1);
+	SV_UserinfoChanged (newcl);
+
+	// send the connect packet to the client
+	Netchan_OutOfBandPrint (NS_SERVER, adr, "client_connect");
+
+	Netchan_Setup (NS_SERVER, &newcl->netchan , adr, qport);
+
+	newcl->state = cs_connected;
+	
+	SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf) );
+	newcl->datagram.allowoverflow = true;
+	newcl->lastmessage = svs.realtime;	// don't timeout
+	newcl->lastconnect = svs.realtime;
+}
+
+int Rcon_Validate (void)
+{
+	if (!strlen (rcon_password->string))
+		return 0;
+
+	if (strcmp (Cmd_Argv(1), rcon_password->string) )
+		return 0;
+
+	return 1;
+}
+
+/*
+===============
+SVC_RemoteCommand
+
+A client issued an rcon command.
+Shift down the remaining args
+Redirect all printfs
+===============
+*/
+void SVC_RemoteCommand (void)
+{
+	int		i;
+	char	remaining[1024];
+
+	i = Rcon_Validate ();
+
+	if (i == 0)
+		Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
+	else
+		Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
+
+	Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
+
+	if (!Rcon_Validate ())
+	{
+		Com_Printf ("Bad rcon_password.\n");
+	}
+	else
+	{
+		remaining[0] = 0;
+
+		for (i=2 ; i<Cmd_Argc() ; i++)
+		{
+			strcat (remaining, Cmd_Argv(i) );
+			strcat (remaining, " ");
+		}
+
+		Cmd_ExecuteString (remaining);
+	}
+
+	Com_EndRedirect ();
+}
+
+/*
+=================
+SV_ConnectionlessPacket
+
+A connectionless packet has four leading 0xff
+characters to distinguish it from a game channel.
+Clients that are in the game can still send
+connectionless packets.
+=================
+*/
+void SV_ConnectionlessPacket (void)
+{
+	char	*s;
+	char	*c;
+
+	MSG_BeginReading (&net_message);
+	MSG_ReadLong (&net_message);		// skip the -1 marker
+
+	s = MSG_ReadStringLine (&net_message);
+
+	Cmd_TokenizeString (s, false);
+
+	c = Cmd_Argv(0);
+	Com_DPrintf ("Packet %s : %s\n", NET_AdrToString(net_from), c);
+
+	if (!strcmp(c, "ping"))
+		SVC_Ping ();
+	else if (!strcmp(c, "ack"))
+		SVC_Ack ();
+	else if (!strcmp(c,"status"))
+		SVC_Status ();
+	else if (!strcmp(c,"info"))
+		SVC_Info ();
+	else if (!strcmp(c,"getchallenge"))
+		SVC_GetChallenge ();
+	else if (!strcmp(c,"connect"))
+		SVC_DirectConnect ();
+	else if (!strcmp(c, "rcon"))
+		SVC_RemoteCommand ();
+	else
+		Com_Printf ("bad connectionless packet from %s:\n%s\n"
+		, NET_AdrToString (net_from), s);
+}
+
+
+//============================================================================
+
+/*
+===================
+SV_CalcPings
+
+Updates the cl->ping variables
+===================
+*/
+void SV_CalcPings (void)
+{
+	int			i, j;
+	client_t	*cl;
+	int			total, count;
+
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		cl = &svs.clients[i];
+		if (cl->state != cs_spawned )
+			continue;
+
+/*
+		if (cl->lastframe > 0)
+			cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = sv.framenum - cl->lastframe + 1;
+		else
+			cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = 0;
+*/
+
+		total = 0;
+		count = 0;
+		for (j=0 ; j<LATENCY_COUNTS ; j++)
+		{
+			if (cl->frame_latency[j] > 0)
+			{
+				count++;
+				total += cl->frame_latency[j];
+			}
+		}
+		if (!count)
+			cl->ping = 0;
+		else
+			//cl->ping = total*100/count - 100;
+			cl->ping = total / count;
+
+		// let the game dll know about the ping
+		cl->edict->client->ping = cl->ping;
+	}
+}
+
+
+/*
+===================
+SV_GiveMsec
+
+Every few frames, gives all clients an allotment of milliseconds
+for their command moves.  If they exceed it, assume cheating.
+===================
+*/
+void SV_GiveMsec (void)
+{
+	int			i;
+	client_t	*cl;
+
+	if (sv.framenum & 15)
+		return;
+
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		cl = &svs.clients[i];
+		if (cl->state == cs_free )
+			continue;
+		
+		cl->commandMsec = 1800;		// 1600 + some slop
+	}
+}
+
+
+/*
+=================
+SV_ReadPackets
+=================
+*/
+void SV_ReadPackets (void)
+{
+	int			i;
+	client_t	*cl;
+	int			qport;
+
+	while (NET_GetPacket (NS_SERVER, &net_from, &net_message))
+	{
+		// check for connectionless packet (0xffffffff) first
+		if (*(int *)net_message.data == -1)
+		{
+			SV_ConnectionlessPacket ();
+			continue;
+		}
+
+		// read the qport out of the message so we can fix up
+		// stupid address translating routers
+		MSG_BeginReading (&net_message);
+		MSG_ReadLong (&net_message);		// sequence number
+		MSG_ReadLong (&net_message);		// sequence number
+		qport = MSG_ReadShort (&net_message) & 0xffff;
+
+		// check for packets from connected clients
+		for (i=0, cl=svs.clients ; i<maxclients->value ; i++,cl++)
+		{
+			if (cl->state == cs_free)
+				continue;
+			if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
+				continue;
+			if (cl->netchan.qport != qport)
+				continue;
+			if (cl->netchan.remote_address.port != net_from.port)
+			{
+				Com_Printf ("SV_ReadPackets: fixing up a translated port\n");
+				cl->netchan.remote_address.port = net_from.port;
+			}
+
+			if (Netchan_Process(&cl->netchan, &net_message))
+			{	// this is a valid, sequenced packet, so process it
+				if (cl->state != cs_zombie)
+				{
+					cl->lastmessage = svs.realtime;	// don't timeout
+					SV_ExecuteClientMessage (cl);
+				}
+			}
+			break;
+		}
+		
+		if (i != maxclients->value)
+			continue;
+	}
+}
+
+/*
+==================
+SV_CheckTimeouts
+
+If a packet has not been received from a client for timeout->value
+seconds, drop the conneciton.  Server frames are used instead of
+realtime to avoid dropping the local client while debugging.
+
+When a client is normally dropped, the client_t goes into a zombie state
+for a few seconds to make sure any final reliable message gets resent
+if necessary
+==================
+*/
+void SV_CheckTimeouts (void)
+{
+	int		i;
+	client_t	*cl;
+	int			droppoint;
+	int			zombiepoint;
+
+	droppoint = svs.realtime - 1000*timeout->value;
+	zombiepoint = svs.realtime - 1000*zombietime->value;
+
+	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
+	{
+		// message times may be wrong across a changelevel
+		if (cl->lastmessage > svs.realtime)
+			cl->lastmessage = svs.realtime;
+
+		if (cl->state == cs_zombie
+		&& cl->lastmessage < zombiepoint)
+		{
+			cl->state = cs_free;	// can now be reused
+			continue;
+		}
+		if ( (cl->state == cs_connected || cl->state == cs_spawned) 
+			&& cl->lastmessage < droppoint)
+		{
+			SV_BroadcastPrintf (PRINT_HIGH, "%s timed out\n", cl->name);
+			SV_DropClient (cl); 
+			cl->state = cs_free;	// don't bother with zombie state
+		}
+	}
+}
+
+/*
+================
+SV_PrepWorldFrame
+
+This has to be done before the world logic, because
+player processing happens outside RunWorldFrame
+================
+*/
+void SV_PrepWorldFrame (void)
+{
+	edict_t	*ent;
+	int		i;
+
+	for (i=0 ; i<ge->num_edicts ; i++)
+	{
+		ent = EDICT_NUM(i);
+		// events only last for a single message
+		ent->s.event = 0;
+	}
+
+}
+
+
+/*
+=================
+SV_RunGameFrame
+=================
+*/
+void SV_RunGameFrame (void)
+{
+	if (host_speeds->value)
+		time_before_game = Sys_Milliseconds ();
+
+	// we always need to bump framenum, even if we
+	// don't run the world, otherwise the delta
+	// compression can get confused when a client
+	// has the "current" frame
+	sv.framenum++;
+	sv.time = sv.framenum*100;
+
+	// don't run if paused
+	if (!sv_paused->value || maxclients->value > 1)
+	{
+		ge->RunFrame ();
+
+		// never get more than one tic behind
+		if (sv.time < svs.realtime)
+		{
+			if (sv_showclamp->value)
+				Com_Printf ("sv highclamp\n");
+			svs.realtime = sv.time;
+		}
+	}
+
+	if (host_speeds->value)
+		time_after_game = Sys_Milliseconds ();
+
+}
+
+/*
+==================
+SV_Frame
+
+==================
+*/
+void SV_Frame (int msec)
+{
+	time_before_game = time_after_game = 0;
+
+	// if server is not active, do nothing
+	if (!svs.initialized)
+		return;
+
+    svs.realtime += msec;
+
+	// keep the random time dependent
+	rand ();
+
+	// check timeouts
+	SV_CheckTimeouts ();
+
+	// get packets from clients
+	SV_ReadPackets ();
+
+	// move autonomous things around if enough time has passed
+	if (!sv_timedemo->value && svs.realtime < sv.time)
+	{
+		// never let the time get too far off
+		if (sv.time - svs.realtime > 100)
+		{
+			if (sv_showclamp->value)
+				Com_Printf ("sv lowclamp\n");
+			svs.realtime = sv.time - 100;
+		}
+		NET_Sleep(sv.time - svs.realtime);
+		return;
+	}
+
+	// update ping based on the last known frame from all clients
+	SV_CalcPings ();
+
+	// give the clients some timeslices
+	SV_GiveMsec ();
+
+	// let everything in the world think and move
+	SV_RunGameFrame ();
+
+	// send messages back to the clients that had packets read this frame
+	SV_SendClientMessages ();
+
+	// save the entire world state if recording a serverdemo
+	SV_RecordDemoMessage ();
+
+	// send a heartbeat to the master if needed
+	Master_Heartbeat ();
+
+	// clear teleport flags, etc for next frame
+	SV_PrepWorldFrame ();
+
+}
+
+//============================================================================
+
+/*
+================
+Master_Heartbeat
+
+Send a message to the master every few minutes to
+let it know we are alive, and log information
+================
+*/
+#define	HEARTBEAT_SECONDS	300
+void Master_Heartbeat (void)
+{
+	char		*string;
+	int			i;
+
+	
+	if (!dedicated->value)
+		return;		// only dedicated servers send heartbeats
+
+	if (!public_server->value)
+		return;		// a private dedicated game
+
+	// check for time wraparound
+	if (svs.last_heartbeat > svs.realtime)
+		svs.last_heartbeat = svs.realtime;
+
+	if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS*1000)
+		return;		// not time to send yet
+
+	svs.last_heartbeat = svs.realtime;
+
+	// send the same string that we would give for a status OOB command
+	string = SV_StatusString();
+
+	// send to group master
+	for (i=0 ; i<MAX_MASTERS ; i++)
+		if (master_adr[i].port)
+		{
+			Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
+			Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "heartbeat\n%s", string);
+		}
+}
+
+/*
+=================
+Master_Shutdown
+
+Informs all masters that this server is going down
+=================
+*/
+void Master_Shutdown (void)
+{
+	int			i;
+
+	if (!dedicated->value)
+		return;		// only dedicated servers send heartbeats
+
+	if (!public_server->value)
+		return;		// a private dedicated game
+
+	// send to group master
+	for (i=0 ; i<MAX_MASTERS ; i++)
+		if (master_adr[i].port)
+		{
+			if (i > 0)
+				Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
+			Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "shutdown");
+		}
+}
+
+//============================================================================
+
+
+/*
+=================
+SV_UserinfoChanged
+
+Pull specific info from a newly changed userinfo string
+into a more C freindly form.
+=================
+*/
+void SV_UserinfoChanged (client_t *cl)
+{
+	char	*val;
+	int		i;
+
+	// call prog code to allow overrides
+	ge->ClientUserinfoChanged (cl->edict, cl->userinfo);
+	
+	// name for C code
+	strncpy (cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name)-1);
+	// mask off high bit
+	for (i=0 ; i<sizeof(cl->name) ; i++)
+		cl->name[i] &= 127;
+
+	// rate command
+	val = Info_ValueForKey (cl->userinfo, "rate");
+	if (strlen(val))
+	{
+		i = atoi(val);
+		cl->rate = i;
+		if (cl->rate < 100)
+			cl->rate = 100;
+		if (cl->rate > 15000)
+			cl->rate = 15000;
+	}
+	else
+		cl->rate = 5000;
+
+	// msg command
+	val = Info_ValueForKey (cl->userinfo, "msg");
+	if (strlen(val))
+	{
+		cl->messagelevel = atoi(val);
+	}
+
+}
+
+
+//============================================================================
+
+/*
+===============
+SV_Init
+
+Only called at quake2.exe startup, not for each game
+===============
+*/
+void SV_Init (void)
+{
+	SV_InitOperatorCommands	();
+
+	rcon_password = Cvar_Get ("rcon_password", "", 0);
+	Cvar_Get ("skill", "1", 0);
+	Cvar_Get ("deathmatch", "0", CVAR_LATCH);
+	Cvar_Get ("coop", "0", CVAR_LATCH);
+	Cvar_Get ("dmflags", va("%i", DF_INSTANT_ITEMS), CVAR_SERVERINFO);
+	Cvar_Get ("fraglimit", "0", CVAR_SERVERINFO);
+	Cvar_Get ("timelimit", "0", CVAR_SERVERINFO);
+	Cvar_Get ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
+	Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO|CVAR_NOSET);;
+	maxclients = Cvar_Get ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
+	hostname = Cvar_Get ("hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE);
+	timeout = Cvar_Get ("timeout", "125", 0);
+	zombietime = Cvar_Get ("zombietime", "2", 0);
+	sv_showclamp = Cvar_Get ("showclamp", "0", 0);
+	sv_paused = Cvar_Get ("paused", "0", 0);
+	sv_timedemo = Cvar_Get ("timedemo", "0", 0);
+	sv_enforcetime = Cvar_Get ("sv_enforcetime", "0", 0);
+	allow_download = Cvar_Get ("allow_download", "0", CVAR_ARCHIVE);
+	allow_download_players  = Cvar_Get ("allow_download_players", "0", CVAR_ARCHIVE);
+	allow_download_models = Cvar_Get ("allow_download_models", "1", CVAR_ARCHIVE);
+	allow_download_sounds = Cvar_Get ("allow_download_sounds", "1", CVAR_ARCHIVE);
+	allow_download_maps	  = Cvar_Get ("allow_download_maps", "1", CVAR_ARCHIVE);
+
+	sv_noreload = Cvar_Get ("sv_noreload", "0", 0);
+
+	sv_airaccelerate = Cvar_Get("sv_airaccelerate", "0", CVAR_LATCH);
+
+	public_server = Cvar_Get ("public", "0", 0);
+
+	sv_reconnect_limit = Cvar_Get ("sv_reconnect_limit", "3", CVAR_ARCHIVE);
+
+	SZ_Init (&net_message, net_message_buffer, sizeof(net_message_buffer));
+}
+
+/*
+==================
+SV_FinalMessage
+
+Used by SV_Shutdown to send a final message to all
+connected clients before the server goes down.  The messages are sent immediately,
+not just stuck on the outgoing message list, because the server is going
+to totally exit after returning from this function.
+==================
+*/
+void SV_FinalMessage (char *message, qboolean reconnect)
+{
+	int			i;
+	client_t	*cl;
+	
+	SZ_Clear (&net_message);
+	MSG_WriteByte (&net_message, svc_print);
+	MSG_WriteByte (&net_message, PRINT_HIGH);
+	MSG_WriteString (&net_message, message);
+
+	if (reconnect)
+		MSG_WriteByte (&net_message, svc_reconnect);
+	else
+		MSG_WriteByte (&net_message, svc_disconnect);
+
+	// send it twice
+	// stagger the packets to crutch operating system limited buffers
+
+	for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
+		if (cl->state >= cs_connected)
+			Netchan_Transmit (&cl->netchan, net_message.cursize
+			, net_message.data);
+
+	for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
+		if (cl->state >= cs_connected)
+			Netchan_Transmit (&cl->netchan, net_message.cursize
+			, net_message.data);
+}
+
+
+
+/*
+================
+SV_Shutdown
+
+Called when each game quits,
+before Sys_Quit or Sys_Error
+================
+*/
+void SV_Shutdown (char *finalmsg, qboolean reconnect)
+{
+	if (svs.clients)
+		SV_FinalMessage (finalmsg, reconnect);
+
+	Master_Shutdown ();
+	SV_ShutdownGameProgs ();
+
+	// free current level
+	if (sv.demofile)
+		fclose (sv.demofile);
+	memset (&sv, 0, sizeof(sv));
+	Com_SetServerState (sv.state);
+
+	// free server static data
+	if (svs.clients)
+		Z_Free (svs.clients);
+	if (svs.client_entities)
+		Z_Free (svs.client_entities);
+	if (svs.demofile)
+		fclose (svs.demofile);
+	memset (&svs, 0, sizeof(svs));
+}
+
--- /dev/null
+++ b/sv_send.c
@@ -1,0 +1,548 @@
+// sv_main.c -- server main program
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+=============================================================================
+
+Com_Printf redirection
+
+=============================================================================
+*/
+
+char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
+
+void SV_FlushRedirect (int sv_redirected, char *outputbuf)
+{
+	if (sv_redirected == RD_PACKET)
+	{
+		Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", outputbuf);
+	}
+	else if (sv_redirected == RD_CLIENT)
+	{
+		MSG_WriteByte (&sv_client->netchan.message, svc_print);
+		MSG_WriteByte (&sv_client->netchan.message, PRINT_HIGH);
+		MSG_WriteString (&sv_client->netchan.message, outputbuf);
+	}
+}
+
+
+/*
+=============================================================================
+
+EVENT MESSAGES
+
+=============================================================================
+*/
+
+
+/*
+=================
+SV_ClientPrintf
+
+Sends text across to be displayed if the level passes
+=================
+*/
+void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...)
+{
+	va_list		argptr;
+	char		string[1024];
+	
+	if (level < cl->messagelevel)
+		return;
+	
+	va_start (argptr,fmt);
+	vsprintf (string, fmt,argptr);
+	va_end (argptr);
+	
+	MSG_WriteByte (&cl->netchan.message, svc_print);
+	MSG_WriteByte (&cl->netchan.message, level);
+	MSG_WriteString (&cl->netchan.message, string);
+}
+
+/*
+=================
+SV_BroadcastPrintf
+
+Sends text to all active clients
+=================
+*/
+void SV_BroadcastPrintf (int level, char *fmt, ...)
+{
+	va_list		argptr;
+	char		string[2048];
+	client_t	*cl;
+	int			i;
+
+	va_start (argptr,fmt);
+	vsprintf (string, fmt,argptr);
+	va_end (argptr);
+	
+	// echo to console
+	if (dedicated->value)
+	{
+		char	copy[1024];
+		int		i;
+		
+		// mask off high bits
+		for (i=0 ; i<1023 && string[i] ; i++)
+			copy[i] = string[i]&127;
+		copy[i] = 0;
+		Com_Printf ("%s", copy);
+	}
+
+	for (i=0, cl = svs.clients ; i<maxclients->value; i++, cl++)
+	{
+		if (level < cl->messagelevel)
+			continue;
+		if (cl->state != cs_spawned)
+			continue;
+		MSG_WriteByte (&cl->netchan.message, svc_print);
+		MSG_WriteByte (&cl->netchan.message, level);
+		MSG_WriteString (&cl->netchan.message, string);
+	}
+}
+
+/*
+=================
+SV_BroadcastCommand
+
+Sends text to all active clients
+=================
+*/
+void SV_BroadcastCommand (char *fmt, ...)
+{
+	va_list		argptr;
+	char		string[1024];
+	
+	if (!sv.state)
+		return;
+	va_start (argptr,fmt);
+	vsprintf (string, fmt,argptr);
+	va_end (argptr);
+
+	MSG_WriteByte (&sv.multicast, svc_stufftext);
+	MSG_WriteString (&sv.multicast, string);
+	SV_Multicast (NULL, MULTICAST_ALL_R);
+}
+
+
+/*
+=================
+SV_Multicast
+
+Sends the contents of sv.multicast to a subset of the clients,
+then clears sv.multicast.
+
+MULTICAST_ALL	same as broadcast (origin can be NULL)
+MULTICAST_PVS	send to clients potentially visible from org
+MULTICAST_PHS	send to clients potentially hearable from org
+=================
+*/
+void SV_Multicast (vec3_t origin, multicast_t to)
+{
+	client_t	*client;
+	byte		*mask;
+	int			leafnum, cluster;
+	int			j;
+	qboolean	reliable;
+	int			area1, area2;
+
+	reliable = false;
+
+	if (to != MULTICAST_ALL_R && to != MULTICAST_ALL)
+	{
+		leafnum = CM_PointLeafnum (origin);
+		area1 = CM_LeafArea (leafnum);
+	}
+	else
+		area1 = 0;	// just to avoid compiler warnings
+
+	// if doing a serverrecord, store everything
+	if (svs.demofile)
+		SZ_Write (&svs.demo_multicast, sv.multicast.data, sv.multicast.cursize);
+	
+	switch (to)
+	{
+	case MULTICAST_ALL_R:
+		reliable = true;	// intentional fallthrough
+	case MULTICAST_ALL:
+		mask = NULL;
+		break;
+
+	case MULTICAST_PHS_R:
+		reliable = true;	// intentional fallthrough
+	case MULTICAST_PHS:
+		leafnum = CM_PointLeafnum (origin);
+		cluster = CM_LeafCluster (leafnum);
+		mask = CM_ClusterPHS (cluster);
+		break;
+
+	case MULTICAST_PVS_R:
+		reliable = true;	// intentional fallthrough
+	case MULTICAST_PVS:
+		leafnum = CM_PointLeafnum (origin);
+		cluster = CM_LeafCluster (leafnum);
+		mask = CM_ClusterPVS (cluster);
+		break;
+
+	default:
+		mask = NULL;
+		Com_Error (ERR_FATAL, "SV_Multicast: bad to:%i", to);
+	}
+
+	// send the data to all relevent clients
+	for (j = 0, client = svs.clients; j < maxclients->value; j++, client++)
+	{
+		if (client->state == cs_free || client->state == cs_zombie)
+			continue;
+		if (client->state != cs_spawned && !reliable)
+			continue;
+
+		if (mask)
+		{
+			leafnum = CM_PointLeafnum (client->edict->s.origin);
+			cluster = CM_LeafCluster (leafnum);
+			area2 = CM_LeafArea (leafnum);
+			if (!CM_AreasConnected (area1, area2))
+				continue;
+			if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
+				continue;
+		}
+
+		if (reliable)
+			SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
+		else
+			SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
+	}
+
+	SZ_Clear (&sv.multicast);
+}
+
+
+/*  
+==================
+SV_StartSound
+
+Each entity can have eight independant sound sources, like voice,
+weapon, feet, etc.
+
+If cahnnel & 8, the sound will be sent to everyone, not just
+things in the PHS.
+
+FIXME: if entity isn't in PHS, they must be forced to be sent or
+have the origin explicitly sent.
+
+Channel 0 is an auto-allocate channel, the others override anything
+already running on that entity/channel pair.
+
+An attenuation of 0 will play full volume everywhere in the level.
+Larger attenuations will drop off.  (max 4 attenuation)
+
+Timeofs can range from 0.0 to 0.1 to cause sounds to be started
+later in the frame than they normally would.
+
+If origin is NULL, the origin is determined from the entity origin
+or the midpoint of the entity box for bmodels.
+==================
+*/  
+void SV_StartSound (vec3_t origin, edict_t *entity, int channel,
+					int soundindex, float volume,
+					float attenuation, float timeofs)
+{       
+	int			sendchan;
+    int			flags;
+    int			i;
+	int			ent;
+	vec3_t		origin_v;
+	qboolean	use_phs;
+
+	if (volume < 0 || volume > 1.0)
+		Com_Error (ERR_FATAL, "SV_StartSound: volume = %f", volume);
+
+	if (attenuation < 0 || attenuation > 4)
+		Com_Error (ERR_FATAL, "SV_StartSound: attenuation = %f", attenuation);
+
+//	if (channel < 0 || channel > 15)
+//		Com_Error (ERR_FATAL, "SV_StartSound: channel = %i", channel);
+
+	if (timeofs < 0 || timeofs > 0.255)
+		Com_Error (ERR_FATAL, "SV_StartSound: timeofs = %f", timeofs);
+
+	ent = NUM_FOR_EDICT(entity);
+
+	if (channel & 8)	// no PHS flag
+	{
+		use_phs = false;
+		channel &= 7;
+	}
+	else
+		use_phs = true;
+
+	sendchan = (ent<<3) | (channel&7);
+
+	flags = 0;
+	if (volume != DEFAULT_SOUND_PACKET_VOLUME)
+		flags |= SND_VOLUME;
+	if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
+		flags |= SND_ATTENUATION;
+
+	// the client doesn't know that bmodels have weird origins
+	// the origin can also be explicitly set
+	if ( (entity->svflags & SVF_NOCLIENT)
+		|| (entity->solid == SOLID_BSP) 
+		|| origin )
+		flags |= SND_POS;
+
+	// always send the entity number for channel overrides
+	flags |= SND_ENT;
+
+	if (timeofs)
+		flags |= SND_OFFSET;
+
+	// use the entity origin unless it is a bmodel or explicitly specified
+	if (!origin)
+	{
+		origin = origin_v;
+		if (entity->solid == SOLID_BSP)
+		{
+			for (i=0 ; i<3 ; i++)
+				origin_v[i] = entity->s.origin[i]+0.5*(entity->mins[i]+entity->maxs[i]);
+		}
+		else
+		{
+			VectorCopy (entity->s.origin, origin_v);
+		}
+	}
+
+	MSG_WriteByte (&sv.multicast, svc_sound);
+	MSG_WriteByte (&sv.multicast, flags);
+	MSG_WriteByte (&sv.multicast, soundindex);
+
+	if (flags & SND_VOLUME)
+		MSG_WriteByte (&sv.multicast, volume*255);
+	if (flags & SND_ATTENUATION)
+		MSG_WriteByte (&sv.multicast, attenuation*64);
+	if (flags & SND_OFFSET)
+		MSG_WriteByte (&sv.multicast, timeofs*1000);
+
+	if (flags & SND_ENT)
+		MSG_WriteShort (&sv.multicast, sendchan);
+
+	if (flags & SND_POS)
+		MSG_WritePos (&sv.multicast, origin);
+
+	// if the sound doesn't attenuate,send it to everyone
+	// (global radio chatter, voiceovers, etc)
+	if (attenuation == ATTN_NONE)
+		use_phs = false;
+
+	if (channel & CHAN_RELIABLE)
+	{
+		if (use_phs)
+			SV_Multicast (origin, MULTICAST_PHS_R);
+		else
+			SV_Multicast (origin, MULTICAST_ALL_R);
+	}
+	else
+	{
+		if (use_phs)
+			SV_Multicast (origin, MULTICAST_PHS);
+		else
+			SV_Multicast (origin, MULTICAST_ALL);
+	}
+}           
+
+
+/*
+===============================================================================
+
+FRAME UPDATES
+
+===============================================================================
+*/
+
+
+
+/*
+=======================
+SV_SendClientDatagram
+=======================
+*/
+qboolean SV_SendClientDatagram (client_t *client)
+{
+	byte		msg_buf[MAX_MSGLEN];
+	sizebuf_t	msg;
+
+	SV_BuildClientFrame (client);
+
+	SZ_Init (&msg, msg_buf, sizeof(msg_buf));
+	msg.allowoverflow = true;
+
+	// send over all the relevant entity_state_t
+	// and the player_state_t
+	SV_WriteFrameToClient (client, &msg);
+
+	// copy the accumulated multicast datagram
+	// for this client out to the message
+	// it is necessary for this to be after the WriteEntities
+	// so that entity references will be current
+	if (client->datagram.overflowed)
+		Com_Printf ("WARNING: datagram overflowed for %s\n", client->name);
+	else
+		SZ_Write (&msg, client->datagram.data, client->datagram.cursize);
+	SZ_Clear (&client->datagram);
+
+	if (msg.overflowed)
+	{	// must have room left for the packet header
+		Com_Printf ("WARNING: msg overflowed for %s\n", client->name);
+		SZ_Clear (&msg);
+	}
+
+	// send the datagram
+	Netchan_Transmit (&client->netchan, msg.cursize, msg.data);
+
+	// record the size for rate estimation
+	client->message_size[sv.framenum % RATE_MESSAGES] = msg.cursize;
+
+	return true;
+}
+
+
+/*
+==================
+SV_DemoCompleted
+==================
+*/
+void SV_DemoCompleted (void)
+{
+	if (sv.demofile)
+	{
+		fclose (sv.demofile);
+		sv.demofile = NULL;
+	}
+	SV_Nextserver ();
+}
+
+
+/*
+=======================
+SV_RateDrop
+
+Returns true if the client is over its current
+bandwidth estimation and should not be sent another packet
+=======================
+*/
+qboolean SV_RateDrop (client_t *c)
+{
+	int		total;
+	int		i;
+
+	// never drop over the loopback
+	if (c->netchan.remote_address.type == NA_LOOPBACK)
+		return false;
+
+	total = 0;
+
+	for (i = 0 ; i < RATE_MESSAGES ; i++)
+	{
+		total += c->message_size[i];
+	}
+
+	if (total > c->rate)
+	{
+		c->surpressCount++;
+		c->message_size[sv.framenum % RATE_MESSAGES] = 0;
+		return true;
+	}
+
+	return false;
+}
+
+/*
+=======================
+SV_SendClientMessages
+=======================
+*/
+void SV_SendClientMessages (void)
+{
+	int			i;
+	client_t	*c;
+	int			msglen;
+	byte		msgbuf[MAX_MSGLEN];
+	int			r;
+
+	msglen = 0;
+
+	// read the next demo message if needed
+	if (sv.state == ss_demo && sv.demofile)
+	{
+		if (sv_paused->value)
+			msglen = 0;
+		else
+		{
+			// get the next message
+			r = fread (&msglen, 4, 1, sv.demofile);
+			if (r != 1)
+			{
+				SV_DemoCompleted ();
+				return;
+			}
+			msglen = LittleLong (msglen);
+			if (msglen == -1)
+			{
+				SV_DemoCompleted ();
+				return;
+			}
+			if (msglen > MAX_MSGLEN)
+				Com_Error (ERR_DROP, "SV_SendClientMessages: msglen > MAX_MSGLEN");
+			r = fread (msgbuf, msglen, 1, sv.demofile);
+			if (r != 1)
+			{
+				SV_DemoCompleted ();
+				return;
+			}
+		}
+	}
+
+	// send a message to each connected client
+	for (i=0, c = svs.clients ; i<maxclients->value; i++, c++)
+	{
+		if (!c->state)
+			continue;
+		// if the reliable message overflowed,
+		// drop the client
+		if (c->netchan.message.overflowed)
+		{
+			SZ_Clear (&c->netchan.message);
+			SZ_Clear (&c->datagram);
+			SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", c->name);
+			SV_DropClient (c);
+		}
+
+		if (sv.state == ss_cinematic 
+			|| sv.state == ss_demo 
+			|| sv.state == ss_pic
+			)
+			Netchan_Transmit (&c->netchan, msglen, msgbuf);
+		else if (c->state == cs_spawned)
+		{
+			// don't overrun bandwidth
+			if (SV_RateDrop (c))
+				continue;
+
+			SV_SendClientDatagram (c);
+		}
+		else
+		{
+	// just update reliable	if needed
+			if (c->netchan.message.cursize	|| curtime - c->netchan.last_sent > 1000 )
+				Netchan_Transmit (&c->netchan, 0, NULL);
+		}
+	}
+}
+
--- /dev/null
+++ b/sv_user.c
@@ -1,0 +1,649 @@
+// sv_user.c -- server code for moving users
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+edict_t	*sv_player;
+
+/*
+============================================================
+
+USER STRINGCMD EXECUTION
+
+sv_client and sv_player will be valid.
+============================================================
+*/
+
+/*
+==================
+SV_BeginDemoServer
+==================
+*/
+void SV_BeginDemoserver (void)
+{
+	char		name[MAX_OSPATH];
+
+	Com_sprintf (name, sizeof(name), "demos/%s", sv.name);
+	FS_FOpenFile (name, &sv.demofile);
+	if (!sv.demofile)
+		Com_Error (ERR_DROP, "Couldn't open %s\n", name);
+}
+
+/*
+================
+SV_New_f
+
+Sends the first message from the server to a connected client.
+This will be sent on the initial connection and upon each server load.
+================
+*/
+void SV_New_f (void)
+{
+	char		*gamedir;
+	int			playernum;
+	edict_t		*ent;
+
+	Com_DPrintf ("New() from %s\n", sv_client->name);
+
+	if (sv_client->state != cs_connected)
+	{
+		Com_Printf ("New not valid -- already spawned\n");
+		return;
+	}
+
+	// demo servers just dump the file message
+	if (sv.state == ss_demo)
+	{
+		SV_BeginDemoserver ();
+		return;
+	}
+
+	//
+	// serverdata needs to go over for all types of servers
+	// to make sure the protocol is right, and to set the gamedir
+	//
+	gamedir = Cvar_VariableString ("gamedir");
+
+	// send the serverdata
+	MSG_WriteByte (&sv_client->netchan.message, svc_serverdata);
+	MSG_WriteLong (&sv_client->netchan.message, PROTOCOL_VERSION);
+	MSG_WriteLong (&sv_client->netchan.message, svs.spawncount);
+	MSG_WriteByte (&sv_client->netchan.message, sv.attractloop);
+	MSG_WriteString (&sv_client->netchan.message, gamedir);
+
+	if (sv.state == ss_cinematic || sv.state == ss_pic)
+		playernum = -1;
+	else
+		playernum = sv_client - svs.clients;
+	MSG_WriteShort (&sv_client->netchan.message, playernum);
+
+	// send full levelname
+	MSG_WriteString (&sv_client->netchan.message, sv.configstrings[CS_NAME]);
+
+	//
+	// game server
+	// 
+	if (sv.state == ss_game)
+	{
+		// set up the entity for the client
+		ent = EDICT_NUM(playernum+1);
+		ent->s.number = playernum+1;
+		sv_client->edict = ent;
+		memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd));
+
+		// begin fetching configstrings
+		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+		MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i 0\n",svs.spawncount) );
+	}
+
+}
+
+/*
+==================
+SV_Configstrings_f
+==================
+*/
+void SV_Configstrings_f (void)
+{
+	int			start;
+
+	Com_DPrintf ("Configstrings() from %s\n", sv_client->name);
+
+	if (sv_client->state != cs_connected)
+	{
+		Com_Printf ("configstrings not valid -- already spawned\n");
+		return;
+	}
+
+	// handle the case of a level changing while a client was connecting
+	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
+	{
+		Com_Printf ("SV_Configstrings_f from different level\n");
+		SV_New_f ();
+		return;
+	}
+	
+	start = atoi(Cmd_Argv(2));
+
+	// write a packet full of data
+
+	while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2 
+		&& start < MAX_CONFIGSTRINGS)
+	{
+		if (sv.configstrings[start][0])
+		{
+			MSG_WriteByte (&sv_client->netchan.message, svc_configstring);
+			MSG_WriteShort (&sv_client->netchan.message, start);
+			MSG_WriteString (&sv_client->netchan.message, sv.configstrings[start]);
+		}
+		start++;
+	}
+
+	// send next command
+
+	if (start == MAX_CONFIGSTRINGS)
+	{
+		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+		MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i 0\n",svs.spawncount) );
+	}
+	else
+	{
+		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+		MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i %i\n",svs.spawncount, start) );
+	}
+}
+
+/*
+==================
+SV_Baselines_f
+==================
+*/
+void SV_Baselines_f (void)
+{
+	int		start;
+	entity_state_t	nullstate;
+	entity_state_t	*base;
+
+	Com_DPrintf ("Baselines() from %s\n", sv_client->name);
+
+	if (sv_client->state != cs_connected)
+	{
+		Com_Printf ("baselines not valid -- already spawned\n");
+		return;
+	}
+	
+	// handle the case of a level changing while a client was connecting
+	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
+	{
+		Com_Printf ("SV_Baselines_f from different level\n");
+		SV_New_f ();
+		return;
+	}
+	
+	start = atoi(Cmd_Argv(2));
+
+	memset (&nullstate, 0, sizeof(nullstate));
+
+	// write a packet full of data
+
+	while ( sv_client->netchan.message.cursize <  MAX_MSGLEN/2
+		&& start < MAX_EDICTS)
+	{
+		base = &sv.baselines[start];
+		if (base->modelindex || base->sound || base->effects)
+		{
+			MSG_WriteByte (&sv_client->netchan.message, svc_spawnbaseline);
+			MSG_WriteDeltaEntity (&nullstate, base, &sv_client->netchan.message, true, true);
+		}
+		start++;
+	}
+
+	// send next command
+
+	if (start == MAX_EDICTS)
+	{
+		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+		MSG_WriteString (&sv_client->netchan.message, va("precache %i\n", svs.spawncount) );
+	}
+	else
+	{
+		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+		MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i %i\n",svs.spawncount, start) );
+	}
+}
+
+/*
+==================
+SV_Begin_f
+==================
+*/
+void SV_Begin_f (void)
+{
+	Com_DPrintf ("Begin() from %s\n", sv_client->name);
+
+	// handle the case of a level changing while a client was connecting
+	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
+	{
+		Com_Printf ("SV_Begin_f from different level\n");
+		SV_New_f ();
+		return;
+	}
+
+	sv_client->state = cs_spawned;
+
+	// call the game begin function
+	ge->ClientBegin (sv_player);
+
+	Cbuf_InsertFromDefer ();
+}
+
+//=============================================================================
+
+/*
+==================
+SV_NextDownload_f
+==================
+*/
+void SV_NextDownload_f (void)
+{
+	int		r;
+	int		percent;
+	int		size;
+
+	if (!sv_client->download)
+		return;
+
+	r = sv_client->downloadsize - sv_client->downloadcount;
+	if (r > 1024)
+		r = 1024;
+
+	MSG_WriteByte (&sv_client->netchan.message, svc_download);
+	MSG_WriteShort (&sv_client->netchan.message, r);
+
+	sv_client->downloadcount += r;
+	size = sv_client->downloadsize;
+	if (!size)
+		size = 1;
+	percent = sv_client->downloadcount*100/size;
+	MSG_WriteByte (&sv_client->netchan.message, percent);
+	SZ_Write (&sv_client->netchan.message,
+		sv_client->download + sv_client->downloadcount - r, r);
+
+	if (sv_client->downloadcount != sv_client->downloadsize)
+		return;
+
+	FS_FreeFile (sv_client->download);
+	sv_client->download = NULL;
+}
+
+/*
+==================
+SV_BeginDownload_f
+==================
+*/
+void SV_BeginDownload_f(void)
+{
+	char	*name;
+	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;
+	extern	int		file_from_pak; // ZOID did file come from pak?
+	int offset = 0;
+
+	name = Cmd_Argv(1);
+
+	if (Cmd_Argc() > 2)
+		offset = atoi(Cmd_Argv(2)); // downloaded offset
+
+	// hacked by zoid to allow more conrol over download
+	// first off, no .. or global allow check
+	if (strstr (name, "..") || !allow_download->value
+		// leading dot is no good
+		|| *name == '.' 
+		// leading slash bad as well, must be in subdir
+		|| *name == '/'
+		// next up, skin check
+		|| (strncmp(name, "players/", 6) == 0 && !allow_download_players->value)
+		// now models
+		|| (strncmp(name, "models/", 6) == 0 && !allow_download_models->value)
+		// now sounds
+		|| (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds->value)
+		// now maps (note special case for maps, must not be in pak)
+		|| (strncmp(name, "maps/", 6) == 0 && !allow_download_maps->value)
+		// MUST be in a subdirectory	
+		|| !strstr (name, "/") )	
+	{	// don't allow anything with .. path
+		MSG_WriteByte (&sv_client->netchan.message, svc_download);
+		MSG_WriteShort (&sv_client->netchan.message, -1);
+		MSG_WriteByte (&sv_client->netchan.message, 0);
+		return;
+	}
+
+
+	if (sv_client->download)
+		FS_FreeFile (sv_client->download);
+
+	sv_client->downloadsize = FS_LoadFile (name, (void **)&sv_client->download);
+	sv_client->downloadcount = offset;
+
+	if (offset > sv_client->downloadsize)
+		sv_client->downloadcount = sv_client->downloadsize;
+
+	if (!sv_client->download
+		// special check for maps, if it came from a pak file, don't allow
+		// download  ZOID
+		|| (strncmp(name, "maps/", 5) == 0 && file_from_pak))
+	{
+		Com_DPrintf ("Couldn't download %s to %s\n", name, sv_client->name);
+		if (sv_client->download) {
+			FS_FreeFile (sv_client->download);
+			sv_client->download = NULL;
+		}
+
+		MSG_WriteByte (&sv_client->netchan.message, svc_download);
+		MSG_WriteShort (&sv_client->netchan.message, -1);
+		MSG_WriteByte (&sv_client->netchan.message, 0);
+		return;
+	}
+
+	SV_NextDownload_f ();
+	Com_DPrintf ("Downloading %s to %s\n", name, sv_client->name);
+}
+
+
+
+//============================================================================
+
+
+/*
+=================
+SV_Disconnect_f
+
+The client is going to disconnect, so remove the connection immediately
+=================
+*/
+void SV_Disconnect_f (void)
+{
+//	SV_EndRedirect ();
+	SV_DropClient (sv_client);	
+}
+
+
+/*
+==================
+SV_ShowServerinfo_f
+
+Dumps the serverinfo info string
+==================
+*/
+void SV_ShowServerinfo_f (void)
+{
+	Info_Print (Cvar_Serverinfo());
+}
+
+
+void SV_Nextserver (void)
+{
+	char	*v;
+
+	//ZOID, ss_pic can be nextserver'd in coop mode
+	if (sv.state == ss_game || (sv.state == ss_pic && !Cvar_VariableValue("coop")))
+		return;		// can't nextserver while playing a normal game
+
+	svs.spawncount++;	// make sure another doesn't sneak in
+	v = Cvar_VariableString ("nextserver");
+	if (!v[0])
+		Cbuf_AddText ("killserver\n");
+	else
+	{
+		Cbuf_AddText (v);
+		Cbuf_AddText ("\n");
+	}
+	Cvar_Set ("nextserver","");
+}
+
+/*
+==================
+SV_Nextserver_f
+
+A cinematic has completed or been aborted by a client, so move
+to the next server,
+==================
+*/
+void SV_Nextserver_f (void)
+{
+	if ( atoi(Cmd_Argv(1)) != svs.spawncount ) {
+		Com_DPrintf ("Nextserver() from wrong level, from %s\n", sv_client->name);
+		return;		// leftover from last server
+	}
+
+	Com_DPrintf ("Nextserver() from %s\n", sv_client->name);
+
+	SV_Nextserver ();
+}
+
+typedef struct
+{
+	char	*name;
+	void	(*func) (void);
+} ucmd_t;
+
+ucmd_t ucmds[] =
+{
+	// auto issued
+	{"new", SV_New_f},
+	{"configstrings", SV_Configstrings_f},
+	{"baselines", SV_Baselines_f},
+	{"begin", SV_Begin_f},
+
+	{"nextserver", SV_Nextserver_f},
+
+	{"disconnect", SV_Disconnect_f},
+
+	// issued by hand at client consoles	
+	{"info", SV_ShowServerinfo_f},
+
+	{"download", SV_BeginDownload_f},
+	{"nextdl", SV_NextDownload_f},
+
+	{NULL, NULL}
+};
+
+/*
+==================
+SV_ExecuteUserCommand
+==================
+*/
+void SV_ExecuteUserCommand (char *s)
+{
+	ucmd_t	*u;
+	
+	Cmd_TokenizeString (s, true);
+	sv_player = sv_client->edict;
+
+//	SV_BeginRedirect (RD_CLIENT);
+
+	for (u=ucmds ; u->name ; u++)
+		if (!strcmp (Cmd_Argv(0), u->name) )
+		{
+			u->func ();
+			break;
+		}
+
+	if (!u->name && sv.state == ss_game)
+		ge->ClientCommand (sv_player);
+
+//	SV_EndRedirect ();
+}
+
+/*
+===========================================================================
+
+USER CMD EXECUTION
+
+===========================================================================
+*/
+
+
+
+void SV_ClientThink (client_t *cl, usercmd_t *cmd)
+
+{
+	cl->commandMsec -= cmd->msec;
+
+	if (cl->commandMsec < 0 && sv_enforcetime->value )
+	{
+		Com_DPrintf ("commandMsec underflow from %s\n", cl->name);
+		return;
+	}
+
+	ge->ClientThink (cl->edict, cmd);
+}
+
+
+
+#define	MAX_STRINGCMDS	8
+/*
+===================
+SV_ExecuteClientMessage
+
+The current net_message is parsed for the given client
+===================
+*/
+void SV_ExecuteClientMessage (client_t *cl)
+{
+	int		c;
+	char	*s;
+
+	usercmd_t	nullcmd;
+	usercmd_t	oldest, oldcmd, newcmd;
+	int		net_drop;
+	int		stringCmdCount;
+	int		checksum, calculatedChecksum;
+	int		checksumIndex;
+	qboolean	move_issued;
+	int		lastframe;
+
+	sv_client = cl;
+	sv_player = sv_client->edict;
+
+	// only allow one move command
+	move_issued = false;
+	stringCmdCount = 0;
+
+	while (1)
+	{
+		if (net_message.readcount > net_message.cursize)
+		{
+			Com_Printf ("SV_ReadClientMessage: badread\n");
+			SV_DropClient (cl);
+			return;
+		}	
+
+		c = MSG_ReadByte (&net_message);
+		if (c == -1)
+			break;
+				
+		switch (c)
+		{
+		default:
+			Com_Printf ("SV_ReadClientMessage: unknown command char\n");
+			SV_DropClient (cl);
+			return;
+						
+		case clc_nop:
+			break;
+
+		case clc_userinfo:
+			strncpy (cl->userinfo, MSG_ReadString (&net_message), sizeof(cl->userinfo)-1);
+			SV_UserinfoChanged (cl);
+			break;
+
+		case clc_move:
+			if (move_issued)
+				return;		// someone is trying to cheat...
+
+			move_issued = true;
+			checksumIndex = net_message.readcount;
+			checksum = MSG_ReadByte (&net_message);
+			lastframe = MSG_ReadLong (&net_message);
+			if (lastframe != cl->lastframe) {
+				cl->lastframe = lastframe;
+				if (cl->lastframe > 0) {
+					cl->frame_latency[cl->lastframe&(LATENCY_COUNTS-1)] = 
+						svs.realtime - cl->frames[cl->lastframe & UPDATE_MASK].senttime;
+				}
+			}
+
+			memset (&nullcmd, 0, sizeof(nullcmd));
+			MSG_ReadDeltaUsercmd (&net_message, &nullcmd, &oldest);
+			MSG_ReadDeltaUsercmd (&net_message, &oldest, &oldcmd);
+			MSG_ReadDeltaUsercmd (&net_message, &oldcmd, &newcmd);
+
+			if ( cl->state != cs_spawned )
+			{
+				cl->lastframe = -1;
+				break;
+			}
+
+			// if the checksum fails, ignore the rest of the packet
+			calculatedChecksum = COM_BlockSequenceCRCByte (
+				net_message.data + checksumIndex + 1,
+				net_message.readcount - checksumIndex - 1,
+				cl->netchan.incoming_sequence);
+
+			if (calculatedChecksum != checksum)
+			{
+				Com_DPrintf ("Failed command checksum for %s (%d != %d)/%d\n", 
+					cl->name, calculatedChecksum, checksum, 
+					cl->netchan.incoming_sequence);
+				return;
+			}
+
+			if (!sv_paused->value)
+			{
+				net_drop = cl->netchan.dropped;
+				if (net_drop < 20)
+				{
+
+//if (net_drop > 2)
+
+//	Com_Printf ("drop %i\n", net_drop);
+					while (net_drop > 2)
+					{
+						SV_ClientThink (cl, &cl->lastcmd);
+
+						net_drop--;
+					}
+					if (net_drop > 1)
+						SV_ClientThink (cl, &oldest);
+
+					if (net_drop > 0)
+						SV_ClientThink (cl, &oldcmd);
+
+				}
+				SV_ClientThink (cl, &newcmd);
+			}
+
+			cl->lastcmd = newcmd;
+			break;
+
+		case clc_stringcmd:	
+			s = MSG_ReadString (&net_message);
+
+			// malicious users may try using too many string commands
+			if (++stringCmdCount < MAX_STRINGCMDS)
+				SV_ExecuteUserCommand (s);
+
+			if (cl->state == cs_zombie)
+				return;	// disconnect command
+			break;
+		}
+	}
+}
+
--- /dev/null
+++ b/sv_world.c
@@ -1,0 +1,591 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef struct moveclip_t moveclip_t;
+typedef struct areanode_t areanode_t;
+
+/* ENTITY AREA CHECKING: high level object sorting to reduce interaction tests
+ * FIXME: this use of "area" is different from the bsp file use */
+
+// (type *)STRUCT_FROM_LINK(link_t *link, type, member)
+// ent = STRUCT_FROM_LINK(link,entity_t,order)
+// FIXME: remove this mess!
+#define	STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (uintptr)&(((t *)0)->m)))
+#define	EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
+
+enum{
+	AREA_DEPTH = 4,
+	AREA_NODES = 32,
+	MAX_TOTAL_ENT_LEAFS = 128
+};
+struct areanode_t{
+	int axis;	// -1 = leaf node
+	float dist;
+	areanode_t *children[2];
+	link_t trigger_edicts;
+	link_t solid_edicts;
+};
+areanode_t sv_areanodes[AREA_NODES];
+int sv_numareanodes;
+
+float *area_mins;
+float *area_maxs;
+edict_t **area_list;
+int area_count;
+int area_maxcount;
+int area_type;
+
+struct moveclip_t{
+	vec3_t boxmins;	// enclose the test object along entire move
+	vec3_t boxmaxs;
+	float *mins;	// size of the moving object
+	float *maxs;
+	vec3_t mins2;	// size when clipping against monsters
+	vec3_t maxs2;
+	float *start;
+	float *end;
+	trace_t trace;
+	edict_t *passedict;
+	int contentmask;
+};
+
+int	SV_HullForEntity(edict_t *);
+
+
+/* used for new headnodes */
+void
+ClearLink(link_t *l)
+{
+	l->prev = l->next = l;
+}
+
+void
+RemoveLink(link_t *l)
+{
+	l->next->prev = l->prev;
+	l->prev->next = l->next;
+}
+
+void
+InsertLinkBefore(link_t *l, link_t *before)
+{
+	l->next = before;
+	l->prev = before->prev;
+	l->prev->next = l;
+	l->next->prev = l;
+}
+
+/* builds a uniformly subdivided tree for the given world size */
+areanode_t *
+SV_CreateAreaNode(int depth, vec3_t mins, vec3_t maxs)
+{
+	areanode_t	*anode;
+	vec3_t		size;
+	vec3_t		mins1, maxs1, mins2, maxs2;
+
+	anode = &sv_areanodes[sv_numareanodes];
+	sv_numareanodes++;
+
+	ClearLink (&anode->trigger_edicts);
+	ClearLink (&anode->solid_edicts);
+	
+	if (depth == AREA_DEPTH)
+	{
+		anode->axis = -1;
+		anode->children[0] = anode->children[1] = NULL;
+		return anode;
+	}
+	
+	VectorSubtract (maxs, mins, size);
+	if (size[0] > size[1])
+		anode->axis = 0;
+	else
+		anode->axis = 1;
+	
+	anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
+	VectorCopy (mins, mins1);	
+	VectorCopy (mins, mins2);	
+	VectorCopy (maxs, maxs1);	
+	VectorCopy (maxs, maxs2);	
+	
+	maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
+	
+	anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);
+	anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1);
+
+	return anode;
+}
+
+/* called after the world model has been loaded, before linking any entities */
+void
+SV_ClearWorld(void)
+{
+	memset(sv_areanodes, 0, sizeof sv_areanodes);
+	sv_numareanodes = 0;
+	SV_CreateAreaNode(0, sv.models[1]->mins, sv.models[1]->maxs);
+}
+
+/* call before removing an entity, and before trying to move one, so it doesn't
+ * clip against itself */
+void
+SV_UnlinkEdict(edict_t *p)
+{
+	if(!p->area.prev)
+		return;	// not linked in anywhere
+	RemoveLink(&p->area);
+	p->area.prev = p->area.next = nil;
+}
+
+/* needs to be called any time an entity changes origin, mins, maxs, or solid.
+ * automatically unlinks if needed. sets ent->v.absmin and ent->v.absmax. sets
+ * ent->leafnums[] for pvs determination even if the entity is not solid */
+void
+SV_LinkEdict(edict_t *ent)
+{
+	areanode_t	*node;
+	int			leafs[MAX_TOTAL_ENT_LEAFS];
+	int			clusters[MAX_TOTAL_ENT_LEAFS];
+	int			num_leafs;
+	int			i, j, k;
+	int			area;
+	int			topnode;
+
+	if (ent->area.prev)
+		SV_UnlinkEdict (ent);	// unlink from old position
+		
+	if (ent == ge->edicts)
+		return;		// don't add the world
+
+	if (!ent->inuse)
+		return;
+
+	// set the size
+	VectorSubtract (ent->maxs, ent->mins, ent->size);
+	
+	// encode the size into the entity_state for client prediction
+	if (ent->solid == SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER))
+	{	// assume that x/y are equal and symetric
+		i = ent->maxs[0]/8;
+		if (i<1)
+			i = 1;
+		if (i>31)
+			i = 31;
+
+		// z is not symetric
+		j = (-ent->mins[2])/8;
+		if (j<1)
+			j = 1;
+		if (j>31)
+			j = 31;
+
+		// and z maxs can be negative...
+		k = (ent->maxs[2]+32)/8;
+		if (k<1)
+			k = 1;
+		if (k>63)
+			k = 63;
+
+		ent->s.solid = (k<<10) | (j<<5) | i;
+	}
+	else if (ent->solid == SOLID_BSP)
+	{
+		ent->s.solid = 31;		// a solid_bbox will never create this value
+	}
+	else
+		ent->s.solid = 0;
+
+	// set the abs box
+	if (ent->solid == SOLID_BSP && 
+	(ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) )
+	{	// expand for rotation
+		float		max, v;
+		int			i;
+
+		max = 0;
+		for (i=0 ; i<3 ; i++)
+		{
+			v =fabs( ent->mins[i]);
+			if (v > max)
+				max = v;
+			v =fabs( ent->maxs[i]);
+			if (v > max)
+				max = v;
+		}
+		for (i=0 ; i<3 ; i++)
+		{
+			ent->absmin[i] = ent->s.origin[i] - max;
+			ent->absmax[i] = ent->s.origin[i] + max;
+		}
+	}
+	else
+	{	// normal
+		VectorAdd (ent->s.origin, ent->mins, ent->absmin);	
+		VectorAdd (ent->s.origin, ent->maxs, ent->absmax);
+	}
+
+	// because movement is clipped an epsilon away from an actual edge,
+	// we must fully check even when bounding boxes don't quite touch
+	ent->absmin[0] -= 1;
+	ent->absmin[1] -= 1;
+	ent->absmin[2] -= 1;
+	ent->absmax[0] += 1;
+	ent->absmax[1] += 1;
+	ent->absmax[2] += 1;
+
+// link to PVS leafs
+	ent->num_clusters = 0;
+	ent->areanum = 0;
+	ent->areanum2 = 0;
+
+	//get all leafs, including solids
+	num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax,
+		leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
+
+	// set areas
+	for (i=0 ; i<num_leafs ; i++)
+	{
+		clusters[i] = CM_LeafCluster (leafs[i]);
+		area = CM_LeafArea (leafs[i]);
+		if (area)
+		{	// doors may legally straggle two areas,
+			// but nothing should evern need more than that
+			if (ent->areanum && ent->areanum != area)
+			{
+				if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading)
+					Com_DPrintf ("Object touching 3 areas at %f %f %f\n",
+					ent->absmin[0], ent->absmin[1], ent->absmin[2]);
+				ent->areanum2 = area;
+			}
+			else
+				ent->areanum = area;
+		}
+	}
+
+	if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
+	{	// assume we missed some leafs, and mark by headnode
+		ent->num_clusters = -1;
+		ent->headnode = topnode;
+	}
+	else
+	{
+		ent->num_clusters = 0;
+		for (i=0 ; i<num_leafs ; i++)
+		{
+			if (clusters[i] == -1)
+				continue;		// not a visible leaf
+			for (j=0 ; j<i ; j++)
+				if (clusters[j] == clusters[i])
+					break;
+			if (j == i)
+			{
+				if (ent->num_clusters == MAX_ENT_CLUSTERS)
+				{	// assume we missed some leafs, and mark by headnode
+					ent->num_clusters = -1;
+					ent->headnode = topnode;
+					break;
+				}
+
+				ent->clusternums[ent->num_clusters++] = clusters[i];
+			}
+		}
+	}
+
+	// if first time, make sure old_origin is valid
+	if (!ent->linkcount)
+	{
+		VectorCopy (ent->s.origin, ent->s.old_origin);
+	}
+	ent->linkcount++;
+
+	if (ent->solid == SOLID_NOT)
+		return;
+
+// find the first node that the ent's box crosses
+	node = sv_areanodes;
+	while (1)
+	{
+		if (node->axis == -1)
+			break;
+		if (ent->absmin[node->axis] > node->dist)
+			node = node->children[0];
+		else if (ent->absmax[node->axis] < node->dist)
+			node = node->children[1];
+		else
+			break;		// crosses the node
+	}
+	
+	// link it in	
+	if (ent->solid == SOLID_TRIGGER)
+		InsertLinkBefore (&ent->area, &node->trigger_edicts);
+	else
+		InsertLinkBefore (&ent->area, &node->solid_edicts);
+
+}
+
+void
+SV_AreaEdicts_r(areanode_t *node)
+{
+	link_t		*l, *next, *start;
+	edict_t		*check;
+
+	// touch linked edicts
+	if (area_type == AREA_SOLID)
+		start = &node->solid_edicts;
+	else
+		start = &node->trigger_edicts;
+
+	for (l=start->next  ; l != start ; l = next)
+	{
+		next = l->next;
+		check = EDICT_FROM_AREA(l);
+
+		if (check->solid == SOLID_NOT)
+			continue;		// deactivated
+		if (check->absmin[0] > area_maxs[0]
+		|| check->absmin[1] > area_maxs[1]
+		|| check->absmin[2] > area_maxs[2]
+		|| check->absmax[0] < area_mins[0]
+		|| check->absmax[1] < area_mins[1]
+		|| check->absmax[2] < area_mins[2])
+			continue;		// not touching
+
+		if (area_count == area_maxcount)
+		{
+			Com_Printf ("SV_AreaEdicts: MAXCOUNT\n");
+			return;
+		}
+
+		area_list[area_count] = check;
+		area_count++;
+	}
+	
+	if (node->axis == -1)
+		return;		// terminal node
+
+	// recurse down both sides
+	if ( area_maxs[node->axis] > node->dist )
+		SV_AreaEdicts_r ( node->children[0] );
+	if ( area_mins[node->axis] < node->dist )
+		SV_AreaEdicts_r ( node->children[1] );
+}
+
+/* fills in a table of edict pointers with edicts that have bounding boxes that
+ * intersect the given area. it is possible for a non-axial bmodel to be
+ * returned that doesn't actually intersect the area on an exact test. returns 
+ * the number of pointers filled in.
+ * ??? does this always return the world? */
+int
+SV_AreaEdicts(vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype)
+{
+	area_mins = mins;
+	area_maxs = maxs;
+	area_list = list;
+	area_count = 0;
+	area_maxcount = maxcount;
+	area_type = areatype;
+
+	SV_AreaEdicts_r (sv_areanodes);
+
+	return area_count;
+}
+
+/* returns the CONTENTS_* value from the world at the given point. Quake 2
+ * extends this to also check entities, to allow moving liquids */
+int
+SV_PointContents(vec3_t p)
+{
+	edict_t		*touch[MAX_EDICTS], *hit;
+	int			i, num;
+	int			contents, c2;
+	int			headnode;
+
+	// get base contents from world
+	contents = CM_PointContents (p, sv.models[1]->headnode);
+
+	// or in contents from all the other entities
+	num = SV_AreaEdicts (p, p, touch, MAX_EDICTS, AREA_SOLID);
+
+	for (i=0 ; i<num ; i++)
+	{
+		hit = touch[i];
+
+		// might intersect, so do an exact clip
+		headnode = SV_HullForEntity (hit);
+
+		/* unused
+		float *angles;
+		angles = hit->s.angles;
+		if (hit->solid != SOLID_BSP)
+			angles = vec3_origin;	// boxes don't rotate
+		*/
+
+		c2 = CM_TransformedPointContents (p, headnode, hit->s.origin, hit->s.angles);
+
+		contents |= c2;
+	}
+
+	return contents;
+}
+
+/* returns a headnode that can be used for testing or clipping an object of
+ * mins/maxs size. offset is filled in to contain the adjustment that must be
+ * added to the testing object's origin to get a point to use with the returned
+ * hull. */
+int
+SV_HullForEntity(edict_t *ent)
+{
+	cmodel_t	*model;
+
+// decide which clipping hull to use, based on the size
+	if (ent->solid == SOLID_BSP)
+	{	// explicit hulls in the BSP model
+		model = sv.models[ ent->s.modelindex ];
+
+		if (!model)
+			Com_Error (ERR_FATAL, "MOVETYPE_PUSH with a non bsp model");
+
+		return model->headnode;
+	}
+
+	// create a temp hull from bounding box sizes
+
+	return CM_HeadnodeForBox (ent->mins, ent->maxs);
+}
+
+void
+SV_ClipMoveToEntities(moveclip_t *clip)
+{
+	int			i, num;
+	edict_t		*touchlist[MAX_EDICTS], *touch;
+	trace_t		trace;
+	int			headnode;
+	float		*angles;
+
+	num = SV_AreaEdicts (clip->boxmins, clip->boxmaxs, touchlist
+		, MAX_EDICTS, AREA_SOLID);
+
+	// be careful, it is possible to have an entity in this
+	// list removed before we get to it (killtriggered)
+	for (i=0 ; i<num ; i++)
+	{
+		touch = touchlist[i];
+		if (touch->solid == SOLID_NOT)
+			continue;
+		if (touch == clip->passedict)
+			continue;
+		if (clip->trace.allsolid)
+			return;
+		if (clip->passedict)
+		{
+		 	if (touch->owner == clip->passedict)
+				continue;	// don't clip against own missiles
+			if (clip->passedict->owner == touch)
+				continue;	// don't clip against owner
+		}
+
+		if ( !(clip->contentmask & CONTENTS_DEADMONSTER)
+		&& (touch->svflags & SVF_DEADMONSTER) )
+				continue;
+
+		// might intersect, so do an exact clip
+		headnode = SV_HullForEntity (touch);
+		angles = touch->s.angles;
+		if (touch->solid != SOLID_BSP)
+			angles = vec3_origin;	// boxes don't rotate
+
+		if (touch->svflags & SVF_MONSTER)
+			trace = CM_TransformedBoxTrace (clip->start, clip->end,
+				clip->mins2, clip->maxs2, headnode, clip->contentmask,
+				touch->s.origin, angles);
+		else
+			trace = CM_TransformedBoxTrace (clip->start, clip->end,
+				clip->mins, clip->maxs, headnode,  clip->contentmask,
+				touch->s.origin, angles);
+
+		if (trace.allsolid || trace.startsolid ||
+		trace.fraction < clip->trace.fraction)
+		{
+			trace.ent = touch;
+		 	if (clip->trace.startsolid)
+			{
+				clip->trace = trace;
+				clip->trace.startsolid = true;
+			}
+			else
+				clip->trace = trace;
+		}
+		else if (trace.startsolid)
+			clip->trace.startsolid = true;
+	}
+}
+
+void
+SV_TraceBounds(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
+{
+/*
+	// debug to test against everything
+	boxmins[0] = boxmins[1] = boxmins[2] = -9999;
+	boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999;
+*/
+	int		i;
+	
+	for (i=0 ; i<3 ; i++)
+	{
+		if (end[i] > start[i])
+		{
+			boxmins[i] = start[i] + mins[i] - 1;
+			boxmaxs[i] = end[i] + maxs[i] + 1;
+		}
+		else
+		{
+			boxmins[i] = end[i] + mins[i] - 1;
+			boxmaxs[i] = start[i] + maxs[i] + 1;
+		}
+	}
+}
+
+/* moves the given mins/maxs volume through the world from start to end.
+ * passedict and edicts owned by passedict are explicitly not checked. mins and
+ * maxs are relative.
+ * if the entire move stays in a solid volume, trace.allsolid will be set,
+ * trace.startsolid will be set, and trace.fraction will be 0. if the starting
+ * point is in a solid, it will be allowed to move out to an open area */
+trace_t
+SV_Trace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask)
+{
+	moveclip_t	clip;
+
+	if (!mins)
+		mins = vec3_origin;
+	if (!maxs)
+		maxs = vec3_origin;
+
+	memset ( &clip, 0, sizeof ( moveclip_t ) );
+
+	// clip to world
+	clip.trace = CM_BoxTrace (start, end, mins, maxs, 0, contentmask);
+	clip.trace.ent = ge->edicts;
+	if (clip.trace.fraction == 0)
+		return clip.trace;		// blocked by the world
+
+	clip.contentmask = contentmask;
+	clip.start = start;
+	clip.end = end;
+	clip.mins = mins;
+	clip.maxs = maxs;
+	clip.passedict = passedict;
+
+	VectorCopy (mins, clip.mins2);
+	VectorCopy (maxs, clip.maxs2);
+	
+	// create the bounding box of the entire move
+	SV_TraceBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
+
+	// clip to other solid entities
+	SV_ClipMoveToEntities ( &clip );
+
+	return clip.trace;
+}
--- /dev/null
+++ b/sys.c
@@ -1,0 +1,453 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.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;
+	}
+}
--- /dev/null
+++ b/udp.c
@@ -1,0 +1,553 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <thread.h>
+#include <bio.h>
+#include <ndb.h>
+#include <ip.h>
+#include "dat.h"
+#include "fns.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);
+}
--- /dev/null
+++ b/vid.c
@@ -1,0 +1,251 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "dat.h"
+#include "fns.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;
+	vidref_val = VIDREF_SOFT;
+	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/vmenu.c
@@ -1,0 +1,138 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+extern void M_PopMenu(void);
+
+static menuframework_t vmenu;
+static menuslider_t ssizeslide, gammaslide;
+static menulist_t fullscrbox;
+static menuaction_t applyaction, defaultsaction;
+
+
+void
+vmssize(void *s)
+{
+	Cvar_SetValue("viewsize", ((menuslider_t *)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_t *)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;
+}