ref: 61e35a208c16f339e39e5b4d6244e12ddcc980f7
parent: 4cae69d325329e3c1d7bf043eb52d610369a26bb
author: Konstantinn Bonnet <qu7uux@gmail.com>
date: Sun Jun 28 12:02:21 EDT 2015
more mostly pointless file shuffling - merge headers (except adivtab.h, anorms.h, rand1k.h) → dat.h, fns.h and game/game.h. game.h remains for mod shit - remove const qualifiers (mostly from menu stuff) - put TARG in mk.$game for setting binary's name for each mod - plan9-ish C style for some files
--- /dev/null
+++ b/adivtab.h
@@ -1,0 +1,1058 @@
+// table of quotients and remainders for [-15...16] / [-15...16]
+
+// numerator = -15
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{1, -7},
+{2, -1},
+{2, -3},
+{3, 0},
+{3, -3},
+{5, 0},
+{7, -1},
+{15, 0},
+{0, 0},
+{-15, 0},
+{-8, 1},
+{-5, 0},
+{-4, 1},
+{-3, 0},
+{-3, 3},
+{-3, 6},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-2, 11},
+{-2, 13},
+{-1, 0},
+{-1, 1},
+// numerator = -14
+{0, -14},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{2, 0},
+{2, -2},
+{2, -4},
+{3, -2},
+{4, -2},
+{7, 0},
+{14, 0},
+{0, 0},
+{-14, 0},
+{-7, 0},
+{-5, 1},
+{-4, 2},
+{-3, 1},
+{-3, 4},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-2, 10},
+{-2, 12},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+// numerator = -13
+{0, -13},
+{0, -13},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{2, -1},
+{2, -3},
+{3, -1},
+{4, -1},
+{6, -1},
+{13, 0},
+{0, 0},
+{-13, 0},
+{-7, 1},
+{-5, 2},
+{-4, 3},
+{-3, 2},
+{-3, 5},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-2, 11},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+// numerator = -12
+{0, -12},
+{0, -12},
+{0, -12},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{2, 0},
+{2, -2},
+{3, 0},
+{4, 0},
+{6, 0},
+{12, 0},
+{0, 0},
+{-12, 0},
+{-6, 0},
+{-4, 0},
+{-3, 0},
+{-3, 3},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-2, 10},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+// numerator = -11
+{0, -11},
+{0, -11},
+{0, -11},
+{0, -11},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{2, -1},
+{2, -3},
+{3, -2},
+{5, -1},
+{11, 0},
+{0, 0},
+{-11, 0},
+{-6, 1},
+{-4, 1},
+{-3, 1},
+{-3, 4},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+// numerator = -10
+{0, -10},
+{0, -10},
+{0, -10},
+{0, -10},
+{0, -10},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{2, 0},
+{2, -2},
+{3, -1},
+{5, 0},
+{10, 0},
+{0, 0},
+{-10, 0},
+{-5, 0},
+{-4, 2},
+{-3, 2},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+// numerator = -9
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{2, -1},
+{3, 0},
+{4, -1},
+{9, 0},
+{0, 0},
+{-9, 0},
+{-5, 1},
+{-3, 0},
+{-3, 3},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+// numerator = -8
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{2, 0},
+{2, -2},
+{4, 0},
+{8, 0},
+{0, 0},
+{-8, 0},
+{-4, 0},
+{-3, 1},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+// numerator = -7
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{2, -1},
+{3, -1},
+{7, 0},
+{0, 0},
+{-7, 0},
+{-4, 1},
+{-3, 2},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+// numerator = -6
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{1, 0},
+{1, -1},
+{1, -2},
+{2, 0},
+{3, 0},
+{6, 0},
+{0, 0},
+{-6, 0},
+{-3, 0},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+// numerator = -5
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{1, 0},
+{1, -1},
+{1, -2},
+{2, -1},
+{5, 0},
+{0, 0},
+{-5, 0},
+{-3, 1},
+{-2, 1},
+{-2, 3},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+// numerator = -4
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{1, 0},
+{1, -1},
+{2, 0},
+{4, 0},
+{0, 0},
+{-4, 0},
+{-2, 0},
+{-2, 2},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+// numerator = -3
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{1, 0},
+{1, -1},
+{3, 0},
+{0, 0},
+{-3, 0},
+{-2, 1},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+// numerator = -2
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{1, 0},
+{2, 0},
+{0, 0},
+{-2, 0},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+{-1, 14},
+// numerator = -1
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{1, 0},
+{0, 0},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+{-1, 14},
+{-1, 15},
+// numerator = 0
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+// numerator = 1
+{-1, -14},
+{-1, -13},
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{0, 0},
+{1, 0},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+// numerator = 2
+{-1, -13},
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, 0},
+{0, 0},
+{2, 0},
+{1, 0},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+// numerator = 3
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -1},
+{-3, 0},
+{0, 0},
+{3, 0},
+{1, 1},
+{1, 0},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+// numerator = 4
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -2},
+{-2, 0},
+{-4, 0},
+{0, 0},
+{4, 0},
+{2, 0},
+{1, 1},
+{1, 0},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+// numerator = 5
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -3},
+{-2, -1},
+{-3, -1},
+{-5, 0},
+{0, 0},
+{5, 0},
+{2, 1},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+// numerator = 6
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, 0},
+{-6, 0},
+{0, 0},
+{6, 0},
+{3, 0},
+{2, 0},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+// numerator = 7
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -2},
+{-4, -1},
+{-7, 0},
+{0, 0},
+{7, 0},
+{3, 1},
+{2, 1},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+// numerator = 8
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -1},
+{-4, 0},
+{-8, 0},
+{0, 0},
+{8, 0},
+{4, 0},
+{2, 2},
+{2, 0},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+// numerator = 9
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -3},
+{-3, 0},
+{-5, -1},
+{-9, 0},
+{0, 0},
+{9, 0},
+{4, 1},
+{3, 0},
+{2, 1},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+// numerator = 10
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -2},
+{-4, -2},
+{-5, 0},
+{-10, 0},
+{0, 0},
+{10, 0},
+{5, 0},
+{3, 1},
+{2, 2},
+{2, 0},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+// numerator = 11
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -4},
+{-3, -1},
+{-4, -1},
+{-6, -1},
+{-11, 0},
+{0, 0},
+{11, 0},
+{5, 1},
+{3, 2},
+{2, 3},
+{2, 1},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 11},
+{0, 11},
+{0, 11},
+{0, 11},
+{0, 11},
+// numerator = 12
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -3},
+{-3, 0},
+{-4, 0},
+{-6, 0},
+{-12, 0},
+{0, 0},
+{12, 0},
+{6, 0},
+{4, 0},
+{3, 0},
+{2, 2},
+{2, 0},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 12},
+{0, 12},
+{0, 12},
+{0, 12},
+// numerator = 13
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -11},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -5},
+{-3, -2},
+{-4, -3},
+{-5, -2},
+{-7, -1},
+{-13, 0},
+{0, 0},
+{13, 0},
+{6, 1},
+{4, 1},
+{3, 1},
+{2, 3},
+{2, 1},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 13},
+{0, 13},
+{0, 13},
+// numerator = 14
+{-1, -1},
+{-1, 0},
+{-2, -12},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -4},
+{-3, -1},
+{-4, -2},
+{-5, -1},
+{-7, 0},
+{-14, 0},
+{0, 0},
+{14, 0},
+{7, 0},
+{4, 2},
+{3, 2},
+{2, 4},
+{2, 2},
+{2, 0},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 14},
+{0, 14},
+// numerator = 15
+{-1, 0},
+{-2, -13},
+{-2, -11},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -6},
+{-3, -3},
+{-3, 0},
+{-4, -1},
+{-5, 0},
+{-8, -1},
+{-15, 0},
+{0, 0},
+{15, 0},
+{7, 1},
+{5, 0},
+{3, 3},
+{3, 0},
+{2, 3},
+{2, 1},
+{1, 7},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 15},
+// numerator = 16
+{-2, -14},
+{-2, -12},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -5},
+{-3, -2},
+{-4, -4},
+{-4, 0},
+{-6, -2},
+{-8, 0},
+{-16, 0},
+{0, 0},
+{16, 0},
+{8, 0},
+{5, 1},
+{4, 0},
+{3, 1},
+{2, 4},
+{2, 2},
+{2, 0},
+{1, 7},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
--- /dev/null
+++ b/cd.c
@@ -1,0 +1,415 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+qboolean cdValid = false;
+qboolean playing = false;
+qboolean wasPlaying = false;
+qboolean initialized = false;
+qboolean enabled = true;
+qboolean playLooping = false;
+float cdvolume;
+byte remap[100];
+byte playTrack;
+byte maxTrack;
+int cdfile = -1;
+
+cvar_t *cd_volume;
+cvar_t *cd_nocd;
+cvar_t *cd_dev;
+
+
+void CDAudio_Eject(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+
+ Com_DPrintf("CDAudio_Eject: PORTME\n");
+ /*
+ if ( ioctl(cdfile, CDROMEJECT) == -1 )
+ Com_DPrintf("ioctl cdromeject failed\n");
+ */
+}
+
+void CDAudio_CloseDoor(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+
+ Com_DPrintf("CDAudio_CloseDoor: PORTME\n");
+ /*
+ if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 )
+ Com_DPrintf("ioctl cdromclosetray failed\n");
+ */
+}
+
+int CDAudio_GetAudioDiskInfo(void)
+{
+ cdValid = false;
+ Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
+ return -1;
+
+ /*
+ struct cdrom_tochdr tochdr;
+
+ if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 )
+ {
+ Com_DPrintf("ioctl cdromreadtochdr failed\n");
+ return -1;
+ }
+
+ if (tochdr.cdth_trk0 < 1)
+ {
+ Com_DPrintf("CDAudio: no music tracks\n");
+ return -1;
+ }
+
+ cdValid = true;
+ maxTrack = tochdr.cdth_trk1;
+ return 0;
+ */
+}
+
+void CDAudio_Pause(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+ if (!playing)
+ return;
+
+ Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
+
+ /*
+ if ( ioctl(cdfile, CDROMPAUSE) == -1 )
+ Com_DPrintf("ioctl cdrompause failed\n");
+
+ wasPlaying = playing;
+ playing = false;
+ */
+}
+
+void CDAudio_Play(int track, qboolean looping)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+ if (!cdValid)
+ {
+ CDAudio_GetAudioDiskInfo();
+ if (!cdValid)
+ return;
+ }
+
+ track = remap[track];
+ if (track < 1 || track > maxTrack)
+ {
+ Com_DPrintf("CDAudio: Bad track number %u.\n", track);
+ return;
+ }
+
+ USED(looping);
+ Com_DPrintf("CDAudio_Play: PORTME\n");
+
+ /*
+ struct cdrom_tocentry entry;
+ struct cdrom_ti ti;
+
+ // don't try to play a non-audio track
+ entry.cdte_track = track;
+ entry.cdte_format = CDROM_MSF;
+ if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 )
+ {
+ Com_DPrintf("ioctl cdromreadtocentry failed\n");
+ return;
+ }
+ if (entry.cdte_ctrl == CDROM_DATA_TRACK)
+ {
+ Com_Printf("CDAudio: track %i is not audio\n", track);
+ return;
+ }
+
+ if (playing)
+ {
+ if (playTrack == track)
+ return;
+ CDAudio_Stop();
+ }
+
+ ti.cdti_trk0 = track;
+ ti.cdti_trk1 = track;
+ ti.cdti_ind0 = 1;
+ ti.cdti_ind1 = 99;
+ if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 )
+ {
+ Com_DPrintf("ioctl cdromplaytrkind failed\n");
+ return;
+ }
+ if ( ioctl(cdfile, CDROMRESUME) == -1 )
+ Com_DPrintf("ioctl cdromresume failed\n");
+
+ playLooping = looping;
+ playTrack = track;
+ playing = true;
+
+ if (cd_volume->value == 0.0)
+ CDAudio_Pause ();
+ */
+}
+
+
+void CDAudio_Stop(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+ if (!playing)
+ return;
+
+ Com_DPrintf("CDAudio_Stop: PORTME\n");
+
+ /*
+ if ( ioctl(cdfile, CDROMSTOP) == -1 )
+ Com_DPrintf("ioctl cdromstop failed (%d)\n", errno);
+
+ wasPlaying = false;
+ playing = false;
+ */
+}
+
+void CDAudio_Resume(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+ if (!cdValid)
+ return;
+ if (!wasPlaying)
+ return;
+
+ Com_DPrintf("CDAudio_Stop: PORTME\n");
+
+ /*
+ if ( ioctl(cdfile, CDROMRESUME) == -1 )
+ Com_DPrintf("ioctl cdromresume failed\n");
+ playing = true;
+ */
+}
+
+static void CD_f (void)
+{
+ char *command;
+ int n, ret;
+
+ if (Cmd_Argc() < 2)
+ return;
+
+ command = Cmd_Argv (1);
+
+ if (cistrcmp(command, "on") == 0)
+ {
+ enabled = true;
+ return;
+ }
+
+ if (cistrcmp(command, "off") == 0)
+ {
+ if (playing)
+ CDAudio_Stop();
+ enabled = false;
+ return;
+ }
+
+ if (cistrcmp(command, "reset") == 0)
+ {
+ enabled = true;
+ if (playing)
+ CDAudio_Stop();
+ for (n = 0; n < 100; n++)
+ remap[n] = n;
+ CDAudio_GetAudioDiskInfo();
+ return;
+ }
+
+ if (cistrcmp(command, "remap") == 0)
+ {
+ ret = Cmd_Argc() - 2;
+ if (ret <= 0)
+ {
+ for (n = 1; n < 100; n++)
+ if (remap[n] != n)
+ Com_Printf(" %u -> %u\n", n, remap[n]);
+ return;
+ }
+ for (n = 1; n <= ret; n++)
+ remap[n] = atoi(Cmd_Argv (n+1));
+ return;
+ }
+
+ if (cistrcmp(command, "close") == 0)
+ {
+ CDAudio_CloseDoor();
+ return;
+ }
+
+ if (!cdValid)
+ {
+ CDAudio_GetAudioDiskInfo();
+ if (!cdValid)
+ {
+ Com_Printf("No CD in player.\n");
+ return;
+ }
+ }
+
+ if (cistrcmp(command, "play") == 0)
+ {
+ CDAudio_Play((byte)atoi(Cmd_Argv (2)), false);
+ return;
+ }
+
+ if (cistrcmp(command, "loop") == 0)
+ {
+ CDAudio_Play((byte)atoi(Cmd_Argv (2)), true);
+ return;
+ }
+
+ if (cistrcmp(command, "stop") == 0)
+ {
+ CDAudio_Stop();
+ return;
+ }
+
+ if (cistrcmp(command, "pause") == 0)
+ {
+ CDAudio_Pause();
+ return;
+ }
+
+ if (cistrcmp(command, "resume") == 0)
+ {
+ CDAudio_Resume();
+ return;
+ }
+
+ if (cistrcmp(command, "eject") == 0)
+ {
+ if (playing)
+ CDAudio_Stop();
+ CDAudio_Eject();
+ cdValid = false;
+ return;
+ }
+
+ if (cistrcmp(command, "info") == 0)
+ {
+ Com_Printf("%u tracks\n", maxTrack);
+ if (playing)
+ Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
+ else if (wasPlaying)
+ Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
+ Com_Printf("Volume is %f\n", cdvolume);
+ return;
+ }
+}
+
+void CDAudio_Update(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+ if (cd_volume && cd_volume->value != cdvolume)
+ {
+ if (cdvolume)
+ {
+ Cvar_SetValue ("cd_volume", 0.0);
+ cdvolume = cd_volume->value;
+ CDAudio_Pause ();
+ }
+ else
+ {
+ Cvar_SetValue ("cd_volume", 1.0);
+ cdvolume = cd_volume->value;
+ CDAudio_Resume ();
+ }
+ }
+
+ Com_DPrintf("CDAudio_Stop: PORTME\n");
+
+ /*
+ struct cdrom_subchnl subchnl;
+ static time_t lastchk;
+
+ if (playing && lastchk < time(NULL)) {
+ lastchk = time(NULL) + 2; //two seconds between chks
+ subchnl.cdsc_format = CDROM_MSF;
+ if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) {
+ Com_DPrintf("ioctl cdromsubchnl failed\n");
+ playing = false;
+ return;
+ }
+ if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY &&
+ subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) {
+ playing = false;
+ if (playLooping)
+ CDAudio_Play(playTrack, true);
+ }
+ }
+ */
+}
+
+int CDAudio_Init(void)
+{
+ int i;
+ cvar_t *cv;
+
+ cv = Cvar_Get ("nocdaudio", "0", CVAR_NOSET);
+ if (cv->value)
+ return -1;
+
+ cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
+ if ( cd_nocd->value)
+ return -1;
+
+ cd_volume = Cvar_Get ("cd_volume", "1", CVAR_ARCHIVE);
+
+ cd_dev = Cvar_Get("cd_dev", "/dev/cdrom", CVAR_ARCHIVE);
+
+ if((cdfile = open(cd_dev->string, OREAD)) < 0){
+ fprint(2, "CDAudio_Init: %r\n");
+ Com_Printf("CDAudio_Init: failed to open \"%s\"\n", cd_dev->string);
+ cdfile = -1;
+ return -1;
+ }
+
+ for (i = 0; i < 100; i++)
+ remap[i] = i;
+ initialized = true;
+ enabled = true;
+
+ if (CDAudio_GetAudioDiskInfo())
+ {
+ Com_Printf("CDAudio_Init: No CD in player.\n");
+ cdValid = false;
+ }
+
+ Cmd_AddCommand ("cd", CD_f);
+
+ Com_Printf("CD Audio Initialized\n");
+
+ return 0;
+}
+
+void CDAudio_Activate (qboolean active)
+{
+ if (active)
+ CDAudio_Resume ();
+ else
+ CDAudio_Pause ();
+}
+
+void CDAudio_Shutdown(void)
+{
+ if (!initialized)
+ return;
+ CDAudio_Stop();
+ close(cdfile);
+ cdfile = -1;
+}
--- /dev/null
+++ b/cl_cin.c
@@ -1,0 +1,633 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef struct
+{
+ byte *data;
+ int count;
+} cblock_t;
+
+typedef struct
+{
+ qboolean restart_sound;
+ int s_rate;
+ int s_width;
+ int s_channels;
+
+ int width;
+ int height;
+ byte *pic;
+ byte *pic_pending;
+
+ // order 1 huffman stuff
+ int *hnodes1; // [256][256][2];
+ int numhnodes1[256];
+
+ int h_used[512];
+ int h_count[512];
+} cinematics_t;
+
+cinematics_t cin;
+
+/*
+=================================================================
+
+PCX LOADING
+
+=================================================================
+*/
+
+
+/*
+==============
+SCR_LoadPCX
+==============
+*/
+void SCR_LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
+{
+ byte *raw;
+ pcx_t *pcx;
+ int x, y;
+ int len;
+ int dataByte, runLength;
+ byte *out, *pix;
+
+ *pic = NULL;
+
+ //
+ // load the file
+ //
+ len = FS_LoadFile (filename, (void **)&raw);
+ if (!raw)
+ return; // Com_Printf ("Bad pcx file %s\n", filename);
+
+ //
+ // parse the PCX file
+ //
+ pcx = (pcx_t *)raw;
+ raw = &pcx->data;
+
+ if (pcx->manufacturer != 0x0a
+ || pcx->version != 5
+ || pcx->encoding != 1
+ || pcx->bits_per_pixel != 8
+ || pcx->xmax >= 640
+ || pcx->ymax >= 480)
+ {
+ Com_Printf ("Bad pcx file %s\n", filename);
+ return;
+ }
+
+ out = Z_Malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
+
+ *pic = out;
+
+ pix = out;
+
+ if (palette)
+ {
+ *palette = Z_Malloc(768);
+ memcpy (*palette, (byte *)pcx + len - 768, 768);
+ }
+
+ if (width)
+ *width = pcx->xmax+1;
+ if (height)
+ *height = pcx->ymax+1;
+
+ for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
+ {
+ for (x=0 ; x<=pcx->xmax ; )
+ {
+ dataByte = *raw++;
+
+ if((dataByte & 0xC0) == 0xC0)
+ {
+ runLength = dataByte & 0x3F;
+ dataByte = *raw++;
+ }
+ else
+ runLength = 1;
+
+ while(runLength-- > 0)
+ pix[x++] = dataByte;
+ }
+
+ }
+
+ if ( raw - (byte *)pcx > len)
+ {
+ Com_Printf ("PCX file %s was malformed", filename);
+ Z_Free (*pic);
+ *pic = NULL;
+ }
+
+ FS_FreeFile (pcx);
+}
+
+//=============================================================
+
+/*
+==================
+SCR_StopCinematic
+==================
+*/
+void SCR_StopCinematic (void)
+{
+ cl.cinematictime = 0; // done
+ if (cin.pic)
+ {
+ Z_Free (cin.pic);
+ cin.pic = NULL;
+ }
+ if (cin.pic_pending)
+ {
+ Z_Free (cin.pic_pending);
+ cin.pic_pending = NULL;
+ }
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ }
+ if (cl.cinematic_file)
+ {
+ fclose (cl.cinematic_file);
+ cl.cinematic_file = NULL;
+ }
+ if (cin.hnodes1)
+ {
+ Z_Free (cin.hnodes1);
+ cin.hnodes1 = NULL;
+ }
+
+ // switch back down to 11 khz sound if necessary
+ if (cin.restart_sound)
+ {
+ cin.restart_sound = false;
+ CL_Snd_Restart_f ();
+ }
+
+}
+
+/*
+====================
+SCR_FinishCinematic
+
+Called when either the cinematic completes, or it is aborted
+====================
+*/
+void SCR_FinishCinematic (void)
+{
+ // tell the server to advance to the next map / cinematic
+ MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+ SZ_Print (&cls.netchan.message, va("nextserver %i\n", cl.servercount));
+}
+
+//==========================================================================
+
+/*
+==================
+SmallestNode1
+==================
+*/
+int SmallestNode1 (int numhnodes)
+{
+ int i;
+ int best, bestnode;
+
+ best = 99999999;
+ bestnode = -1;
+ for (i=0 ; i<numhnodes ; i++)
+ {
+ if (cin.h_used[i])
+ continue;
+ if (!cin.h_count[i])
+ continue;
+ if (cin.h_count[i] < best)
+ {
+ best = cin.h_count[i];
+ bestnode = i;
+ }
+ }
+
+ if (bestnode == -1)
+ return -1;
+
+ cin.h_used[bestnode] = true;
+ return bestnode;
+}
+
+
+/*
+==================
+Huff1TableInit
+
+Reads the 64k counts table and initializes the node trees
+==================
+*/
+void Huff1TableInit (void)
+{
+ int prev;
+ int j;
+ int *node, *nodebase;
+ byte counts[256];
+ int numhnodes;
+
+ cin.hnodes1 = Z_Malloc (256*256*2*4);
+ memset (cin.hnodes1, 0, 256*256*2*4);
+
+ for (prev=0 ; prev<256 ; prev++)
+ {
+ memset (cin.h_count,0,sizeof(cin.h_count));
+ memset (cin.h_used,0,sizeof(cin.h_used));
+
+ // read a row of counts
+ FS_Read (counts, sizeof(counts), cl.cinematic_file);
+ for (j=0 ; j<256 ; j++)
+ cin.h_count[j] = counts[j];
+
+ // build the nodes
+ numhnodes = 256;
+ nodebase = cin.hnodes1 + prev*256*2;
+
+ while (numhnodes != 511)
+ {
+ node = nodebase + (numhnodes-256)*2;
+
+ // pick two lowest counts
+ node[0] = SmallestNode1 (numhnodes);
+ if (node[0] == -1)
+ break; // no more
+
+ node[1] = SmallestNode1 (numhnodes);
+ if (node[1] == -1)
+ break;
+
+ cin.h_count[numhnodes] = cin.h_count[node[0]] + cin.h_count[node[1]];
+ numhnodes++;
+ }
+
+ cin.numhnodes1[prev] = numhnodes-1;
+ }
+}
+
+/*
+==================
+Huff1Decompress
+==================
+*/
+cblock_t Huff1Decompress (cblock_t in)
+{
+ byte *input;
+ byte *out_p;
+ int nodenum;
+ int count;
+ cblock_t out;
+ int inbyte;
+ int *hnodes, *hnodesbase;
+//int i;
+
+ // get decompressed count
+ count = in.data[0] + (in.data[1]<<8) + (in.data[2]<<16) + (in.data[3]<<24);
+ input = in.data + 4;
+ out_p = out.data = Z_Malloc (count);
+
+ // read bits
+
+ hnodesbase = cin.hnodes1 - 256*2; // nodes 0-255 aren't stored
+
+ hnodes = hnodesbase;
+ nodenum = cin.numhnodes1[0];
+ while (count)
+ {
+ inbyte = *input++;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ }
+
+ if (input - in.data != in.count && input - in.data != in.count+1)
+ {
+ Com_Printf ("Decompression overread by %i", (input - in.data) - in.count);
+ }
+ out.count = out_p - out.data;
+
+ return out;
+}
+
+/*
+==================
+SCR_ReadNextFrame
+==================
+*/
+byte *SCR_ReadNextFrame (void)
+{
+ int r;
+ int command;
+ byte samples[22050/14*4];
+ byte compressed[0x20000];
+ int size;
+ byte *pic;
+ cblock_t in, huf1;
+ int start, end, count;
+
+ // read the next frame
+ r = fread (&command, 4, 1, cl.cinematic_file);
+ if (r == 0) // we'll give it one more chance
+ r = fread (&command, 4, 1, cl.cinematic_file);
+
+ if (r != 1)
+ return NULL;
+ command = LittleLong(command);
+ if (command == 2)
+ return NULL; // last frame marker
+
+ if (command == 1)
+ { // read palette
+ FS_Read (cl.cinematicpalette, sizeof(cl.cinematicpalette), cl.cinematic_file);
+ cl.cinematicpalette_active=0; // dubious.... exposes an edge case
+ }
+
+ // decompress the next frame
+ FS_Read (&size, 4, cl.cinematic_file);
+ size = LittleLong(size);
+ if (size > sizeof(compressed) || size < 1)
+ Com_Error (ERR_DROP, "Bad compressed frame size");
+ FS_Read (compressed, size, cl.cinematic_file);
+
+ // read sound
+ start = cl.cinematicframe*cin.s_rate/14;
+ end = (cl.cinematicframe+1)*cin.s_rate/14;
+ count = end - start;
+
+ FS_Read (samples, count*cin.s_width*cin.s_channels, cl.cinematic_file);
+
+ S_RawSamples (count, cin.s_rate, cin.s_width, cin.s_channels, samples);
+
+ in.data = compressed;
+ in.count = size;
+
+ huf1 = Huff1Decompress (in);
+
+ pic = huf1.data;
+
+ cl.cinematicframe++;
+
+ return pic;
+}
+
+
+/*
+==================
+SCR_RunCinematic
+
+==================
+*/
+void SCR_RunCinematic (void)
+{
+ int frame;
+
+ if (cl.cinematictime <= 0)
+ {
+ SCR_StopCinematic ();
+ return;
+ }
+
+ if (cl.cinematicframe == -1)
+ return; // static image
+
+ if (cls.key_dest != key_game)
+ { // pause if menu or console is up
+ cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
+ return;
+ }
+
+ frame = (cls.realtime - cl.cinematictime)*14.0/1000;
+ if (frame <= cl.cinematicframe)
+ return;
+ if (frame > cl.cinematicframe+1)
+ {
+ Com_Printf ("Dropped frame: %i > %i\n", frame, cl.cinematicframe+1);
+ cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
+ }
+ if (cin.pic)
+ Z_Free (cin.pic);
+ cin.pic = cin.pic_pending;
+ cin.pic_pending = NULL;
+ cin.pic_pending = SCR_ReadNextFrame ();
+ if (!cin.pic_pending)
+ {
+ SCR_StopCinematic ();
+ SCR_FinishCinematic ();
+ cl.cinematictime = 1; // hack to get the black screen behind loading
+ SCR_BeginLoadingPlaque ();
+ cl.cinematictime = 0;
+ return;
+ }
+}
+
+/*
+==================
+SCR_DrawCinematic
+
+Returns true if a cinematic is active, meaning the view rendering
+should be skipped
+==================
+*/
+qboolean SCR_DrawCinematic (void)
+{
+ if (cl.cinematictime <= 0)
+ {
+ return false;
+ }
+
+ if (cls.key_dest == key_menu)
+ { // blank screen and pause if menu is up
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ return true;
+ }
+
+ if (!cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette((uchar *)cl.cinematicpalette);
+ cl.cinematicpalette_active = true;
+ }
+
+ if (!cin.pic)
+ return true;
+
+ re.DrawStretchRaw (0, 0, vid.width, vid.height, cin.width, cin.height, cin.pic);
+
+ return true;
+}
+
+/*
+==================
+SCR_PlayCinematic
+
+==================
+*/
+void SCR_PlayCinematic (char *arg)
+{
+ int width, height;
+ byte *palette;
+ char name[MAX_OSPATH], *dot;
+ int old_khz;
+
+ // make sure CD isn't playing music
+ CDAudio_Stop();
+
+ cl.cinematicframe = 0;
+ dot = strstr (arg, ".");
+ if (dot && !strcmp (dot, ".pcx"))
+ { // static pcx image
+ Com_sprintf (name, sizeof(name), "pics/%s", arg);
+ SCR_LoadPCX (name, &cin.pic, &palette, &cin.width, &cin.height);
+ cl.cinematicframe = -1;
+ cl.cinematictime = 1;
+ SCR_EndLoadingPlaque ();
+ cls.state = ca_active;
+ if (!cin.pic)
+ {
+ Com_Printf ("%s not found.\n", name);
+ cl.cinematictime = 0;
+ }
+ else
+ {
+ memcpy (cl.cinematicpalette, palette, sizeof(cl.cinematicpalette));
+ Z_Free (palette);
+ }
+ return;
+ }
+
+ Com_sprintf (name, sizeof(name), "video/%s", arg);
+ FS_FOpenFile (name, &cl.cinematic_file);
+ if (!cl.cinematic_file)
+ {
+// Com_Error (ERR_DROP, "Cinematic %s not found.\n", name);
+ SCR_FinishCinematic ();
+ cl.cinematictime = 0; // done
+ return;
+ }
+
+ SCR_EndLoadingPlaque ();
+
+ cls.state = ca_active;
+
+ FS_Read (&width, 4, cl.cinematic_file);
+ FS_Read (&height, 4, cl.cinematic_file);
+ cin.width = LittleLong(width);
+ cin.height = LittleLong(height);
+
+ FS_Read (&cin.s_rate, 4, cl.cinematic_file);
+ cin.s_rate = LittleLong(cin.s_rate);
+ FS_Read (&cin.s_width, 4, cl.cinematic_file);
+ cin.s_width = LittleLong(cin.s_width);
+ FS_Read (&cin.s_channels, 4, cl.cinematic_file);
+ cin.s_channels = LittleLong(cin.s_channels);
+
+ Huff1TableInit ();
+
+ // switch up to 22 khz sound if necessary
+ old_khz = Cvar_VariableValue ("s_khz");
+ if (old_khz != cin.s_rate/1000)
+ {
+ cin.restart_sound = true;
+ Cvar_SetValue ("s_khz", cin.s_rate/1000);
+ CL_Snd_Restart_f ();
+ Cvar_SetValue ("s_khz", old_khz);
+ }
+
+ cl.cinematicframe = 0;
+ cin.pic = SCR_ReadNextFrame ();
+ cl.cinematictime = Sys_Milliseconds ();
+}
--- /dev/null
+++ b/cl_ents.c
@@ -1,0 +1,1479 @@
+// cl_ents.c -- entity parsing and management
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+extern model_t *cl_mod_powerscreen;
+int vidref_val;
+
+/*
+=========================================================================
+
+FRAME PARSING
+
+=========================================================================
+*/
+
+/* the following are commented out in release
+
+typedef struct
+{
+ int modelindex;
+ int num; // entity number
+ int effects;
+ vec3_t origin;
+ vec3_t oldorigin;
+ vec3_t angles;
+ qboolean present;
+} projectile_t;
+
+#define MAX_PROJECTILES 64
+projectile_t cl_projectiles[MAX_PROJECTILES];
+
+void CL_ClearProjectiles (void)
+{
+ int i;
+
+ for (i = 0; i < MAX_PROJECTILES; i++) {
+// if (cl_projectiles[i].present)
+// Com_DPrintf("PROJ: %d CLEARED\n", cl_projectiles[i].num);
+ cl_projectiles[i].present = false;
+ }
+}
+
+*/
+
+/*
+=====================
+CL_ParseProjectiles
+
+Flechettes are passed as efficient temporary entities
+=====================
+*/
+/*
+void CL_ParseProjectiles (void)
+{
+ int i, c, j;
+ byte bits[8];
+ byte b;
+ projectile_t pr;
+ int lastempty = -1;
+ qboolean old = false;
+
+ c = MSG_ReadByte (&net_message);
+ for (i=0 ; i<c ; i++)
+ {
+ bits[0] = MSG_ReadByte (&net_message);
+ bits[1] = MSG_ReadByte (&net_message);
+ bits[2] = MSG_ReadByte (&net_message);
+ bits[3] = MSG_ReadByte (&net_message);
+ bits[4] = MSG_ReadByte (&net_message);
+ pr.origin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
+ pr.origin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
+ pr.origin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
+ VectorCopy(pr.origin, pr.oldorigin);
+
+ if (bits[4] & 64)
+ pr.effects = EF_BLASTER;
+ else
+ pr.effects = 0;
+
+ if (bits[4] & 128) {
+ old = true;
+ bits[0] = MSG_ReadByte (&net_message);
+ bits[1] = MSG_ReadByte (&net_message);
+ bits[2] = MSG_ReadByte (&net_message);
+ bits[3] = MSG_ReadByte (&net_message);
+ bits[4] = MSG_ReadByte (&net_message);
+ pr.oldorigin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
+ pr.oldorigin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
+ pr.oldorigin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
+ }
+
+ bits[0] = MSG_ReadByte (&net_message);
+ bits[1] = MSG_ReadByte (&net_message);
+ bits[2] = MSG_ReadByte (&net_message);
+
+ pr.angles[0] = 360*bits[0]/256;
+ pr.angles[1] = 360*bits[1]/256;
+ pr.modelindex = bits[2];
+
+ b = MSG_ReadByte (&net_message);
+ pr.num = (b & 0x7f);
+ if (b & 128) // extra entity number byte
+ pr.num |= (MSG_ReadByte (&net_message) << 7);
+
+ pr.present = true;
+
+ // find if this projectile already exists from previous frame
+ for (j = 0; j < MAX_PROJECTILES; j++) {
+ if (cl_projectiles[j].modelindex) {
+ if (cl_projectiles[j].num == pr.num) {
+ // already present, set up oldorigin for interpolation
+ if (!old)
+ VectorCopy(cl_projectiles[j].origin, pr.oldorigin);
+ cl_projectiles[j] = pr;
+ break;
+ }
+ } else
+ lastempty = j;
+ }
+
+ // not present previous frame, add it
+ if (j == MAX_PROJECTILES) {
+ if (lastempty != -1) {
+ cl_projectiles[lastempty] = pr;
+ }
+ }
+ }
+}
+*/
+
+/*
+=============
+CL_LinkProjectiles
+
+=============
+*/
+/*
+void CL_AddProjectiles (void)
+{
+ int i, j;
+ projectile_t *pr;
+ entity_t ent;
+
+ memset (&ent, 0, sizeof(ent));
+
+ for (i=0, pr=cl_projectiles ; i < MAX_PROJECTILES ; i++, pr++)
+ {
+ // grab an entity to fill in
+ if (pr->modelindex < 1)
+ continue;
+ if (!pr->present) {
+ pr->modelindex = 0;
+ continue; // not present this frame (it was in the previous frame)
+ }
+
+ ent.model = cl.model_draw[pr->modelindex];
+
+ // interpolate origin
+ for (j=0 ; j<3 ; j++)
+ {
+ ent.origin[j] = ent.oldorigin[j] = pr->oldorigin[j] + cl.lerpfrac *
+ (pr->origin[j] - pr->oldorigin[j]);
+
+ }
+
+ if (pr->effects & EF_BLASTER)
+ CL_BlasterTrail (pr->oldorigin, ent.origin);
+ V_AddLight (pr->origin, 200, 1, 1, 0);
+
+ VectorCopy (pr->angles, ent.angles);
+ V_AddEntity (&ent);
+ }
+}
+*/
+
+/*
+=================
+CL_ParseEntityBits
+
+Returns the entity number and the header bits
+=================
+*/
+int bitcounts[32]; /// just for protocol profiling
+int CL_ParseEntityBits (int *bits)
+{
+ unsigned b, total;
+ int i;
+ int number;
+
+ total = MSG_ReadByte (&net_message);
+ if (total & U_MOREBITS1)
+ {
+ b = MSG_ReadByte (&net_message);
+ total |= b<<8;
+ }
+ if (total & U_MOREBITS2)
+ {
+ b = MSG_ReadByte (&net_message);
+ total |= b<<16;
+ }
+ if (total & U_MOREBITS3)
+ {
+ b = MSG_ReadByte (&net_message);
+ total |= b<<24;
+ }
+
+ // count the bits for net profiling
+ for (i=0 ; i<32 ; i++)
+ if (total&(1<<i))
+ bitcounts[i]++;
+
+ if (total & U_NUMBER16)
+ number = MSG_ReadShort (&net_message);
+ else
+ number = MSG_ReadByte (&net_message);
+
+ *bits = total;
+
+ return number;
+}
+
+/*
+==================
+CL_ParseDelta
+
+Can go from either a baseline or a previous packet_entity
+==================
+*/
+void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits)
+{
+ // set everything to the state we are delta'ing from
+ *to = *from;
+
+ VectorCopy (from->origin, to->old_origin);
+ to->number = number;
+
+ if (bits & U_MODEL)
+ to->modelindex = MSG_ReadByte (&net_message);
+ if (bits & U_MODEL2)
+ to->modelindex2 = MSG_ReadByte (&net_message);
+ if (bits & U_MODEL3)
+ to->modelindex3 = MSG_ReadByte (&net_message);
+ if (bits & U_MODEL4)
+ to->modelindex4 = MSG_ReadByte (&net_message);
+
+ if (bits & U_FRAME8)
+ to->frame = MSG_ReadByte (&net_message);
+ if (bits & U_FRAME16)
+ to->frame = MSG_ReadShort (&net_message);
+
+ if ((bits & U_SKIN8) && (bits & U_SKIN16)) //used for laser colors
+ to->skinnum = MSG_ReadLong(&net_message);
+ else if (bits & U_SKIN8)
+ to->skinnum = MSG_ReadByte(&net_message);
+ else if (bits & U_SKIN16)
+ to->skinnum = MSG_ReadShort(&net_message);
+
+ if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
+ to->effects = MSG_ReadLong(&net_message);
+ else if (bits & U_EFFECTS8)
+ to->effects = MSG_ReadByte(&net_message);
+ else if (bits & U_EFFECTS16)
+ to->effects = MSG_ReadShort(&net_message);
+
+ if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
+ to->renderfx = MSG_ReadLong(&net_message);
+ else if (bits & U_RENDERFX8)
+ to->renderfx = MSG_ReadByte(&net_message);
+ else if (bits & U_RENDERFX16)
+ to->renderfx = MSG_ReadShort(&net_message);
+
+ if (bits & U_ORIGIN1)
+ to->origin[0] = MSG_ReadCoord (&net_message);
+ if (bits & U_ORIGIN2)
+ to->origin[1] = MSG_ReadCoord (&net_message);
+ if (bits & U_ORIGIN3)
+ to->origin[2] = MSG_ReadCoord (&net_message);
+
+ if (bits & U_ANGLE1)
+ to->angles[0] = MSG_ReadAngle(&net_message);
+ if (bits & U_ANGLE2)
+ to->angles[1] = MSG_ReadAngle(&net_message);
+ if (bits & U_ANGLE3)
+ to->angles[2] = MSG_ReadAngle(&net_message);
+
+ if (bits & U_OLDORIGIN)
+ MSG_ReadPos (&net_message, to->old_origin);
+
+ if (bits & U_SOUND)
+ to->sound = MSG_ReadByte (&net_message);
+
+ if (bits & U_EVENT)
+ to->event = MSG_ReadByte (&net_message);
+ else
+ to->event = 0;
+
+ if (bits & U_SOLID)
+ to->solid = MSG_ReadShort (&net_message);
+}
+
+/*
+==================
+CL_DeltaEntity
+
+Parses deltas from the given base and adds the resulting entity
+to the current frame
+==================
+*/
+void CL_DeltaEntity (frame_t *frame, int newnum, entity_state_t *old, int bits)
+{
+ centity_t *ent;
+ entity_state_t *state;
+
+ ent = &cl_entities[newnum];
+
+ state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)];
+ cl.parse_entities++;
+ frame->num_entities++;
+
+ CL_ParseDelta (old, state, newnum, bits);
+
+ // some data changes will force no lerping
+ if (state->modelindex != ent->current.modelindex
+ || state->modelindex2 != ent->current.modelindex2
+ || state->modelindex3 != ent->current.modelindex3
+ || state->modelindex4 != ent->current.modelindex4
+ || abs(state->origin[0] - ent->current.origin[0]) > 512
+ || abs(state->origin[1] - ent->current.origin[1]) > 512
+ || abs(state->origin[2] - ent->current.origin[2]) > 512
+ || state->event == EV_PLAYER_TELEPORT
+ || state->event == EV_OTHER_TELEPORT
+ )
+ {
+ ent->serverframe = -99;
+ }
+
+ if (ent->serverframe != cl.frame.serverframe - 1)
+ { // wasn't in last update, so initialize some things
+ ent->trailcount = 1024; // for diminishing rocket / grenade trails
+ // duplicate the current state so lerping doesn't hurt anything
+ ent->prev = *state;
+ if (state->event == EV_OTHER_TELEPORT)
+ {
+ VectorCopy (state->origin, ent->prev.origin);
+ VectorCopy (state->origin, ent->lerp_origin);
+ }
+ else
+ {
+ VectorCopy (state->old_origin, ent->prev.origin);
+ VectorCopy (state->old_origin, ent->lerp_origin);
+ }
+ }
+ else
+ { // shuffle the last state to previous
+ ent->prev = ent->current;
+ }
+
+ ent->serverframe = cl.frame.serverframe;
+ ent->current = *state;
+}
+
+/*
+==================
+CL_ParsePacketEntities
+
+An svc_packetentities has just been parsed, deal with the
+rest of the data stream.
+==================
+*/
+void CL_ParsePacketEntities (frame_t *oldframe, frame_t *newframe)
+{
+ int newnum;
+ int bits;
+ entity_state_t *oldstate = nil;
+ int oldindex, oldnum;
+
+ newframe->parse_entities = cl.parse_entities;
+ newframe->num_entities = 0;
+
+ // delta from the entities present in oldframe
+ oldindex = 0;
+ if (!oldframe)
+ oldnum = 99999;
+ else
+ {
+ if (oldindex >= oldframe->num_entities)
+ oldnum = 99999;
+ else
+ {
+ oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ }
+
+ while (1)
+ {
+ newnum = CL_ParseEntityBits (&bits);
+ if (newnum >= MAX_EDICTS)
+ Com_Error (ERR_DROP,"CL_ParsePacketEntities: bad number:%i", newnum);
+
+ if (net_message.readcount > net_message.cursize)
+ Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
+
+ if (!newnum)
+ break;
+
+ while (oldnum < newnum)
+ { // one or more entities from the old packet are unchanged
+ if (cl_shownet->value == 3)
+ Com_Printf (" unchanged: %i\n", oldnum);
+ CL_DeltaEntity (newframe, oldnum, oldstate, 0);
+
+ oldindex++;
+
+ if (oldindex >= oldframe->num_entities)
+ oldnum = 99999;
+ else
+ {
+ oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ }
+
+ if (bits & U_REMOVE)
+ { // the entity present in oldframe is not in the current frame
+ if (cl_shownet->value == 3)
+ Com_Printf (" remove: %i\n", newnum);
+ if (oldnum != newnum)
+ Com_Printf ("U_REMOVE: oldnum != newnum\n");
+
+ oldindex++;
+
+ if (oldindex >= oldframe->num_entities)
+ oldnum = 99999;
+ else
+ {
+ oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ continue;
+ }
+
+ if (oldnum == newnum)
+ { // delta from previous state
+ if (cl_shownet->value == 3)
+ Com_Printf (" delta: %i\n", newnum);
+ CL_DeltaEntity (newframe, newnum, oldstate, bits);
+
+ oldindex++;
+
+ if (oldindex >= oldframe->num_entities)
+ oldnum = 99999;
+ else
+ {
+ oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ continue;
+ }
+
+ if (oldnum > newnum)
+ { // delta from baseline
+ if (cl_shownet->value == 3)
+ Com_Printf (" baseline: %i\n", newnum);
+ CL_DeltaEntity (newframe, newnum, &cl_entities[newnum].baseline, bits);
+ continue;
+ }
+
+ }
+
+ // any remaining entities in the old frame are copied over
+ while (oldnum != 99999)
+ { // one or more entities from the old packet are unchanged
+ if (cl_shownet->value == 3)
+ Com_Printf (" unchanged: %i\n", oldnum);
+ CL_DeltaEntity (newframe, oldnum, oldstate, 0);
+
+ oldindex++;
+
+ if (oldindex >= oldframe->num_entities)
+ oldnum = 99999;
+ else
+ {
+ oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ }
+}
+
+
+
+/*
+===================
+CL_ParsePlayerstate
+===================
+*/
+void CL_ParsePlayerstate (frame_t *oldframe, frame_t *newframe)
+{
+ int flags;
+ player_state_t *state;
+ int i;
+ int statbits;
+
+ state = &newframe->playerstate;
+
+ // clear to old value before delta parsing
+ if (oldframe)
+ *state = oldframe->playerstate;
+ else
+ memset (state, 0, sizeof(*state));
+
+ flags = MSG_ReadShort (&net_message);
+
+ //
+ // parse the pmove_state_t
+ //
+ if (flags & PS_M_TYPE)
+ state->pmove.pm_type = MSG_ReadByte (&net_message);
+
+ if (flags & PS_M_ORIGIN)
+ {
+ state->pmove.origin[0] = MSG_ReadShort (&net_message);
+ state->pmove.origin[1] = MSG_ReadShort (&net_message);
+ state->pmove.origin[2] = MSG_ReadShort (&net_message);
+ }
+
+ if (flags & PS_M_VELOCITY)
+ {
+ state->pmove.velocity[0] = MSG_ReadShort (&net_message);
+ state->pmove.velocity[1] = MSG_ReadShort (&net_message);
+ state->pmove.velocity[2] = MSG_ReadShort (&net_message);
+ }
+
+ if (flags & PS_M_TIME)
+ state->pmove.pm_time = MSG_ReadByte (&net_message);
+
+ if (flags & PS_M_FLAGS)
+ state->pmove.pm_flags = MSG_ReadByte (&net_message);
+
+ if (flags & PS_M_GRAVITY)
+ state->pmove.gravity = MSG_ReadShort (&net_message);
+
+ if (flags & PS_M_DELTA_ANGLES)
+ {
+ state->pmove.delta_angles[0] = MSG_ReadShort (&net_message);
+ state->pmove.delta_angles[1] = MSG_ReadShort (&net_message);
+ state->pmove.delta_angles[2] = MSG_ReadShort (&net_message);
+ }
+
+ if (cl.attractloop)
+ state->pmove.pm_type = PM_FREEZE; // demo playback
+
+ //
+ // parse the rest of the player_state_t
+ //
+ if (flags & PS_VIEWOFFSET)
+ {
+ state->viewoffset[0] = MSG_ReadChar (&net_message) * 0.25;
+ state->viewoffset[1] = MSG_ReadChar (&net_message) * 0.25;
+ state->viewoffset[2] = MSG_ReadChar (&net_message) * 0.25;
+ }
+
+ if (flags & PS_VIEWANGLES)
+ {
+ state->viewangles[0] = MSG_ReadAngle16 (&net_message);
+ state->viewangles[1] = MSG_ReadAngle16 (&net_message);
+ state->viewangles[2] = MSG_ReadAngle16 (&net_message);
+ }
+
+ if (flags & PS_KICKANGLES)
+ {
+ state->kick_angles[0] = MSG_ReadChar (&net_message) * 0.25;
+ state->kick_angles[1] = MSG_ReadChar (&net_message) * 0.25;
+ state->kick_angles[2] = MSG_ReadChar (&net_message) * 0.25;
+ }
+
+ if (flags & PS_WEAPONINDEX)
+ {
+ state->gunindex = MSG_ReadByte (&net_message);
+ }
+
+ if (flags & PS_WEAPONFRAME)
+ {
+ state->gunframe = MSG_ReadByte (&net_message);
+ state->gunoffset[0] = MSG_ReadChar (&net_message)*0.25;
+ state->gunoffset[1] = MSG_ReadChar (&net_message)*0.25;
+ state->gunoffset[2] = MSG_ReadChar (&net_message)*0.25;
+ state->gunangles[0] = MSG_ReadChar (&net_message)*0.25;
+ state->gunangles[1] = MSG_ReadChar (&net_message)*0.25;
+ state->gunangles[2] = MSG_ReadChar (&net_message)*0.25;
+ }
+
+ if (flags & PS_BLEND)
+ {
+ state->blend[0] = MSG_ReadByte (&net_message)/255.0;
+ state->blend[1] = MSG_ReadByte (&net_message)/255.0;
+ state->blend[2] = MSG_ReadByte (&net_message)/255.0;
+ state->blend[3] = MSG_ReadByte (&net_message)/255.0;
+ }
+
+ if (flags & PS_FOV)
+ state->fov = MSG_ReadByte (&net_message);
+
+ if (flags & PS_RDFLAGS)
+ state->rdflags = MSG_ReadByte (&net_message);
+
+ // parse stats
+ statbits = MSG_ReadLong (&net_message);
+ for (i=0 ; i<MAX_STATS ; i++)
+ if (statbits & (1<<i) )
+ state->stats[i] = MSG_ReadShort(&net_message);
+}
+
+
+/*
+==================
+CL_FireEntityEvents
+
+==================
+*/
+void CL_FireEntityEvents (frame_t *frame)
+{
+ entity_state_t *s1;
+ int pnum, num;
+
+ for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
+ {
+ num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1);
+ s1 = &cl_parse_entities[num];
+ if (s1->event)
+ CL_EntityEvent (s1);
+
+ // EF_TELEPORTER acts like an event, but is not cleared each frame
+ if (s1->effects & EF_TELEPORTER)
+ CL_TeleporterParticles (s1);
+ }
+}
+
+
+/*
+================
+CL_ParseFrame
+================
+*/
+void CL_ParseFrame (void)
+{
+ int cmd;
+ int len;
+ frame_t *old;
+
+ memset (&cl.frame, 0, sizeof(cl.frame));
+
+/*
+ CL_ClearProjectiles(); // clear projectiles for new frame
+*/
+
+ cl.frame.serverframe = MSG_ReadLong (&net_message);
+ cl.frame.deltaframe = MSG_ReadLong (&net_message);
+ cl.frame.servertime = cl.frame.serverframe*100;
+
+ // BIG HACK to let old demos continue to work
+ if (cls.serverProtocol != 26)
+ cl.surpressCount = MSG_ReadByte (&net_message);
+
+ if (cl_shownet->value == 3)
+ Com_Printf (" frame:%i delta:%i\n", cl.frame.serverframe,
+ cl.frame.deltaframe);
+
+ // If the frame is delta compressed from data that we
+ // no longer have available, we must suck up the rest of
+ // the frame, but not use it, then ask for a non-compressed
+ // message
+ if (cl.frame.deltaframe <= 0)
+ {
+ cl.frame.valid = true; // uncompressed frame
+ old = NULL;
+ cls.demowaiting = false; // we can start recording now
+ }
+ else
+ {
+ old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
+ if (!old->valid)
+ { // should never happen
+ Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
+ }
+ if (old->serverframe != cl.frame.deltaframe)
+ { // The frame that the server did the delta from
+ // is too old, so we can't reconstruct it properly.
+ Com_Printf ("Delta frame too old.\n");
+ }
+ else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128)
+ {
+ Com_Printf ("Delta parse_entities too old.\n");
+ }
+ else
+ cl.frame.valid = true; // valid delta parse
+ }
+
+ // clamp time
+ if (cl.time > cl.frame.servertime)
+ cl.time = cl.frame.servertime;
+ else if (cl.time < cl.frame.servertime - 100)
+ cl.time = cl.frame.servertime - 100;
+
+ // read areabits
+ len = MSG_ReadByte (&net_message);
+ MSG_ReadData (&net_message, cl.frame.areabits, len);
+
+ // read playerinfo
+ cmd = MSG_ReadByte (&net_message);
+ SHOWNET(svc_strings[cmd]);
+ if (cmd != svc_playerinfo)
+ Com_Error (ERR_DROP, "CL_ParseFrame: not playerinfo");
+ CL_ParsePlayerstate (old, &cl.frame);
+
+ // read packet entities
+ cmd = MSG_ReadByte (&net_message);
+ SHOWNET(svc_strings[cmd]);
+ if (cmd != svc_packetentities)
+ Com_Error (ERR_DROP, "CL_ParseFrame: not packetentities");
+ CL_ParsePacketEntities (old, &cl.frame);
+
+/*
+ if (cmd == svc_packetentities2)
+ CL_ParseProjectiles();
+*/
+
+ // save the frame off in the backup array for later delta comparisons
+ cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;
+
+ if (cl.frame.valid)
+ {
+ // getting a valid frame message ends the connection process
+ if (cls.state != ca_active)
+ {
+ cls.state = ca_active;
+ cl.force_refdef = true;
+ cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
+ cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
+ cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125;
+ VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles);
+ if (cls.disable_servercount != cl.servercount
+ && cl.refresh_prepped)
+ SCR_EndLoadingPlaque (); // get rid of loading plaque
+ }
+ cl.sound_prepped = true; // can start mixing ambient sounds
+
+ // fire entity events
+ CL_FireEntityEvents (&cl.frame);
+ CL_CheckPredictionError ();
+ }
+}
+
+/*
+==========================================================================
+
+INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
+
+==========================================================================
+*/
+
+model_t *
+S_RegisterSexedModel(entity_state_t *ent, char *base)
+{
+ int n;
+ char *p;
+ model_t *mdl;
+ char model[MAX_QPATH];
+ char buffer[MAX_QPATH];
+
+ // determine what model the client is using
+ model[0] = 0;
+ n = CS_PLAYERSKINS + ent->number - 1;
+ if (cl.configstrings[n][0])
+ {
+ p = strchr(cl.configstrings[n], '\\');
+ if (p)
+ {
+ p += 1;
+ strcpy(model, p);
+ p = strchr(model, '/');
+ if (p)
+ *p = 0;
+ }
+ }
+ // if we can't figure it out, they're male
+ if (!model[0])
+ strcpy(model, "male");
+
+ Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", model, base+1);
+ mdl = re.RegisterModel(buffer);
+ if (!mdl) {
+ // not found, try default weapon model
+ Com_sprintf (buffer, sizeof(buffer), "players/%s/weapon.md2", model);
+ mdl = re.RegisterModel(buffer);
+ if (!mdl) {
+ // no, revert to the male model
+ Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", "male", base+1);
+ mdl = re.RegisterModel(buffer);
+ if (!mdl) {
+ // last try, default male weapon.md2
+ Com_sprintf (buffer, sizeof(buffer), "players/male/weapon.md2");
+ mdl = re.RegisterModel(buffer);
+ }
+ }
+ }
+
+ return mdl;
+}
+
+/*
+===============
+CL_AddPacketEntities
+
+===============
+*/
+void CL_AddPacketEntities (frame_t *frame)
+{
+ entity_t ent;
+ entity_state_t *s1;
+ float autorotate;
+ int i;
+ int pnum;
+ centity_t *cent;
+ int autoanim;
+ clientinfo_t *ci;
+ unsigned int effects, renderfx;
+
+ // bonus items rotate at a fixed rate
+ autorotate = anglemod(cl.time/10);
+
+ // brush models can auto animate their frames
+ autoanim = 2*cl.time/1000;
+
+ memset (&ent, 0, sizeof(ent));
+
+ for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
+ {
+ s1 = &cl_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)];
+
+ cent = &cl_entities[s1->number];
+
+ effects = s1->effects;
+ renderfx = s1->renderfx;
+
+ // set frame
+ if (effects & EF_ANIM01)
+ ent.frame = autoanim & 1;
+ else if (effects & EF_ANIM23)
+ ent.frame = 2 + (autoanim & 1);
+ else if (effects & EF_ANIM_ALL)
+ ent.frame = autoanim;
+ else if (effects & EF_ANIM_ALLFAST)
+ ent.frame = cl.time / 100;
+ else
+ ent.frame = s1->frame;
+
+ // quad and pent can do different things on client
+ if (effects & EF_PENT)
+ {
+ effects &= ~EF_PENT;
+ effects |= EF_COLOR_SHELL;
+ renderfx |= RF_SHELL_RED;
+ }
+
+ if (effects & EF_QUAD)
+ {
+ effects &= ~EF_QUAD;
+ effects |= EF_COLOR_SHELL;
+ renderfx |= RF_SHELL_BLUE;
+ }
+//======
+// PMM
+ if (effects & EF_DOUBLE)
+ {
+ effects &= ~EF_DOUBLE;
+ effects |= EF_COLOR_SHELL;
+ renderfx |= RF_SHELL_DOUBLE;
+ }
+
+ if (effects & EF_HALF_DAMAGE)
+ {
+ effects &= ~EF_HALF_DAMAGE;
+ effects |= EF_COLOR_SHELL;
+ renderfx |= RF_SHELL_HALF_DAM;
+ }
+// pmm
+//======
+ ent.oldframe = cent->prev.frame;
+ ent.backlerp = 1.0 - cl.lerpfrac;
+
+ if (renderfx & (RF_FRAMELERP|RF_BEAM))
+ { // step origin discretely, because the frames
+ // do the animation properly
+ VectorCopy (cent->current.origin, ent.origin);
+ VectorCopy (cent->current.old_origin, ent.oldorigin);
+ }
+ else
+ { // interpolate origin
+ for (i=0 ; i<3 ; i++)
+ {
+ ent.origin[i] = ent.oldorigin[i] = cent->prev.origin[i] + cl.lerpfrac *
+ (cent->current.origin[i] - cent->prev.origin[i]);
+ }
+ }
+
+ // create a new entity
+
+ // tweak the color of beams
+ if ( renderfx & RF_BEAM )
+ { // the four beam colors are encoded in 32 bits of skinnum (hack)
+ ent.alpha = 0.30;
+ ent.skinnum = (s1->skinnum >> ((rand() % 4)*8)) & 0xff;
+ ent.model = NULL;
+ }
+ else
+ {
+ // set skin
+ if (s1->modelindex == 255)
+ { // use custom player skin
+ ent.skinnum = 0;
+ ci = &cl.clientinfo[s1->skinnum & 0xff];
+ ent.skin = ci->skin;
+ ent.model = ci->model;
+ if (!ent.skin || !ent.model)
+ {
+ ent.skin = cl.baseclientinfo.skin;
+ ent.model = cl.baseclientinfo.model;
+ }
+
+//============
+//PGM
+ if (renderfx & RF_USE_DISGUISE)
+ {
+ if(!strncmp((char *)ent.skin, "players/male", 12))
+ {
+ ent.skin = re.RegisterSkin ("players/male/disguise.pcx");
+ ent.model = re.RegisterModel ("players/male/tris.md2");
+ }
+ else if(!strncmp((char *)ent.skin, "players/female", 14))
+ {
+ ent.skin = re.RegisterSkin ("players/female/disguise.pcx");
+ ent.model = re.RegisterModel ("players/female/tris.md2");
+ }
+ else if(!strncmp((char *)ent.skin, "players/cyborg", 14))
+ {
+ ent.skin = re.RegisterSkin ("players/cyborg/disguise.pcx");
+ ent.model = re.RegisterModel ("players/cyborg/tris.md2");
+ }
+ }
+//PGM
+//============
+ }
+ else
+ {
+ ent.skinnum = s1->skinnum;
+ ent.skin = NULL;
+ ent.model = cl.model_draw[s1->modelindex];
+ }
+ }
+
+ // only used for black hole model right now, FIXME: do better
+ if (renderfx == RF_TRANSLUCENT)
+ ent.alpha = 0.70;
+
+ // render effects (fullbright, translucent, etc)
+ if ((effects & EF_COLOR_SHELL))
+ ent.flags = 0; // renderfx go on color shell entity
+ else
+ ent.flags = renderfx;
+
+ // calculate angles
+ if (effects & EF_ROTATE)
+ { // some bonus items auto-rotate
+ ent.angles[0] = 0;
+ ent.angles[1] = autorotate;
+ ent.angles[2] = 0;
+ }
+ // RAFAEL
+ else if (effects & EF_SPINNINGLIGHTS)
+ {
+ ent.angles[0] = 0;
+ ent.angles[1] = anglemod(cl.time/2) + s1->angles[1];
+ ent.angles[2] = 180;
+ {
+ vec3_t forward;
+ vec3_t start;
+
+ AngleVectors (ent.angles, forward, NULL, NULL);
+ VectorMA (ent.origin, 64, forward, start);
+ V_AddLight (start, 100, 1, 0, 0);
+ }
+ }
+ else
+ { // interpolate angles
+ float a1, a2;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ a1 = cent->current.angles[i];
+ a2 = cent->prev.angles[i];
+ ent.angles[i] = LerpAngle (a2, a1, cl.lerpfrac);
+ }
+ }
+
+ if (s1->number == cl.playernum+1)
+ {
+ ent.flags |= RF_VIEWERMODEL; // only draw from mirrors
+ // FIXME: still pass to refresh
+
+ if (effects & EF_FLAG1)
+ V_AddLight (ent.origin, 225, 1.0, 0.1, 0.1);
+ else if (effects & EF_FLAG2)
+ V_AddLight (ent.origin, 225, 0.1, 0.1, 1.0);
+ else if (effects & EF_TAGTRAIL) //PGM
+ V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0); //PGM
+ else if (effects & EF_TRACKERTRAIL) //PGM
+ V_AddLight (ent.origin, 225, -1.0, -1.0, -1.0); //PGM
+
+ continue;
+ }
+
+ // if set to invisible, skip
+ if (!s1->modelindex)
+ continue;
+
+ if (effects & EF_BFG)
+ {
+ ent.flags |= RF_TRANSLUCENT;
+ ent.alpha = 0.30;
+ }
+
+ // RAFAEL
+ if (effects & EF_PLASMA)
+ {
+ ent.flags |= RF_TRANSLUCENT;
+ ent.alpha = 0.6;
+ }
+
+ if (effects & EF_SPHERETRANS)
+ {
+ ent.flags |= RF_TRANSLUCENT;
+ // PMM - *sigh* yet more EF overloading
+ if (effects & EF_TRACKERTRAIL)
+ ent.alpha = 0.6;
+ else
+ ent.alpha = 0.3;
+ }
+//pmm
+
+ // add to refresh list
+ V_AddEntity (&ent);
+
+ // color shells generate a seperate entity for the main model
+ if (effects & EF_COLOR_SHELL)
+ {
+ ent.flags = renderfx | RF_TRANSLUCENT;
+ ent.alpha = 0.30;
+ V_AddEntity (&ent);
+ }
+
+ ent.skin = NULL; // never use a custom skin on others
+ ent.skinnum = 0;
+ ent.flags = 0;
+ ent.alpha = 0;
+
+ // duplicate for linked models
+ if (s1->modelindex2)
+ {
+ if (s1->modelindex2 == 255)
+ { // custom weapon
+ ci = &cl.clientinfo[s1->skinnum & 0xff];
+ i = (s1->skinnum >> 8); // 0 is default weapon model
+ if (!cl_vwep->value || i > MAX_CLIENTWEAPONMODELS - 1)
+ i = 0;
+ ent.model = ci->weaponmodel[i];
+ if (!ent.model) {
+ if (i != 0)
+ ent.model = ci->weaponmodel[0];
+ if (!ent.model)
+ ent.model = cl.baseclientinfo.weaponmodel[0];
+ }
+ }
+ //PGM - hack to allow translucent linked models (defender sphere's shell)
+ // set the high bit 0x80 on modelindex2 to enable translucency
+ else if(s1->modelindex2 & 0x80)
+ {
+ ent.model = cl.model_draw[s1->modelindex2 & 0x7F];
+ ent.alpha = 0.32;
+ ent.flags = RF_TRANSLUCENT;
+ }
+ //PGM
+ else
+ ent.model = cl.model_draw[s1->modelindex2];
+ V_AddEntity (&ent);
+
+ //PGM - make sure these get reset.
+ ent.flags = 0;
+ ent.alpha = 0;
+ //PGM
+ }
+ if (s1->modelindex3)
+ {
+ ent.model = cl.model_draw[s1->modelindex3];
+ V_AddEntity (&ent);
+ }
+ if (s1->modelindex4)
+ {
+ ent.model = cl.model_draw[s1->modelindex4];
+ V_AddEntity (&ent);
+ }
+
+ if ( effects & EF_POWERSCREEN )
+ {
+ ent.model = cl_mod_powerscreen;
+ ent.oldframe = 0;
+ ent.frame = 0;
+ ent.flags |= (RF_TRANSLUCENT | RF_SHELL_GREEN);
+ ent.alpha = 0.30;
+ V_AddEntity (&ent);
+ }
+
+ // add automatic particle trails
+ if ( (effects&~EF_ROTATE) )
+ {
+ if (effects & EF_ROCKET)
+ {
+ CL_RocketTrail (cent->lerp_origin, ent.origin, cent);
+ V_AddLight (ent.origin, 200, 1, 1, 0);
+ }
+ // PGM - Do not reorder EF_BLASTER and EF_HYPERBLASTER.
+ // EF_BLASTER | EF_TRACKER is a special case for EF_BLASTER2... Cheese!
+ else if (effects & EF_BLASTER)
+ {
+// CL_BlasterTrail (cent->lerp_origin, ent.origin);
+//PGM
+ if (effects & EF_TRACKER) // lame... problematic?
+ {
+ CL_BlasterTrail2 (cent->lerp_origin, ent.origin);
+ V_AddLight (ent.origin, 200, 0, 1, 0);
+ }
+ else
+ {
+ CL_BlasterTrail (cent->lerp_origin, ent.origin);
+ V_AddLight (ent.origin, 200, 1, 1, 0);
+ }
+//PGM
+ }
+ else if (effects & EF_HYPERBLASTER)
+ {
+ if (effects & EF_TRACKER) // PGM overloaded for blaster2.
+ V_AddLight (ent.origin, 200, 0, 1, 0); // PGM
+ else // PGM
+ V_AddLight (ent.origin, 200, 1, 1, 0);
+ }
+ else if (effects & EF_GIB)
+ {
+ CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
+ }
+ else if (effects & EF_GRENADE)
+ {
+ CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
+ }
+ else if (effects & EF_FLIES)
+ {
+ CL_FlyEffect (cent, ent.origin);
+ }
+ else if (effects & EF_BFG)
+ {
+ static int bfg_lightramp[6] = {300, 400, 600, 300, 150, 75};
+
+ if (effects & EF_ANIM_ALLFAST)
+ {
+ CL_BfgParticles (&ent);
+ i = 200;
+ }
+ else
+ {
+ i = bfg_lightramp[s1->frame];
+ }
+ V_AddLight (ent.origin, i, 0, 1, 0);
+ }
+ // RAFAEL
+ else if (effects & EF_TRAP)
+ {
+ ent.origin[2] += 32;
+ CL_TrapParticles (&ent);
+ i = (rand()%100) + 100;
+ V_AddLight (ent.origin, i, 1, 0.8, 0.1);
+ }
+ else if (effects & EF_FLAG1)
+ {
+ CL_FlagTrail (cent->lerp_origin, ent.origin, 242);
+ V_AddLight (ent.origin, 225, 1, 0.1, 0.1);
+ }
+ else if (effects & EF_FLAG2)
+ {
+ CL_FlagTrail (cent->lerp_origin, ent.origin, 115);
+ V_AddLight (ent.origin, 225, 0.1, 0.1, 1);
+ }
+//======
+//ROGUE
+ else if (effects & EF_TAGTRAIL)
+ {
+ CL_TagTrail (cent->lerp_origin, ent.origin, 220);
+ V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);
+ }
+ else if (effects & EF_TRACKERTRAIL)
+ {
+ if (effects & EF_TRACKER)
+ {
+ float intensity;
+
+ intensity = 50 + (500 * (sin(cl.time/500.0) + 1.0));
+ // FIXME - check out this effect in rendition
+ if(vidref_val == VIDREF_GL)
+ V_AddLight (ent.origin, intensity, -1.0, -1.0, -1.0);
+ else
+ V_AddLight (ent.origin, -1.0 * intensity, 1.0, 1.0, 1.0);
+ }
+ else
+ {
+ CL_Tracker_Shell (cent->lerp_origin);
+ V_AddLight (ent.origin, 155, -1.0, -1.0, -1.0);
+ }
+ }
+ else if (effects & EF_TRACKER)
+ {
+ CL_TrackerTrail (cent->lerp_origin, ent.origin, 0);
+ // FIXME - check out this effect in rendition
+ if(vidref_val == VIDREF_GL)
+ V_AddLight (ent.origin, 200, -1, -1, -1);
+ else
+ V_AddLight (ent.origin, -200, 1, 1, 1);
+ }
+//ROGUE
+//======
+ // RAFAEL
+ else if (effects & EF_GREENGIB)
+ {
+ CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
+ }
+ // RAFAEL
+ else if (effects & EF_IONRIPPER)
+ {
+ CL_IonripperTrail (cent->lerp_origin, ent.origin);
+ V_AddLight (ent.origin, 100, 1, 0.5, 0.5);
+ }
+ // RAFAEL
+ else if (effects & EF_BLUEHYPERBLASTER)
+ {
+ V_AddLight (ent.origin, 200, 0, 0, 1);
+ }
+ // RAFAEL
+ else if (effects & EF_PLASMA)
+ {
+ if (effects & EF_ANIM_ALLFAST)
+ {
+ CL_BlasterTrail (cent->lerp_origin, ent.origin);
+ }
+ V_AddLight (ent.origin, 130, 1, 0.5, 0.5);
+ }
+ }
+
+ VectorCopy (ent.origin, cent->lerp_origin);
+ }
+}
+
+
+
+/*
+==============
+CL_AddViewWeapon
+==============
+*/
+void CL_AddViewWeapon (player_state_t *ps, player_state_t *ops)
+{
+ entity_t gun; // view model
+ int i;
+
+ // allow the gun to be completely removed
+ if (!cl_gun->value)
+ return;
+
+ // don't draw gun if in wide angle view
+ if (ps->fov > 90)
+ return;
+
+ memset (&gun, 0, sizeof(gun));
+
+ if (gun_model)
+ gun.model = gun_model; // development tool
+ else
+ gun.model = cl.model_draw[ps->gunindex];
+ if (!gun.model)
+ return;
+
+ // set up gun position
+ for (i=0 ; i<3 ; i++)
+ {
+ gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i]
+ + cl.lerpfrac * (ps->gunoffset[i] - ops->gunoffset[i]);
+ gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->gunangles[i],
+ ps->gunangles[i], cl.lerpfrac);
+ }
+
+ if (gun_frame)
+ {
+ gun.frame = gun_frame; // development tool
+ gun.oldframe = gun_frame; // development tool
+ }
+ else
+ {
+ gun.frame = ps->gunframe;
+ if (gun.frame == 0)
+ gun.oldframe = 0; // just changed weapons, don't lerp from old
+ else
+ gun.oldframe = ops->gunframe;
+ }
+
+ gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
+ gun.backlerp = 1.0 - cl.lerpfrac;
+ VectorCopy (gun.origin, gun.oldorigin); // don't lerp at all
+ V_AddEntity (&gun);
+}
+
+
+/*
+===============
+CL_CalcViewValues
+
+Sets cl.refdef view values
+===============
+*/
+void CL_CalcViewValues (void)
+{
+ int i;
+ float lerp, backlerp;
+ frame_t *oldframe;
+ player_state_t *ps, *ops;
+
+ // find the previous frame to interpolate from
+ ps = &cl.frame.playerstate;
+ i = (cl.frame.serverframe - 1) & UPDATE_MASK;
+ oldframe = &cl.frames[i];
+ if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
+ oldframe = &cl.frame; // previous frame was dropped or involid
+ ops = &oldframe->playerstate;
+
+ // see if the player entity was teleported this frame
+ if ( fabs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256*8
+ || abs(ops->pmove.origin[1] - ps->pmove.origin[1]) > 256*8
+ || abs(ops->pmove.origin[2] - ps->pmove.origin[2]) > 256*8)
+ ops = ps; // don't interpolate
+
+ lerp = cl.lerpfrac;
+
+ // calculate the origin
+ if ((cl_predict->value) && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
+ { // use predicted values
+ unsigned delta;
+
+ backlerp = 1.0 - lerp;
+ for (i=0 ; i<3 ; i++)
+ {
+ cl.refdef.vieworg[i] = cl.predicted_origin[i] + ops->viewoffset[i]
+ + cl.lerpfrac * (ps->viewoffset[i] - ops->viewoffset[i])
+ - backlerp * cl.prediction_error[i];
+ }
+
+ // smooth out stair climbing
+ delta = cls.realtime - cl.predicted_step_time;
+ if (delta < 100)
+ cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01;
+ }
+ else
+ { // just use interpolated values
+ for (i=0 ; i<3 ; i++)
+ cl.refdef.vieworg[i] = ops->pmove.origin[i]*0.125 + ops->viewoffset[i]
+ + lerp * (ps->pmove.origin[i]*0.125 + ps->viewoffset[i]
+ - (ops->pmove.origin[i]*0.125 + ops->viewoffset[i]) );
+ }
+
+ // if not running a demo or on a locked frame, add the local angle movement
+ if ( cl.frame.playerstate.pmove.pm_type < PM_DEAD )
+ { // use predicted values
+ for (i=0 ; i<3 ; i++)
+ cl.refdef.viewangles[i] = cl.predicted_angles[i];
+ }
+ else
+ { // just use interpolated values
+ for (i=0 ; i<3 ; i++)
+ cl.refdef.viewangles[i] = LerpAngle (ops->viewangles[i], ps->viewangles[i], lerp);
+ }
+
+ for (i=0 ; i<3 ; i++)
+ cl.refdef.viewangles[i] += LerpAngle (ops->kick_angles[i], ps->kick_angles[i], lerp);
+
+ AngleVectors (cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up);
+
+ // interpolate field of view
+ cl.refdef.fov_x = ops->fov + lerp * (ps->fov - ops->fov);
+
+ // don't interpolate blend color
+ for (i=0 ; i<4 ; i++)
+ cl.refdef.blend[i] = ps->blend[i];
+
+ // add the weapon
+ CL_AddViewWeapon (ps, ops);
+}
+
+/*
+===============
+CL_AddEntities
+
+Emits all entities, particles, and lights to the refresh
+===============
+*/
+void CL_AddEntities (void)
+{
+ if (cls.state != ca_active)
+ return;
+
+ if (cl.time > cl.frame.servertime)
+ {
+ if (cl_showclamp->value)
+ Com_Printf ("high clamp %i\n", cl.time - cl.frame.servertime);
+ cl.time = cl.frame.servertime;
+ cl.lerpfrac = 1.0;
+ }
+ else if (cl.time < cl.frame.servertime - 100)
+ {
+ if (cl_showclamp->value)
+ Com_Printf ("low clamp %i\n", cl.frame.servertime-100 - cl.time);
+ cl.time = cl.frame.servertime - 100;
+ cl.lerpfrac = 0;
+ }
+ else
+ cl.lerpfrac = 1.0 - (cl.frame.servertime - cl.time) * 0.01;
+
+ if (cl_timedemo->value)
+ cl.lerpfrac = 1.0;
+
+// CL_AddPacketEntities (&cl.frame);
+// CL_AddTEnts ();
+// CL_AddParticles ();
+// CL_AddDLights ();
+// CL_AddLightStyles ();
+
+ CL_CalcViewValues ();
+ // PMM - moved this here so the heat beam has the right values for the vieworg, and can lock the beam to the gun
+ CL_AddPacketEntities (&cl.frame);
+/*
+ CL_AddProjectiles ();
+*/
+ CL_AddTEnts ();
+ CL_AddParticles ();
+ CL_AddDLights ();
+ CL_AddLightStyles ();
+}
+
+/* the sound code makes callbacks to the client for entitiy position
+ * information, so entities can be dynamically re-spatialized */
+void CL_GetEntitySoundOrigin (int ent, vec3_t org)
+{
+ centity_t *old;
+
+ if (ent < 0 || ent >= MAX_EDICTS)
+ Com_Error (ERR_DROP, "CL_GetEntitySoundOrigin: bad ent");
+ old = &cl_entities[ent];
+ VectorCopy (old->lerp_origin, org);
+
+ // FIXME: bmodel issues...
+}
--- /dev/null
+++ b/cl_fx.c
@@ -1,0 +1,2266 @@
+// cl_fx.c -- entity effects parsing and management
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+void CL_LogoutEffect (vec3_t org, int type);
+void CL_ItemRespawnParticles (vec3_t org);
+
+static vec3_t avelocities [NUMVERTEXNORMALS];
+
+extern model_t *cl_mod_smoke;
+extern model_t *cl_mod_flash;
+
+/*
+==============================================================
+
+LIGHT STYLE MANAGEMENT
+
+==============================================================
+*/
+
+typedef struct
+{
+ int length;
+ float value[3];
+ float map[MAX_QPATH];
+} clightstyle_t;
+
+clightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
+int lastofs;
+
+/*
+================
+CL_ClearLightStyles
+================
+*/
+void CL_ClearLightStyles (void)
+{
+ memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
+ lastofs = -1;
+}
+
+/*
+================
+CL_RunLightStyles
+================
+*/
+void CL_RunLightStyles (void)
+{
+ int ofs;
+ int i;
+ clightstyle_t *ls;
+
+ ofs = cl.time / 100;
+ if (ofs == lastofs)
+ return;
+ lastofs = ofs;
+
+ for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
+ {
+ if (!ls->length)
+ {
+ ls->value[0] = ls->value[1] = ls->value[2] = 1.0;
+ continue;
+ }
+ if (ls->length == 1)
+ ls->value[0] = ls->value[1] = ls->value[2] = ls->map[0];
+ else
+ ls->value[0] = ls->value[1] = ls->value[2] = ls->map[ofs%ls->length];
+ }
+}
+
+
+void CL_SetLightstyle (int i)
+{
+ char *s;
+ int j, k;
+
+ s = cl.configstrings[i+CS_LIGHTS];
+
+ j = strlen (s);
+ if (j >= MAX_QPATH)
+ Com_Error (ERR_DROP, "svc_lightstyle length=%i", j);
+
+ cl_lightstyle[i].length = j;
+
+ for (k=0 ; k<j ; k++)
+ cl_lightstyle[i].map[k] = (float)(s[k]-'a')/(float)('m'-'a');
+}
+
+/*
+================
+CL_AddLightStyles
+================
+*/
+void CL_AddLightStyles (void)
+{
+ int i;
+ clightstyle_t *ls;
+
+ for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
+ V_AddLightStyle (i, ls->value[0], ls->value[1], ls->value[2]);
+}
+
+/*
+==============================================================
+
+DLIGHT MANAGEMENT
+
+==============================================================
+*/
+
+cdlight_t cl_dlights[MAX_DLIGHTS];
+
+/*
+================
+CL_ClearDlights
+================
+*/
+void CL_ClearDlights (void)
+{
+ memset (cl_dlights, 0, sizeof(cl_dlights));
+}
+
+/*
+===============
+CL_AllocDlight
+
+===============
+*/
+cdlight_t *CL_AllocDlight (int key)
+{
+ int i;
+ cdlight_t *dl;
+
+// first look for an exact key match
+ if (key)
+ {
+ dl = cl_dlights;
+ for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+ {
+ if (dl->key == key)
+ {
+ memset (dl, 0, sizeof(*dl));
+ dl->key = key;
+ return dl;
+ }
+ }
+ }
+
+// then look for anything else
+ dl = cl_dlights;
+ for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+ {
+ if (dl->die < cl.time)
+ {
+ memset (dl, 0, sizeof(*dl));
+ dl->key = key;
+ return dl;
+ }
+ }
+
+ dl = &cl_dlights[0];
+ memset (dl, 0, sizeof(*dl));
+ dl->key = key;
+ return dl;
+}
+
+/*
+===============
+CL_NewDlight
+===============
+*/
+void CL_NewDlight (int key, float x, float y, float z, float radius, float time)
+{
+ cdlight_t *dl;
+
+ dl = CL_AllocDlight (key);
+ dl->origin[0] = x;
+ dl->origin[1] = y;
+ dl->origin[2] = z;
+ dl->radius = radius;
+ dl->die = cl.time + time;
+}
+
+
+/*
+===============
+CL_RunDLights
+
+===============
+*/
+void CL_RunDLights (void)
+{
+ int i;
+ cdlight_t *dl;
+
+ dl = cl_dlights;
+ for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+ {
+ if (!dl->radius)
+ continue;
+
+ if (dl->die < cl.time)
+ {
+ dl->radius = 0;
+ return;
+ }
+ dl->radius -= cls.frametime*dl->decay;
+ if (dl->radius < 0)
+ dl->radius = 0;
+ }
+}
+
+/*
+==============
+CL_ParseMuzzleFlash
+==============
+*/
+void CL_ParseMuzzleFlash (void)
+{
+ vec3_t fv, rv;
+ cdlight_t *dl;
+ int i, weapon;
+ centity_t *pl;
+ int silenced;
+ float volume;
+ char soundname[64];
+
+ i = MSG_ReadShort (&net_message);
+ if (i < 1 || i >= MAX_EDICTS)
+ Com_Error (ERR_DROP, "CL_ParseMuzzleFlash: bad entity");
+
+ weapon = MSG_ReadByte (&net_message);
+ silenced = weapon & MZ_SILENCED;
+ weapon &= ~MZ_SILENCED;
+
+ pl = &cl_entities[i];
+
+ dl = CL_AllocDlight (i);
+ VectorCopy (pl->current.origin, dl->origin);
+ AngleVectors (pl->current.angles, fv, rv, NULL);
+ VectorMA (dl->origin, 18, fv, dl->origin);
+ VectorMA (dl->origin, 16, rv, dl->origin);
+ if (silenced)
+ dl->radius = 100 + (rand()&31);
+ else
+ dl->radius = 200 + (rand()&31);
+ dl->minlight = 32;
+ dl->die = cl.time; // + 0.1;
+
+ if (silenced)
+ volume = 0.2;
+ else
+ volume = 1;
+
+ switch (weapon)
+ {
+ case MZ_BLASTER:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_BLUEHYPERBLASTER:
+ dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_HYPERBLASTER:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_MACHINEGUN:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+ break;
+ case MZ_SHOTGUN:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotgf1b.wav"), volume, ATTN_NORM, 0);
+ S_StartSound (NULL, i, CHAN_AUTO, S_RegisterSound("weapons/shotgr1b.wav"), volume, ATTN_NORM, 0.1);
+ break;
+ case MZ_SSHOTGUN:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/sshotf1b.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_CHAINGUN1:
+ dl->radius = 200 + (rand()&31);
+ dl->color[0] = 1;dl->color[1] = 0.25;dl->color[2] = 0;
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+ break;
+ case MZ_CHAINGUN2:
+ dl->radius = 225 + (rand()&31);
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
+ dl->die = cl.time + 0.1; // long delay
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.05);
+ break;
+ case MZ_CHAINGUN3:
+ dl->radius = 250 + (rand()&31);
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ dl->die = cl.time + 0.1; // long delay
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.033);
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.066);
+ break;
+ case MZ_RAILGUN:
+ dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/railgf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_ROCKET:
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rocklf1a.wav"), volume, ATTN_NORM, 0);
+ S_StartSound (NULL, i, CHAN_AUTO, S_RegisterSound("weapons/rocklr1b.wav"), volume, ATTN_NORM, 0.1);
+ break;
+ case MZ_GRENADE:
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0);
+ S_StartSound (NULL, i, CHAN_AUTO, S_RegisterSound("weapons/grenlr1b.wav"), volume, ATTN_NORM, 0.1);
+ break;
+ case MZ_BFG:
+ dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0);
+ break;
+
+ case MZ_LOGIN:
+ dl->color[0] = 0;dl->color[1] = 1; dl->color[2] = 0;
+ dl->die = cl.time + 1.0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+ CL_LogoutEffect (pl->current.origin, weapon);
+ break;
+ case MZ_LOGOUT:
+ dl->color[0] = 1;dl->color[1] = 0; dl->color[2] = 0;
+ dl->die = cl.time + 1.0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+ CL_LogoutEffect (pl->current.origin, weapon);
+ break;
+ case MZ_RESPAWN:
+ dl->color[0] = 1;dl->color[1] = 1; dl->color[2] = 0;
+ dl->die = cl.time + 1.0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+ CL_LogoutEffect (pl->current.origin, weapon);
+ break;
+ // RAFAEL
+ case MZ_PHALANX:
+ dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/plasshot.wav"), volume, ATTN_NORM, 0);
+ break;
+ // RAFAEL
+ case MZ_IONRIPPER:
+ dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0);
+ break;
+
+// ======================
+// PGM
+ case MZ_ETF_RIFLE:
+ dl->color[0] = 0.9;dl->color[1] = 0.7;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_SHOTGUN2:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_HEATBEAM:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ dl->die = cl.time + 100;
+// S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_BLASTER2:
+ dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
+ // FIXME - different sound for blaster2 ??
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_TRACKER:
+ // negative flashes handled the same in gl/soft until CL_AddDLights
+ dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_NUKE1:
+ dl->color[0] = 1;dl->color[1] = 0;dl->color[2] = 0;
+ dl->die = cl.time + 100;
+ break;
+ case MZ_NUKE2:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ dl->die = cl.time + 100;
+ break;
+ case MZ_NUKE4:
+ dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
+ dl->die = cl.time + 100;
+ break;
+ case MZ_NUKE8:
+ dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 1;
+ dl->die = cl.time + 100;
+ break;
+// PGM
+// ======================
+ }
+}
+
+
+/*
+==============
+CL_ParseMuzzleFlash2
+==============
+*/
+void CL_ParseMuzzleFlash2 (void)
+{
+ int ent;
+ vec3_t origin;
+ int flash_number;
+ cdlight_t *dl;
+ vec3_t forward, right;
+ char soundname[64];
+
+ ent = MSG_ReadShort (&net_message);
+ if (ent < 1 || ent >= MAX_EDICTS)
+ Com_Error (ERR_DROP, "CL_ParseMuzzleFlash2: bad entity");
+
+ flash_number = MSG_ReadByte (&net_message);
+
+ // locate the origin
+ AngleVectors (cl_entities[ent].current.angles, forward, right, NULL);
+ origin[0] = cl_entities[ent].current.origin[0] + forward[0] * monster_flash_offset[flash_number][0] + right[0] * monster_flash_offset[flash_number][1];
+ origin[1] = cl_entities[ent].current.origin[1] + forward[1] * monster_flash_offset[flash_number][0] + right[1] * monster_flash_offset[flash_number][1];
+ origin[2] = cl_entities[ent].current.origin[2] + forward[2] * monster_flash_offset[flash_number][0] + right[2] * monster_flash_offset[flash_number][1] + monster_flash_offset[flash_number][2];
+
+ dl = CL_AllocDlight (ent);
+ VectorCopy (origin, dl->origin);
+ dl->radius = 200 + (rand()&31);
+ dl->minlight = 32;
+ dl->die = cl.time; // + 0.1;
+
+ switch (flash_number)
+ {
+ case MZ2_INFANTRY_MACHINEGUN_1:
+ case MZ2_INFANTRY_MACHINEGUN_2:
+ case MZ2_INFANTRY_MACHINEGUN_3:
+ case MZ2_INFANTRY_MACHINEGUN_4:
+ case MZ2_INFANTRY_MACHINEGUN_5:
+ case MZ2_INFANTRY_MACHINEGUN_6:
+ case MZ2_INFANTRY_MACHINEGUN_7:
+ case MZ2_INFANTRY_MACHINEGUN_8:
+ case MZ2_INFANTRY_MACHINEGUN_9:
+ case MZ2_INFANTRY_MACHINEGUN_10:
+ case MZ2_INFANTRY_MACHINEGUN_11:
+ case MZ2_INFANTRY_MACHINEGUN_12:
+ case MZ2_INFANTRY_MACHINEGUN_13:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_SOLDIER_MACHINEGUN_1:
+ case MZ2_SOLDIER_MACHINEGUN_2:
+ case MZ2_SOLDIER_MACHINEGUN_3:
+ case MZ2_SOLDIER_MACHINEGUN_4:
+ case MZ2_SOLDIER_MACHINEGUN_5:
+ case MZ2_SOLDIER_MACHINEGUN_6:
+ case MZ2_SOLDIER_MACHINEGUN_7:
+ case MZ2_SOLDIER_MACHINEGUN_8:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_GUNNER_MACHINEGUN_1:
+ case MZ2_GUNNER_MACHINEGUN_2:
+ case MZ2_GUNNER_MACHINEGUN_3:
+ case MZ2_GUNNER_MACHINEGUN_4:
+ case MZ2_GUNNER_MACHINEGUN_5:
+ case MZ2_GUNNER_MACHINEGUN_6:
+ case MZ2_GUNNER_MACHINEGUN_7:
+ case MZ2_GUNNER_MACHINEGUN_8:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_ACTOR_MACHINEGUN_1:
+ case MZ2_SUPERTANK_MACHINEGUN_1:
+ case MZ2_SUPERTANK_MACHINEGUN_2:
+ case MZ2_SUPERTANK_MACHINEGUN_3:
+ case MZ2_SUPERTANK_MACHINEGUN_4:
+ case MZ2_SUPERTANK_MACHINEGUN_5:
+ case MZ2_SUPERTANK_MACHINEGUN_6:
+ case MZ2_TURRET_MACHINEGUN: // PGM
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_BOSS2_MACHINEGUN_L1:
+ case MZ2_BOSS2_MACHINEGUN_L2:
+ case MZ2_BOSS2_MACHINEGUN_L3:
+ case MZ2_BOSS2_MACHINEGUN_L4:
+ case MZ2_BOSS2_MACHINEGUN_L5:
+ case MZ2_CARRIER_MACHINEGUN_L1: // PMM
+ case MZ2_CARRIER_MACHINEGUN_L2: // PMM
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0);
+ break;
+
+ case MZ2_SOLDIER_BLASTER_1:
+ case MZ2_SOLDIER_BLASTER_2:
+ case MZ2_SOLDIER_BLASTER_3:
+ case MZ2_SOLDIER_BLASTER_4:
+ case MZ2_SOLDIER_BLASTER_5:
+ case MZ2_SOLDIER_BLASTER_6:
+ case MZ2_SOLDIER_BLASTER_7:
+ case MZ2_SOLDIER_BLASTER_8:
+ case MZ2_TURRET_BLASTER: // PGM
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck2.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_FLYER_BLASTER_1:
+ case MZ2_FLYER_BLASTER_2:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("flyer/flyatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_MEDIC_BLASTER_1:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("medic/medatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_HOVER_BLASTER_1:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("hover/hovatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_FLOAT_BLASTER_1:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("floater/fltatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_SOLDIER_SHOTGUN_1:
+ case MZ2_SOLDIER_SHOTGUN_2:
+ case MZ2_SOLDIER_SHOTGUN_3:
+ case MZ2_SOLDIER_SHOTGUN_4:
+ case MZ2_SOLDIER_SHOTGUN_5:
+ case MZ2_SOLDIER_SHOTGUN_6:
+ case MZ2_SOLDIER_SHOTGUN_7:
+ case MZ2_SOLDIER_SHOTGUN_8:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_TANK_BLASTER_1:
+ case MZ2_TANK_BLASTER_2:
+ case MZ2_TANK_BLASTER_3:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_TANK_MACHINEGUN_1:
+ case MZ2_TANK_MACHINEGUN_2:
+ case MZ2_TANK_MACHINEGUN_3:
+ case MZ2_TANK_MACHINEGUN_4:
+ case MZ2_TANK_MACHINEGUN_5:
+ case MZ2_TANK_MACHINEGUN_6:
+ case MZ2_TANK_MACHINEGUN_7:
+ case MZ2_TANK_MACHINEGUN_8:
+ case MZ2_TANK_MACHINEGUN_9:
+ case MZ2_TANK_MACHINEGUN_10:
+ case MZ2_TANK_MACHINEGUN_11:
+ case MZ2_TANK_MACHINEGUN_12:
+ case MZ2_TANK_MACHINEGUN_13:
+ case MZ2_TANK_MACHINEGUN_14:
+ case MZ2_TANK_MACHINEGUN_15:
+ case MZ2_TANK_MACHINEGUN_16:
+ case MZ2_TANK_MACHINEGUN_17:
+ case MZ2_TANK_MACHINEGUN_18:
+ case MZ2_TANK_MACHINEGUN_19:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ Com_sprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + rand() % 5);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound(soundname), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_CHICK_ROCKET_1:
+ case MZ2_TURRET_ROCKET: // PGM
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("chick/chkatck2.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_TANK_ROCKET_1:
+ case MZ2_TANK_ROCKET_2:
+ case MZ2_TANK_ROCKET_3:
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_SUPERTANK_ROCKET_1:
+ case MZ2_SUPERTANK_ROCKET_2:
+ case MZ2_SUPERTANK_ROCKET_3:
+ case MZ2_BOSS2_ROCKET_1:
+ case MZ2_BOSS2_ROCKET_2:
+ case MZ2_BOSS2_ROCKET_3:
+ case MZ2_BOSS2_ROCKET_4:
+ case MZ2_CARRIER_ROCKET_1:
+// case MZ2_CARRIER_ROCKET_2:
+// case MZ2_CARRIER_ROCKET_3:
+// case MZ2_CARRIER_ROCKET_4:
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/rocket.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_GUNNER_GRENADE_1:
+ case MZ2_GUNNER_GRENADE_2:
+ case MZ2_GUNNER_GRENADE_3:
+ case MZ2_GUNNER_GRENADE_4:
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_GLADIATOR_RAILGUN_1:
+ // PMM
+ case MZ2_CARRIER_RAILGUN:
+ case MZ2_WIDOW_RAIL:
+ // pmm
+ dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
+ break;
+
+// --- Xian's shit starts ---
+ case MZ2_MAKRON_BFG:
+ dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
+ //S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_MAKRON_BLASTER_1:
+ case MZ2_MAKRON_BLASTER_2:
+ case MZ2_MAKRON_BLASTER_3:
+ case MZ2_MAKRON_BLASTER_4:
+ case MZ2_MAKRON_BLASTER_5:
+ case MZ2_MAKRON_BLASTER_6:
+ case MZ2_MAKRON_BLASTER_7:
+ case MZ2_MAKRON_BLASTER_8:
+ case MZ2_MAKRON_BLASTER_9:
+ case MZ2_MAKRON_BLASTER_10:
+ case MZ2_MAKRON_BLASTER_11:
+ case MZ2_MAKRON_BLASTER_12:
+ case MZ2_MAKRON_BLASTER_13:
+ case MZ2_MAKRON_BLASTER_14:
+ case MZ2_MAKRON_BLASTER_15:
+ case MZ2_MAKRON_BLASTER_16:
+ case MZ2_MAKRON_BLASTER_17:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/blaster.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_JORG_MACHINEGUN_L1:
+ case MZ2_JORG_MACHINEGUN_L2:
+ case MZ2_JORG_MACHINEGUN_L3:
+ case MZ2_JORG_MACHINEGUN_L4:
+ case MZ2_JORG_MACHINEGUN_L5:
+ case MZ2_JORG_MACHINEGUN_L6:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("boss3/xfire.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_JORG_MACHINEGUN_R1:
+ case MZ2_JORG_MACHINEGUN_R2:
+ case MZ2_JORG_MACHINEGUN_R3:
+ case MZ2_JORG_MACHINEGUN_R4:
+ case MZ2_JORG_MACHINEGUN_R5:
+ case MZ2_JORG_MACHINEGUN_R6:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ break;
+
+ case MZ2_JORG_BFG_1:
+ dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
+ break;
+
+ case MZ2_BOSS2_MACHINEGUN_R1:
+ case MZ2_BOSS2_MACHINEGUN_R2:
+ case MZ2_BOSS2_MACHINEGUN_R3:
+ case MZ2_BOSS2_MACHINEGUN_R4:
+ case MZ2_BOSS2_MACHINEGUN_R5:
+ case MZ2_CARRIER_MACHINEGUN_R1: // PMM
+ case MZ2_CARRIER_MACHINEGUN_R2: // PMM
+
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ break;
+
+// ======
+// ROGUE
+ case MZ2_STALKER_BLASTER:
+ case MZ2_DAEDALUS_BLASTER:
+ case MZ2_MEDIC_BLASTER_2:
+ case MZ2_WIDOW_BLASTER:
+ case MZ2_WIDOW_BLASTER_SWEEP1:
+ case MZ2_WIDOW_BLASTER_SWEEP2:
+ case MZ2_WIDOW_BLASTER_SWEEP3:
+ case MZ2_WIDOW_BLASTER_SWEEP4:
+ case MZ2_WIDOW_BLASTER_SWEEP5:
+ case MZ2_WIDOW_BLASTER_SWEEP6:
+ case MZ2_WIDOW_BLASTER_SWEEP7:
+ case MZ2_WIDOW_BLASTER_SWEEP8:
+ case MZ2_WIDOW_BLASTER_SWEEP9:
+ case MZ2_WIDOW_BLASTER_100:
+ case MZ2_WIDOW_BLASTER_90:
+ case MZ2_WIDOW_BLASTER_80:
+ case MZ2_WIDOW_BLASTER_70:
+ case MZ2_WIDOW_BLASTER_60:
+ case MZ2_WIDOW_BLASTER_50:
+ case MZ2_WIDOW_BLASTER_40:
+ case MZ2_WIDOW_BLASTER_30:
+ case MZ2_WIDOW_BLASTER_20:
+ case MZ2_WIDOW_BLASTER_10:
+ case MZ2_WIDOW_BLASTER_0:
+ case MZ2_WIDOW_BLASTER_10L:
+ case MZ2_WIDOW_BLASTER_20L:
+ case MZ2_WIDOW_BLASTER_30L:
+ case MZ2_WIDOW_BLASTER_40L:
+ case MZ2_WIDOW_BLASTER_50L:
+ case MZ2_WIDOW_BLASTER_60L:
+ case MZ2_WIDOW_BLASTER_70L:
+ case MZ2_WIDOW_RUN_1:
+ case MZ2_WIDOW_RUN_2:
+ case MZ2_WIDOW_RUN_3:
+ case MZ2_WIDOW_RUN_4:
+ case MZ2_WIDOW_RUN_5:
+ case MZ2_WIDOW_RUN_6:
+ case MZ2_WIDOW_RUN_7:
+ case MZ2_WIDOW_RUN_8:
+ dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_WIDOW_DISRUPTOR:
+ dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_WIDOW_PLASMABEAM:
+ case MZ2_WIDOW2_BEAMER_1:
+ case MZ2_WIDOW2_BEAMER_2:
+ case MZ2_WIDOW2_BEAMER_3:
+ case MZ2_WIDOW2_BEAMER_4:
+ case MZ2_WIDOW2_BEAMER_5:
+ case MZ2_WIDOW2_BEAM_SWEEP_1:
+ case MZ2_WIDOW2_BEAM_SWEEP_2:
+ case MZ2_WIDOW2_BEAM_SWEEP_3:
+ case MZ2_WIDOW2_BEAM_SWEEP_4:
+ case MZ2_WIDOW2_BEAM_SWEEP_5:
+ case MZ2_WIDOW2_BEAM_SWEEP_6:
+ case MZ2_WIDOW2_BEAM_SWEEP_7:
+ case MZ2_WIDOW2_BEAM_SWEEP_8:
+ case MZ2_WIDOW2_BEAM_SWEEP_9:
+ case MZ2_WIDOW2_BEAM_SWEEP_10:
+ case MZ2_WIDOW2_BEAM_SWEEP_11:
+ dl->radius = 300 + (rand()&100);
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ dl->die = cl.time + 200;
+ break;
+// ROGUE
+// ======
+
+// --- Xian's shit ends ---
+
+ }
+}
+
+
+/*
+===============
+CL_AddDLights
+
+===============
+*/
+void CL_AddDLights (void)
+{
+ int i;
+ cdlight_t *dl;
+
+ dl = cl_dlights;
+
+//=====
+//PGM
+ if(vidref_val == VIDREF_GL)
+ {
+ for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+ {
+ if (!dl->radius)
+ continue;
+ V_AddLight (dl->origin, dl->radius,
+ dl->color[0], dl->color[1], dl->color[2]);
+ }
+ }
+ else
+ {
+ for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+ {
+ if (!dl->radius)
+ continue;
+
+ // negative light in software. only black allowed
+ if ((dl->color[0] < 0) || (dl->color[1] < 0) || (dl->color[2] < 0))
+ {
+ dl->radius = -(dl->radius);
+ dl->color[0] = 1;
+ dl->color[1] = 1;
+ dl->color[2] = 1;
+ }
+ V_AddLight (dl->origin, dl->radius,
+ dl->color[0], dl->color[1], dl->color[2]);
+ }
+ }
+//PGM
+//=====
+}
+
+
+
+/*
+==============================================================
+
+PARTICLE MANAGEMENT
+
+==============================================================
+*/
+
+cparticle_t *active_particles, *free_particles;
+
+cparticle_t particles[MAX_PARTICLES];
+int cl_numparticles = MAX_PARTICLES;
+
+
+/*
+===============
+CL_ClearParticles
+===============
+*/
+void CL_ClearParticles (void)
+{
+ int i;
+
+ free_particles = &particles[0];
+ active_particles = NULL;
+
+ for (i=0 ;i<cl_numparticles ; i++)
+ particles[i].next = &particles[i+1];
+ particles[cl_numparticles-1].next = NULL;
+}
+
+
+/*
+===============
+CL_ParticleEffect
+
+Wall impact puffs
+===============
+*/
+void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color + (rand()&7);
+
+ d = rand()&31;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+ p->vel[j] = crand()*20;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_ParticleEffect2
+===============
+*/
+void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color;
+
+ d = rand()&7;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+ p->vel[j] = crand()*20;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+
+// RAFAEL
+/*
+===============
+CL_ParticleEffect3
+===============
+*/
+void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color;
+
+ d = rand()&7;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+ p->vel[j] = crand()*20;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+/*
+===============
+CL_TeleporterParticles
+===============
+*/
+void CL_TeleporterParticles (entity_state_t *ent)
+{
+ int i, j;
+ cparticle_t *p;
+
+ for (i=0 ; i<8 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = 0xdb;
+
+ for (j=0 ; j<2 ; j++)
+ {
+ p->org[j] = ent->origin[j] - 16 + (rand()&31);
+ p->vel[j] = crand()*14;
+ }
+
+ p->org[2] = ent->origin[2] - 8 + (rand()&7);
+ p->vel[2] = 80 + (rand()&7);
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -0.5;
+ }
+}
+
+
+/*
+===============
+CL_LogoutEffect
+
+===============
+*/
+void CL_LogoutEffect (vec3_t org, int type)
+{
+ int i, j;
+ cparticle_t *p;
+
+ for (i=0 ; i<500 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+
+ if (type == MZ_LOGIN)
+ p->color = 0xd0 + (rand()&7); // green
+ else if (type == MZ_LOGOUT)
+ p->color = 0x40 + (rand()&7); // red
+ else
+ p->color = 0xe0 + (rand()&7); // yellow
+
+ p->org[0] = org[0] - 16 + qfrand()*32;
+ p->org[1] = org[1] - 16 + qfrand()*32;
+ p->org[2] = org[2] - 24 + qfrand()*56;
+
+ for (j=0 ; j<3 ; j++)
+ p->vel[j] = crand()*20;
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (1.0 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_ItemRespawnParticles
+
+===============
+*/
+void CL_ItemRespawnParticles (vec3_t org)
+{
+ int i, j;
+ cparticle_t *p;
+
+ for (i=0 ; i<64 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+
+ p->color = 0xd4 + (rand()&3); // green
+
+ p->org[0] = org[0] + crand()*8;
+ p->org[1] = org[1] + crand()*8;
+ p->org[2] = org[2] + crand()*8;
+
+ for (j=0 ; j<3 ; j++)
+ p->vel[j] = crand()*8;
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY*0.2;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (1.0 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_ExplosionParticles
+===============
+*/
+void CL_ExplosionParticles (vec3_t org)
+{
+ int i, j;
+ cparticle_t *p;
+
+ for (i=0 ; i<256 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = 0xe0 + (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()%32)-16);
+ p->vel[j] = (rand()%384)-192;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_BigTeleportParticles
+===============
+*/
+void CL_BigTeleportParticles (vec3_t org)
+{
+ int i;
+ cparticle_t *p;
+ float angle, dist;
+ static int colortable[4] = {2*8,13*8,21*8,18*8};
+
+ for (i=0 ; i<4096 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+
+ p->color = colortable[rand()&3];
+
+ angle = M_PI*2*(rand()&1023)/1023.0;
+ dist = rand()&31;
+ p->org[0] = org[0] + cos(angle)*dist;
+ p->vel[0] = cos(angle)*(70+(rand()&63));
+ p->accel[0] = -cos(angle)*100;
+
+ p->org[1] = org[1] + sin(angle)*dist;
+ p->vel[1] = sin(angle)*(70+(rand()&63));
+ p->accel[1] = -sin(angle)*100;
+
+ p->org[2] = org[2] + 8 + (rand()%90);
+ p->vel[2] = -100 + (rand()&31);
+ p->accel[2] = PARTICLE_GRAVITY*4;
+ p->alpha = 1.0;
+
+ p->alphavel = -0.3 / (0.5 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_BlasterParticles
+
+Wall impact puffs
+===============
+*/
+void CL_BlasterParticles (vec3_t org, vec3_t dir)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+ int count;
+
+ count = 40;
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = 0xe0 + (rand()&7);
+
+ d = rand()&15;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+ p->vel[j] = dir[j] * 30 + crand()*40;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_BlasterTrail
+
+===============
+*/
+void CL_BlasterTrail (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.3+qfrand()*0.2);
+ p->color = 0xe0;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand();
+ p->vel[j] = crand()*5;
+ p->accel[j] = 0;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+/*
+===============
+CL_QuadTrail
+
+===============
+*/
+void CL_QuadTrail (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.8+qfrand()*0.2);
+ p->color = 115;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*16;
+ p->vel[j] = crand()*5;
+ p->accel[j] = 0;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+/*
+===============
+CL_FlagTrail
+
+===============
+*/
+void CL_FlagTrail (vec3_t start, vec3_t end, float color)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.8+qfrand()*0.2);
+ p->color = color;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*16;
+ p->vel[j] = crand()*5;
+ p->accel[j] = 0;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+/*
+===============
+CL_DiminishingTrail
+
+===============
+*/
+void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ float dec;
+ float orgscale;
+ float velscale;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 0.5;
+ VectorScale (vec, dec, vec);
+
+ if (old->trailcount > 900)
+ {
+ orgscale = 4;
+ velscale = 15;
+ }
+ else if (old->trailcount > 800)
+ {
+ orgscale = 2;
+ velscale = 10;
+ }
+ else
+ {
+ orgscale = 1;
+ velscale = 5;
+ }
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+
+ // drop less particles as it flies
+ if ((rand()&1023) < old->trailcount)
+ {
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ if (flags & EF_GIB)
+ {
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.4);
+ p->color = 0xe8 + (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*orgscale;
+ p->vel[j] = crand()*velscale;
+ p->accel[j] = 0;
+ }
+ p->vel[2] -= PARTICLE_GRAVITY;
+ }
+ else if (flags & EF_GREENGIB)
+ {
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.4);
+ p->color = 0xdb + (rand()&7);
+ for (j=0; j< 3; j++)
+ {
+ p->org[j] = move[j] + crand()*orgscale;
+ p->vel[j] = crand()*velscale;
+ p->accel[j] = 0;
+ }
+ p->vel[2] -= PARTICLE_GRAVITY;
+ }
+ else
+ {
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->color = 4 + (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*orgscale;
+ p->vel[j] = crand()*velscale;
+ }
+ p->accel[2] = 20;
+ }
+ }
+
+ old->trailcount -= 5;
+ if (old->trailcount < 100)
+ old->trailcount = 100;
+ VectorAdd (move, vec, move);
+ }
+}
+
+void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up)
+{
+ float d;
+
+ // this rotate and negat guarantees a vector
+ // not colinear with the original
+ right[1] = -forward[0];
+ right[2] = forward[1];
+ right[0] = forward[2];
+
+ d = DotProduct (right, forward);
+ VectorMA (right, -d, forward, right);
+ VectorNormalize (right);
+ CrossProduct (right, forward, up);
+}
+
+/*
+===============
+CL_RocketTrail
+
+===============
+*/
+void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ float dec;
+
+ // smoke
+ CL_DiminishingTrail (start, end, old, EF_ROCKET);
+
+ // fire
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 1;
+ VectorScale (vec, dec, vec);
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+
+ if ( (rand()&7) == 0)
+ {
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ VectorClear (p->accel);
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->color = 0xdc + (rand()&3);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*5;
+ p->vel[j] = crand()*20;
+ }
+ p->accel[2] = -PARTICLE_GRAVITY;
+ }
+ VectorAdd (move, vec, move);
+ }
+}
+
+/*
+===============
+CL_RailTrail
+
+===============
+*/
+void CL_RailTrail (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ float dec;
+ vec3_t right, up;
+ int i;
+ float d, c, s;
+ vec3_t dir;
+ byte clr = 0x74;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ MakeNormalVectors (vec, right, up);
+
+ for (i=0 ; i<len ; i++)
+ {
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+
+ d = i * 0.1;
+ c = cos(d);
+ s = sin(d);
+
+ VectorScale (right, c, dir);
+ VectorMA (dir, s, up, dir);
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->color = clr + (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + dir[j]*3;
+ p->vel[j] = dir[j]*6;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+
+ dec = 0.75;
+ VectorScale (vec, dec, vec);
+ VectorCopy (start, move);
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.6+qfrand()*0.2);
+ p->color = 0x0 + rand()&15;
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*3;
+ p->vel[j] = crand()*3;
+ p->accel[j] = 0;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+// RAFAEL
+/*
+===============
+CL_IonripperTrail
+===============
+*/
+void CL_IonripperTrail (vec3_t start, vec3_t ent)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+ int left = 0;
+
+ VectorCopy (start, move);
+ VectorSubtract (ent, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+ p->alpha = 0.5;
+ p->alphavel = -1.0 / (0.3 + qfrand() * 0.2);
+ p->color = 0xe4 + (rand()&3);
+
+ for (j=0; j<3; j++)
+ {
+ p->org[j] = move[j];
+ p->accel[j] = 0;
+ }
+ if (left)
+ {
+ left = 0;
+ p->vel[0] = 10;
+ }
+ else
+ {
+ left = 1;
+ p->vel[0] = -10;
+ }
+
+ p->vel[1] = 0;
+ p->vel[2] = 0;
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+
+/*
+===============
+CL_BubbleTrail
+
+===============
+*/
+void CL_BubbleTrail (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int i, j;
+ cparticle_t *p;
+ float dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 32;
+ VectorScale (vec, dec, vec);
+
+ for (i=0 ; i<len ; i+=dec)
+ {
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ VectorClear (p->accel);
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->color = 4 + (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*2;
+ p->vel[j] = crand()*5;
+ }
+ p->vel[2] += 6;
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+
+/*
+===============
+CL_FlyParticles
+===============
+*/
+
+#define BEAMLENGTH 16
+
+void CL_FlyParticles (vec3_t origin, int count)
+{
+ int i;
+ cparticle_t *p;
+ float angle;
+ float sp, sy, cp, cy;
+ vec3_t forward;
+ float dist;
+ float ltime;
+
+
+ if (count > NUMVERTEXNORMALS)
+ count = NUMVERTEXNORMALS;
+
+ if (!avelocities[0][0])
+ {
+ for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
+ avelocities[0][i] = (rand()&255) * 0.01;
+ }
+
+
+ ltime = (float)cl.time / 1000.0;
+ for (i=0 ; i<count ; i+=2)
+ {
+ angle = ltime * avelocities[i][0];
+ sy = sin(angle);
+ cy = cos(angle);
+ angle = ltime * avelocities[i][1];
+ sp = sin(angle);
+ cp = cos(angle);
+ /*
+ angle = ltime * avelocities[i][2];
+ sr = sin(angle);
+ cr = cos(angle);
+ */
+
+ forward[0] = cp*cy;
+ forward[1] = cp*sy;
+ forward[2] = -sp;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+
+ dist = sin(ltime + i)*64;
+ p->org[0] = origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
+ p->org[1] = origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
+ p->org[2] = origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
+
+ VectorClear (p->vel);
+ VectorClear (p->accel);
+
+ p->color = 0;
+ p->colorvel = 0;
+
+ p->alpha = 1;
+ p->alphavel = -100;
+ }
+}
+
+void CL_FlyEffect (centity_t *ent, vec3_t origin)
+{
+ int n;
+ int count;
+ int starttime;
+
+ if (ent->fly_stoptime < cl.time)
+ {
+ starttime = cl.time;
+ ent->fly_stoptime = cl.time + 60000;
+ }
+ else
+ {
+ starttime = ent->fly_stoptime - 60000;
+ }
+
+ n = cl.time - starttime;
+ if (n < 20000)
+ count = n * 162 / 20000.0;
+ else
+ {
+ n = ent->fly_stoptime - cl.time;
+ if (n < 20000)
+ count = n * 162 / 20000.0;
+ else
+ count = 162;
+ }
+
+ CL_FlyParticles (origin, count);
+}
+
+
+/*
+===============
+CL_BfgParticles
+===============
+*/
+
+void CL_BfgParticles (entity_t *ent)
+{
+ int i;
+ cparticle_t *p;
+ float angle;
+ float sp, sy, cp, cy;
+ vec3_t forward;
+ float dist;
+ vec3_t v;
+ float ltime;
+
+ if (!avelocities[0][0])
+ {
+ for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
+ avelocities[0][i] = (rand()&255) * 0.01;
+ }
+
+
+ ltime = (float)cl.time / 1000.0;
+ for (i=0 ; i<NUMVERTEXNORMALS ; i++)
+ {
+ angle = ltime * avelocities[i][0];
+ sy = sin(angle);
+ cy = cos(angle);
+ angle = ltime * avelocities[i][1];
+ sp = sin(angle);
+ cp = cos(angle);
+ /*
+ angle = ltime * avelocities[i][2];
+ sr = sin(angle);
+ cr = cos(angle);
+ */
+
+ forward[0] = cp*cy;
+ forward[1] = cp*sy;
+ forward[2] = -sp;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+
+ dist = sin(ltime + i)*64;
+ p->org[0] = ent->origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
+ p->org[1] = ent->origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
+ p->org[2] = ent->origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
+
+ VectorClear (p->vel);
+ VectorClear (p->accel);
+
+ VectorSubtract (p->org, ent->origin, v);
+ dist = VectorLength(v) / 90.0;
+ p->color = floor (0xd0 + dist * 7);
+ p->colorvel = 0;
+
+ p->alpha = 1.0 - dist;
+ p->alphavel = -100;
+ }
+}
+
+
+/*
+===============
+CL_TrapParticles
+===============
+*/
+// RAFAEL
+void CL_TrapParticles (entity_t *ent)
+{
+ vec3_t move;
+ vec3_t vec;
+ vec3_t start, end;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+
+ ent->origin[2]-=14;
+ VectorCopy (ent->origin, start);
+ VectorCopy (ent->origin, end);
+ end[2]+=64;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.3+qfrand()*0.2);
+ p->color = 0xe0;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand();
+ p->vel[j] = crand()*15;
+ p->accel[j] = 0;
+ }
+ p->accel[2] = PARTICLE_GRAVITY;
+
+ VectorAdd (move, vec, move);
+ }
+
+ {
+
+
+ int i, j, k;
+ cparticle_t *p;
+ float vel;
+ vec3_t dir;
+ vec3_t org;
+
+
+ ent->origin[2]+=14;
+ VectorCopy (ent->origin, org);
+
+
+ for (i=-2 ; i<=2 ; i+=4)
+ for (j=-2 ; j<=2 ; j+=4)
+ for (k=-2 ; k<=4 ; k+=4)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = 0xe0 + (rand()&3);
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
+
+ p->org[0] = org[0] + i + ((rand()&23) * crand());
+ p->org[1] = org[1] + j + ((rand()&23) * crand());
+ p->org[2] = org[2] + k + ((rand()&23) * crand());
+
+ dir[0] = j * 8;
+ dir[1] = i * 8;
+ dir[2] = k * 8;
+
+ VectorNormalize (dir);
+ vel = 50 + rand()&63;
+ VectorScale (dir, vel, p->vel);
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ }
+ }
+}
+
+
+/*
+===============
+CL_BFGExplosionParticles
+===============
+*/
+//FIXME combined with CL_ExplosionParticles
+void CL_BFGExplosionParticles (vec3_t org)
+{
+ int i, j;
+ cparticle_t *p;
+
+ for (i=0 ; i<256 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = 0xd0 + (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()%32)-16);
+ p->vel[j] = (rand()%384)-192;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_TeleportParticles
+
+===============
+*/
+void CL_TeleportParticles (vec3_t org)
+{
+ int i, j, k;
+ cparticle_t *p;
+ float vel;
+ vec3_t dir;
+
+ for (i=-16 ; i<=16 ; i+=4)
+ for (j=-16 ; j<=16 ; j+=4)
+ for (k=-16 ; k<=32 ; k+=4)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = 7 + (rand()&7);
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
+
+ p->org[0] = org[0] + i + (rand()&3);
+ p->org[1] = org[1] + j + (rand()&3);
+ p->org[2] = org[2] + k + (rand()&3);
+
+ dir[0] = j*8;
+ dir[1] = i*8;
+ dir[2] = k*8;
+
+ VectorNormalize (dir);
+ vel = 50 + (rand()&63);
+ VectorScale (dir, vel, p->vel);
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ }
+}
+
+
+/*
+===============
+CL_AddParticles
+===============
+*/
+void CL_AddParticles (void)
+{
+ cparticle_t *p, *next;
+ float alpha;
+ float time = 0, time2;
+ vec3_t org;
+ int color;
+ cparticle_t *active, *tail;
+
+ active = NULL;
+ tail = NULL;
+
+ for (p=active_particles ; p ; p=next)
+ {
+ next = p->next;
+
+ // PMM - added INSTANT_PARTICLE handling for heat beam
+ if (p->alphavel != INSTANT_PARTICLE)
+ {
+ time = (cl.time - p->time)*0.001;
+ alpha = p->alpha + time*p->alphavel;
+ if (alpha <= 0)
+ { // faded out
+ p->next = free_particles;
+ free_particles = p;
+ continue;
+ }
+ }
+ else
+ {
+ alpha = p->alpha;
+ }
+
+ p->next = NULL;
+ if (!tail)
+ active = tail = p;
+ else
+ {
+ tail->next = p;
+ tail = p;
+ }
+
+ if (alpha > 1.0)
+ alpha = 1;
+ color = p->color;
+
+ time2 = time*time;
+
+ org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
+ org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
+ org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
+
+ V_AddParticle (org, color, alpha);
+ // PMM
+ if (p->alphavel == INSTANT_PARTICLE)
+ {
+ p->alphavel = 0.0;
+ p->alpha = 0.0;
+ }
+ }
+
+ active_particles = active;
+}
+
+
+/*
+==============
+CL_EntityEvent
+
+An entity has just been parsed that has an event value
+
+the female events are there for backwards compatability
+==============
+*/
+struct sfx_t *cl_sfx_footsteps[4];
+
+void CL_EntityEvent (entity_state_t *ent)
+{
+ switch (ent->event)
+ {
+ case EV_ITEM_RESPAWN:
+ S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("items/respawn1.wav"), 1, ATTN_IDLE, 0);
+ CL_ItemRespawnParticles (ent->origin);
+ break;
+ case EV_PLAYER_TELEPORT:
+ S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("misc/tele1.wav"), 1, ATTN_IDLE, 0);
+ CL_TeleportParticles (ent->origin);
+ break;
+ case EV_FOOTSTEP:
+ if (cl_footsteps->value)
+ S_StartSound (NULL, ent->number, CHAN_BODY, cl_sfx_footsteps[rand()&3], 1, ATTN_NORM, 0);
+ break;
+ case EV_FALLSHORT:
+ S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("player/land1.wav"), 1, ATTN_NORM, 0);
+ break;
+ case EV_FALL:
+ S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall2.wav"), 1, ATTN_NORM, 0);
+ break;
+ case EV_FALLFAR:
+ S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall1.wav"), 1, ATTN_NORM, 0);
+ break;
+ }
+}
+
+
+/*
+==============
+CL_ClearEffects
+
+==============
+*/
+void CL_ClearEffects (void)
+{
+ CL_ClearParticles ();
+ CL_ClearDlights ();
+ CL_ClearLightStyles ();
+}
--- /dev/null
+++ b/cl_input.c
@@ -1,0 +1,526 @@
+// cl.input.c -- builds an intended movement command to send to the server
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+cvar_t *cl_nodelta;
+
+unsigned frame_msec;
+unsigned old_sys_frame_time;
+
+/*
+===============================================================================
+
+KEY BUTTONS
+
+Continuous button event tracking is complicated by the fact that two different
+input sources (say, mouse button 1 and the control key) can both press the
+same button, but the button should only be released when both of the
+pressing key have been released.
+
+When a key event issues a button command (+forward, +attack, etc), it appends
+its key number as a parameter to the command so it can be matched up with
+the release.
+
+state bit 0 is the current state of the key
+state bit 1 is edge triggered on the up to down transition
+state bit 2 is edge triggered on the down to up transition
+
+
+Key_Event (int key, qboolean down, unsigned time);
+
+ +mlook src time
+
+===============================================================================
+*/
+
+
+kbutton_t in_klook;
+kbutton_t in_left, in_right, in_forward, in_back;
+kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
+kbutton_t in_strafe, in_speed, in_use, in_attack;
+kbutton_t in_up, in_down;
+
+int in_impulse;
+
+
+void KeyDown (kbutton_t *b)
+{
+ int k;
+ char *c;
+
+ c = Cmd_Argv(1);
+ if (c[0])
+ k = atoi(c);
+ else
+ k = -1; // typed manually at the console for continuous down
+
+ if (k == b->down[0] || k == b->down[1])
+ return; // repeating key
+
+ if (!b->down[0])
+ b->down[0] = k;
+ else if (!b->down[1])
+ b->down[1] = k;
+ else
+ {
+ Com_Printf ("Three keys down for a button!\n");
+ return;
+ }
+
+ if (b->state & 1)
+ return; // still down
+
+ // save timestamp
+ c = Cmd_Argv(2);
+ b->downtime = atoi(c);
+ if (!b->downtime)
+ b->downtime = sys_frame_time - 100;
+
+ b->state |= 1 + 2; // down + impulse down
+}
+
+void KeyUp (kbutton_t *b)
+{
+ int k;
+ char *c;
+ unsigned uptime;
+
+ c = Cmd_Argv(1);
+ if (c[0])
+ k = atoi(c);
+ else
+ { // typed manually at the console, assume for unsticking, so clear all
+ b->down[0] = b->down[1] = 0;
+ b->state = 4; // impulse up
+ return;
+ }
+
+ if (b->down[0] == k)
+ b->down[0] = 0;
+ else if (b->down[1] == k)
+ b->down[1] = 0;
+ else
+ return; // key up without coresponding down (menu pass through)
+ if (b->down[0] || b->down[1])
+ return; // some other key is still holding it down
+
+ if (!(b->state & 1))
+ return; // still up (this should not happen)
+
+ // save timestamp
+ c = Cmd_Argv(2);
+ uptime = atoi(c);
+ if (uptime)
+ b->msec += uptime - b->downtime;
+ else
+ b->msec += 10;
+
+ b->state &= ~1; // now up
+ b->state |= 4; // impulse up
+}
+
+void IN_KLookDown (void) {KeyDown(&in_klook);}
+void IN_KLookUp (void) {KeyUp(&in_klook);}
+void IN_UpDown(void) {KeyDown(&in_up);}
+void IN_UpUp(void) {KeyUp(&in_up);}
+void IN_DownDown(void) {KeyDown(&in_down);}
+void IN_DownUp(void) {KeyUp(&in_down);}
+void IN_LeftDown(void) {KeyDown(&in_left);}
+void IN_LeftUp(void) {KeyUp(&in_left);}
+void IN_RightDown(void) {KeyDown(&in_right);}
+void IN_RightUp(void) {KeyUp(&in_right);}
+void IN_ForwardDown(void) {KeyDown(&in_forward);}
+void IN_ForwardUp(void) {KeyUp(&in_forward);}
+void IN_BackDown(void) {KeyDown(&in_back);}
+void IN_BackUp(void) {KeyUp(&in_back);}
+void IN_LookupDown(void) {KeyDown(&in_lookup);}
+void IN_LookupUp(void) {KeyUp(&in_lookup);}
+void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
+void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
+void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
+void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
+void IN_MoverightDown(void) {KeyDown(&in_moveright);}
+void IN_MoverightUp(void) {KeyUp(&in_moveright);}
+
+void IN_SpeedDown(void) {KeyDown(&in_speed);}
+void IN_SpeedUp(void) {KeyUp(&in_speed);}
+void IN_StrafeDown(void) {KeyDown(&in_strafe);}
+void IN_StrafeUp(void) {KeyUp(&in_strafe);}
+
+void IN_AttackDown(void) {KeyDown(&in_attack);}
+void IN_AttackUp(void) {KeyUp(&in_attack);}
+
+void IN_UseDown (void) {KeyDown(&in_use);}
+void IN_UseUp (void) {KeyUp(&in_use);}
+
+void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
+
+/*
+===============
+CL_KeyState
+
+Returns the fraction of the frame that the key was down
+===============
+*/
+float CL_KeyState (kbutton_t *key)
+{
+ float val;
+ int msec;
+
+ key->state &= 1; // clear impulses
+
+ msec = key->msec;
+ key->msec = 0;
+
+ if (key->state)
+ { // still down
+ msec += sys_frame_time - key->downtime;
+ key->downtime = sys_frame_time;
+ }
+
+/*
+ if (msec)
+ {
+ Com_Printf ("%i ", msec);
+ }
+*/
+
+ val = (float)msec / frame_msec;
+ if (val < 0)
+ val = 0;
+ if (val > 1)
+ val = 1;
+
+ return val;
+}
+
+
+
+
+//==========================================================================
+
+cvar_t *cl_upspeed;
+cvar_t *cl_forwardspeed;
+cvar_t *cl_sidespeed;
+
+cvar_t *cl_yawspeed;
+cvar_t *cl_pitchspeed;
+
+cvar_t *cl_run;
+
+cvar_t *cl_anglespeedkey;
+
+
+/*
+================
+CL_AdjustAngles
+
+Moves the local angle positions
+================
+*/
+void CL_AdjustAngles (void)
+{
+ float speed;
+ float up, down;
+
+ if (in_speed.state & 1)
+ speed = cls.frametime * cl_anglespeedkey->value;
+ else
+ speed = cls.frametime;
+
+ if (!(in_strafe.state & 1))
+ {
+ cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
+ cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
+ }
+ if (in_klook.state & 1)
+ {
+ cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward);
+ cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back);
+ }
+
+ up = CL_KeyState (&in_lookup);
+ down = CL_KeyState(&in_lookdown);
+
+ cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * up;
+ cl.viewangles[PITCH] += speed*cl_pitchspeed->value * down;
+}
+
+/*
+================
+CL_BaseMove
+
+Send the intended movement message to the server
+================
+*/
+void CL_BaseMove (usercmd_t *cmd)
+{
+ CL_AdjustAngles ();
+
+ memset (cmd, 0, sizeof(*cmd));
+
+ VectorCopy (cl.viewangles, cmd->angles);
+ if (in_strafe.state & 1)
+ {
+ cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right);
+ cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left);
+ }
+
+ cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright);
+ cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft);
+
+ cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up);
+ cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down);
+
+ if (! (in_klook.state & 1) )
+ {
+ cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward);
+ cmd->forwardmove -= cl_forwardspeed->value * CL_KeyState (&in_back);
+ }
+
+//
+// adjust for speed key / running
+//
+ if ( (in_speed.state & 1) ^ (int)(cl_run->value) )
+ {
+ cmd->forwardmove *= 2;
+ cmd->sidemove *= 2;
+ cmd->upmove *= 2;
+ }
+}
+
+void CL_ClampPitch (void)
+{
+ float pitch;
+
+ pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
+ if (pitch > 180)
+ pitch -= 360;
+ if (cl.viewangles[PITCH] + pitch > 89)
+ cl.viewangles[PITCH] = 89 - pitch;
+ if (cl.viewangles[PITCH] + pitch < -89)
+ cl.viewangles[PITCH] = -89 - pitch;
+}
+
+/*
+==============
+CL_FinishMove
+==============
+*/
+void CL_FinishMove (usercmd_t *cmd)
+{
+ int ms;
+ int i;
+
+//
+// figure button bits
+//
+ if ( in_attack.state & 3 )
+ cmd->buttons |= BUTTON_ATTACK;
+ in_attack.state &= ~2;
+
+ if (in_use.state & 3)
+ cmd->buttons |= BUTTON_USE;
+ in_use.state &= ~2;
+
+ if (anykeydown && cls.key_dest == key_game)
+ cmd->buttons |= BUTTON_ANY;
+
+ // send milliseconds of time to apply the move
+ ms = cls.frametime * 1000;
+ if (ms > 250)
+ ms = 100; // time was unreasonable
+ cmd->msec = ms;
+
+ CL_ClampPitch ();
+ for (i=0 ; i<3 ; i++)
+ cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
+
+ cmd->impulse = in_impulse;
+ in_impulse = 0;
+
+// send the ambient light level at the player's current position
+ cmd->lightlevel = (byte)cl_lightlevel->value;
+}
+
+/*
+=================
+CL_CreateCmd
+=================
+*/
+usercmd_t CL_CreateCmd (void)
+{
+ usercmd_t cmd;
+
+ frame_msec = sys_frame_time - old_sys_frame_time;
+ if (frame_msec < 1)
+ frame_msec = 1;
+ if (frame_msec > 200)
+ frame_msec = 200;
+
+ // get basic movement from keyboard
+ CL_BaseMove (&cmd);
+
+ // allow mice or other external controllers to add to the move
+ IN_Move (&cmd);
+
+ CL_FinishMove (&cmd);
+
+ old_sys_frame_time = sys_frame_time;
+
+//cmd.impulse = cls.framecount;
+
+ return cmd;
+}
+
+
+void IN_CenterView (void)
+{
+ cl.viewangles[PITCH] = -SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
+}
+
+/*
+============
+CL_InitInput
+============
+*/
+void CL_InitInput (void)
+{
+ Cmd_AddCommand ("centerview",IN_CenterView);
+
+ Cmd_AddCommand ("+moveup",IN_UpDown);
+ Cmd_AddCommand ("-moveup",IN_UpUp);
+ Cmd_AddCommand ("+movedown",IN_DownDown);
+ Cmd_AddCommand ("-movedown",IN_DownUp);
+ Cmd_AddCommand ("+left",IN_LeftDown);
+ Cmd_AddCommand ("-left",IN_LeftUp);
+ Cmd_AddCommand ("+right",IN_RightDown);
+ Cmd_AddCommand ("-right",IN_RightUp);
+ Cmd_AddCommand ("+forward",IN_ForwardDown);
+ Cmd_AddCommand ("-forward",IN_ForwardUp);
+ Cmd_AddCommand ("+back",IN_BackDown);
+ Cmd_AddCommand ("-back",IN_BackUp);
+ Cmd_AddCommand ("+lookup", IN_LookupDown);
+ Cmd_AddCommand ("-lookup", IN_LookupUp);
+ Cmd_AddCommand ("+lookdown", IN_LookdownDown);
+ Cmd_AddCommand ("-lookdown", IN_LookdownUp);
+ Cmd_AddCommand ("+strafe", IN_StrafeDown);
+ Cmd_AddCommand ("-strafe", IN_StrafeUp);
+ Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
+ Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
+ Cmd_AddCommand ("+moveright", IN_MoverightDown);
+ Cmd_AddCommand ("-moveright", IN_MoverightUp);
+ Cmd_AddCommand ("+speed", IN_SpeedDown);
+ Cmd_AddCommand ("-speed", IN_SpeedUp);
+ Cmd_AddCommand ("+attack", IN_AttackDown);
+ Cmd_AddCommand ("-attack", IN_AttackUp);
+ Cmd_AddCommand ("+use", IN_UseDown);
+ Cmd_AddCommand ("-use", IN_UseUp);
+ Cmd_AddCommand ("impulse", IN_Impulse);
+ Cmd_AddCommand ("+klook", IN_KLookDown);
+ Cmd_AddCommand ("-klook", IN_KLookUp);
+
+ cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
+}
+
+
+
+/*
+=================
+CL_SendCmd
+=================
+*/
+void CL_SendCmd (void)
+{
+ sizebuf_t buf;
+ byte data[128];
+ int i;
+ usercmd_t *cmd, *oldcmd;
+ usercmd_t nullcmd;
+ int checksumIndex;
+
+ // build a command even if not connected
+
+ // save this command off for prediction
+ i = cls.netchan.outgoing_sequence & (CMD_BACKUP-1);
+ cmd = &cl.cmds[i];
+ cl.cmd_time[i] = cls.realtime; // for netgraph ping calculation
+
+ *cmd = CL_CreateCmd ();
+
+ cl.cmd = *cmd;
+
+ if (cls.state == ca_disconnected || cls.state == ca_connecting)
+ return;
+
+ if ( cls.state == ca_connected)
+ {
+ if (cls.netchan.message.cursize || curtime - cls.netchan.last_sent > 1000 )
+ Netchan_Transmit (&cls.netchan, 0, buf.data);
+ return;
+ }
+
+ // send a userinfo update if needed
+ if (userinfo_modified)
+ {
+ CL_FixUpGender();
+ userinfo_modified = false;
+ MSG_WriteByte (&cls.netchan.message, clc_userinfo);
+ MSG_WriteString (&cls.netchan.message, Cvar_Userinfo() );
+ }
+
+ SZ_Init (&buf, data, sizeof(data));
+
+ if (cmd->buttons && cl.cinematictime > 0 && !cl.attractloop
+ && cls.realtime - cl.cinematictime > 1000)
+ { // skip the rest of the cinematic
+ SCR_FinishCinematic ();
+ }
+
+ // begin a client move command
+ MSG_WriteByte (&buf, clc_move);
+
+ // save the position for a checksum byte
+ checksumIndex = buf.cursize;
+ MSG_WriteByte (&buf, 0);
+
+ // let the server know what the last frame we
+ // got was, so the next message can be delta compressed
+ if (cl_nodelta->value || !cl.frame.valid || cls.demowaiting)
+ MSG_WriteLong (&buf, -1); // no compression
+ else
+ MSG_WriteLong (&buf, cl.frame.serverframe);
+
+ // send this and the previous cmds in the message, so
+ // if the last packet was dropped, it can be recovered
+ i = (cls.netchan.outgoing_sequence-2) & (CMD_BACKUP-1);
+ cmd = &cl.cmds[i];
+ memset (&nullcmd, 0, sizeof(nullcmd));
+ MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd);
+ oldcmd = cmd;
+
+ i = (cls.netchan.outgoing_sequence-1) & (CMD_BACKUP-1);
+ cmd = &cl.cmds[i];
+ MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
+ oldcmd = cmd;
+
+ i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP-1);
+ cmd = &cl.cmds[i];
+ MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
+
+ // calculate a checksum over the move commands
+ buf.data[checksumIndex] = COM_BlockSequenceCRCByte(
+ buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,
+ cls.netchan.outgoing_sequence);
+
+ //
+ // deliver the message
+ //
+ Netchan_Transmit (&cls.netchan, buf.cursize, buf.data);
+}
+
+
--- /dev/null
+++ b/cl_inv.c
@@ -1,0 +1,127 @@
+// cl_inv.c -- client inventory screen
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+================
+CL_ParseInventory
+================
+*/
+void CL_ParseInventory (void)
+{
+ int i;
+
+ for (i=0 ; i<MAX_ITEMS ; i++)
+ cl.inventory[i] = MSG_ReadShort (&net_message);
+}
+
+
+/*
+================
+Inv_DrawString
+================
+*/
+void Inv_DrawString (int x, int y, char *string)
+{
+ while (*string)
+ {
+ re.DrawChar (x, y, *string);
+ x+=8;
+ string++;
+ }
+}
+
+void SetStringHighBit (char *s)
+{
+ while (*s)
+ *s++ |= 128;
+}
+
+/*
+================
+CL_DrawInventory
+================
+*/
+#define DISPLAY_ITEMS 17
+
+void CL_DrawInventory (void)
+{
+ int i, j;
+ int num, selected_num, item;
+ int index[MAX_ITEMS];
+ char string[1024];
+ int x, y;
+ char binding[1024];
+ char *bind;
+ int selected;
+ int top;
+
+ selected = cl.frame.playerstate.stats[STAT_SELECTED_ITEM];
+
+ num = 0;
+ selected_num = 0;
+ for (i=0 ; i<MAX_ITEMS ; i++)
+ {
+ if (i==selected)
+ selected_num = num;
+ if (cl.inventory[i])
+ {
+ index[num] = i;
+ num++;
+ }
+ }
+
+ // determine scroll point
+ top = selected_num - DISPLAY_ITEMS/2;
+ if (num - top < DISPLAY_ITEMS)
+ top = num - DISPLAY_ITEMS;
+ if (top < 0)
+ top = 0;
+
+ x = (vid.width-256)/2;
+ y = (vid.height-240)/2;
+
+ // repaint everything next frame
+ SCR_DirtyScreen ();
+
+ re.DrawPic (x, y+8, "inventory");
+
+ y += 24;
+ x += 24;
+ Inv_DrawString (x, y, "hotkey ### item");
+ Inv_DrawString (x, y+8, "------ --- ----");
+ y += 16;
+ for (i=top ; i<num && i < top+DISPLAY_ITEMS ; i++)
+ {
+ item = index[i];
+ // search for a binding
+ Com_sprintf (binding, sizeof(binding), "use %s", cl.configstrings[CS_ITEMS+item]);
+ bind = "";
+ for (j=0 ; j<256 ; j++)
+ if (keybindings[j] && !cistrcmp (keybindings[j], binding))
+ {
+ bind = Key_KeynumToString(j);
+ break;
+ }
+
+ Com_sprintf (string, sizeof(string), "%6s %3i %s", bind, cl.inventory[item],
+ cl.configstrings[CS_ITEMS+item] );
+ if (item != selected)
+ SetStringHighBit (string);
+ else // draw a blinky cursor by the selected item
+ {
+ if ( (int)(cls.realtime*10) & 1)
+ re.DrawChar (x-8, y, 15);
+ }
+ Inv_DrawString (x, y, string);
+ y += 8;
+ }
+
+
+}
+
+
--- /dev/null
+++ b/cl_main.c
@@ -1,0 +1,1773 @@
+// cl_main.c -- client main loop
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+cvar_t *adr0;
+cvar_t *adr1;
+cvar_t *adr2;
+cvar_t *adr3;
+cvar_t *adr4;
+cvar_t *adr5;
+cvar_t *adr6;
+cvar_t *adr7;
+cvar_t *adr8;
+
+cvar_t *cl_stereo_separation;
+cvar_t *cl_stereo;
+
+cvar_t *rcon_client_password;
+cvar_t *rcon_address;
+
+cvar_t *cl_noskins;
+cvar_t *cl_autoskins;
+cvar_t *cl_footsteps;
+cvar_t *cl_timeout;
+cvar_t *cl_predict;
+//cvar_t *cl_minfps;
+cvar_t *cl_maxfps;
+cvar_t *cl_gun;
+
+cvar_t *cl_add_particles;
+cvar_t *cl_add_lights;
+cvar_t *cl_add_entities;
+cvar_t *cl_add_blend;
+
+cvar_t *cl_shownet;
+cvar_t *cl_showmiss;
+cvar_t *cl_showclamp;
+
+cvar_t *cl_paused;
+cvar_t *cl_timedemo;
+
+cvar_t *cl_lightlevel;
+
+//
+// userinfo
+//
+cvar_t *info_password;
+cvar_t *info_spectator;
+cvar_t *name;
+cvar_t *skin;
+cvar_t *rate;
+cvar_t *fov;
+cvar_t *msg;
+cvar_t *hand;
+cvar_t *gender;
+cvar_t *gender_auto;
+
+cvar_t *cl_vwep;
+
+client_static_t cls;
+client_state_t cl;
+
+centity_t cl_entities[MAX_EDICTS];
+
+entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
+
+extern cvar_t *allow_download;
+extern cvar_t *allow_download_players;
+extern cvar_t *allow_download_models;
+extern cvar_t *allow_download_sounds;
+extern cvar_t *allow_download_maps;
+
+//======================================================================
+
+
+/*
+====================
+CL_WriteDemoMessage
+
+Dumps the current net message, prefixed by the length
+====================
+*/
+void CL_WriteDemoMessage (void)
+{
+ int len, swlen;
+
+ // the first eight bytes are just packet sequencing stuff
+ len = net_message.cursize-8;
+ swlen = LittleLong(len);
+ fwrite (&swlen, 4, 1, cls.demofile);
+ fwrite (net_message.data+8, len, 1, cls.demofile);
+}
+
+
+/*
+====================
+CL_Stop_f
+
+stop recording a demo
+====================
+*/
+void CL_Stop_f (void)
+{
+ int len;
+
+ if (!cls.demorecording)
+ {
+ Com_Printf ("Not recording a demo.\n");
+ return;
+ }
+
+// finish up
+ len = -1;
+ fwrite (&len, 4, 1, cls.demofile);
+ fclose (cls.demofile);
+ cls.demofile = NULL;
+ cls.demorecording = false;
+ Com_Printf ("Stopped demo.\n");
+}
+
+/*
+====================
+CL_Record_f
+
+record <demoname>
+
+Begins recording a demo from the current position
+====================
+*/
+void CL_Record_f (void)
+{
+ char name[MAX_OSPATH];
+ char buf_data[MAX_MSGLEN];
+ sizebuf_t buf;
+ int i;
+ int len;
+ entity_state_t *ent;
+ entity_state_t nullstate;
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("record <demoname>\n");
+ return;
+ }
+
+ if (cls.demorecording)
+ {
+ Com_Printf ("Already recording.\n");
+ return;
+ }
+
+ if (cls.state != ca_active)
+ {
+ Com_Printf ("You must be in a level to record.\n");
+ return;
+ }
+
+ //
+ // open the demo file
+ //
+ Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
+
+ Com_Printf ("recording to %s.\n", name);
+ FS_CreatePath (name);
+ cls.demofile = fopen (name, "wb");
+ if (!cls.demofile)
+ {
+ Com_Printf ("ERROR: couldn't open.\n");
+ return;
+ }
+ cls.demorecording = true;
+
+ // don't start saving messages until a non-delta compressed message is received
+ cls.demowaiting = true;
+
+ //
+ // write out messages to hold the startup information
+ //
+ SZ_Init (&buf, (uchar *)buf_data, sizeof(buf_data));
+
+ // send the serverdata
+ MSG_WriteByte (&buf, svc_serverdata);
+ MSG_WriteLong (&buf, PROTOCOL_VERSION);
+ MSG_WriteLong (&buf, 0x10000 + cl.servercount);
+ MSG_WriteByte (&buf, 1); // demos are always attract loops
+ MSG_WriteString (&buf, cl.gamedir);
+ MSG_WriteShort (&buf, cl.playernum);
+
+ MSG_WriteString (&buf, cl.configstrings[CS_NAME]);
+
+ // configstrings
+ for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
+ {
+ if (cl.configstrings[i][0])
+ {
+ if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
+ { // write it out
+ len = LittleLong (buf.cursize);
+ fwrite (&len, 4, 1, cls.demofile);
+ fwrite (buf.data, buf.cursize, 1, cls.demofile);
+ buf.cursize = 0;
+ }
+
+ MSG_WriteByte (&buf, svc_configstring);
+ MSG_WriteShort (&buf, i);
+ MSG_WriteString (&buf, cl.configstrings[i]);
+ }
+
+ }
+
+ // baselines
+ memset (&nullstate, 0, sizeof(nullstate));
+ for (i=0; i<MAX_EDICTS ; i++)
+ {
+ ent = &cl_entities[i].baseline;
+ if (!ent->modelindex)
+ continue;
+
+ if (buf.cursize + 64 > buf.maxsize)
+ { // write it out
+ len = LittleLong (buf.cursize);
+ fwrite (&len, 4, 1, cls.demofile);
+ fwrite (buf.data, buf.cursize, 1, cls.demofile);
+ buf.cursize = 0;
+ }
+
+ MSG_WriteByte (&buf, svc_spawnbaseline);
+ MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
+ }
+
+ MSG_WriteByte (&buf, svc_stufftext);
+ MSG_WriteString (&buf, "precache\n");
+
+ // write it to the demo file
+
+ len = LittleLong (buf.cursize);
+ fwrite (&len, 4, 1, cls.demofile);
+ fwrite (buf.data, buf.cursize, 1, cls.demofile);
+
+ // the rest of the demo file will be individual frames
+}
+
+/* adds the current command line as a clc_stringcmd to the client message.
+ * things like godmode, noclip, etc, are commands directed to the server, so
+ * when they are typed in at the console, they will need to be forwarded. */
+void Cmd_ForwardToServer (void)
+{
+ char *cmd;
+
+ cmd = Cmd_Argv(0);
+ if(cls.state <= ca_connected || *cmd == '-' || *cmd == '+'){
+ Com_Printf("Unknown command \"%s\"\n", cmd);
+ return;
+ }
+
+ MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
+ SZ_Print(&cls.netchan.message, cmd);
+ if(Cmd_Argc() > 1){
+ SZ_Print(&cls.netchan.message, " ");
+ SZ_Print(&cls.netchan.message, Cmd_Args());
+ }
+}
+
+void
+CL_Setenv_f(void)
+{
+ int i, l = 0, argc;
+ char name[1024], val[1024], *env;
+
+ argc = Cmd_Argc();
+
+ if(argc > 2){
+ strncpy(name, Cmd_Argv(1), sizeof name);
+ for(i = 2; i < argc; i++){
+ strncpy(val+l, Cmd_Argv(i), sizeof(name) - l - 2);
+ val[sizeof(val)-2] = 0;
+ strcat(val, " ");
+ l = strlen(val);
+ }
+ putenv(name, val);
+ }else if(argc == 2){
+ env = getenv(Cmd_Argv(1));
+ if(env){
+ Com_Printf("%s=%s\n", Cmd_Argv(1), env);
+ free(env);
+ }else
+ Com_Printf("%s undefined\n", Cmd_Argv(1), env);
+ }
+}
+
+void
+CL_ForwardToServer_f(void)
+{
+ if(cls.state != ca_connected && cls.state != ca_active){
+ Com_Printf("Can't \"%s\", not connected\n", Cmd_Argv(0));
+ return;
+ }
+ /* don't forward the first argument */
+ if(Cmd_Argc() > 1){
+ MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
+ SZ_Print(&cls.netchan.message, Cmd_Args());
+ }
+}
+
+
+/*
+==================
+CL_Pause_f
+==================
+*/
+void CL_Pause_f (void)
+{
+ // never pause in multiplayer
+ if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
+ {
+ Cvar_SetValue ("paused", 0);
+ return;
+ }
+
+ Cvar_SetValue ("paused", !cl_paused->value);
+}
+
+/*
+==================
+CL_Quit_f
+==================
+*/
+void CL_Quit_f (void)
+{
+ CL_Disconnect ();
+ Com_Quit ();
+}
+
+/*
+================
+CL_Drop
+
+Called after an ERR_DROP was thrown
+================
+*/
+void CL_Drop (void)
+{
+ if (cls.state == ca_uninitialized)
+ return;
+ if (cls.state == ca_disconnected)
+ return;
+
+ CL_Disconnect ();
+
+ // drop loading plaque unless this is the initial game start
+ if (cls.disable_servercount != -1)
+ SCR_EndLoadingPlaque (); // get rid of loading plaque
+}
+
+
+/*
+=======================
+CL_SendConnectPacket
+
+We have gotten a challenge from the server, so try and
+connect.
+======================
+*/
+void CL_SendConnectPacket (void)
+{
+ netadr_t adr;
+ int port;
+
+ if (!NET_StringToAdr (cls.servername, &adr))
+ {
+ Com_Printf ("Bad server address\n");
+ cls.connect_time = 0;
+ return;
+ }
+ if (adr.port == 0)
+ adr.port = BigShort (PORT_SERVER);
+
+ port = Cvar_VariableValue ("qport");
+ userinfo_modified = false;
+
+ Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n",
+ PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );
+}
+
+/*
+=================
+CL_CheckForResend
+
+Resend a connect message if the last one has timed out
+=================
+*/
+void CL_CheckForResend (void)
+{
+ netadr_t adr;
+
+ // if the local server is running and we aren't
+ // then connect
+ if (cls.state == ca_disconnected && Com_ServerState() )
+ {
+ cls.state = ca_connecting;
+ strncpy (cls.servername, "localhost", sizeof(cls.servername)-1);
+ // we don't need a challenge on the localhost
+ CL_SendConnectPacket ();
+ return;
+// cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
+ }
+
+ // resend if we haven't gotten a reply yet
+ if (cls.state != ca_connecting)
+ return;
+
+ if (cls.realtime - cls.connect_time < 3000)
+ return;
+
+ if (!NET_StringToAdr (cls.servername, &adr))
+ {
+ Com_Printf ("Bad server address\n");
+ cls.state = ca_disconnected;
+ return;
+ }
+ if (adr.port == 0)
+ adr.port = BigShort (PORT_SERVER);
+
+ cls.connect_time = cls.realtime; // for retransmit requests
+
+ Com_Printf ("Connecting to %s...\n", cls.servername);
+
+ Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
+}
+
+
+/*
+================
+CL_Connect_f
+
+================
+*/
+void CL_Connect_f (void)
+{
+ char *server;
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("usage: connect <server>\n");
+ return;
+ }
+
+ if (Com_ServerState ())
+ { // if running a local server, kill it and reissue
+ SV_Shutdown (va("Server quit\n", msg), false);
+ }
+ else
+ {
+ CL_Disconnect ();
+ }
+
+ server = Cmd_Argv (1);
+
+ NET_Config (true); // allow remote
+
+ CL_Disconnect ();
+
+ cls.state = ca_connecting;
+ strncpy (cls.servername, server, sizeof(cls.servername)-1);
+ cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
+}
+
+
+/*
+=====================
+CL_Rcon_f
+
+ Send the rest of the command line over as
+ an unconnected command.
+=====================
+*/
+void CL_Rcon_f (void)
+{
+ char message[1024];
+ int i;
+ netadr_t to;
+
+ if (!rcon_client_password->string)
+ {
+ Com_Printf ("You must set 'rcon_password' before\n"
+ "issuing an rcon command.\n");
+ return;
+ }
+
+ message[0] = (char)255;
+ message[1] = (char)255;
+ message[2] = (char)255;
+ message[3] = (char)255;
+ message[4] = 0;
+
+ NET_Config (true); // allow remote
+
+ strcat (message, "rcon ");
+
+ strcat (message, rcon_client_password->string);
+ strcat (message, " ");
+
+ for (i=1 ; i<Cmd_Argc() ; i++)
+ {
+ strcat (message, Cmd_Argv(i));
+ strcat (message, " ");
+ }
+
+ if (cls.state >= ca_connected)
+ to = cls.netchan.remote_address;
+ else
+ {
+ if (!strlen(rcon_address->string))
+ {
+ Com_Printf ("You must either be connected,\n"
+ "or set the 'rcon_address' cvar\n"
+ "to issue rcon commands\n");
+
+ return;
+ }
+ NET_StringToAdr (rcon_address->string, &to);
+ if (to.port == 0)
+ to.port = BigShort (PORT_SERVER);
+ }
+
+ NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
+}
+
+
+/*
+=====================
+CL_ClearState
+
+=====================
+*/
+void CL_ClearState (void)
+{
+ S_StopAllSounds ();
+ CL_ClearEffects ();
+ CL_ClearTEnts ();
+
+// wipe the entire cl structure
+ memset (&cl, 0, sizeof(cl));
+ memset (cl_entities, 0, sizeof(cl_entities));
+
+ SZ_Clear (&cls.netchan.message);
+
+}
+
+/*
+=====================
+CL_Disconnect
+
+Goes from a connected state to full screen console state
+Sends a disconnect message to the server
+This is also called on Com_Error, so it shouldn't cause any errors
+=====================
+*/
+void CL_Disconnect (void)
+{
+ byte final[32];
+
+ if (cls.state == ca_disconnected)
+ return;
+
+ if (cl_timedemo && cl_timedemo->value)
+ {
+ int time;
+
+ time = Sys_Milliseconds () - cl.timedemo_start;
+ if (time > 0)
+ Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
+ time/1000.0, cl.timedemo_frames*1000.0 / time);
+ }
+
+ VectorClear (cl.refdef.blend);
+ re.CinematicSetPalette(NULL);
+
+ M_ForceMenuOff ();
+
+ cls.connect_time = 0;
+
+ SCR_StopCinematic ();
+
+ if (cls.demorecording)
+ CL_Stop_f ();
+
+ // send a disconnect message to the server
+ final[0] = clc_stringcmd;
+ strcpy ((char *)final+1, "disconnect");
+ Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
+ Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
+ Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
+
+ CL_ClearState ();
+
+ // stop download
+ if (cls.download) {
+ fclose(cls.download);
+ cls.download = NULL;
+ }
+
+ cls.state = ca_disconnected;
+}
+
+void CL_Disconnect_f (void)
+{
+ Com_Error (ERR_DROP, "Disconnected from server");
+}
+
+
+/*
+====================
+CL_Packet_f
+
+packet <destination> <contents>
+
+Contents allows \n escape character
+====================
+*/
+void CL_Packet_f (void)
+{
+ char send[2048];
+ int i, l;
+ char *in, *out;
+ netadr_t adr;
+
+ if (Cmd_Argc() != 3)
+ {
+ Com_Printf ("packet <destination> <contents>\n");
+ return;
+ }
+
+ NET_Config (true); // allow remote
+
+ if (!NET_StringToAdr (Cmd_Argv(1), &adr))
+ {
+ Com_Printf ("Bad address\n");
+ return;
+ }
+ if (!adr.port)
+ adr.port = BigShort (PORT_SERVER);
+
+ in = Cmd_Argv(2);
+ out = send+4;
+ send[0] = send[1] = send[2] = send[3] = (char)0xff;
+
+ l = strlen (in);
+ for (i=0 ; i<l ; i++)
+ {
+ if (in[i] == '\\' && in[i+1] == 'n')
+ {
+ *out++ = '\n';
+ i++;
+ }
+ else
+ *out++ = in[i];
+ }
+ *out = 0;
+
+ NET_SendPacket (NS_CLIENT, out-send, send, adr);
+}
+
+/*
+=================
+CL_Changing_f
+
+Just sent as a hint to the client that they should
+drop to full console
+=================
+*/
+void CL_Changing_f (void)
+{
+ //ZOID
+ //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
+ if (cls.download)
+ return;
+
+ SCR_BeginLoadingPlaque ();
+ cls.state = ca_connected; // not active anymore, but not disconnected
+ Com_Printf ("\nChanging map...\n");
+}
+
+
+/*
+=================
+CL_Reconnect_f
+
+The server is changing levels
+=================
+*/
+void CL_Reconnect_f (void)
+{
+ //ZOID
+ //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
+ if (cls.download)
+ return;
+
+ S_StopAllSounds ();
+ if (cls.state == ca_connected) {
+ Com_Printf ("reconnecting...\n");
+ cls.state = ca_connected;
+ MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
+ MSG_WriteString (&cls.netchan.message, "new");
+ return;
+ }
+
+ if (*cls.servername) {
+ if (cls.state >= ca_connected) {
+ CL_Disconnect();
+ cls.connect_time = cls.realtime - 1500;
+ } else
+ cls.connect_time = -99999; // fire immediately
+
+ cls.state = ca_connecting;
+ Com_Printf ("reconnecting...\n");
+ }
+}
+
+/*
+=================
+CL_ParseStatusMessage
+
+Handle a reply from a ping
+=================
+*/
+void CL_ParseStatusMessage (void)
+{
+ char *s;
+
+ s = MSG_ReadString(&net_message);
+
+ Com_Printf ("%s\n", s);
+ M_AddToServerList (net_from, s);
+}
+
+
+/*
+=================
+CL_PingServers_f
+=================
+*/
+void CL_PingServers_f (void)
+{
+ int i;
+ netadr_t adr;
+ char name[32];
+ char *adrstring;
+ cvar_t *noudp;
+ cvar_t *noipx;
+
+ NET_Config (true); // allow remote
+
+ // send a broadcast packet
+ Com_Printf ("pinging broadcast...\n");
+
+ noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
+ if (!noudp->value)
+ {
+ adr.type = NA_BROADCAST;
+ adr.port = BigShort(PORT_SERVER);
+ Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
+ }
+
+ noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
+ if (!noipx->value)
+ {
+ adr.type = NA_BROADCAST_IPX;
+ adr.port = BigShort(PORT_SERVER);
+ Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
+ }
+
+ // send a packet to each address book entry
+ for (i=0 ; i<16 ; i++)
+ {
+ Com_sprintf (name, sizeof(name), "adr%i", i);
+ adrstring = Cvar_VariableString (name);
+ if (!adrstring || !adrstring[0])
+ continue;
+
+ Com_Printf ("pinging %s...\n", adrstring);
+ if (!NET_StringToAdr (adrstring, &adr))
+ {
+ Com_Printf ("Bad address: %s\n", adrstring);
+ continue;
+ }
+ if (!adr.port)
+ adr.port = BigShort(PORT_SERVER);
+ Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
+ }
+}
+
+
+/*
+=================
+CL_Skins_f
+
+Load or download any custom player skins and models
+=================
+*/
+void CL_Skins_f (void)
+{
+ int i;
+
+ for (i=0 ; i<MAX_CLIENTS ; i++)
+ {
+ if (!cl.configstrings[CS_PLAYERSKINS+i][0])
+ continue;
+ Com_Printf ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]);
+ SCR_UpdateScreen ();
+ Sys_SendKeyEvents (); // pump message loop
+ CL_ParseClientinfo (i);
+ }
+}
+
+
+/*
+=================
+CL_ConnectionlessPacket
+
+Responses to broadcasts, etc
+=================
+*/
+void CL_ConnectionlessPacket (void)
+{
+ char *s;
+ char *c;
+
+ MSG_BeginReading (&net_message);
+ MSG_ReadLong (&net_message); // skip the -1
+
+ s = MSG_ReadStringLine (&net_message);
+
+ Cmd_TokenizeString (s, false);
+
+ c = Cmd_Argv(0);
+
+ Com_Printf ("%s: %s\n", NET_AdrToString (net_from), c);
+
+ // server connection
+ if (!strcmp(c, "client_connect"))
+ {
+ if (cls.state == ca_connected)
+ {
+ Com_Printf ("Dup connect received. Ignored.\n");
+ return;
+ }
+ Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
+ MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
+ MSG_WriteString (&cls.netchan.message, "new");
+ cls.state = ca_connected;
+ return;
+ }
+
+ // server responding to a status broadcast
+ if (!strcmp(c, "info"))
+ {
+ CL_ParseStatusMessage ();
+ return;
+ }
+
+ // remote command from gui front end
+ if (!strcmp(c, "cmd"))
+ {
+ if (!NET_IsLocalAddress(net_from))
+ {
+ Com_Printf ("Command packet from remote host. Ignored.\n");
+ return;
+ }
+ Sys_AppActivate ();
+ s = MSG_ReadString (&net_message);
+ Cbuf_AddText (s);
+ Cbuf_AddText ("\n");
+ return;
+ }
+ // print command from somewhere
+ if (!strcmp(c, "print"))
+ {
+ s = MSG_ReadString (&net_message);
+ Com_Printf ("%s", s);
+ return;
+ }
+
+ // ping from somewhere
+ if (!strcmp(c, "ping"))
+ {
+ Netchan_OutOfBandPrint (NS_CLIENT, net_from, "ack");
+ return;
+ }
+
+ // challenge from the server we are connecting to
+ if (!strcmp(c, "challenge"))
+ {
+ cls.challenge = atoi(Cmd_Argv(1));
+ CL_SendConnectPacket ();
+ return;
+ }
+
+ // echo request from server
+ if (!strcmp(c, "echo"))
+ {
+ Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
+ return;
+ }
+
+ Com_Printf ("Unknown command.\n");
+}
+
+
+/*
+=================
+CL_DumpPackets
+
+A vain attempt to help bad TCP stacks that cause problems
+when they overflow
+=================
+*/
+void CL_DumpPackets (void)
+{
+ while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
+ {
+ Com_Printf ("dumnping a packet\n");
+ }
+}
+
+/*
+=================
+CL_ReadPackets
+=================
+*/
+void CL_ReadPackets (void)
+{
+ while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
+ {
+// Com_Printf ("packet\n");
+ //
+ // remote command packet
+ //
+ if (*(int *)net_message.data == -1)
+ {
+ CL_ConnectionlessPacket ();
+ continue;
+ }
+
+ if (cls.state == ca_disconnected || cls.state == ca_connecting)
+ continue; // dump it if not connected
+
+ if (net_message.cursize < 8)
+ {
+ Com_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
+ continue;
+ }
+
+ //
+ // packet from server
+ //
+ if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
+ {
+ Com_DPrintf ("%s:sequenced packet without connection\n"
+ ,NET_AdrToString(net_from));
+ continue;
+ }
+ if (!Netchan_Process(&cls.netchan, &net_message))
+ continue; // wasn't accepted for some reason
+ CL_ParseServerMessage ();
+ }
+
+ //
+ // check timeout
+ //
+ if (cls.state >= ca_connected
+ && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000)
+ {
+ if (++cl.timeoutcount > 5) // timeoutcount saves debugger
+ {
+ Com_Printf ("\nServer connection timed out.\n");
+ CL_Disconnect ();
+ return;
+ }
+ }
+ else
+ cl.timeoutcount = 0;
+
+}
+
+
+//=============================================================================
+
+/*
+==============
+CL_FixUpGender_f
+==============
+*/
+void CL_FixUpGender(void)
+{
+ char *p;
+ char sk[80];
+
+ if (gender_auto->value) {
+
+ if (gender->modified) {
+ // was set directly, don't override the user
+ gender->modified = false;
+ return;
+ }
+
+ strncpy(sk, skin->string, sizeof(sk) - 1);
+ if ((p = strchr(sk, '/')) != NULL)
+ *p = 0;
+ if (cistrcmp(sk, "male") == 0 || cistrcmp(sk, "cyborg") == 0)
+ Cvar_Set ("gender", "male");
+ else if (cistrcmp(sk, "female") == 0 || cistrcmp(sk, "crackhor") == 0)
+ Cvar_Set ("gender", "female");
+ else
+ Cvar_Set ("gender", "none");
+ gender->modified = false;
+ }
+}
+
+/*
+==============
+CL_Userinfo_f
+==============
+*/
+void CL_Userinfo_f (void)
+{
+ Com_Printf ("User info settings:\n");
+ Info_Print (Cvar_Userinfo());
+}
+
+/*
+=================
+CL_Snd_Restart_f
+
+Restart the sound subsystem so it can pick up
+new parameters and flush all sounds
+=================
+*/
+void CL_Snd_Restart_f (void)
+{
+ S_Shutdown ();
+ S_Init ();
+ CL_RegisterSounds ();
+}
+
+int precache_check; // for autodownload of precache items
+int precache_spawncount;
+int precache_tex;
+int precache_model_skin;
+
+byte *precache_model; // used for skin checking in alias models
+
+#define PLAYER_MULT 5
+
+// ENV_CNT is map load, ENV_CNT+1 is first env map
+#define ENV_CNT (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
+#define TEXTURE_CNT (ENV_CNT+13)
+
+static char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+
+void CL_RequestNextDownload (void)
+{
+ unsigned map_checksum; // for detecting cheater maps
+ char fn[MAX_OSPATH];
+ dmdl_t *pheader;
+
+ if (cls.state != ca_connected)
+ return;
+
+ if (!allow_download->value && precache_check < ENV_CNT)
+ precache_check = ENV_CNT;
+
+//ZOID
+ if (precache_check == CS_MODELS) { // confirm map
+ precache_check = CS_MODELS+2; // 0 isn't used
+ if (allow_download_maps->value)
+ if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
+ return; // started a download
+ }
+ if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS) {
+ if (allow_download_models->value) {
+ while (precache_check < CS_MODELS+MAX_MODELS &&
+ cl.configstrings[precache_check][0]) {
+ if (cl.configstrings[precache_check][0] == '*' ||
+ cl.configstrings[precache_check][0] == '#') {
+ precache_check++;
+ continue;
+ }
+ if (precache_model_skin == 0) {
+ if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
+ precache_model_skin = 1;
+ return; // started a download
+ }
+ precache_model_skin = 1;
+ }
+
+ // checking for skins in the model
+ if (!precache_model) {
+
+ FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model);
+ if (!precache_model) {
+ precache_model_skin = 0;
+ precache_check++;
+ continue; // couldn't load it
+ }
+ if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER) {
+ // not an alias model
+ FS_FreeFile(precache_model);
+ precache_model = 0;
+ precache_model_skin = 0;
+ precache_check++;
+ continue;
+ }
+ pheader = (dmdl_t *)precache_model;
+ if (LittleLong (pheader->version) != ALIAS_VERSION) {
+ precache_check++;
+ precache_model_skin = 0;
+ continue; // couldn't load it
+ }
+ }
+
+ pheader = (dmdl_t *)precache_model;
+
+ while (precache_model_skin - 1 < LittleLong(pheader->num_skins)) {
+ if (!CL_CheckOrDownloadFile((char *)precache_model +
+ LittleLong(pheader->ofs_skins) +
+ (precache_model_skin - 1)*MAX_SKINNAME)) {
+ precache_model_skin++;
+ return; // started a download
+ }
+ precache_model_skin++;
+ }
+ if (precache_model) {
+ FS_FreeFile(precache_model);
+ precache_model = 0;
+ }
+ precache_model_skin = 0;
+ precache_check++;
+ }
+ }
+ precache_check = CS_SOUNDS;
+ }
+ if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS) {
+ if (allow_download_sounds->value) {
+ if (precache_check == CS_SOUNDS)
+ precache_check++; // zero is blank
+ while (precache_check < CS_SOUNDS+MAX_SOUNDS &&
+ cl.configstrings[precache_check][0]) {
+ if (cl.configstrings[precache_check][0] == '*') {
+ precache_check++;
+ continue;
+ }
+ Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]);
+ if (!CL_CheckOrDownloadFile(fn))
+ return; // started a download
+ }
+ }
+ precache_check = CS_IMAGES;
+ }
+ if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES) {
+ if (precache_check == CS_IMAGES)
+ precache_check++; // zero is blank
+ while (precache_check < CS_IMAGES+MAX_IMAGES &&
+ cl.configstrings[precache_check][0]) {
+ Com_sprintf(fn, sizeof(fn), "pics/%s.pcx", cl.configstrings[precache_check++]);
+ if (!CL_CheckOrDownloadFile(fn))
+ return; // started a download
+ }
+ precache_check = CS_PLAYERSKINS;
+ }
+ // skins are special, since a player has three things to download:
+ // model, weapon model and skin
+ // so precache_check is now *3
+ if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
+ if (allow_download_players->value) {
+ while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
+ int i, n;
+ char model[MAX_QPATH], skin[MAX_QPATH], *p;
+
+ i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
+ n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
+
+ if (!cl.configstrings[CS_PLAYERSKINS+i][0]) {
+ precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
+ continue;
+ }
+
+ if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
+ p++;
+ else
+ p = cl.configstrings[CS_PLAYERSKINS+i];
+ strcpy(model, p);
+ p = strchr(model, '/');
+ if (!p)
+ p = strchr(model, '\\');
+ if (p) {
+ *p++ = 0;
+ strcpy(skin, p);
+ } else
+ *skin = 0;
+
+ switch (n) {
+ case 0: // model
+ Com_sprintf(fn, sizeof(fn), "players/%s/tris.md2", model);
+ if (!CL_CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
+ return; // started a download
+ }
+ /*FALL THROUGH*/
+
+ case 1: // weapon model
+ Com_sprintf(fn, sizeof(fn), "players/%s/weapon.md2", model);
+ if (!CL_CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
+ return; // started a download
+ }
+ /*FALL THROUGH*/
+
+ case 2: // weapon skin
+ Com_sprintf(fn, sizeof(fn), "players/%s/weapon.pcx", model);
+ if (!CL_CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
+ return; // started a download
+ }
+ /*FALL THROUGH*/
+
+ case 3: // skin
+ Com_sprintf(fn, sizeof(fn), "players/%s/%s.pcx", model, skin);
+ if (!CL_CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
+ return; // started a download
+ }
+ /*FALL THROUGH*/
+
+ case 4: // skin_i
+ Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.pcx", model, skin);
+ if (!CL_CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
+ return; // started a download
+ }
+ // move on to next model
+ precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
+ }
+ }
+ }
+ // precache phase completed
+ precache_check = ENV_CNT;
+ }
+
+ if (precache_check == ENV_CNT) {
+ precache_check = ENV_CNT + 1;
+
+ CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
+
+ if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM])) {
+ Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n",
+ map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
+ return;
+ }
+ }
+
+ if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) {
+ if (allow_download->value && allow_download_maps->value) {
+ while (precache_check < TEXTURE_CNT) {
+ int n = precache_check++ - ENV_CNT - 1;
+
+ if (n & 1)
+ Com_sprintf(fn, sizeof(fn), "env/%s%s.pcx",
+ cl.configstrings[CS_SKY], env_suf[n/2]);
+ else
+ Com_sprintf(fn, sizeof(fn), "env/%s%s.tga",
+ cl.configstrings[CS_SKY], env_suf[n/2]);
+ if (!CL_CheckOrDownloadFile(fn))
+ return; // started a download
+ }
+ }
+ precache_check = TEXTURE_CNT;
+ }
+
+ if (precache_check == TEXTURE_CNT) {
+ precache_check = TEXTURE_CNT+1;
+ precache_tex = 0;
+ }
+
+ // confirm existance of textures, download any that don't exist
+ if (precache_check == TEXTURE_CNT+1) {
+ // from qcommon/cmodel.c
+ extern int numtexinfo;
+ extern mapsurface_t map_surfaces[];
+
+ if (allow_download->value && allow_download_maps->value) {
+ while (precache_tex < numtexinfo) {
+ char fn[MAX_OSPATH];
+
+ sprintf(fn, "textures/%s.wal", map_surfaces[precache_tex++].rname);
+ if (!CL_CheckOrDownloadFile(fn))
+ return; // started a download
+ }
+ }
+ precache_check = TEXTURE_CNT+999;
+ }
+
+//ZOID
+ CL_RegisterSounds ();
+ CL_PrepRefresh ();
+
+ MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+ MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) );
+}
+
+/*
+=================
+CL_Precache_f
+
+The server will send this command right
+before allowing the client into the server
+=================
+*/
+void CL_Precache_f (void)
+{
+ //Yet another hack to let old demos work
+ //the old precache sequence
+ if (Cmd_Argc() < 2) {
+ unsigned map_checksum; // for detecting cheater maps
+
+ CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
+ CL_RegisterSounds ();
+ CL_PrepRefresh ();
+ return;
+ }
+
+ precache_check = CS_MODELS;
+ precache_spawncount = atoi(Cmd_Argv(1));
+ precache_model = 0;
+ precache_model_skin = 0;
+
+ CL_RequestNextDownload();
+}
+
+
+/*
+=================
+CL_InitLocal
+=================
+*/
+void CL_InitLocal (void)
+{
+ cls.state = ca_disconnected;
+ cls.realtime = Sys_Milliseconds ();
+
+ CL_InitInput ();
+
+ adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE );
+ adr1 = Cvar_Get( "adr1", "", CVAR_ARCHIVE );
+ adr2 = Cvar_Get( "adr2", "", CVAR_ARCHIVE );
+ adr3 = Cvar_Get( "adr3", "", CVAR_ARCHIVE );
+ adr4 = Cvar_Get( "adr4", "", CVAR_ARCHIVE );
+ adr5 = Cvar_Get( "adr5", "", CVAR_ARCHIVE );
+ adr6 = Cvar_Get( "adr6", "", CVAR_ARCHIVE );
+ adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE );
+ adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE );
+
+//
+// register our variables
+//
+ cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE );
+ cl_stereo = Cvar_Get( "cl_stereo", "0", 0 );
+
+ cl_add_blend = Cvar_Get ("cl_blend", "1", 0);
+ cl_add_lights = Cvar_Get ("cl_lights", "1", 0);
+ cl_add_particles = Cvar_Get ("cl_particles", "1", 0);
+ cl_add_entities = Cvar_Get ("cl_entities", "1", 0);
+ cl_gun = Cvar_Get ("cl_gun", "1", 0);
+ cl_footsteps = Cvar_Get ("cl_footsteps", "1", 0);
+ cl_noskins = Cvar_Get ("cl_noskins", "0", 0);
+ cl_autoskins = Cvar_Get ("cl_autoskins", "0", 0);
+ cl_predict = Cvar_Get ("cl_predict", "1", 0);
+// cl_minfps = Cvar_Get ("cl_minfps", "5", 0);
+ cl_maxfps = Cvar_Get ("cl_maxfps", "90", 0);
+
+ cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0);
+ cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0);
+ cl_sidespeed = Cvar_Get ("cl_sidespeed", "200", 0);
+ cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0);
+ cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0);
+ cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
+
+ cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE);
+
+ cl_shownet = Cvar_Get ("cl_shownet", "0", 0);
+ cl_showmiss = Cvar_Get ("cl_showmiss", "0", 0);
+ cl_showclamp = Cvar_Get ("showclamp", "0", 0);
+ cl_timeout = Cvar_Get ("cl_timeout", "120", 0);
+ cl_paused = Cvar_Get ("paused", "0", 0);
+ cl_timedemo = Cvar_Get ("timedemo", "0", 0);
+
+ rcon_client_password = Cvar_Get ("rcon_password", "", 0);
+ rcon_address = Cvar_Get ("rcon_address", "", 0);
+
+ cl_lightlevel = Cvar_Get ("r_lightlevel", "0", 0);
+
+ //
+ // userinfo
+ //
+ info_password = Cvar_Get ("password", "", CVAR_USERINFO);
+ info_spectator = Cvar_Get ("spectator", "0", CVAR_USERINFO);
+ name = Cvar_Get ("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE);
+ skin = Cvar_Get ("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
+ rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE); // FIXME
+ msg = Cvar_Get ("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
+ hand = Cvar_Get ("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
+ fov = Cvar_Get ("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE);
+ gender = Cvar_Get ("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
+ gender_auto = Cvar_Get ("gender_auto", "1", CVAR_ARCHIVE);
+ gender->modified = false; // clear this so we know when user sets it manually
+
+ cl_vwep = Cvar_Get ("cl_vwep", "1", CVAR_ARCHIVE);
+
+
+ //
+ // register our commands
+ //
+ Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
+ Cmd_AddCommand ("pause", CL_Pause_f);
+ Cmd_AddCommand ("pingservers", CL_PingServers_f);
+ Cmd_AddCommand ("skins", CL_Skins_f);
+
+ Cmd_AddCommand ("userinfo", CL_Userinfo_f);
+ Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
+
+ Cmd_AddCommand ("changing", CL_Changing_f);
+ Cmd_AddCommand ("disconnect", CL_Disconnect_f);
+ Cmd_AddCommand ("record", CL_Record_f);
+ Cmd_AddCommand ("stop", CL_Stop_f);
+
+ Cmd_AddCommand ("quit", CL_Quit_f);
+
+ Cmd_AddCommand ("connect", CL_Connect_f);
+ Cmd_AddCommand ("reconnect", CL_Reconnect_f);
+
+ Cmd_AddCommand ("rcon", CL_Rcon_f);
+
+// Cmd_AddCommand ("packet", CL_Packet_f); // this is dangerous to leave in
+
+ Cmd_AddCommand ("setenv", CL_Setenv_f );
+
+ Cmd_AddCommand ("precache", CL_Precache_f);
+
+ Cmd_AddCommand ("download", CL_Download_f);
+
+ //
+ // forward to server commands
+ //
+ // the only thing this does is allow command completion
+ // to work -- all unknown commands are automatically
+ // forwarded to the server
+ Cmd_AddCommand ("wave", NULL);
+ Cmd_AddCommand ("inven", NULL);
+ Cmd_AddCommand ("kill", NULL);
+ Cmd_AddCommand ("use", NULL);
+ Cmd_AddCommand ("drop", NULL);
+ Cmd_AddCommand ("say", NULL);
+ Cmd_AddCommand ("say_team", NULL);
+ Cmd_AddCommand ("info", NULL);
+ Cmd_AddCommand ("prog", NULL);
+ Cmd_AddCommand ("give", NULL);
+ Cmd_AddCommand ("god", NULL);
+ Cmd_AddCommand ("notarget", NULL);
+ Cmd_AddCommand ("noclip", NULL);
+ Cmd_AddCommand ("invuse", NULL);
+ Cmd_AddCommand ("invprev", NULL);
+ Cmd_AddCommand ("invnext", NULL);
+ Cmd_AddCommand ("invdrop", NULL);
+ Cmd_AddCommand ("weapnext", NULL);
+ Cmd_AddCommand ("weapprev", NULL);
+}
+
+
+
+/*
+===============
+CL_WriteConfiguration
+
+Writes key bindings and archived cvars to config.cfg
+===============
+*/
+void CL_WriteConfiguration (void)
+{
+ FILE *f;
+ char path[MAX_QPATH];
+
+ if (cls.state == ca_uninitialized)
+ return;
+
+ Com_sprintf (path, sizeof(path),"%s/config.cfg",FS_Gamedir());
+ f = fopen (path, "w");
+ if (!f)
+ {
+ Com_Printf ("Couldn't write config.cfg.\n");
+ return;
+ }
+
+ fprintf (f, "// generated by quake, do not modify\n");
+ Key_WriteBindings (f);
+ fclose (f);
+
+ Cvar_WriteVariables (path);
+}
+
+
+/*
+==================
+CL_FixCvarCheats
+
+==================
+*/
+
+typedef struct
+{
+ char *name;
+ char *value;
+ cvar_t *var;
+} cheatvar_t;
+
+cheatvar_t cheatvars[] = {
+ {"timescale", "1"},
+ {"timedemo", "0"},
+ {"r_drawworld", "1"},
+ {"cl_testlights", "0"},
+ {"r_fullbright", "0"},
+ {"r_drawflat", "0"},
+ {"paused", "0"},
+ {"fixedtime", "0"},
+ {"sw_draworder", "0"},
+ {"gl_lightmap", "0"},
+ {"gl_saturatelighting", "0"},
+ {NULL, NULL}
+};
+
+int numcheatvars;
+
+void CL_FixCvarCheats (void)
+{
+ int i;
+ cheatvar_t *var;
+
+ if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1")
+ || !cl.configstrings[CS_MAXCLIENTS][0] )
+ return; // single player can cheat
+
+ // find all the cvars if we haven't done it yet
+ if (!numcheatvars)
+ {
+ while (cheatvars[numcheatvars].name)
+ {
+ cheatvars[numcheatvars].var = Cvar_Get (cheatvars[numcheatvars].name,
+ cheatvars[numcheatvars].value, 0);
+ numcheatvars++;
+ }
+ }
+
+ // make sure they are all set to the proper values
+ for (i=0, var = cheatvars ; i<numcheatvars ; i++, var++)
+ {
+ if ( strcmp (var->var->string, var->value) )
+ {
+ Cvar_Set (var->name, var->value);
+ }
+ }
+}
+
+//============================================================================
+
+/*
+==================
+CL_SendCommand
+
+==================
+*/
+void CL_SendCommand (void)
+{
+ // get new key events
+ Sys_SendKeyEvents ();
+
+ // allow mice or other external controllers to add commands
+ IN_Commands ();
+
+ // process console commands
+ Cbuf_Execute ();
+
+ // fix any cheating cvars
+ CL_FixCvarCheats ();
+
+ // send intentions now
+ CL_SendCmd ();
+
+ // resend a connection request if necessary
+ CL_CheckForResend ();
+}
+
+
+/*
+==================
+CL_Frame
+
+==================
+*/
+void CL_Frame (int msec)
+{
+ static int extratime;
+ static int lasttimecalled;
+
+ if (dedicated->value)
+ return;
+
+ extratime += msec;
+
+ if (!cl_timedemo->value)
+ {
+ if (cls.state == ca_connected && extratime < 100)
+ return; // don't flood packets out while connecting
+ if (extratime < 1000/cl_maxfps->value)
+ return; // framerate is too high
+ }
+
+ // let the mouse activate or deactivate
+ IN_Frame ();
+
+ // decide the simulation time
+ cls.frametime = extratime/1000.0;
+ cl.time += extratime;
+ cls.realtime = curtime;
+
+ extratime = 0;
+/*
+ if (cls.frametime > (1.0 / cl_minfps->value))
+ cls.frametime = (1.0 / cl_minfps->value);
+*/
+ if (cls.frametime > (1.0 / 5))
+ cls.frametime = (1.0 / 5);
+
+ // if in the debugger last frame, don't timeout
+ if (msec > 5000)
+ cls.netchan.last_received = Sys_Milliseconds ();
+
+ // fetch results from server
+ CL_ReadPackets ();
+
+ // send a new command message to the server
+ CL_SendCommand ();
+
+ // predict all unacknowledged movements
+ CL_PredictMovement ();
+
+ // allow rendering DLL change
+ VID_CheckChanges ();
+ if (!cl.refresh_prepped && cls.state == ca_active)
+ CL_PrepRefresh ();
+
+ // update the screen
+ if (host_speeds->value)
+ time_before_ref = Sys_Milliseconds ();
+ SCR_UpdateScreen ();
+ if (host_speeds->value)
+ time_after_ref = Sys_Milliseconds ();
+
+ // update audio
+ S_Update (cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up);
+
+ CDAudio_Update();
+
+ // advance local effects for next frame
+ CL_RunDLights ();
+ CL_RunLightStyles ();
+ SCR_RunCinematic ();
+ SCR_RunConsole ();
+
+ cls.framecount++;
+
+ if ( log_stats->value )
+ {
+ if ( cls.state == ca_active )
+ {
+ if ( !lasttimecalled )
+ {
+ lasttimecalled = Sys_Milliseconds();
+ if ( log_stats_file )
+ fprintf( log_stats_file, "0\n" );
+ }
+ else
+ {
+ int now = Sys_Milliseconds();
+
+ if ( log_stats_file )
+ fprintf( log_stats_file, "%d\n", now - lasttimecalled );
+ lasttimecalled = now;
+ }
+ }
+ }
+}
+
+
+//============================================================================
+
+/*
+====================
+CL_Init
+====================
+*/
+void CL_Init (void)
+{
+ IN_Init();
+
+ if(dedicated->value)
+ return; // nothing running on the client
+
+ // all archived variables will now be loaded
+
+ Con_Init ();
+ S_Init ();
+ VID_Init ();
+
+ V_Init ();
+
+ net_message.data = net_message_buffer;
+ net_message.maxsize = sizeof(net_message_buffer);
+
+ M_Init ();
+
+ SCR_Init ();
+ cls.disable_screen = true; // don't draw yet
+
+ CDAudio_Init ();
+ CL_InitLocal ();
+
+// Cbuf_AddText ("exec autoexec.cfg\n");
+ FS_ExecAutoexec ();
+ Cbuf_Execute ();
+}
+
+
+/*
+===============
+CL_Shutdown
+
+FIXME: this is a callback from Sys_Quit and Com_Error. It would be better
+to run quit through here before the final handoff to the sys code.
+===============
+*/
+void CL_Shutdown(void)
+{
+ static qboolean isdown = false;
+
+ if (isdown)
+ {
+ printf ("recursive shutdown\n");
+ return;
+ }
+ isdown = true;
+
+ CL_WriteConfiguration ();
+
+ CDAudio_Shutdown ();
+ S_Shutdown();
+ IN_Shutdown ();
+ VID_Shutdown();
+}
+
+
--- /dev/null
+++ b/cl_newfx.c
@@ -1,0 +1,1307 @@
+// cl_newfx.c -- MORE entity effects parsing and management
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+extern cparticle_t *active_particles, *free_particles;
+extern cparticle_t particles[MAX_PARTICLES];
+extern int cl_numparticles;
+
+extern void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up);
+
+
+/*
+======
+vectoangles2 - this is duplicated in the game DLL, but I need it here.
+======
+*/
+void vectoangles2 (vec3_t value1, vec3_t angles)
+{
+ float forward;
+ float yaw, pitch;
+
+ if (value1[1] == 0 && value1[0] == 0)
+ {
+ yaw = 0;
+ if (value1[2] > 0)
+ pitch = 90;
+ else
+ pitch = 270;
+ }
+ else
+ {
+ // PMM - fixed to correct for pitch of 0
+ if (value1[0])
+ yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
+ else if (value1[1] > 0)
+ yaw = 90;
+ else
+ yaw = 270;
+
+ if (yaw < 0)
+ yaw += 360;
+
+ forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
+ pitch = (atan2(value1[2], forward) * 180 / M_PI);
+ if (pitch < 0)
+ pitch += 360;
+ }
+
+ angles[PITCH] = -pitch;
+ angles[YAW] = yaw;
+ angles[ROLL] = 0;
+}
+
+//=============
+//=============
+void CL_Flashlight (int ent, vec3_t pos)
+{
+ cdlight_t *dl;
+
+ dl = CL_AllocDlight (ent);
+ VectorCopy (pos, dl->origin);
+ dl->radius = 400;
+ dl->minlight = 250;
+ dl->die = cl.time + 100;
+ dl->color[0] = 1;
+ dl->color[1] = 1;
+ dl->color[2] = 1;
+}
+
+/*
+======
+CL_ColorFlash - flash of light
+======
+*/
+void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b)
+{
+ cdlight_t *dl;
+
+ if((vidref_val == VIDREF_SOFT) && ((r < 0) || (g<0) || (b<0)))
+ {
+ intensity = -intensity;
+ r = -r;
+ g = -g;
+ b = -b;
+ }
+
+ dl = CL_AllocDlight (ent);
+ VectorCopy (pos, dl->origin);
+ dl->radius = intensity;
+ dl->minlight = 250;
+ dl->die = cl.time + 100;
+ dl->color[0] = r;
+ dl->color[1] = g;
+ dl->color[2] = b;
+}
+
+
+/*
+======
+CL_DebugTrail
+======
+*/
+void CL_DebugTrail (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+// int j;
+ cparticle_t *p;
+ float dec;
+ vec3_t right, up;
+// int i;
+// float d, c, s;
+// vec3_t dir;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ MakeNormalVectors (vec, right, up);
+
+// VectorScale(vec, RT2_SKIP, vec);
+
+// dec = 1.0;
+// dec = 0.75;
+ dec = 3;
+ VectorScale (vec, dec, vec);
+ VectorCopy (start, move);
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+ VectorClear (p->vel);
+ p->alpha = 1.0;
+ p->alphavel = -0.1;
+// p->alphavel = 0;
+ p->color = 0x74 + (rand()&7);
+ VectorCopy (move, p->org);
+/*
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*2;
+ p->vel[j] = crand()*3;
+ p->accel[j] = 0;
+ }
+*/
+ VectorAdd (move, vec, move);
+ }
+
+}
+
+/*
+===============
+CL_SmokeTrail
+===============
+*/
+void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ VectorScale (vec, spacing, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0)
+ {
+ len -= spacing;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.5);
+ p->color = colorStart + (rand() % colorRun);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*3;
+ p->accel[j] = 0;
+ }
+ p->vel[2] = 20 + crand()*5;
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+void CL_ForceWall (vec3_t start, vec3_t end, int color)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ VectorScale (vec, 4, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0)
+ {
+ len -= 4;
+
+ if (!free_particles)
+ return;
+
+ if (qfrand() > 0.3)
+ {
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (3.0+qfrand()*0.5);
+ p->color = color;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*3;
+ p->accel[j] = 0;
+ }
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = -40 - (crand()*10);
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+void CL_FlameEffects (centity_t */*ent*/, vec3_t origin)
+{
+ int n, count;
+ int j;
+ cparticle_t *p;
+
+ count = rand() & 0xF;
+
+ for(n=0;n<count;n++)
+ {
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ VectorClear (p->accel);
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->color = 226 + (rand() % 4);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = origin[j] + crand()*5;
+ p->vel[j] = crand()*5;
+ }
+ p->vel[2] = crand() * -10;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ }
+
+ count = rand() & 0x7;
+
+ for(n=0;n<count;n++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.5);
+ p->color = 0 + (rand() % 4);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = origin[j] + crand()*3;
+ }
+ p->vel[2] = 20 + crand()*5;
+ }
+
+}
+
+
+/*
+===============
+CL_GenericParticleEffect
+===============
+*/
+void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ if (numcolors > 1)
+ p->color = color + (rand() & numcolors);
+ else
+ p->color = color;
+
+ d = rand() & dirspread;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+ p->vel[j] = crand()*20;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+// VectorCopy (accel, p->accel);
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*alphavel);
+// p->alphavel = alphavel;
+ }
+}
+
+/*
+===============
+CL_BubbleTrail2 (lets you control the # of bubbles by setting the distance between the spawns)
+
+===============
+*/
+void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int i, j;
+ cparticle_t *p;
+ float dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = dist;
+ VectorScale (vec, dec, vec);
+
+ for (i=0 ; i<len ; i+=dec)
+ {
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ VectorClear (p->accel);
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.1);
+ p->color = 4 + (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*2;
+ p->vel[j] = crand()*10;
+ }
+ p->org[2] -= 4;
+// p->vel[2] += 6;
+ p->vel[2] += 20;
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+//#define CORKSCREW 1
+//#define DOUBLE_SCREW 1
+#define RINGS 1
+//#define SPRAY 1
+
+#ifdef CORKSCREW
+void CL_Heatbeam (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j,k;
+ cparticle_t *p;
+ vec3_t right, up;
+ int i;
+ float d, c, s;
+ vec3_t dir;
+ float ltime;
+ float step = 5.0;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+// MakeNormalVectors (vec, right, up);
+ VectorCopy (cl.v_right, right);
+ VectorCopy (cl.v_up, up);
+ VectorMA (move, -1, right, move);
+ VectorMA (move, -1, up, move);
+
+ VectorScale (vec, step, vec);
+ ltime = (float) cl.time/1000.0;
+
+// for (i=0 ; i<len ; i++)
+ for (i=0 ; i<len ; i+=step)
+ {
+ d = i * 0.1 - fmod(ltime,16.0)*M_PI;
+ c = cos(d)/1.75;
+ s = sin(d)/1.75;
+#ifdef DOUBLE_SCREW
+ for (k=-1; k<2; k+=2)
+ {
+#else
+ k=1;
+#endif
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+
+ p->alpha = 0.5;
+ // p->alphavel = -1.0 / (1+qfrand()*0.2);
+ // only last one frame!
+ p->alphavel = INSTANT_PARTICLE;
+ // p->color = 0x74 + (rand()&7);
+// p->color = 223 - (rand()&7);
+ p->color = 223;
+// p->color = 240;
+
+ // trim it so it looks like it's starting at the origin
+ if (i < 10)
+ {
+ VectorScale (right, c*(i/10.0)*k, dir);
+ VectorMA (dir, s*(i/10.0)*k, up, dir);
+ }
+ else
+ {
+ VectorScale (right, c*k, dir);
+ VectorMA (dir, s*k, up, dir);
+ }
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + dir[j]*3;
+ // p->vel[j] = dir[j]*6;
+ p->vel[j] = 0;
+ }
+#ifdef DOUBLE_SCREW
+ }
+#endif
+ VectorAdd (move, vec, move);
+ }
+}
+#endif
+#ifdef RINGS
+//void CL_Heatbeam (vec3_t start, vec3_t end)
+void CL_Heatbeam (vec3_t start, vec3_t forward)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ vec3_t right, up;
+ int i;
+ float c, s;
+ vec3_t dir;
+ float ltime;
+ float step = 32.0, rstep;
+ float start_pt;
+ float rot;
+ float variance;
+ vec3_t end;
+
+ VectorMA (start, 4096, forward, end);
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ // FIXME - pmm - these might end up using old values?
+// MakeNormalVectors (vec, right, up);
+ VectorCopy (cl.v_right, right);
+ VectorCopy (cl.v_up, up);
+ if (vidref_val == VIDREF_GL)
+ { // GL mode
+ VectorMA (move, -0.5, right, move);
+ VectorMA (move, -0.5, up, move);
+ }
+ // otherwise assume SOFT
+
+ ltime = (float) cl.time/1000.0;
+ start_pt = fmod(ltime*96.0,step);
+ VectorMA (move, start_pt, vec, move);
+
+ VectorScale (vec, step, vec);
+
+// Com_Printf ("%f\n", ltime);
+ rstep = M_PI/10.0;
+ for (i=start_pt ; i<len ; i+=step)
+ {
+ if (i>step*5) // don't bother after the 5th ring
+ break;
+
+ for (rot = 0; rot < M_PI*2; rot += rstep)
+ {
+
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+// rot+= fmod(ltime, 12.0)*M_PI;
+// c = cos(rot)/2.0;
+// s = sin(rot)/2.0;
+// variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2;
+ variance = 0.5;
+ c = cos(rot)*variance;
+ s = sin(rot)*variance;
+
+ // trim it so it looks like it's starting at the origin
+ if (i < 10)
+ {
+ VectorScale (right, c*(i/10.0), dir);
+ VectorMA (dir, s*(i/10.0), up, dir);
+ }
+ else
+ {
+ VectorScale (right, c, dir);
+ VectorMA (dir, s, up, dir);
+ }
+
+ p->alpha = 0.5;
+ // p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->alphavel = -1000.0;
+ // p->color = 0x74 + (rand()&7);
+ p->color = 223 - (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + dir[j]*3;
+ // p->vel[j] = dir[j]*6;
+ p->vel[j] = 0;
+ }
+ }
+ VectorAdd (move, vec, move);
+ }
+}
+#endif
+#ifdef SPRAY
+void CL_Heatbeam (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ vec3_t forward, right, up;
+ int i;
+ float d, c, s;
+ vec3_t dir;
+ float ltime;
+ float step = 32.0, rstep;
+ float start_pt;
+ float rot;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+// MakeNormalVectors (vec, right, up);
+ VectorCopy (cl.v_forward, forward);
+ VectorCopy (cl.v_right, right);
+ VectorCopy (cl.v_up, up);
+ VectorMA (move, -0.5, right, move);
+ VectorMA (move, -0.5, up, move);
+
+ for (i=0; i<8; i++)
+ {
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+
+ d = crand()*M_PI;
+ c = cos(d)*30;
+ s = sin(d)*30;
+
+ p->alpha = 1.0;
+ p->alphavel = -5.0 / (1+qfrand());
+ p->color = 223 - (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j];
+ }
+ VectorScale (vec, 450, p->vel);
+ VectorMA (p->vel, c, right, p->vel);
+ VectorMA (p->vel, s, up, p->vel);
+ }
+/*
+
+ ltime = (float) cl.time/1000.0;
+ start_pt = fmod(ltime*16.0,step);
+ VectorMA (move, start_pt, vec, move);
+
+ VectorScale (vec, step, vec);
+
+// Com_Printf ("%f\n", ltime);
+ rstep = M_PI/12.0;
+ for (i=start_pt ; i<len ; i+=step)
+ {
+ if (i>step*5) // don't bother after the 5th ring
+ break;
+
+ for (rot = 0; rot < M_PI*2; rot += rstep)
+ {
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+// rot+= fmod(ltime, 12.0)*M_PI;
+// c = cos(rot)/2.0;
+// s = sin(rot)/2.0;
+ c = cos(rot)/1.5;
+ s = sin(rot)/1.5;
+
+ // trim it so it looks like it's starting at the origin
+ if (i < 10)
+ {
+ VectorScale (right, c*(i/10.0), dir);
+ VectorMA (dir, s*(i/10.0), up, dir);
+ }
+ else
+ {
+ VectorScale (right, c, dir);
+ VectorMA (dir, s, up, dir);
+ }
+
+ p->alpha = 0.5;
+ // p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->alphavel = -1000.0;
+ // p->color = 0x74 + (rand()&7);
+ p->color = 223 - (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + dir[j]*3;
+ // p->vel[j] = dir[j]*6;
+ p->vel[j] = 0;
+ }
+ }
+ VectorAdd (move, vec, move);
+ }
+*/
+}
+#endif
+
+/*
+===============
+CL_ParticleSteamEffect
+
+Puffs with velocity along direction, with some randomness thrown in
+===============
+*/
+void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+ vec3_t r, u;
+
+// vectoangles2 (dir, angle_dir);
+// AngleVectors (angle_dir, f, r, u);
+
+ MakeNormalVectors (dir, r, u);
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color + (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + magnitude*0.1*crand();
+// p->vel[j] = dir[j]*magnitude;
+ }
+ VectorScale (dir, magnitude, p->vel);
+ d = crand()*magnitude/3;
+ VectorMA (p->vel, d, r, p->vel);
+ d = crand()*magnitude/3;
+ VectorMA (p->vel, d, u, p->vel);
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY/2;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+void CL_ParticleSteamEffect2 (cl_sustain_t *self)
+//vec3_t org, vec3_t dir, int color, int count, int magnitude)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+ vec3_t r, u;
+ vec3_t dir;
+
+// vectoangles2 (dir, angle_dir);
+// AngleVectors (angle_dir, f, r, u);
+
+ VectorCopy (self->dir, dir);
+ MakeNormalVectors (dir, r, u);
+
+ for (i=0 ; i<self->count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = self->color + (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = self->org[j] + self->magnitude*0.1*crand();
+// p->vel[j] = dir[j]*magnitude;
+ }
+ VectorScale (dir, self->magnitude, p->vel);
+ d = crand()*self->magnitude/3;
+ VectorMA (p->vel, d, r, p->vel);
+ d = crand()*self->magnitude/3;
+ VectorMA (p->vel, d, u, p->vel);
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY/2;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+ self->nextthink += self->thinkinterval;
+}
+
+/*
+===============
+CL_TrackerTrail
+===============
+*/
+void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor)
+{
+ vec3_t move;
+ vec3_t vec;
+ vec3_t forward,right,up,angle_dir;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+ float dist;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ VectorCopy(vec, forward);
+ vectoangles2 (forward, angle_dir);
+ AngleVectors (angle_dir, forward, right, up);
+
+ dec = 3;
+ VectorScale (vec, 3, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -2.0;
+ p->color = particleColor;
+ dist = DotProduct(move, forward);
+ VectorMA(move, 8 * cos(dist), up, p->org);
+ for (j=0 ; j<3 ; j++)
+ {
+// p->org[j] = move[j] + crand();
+ p->vel[j] = 0;
+ p->accel[j] = 0;
+ }
+ p->vel[2] = 5;
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+void CL_Tracker_Shell(vec3_t origin)
+{
+ vec3_t dir;
+ int i;
+ cparticle_t *p;
+
+ for(i=0;i<300;i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = INSTANT_PARTICLE;
+ p->color = 0;
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+
+ VectorMA(origin, 40, dir, p->org);
+ }
+}
+
+void CL_MonsterPlasma_Shell(vec3_t origin)
+{
+ vec3_t dir;
+ int i;
+ cparticle_t *p;
+
+ for(i=0;i<40;i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = INSTANT_PARTICLE;
+ p->color = 0xe0;
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+
+ VectorMA(origin, 10, dir, p->org);
+// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
+ }
+}
+
+void CL_Widowbeamout (cl_sustain_t *self)
+{
+ vec3_t dir;
+ int i;
+ cparticle_t *p;
+ static int colortable[4] = {2*8,13*8,21*8,18*8};
+ float ratio;
+
+ ratio = 1.0 - (((float)self->endtime - (float)cl.time)/2100.0);
+
+ for(i=0;i<300;i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = INSTANT_PARTICLE;
+ p->color = colortable[rand()&3];
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+
+ VectorMA(self->org, (45.0 * ratio), dir, p->org);
+// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
+ }
+}
+
+void CL_Nukeblast (cl_sustain_t *self)
+{
+ vec3_t dir;
+ int i;
+ cparticle_t *p;
+ static int colortable[4] = {110, 112, 114, 116};
+ float ratio;
+
+ ratio = 1.0 - (((float)self->endtime - (float)cl.time)/1000.0);
+
+ for(i=0;i<700;i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = INSTANT_PARTICLE;
+ p->color = colortable[rand()&3];
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+
+ VectorMA(self->org, (200.0 * ratio), dir, p->org);
+// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
+ }
+}
+
+void CL_WidowSplash (vec3_t org)
+{
+ static int colortable[4] = {2*8,13*8,21*8,18*8};
+ int i;
+ cparticle_t *p;
+ vec3_t dir;
+
+ for (i=0 ; i<256 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = colortable[rand()&3];
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+ VectorMA(org, 45.0, dir, p->org);
+ VectorMA(vec3_origin, 40.0, dir, p->vel);
+
+ p->accel[0] = p->accel[1] = 0;
+ p->alpha = 1.0;
+
+ p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
+ }
+
+}
+
+void CL_Tracker_Explode(vec3_t origin)
+{
+ vec3_t dir, backdir;
+ int i;
+ cparticle_t *p;
+
+ for(i=0;i<300;i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0;
+ p->color = 0;
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+ VectorScale(dir, -1, backdir);
+
+ VectorMA(origin, 64, dir, p->org);
+ VectorScale(backdir, 64, p->vel);
+ }
+
+}
+
+/*
+===============
+CL_TagTrail
+
+===============
+*/
+void CL_TagTrail (vec3_t start, vec3_t end, float color)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ while (len >= 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.8+qfrand()*0.2);
+ p->color = color;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*16;
+ p->vel[j] = crand()*5;
+ p->accel[j] = 0;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+/*
+===============
+CL_ColorExplosionParticles
+===============
+*/
+void CL_ColorExplosionParticles (vec3_t org, int color, int run)
+{
+ int i, j;
+ cparticle_t *p;
+
+ for (i=0 ; i<128 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color + (rand() % run);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()%32)-16);
+ p->vel[j] = (rand()%256)-128;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -0.4 / (0.6 + qfrand()*0.2);
+ }
+}
+
+/*
+===============
+CL_ParticleSmokeEffect - like the steam effect, but unaffected by gravity
+===============
+*/
+void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+ vec3_t r, u;
+
+ MakeNormalVectors (dir, r, u);
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color + (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + magnitude*0.1*crand();
+// p->vel[j] = dir[j]*magnitude;
+ }
+ VectorScale (dir, magnitude, p->vel);
+ d = crand()*magnitude/3;
+ VectorMA (p->vel, d, r, p->vel);
+ d = crand()*magnitude/3;
+ VectorMA (p->vel, d, u, p->vel);
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+/*
+===============
+CL_BlasterParticles2
+
+Wall impact puffs (Green)
+===============
+*/
+void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+ int count;
+
+ count = 40;
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color + (rand()&7);
+
+ d = rand()&15;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+ p->vel[j] = dir[j] * 30 + crand()*40;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+/*
+===============
+CL_BlasterTrail2
+
+Green!
+===============
+*/
+void CL_BlasterTrail2 (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.3+qfrand()*0.2);
+ p->color = 0xd0;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand();
+ p->vel[j] = crand()*5;
+ p->accel[j] = 0;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
--- /dev/null
+++ b/cl_parse.c
@@ -1,0 +1,803 @@
+// cl_parse.c -- parse a message received from the server
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+char *svc_strings[256] =
+{
+ "svc_bad",
+
+ "svc_muzzleflash",
+ "svc_muzzlflash2",
+ "svc_temp_entity",
+ "svc_layout",
+ "svc_inventory",
+
+ "svc_nop",
+ "svc_disconnect",
+ "svc_reconnect",
+ "svc_sound",
+ "svc_print",
+ "svc_stufftext",
+ "svc_serverdata",
+ "svc_configstring",
+ "svc_spawnbaseline",
+ "svc_centerprint",
+ "svc_download",
+ "svc_playerinfo",
+ "svc_packetentities",
+ "svc_deltapacketentities",
+ "svc_frame"
+};
+
+//=============================================================================
+
+void CL_DownloadFileName(char *dest, int destlen, char *fn)
+{
+ if (strncmp(fn, "players", 7) == 0)
+ Com_sprintf (dest, destlen, "%s/%s", BASEDIRNAME, fn);
+ else
+ Com_sprintf (dest, destlen, "%s/%s", FS_Gamedir(), fn);
+}
+
+/*
+===============
+CL_CheckOrDownloadFile
+
+Returns true if the file exists, otherwise it attempts
+to start a download from the server.
+===============
+*/
+qboolean CL_CheckOrDownloadFile (char *filename)
+{
+ FILE *fp;
+ char name[MAX_OSPATH];
+
+ if (strstr (filename, ".."))
+ {
+ Com_Printf ("Refusing to download a path with ..\n");
+ return true;
+ }
+
+ if (FS_LoadFile (filename, NULL) != -1)
+ { // it exists, no need to download
+ return true;
+ }
+
+ strcpy (cls.downloadname, filename);
+
+ // download to a temp name, and only rename
+ // to the real name when done, so if interrupted
+ // a runt file wont be left
+ COM_StripExtension (cls.downloadname, cls.downloadtempname);
+ strcat (cls.downloadtempname, ".tmp");
+
+//ZOID
+ // check to see if we already have a tmp for this file, if so, try to resume
+ // open the file if not opened yet
+ CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
+
+// FS_CreatePath (name);
+
+ fp = fopen (name, "r+b");
+ if (fp) { // it exists
+ int len;
+ fseek(fp, 0, SEEK_END);
+ len = ftell(fp);
+
+ cls.download = fp;
+
+ // give the server an offset to start the download
+ Com_Printf ("Resuming %s\n", cls.downloadname);
+ MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+ MSG_WriteString (&cls.netchan.message,
+ va("download %s %i", cls.downloadname, len));
+ } else {
+ Com_Printf ("Downloading %s\n", cls.downloadname);
+ MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+ MSG_WriteString (&cls.netchan.message,
+ va("download %s", cls.downloadname));
+ }
+
+ cls.downloadnumber++;
+
+ return false;
+}
+
+/*
+===============
+CL_Download_f
+
+Request a download from the server
+===============
+*/
+void CL_Download_f (void)
+{
+ char filename[MAX_OSPATH];
+
+ if (Cmd_Argc() != 2) {
+ Com_Printf("Usage: download <filename>\n");
+ return;
+ }
+
+ Com_sprintf(filename, sizeof(filename), "%s", Cmd_Argv(1));
+
+ if (strstr (filename, ".."))
+ {
+ Com_Printf ("Refusing to download a path with ..\n");
+ return;
+ }
+
+ if (FS_LoadFile (filename, NULL) != -1)
+ { // it exists, no need to download
+ Com_Printf("File already exists.\n");
+ return;
+ }
+
+ strcpy (cls.downloadname, filename);
+ Com_Printf ("Downloading %s\n", cls.downloadname);
+
+ // download to a temp name, and only rename
+ // to the real name when done, so if interrupted
+ // a runt file wont be left
+ COM_StripExtension (cls.downloadname, cls.downloadtempname);
+ strcat (cls.downloadtempname, ".tmp");
+
+ MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+ MSG_WriteString (&cls.netchan.message,
+ va("download %s", cls.downloadname));
+
+ cls.downloadnumber++;
+}
+
+/*
+======================
+CL_RegisterSounds
+======================
+*/
+void CL_RegisterSounds (void)
+{
+ int i;
+
+ S_BeginRegistration ();
+ CL_RegisterTEntSounds ();
+ for (i=1 ; i<MAX_SOUNDS ; i++)
+ {
+ if (!cl.configstrings[CS_SOUNDS+i][0])
+ break;
+ cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
+ Sys_SendKeyEvents (); // pump message loop
+ }
+ S_EndRegistration ();
+}
+
+static void
+rename(char *old, char *new)
+{
+ char *p;
+ Dir d;
+
+ if((p = strrchr(new, '/')) == nil)
+ p = new;
+ else
+ p++;
+ nulldir(&d);
+ d.name = p;
+ if(dirwstat(old, &d) < 0)
+ fprint(2, "rename: %r\n");
+}
+
+/*
+=====================
+CL_ParseDownload
+
+A download message has been received from the server
+=====================
+*/
+void CL_ParseDownload (void)
+{
+ int size, percent;
+ char name[MAX_OSPATH];
+
+ // read the data
+ size = MSG_ReadShort (&net_message);
+ percent = MSG_ReadByte (&net_message);
+ if (size == -1)
+ {
+ Com_Printf ("Server does not have this file.\n");
+ if (cls.download)
+ {
+ // if here, we tried to resume a file but the server said no
+ fclose (cls.download);
+ cls.download = NULL;
+ }
+ CL_RequestNextDownload ();
+ return;
+ }
+
+ // open the file if not opened yet
+ if (!cls.download)
+ {
+ CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
+
+ FS_CreatePath (name);
+
+ cls.download = fopen (name, "wb");
+ if (!cls.download)
+ {
+ net_message.readcount += size;
+ Com_Printf ("Failed to open %s\n", cls.downloadtempname);
+ CL_RequestNextDownload ();
+ return;
+ }
+ }
+
+ fwrite (net_message.data + net_message.readcount, 1, size, cls.download);
+ net_message.readcount += size;
+
+ if (percent != 100)
+ {
+ // request next block
+// change display routines by zoid
+/*
+ Com_Printf (".");
+ if (10*(percent/10) != cls.downloadpercent)
+ {
+ cls.downloadpercent = 10*(percent/10);
+ Com_Printf ("%i%%", cls.downloadpercent);
+ }
+*/
+ cls.downloadpercent = percent;
+
+ MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+ SZ_Print (&cls.netchan.message, "nextdl");
+ }
+ else
+ {
+ char oldn[MAX_OSPATH];
+ char newn[MAX_OSPATH];
+
+// Com_Printf ("100%%\n");
+
+ fclose (cls.download);
+
+ // rename the temp file to it's final name
+ CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
+ CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
+ rename (oldn, newn); /* FIXME */
+
+ cls.download = NULL;
+ cls.downloadpercent = 0;
+
+ // get another file if needed
+
+ CL_RequestNextDownload ();
+ }
+}
+
+
+/*
+=====================================================================
+
+ SERVER CONNECTING MESSAGES
+
+=====================================================================
+*/
+
+/*
+==================
+CL_ParseServerData
+==================
+*/
+void CL_ParseServerData (void)
+{
+ extern cvar_t *fs_gamedirvar;
+ char *str;
+ int i;
+
+ Com_DPrintf ("Serverdata packet received.\n");
+//
+// wipe the client_state_t struct
+//
+ CL_ClearState ();
+ cls.state = ca_connected;
+
+// parse protocol version number
+ i = MSG_ReadLong (&net_message);
+ cls.serverProtocol = i;
+
+ // BIG HACK to let demos from release work with the 3.0x patch!!!
+ if (Com_ServerState() && PROTOCOL_VERSION == 34)
+ {
+ }
+ else if (i != PROTOCOL_VERSION)
+ Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
+
+ cl.servercount = MSG_ReadLong (&net_message);
+ cl.attractloop = MSG_ReadByte (&net_message);
+
+ // game directory
+ str = MSG_ReadString (&net_message);
+ strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
+
+ // set gamedir
+ if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
+ Cvar_Set("game", str);
+
+ // parse player entity number
+ cl.playernum = MSG_ReadShort (&net_message);
+
+ // get the full level name
+ str = MSG_ReadString (&net_message);
+
+ if (cl.playernum == -1)
+ { // playing a cinematic or showing a pic, not a level
+ SCR_PlayCinematic (str);
+ }
+ else
+ {
+ // seperate the printfs so the server message can have a color
+ Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+ Com_Printf ("%c%s\n", 2, str);
+
+ // need to prep refresh at next oportunity
+ cl.refresh_prepped = false;
+ }
+}
+
+/*
+==================
+CL_ParseBaseline
+==================
+*/
+void CL_ParseBaseline (void)
+{
+ entity_state_t *es;
+ int bits;
+ int newnum;
+ entity_state_t nullstate;
+
+ memset (&nullstate, 0, sizeof(nullstate));
+
+ newnum = CL_ParseEntityBits (&bits);
+ es = &cl_entities[newnum].baseline;
+ CL_ParseDelta (&nullstate, es, newnum, bits);
+}
+
+
+/*
+================
+CL_LoadClientinfo
+
+================
+*/
+void CL_LoadClientinfo (clientinfo_t *ci, char *s)
+{
+ int i;
+ char *t;
+ char model_name[MAX_QPATH];
+ char skin_name[MAX_QPATH];
+ char model_filename[MAX_QPATH];
+ char skin_filename[MAX_QPATH];
+ char weapon_filename[MAX_QPATH];
+
+ strncpy(ci->cinfo, s, sizeof(ci->cinfo));
+ ci->cinfo[sizeof(ci->cinfo)-1] = 0;
+
+ // isolate the player's name
+ strncpy(ci->name, s, sizeof(ci->name));
+ ci->name[sizeof(ci->name)-1] = 0;
+ t = strstr (s, "\\");
+ if (t)
+ {
+ ci->name[t-s] = 0;
+ s = t+1;
+ }
+
+ if (cl_noskins->value || *s == 0)
+ {
+ Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
+ Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/weapon.md2");
+ Com_sprintf (skin_filename, sizeof(skin_filename), "players/male/grunt.pcx");
+ Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/male/grunt_i.pcx");
+ ci->model = re.RegisterModel (model_filename);
+ memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
+ ci->weaponmodel[0] = re.RegisterModel (weapon_filename);
+ ci->skin = re.RegisterSkin (skin_filename);
+ ci->icon = re.RegisterPic (ci->iconname);
+ }
+ else
+ {
+ // isolate the model name
+ strcpy (model_name, s);
+ t = strstr(model_name, "/");
+ if (!t)
+ t = strstr(model_name, "\\");
+ if (!t)
+ t = model_name;
+ *t = 0;
+
+ // isolate the skin name
+ strcpy (skin_name, s + strlen(model_name) + 1);
+
+ // model file
+ Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
+ ci->model = re.RegisterModel (model_filename);
+ if (!ci->model)
+ {
+ strcpy(model_name, "male");
+ Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
+ ci->model = re.RegisterModel (model_filename);
+ }
+
+ // skin file
+ Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
+ ci->skin = re.RegisterSkin (skin_filename);
+
+ // if we don't have the skin and the model wasn't male,
+ // see if the male has it (this is for CTF's skins)
+ if (!ci->skin && cistrcmp(model_name, "male"))
+ {
+ // change model to male
+ strcpy(model_name, "male");
+ Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
+ ci->model = re.RegisterModel (model_filename);
+
+ // see if the skin exists for the male model
+ Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
+ ci->skin = re.RegisterSkin (skin_filename);
+ }
+
+ // if we still don't have a skin, it means that the male model didn't have
+ // it, so default to grunt
+ if (!ci->skin) {
+ // see if the skin exists for the male model
+ Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/grunt.pcx", model_name, skin_name);
+ ci->skin = re.RegisterSkin (skin_filename);
+ }
+
+ // weapon file
+ for (i = 0; i < num_cl_weaponmodels; i++) {
+ Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
+ ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
+ if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
+ // try male
+ Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
+ ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
+ }
+ if (!cl_vwep->value)
+ break; // only one when vwep is off
+ }
+
+ // icon file
+ Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
+ ci->icon = re.RegisterPic (ci->iconname);
+ }
+
+ // must have loaded all data types to be valud
+ if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
+ {
+ ci->skin = NULL;
+ ci->icon = NULL;
+ ci->model = NULL;
+ ci->weaponmodel[0] = NULL;
+ return;
+ }
+}
+
+/*
+================
+CL_ParseClientinfo
+
+Load the skin, icon, and model for a client
+================
+*/
+void CL_ParseClientinfo (int player)
+{
+ char *s;
+ clientinfo_t *ci;
+
+ s = cl.configstrings[player+CS_PLAYERSKINS];
+
+ ci = &cl.clientinfo[player];
+
+ CL_LoadClientinfo (ci, s);
+}
+
+
+/*
+================
+CL_ParseConfigString
+================
+*/
+void CL_ParseConfigString (void)
+{
+ int i;
+ char *s;
+
+ i = MSG_ReadShort (&net_message);
+ if (i < 0 || i >= MAX_CONFIGSTRINGS)
+ Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
+ s = MSG_ReadString(&net_message);
+ strcpy (cl.configstrings[i], s);
+
+ // do something apropriate
+
+ if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
+ CL_SetLightstyle (i - CS_LIGHTS);
+ else if (i == CS_CDTRACK)
+ {
+ if (cl.refresh_prepped)
+ CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
+ }
+ else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS)
+ {
+ if (cl.refresh_prepped)
+ {
+ cl.model_draw[i-CS_MODELS] = re.RegisterModel (cl.configstrings[i]);
+ if (cl.configstrings[i][0] == '*')
+ cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
+ else
+ cl.model_clip[i-CS_MODELS] = NULL;
+ }
+ }
+ else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)
+ {
+ if (cl.refresh_prepped)
+ cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
+ }
+ else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS)
+ {
+ if (cl.refresh_prepped)
+ cl.image_precache[i-CS_IMAGES] = re.RegisterPic (cl.configstrings[i]);
+ }
+ else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS)
+ {
+ if (cl.refresh_prepped)
+ CL_ParseClientinfo (i-CS_PLAYERSKINS);
+ }
+}
+
+
+/*
+=====================================================================
+
+ACTION MESSAGES
+
+=====================================================================
+*/
+
+/*
+==================
+CL_ParseStartSoundPacket
+==================
+*/
+void CL_ParseStartSoundPacket(void)
+{
+ vec3_t pos_v;
+ float *pos;
+ int channel, ent;
+ int sound_num;
+ float volume;
+ float attenuation;
+ int flags;
+ float ofs;
+
+ flags = MSG_ReadByte (&net_message);
+ sound_num = MSG_ReadByte (&net_message);
+
+ if (flags & SND_VOLUME)
+ volume = MSG_ReadByte (&net_message) / 255.0;
+ else
+ volume = DEFAULT_SOUND_PACKET_VOLUME;
+
+ if (flags & SND_ATTENUATION)
+ attenuation = MSG_ReadByte (&net_message) / 64.0;
+ else
+ attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
+
+ if (flags & SND_OFFSET)
+ ofs = MSG_ReadByte (&net_message) / 1000.0;
+ else
+ ofs = 0;
+
+ if (flags & SND_ENT)
+ { // entity reletive
+ channel = MSG_ReadShort(&net_message);
+ ent = channel>>3;
+ if (ent > MAX_EDICTS)
+ Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
+
+ channel &= 7;
+ }
+ else
+ {
+ ent = 0;
+ channel = 0;
+ }
+
+ if (flags & SND_POS)
+ { // positioned in space
+ MSG_ReadPos (&net_message, pos_v);
+
+ pos = pos_v;
+ }
+ else // use entity number
+ pos = NULL;
+
+ if (!cl.sound_precache[sound_num])
+ return;
+
+ S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
+}
+
+
+void SHOWNET(char *s)
+{
+ if (cl_shownet->value>=2)
+ Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
+}
+
+/*
+=====================
+CL_ParseServerMessage
+=====================
+*/
+void CL_ParseServerMessage (void)
+{
+ int cmd;
+ char *s;
+ int i;
+
+//
+// if recording demos, copy the message out
+//
+ if (cl_shownet->value == 1)
+ Com_Printf ("%i ",net_message.cursize);
+ else if (cl_shownet->value >= 2)
+ Com_Printf ("------------------\n");
+
+
+//
+// parse the message
+//
+ while (1)
+ {
+ if (net_message.readcount > net_message.cursize)
+ {
+ Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
+ break;
+ }
+
+ cmd = MSG_ReadByte (&net_message);
+
+ if (cmd == -1)
+ {
+ SHOWNET("END OF MESSAGE");
+ break;
+ }
+
+ if (cl_shownet->value>=2)
+ {
+ if (!svc_strings[cmd])
+ Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
+ else
+ SHOWNET(svc_strings[cmd]);
+ }
+
+ // other commands
+ switch (cmd)
+ {
+ default:
+ Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
+ break;
+
+ case svc_nop:
+// Com_Printf ("svc_nop\n");
+ break;
+
+ case svc_disconnect:
+ Com_Error (ERR_DISCONNECT,"Server disconnected\n");
+ break;
+
+ case svc_reconnect:
+ Com_Printf ("Server disconnected, reconnecting\n");
+ if (cls.download) {
+ //ZOID, close download
+ fclose (cls.download);
+ cls.download = NULL;
+ }
+ cls.state = ca_connecting;
+ cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
+ break;
+
+ case svc_print:
+ i = MSG_ReadByte (&net_message);
+ if (i == PRINT_CHAT)
+ {
+ S_StartLocalSound ("misc/talk.wav");
+ con.ormask = 128;
+ }
+ Com_Printf ("%s", MSG_ReadString (&net_message));
+ con.ormask = 0;
+ break;
+
+ case svc_centerprint:
+ SCR_CenterPrint (MSG_ReadString (&net_message));
+ break;
+
+ case svc_stufftext:
+ s = MSG_ReadString (&net_message);
+ Com_DPrintf ("stufftext: %s\n", s);
+ Cbuf_AddText (s);
+ break;
+
+ case svc_serverdata:
+ Cbuf_Execute (); // make sure any stuffed commands are done
+ CL_ParseServerData ();
+ break;
+
+ case svc_configstring:
+ CL_ParseConfigString ();
+ break;
+
+ case svc_sound:
+ CL_ParseStartSoundPacket();
+ break;
+
+ case svc_spawnbaseline:
+ CL_ParseBaseline ();
+ break;
+
+ case svc_temp_entity:
+ CL_ParseTEnt ();
+ break;
+
+ case svc_muzzleflash:
+ CL_ParseMuzzleFlash ();
+ break;
+
+ case svc_muzzleflash2:
+ CL_ParseMuzzleFlash2 ();
+ break;
+
+ case svc_download:
+ CL_ParseDownload ();
+ break;
+
+ case svc_frame:
+ CL_ParseFrame ();
+ break;
+
+ case svc_inventory:
+ CL_ParseInventory ();
+ break;
+
+ case svc_layout:
+ s = MSG_ReadString (&net_message);
+ strncpy (cl.layout, s, sizeof(cl.layout)-1);
+ break;
+
+ case svc_playerinfo:
+ case svc_packetentities:
+ case svc_deltapacketentities:
+ Com_Error (ERR_DROP, "Out of place frame data");
+ break;
+ }
+ }
+
+ CL_AddNetgraph ();
+
+ //
+ // we don't know if it is ok to save a demo message until
+ // after we have parsed the frame
+ //
+ if (cls.demorecording && !cls.demowaiting)
+ CL_WriteDemoMessage ();
+
+}
+
+
--- /dev/null
+++ b/cl_pred.c
@@ -1,0 +1,260 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+/*
+===================
+CL_CheckPredictionError
+===================
+*/
+void CL_CheckPredictionError (void)
+{
+ int frame;
+ int delta[3];
+ int i;
+ int len;
+
+ if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
+ return;
+
+ // calculate the last usercmd_t we sent that the server has processed
+ frame = cls.netchan.incoming_acknowledged;
+ frame &= (CMD_BACKUP-1);
+
+ // compare what the server returned with what we had predicted it to be
+ VectorSubtract (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame], delta);
+
+ // save the prediction error for interpolation
+ len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
+ if (len > 640) // 80 world units
+ { // a teleport or something
+ VectorClear (cl.prediction_error);
+ }
+ else
+ {
+ if (cl_showmiss->value && (delta[0] || delta[1] || delta[2]) )
+ Com_Printf ("prediction miss on %i: %i\n", cl.frame.serverframe,
+ delta[0] + delta[1] + delta[2]);
+
+ VectorCopy (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame]);
+
+ // save for error itnerpolation
+ for (i=0 ; i<3 ; i++)
+ cl.prediction_error[i] = delta[i]*0.125;
+ }
+}
+
+
+/*
+====================
+CL_ClipMoveToEntities
+
+====================
+*/
+void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
+{
+ int i, x, zd, zu;
+ trace_t trace;
+ int headnode;
+ float *angles;
+ entity_state_t *ent;
+ int num;
+ cmodel_t *cmodel;
+ vec3_t bmins, bmaxs;
+
+ for (i=0 ; i<cl.frame.num_entities ; i++)
+ {
+ num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+ ent = &cl_parse_entities[num];
+
+ if (!ent->solid)
+ continue;
+
+ if (ent->number == cl.playernum+1)
+ continue;
+
+ if (ent->solid == 31)
+ { // special value for bmodel
+ cmodel = cl.model_clip[ent->modelindex];
+ if (!cmodel)
+ continue;
+ headnode = cmodel->headnode;
+ angles = ent->angles;
+ }
+ else
+ { // encoded bbox
+ x = 8*(ent->solid & 31);
+ zd = 8*((ent->solid>>5) & 31);
+ zu = 8*((ent->solid>>10) & 63) - 32;
+
+ bmins[0] = bmins[1] = -x;
+ bmaxs[0] = bmaxs[1] = x;
+ bmins[2] = -zd;
+ bmaxs[2] = zu;
+
+ headnode = CM_HeadnodeForBox (bmins, bmaxs);
+ angles = vec3_origin; // boxes don't rotate
+ }
+
+ if (tr->allsolid)
+ return;
+
+ trace = CM_TransformedBoxTrace (start, end,
+ mins, maxs, headnode, MASK_PLAYERSOLID,
+ ent->origin, angles);
+
+ if (trace.allsolid || trace.startsolid ||
+ trace.fraction < tr->fraction)
+ {
+ trace.ent = (edict_t *)ent;
+ if (tr->startsolid)
+ {
+ *tr = trace;
+ tr->startsolid = true;
+ }
+ else
+ *tr = trace;
+ }
+ else if (trace.startsolid)
+ tr->startsolid = true;
+ }
+}
+
+
+/*
+================
+CL_PMTrace
+================
+*/
+trace_t CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
+{
+ trace_t t;
+
+ // check against world
+ t = CM_BoxTrace (start, end, mins, maxs, 0, MASK_PLAYERSOLID);
+ if (t.fraction < 1.0)
+ t.ent = (edict_t *)1;
+
+ // check all other solid models
+ CL_ClipMoveToEntities (start, mins, maxs, end, &t);
+
+ return t;
+}
+
+int CL_PMpointcontents (vec3_t point)
+{
+ int i;
+ entity_state_t *ent;
+ int num;
+ cmodel_t *cmodel;
+ int contents;
+
+ contents = CM_PointContents (point, 0);
+
+ for (i=0 ; i<cl.frame.num_entities ; i++)
+ {
+ num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+ ent = &cl_parse_entities[num];
+
+ if (ent->solid != 31) // special value for bmodel
+ continue;
+
+ cmodel = cl.model_clip[ent->modelindex];
+ if (!cmodel)
+ continue;
+
+ contents |= CM_TransformedPointContents (point, cmodel->headnode, ent->origin, ent->angles);
+ }
+
+ return contents;
+}
+
+
+/*
+=================
+CL_PredictMovement
+
+Sets cl.predicted_origin and cl.predicted_angles
+=================
+*/
+void CL_PredictMovement (void)
+{
+ int ack, current;
+ int frame;
+ int oldframe;
+ usercmd_t *cmd;
+ pmove_t pm;
+ int i;
+ int step;
+ int oldz;
+
+ if (cls.state != ca_active)
+ return;
+
+ if (cl_paused->value)
+ return;
+
+ if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
+ { // just set angles
+ for (i=0 ; i<3 ; i++)
+ {
+ cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]);
+ }
+ return;
+ }
+
+ ack = cls.netchan.incoming_acknowledged;
+ current = cls.netchan.outgoing_sequence;
+
+ // if we are too far out of date, just freeze
+ if (current - ack >= CMD_BACKUP)
+ {
+ if (cl_showmiss->value)
+ Com_Printf ("exceeded CMD_BACKUP\n");
+ return;
+ }
+
+ // copy current state to pmove
+ memset (&pm, 0, sizeof(pm));
+ pm.trace = CL_PMTrace;
+ pm.pointcontents = CL_PMpointcontents;
+
+ pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
+
+ pm.s = cl.frame.playerstate.pmove;
+
+// SCR_DebugGraph (current - ack - 1, 0);
+
+ // run frames
+ while (++ack < current)
+ {
+ frame = ack & (CMD_BACKUP-1);
+ cmd = &cl.cmds[frame];
+
+ pm.cmd = *cmd;
+ Pmove (&pm);
+
+ // save for debug checking
+ VectorCopy (pm.s.origin, cl.predicted_origins[frame]);
+ }
+
+ oldframe = (ack-2) & (CMD_BACKUP-1);
+ oldz = cl.predicted_origins[oldframe][2];
+ step = pm.s.origin[2] - oldz;
+ if (step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND) )
+ {
+ cl.predicted_step = step * 0.125;
+ cl.predicted_step_time = cls.realtime - cls.frametime * 500;
+ }
+
+
+ // copy results out for rendering
+ cl.predicted_origin[0] = pm.s.origin[0]*0.125;
+ cl.predicted_origin[1] = pm.s.origin[1]*0.125;
+ cl.predicted_origin[2] = pm.s.origin[2]*0.125;
+
+ VectorCopy (pm.viewangles, cl.predicted_angles);
+}
--- /dev/null
+++ b/cl_scrn.c
@@ -1,0 +1,1368 @@
+// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
+
+/*
+
+ full screen console
+ put up loading plaque
+ blanked background with loading plaque
+ blanked background with menu
+ cinematics
+ full screen image for quit and victory
+
+ end of unit intermissions
+
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+float scr_con_current; // aproaches scr_conlines at scr_conspeed
+float scr_conlines; // 0.0 to 1.0 lines of console to display
+
+qboolean scr_initialized; // ready to draw
+
+int scr_draw_loading;
+
+vrect_t scr_vrect; // position of render window on screen
+
+
+cvar_t *scr_viewsize;
+cvar_t *scr_conspeed;
+cvar_t *scr_centertime;
+cvar_t *scr_showturtle;
+cvar_t *scr_showpause;
+cvar_t *scr_printspeed;
+
+cvar_t *scr_netgraph;
+cvar_t *scr_timegraph;
+cvar_t *scr_debuggraph;
+cvar_t *scr_graphheight;
+cvar_t *scr_graphscale;
+cvar_t *scr_graphshift;
+cvar_t *scr_drawall;
+
+typedef struct
+{
+ int x1, y1, x2, y2;
+} dirty_t;
+
+dirty_t scr_dirty, scr_old_dirty[2];
+
+char crosshair_pic[MAX_QPATH];
+int crosshair_width, crosshair_height;
+
+void SCR_TimeRefresh_f (void);
+void SCR_Loading_f (void);
+
+
+/*
+===============================================================================
+
+BAR GRAPHS
+
+===============================================================================
+*/
+
+/*
+==============
+CL_AddNetgraph
+
+A new packet was just parsed
+==============
+*/
+void CL_AddNetgraph (void)
+{
+ int i;
+ int in;
+ int ping;
+
+ // if using the debuggraph for something else, don't
+ // add the net lines
+ if (scr_debuggraph->value || scr_timegraph->value)
+ return;
+
+ for (i=0 ; i<cls.netchan.dropped ; i++)
+ SCR_DebugGraph (30, 0x40);
+
+ for (i=0 ; i<cl.surpressCount ; i++)
+ SCR_DebugGraph (30, 0xdf);
+
+ // see what the latency was on this packet
+ in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
+ ping = cls.realtime - cl.cmd_time[in];
+ ping /= 30;
+ if (ping > 30)
+ ping = 30;
+ SCR_DebugGraph (ping, 0xd0);
+}
+
+
+typedef struct
+{
+ float value;
+ int color;
+} graphsamp_t;
+
+static int current;
+static graphsamp_t values[1024];
+
+/* this is in the client code, but can be used for debugging from server */
+void SCR_DebugGraph (float value, int color)
+{
+ values[current&1023].value = value;
+ values[current&1023].color = color;
+ current++;
+}
+
+/*
+==============
+SCR_DrawDebugGraph
+==============
+*/
+void SCR_DrawDebugGraph (void)
+{
+ int a, x, y, w, i, h;
+ float v;
+ int color;
+
+ //
+ // draw the graph
+ //
+ w = scr_vrect.width;
+
+ x = scr_vrect.x;
+ y = scr_vrect.y+scr_vrect.height;
+ re.DrawFill (x, y-scr_graphheight->value,
+ w, scr_graphheight->value, 8);
+
+ for (a=0 ; a<w ; a++)
+ {
+ i = (current-1-a+1024) & 1023;
+ v = values[i].value;
+ color = values[i].color;
+ v = v*scr_graphscale->value + scr_graphshift->value;
+
+ if (v < 0)
+ v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
+ h = (int)v % (int)scr_graphheight->value;
+ re.DrawFill (x+w-1-a, y - h, 1, h, color);
+ }
+}
+
+/*
+===============================================================================
+
+CENTER PRINTING
+
+===============================================================================
+*/
+
+char scr_centerstring[1024];
+float scr_centertime_start; // for slow victory printing
+float scr_centertime_off;
+int scr_center_lines;
+int scr_erase_center;
+
+/*
+==============
+SCR_CenterPrint
+
+Called for important messages that should stay in the center of the screen
+for a few moments
+==============
+*/
+void SCR_CenterPrint (char *str)
+{
+ char *s;
+ char line[64];
+ int i, j, l;
+
+ strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
+ scr_centertime_off = scr_centertime->value;
+ scr_centertime_start = cl.time;
+
+ // count the number of lines for centering
+ scr_center_lines = 1;
+ s = str;
+ while (*s)
+ {
+ if (*s == '\n')
+ scr_center_lines++;
+ s++;
+ }
+
+ // echo it to the console
+ Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+
+ s = str;
+ do
+ {
+ // scan the width of the line
+ for (l=0 ; l<40 ; l++)
+ if (s[l] == '\n' || !s[l])
+ break;
+ for (i=0 ; i<(40-l)/2 ; i++)
+ line[i] = ' ';
+
+ for (j=0 ; j<l ; j++)
+ {
+ line[i++] = s[j];
+ }
+
+ line[i] = '\n';
+ line[i+1] = 0;
+
+ Com_Printf ("%s", line);
+
+ while (*s && *s != '\n')
+ s++;
+
+ if (!*s)
+ break;
+ s++; // skip the \n
+ } while (1);
+ Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+ Con_ClearNotify ();
+}
+
+
+void SCR_DrawCenterString (void)
+{
+ char *start;
+ int l;
+ int j;
+ int x, y;
+ int remaining;
+
+// the finale prints the characters one at a time
+ remaining = 9999;
+
+ scr_erase_center = 0;
+ start = scr_centerstring;
+
+ if (scr_center_lines <= 4)
+ y = vid.height*0.35;
+ else
+ y = 48;
+
+ do
+ {
+ // scan the width of the line
+ for (l=0 ; l<40 ; l++)
+ if (start[l] == '\n' || !start[l])
+ break;
+ x = (vid.width - l*8)/2;
+ SCR_AddDirtyPoint (x, y);
+ for (j=0 ; j<l ; j++, x+=8)
+ {
+ re.DrawChar (x, y, start[j]);
+ if (!remaining--)
+ return;
+ }
+ SCR_AddDirtyPoint (x, y+8);
+
+ y += 8;
+
+ while (*start && *start != '\n')
+ start++;
+
+ if (!*start)
+ break;
+ start++; // skip the \n
+ } while (1);
+}
+
+void SCR_CheckDrawCenterString (void)
+{
+ scr_centertime_off -= cls.frametime;
+
+ if (scr_centertime_off <= 0)
+ return;
+
+ SCR_DrawCenterString ();
+}
+
+//=============================================================================
+
+/*
+=================
+SCR_CalcVrect
+
+Sets scr_vrect, the coordinates of the rendered window
+=================
+*/
+static void SCR_CalcVrect (void)
+{
+ int size;
+
+ // bound viewsize
+ if (scr_viewsize->value < 40)
+ Cvar_Set ("viewsize","40");
+ if (scr_viewsize->value > 100)
+ Cvar_Set ("viewsize","100");
+
+ size = scr_viewsize->value;
+
+ scr_vrect.width = vid.width*size/100;
+ scr_vrect.width &= ~7;
+
+ scr_vrect.height = vid.height*size/100;
+ scr_vrect.height &= ~1;
+
+ scr_vrect.x = (vid.width - scr_vrect.width)/2;
+ scr_vrect.y = (vid.height - scr_vrect.height)/2;
+}
+
+
+/*
+=================
+SCR_SizeUp_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeUp_f (void)
+{
+ Cvar_SetValue ("viewsize",scr_viewsize->value+10);
+}
+
+
+/*
+=================
+SCR_SizeDown_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeDown_f (void)
+{
+ Cvar_SetValue ("viewsize",scr_viewsize->value-10);
+}
+
+/*
+=================
+SCR_Sky_f
+
+Set a specific sky and rotation speed
+=================
+*/
+void SCR_Sky_f (void)
+{
+ float rotate;
+ vec3_t axis;
+
+ if (Cmd_Argc() < 2)
+ {
+ Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
+ return;
+ }
+ if (Cmd_Argc() > 2)
+ rotate = atof(Cmd_Argv(2));
+ else
+ rotate = 0;
+ if (Cmd_Argc() == 6)
+ {
+ axis[0] = atof(Cmd_Argv(3));
+ axis[1] = atof(Cmd_Argv(4));
+ axis[2] = atof(Cmd_Argv(5));
+ }
+ else
+ {
+ axis[0] = 0;
+ axis[1] = 0;
+ axis[2] = 1;
+ }
+
+ re.SetSky (Cmd_Argv(1), rotate, axis);
+}
+
+//============================================================================
+
+/*
+==================
+SCR_Init
+==================
+*/
+void SCR_Init (void)
+{
+ scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
+ scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
+ scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
+ scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
+ scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
+ scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
+ scr_netgraph = Cvar_Get ("netgraph", "0", 0);
+ scr_timegraph = Cvar_Get ("timegraph", "0", 0);
+ scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
+ scr_graphheight = Cvar_Get ("graphheight", "32", 0);
+ scr_graphscale = Cvar_Get ("graphscale", "1", 0);
+ scr_graphshift = Cvar_Get ("graphshift", "0", 0);
+ scr_drawall = Cvar_Get ("scr_drawall", "0", 0);
+
+//
+// register our commands
+//
+ Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
+ Cmd_AddCommand ("loading",SCR_Loading_f);
+ Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
+ Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
+ Cmd_AddCommand ("sky",SCR_Sky_f);
+
+ scr_initialized = true;
+}
+
+
+/*
+==============
+SCR_DrawNet
+==============
+*/
+void SCR_DrawNet (void)
+{
+ if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged
+ < CMD_BACKUP-1)
+ return;
+
+ re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");
+}
+
+/*
+==============
+SCR_DrawPause
+==============
+*/
+void SCR_DrawPause (void)
+{
+ int w, h;
+
+ if (!scr_showpause->value) // turn off for screenshots
+ return;
+
+ if (!cl_paused->value)
+ return;
+
+ re.DrawGetPicSize (&w, &h, "pause");
+ re.DrawPic ((vid.width-w)/2, vid.height/2 + 8, "pause");
+}
+
+/*
+==============
+SCR_DrawLoading
+==============
+*/
+void SCR_DrawLoading (void)
+{
+ int w, h;
+
+ if (!scr_draw_loading)
+ return;
+
+ scr_draw_loading = false;
+ re.DrawGetPicSize (&w, &h, "loading");
+ re.DrawPic ((vid.width-w)/2, (vid.height-h)/2, "loading");
+}
+
+//=============================================================================
+
+/*
+==================
+SCR_RunConsole
+
+Scroll it up or down
+==================
+*/
+void SCR_RunConsole (void)
+{
+// decide on the height of the console
+ if (cls.key_dest == key_console)
+ scr_conlines = 0.5; // half screen
+ else
+ scr_conlines = 0; // none visible
+
+ if (scr_conlines < scr_con_current)
+ {
+ scr_con_current -= scr_conspeed->value*cls.frametime;
+ if (scr_conlines > scr_con_current)
+ scr_con_current = scr_conlines;
+
+ }
+ else if (scr_conlines > scr_con_current)
+ {
+ scr_con_current += scr_conspeed->value*cls.frametime;
+ if (scr_conlines < scr_con_current)
+ scr_con_current = scr_conlines;
+ }
+
+}
+
+/*
+==================
+SCR_DrawConsole
+==================
+*/
+void SCR_DrawConsole (void)
+{
+ Con_CheckResize ();
+
+ if (cls.state == ca_disconnected || cls.state == ca_connecting)
+ { // forced full screen console
+ Con_DrawConsole (1.0);
+ return;
+ }
+
+ if (cls.state != ca_active || !cl.refresh_prepped)
+ { // connected, but can't render
+ Con_DrawConsole (0.5);
+ re.DrawFill (0, vid.height/2, vid.width, vid.height/2, 0);
+ return;
+ }
+
+ if (scr_con_current)
+ {
+ Con_DrawConsole (scr_con_current);
+ }
+ else
+ {
+ if (cls.key_dest == key_game || cls.key_dest == key_message)
+ Con_DrawNotify (); // only draw notify in game
+ }
+}
+
+//=============================================================================
+
+/*
+================
+SCR_BeginLoadingPlaque
+================
+*/
+void SCR_BeginLoadingPlaque (void)
+{
+ S_StopAllSounds ();
+ cl.sound_prepped = false; // don't play ambients
+ CDAudio_Stop ();
+ if (cls.disable_screen)
+ return;
+ if (developer->value)
+ return;
+ if (cls.state == ca_disconnected)
+ return; // if at console, don't bring up the plaque
+ if (cls.key_dest == key_console)
+ return;
+ if (cl.cinematictime > 0)
+ scr_draw_loading = 2; // clear to balack first
+ else
+ scr_draw_loading = 1;
+ SCR_UpdateScreen ();
+ cls.disable_screen = Sys_Milliseconds ();
+ cls.disable_servercount = cl.servercount;
+}
+
+/*
+================
+SCR_EndLoadingPlaque
+================
+*/
+void SCR_EndLoadingPlaque (void)
+{
+ cls.disable_screen = 0;
+ Con_ClearNotify ();
+}
+
+/*
+================
+SCR_Loading_f
+================
+*/
+void SCR_Loading_f (void)
+{
+ SCR_BeginLoadingPlaque ();
+}
+
+int
+entitycmpfnc(entity_t *a, entity_t *b)
+{
+ /* all other models are sorted by model then skin */
+ if(a->model == b->model)
+ return (uintptr)a->skin - (uintptr)b->skin;
+ else
+ return (uintptr)a->model - (uintptr)b->model;
+}
+
+void SCR_TimeRefresh_f (void)
+{
+ int i;
+ int start, stop;
+ float time;
+
+ if ( cls.state != ca_active )
+ return;
+
+ start = Sys_Milliseconds ();
+
+ if (Cmd_Argc() == 2)
+ { // run without page flipping
+ re.BeginFrame( 0 );
+ for (i=0 ; i<128 ; i++)
+ {
+ cl.refdef.viewangles[1] = i/128.0*360.0;
+ re.RenderFrame (&cl.refdef);
+ }
+ re.EndFrame();
+ }
+ else
+ {
+ for (i=0 ; i<128 ; i++)
+ {
+ cl.refdef.viewangles[1] = i/128.0*360.0;
+
+ re.BeginFrame( 0 );
+ re.RenderFrame (&cl.refdef);
+ re.EndFrame();
+ }
+ }
+
+ stop = Sys_Milliseconds ();
+ time = (stop-start)/1000.0;
+ Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
+}
+
+/*
+=================
+SCR_AddDirtyPoint
+=================
+*/
+void SCR_AddDirtyPoint (int x, int y)
+{
+ if (x < scr_dirty.x1)
+ scr_dirty.x1 = x;
+ if (x > scr_dirty.x2)
+ scr_dirty.x2 = x;
+ if (y < scr_dirty.y1)
+ scr_dirty.y1 = y;
+ if (y > scr_dirty.y2)
+ scr_dirty.y2 = y;
+}
+
+void SCR_DirtyScreen (void)
+{
+ SCR_AddDirtyPoint (0, 0);
+ SCR_AddDirtyPoint (vid.width-1, vid.height-1);
+}
+
+/*
+==============
+SCR_TileClear
+
+Clear any parts of the tiled background that were drawn on last frame
+==============
+*/
+void SCR_TileClear (void)
+{
+ int i;
+ int top, bottom, left, right;
+ dirty_t clear;
+
+ if (scr_drawall->value)
+ SCR_DirtyScreen (); // for power vr or broken page flippers...
+
+ if (scr_con_current == 1.0)
+ return; // full screen console
+ if (scr_viewsize->value == 100)
+ return; // full screen rendering
+ if (cl.cinematictime > 0)
+ return; // full screen cinematic
+
+ // erase rect will be the union of the past three frames
+ // so tripple buffering works properly
+ clear = scr_dirty;
+ for (i=0 ; i<2 ; i++)
+ {
+ if (scr_old_dirty[i].x1 < clear.x1)
+ clear.x1 = scr_old_dirty[i].x1;
+ if (scr_old_dirty[i].x2 > clear.x2)
+ clear.x2 = scr_old_dirty[i].x2;
+ if (scr_old_dirty[i].y1 < clear.y1)
+ clear.y1 = scr_old_dirty[i].y1;
+ if (scr_old_dirty[i].y2 > clear.y2)
+ clear.y2 = scr_old_dirty[i].y2;
+ }
+
+ scr_old_dirty[1] = scr_old_dirty[0];
+ scr_old_dirty[0] = scr_dirty;
+
+ scr_dirty.x1 = 9999;
+ scr_dirty.x2 = -9999;
+ scr_dirty.y1 = 9999;
+ scr_dirty.y2 = -9999;
+
+ // don't bother with anything convered by the console)
+ top = scr_con_current*vid.height;
+ if (top >= clear.y1)
+ clear.y1 = top;
+
+ if (clear.y2 <= clear.y1)
+ return; // nothing disturbed
+
+ top = scr_vrect.y;
+ bottom = top + scr_vrect.height-1;
+ left = scr_vrect.x;
+ right = left + scr_vrect.width-1;
+
+ if (clear.y1 < top)
+ { // clear above view screen
+ i = clear.y2 < top-1 ? clear.y2 : top-1;
+ re.DrawTileClear (clear.x1 , clear.y1,
+ clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
+ clear.y1 = top;
+ }
+ if (clear.y2 > bottom)
+ { // clear below view screen
+ i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
+ re.DrawTileClear (clear.x1, i,
+ clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
+ clear.y2 = bottom;
+ }
+ if (clear.x1 < left)
+ { // clear left of view screen
+ i = clear.x2 < left-1 ? clear.x2 : left-1;
+ re.DrawTileClear (clear.x1, clear.y1,
+ i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
+ clear.x1 = left;
+ }
+ if (clear.x2 > right)
+ { // clear left of view screen
+ i = clear.x1 > right+1 ? clear.x1 : right+1;
+ re.DrawTileClear (i, clear.y1,
+ clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
+ clear.x2 = right;
+ }
+
+}
+
+
+//===============================================================
+
+
+#define STAT_MINUS 10 // num frame for '-' stats digit
+char *sb_nums[2][11] =
+{
+ {"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
+ "num_6", "num_7", "num_8", "num_9", "num_minus"},
+ {"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
+ "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
+};
+
+#define ICON_WIDTH 24
+#define ICON_HEIGHT 24
+#define CHAR_WIDTH 16
+#define ICON_SPACE 8
+
+
+
+/*
+================
+SizeHUDString
+
+Allow embedded \n in the string
+================
+*/
+void SizeHUDString (char *string, int *w, int *h)
+{
+ int lines, width, current;
+
+ lines = 1;
+ width = 0;
+
+ current = 0;
+ while (*string)
+ {
+ if (*string == '\n')
+ {
+ lines++;
+ current = 0;
+ }
+ else
+ {
+ current++;
+ if (current > width)
+ width = current;
+ }
+ string++;
+ }
+
+ *w = width * 8;
+ *h = lines * 8;
+}
+
+void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)
+{
+ int margin;
+ char line[1024];
+ int width;
+ int i;
+
+ margin = x;
+
+ while (*string)
+ {
+ // scan out one line of text from the string
+ width = 0;
+ while (*string && *string != '\n')
+ line[width++] = *string++;
+ line[width] = 0;
+
+ if (centerwidth)
+ x = margin + (centerwidth - width*8)/2;
+ else
+ x = margin;
+ for (i=0 ; i<width ; i++)
+ {
+ re.DrawChar (x, y, line[i]^xor);
+ x += 8;
+ }
+ if (*string)
+ {
+ string++; // skip the \n
+ y += 8;
+ }
+ }
+}
+
+
+/*
+==============
+SCR_DrawField
+==============
+*/
+void SCR_DrawField (int x, int y, int color, int width, int value)
+{
+ char num[16], *ptr;
+ int l;
+ int frame;
+
+ if (width < 1)
+ return;
+
+ // draw number string
+ if (width > 5)
+ width = 5;
+
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);
+
+ Com_sprintf (num, sizeof(num), "%i", value);
+ l = strlen(num);
+ if (l > width)
+ l = width;
+ x += 2 + CHAR_WIDTH*(width - l);
+
+ ptr = num;
+ while (*ptr && l)
+ {
+ if (*ptr == '-')
+ frame = STAT_MINUS;
+ else
+ frame = *ptr -'0';
+
+ re.DrawPic (x,y,sb_nums[color][frame]);
+ x += CHAR_WIDTH;
+ ptr++;
+ l--;
+ }
+}
+
+
+/*
+===============
+SCR_TouchPics
+
+Allows rendering code to cache all needed sbar graphics
+===============
+*/
+void SCR_TouchPics (void)
+{
+ int i, j;
+
+ for (i=0 ; i<2 ; i++)
+ for (j=0 ; j<11 ; j++)
+ re.RegisterPic (sb_nums[i][j]);
+
+ if (crosshair->value)
+ {
+ if (crosshair->value > 3 || crosshair->value < 0)
+ crosshair->value = 3;
+
+ Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));
+ re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
+ if (!crosshair_width)
+ crosshair_pic[0] = 0;
+ }
+}
+
+/*
+================
+SCR_ExecuteLayoutString
+
+================
+*/
+void SCR_ExecuteLayoutString (char *s)
+{
+ int x, y;
+ int value;
+ char *token;
+ int width;
+ int index;
+ clientinfo_t *ci;
+
+ if (cls.state != ca_active || !cl.refresh_prepped)
+ return;
+
+ if (!s[0])
+ return;
+
+ x = 0;
+ y = 0;
+
+ while (s)
+ {
+ token = COM_Parse (&s);
+ if (!strcmp(token, "xl"))
+ {
+ token = COM_Parse (&s);
+ x = atoi(token);
+ continue;
+ }
+ if (!strcmp(token, "xr"))
+ {
+ token = COM_Parse (&s);
+ x = vid.width + atoi(token);
+ continue;
+ }
+ if (!strcmp(token, "xv"))
+ {
+ token = COM_Parse (&s);
+ x = vid.width/2 - 160 + atoi(token);
+ continue;
+ }
+
+ if (!strcmp(token, "yt"))
+ {
+ token = COM_Parse (&s);
+ y = atoi(token);
+ continue;
+ }
+ if (!strcmp(token, "yb"))
+ {
+ token = COM_Parse (&s);
+ y = vid.height + atoi(token);
+ continue;
+ }
+ if (!strcmp(token, "yv"))
+ {
+ token = COM_Parse (&s);
+ y = vid.height/2 - 120 + atoi(token);
+ continue;
+ }
+
+ if (!strcmp(token, "pic"))
+ { // draw a pic from a stat number
+ token = COM_Parse (&s);
+ value = cl.frame.playerstate.stats[atoi(token)];
+ if (value >= MAX_IMAGES)
+ Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
+ if (cl.configstrings[CS_IMAGES+value])
+ {
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+23, y+23);
+ re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
+ }
+ continue;
+ }
+
+ if (!strcmp(token, "client"))
+ { // draw a deathmatch client block
+ int score, ping, time;
+
+ token = COM_Parse (&s);
+ x = vid.width/2 - 160 + atoi(token);
+ token = COM_Parse (&s);
+ y = vid.height/2 - 120 + atoi(token);
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+159, y+31);
+
+ token = COM_Parse (&s);
+ value = atoi(token);
+ if (value >= MAX_CLIENTS || value < 0)
+ Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
+ ci = &cl.clientinfo[value];
+
+ token = COM_Parse (&s);
+ score = atoi(token);
+
+ token = COM_Parse (&s);
+ ping = atoi(token);
+
+ token = COM_Parse (&s);
+ time = atoi(token);
+
+ DrawAltString (x+32, y, ci->name);
+ DrawString (x+32, y+8, "Score: ");
+ DrawAltString (x+32+7*8, y+8, va("%i", score));
+ DrawString (x+32, y+16, va("Ping: %i", ping));
+ DrawString (x+32, y+24, va("Time: %i", time));
+
+ if (!ci->icon)
+ ci = &cl.baseclientinfo;
+ re.DrawPic (x, y, ci->iconname);
+ continue;
+ }
+
+ if (!strcmp(token, "ctf"))
+ { // draw a ctf client block
+ int score, ping;
+ char block[80];
+
+ token = COM_Parse (&s);
+ x = vid.width/2 - 160 + atoi(token);
+ token = COM_Parse (&s);
+ y = vid.height/2 - 120 + atoi(token);
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+159, y+31);
+
+ token = COM_Parse (&s);
+ value = atoi(token);
+ if (value >= MAX_CLIENTS || value < 0)
+ Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
+ ci = &cl.clientinfo[value];
+
+ token = COM_Parse (&s);
+ score = atoi(token);
+
+ token = COM_Parse (&s);
+ ping = atoi(token);
+ if (ping > 999)
+ ping = 999;
+
+ sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
+
+ if (value == cl.playernum)
+ DrawAltString (x, y, block);
+ else
+ DrawString (x, y, block);
+ continue;
+ }
+
+ if (!strcmp(token, "picn"))
+ { // draw a pic from a name
+ token = COM_Parse (&s);
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+23, y+23);
+ re.DrawPic (x, y, token);
+ continue;
+ }
+
+ if (!strcmp(token, "num"))
+ { // draw a number
+ token = COM_Parse (&s);
+ width = atoi(token);
+ token = COM_Parse (&s);
+ value = cl.frame.playerstate.stats[atoi(token)];
+ SCR_DrawField (x, y, 0, width, value);
+ continue;
+ }
+
+ if (!strcmp(token, "hnum"))
+ { // health number
+ int color;
+
+ width = 3;
+ value = cl.frame.playerstate.stats[STAT_HEALTH];
+ if (value > 25)
+ color = 0; // green
+ else if (value > 0)
+ color = (cl.frame.serverframe>>2) & 1; // flash
+ else
+ color = 1;
+
+ if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)
+ re.DrawPic (x, y, "field_3");
+
+ SCR_DrawField (x, y, color, width, value);
+ continue;
+ }
+
+ if (!strcmp(token, "anum"))
+ { // ammo number
+ int color;
+
+ width = 3;
+ value = cl.frame.playerstate.stats[STAT_AMMO];
+ if (value > 5)
+ color = 0; // green
+ else if (value >= 0)
+ color = (cl.frame.serverframe>>2) & 1; // flash
+ else
+ continue; // negative number = don't show
+
+ if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)
+ re.DrawPic (x, y, "field_3");
+
+ SCR_DrawField (x, y, color, width, value);
+ continue;
+ }
+
+ if (!strcmp(token, "rnum"))
+ { // armor number
+ int color;
+
+ width = 3;
+ value = cl.frame.playerstate.stats[STAT_ARMOR];
+ if (value < 1)
+ continue;
+
+ color = 0; // green
+
+ if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)
+ re.DrawPic (x, y, "field_3");
+
+ SCR_DrawField (x, y, color, width, value);
+ continue;
+ }
+
+
+ if (!strcmp(token, "stat_string"))
+ {
+ token = COM_Parse (&s);
+ index = atoi(token);
+ if (index < 0 || index >= MAX_CONFIGSTRINGS)
+ Com_Error (ERR_DROP, "Bad stat_string index");
+ index = cl.frame.playerstate.stats[index];
+ if (index < 0 || index >= MAX_CONFIGSTRINGS)
+ Com_Error (ERR_DROP, "Bad stat_string index");
+ DrawString (x, y, cl.configstrings[index]);
+ continue;
+ }
+
+ if (!strcmp(token, "cstring"))
+ {
+ token = COM_Parse (&s);
+ DrawHUDString (token, x, y, 320, 0);
+ continue;
+ }
+
+ if (!strcmp(token, "string"))
+ {
+ token = COM_Parse (&s);
+ DrawString (x, y, token);
+ continue;
+ }
+
+ if (!strcmp(token, "cstring2"))
+ {
+ token = COM_Parse (&s);
+ DrawHUDString (token, x, y, 320,0x80);
+ continue;
+ }
+
+ if (!strcmp(token, "string2"))
+ {
+ token = COM_Parse (&s);
+ DrawAltString (x, y, token);
+ continue;
+ }
+
+ if (!strcmp(token, "if"))
+ { // draw a number
+ token = COM_Parse (&s);
+ value = cl.frame.playerstate.stats[atoi(token)];
+ if (!value)
+ { // skip to endif
+ while (s && strcmp(token, "endif") )
+ {
+ token = COM_Parse (&s);
+ }
+ }
+
+ continue;
+ }
+
+
+ }
+}
+
+
+/*
+================
+SCR_DrawStats
+
+The status bar is a small layout program that
+is based on the stats array
+================
+*/
+void SCR_DrawStats (void)
+{
+ SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
+}
+
+
+/*
+================
+SCR_DrawLayout
+
+================
+*/
+void SCR_DrawLayout (void)
+{
+ if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
+ return;
+ SCR_ExecuteLayoutString (cl.layout);
+}
+
+//=======================================================
+
+/*
+==================
+SCR_UpdateScreen
+
+This is called every frame, and can also be called explicitly to flush
+text to the screen.
+==================
+*/
+void SCR_UpdateScreen (void)
+{
+ int numframes;
+ int i;
+ float separation[2] = { 0, 0 };
+
+ // if the screen is disabled (loading plaque is up, or vid mode changing)
+ // do nothing at all
+ if (cls.disable_screen)
+ {
+ if (Sys_Milliseconds() - cls.disable_screen > 120000)
+ {
+ cls.disable_screen = 0;
+ Com_Printf ("Loading plaque timed out.\n");
+ }
+ return;
+ }
+
+ if (!scr_initialized || !con.initialized)
+ return; // not initialized yet
+
+ /*
+ ** range check cl_camera_separation so we don't inadvertently fry someone's
+ ** brain
+ */
+ if ( cl_stereo_separation->value > 1.0 )
+ Cvar_SetValue( "cl_stereo_separation", 1.0 );
+ else if ( cl_stereo_separation->value < 0 )
+ Cvar_SetValue( "cl_stereo_separation", 0.0 );
+
+ if ( cl_stereo->value )
+ {
+ numframes = 2;
+ separation[0] = -cl_stereo_separation->value / 2;
+ separation[1] = cl_stereo_separation->value / 2;
+ }
+ else
+ {
+ separation[0] = 0;
+ separation[1] = 0;
+ numframes = 1;
+ }
+
+ for ( i = 0; i < numframes; i++ )
+ {
+ re.BeginFrame( separation[i] );
+
+ if (scr_draw_loading == 2)
+ { // loading plaque over black screen
+ int w, h;
+
+ re.CinematicSetPalette(NULL);
+ scr_draw_loading = false;
+ re.DrawGetPicSize (&w, &h, "loading");
+ re.DrawPic ((vid.width-w)/2, (vid.height-h)/2, "loading");
+// re.EndFrame();
+// return;
+ }
+ // if a cinematic is supposed to be running, handle menus
+ // and console specially
+ else if (cl.cinematictime > 0)
+ {
+ if (cls.key_dest == key_menu)
+ {
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ }
+ M_Draw ();
+// re.EndFrame();
+// return;
+ }
+ else if (cls.key_dest == key_console)
+ {
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ }
+ SCR_DrawConsole ();
+// re.EndFrame();
+// return;
+ }
+ else
+ {
+ SCR_DrawCinematic();
+// re.EndFrame();
+// return;
+ }
+ }
+ else
+ {
+
+ // make sure the game palette is active
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ }
+
+ // do 3D refresh drawing, and then update the screen
+ SCR_CalcVrect ();
+
+ // clear any dirty part of the background
+ SCR_TileClear ();
+
+ V_RenderView ( separation[i] );
+
+ SCR_DrawStats ();
+ if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
+ SCR_DrawLayout ();
+ if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
+ CL_DrawInventory ();
+
+ SCR_DrawNet ();
+ SCR_CheckDrawCenterString ();
+
+ if (scr_timegraph->value)
+ SCR_DebugGraph (cls.frametime*300, 0);
+
+ if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
+ SCR_DrawDebugGraph ();
+
+ SCR_DrawPause ();
+
+ SCR_DrawConsole ();
+
+ M_Draw ();
+
+ SCR_DrawLoading ();
+ }
+ }
+ re.EndFrame();
+}
--- /dev/null
+++ b/cl_tent.c
@@ -1,0 +1,1718 @@
+// cl_tent.c -- client side temporary entities
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef enum
+{
+ ex_free, ex_explosion, ex_misc, ex_flash, ex_mflash, ex_poly, ex_poly2
+} exptype_t;
+
+typedef struct
+{
+ exptype_t type;
+ entity_t ent;
+
+ int frames;
+ float light;
+ vec3_t lightcolor;
+ float start;
+ int baseframe;
+} explosion_t;
+
+
+
+#define MAX_EXPLOSIONS 32
+explosion_t cl_explosions[MAX_EXPLOSIONS];
+
+
+#define MAX_BEAMS 32
+typedef struct
+{
+ int entity;
+ int dest_entity;
+ model_t *model;
+ int endtime;
+ vec3_t offset;
+ vec3_t start, end;
+} beam_t;
+beam_t cl_beams[MAX_BEAMS];
+//PMM - added this for player-linked beams. Currently only used by the plasma beam
+beam_t cl_playerbeams[MAX_BEAMS];
+
+
+#define MAX_LASERS 32
+typedef struct
+{
+ entity_t ent;
+ int endtime;
+} laser_t;
+laser_t cl_lasers[MAX_LASERS];
+
+//ROGUE
+cl_sustain_t cl_sustains[MAX_SUSTAINS];
+//ROGUE
+
+//PGM
+extern void CL_TeleportParticles (vec3_t org);
+//PGM
+
+void CL_BlasterParticles (vec3_t org, vec3_t dir);
+void CL_ExplosionParticles (vec3_t org);
+void CL_BFGExplosionParticles (vec3_t org);
+// RAFAEL
+void CL_BlueBlasterParticles (vec3_t org, vec3_t dir);
+
+sfx_t *cl_sfx_ric1;
+sfx_t *cl_sfx_ric2;
+sfx_t *cl_sfx_ric3;
+sfx_t *cl_sfx_lashit;
+sfx_t *cl_sfx_spark5;
+sfx_t *cl_sfx_spark6;
+sfx_t *cl_sfx_spark7;
+sfx_t *cl_sfx_railg;
+sfx_t *cl_sfx_rockexp;
+sfx_t *cl_sfx_grenexp;
+sfx_t *cl_sfx_watrexp;
+sfx_t *cl_sfx_plasexp;
+sfx_t *cl_sfx_footsteps[4];
+
+model_t *cl_mod_explode;
+model_t *cl_mod_smoke;
+model_t *cl_mod_flash;
+model_t *cl_mod_parasite_segment;
+model_t *cl_mod_grapple_cable;
+model_t *cl_mod_parasite_tip;
+model_t *cl_mod_explo4;
+model_t *cl_mod_bfg_explo;
+model_t *cl_mod_powerscreen;
+// RAFAEL
+model_t *cl_mod_plasmaexplo;
+
+//ROGUE
+sfx_t *cl_sfx_lightning;
+sfx_t *cl_sfx_disrexp;
+model_t *cl_mod_lightning;
+model_t *cl_mod_heatbeam;
+model_t *cl_mod_monster_heatbeam;
+model_t *cl_mod_explo4_big;
+
+//ROGUE
+/*
+=================
+CL_RegisterTEntSounds
+=================
+*/
+void CL_RegisterTEntSounds (void)
+{
+ int i;
+ char name[MAX_QPATH];
+
+ // PMM - version stuff
+// Com_Printf ("%s\n", ROGUE_VERSION_STRING);
+ // PMM
+ cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav");
+ cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav");
+ cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav");
+ cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav");
+ cl_sfx_spark5 = S_RegisterSound ("world/spark5.wav");
+ cl_sfx_spark6 = S_RegisterSound ("world/spark6.wav");
+ cl_sfx_spark7 = S_RegisterSound ("world/spark7.wav");
+ cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav");
+ cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav");
+ cl_sfx_grenexp = S_RegisterSound ("weapons/grenlx1a.wav");
+ cl_sfx_watrexp = S_RegisterSound ("weapons/xpld_wat.wav");
+ // RAFAEL
+ // cl_sfx_plasexp = S_RegisterSound ("weapons/plasexpl.wav");
+ S_RegisterSound ("player/land1.wav");
+
+ S_RegisterSound ("player/fall2.wav");
+ S_RegisterSound ("player/fall1.wav");
+
+ for (i=0 ; i<4 ; i++)
+ {
+ Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
+ cl_sfx_footsteps[i] = S_RegisterSound (name);
+ }
+
+//PGM
+ cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav");
+ cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav");
+ // version stuff
+ sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID);
+ if (name[0] == 'w')
+ name[0] = 'W';
+//PGM
+}
+
+/*
+=================
+CL_RegisterTEntModels
+=================
+*/
+void CL_RegisterTEntModels (void)
+{
+ cl_mod_explode = re.RegisterModel ("models/objects/explode/tris.md2");
+ cl_mod_smoke = re.RegisterModel ("models/objects/smoke/tris.md2");
+ cl_mod_flash = re.RegisterModel ("models/objects/flash/tris.md2");
+ cl_mod_parasite_segment = re.RegisterModel ("models/monsters/parasite/segment/tris.md2");
+ cl_mod_grapple_cable = re.RegisterModel ("models/ctf/segment/tris.md2");
+ cl_mod_parasite_tip = re.RegisterModel ("models/monsters/parasite/tip/tris.md2");
+ cl_mod_explo4 = re.RegisterModel ("models/objects/r_explode/tris.md2");
+ cl_mod_bfg_explo = re.RegisterModel ("sprites/s_bfg2.sp2");
+ cl_mod_powerscreen = re.RegisterModel ("models/items/armor/effect/tris.md2");
+
+re.RegisterModel ("models/objects/laser/tris.md2");
+re.RegisterModel ("models/objects/grenade2/tris.md2");
+re.RegisterModel ("models/weapons/v_machn/tris.md2");
+re.RegisterModel ("models/weapons/v_handgr/tris.md2");
+re.RegisterModel ("models/weapons/v_shotg2/tris.md2");
+re.RegisterModel ("models/objects/gibs/bone/tris.md2");
+re.RegisterModel ("models/objects/gibs/sm_meat/tris.md2");
+re.RegisterModel ("models/objects/gibs/bone2/tris.md2");
+// RAFAEL
+// re.RegisterModel ("models/objects/blaser/tris.md2");
+
+re.RegisterPic ("w_machinegun");
+re.RegisterPic ("a_bullets");
+re.RegisterPic ("i_health");
+re.RegisterPic ("a_grenades");
+
+//ROGUE
+ cl_mod_explo4_big = re.RegisterModel ("models/objects/r_explode2/tris.md2");
+ cl_mod_lightning = re.RegisterModel ("models/proj/lightning/tris.md2");
+ cl_mod_heatbeam = re.RegisterModel ("models/proj/beam/tris.md2");
+ cl_mod_monster_heatbeam = re.RegisterModel ("models/proj/widowbeam/tris.md2");
+//ROGUE
+}
+
+/*
+=================
+CL_ClearTEnts
+=================
+*/
+void CL_ClearTEnts (void)
+{
+ memset (cl_beams, 0, sizeof(cl_beams));
+ memset (cl_explosions, 0, sizeof(cl_explosions));
+ memset (cl_lasers, 0, sizeof(cl_lasers));
+
+//ROGUE
+ memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
+ memset (cl_sustains, 0, sizeof(cl_sustains));
+//ROGUE
+}
+
+/*
+=================
+CL_AllocExplosion
+=================
+*/
+explosion_t *CL_AllocExplosion (void)
+{
+ int i;
+ int time;
+ int index;
+
+ for (i=0 ; i<MAX_EXPLOSIONS ; i++)
+ {
+ if (cl_explosions[i].type == ex_free)
+ {
+ memset (&cl_explosions[i], 0, sizeof (cl_explosions[i]));
+ return &cl_explosions[i];
+ }
+ }
+// find the oldest explosion
+ time = cl.time;
+ index = 0;
+
+ for (i=0 ; i<MAX_EXPLOSIONS ; i++)
+ if (cl_explosions[i].start < time)
+ {
+ time = cl_explosions[i].start;
+ index = i;
+ }
+ memset (&cl_explosions[index], 0, sizeof (cl_explosions[index]));
+ return &cl_explosions[index];
+}
+
+/*
+=================
+CL_SmokeAndFlash
+=================
+*/
+void CL_SmokeAndFlash(vec3_t origin)
+{
+ explosion_t *ex;
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (origin, ex->ent.origin);
+ ex->type = ex_misc;
+ ex->frames = 4;
+ ex->ent.flags = RF_TRANSLUCENT;
+ ex->start = cl.frame.servertime - 100;
+ ex->ent.model = cl_mod_smoke;
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (origin, ex->ent.origin);
+ ex->type = ex_flash;
+ ex->ent.flags = RF_FULLBRIGHT;
+ ex->frames = 2;
+ ex->start = cl.frame.servertime - 100;
+ ex->ent.model = cl_mod_flash;
+}
+
+/*
+=================
+CL_ParseParticles
+=================
+*/
+void CL_ParseParticles (void)
+{
+ int color, count;
+ vec3_t pos, dir;
+
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+
+ color = MSG_ReadByte (&net_message);
+
+ count = MSG_ReadByte (&net_message);
+
+ CL_ParticleEffect (pos, dir, color, count);
+}
+
+int
+CL_ParseBeam(model_t *model)
+{
+ int ent;
+ vec3_t start, end;
+ beam_t *b;
+ int i;
+
+ ent = MSG_ReadShort (&net_message);
+
+ MSG_ReadPos (&net_message, start);
+ MSG_ReadPos (&net_message, end);
+
+// override any beam with the same entity
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ if (b->entity == ent)
+ {
+ b->entity = ent;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorClear (b->offset);
+ return ent;
+ }
+
+// find a free beam
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ {
+ if (!b->model || b->endtime < cl.time)
+ {
+ b->entity = ent;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorClear (b->offset);
+ return ent;
+ }
+ }
+ Com_Printf ("beam list overflow!\n");
+ return ent;
+}
+
+int
+CL_ParseBeam2(model_t *model)
+{
+ int ent;
+ vec3_t start, end, offset;
+ beam_t *b;
+ int i;
+
+ ent = MSG_ReadShort (&net_message);
+
+ MSG_ReadPos (&net_message, start);
+ MSG_ReadPos (&net_message, end);
+ MSG_ReadPos (&net_message, offset);
+
+// Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
+
+// override any beam with the same entity
+
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ if (b->entity == ent)
+ {
+ b->entity = ent;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorCopy (offset, b->offset);
+ return ent;
+ }
+
+// find a free beam
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ {
+ if (!b->model || b->endtime < cl.time)
+ {
+ b->entity = ent;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorCopy (offset, b->offset);
+ return ent;
+ }
+ }
+ Com_Printf ("beam list overflow!\n");
+ return ent;
+}
+
+// ROGUE
+/*
+=================
+CL_ParsePlayerBeam
+ - adds to the cl_playerbeam array instead of the cl_beams array
+=================
+*/
+int
+CL_ParsePlayerBeam(model_t *model)
+{
+ int ent;
+ vec3_t start, end, offset;
+ beam_t *b;
+ int i;
+
+ ent = MSG_ReadShort (&net_message);
+
+ MSG_ReadPos (&net_message, start);
+ MSG_ReadPos (&net_message, end);
+ // PMM - network optimization
+ if (model == cl_mod_heatbeam)
+ VectorSet(offset, 2, 7, -3);
+ else if (model == cl_mod_monster_heatbeam)
+ {
+ model = cl_mod_heatbeam;
+ VectorSet(offset, 0, 0, 0);
+ }
+ else
+ MSG_ReadPos (&net_message, offset);
+
+// Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
+
+// override any beam with the same entity
+// PMM - For player beams, we only want one per player (entity) so..
+ for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
+ {
+ if (b->entity == ent)
+ {
+ b->entity = ent;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorCopy (offset, b->offset);
+ return ent;
+ }
+ }
+
+// find a free beam
+ for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
+ {
+ if (!b->model || b->endtime < cl.time)
+ {
+ b->entity = ent;
+ b->model = model;
+ b->endtime = cl.time + 100; // PMM - this needs to be 100 to prevent multiple heatbeams
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorCopy (offset, b->offset);
+ return ent;
+ }
+ }
+ Com_Printf ("beam list overflow!\n");
+ return ent;
+}
+//rogue
+
+int
+CL_ParseLightning(model_t *model)
+{
+ int srcEnt, destEnt;
+ vec3_t start, end;
+ beam_t *b;
+ int i;
+
+ srcEnt = MSG_ReadShort (&net_message);
+ destEnt = MSG_ReadShort (&net_message);
+
+ MSG_ReadPos (&net_message, start);
+ MSG_ReadPos (&net_message, end);
+
+// override any beam with the same source AND destination entities
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ if (b->entity == srcEnt && b->dest_entity == destEnt)
+ {
+// Com_Printf("%d: OVERRIDE %d -> %d\n", cl.time, srcEnt, destEnt);
+ b->entity = srcEnt;
+ b->dest_entity = destEnt;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorClear (b->offset);
+ return srcEnt;
+ }
+
+// find a free beam
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ {
+ if (!b->model || b->endtime < cl.time)
+ {
+// Com_Printf("%d: NORMAL %d -> %d\n", cl.time, srcEnt, destEnt);
+ b->entity = srcEnt;
+ b->dest_entity = destEnt;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorClear (b->offset);
+ return srcEnt;
+ }
+ }
+ Com_Printf ("beam list overflow!\n");
+ return srcEnt;
+}
+
+/*
+=================
+CL_ParseLaser
+=================
+*/
+void CL_ParseLaser (int colors)
+{
+ vec3_t start;
+ vec3_t end;
+ laser_t *l;
+ int i;
+
+ MSG_ReadPos (&net_message, start);
+ MSG_ReadPos (&net_message, end);
+
+ for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
+ {
+ if (l->endtime < cl.time)
+ {
+ l->ent.flags = RF_TRANSLUCENT | RF_BEAM;
+ VectorCopy (start, l->ent.origin);
+ VectorCopy (end, l->ent.oldorigin);
+ l->ent.alpha = 0.30;
+ l->ent.skinnum = (colors >> ((rand() % 4)*8)) & 0xff;
+ l->ent.model = NULL;
+ l->ent.frame = 4;
+ l->endtime = cl.time + 100;
+ return;
+ }
+ }
+}
+
+//=============
+//ROGUE
+void CL_ParseSteam (void)
+{
+ vec3_t pos, dir;
+ int id, i;
+ int r;
+ int cnt;
+ int color;
+ int magnitude;
+ cl_sustain_t *s, *free_sustain;
+
+ id = MSG_ReadShort (&net_message); // an id of -1 is an instant effect
+ if (id != -1) // sustains
+ {
+// Com_Printf ("Sustain effect id %d\n", id);
+ free_sustain = NULL;
+ for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
+ {
+ if (s->id == 0)
+ {
+ free_sustain = s;
+ break;
+ }
+ }
+ if (free_sustain)
+ {
+ s->id = id;
+ s->count = MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, s->org);
+ MSG_ReadDir (&net_message, s->dir);
+ r = MSG_ReadByte (&net_message);
+ s->color = r & 0xff;
+ s->magnitude = MSG_ReadShort (&net_message);
+ s->endtime = cl.time + MSG_ReadLong (&net_message);
+ s->think = CL_ParticleSteamEffect2;
+ s->thinkinterval = 100;
+ s->nextthink = cl.time;
+ }
+ else
+ {
+// Com_Printf ("No free sustains!\n");
+ // FIXME - read the stuff anyway /* and toss the results */
+ MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ MSG_ReadByte (&net_message);
+ MSG_ReadShort (&net_message);
+ MSG_ReadLong (&net_message); // really interval
+ }
+ }
+ else // instant
+ {
+ cnt = MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ r = MSG_ReadByte (&net_message);
+ magnitude = MSG_ReadShort (&net_message);
+ color = r & 0xff;
+ CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
+// S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ }
+}
+
+void CL_ParseWidow (void)
+{
+ vec3_t pos;
+ int id, i;
+ cl_sustain_t *s, *free_sustain;
+
+ id = MSG_ReadShort (&net_message);
+
+ free_sustain = NULL;
+ for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
+ {
+ if (s->id == 0)
+ {
+ free_sustain = s;
+ break;
+ }
+ }
+ if (free_sustain)
+ {
+ s->id = id;
+ MSG_ReadPos (&net_message, s->org);
+ s->endtime = cl.time + 2100;
+ s->think = CL_Widowbeamout;
+ s->thinkinterval = 1;
+ s->nextthink = cl.time;
+ }
+ else // no free sustains
+ {
+ // FIXME - read the stuff anyway
+ MSG_ReadPos (&net_message, pos);
+ }
+}
+
+void CL_ParseNuke (void)
+{
+ vec3_t pos;
+ int i;
+ cl_sustain_t *s, *free_sustain;
+
+ free_sustain = NULL;
+ for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
+ {
+ if (s->id == 0)
+ {
+ free_sustain = s;
+ break;
+ }
+ }
+ if (free_sustain)
+ {
+ s->id = 21000;
+ MSG_ReadPos (&net_message, s->org);
+ s->endtime = cl.time + 1000;
+ s->think = CL_Nukeblast;
+ s->thinkinterval = 1;
+ s->nextthink = cl.time;
+ }
+ else // no free sustains
+ {
+ // FIXME - read the stuff anyway
+ MSG_ReadPos (&net_message, pos);
+ }
+}
+
+//ROGUE
+//=============
+
+
+/*
+=================
+CL_ParseTEnt
+=================
+*/
+static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
+
+void CL_ParseTEnt (void)
+{
+ int type;
+ vec3_t pos, pos2, dir;
+ explosion_t *ex;
+ int cnt;
+ int color;
+ int r;
+ int ent;
+ int magnitude;
+
+ type = MSG_ReadByte (&net_message);
+
+ switch (type)
+ {
+ case TE_BLOOD: // bullet hitting flesh
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ CL_ParticleEffect (pos, dir, 0xe8, 60);
+ break;
+
+ case TE_GUNSHOT: // bullet hitting wall
+ case TE_SPARKS:
+ case TE_BULLET_SPARKS:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ if (type == TE_GUNSHOT)
+ CL_ParticleEffect (pos, dir, 0, 40);
+ else
+ CL_ParticleEffect (pos, dir, 0xe0, 6);
+
+ if (type != TE_SPARKS)
+ {
+ CL_SmokeAndFlash(pos);
+
+ // impact sound
+ cnt = rand()&15;
+ if (cnt == 1)
+ S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
+ else if (cnt == 2)
+ S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
+ else if (cnt == 3)
+ S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
+ }
+
+ break;
+
+ case TE_SCREEN_SPARKS:
+ case TE_SHIELD_SPARKS:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ if (type == TE_SCREEN_SPARKS)
+ CL_ParticleEffect (pos, dir, 0xd0, 40);
+ else
+ CL_ParticleEffect (pos, dir, 0xb0, 40);
+ //FIXME : replace or remove this sound
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_SHOTGUN: // bullet hitting wall
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ CL_ParticleEffect (pos, dir, 0, 20);
+ CL_SmokeAndFlash(pos);
+ break;
+
+ case TE_SPLASH: // bullet hitting water
+ cnt = MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ r = MSG_ReadByte (&net_message);
+ if (r > 6)
+ color = 0x00;
+ else
+ color = splash_color[r];
+ CL_ParticleEffect (pos, dir, color, cnt);
+
+ if (r == SPLASH_SPARKS)
+ {
+ r = rand() & 3;
+ if (r == 0)
+ S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
+ else if (r == 1)
+ S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
+ else
+ S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
+ }
+ break;
+
+ case TE_LASER_SPARKS:
+ cnt = MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ color = MSG_ReadByte (&net_message);
+ CL_ParticleEffect2 (pos, dir, color, cnt);
+ break;
+
+ // RAFAEL
+ case TE_BLUEHYPERBLASTER:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadPos (&net_message, dir);
+ CL_BlasterParticles (pos, dir);
+ break;
+
+ case TE_BLASTER: // blaster hitting wall
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ CL_BlasterParticles (pos, dir);
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->ent.angles[0] = acos(dir[2])/M_PI*180;
+ // PMM - fixed to correct for pitch of 0
+ if (dir[0])
+ ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
+ else if (dir[1] > 0)
+ ex->ent.angles[1] = 90;
+ else if (dir[1] < 0)
+ ex->ent.angles[1] = 270;
+ else
+ ex->ent.angles[1] = 0;
+
+ ex->type = ex_misc;
+ ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 150;
+ ex->lightcolor[0] = 1;
+ ex->lightcolor[1] = 1;
+ ex->ent.model = cl_mod_explode;
+ ex->frames = 4;
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_RAILTRAIL: // railgun effect
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadPos (&net_message, pos2);
+ CL_RailTrail (pos, pos2);
+ S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_EXPLOSION2:
+ case TE_GRENADE_EXPLOSION:
+ case TE_GRENADE_EXPLOSION_WATER:
+ MSG_ReadPos (&net_message, pos);
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->type = ex_poly;
+ ex->ent.flags = RF_FULLBRIGHT;
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 350;
+ ex->lightcolor[0] = 1.0;
+ ex->lightcolor[1] = 0.5;
+ ex->lightcolor[2] = 0.5;
+ ex->ent.model = cl_mod_explo4;
+ ex->frames = 19;
+ ex->baseframe = 30;
+ ex->ent.angles[1] = rand() % 360;
+ CL_ExplosionParticles (pos);
+ if (type == TE_GRENADE_EXPLOSION_WATER)
+ S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+ else
+ S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
+ break;
+
+ // RAFAEL
+ case TE_PLASMA_EXPLOSION:
+ MSG_ReadPos (&net_message, pos);
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->type = ex_poly;
+ ex->ent.flags = RF_FULLBRIGHT;
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 350;
+ ex->lightcolor[0] = 1.0;
+ ex->lightcolor[1] = 0.5;
+ ex->lightcolor[2] = 0.5;
+ ex->ent.angles[1] = rand() % 360;
+ ex->ent.model = cl_mod_explo4;
+ if (qfrand() < 0.5)
+ ex->baseframe = 15;
+ ex->frames = 15;
+ CL_ExplosionParticles (pos);
+ S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_EXPLOSION1:
+ case TE_EXPLOSION1_BIG: // PMM
+ case TE_ROCKET_EXPLOSION:
+ case TE_ROCKET_EXPLOSION_WATER:
+ case TE_EXPLOSION1_NP: // PMM
+ MSG_ReadPos (&net_message, pos);
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->type = ex_poly;
+ ex->ent.flags = RF_FULLBRIGHT;
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 350;
+ ex->lightcolor[0] = 1.0;
+ ex->lightcolor[1] = 0.5;
+ ex->lightcolor[2] = 0.5;
+ ex->ent.angles[1] = rand() % 360;
+ if (type != TE_EXPLOSION1_BIG) // PMM
+ ex->ent.model = cl_mod_explo4; // PMM
+ else
+ ex->ent.model = cl_mod_explo4_big;
+ if (qfrand() < 0.5)
+ ex->baseframe = 15;
+ ex->frames = 15;
+ if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP)) // PMM
+ CL_ExplosionParticles (pos); // PMM
+ if (type == TE_ROCKET_EXPLOSION_WATER)
+ S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+ else
+ S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_BFG_EXPLOSION:
+ MSG_ReadPos (&net_message, pos);
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->type = ex_poly;
+ ex->ent.flags = RF_FULLBRIGHT;
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 350;
+ ex->lightcolor[0] = 0.0;
+ ex->lightcolor[1] = 1.0;
+ ex->lightcolor[2] = 0.0;
+ ex->ent.model = cl_mod_bfg_explo;
+ ex->ent.flags |= RF_TRANSLUCENT;
+ ex->ent.alpha = 0.30;
+ ex->frames = 4;
+ break;
+
+ case TE_BFG_BIGEXPLOSION:
+ MSG_ReadPos (&net_message, pos);
+ CL_BFGExplosionParticles (pos);
+ break;
+
+ case TE_BFG_LASER:
+ CL_ParseLaser (0xd0d1d2d3);
+ break;
+
+ case TE_BUBBLETRAIL:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadPos (&net_message, pos2);
+ CL_BubbleTrail (pos, pos2);
+ break;
+
+ case TE_PARASITE_ATTACK:
+ case TE_MEDIC_CABLE_ATTACK:
+ CL_ParseBeam (cl_mod_parasite_segment); /* toss result */
+ break;
+
+ case TE_BOSSTPORT: // boss teleporting to station
+ MSG_ReadPos (&net_message, pos);
+ CL_BigTeleportParticles (pos);
+ S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0);
+ break;
+
+ case TE_GRAPPLE_CABLE:
+ CL_ParseBeam2 (cl_mod_grapple_cable); /* toss result */
+ break;
+
+ // RAFAEL
+ case TE_WELDING_SPARKS:
+ cnt = MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ color = MSG_ReadByte (&net_message);
+ CL_ParticleEffect2 (pos, dir, color, cnt);
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->type = ex_flash;
+ // note to self
+ // we need a better no draw flag
+ ex->ent.flags = RF_BEAM;
+ ex->start = cl.frame.servertime - 0.1;
+ ex->light = 100 + (rand()%75);
+ ex->lightcolor[0] = 1.0;
+ ex->lightcolor[1] = 1.0;
+ ex->lightcolor[2] = 0.3;
+ ex->ent.model = cl_mod_flash;
+ ex->frames = 2;
+ break;
+
+ case TE_GREENBLOOD:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ CL_ParticleEffect2 (pos, dir, 0xdf, 30);
+ break;
+
+ // RAFAEL
+ case TE_TUNNEL_SPARKS:
+ cnt = MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ color = MSG_ReadByte (&net_message);
+ CL_ParticleEffect3 (pos, dir, color, cnt);
+ break;
+
+//=============
+//PGM
+ // PMM -following code integrated for flechette (different color)
+ case TE_BLASTER2: // green blaster hitting wall
+ case TE_FLECHETTE: // flechette
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+
+ // PMM
+ if (type == TE_BLASTER2)
+ CL_BlasterParticles2 (pos, dir, 0xd0);
+ else
+ CL_BlasterParticles2 (pos, dir, 0x6f); // 75
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->ent.angles[0] = acos(dir[2])/M_PI*180;
+ // PMM - fixed to correct for pitch of 0
+ if (dir[0])
+ ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
+ else if (dir[1] > 0)
+ ex->ent.angles[1] = 90;
+ else if (dir[1] < 0)
+ ex->ent.angles[1] = 270;
+ else
+ ex->ent.angles[1] = 0;
+
+ ex->type = ex_misc;
+ ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+
+ // PMM
+ if (type == TE_BLASTER2)
+ ex->ent.skinnum = 1;
+ else // flechette
+ ex->ent.skinnum = 2;
+
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 150;
+ // PMM
+ if (type == TE_BLASTER2)
+ ex->lightcolor[1] = 1;
+ else // flechette
+ {
+ ex->lightcolor[0] = 0.19;
+ ex->lightcolor[1] = 0.41;
+ ex->lightcolor[2] = 0.75;
+ }
+ ex->ent.model = cl_mod_explode;
+ ex->frames = 4;
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+
+ case TE_LIGHTNING:
+ ent = CL_ParseLightning (cl_mod_lightning);
+ S_StartSound (NULL, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_DEBUGTRAIL:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadPos (&net_message, pos2);
+ CL_DebugTrail (pos, pos2);
+ break;
+
+ case TE_PLAIN_EXPLOSION:
+ MSG_ReadPos (&net_message, pos);
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->type = ex_poly;
+ ex->ent.flags = RF_FULLBRIGHT;
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 350;
+ ex->lightcolor[0] = 1.0;
+ ex->lightcolor[1] = 0.5;
+ ex->lightcolor[2] = 0.5;
+ ex->ent.angles[1] = rand() % 360;
+ ex->ent.model = cl_mod_explo4;
+ if (qfrand() < 0.5)
+ ex->baseframe = 15;
+ ex->frames = 15;
+ if (type == TE_ROCKET_EXPLOSION_WATER)
+ S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+ else
+ S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_FLASHLIGHT:
+ MSG_ReadPos(&net_message, pos);
+ ent = MSG_ReadShort(&net_message);
+ CL_Flashlight(ent, pos);
+ break;
+
+ case TE_FORCEWALL:
+ MSG_ReadPos(&net_message, pos);
+ MSG_ReadPos(&net_message, pos2);
+ color = MSG_ReadByte (&net_message);
+ CL_ForceWall(pos, pos2, color);
+ break;
+
+ case TE_HEATBEAM:
+ CL_ParsePlayerBeam (cl_mod_heatbeam); /* toss result */
+ break;
+
+ case TE_MONSTER_HEATBEAM:
+ CL_ParsePlayerBeam (cl_mod_monster_heatbeam); /* toss result */
+ break;
+
+ case TE_HEATBEAM_SPARKS:
+// cnt = MSG_ReadByte (&net_message);
+ cnt = 50;
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+// r = MSG_ReadByte (&net_message);
+// magnitude = MSG_ReadShort (&net_message);
+ r = 8;
+ magnitude = 60;
+ color = r & 0xff;
+ CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_HEATBEAM_STEAM:
+// cnt = MSG_ReadByte (&net_message);
+ cnt = 20;
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+// r = MSG_ReadByte (&net_message);
+// magnitude = MSG_ReadShort (&net_message);
+// color = r & 0xff;
+ color = 0xe0;
+ magnitude = 60;
+ CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_STEAM:
+ CL_ParseSteam();
+ break;
+
+ case TE_BUBBLETRAIL2:
+// cnt = MSG_ReadByte (&net_message);
+ cnt = 8;
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadPos (&net_message, pos2);
+ CL_BubbleTrail2 (pos, pos2, cnt);
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_MOREBLOOD:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ CL_ParticleEffect (pos, dir, 0xe8, 250);
+ break;
+
+ case TE_CHAINFIST_SMOKE:
+ dir[0]=0; dir[1]=0; dir[2]=1;
+ MSG_ReadPos(&net_message, pos);
+ CL_ParticleSmokeEffect (pos, dir, 0, 20, 20);
+ break;
+
+ case TE_ELECTRIC_SPARKS:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+// CL_ParticleEffect (pos, dir, 109, 40);
+ CL_ParticleEffect (pos, dir, 0x75, 40);
+ //FIXME : replace or remove this sound
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_TRACKER_EXPLOSION:
+ MSG_ReadPos (&net_message, pos);
+ CL_ColorFlash (pos, 0, 150, -1, -1, -1);
+ CL_ColorExplosionParticles (pos, 0, 1);
+// CL_Tracker_Explode (pos);
+ S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_TELEPORT_EFFECT:
+ case TE_DBALL_GOAL:
+ MSG_ReadPos (&net_message, pos);
+ CL_TeleportParticles (pos);
+ break;
+
+ case TE_WIDOWBEAMOUT:
+ CL_ParseWidow ();
+ break;
+
+ case TE_NUKEBLAST:
+ CL_ParseNuke ();
+ break;
+
+ case TE_WIDOWSPLASH:
+ MSG_ReadPos (&net_message, pos);
+ CL_WidowSplash (pos);
+ break;
+//PGM
+//==============
+
+ default:
+ Com_Error (ERR_DROP, "CL_ParseTEnt: bad type");
+ }
+}
+
+/*
+=================
+CL_AddBeams
+=================
+*/
+void CL_AddBeams (void)
+{
+ int i,j;
+ beam_t *b;
+ vec3_t dist, org;
+ float d;
+ entity_t ent;
+ float yaw, pitch;
+ float forward;
+ float len, steps;
+ float model_length;
+
+// update beams
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ {
+ if (!b->model || b->endtime < cl.time)
+ continue;
+
+ // if coming from the player, update the start position
+ if (b->entity == cl.playernum+1) // entity 0 is the world
+ {
+ VectorCopy (cl.refdef.vieworg, b->start);
+ b->start[2] -= 22; // adjust for view height
+ }
+ VectorAdd (b->start, b->offset, org);
+
+ // calculate pitch and yaw
+ VectorSubtract (b->end, org, dist);
+
+ if (dist[1] == 0 && dist[0] == 0)
+ {
+ yaw = 0;
+ if (dist[2] > 0)
+ pitch = 90;
+ else
+ pitch = 270;
+ }
+ else
+ {
+ // PMM - fixed to correct for pitch of 0
+ if (dist[0])
+ yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
+ else if (dist[1] > 0)
+ yaw = 90;
+ else
+ yaw = 270;
+ if (yaw < 0)
+ yaw += 360;
+
+ forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
+ pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
+ if (pitch < 0)
+ pitch += 360.0;
+ }
+
+ // add new entities for the beams
+ d = VectorNormalize(dist);
+
+ memset (&ent, 0, sizeof(ent));
+ if (b->model == cl_mod_lightning)
+ {
+ model_length = 35.0;
+ d-= 20.0; // correction so it doesn't end in middle of tesla
+ }
+ else
+ {
+ model_length = 30.0;
+ }
+ steps = ceil(d/model_length);
+ len = (d-model_length)/(steps-1);
+
+ // PMM - special case for lightning model .. if the real length is shorter than the model,
+ // flip it around & draw it from the end to the start. This prevents the model from going
+ // through the tesla mine (instead it goes through the target)
+ if ((b->model == cl_mod_lightning) && (d <= model_length))
+ {
+// Com_Printf ("special case\n");
+ VectorCopy (b->end, ent.origin);
+ // offset to push beam outside of tesla model (negative because dist is from end to start
+ // for this beam)
+// for (j=0 ; j<3 ; j++)
+// ent.origin[j] -= dist[j]*10.0;
+ ent.model = b->model;
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = pitch;
+ ent.angles[1] = yaw;
+ ent.angles[2] = rand()%360;
+ V_AddEntity (&ent);
+ return;
+ }
+ while (d > 0)
+ {
+ VectorCopy (org, ent.origin);
+ ent.model = b->model;
+ if (b->model == cl_mod_lightning)
+ {
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = -pitch;
+ ent.angles[1] = yaw + 180.0;
+ ent.angles[2] = rand()%360;
+ }
+ else
+ {
+ ent.angles[0] = pitch;
+ ent.angles[1] = yaw;
+ ent.angles[2] = rand()%360;
+ }
+
+// Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
+ V_AddEntity (&ent);
+
+ for (j=0 ; j<3 ; j++)
+ org[j] += dist[j]*len;
+ d -= model_length;
+ }
+ }
+}
+
+
+/*
+// Com_Printf ("Endpoint: %f %f %f\n", b->end[0], b->end[1], b->end[2]);
+// Com_Printf ("Pred View Angles: %f %f %f\n", cl.predicted_angles[0], cl.predicted_angles[1], cl.predicted_angles[2]);
+// Com_Printf ("Act View Angles: %f %f %f\n", cl.refdef.viewangles[0], cl.refdef.viewangles[1], cl.refdef.viewangles[2]);
+// VectorCopy (cl.predicted_origin, b->start);
+// b->start[2] += 22; // adjust for view height
+// if (fabs(cl.refdef.vieworg[2] - b->start[2]) >= 10) {
+// b->start[2] = cl.refdef.vieworg[2];
+// }
+
+// Com_Printf ("Time: %d %d %f\n", cl.time, cls.realtime, cls.frametime);
+*/
+
+extern cvar_t *hand;
+
+/*
+=================
+ROGUE - draw player locked beams
+CL_AddPlayerBeams
+=================
+*/
+void CL_AddPlayerBeams (void)
+{
+ int i,j;
+ beam_t *b;
+ vec3_t dist, org;
+ float d;
+ entity_t ent;
+ float yaw, pitch;
+ float forward;
+ float len, steps;
+ int framenum = 0;
+ float model_length;
+
+ float hand_multiplier;
+ frame_t *oldframe;
+ player_state_t *ps, *ops;
+
+//PMM
+ if (hand)
+ {
+ if (hand->value == 2)
+ hand_multiplier = 0;
+ else if (hand->value == 1)
+ hand_multiplier = -1;
+ else
+ hand_multiplier = 1;
+ }
+ else
+ {
+ hand_multiplier = 1;
+ }
+//PMM
+
+// update beams
+ for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
+ {
+ vec3_t f,r,u;
+ if (!b->model || b->endtime < cl.time)
+ continue;
+
+ if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
+ {
+
+ // if coming from the player, update the start position
+ if (b->entity == cl.playernum+1) // entity 0 is the world
+ {
+ // set up gun position
+ // code straight out of CL_AddViewWeapon
+ ps = &cl.frame.playerstate;
+ j = (cl.frame.serverframe - 1) & UPDATE_MASK;
+ oldframe = &cl.frames[j];
+ if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
+ oldframe = &cl.frame; // previous frame was dropped or involid
+ ops = &oldframe->playerstate;
+ for (j=0 ; j<3 ; j++)
+ {
+ b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j]
+ + cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]);
+ }
+ VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org);
+ VectorMA ( org, b->offset[1], cl.v_forward, org);
+ VectorMA ( org, b->offset[2], cl.v_up, org);
+ if ((hand) && (hand->value == 2)) {
+ VectorMA (org, -1, cl.v_up, org);
+ }
+ // FIXME - take these out when final
+ VectorCopy (cl.v_right, r);
+ VectorCopy (cl.v_forward, f);
+ VectorCopy (cl.v_up, u);
+
+ }
+ else
+ VectorCopy (b->start, org);
+ }
+ else
+ {
+ // if coming from the player, update the start position
+ if (b->entity == cl.playernum+1) // entity 0 is the world
+ {
+ VectorCopy (cl.refdef.vieworg, b->start);
+ b->start[2] -= 22; // adjust for view height
+ }
+ VectorAdd (b->start, b->offset, org);
+ }
+
+ // calculate pitch and yaw
+ VectorSubtract (b->end, org, dist);
+
+//PMM
+ if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1))
+ {
+ vec_t len;
+
+ len = VectorLength (dist);
+ VectorScale (f, len, dist);
+ VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist);
+ VectorMA (dist, b->offset[1], f, dist);
+ VectorMA (dist, b->offset[2], u, dist);
+ if ((hand) && (hand->value == 2)) {
+ VectorMA (org, -1, cl.v_up, org);
+ }
+ }
+//PMM
+
+ if (dist[1] == 0 && dist[0] == 0)
+ {
+ yaw = 0;
+ if (dist[2] > 0)
+ pitch = 90;
+ else
+ pitch = 270;
+ }
+ else
+ {
+ // PMM - fixed to correct for pitch of 0
+ if (dist[0])
+ yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
+ else if (dist[1] > 0)
+ yaw = 90;
+ else
+ yaw = 270;
+ if (yaw < 0)
+ yaw += 360;
+
+ forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
+ pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
+ if (pitch < 0)
+ pitch += 360.0;
+ }
+
+ if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
+ {
+ if (b->entity != cl.playernum+1)
+ {
+ framenum = 2;
+// Com_Printf ("Third person\n");
+ ent.angles[0] = -pitch;
+ ent.angles[1] = yaw + 180.0;
+ ent.angles[2] = 0;
+// Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b->offset[0], b->offset[1], b->offset[2]);
+ AngleVectors(ent.angles, f, r, u);
+
+ // if it's a non-origin offset, it's a player, so use the hardcoded player offset
+ if (!VectorCompare (b->offset, vec3_origin))
+ {
+ VectorMA (org, -(b->offset[0])+1, r, org);
+ VectorMA (org, -(b->offset[1]), f, org);
+ VectorMA (org, -(b->offset[2])-10, u, org);
+ }
+ else
+ {
+ // if it's a monster, do the particle effect
+ CL_MonsterPlasma_Shell(b->start);
+ }
+ }
+ else
+ {
+ framenum = 1;
+ }
+ }
+
+ // if it's the heatbeam, draw the particle effect
+ if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1)))
+ {
+ CL_Heatbeam (org, dist);
+ }
+
+ // add new entities for the beams
+ d = VectorNormalize(dist);
+
+ memset (&ent, 0, sizeof(ent));
+ if (b->model == cl_mod_heatbeam)
+ {
+ model_length = 32.0;
+ }
+ else if (b->model == cl_mod_lightning)
+ {
+ model_length = 35.0;
+ d-= 20.0; // correction so it doesn't end in middle of tesla
+ }
+ else
+ {
+ model_length = 30.0;
+ }
+ steps = ceil(d/model_length);
+ len = (d-model_length)/(steps-1);
+
+ // PMM - special case for lightning model .. if the real length is shorter than the model,
+ // flip it around & draw it from the end to the start. This prevents the model from going
+ // through the tesla mine (instead it goes through the target)
+ if ((b->model == cl_mod_lightning) && (d <= model_length))
+ {
+// Com_Printf ("special case\n");
+ VectorCopy (b->end, ent.origin);
+ // offset to push beam outside of tesla model (negative because dist is from end to start
+ // for this beam)
+// for (j=0 ; j<3 ; j++)
+// ent.origin[j] -= dist[j]*10.0;
+ ent.model = b->model;
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = pitch;
+ ent.angles[1] = yaw;
+ ent.angles[2] = rand()%360;
+ V_AddEntity (&ent);
+ return;
+ }
+ while (d > 0)
+ {
+ VectorCopy (org, ent.origin);
+ ent.model = b->model;
+ if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
+ {
+// ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+// ent.alpha = 0.3;
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = -pitch;
+ ent.angles[1] = yaw + 180.0;
+ ent.angles[2] = (cl.time) % 360;
+// ent.angles[2] = rand()%360;
+ ent.frame = framenum;
+ }
+ else if (b->model == cl_mod_lightning)
+ {
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = -pitch;
+ ent.angles[1] = yaw + 180.0;
+ ent.angles[2] = rand()%360;
+ }
+ else
+ {
+ ent.angles[0] = pitch;
+ ent.angles[1] = yaw;
+ ent.angles[2] = rand()%360;
+ }
+
+// Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
+ V_AddEntity (&ent);
+
+ for (j=0 ; j<3 ; j++)
+ org[j] += dist[j]*len;
+ d -= model_length;
+ }
+ }
+}
+
+/*
+=================
+CL_AddExplosions
+=================
+*/
+void CL_AddExplosions (void)
+{
+ entity_t *ent;
+ int i;
+ explosion_t *ex;
+ float frac;
+ int f;
+
+ memset (&ent, 0, sizeof(ent));
+
+ for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++)
+ {
+ if (ex->type == ex_free)
+ continue;
+ frac = (cl.time - ex->start)/100.0;
+ f = floor(frac);
+
+ ent = &ex->ent;
+
+ switch (ex->type)
+ {
+ case ex_mflash:
+ if (f >= ex->frames-1)
+ ex->type = ex_free;
+ break;
+ case ex_misc:
+ if (f >= ex->frames-1)
+ {
+ ex->type = ex_free;
+ break;
+ }
+ ent->alpha = 1.0 - frac/(ex->frames-1);
+ break;
+ case ex_flash:
+ if (f >= 1)
+ {
+ ex->type = ex_free;
+ break;
+ }
+ ent->alpha = 1.0;
+ break;
+ case ex_poly:
+ if (f >= ex->frames-1)
+ {
+ ex->type = ex_free;
+ break;
+ }
+
+ ent->alpha = (16.0 - (float)f)/16.0;
+
+ if (f < 10)
+ {
+ ent->skinnum = (f>>1);
+ if (ent->skinnum < 0)
+ ent->skinnum = 0;
+ }
+ else
+ {
+ ent->flags |= RF_TRANSLUCENT;
+ if (f < 13)
+ ent->skinnum = 5;
+ else
+ ent->skinnum = 6;
+ }
+ break;
+ case ex_poly2:
+ if (f >= ex->frames-1)
+ {
+ ex->type = ex_free;
+ break;
+ }
+
+ ent->alpha = (5.0 - (float)f)/5.0;
+ ent->skinnum = 0;
+ ent->flags |= RF_TRANSLUCENT;
+ break;
+ }
+
+ if (ex->type == ex_free)
+ continue;
+ if (ex->light)
+ {
+ V_AddLight (ent->origin, ex->light*ent->alpha,
+ ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]);
+ }
+
+ VectorCopy (ent->origin, ent->oldorigin);
+
+ if (f < 0)
+ f = 0;
+ ent->frame = ex->baseframe + f + 1;
+ ent->oldframe = ex->baseframe + f;
+ ent->backlerp = 1.0 - cl.lerpfrac;
+
+ V_AddEntity (ent);
+ }
+}
+
+
+/*
+=================
+CL_AddLasers
+=================
+*/
+void CL_AddLasers (void)
+{
+ laser_t *l;
+ int i;
+
+ for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
+ {
+ if (l->endtime >= cl.time)
+ V_AddEntity (&l->ent);
+ }
+}
+
+/* PMM - CL_Sustains */
+void CL_ProcessSustain (void)
+{
+ cl_sustain_t *s;
+ int i;
+
+ for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++)
+ {
+ if (s->id)
+ if ((s->endtime >= cl.time) && (cl.time >= s->nextthink))
+ {
+// Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval);
+ s->think (s);
+ }
+ else if (s->endtime < cl.time)
+ s->id = 0;
+ }
+}
+
+/*
+=================
+CL_AddTEnts
+=================
+*/
+void CL_AddTEnts (void)
+{
+ CL_AddBeams ();
+ // PMM - draw plasma beams
+ CL_AddPlayerBeams ();
+ CL_AddExplosions ();
+ CL_AddLasers ();
+ // PMM - set up sustain
+ CL_ProcessSustain();
+}
--- /dev/null
+++ b/cl_view.c
@@ -1,0 +1,569 @@
+// cl_view.c -- player rendering positioning
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+//=============
+//
+// development tools for weapons
+//
+int gun_frame;
+model_t *gun_model;
+
+//=============
+
+cvar_t *crosshair;
+cvar_t *cl_testparticles;
+cvar_t *cl_testentities;
+cvar_t *cl_testlights;
+cvar_t *cl_testblend;
+
+cvar_t *cl_stats;
+
+
+int r_numdlights;
+dlight_t r_dlights[MAX_DLIGHTS];
+
+int r_numentities;
+entity_t r_entities[MAX_ENTITIES];
+
+int r_numparticles;
+particle_t r_particles[MAX_PARTICLES];
+
+lightstyle_t r_lightstyles[MAX_LIGHTSTYLES];
+
+char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
+int num_cl_weaponmodels;
+
+/*
+====================
+V_ClearScene
+
+Specifies the model that will be used as the world
+====================
+*/
+void V_ClearScene (void)
+{
+ r_numdlights = 0;
+ r_numentities = 0;
+ r_numparticles = 0;
+}
+
+
+/*
+=====================
+V_AddEntity
+
+=====================
+*/
+void V_AddEntity (entity_t *ent)
+{
+ if (r_numentities >= MAX_ENTITIES)
+ return;
+ r_entities[r_numentities++] = *ent;
+}
+
+
+/*
+=====================
+V_AddParticle
+
+=====================
+*/
+void V_AddParticle (vec3_t org, int color, float alpha)
+{
+ particle_t *p;
+
+ if (r_numparticles >= MAX_PARTICLES)
+ return;
+ p = &r_particles[r_numparticles++];
+ VectorCopy (org, p->origin);
+ p->color = color;
+ p->alpha = alpha;
+}
+
+/*
+=====================
+V_AddLight
+
+=====================
+*/
+void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
+{
+ dlight_t *dl;
+
+ if (r_numdlights >= MAX_DLIGHTS)
+ return;
+ dl = &r_dlights[r_numdlights++];
+ VectorCopy (org, dl->origin);
+ dl->intensity = intensity;
+ dl->color[0] = r;
+ dl->color[1] = g;
+ dl->color[2] = b;
+}
+
+
+/*
+=====================
+V_AddLightStyle
+
+=====================
+*/
+void V_AddLightStyle (int style, float r, float g, float b)
+{
+ lightstyle_t *ls;
+
+ if (style < 0 || style > MAX_LIGHTSTYLES)
+ Com_Error (ERR_DROP, "Bad light style %i", style);
+ ls = &r_lightstyles[style];
+
+ ls->white = r+g+b;
+ ls->rgb[0] = r;
+ ls->rgb[1] = g;
+ ls->rgb[2] = b;
+}
+
+/*
+================
+V_TestParticles
+
+If cl_testparticles is set, create 4096 particles in the view
+================
+*/
+void V_TestParticles (void)
+{
+ particle_t *p;
+ int i, j;
+ float d, r, u;
+
+ r_numparticles = MAX_PARTICLES;
+ for (i=0 ; i<r_numparticles ; i++)
+ {
+ d = i*0.25;
+ r = 4*((i&7)-3.5);
+ u = 4*(((i>>3)&7)-3.5);
+ p = &r_particles[i];
+
+ for (j=0 ; j<3 ; j++)
+ p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*d +
+ cl.v_right[j]*r + cl.v_up[j]*u;
+
+ p->color = 8;
+ p->alpha = cl_testparticles->value;
+ }
+}
+
+/*
+================
+V_TestEntities
+
+If cl_testentities is set, create 32 player models
+================
+*/
+void V_TestEntities (void)
+{
+ int i, j;
+ float f, r;
+ entity_t *ent;
+
+ r_numentities = 32;
+ memset (r_entities, 0, sizeof(r_entities));
+
+ for (i=0 ; i<r_numentities ; i++)
+ {
+ ent = &r_entities[i];
+
+ r = 64 * ( (i%4) - 1.5 );
+ f = 64 * (i/4) + 128;
+
+ for (j=0 ; j<3 ; j++)
+ ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
+ cl.v_right[j]*r;
+
+ ent->model = cl.baseclientinfo.model;
+ ent->skin = cl.baseclientinfo.skin;
+ }
+}
+
+/*
+================
+V_TestLights
+
+If cl_testlights is set, create 32 lights models
+================
+*/
+void V_TestLights (void)
+{
+ int i, j;
+ float f, r;
+ dlight_t *dl;
+
+ r_numdlights = 32;
+ memset (r_dlights, 0, sizeof(r_dlights));
+
+ for (i=0 ; i<r_numdlights ; i++)
+ {
+ dl = &r_dlights[i];
+
+ r = 64 * ( (i%4) - 1.5 );
+ f = 64 * (i/4) + 128;
+
+ for (j=0 ; j<3 ; j++)
+ dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
+ cl.v_right[j]*r;
+ dl->color[0] = ((i%6)+1) & 1;
+ dl->color[1] = (((i%6)+1) & 2)>>1;
+ dl->color[2] = (((i%6)+1) & 4)>>2;
+ dl->intensity = 200;
+ }
+}
+
+//===================================================================
+
+/*
+=================
+CL_PrepRefresh
+
+Call before entering a new level, or after changing dlls
+=================
+*/
+void CL_PrepRefresh (void)
+{
+ char mapname[32];
+ int i;
+ char name[MAX_QPATH];
+ float rotate;
+ vec3_t axis;
+
+ if (!cl.configstrings[CS_MODELS+1][0])
+ return; // no map loaded
+
+ SCR_AddDirtyPoint (0, 0);
+ SCR_AddDirtyPoint (vid.width-1, vid.height-1);
+
+ // let the render dll load the map
+ strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5); // skip "maps/"
+ mapname[strlen(mapname)-4] = 0; // cut off ".bsp"
+
+ // register models, pics, and skins
+ Com_Printf ("Map: %s\r", mapname);
+ SCR_UpdateScreen ();
+ re.BeginRegistration (mapname);
+ Com_Printf (" \r");
+
+ // precache status bar pics
+ Com_Printf ("pics\r");
+ SCR_UpdateScreen ();
+ SCR_TouchPics ();
+ Com_Printf (" \r");
+
+ CL_RegisterTEntModels ();
+
+ num_cl_weaponmodels = 1;
+ strcpy(cl_weaponmodels[0], "weapon.md2");
+
+ for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
+ {
+ strcpy (name, cl.configstrings[CS_MODELS+i]);
+ name[37] = 0; // never go beyond one line
+ if (name[0] != '*')
+ Com_Printf ("%s\r", name);
+ SCR_UpdateScreen ();
+ Sys_SendKeyEvents (); // pump message loop
+ if (name[0] == '#')
+ {
+ // special player weapon model
+ if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
+ {
+ strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
+ sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
+ num_cl_weaponmodels++;
+ }
+ }
+ else
+ {
+ cl.model_draw[i] = re.RegisterModel (cl.configstrings[CS_MODELS+i]);
+ if (name[0] == '*')
+ cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
+ else
+ cl.model_clip[i] = NULL;
+ }
+ if (name[0] != '*')
+ Com_Printf (" \r");
+ }
+
+ Com_Printf ("images\r", i);
+ SCR_UpdateScreen ();
+ for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
+ {
+ cl.image_precache[i] = re.RegisterPic (cl.configstrings[CS_IMAGES+i]);
+ Sys_SendKeyEvents (); // pump message loop
+ }
+
+ Com_Printf (" \r");
+ for (i=0 ; i<MAX_CLIENTS ; i++)
+ {
+ if (!cl.configstrings[CS_PLAYERSKINS+i][0])
+ continue;
+ Com_Printf ("client %i\r", i);
+ SCR_UpdateScreen ();
+ Sys_SendKeyEvents (); // pump message loop
+ CL_ParseClientinfo (i);
+ Com_Printf (" \r");
+ }
+
+ CL_LoadClientinfo (&cl.baseclientinfo, "unnamed\\male/grunt");
+
+ // set sky textures and speed
+ Com_Printf ("sky\r", i);
+ SCR_UpdateScreen ();
+ rotate = atof (cl.configstrings[CS_SKYROTATE]);
+ sscanf (cl.configstrings[CS_SKYAXIS], "%f %f %f",
+ &axis[0], &axis[1], &axis[2]);
+ re.SetSky (cl.configstrings[CS_SKY], rotate, axis);
+ Com_Printf (" \r");
+
+ // the renderer can now free unneeded stuff
+ re.EndRegistration ();
+
+ // clear any lines of console text
+ Con_ClearNotify ();
+
+ SCR_UpdateScreen ();
+ cl.refresh_prepped = true;
+ cl.force_refdef = true; // make sure we have a valid refdef
+
+ // start the cd track
+ CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
+}
+
+/*
+====================
+CalcFov
+====================
+*/
+float CalcFov (float fov_x, float width, float height)
+{
+ float a;
+ float x;
+
+ if (fov_x < 1 || fov_x > 179)
+ Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
+
+ x = width/tan(fov_x/360*M_PI);
+
+ a = atan (height/x);
+
+ a = a*360/M_PI;
+
+ return a;
+}
+
+//============================================================================
+
+// gun frame debugging functions
+void V_Gun_Next_f (void)
+{
+ gun_frame++;
+ Com_Printf ("frame %i\n", gun_frame);
+}
+
+void V_Gun_Prev_f (void)
+{
+ gun_frame--;
+ if (gun_frame < 0)
+ gun_frame = 0;
+ Com_Printf ("frame %i\n", gun_frame);
+}
+
+void V_Gun_Model_f (void)
+{
+ char name[MAX_QPATH];
+
+ if (Cmd_Argc() != 2)
+ {
+ gun_model = NULL;
+ return;
+ }
+ Com_sprintf (name, sizeof(name), "models/%s/tris.md2", Cmd_Argv(1));
+ gun_model = re.RegisterModel (name);
+}
+
+//============================================================================
+
+
+/*
+=================
+SCR_DrawCrosshair
+=================
+*/
+void SCR_DrawCrosshair (void)
+{
+ if (!crosshair->value)
+ return;
+
+ if (crosshair->modified)
+ {
+ crosshair->modified = false;
+ SCR_TouchPics ();
+ }
+
+ if (!crosshair_pic[0])
+ return;
+
+ re.DrawPic (scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1)
+ , scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1), crosshair_pic);
+}
+
+/*
+==================
+V_RenderView
+
+==================
+*/
+void V_RenderView( float stereo_separation )
+{
+ extern int entitycmpfnc(entity_t *, entity_t *);
+
+ if (cls.state != ca_active)
+ return;
+
+ if (!cl.refresh_prepped)
+ return; // still loading
+
+ if (cl_timedemo->value)
+ {
+ if (!cl.timedemo_start)
+ cl.timedemo_start = Sys_Milliseconds ();
+ cl.timedemo_frames++;
+ }
+
+ // an invalid frame will just use the exact previous refdef
+ // we can't use the old frame if the video mode has changed, though...
+ if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
+ {
+ cl.force_refdef = false;
+
+ V_ClearScene ();
+
+ // build a refresh entity list and calc cl.sim*
+ // this also calls CL_CalcViewValues which loads
+ // v_forward, etc.
+ CL_AddEntities ();
+
+ if (cl_testparticles->value)
+ V_TestParticles ();
+ if (cl_testentities->value)
+ V_TestEntities ();
+ if (cl_testlights->value)
+ V_TestLights ();
+ if (cl_testblend->value)
+ {
+ cl.refdef.blend[0] = 1;
+ cl.refdef.blend[1] = 0.5;
+ cl.refdef.blend[2] = 0.25;
+ cl.refdef.blend[3] = 0.5;
+ }
+
+ // offset vieworg appropriately if we're doing stereo separation
+ if ( stereo_separation != 0 )
+ {
+ vec3_t tmp;
+
+ VectorScale( cl.v_right, stereo_separation, tmp );
+ VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
+ }
+
+ // never let it sit exactly on a node line, because a water plane can
+ // dissapear when viewed with the eye exactly on it.
+ // the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
+ cl.refdef.vieworg[0] += 1.0/16;
+ cl.refdef.vieworg[1] += 1.0/16;
+ cl.refdef.vieworg[2] += 1.0/16;
+
+ cl.refdef.x = scr_vrect.x;
+ cl.refdef.y = scr_vrect.y;
+ cl.refdef.width = scr_vrect.width;
+ cl.refdef.height = scr_vrect.height;
+ cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
+ cl.refdef.time = cl.time*0.001;
+
+ cl.refdef.areabits = cl.frame.areabits;
+
+ if (!cl_add_entities->value)
+ r_numentities = 0;
+ if (!cl_add_particles->value)
+ r_numparticles = 0;
+ if (!cl_add_lights->value)
+ r_numdlights = 0;
+ if (!cl_add_blend->value)
+ {
+ VectorClear (cl.refdef.blend);
+ }
+
+ cl.refdef.num_entities = r_numentities;
+ cl.refdef.entities = r_entities;
+ cl.refdef.num_particles = r_numparticles;
+ cl.refdef.particles = r_particles;
+ cl.refdef.num_dlights = r_numdlights;
+ cl.refdef.dlights = r_dlights;
+ cl.refdef.lightstyles = r_lightstyles;
+
+ cl.refdef.rdflags = cl.frame.playerstate.rdflags;
+
+ // sort entities for better cache locality
+ qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(void *, void *))entitycmpfnc );
+ }
+
+ re.RenderFrame (&cl.refdef);
+ if (cl_stats->value)
+ Com_Printf ("ent:%i lt:%i part:%i\n", r_numentities, r_numdlights, r_numparticles);
+ if ( log_stats->value && ( log_stats_file != 0 ) )
+ fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
+
+
+ SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y);
+ SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1,
+ scr_vrect.y+scr_vrect.height-1);
+
+ SCR_DrawCrosshair ();
+}
+
+
+/*
+=============
+V_Viewpos_f
+=============
+*/
+void V_Viewpos_f (void)
+{
+ Com_Printf ("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
+ (int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2],
+ (int)cl.refdef.viewangles[YAW]);
+}
+
+/*
+=============
+V_Init
+=============
+*/
+void V_Init (void)
+{
+ Cmd_AddCommand ("gun_next", V_Gun_Next_f);
+ Cmd_AddCommand ("gun_prev", V_Gun_Prev_f);
+ Cmd_AddCommand ("gun_model", V_Gun_Model_f);
+
+ Cmd_AddCommand ("viewpos", V_Viewpos_f);
+
+ crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
+
+ cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
+ cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
+ cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
+ cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
+
+ cl_stats = Cvar_Get ("cl_stats", "0", 0);
+}
--- a/client/cdaudio.h
+++ /dev/null
@@ -1,6 +1,0 @@
-int CDAudio_Init(void);
-void CDAudio_Shutdown(void);
-void CDAudio_Play(int track, qboolean looping);
-void CDAudio_Stop(void);
-void CDAudio_Update(void);
-void CDAudio_Activate (qboolean active);
--- a/client/cl_cin.c
+++ /dev/null
@@ -1,632 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-typedef struct
-{
- byte *data;
- int count;
-} cblock_t;
-
-typedef struct
-{
- qboolean restart_sound;
- int s_rate;
- int s_width;
- int s_channels;
-
- int width;
- int height;
- byte *pic;
- byte *pic_pending;
-
- // order 1 huffman stuff
- int *hnodes1; // [256][256][2];
- int numhnodes1[256];
-
- int h_used[512];
- int h_count[512];
-} cinematics_t;
-
-cinematics_t cin;
-
-/*
-=================================================================
-
-PCX LOADING
-
-=================================================================
-*/
-
-
-/*
-==============
-SCR_LoadPCX
-==============
-*/
-void SCR_LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
-{
- byte *raw;
- pcx_t *pcx;
- int x, y;
- int len;
- int dataByte, runLength;
- byte *out, *pix;
-
- *pic = NULL;
-
- //
- // load the file
- //
- len = FS_LoadFile (filename, (void **)&raw);
- if (!raw)
- return; // Com_Printf ("Bad pcx file %s\n", filename);
-
- //
- // parse the PCX file
- //
- pcx = (pcx_t *)raw;
- raw = &pcx->data;
-
- if (pcx->manufacturer != 0x0a
- || pcx->version != 5
- || pcx->encoding != 1
- || pcx->bits_per_pixel != 8
- || pcx->xmax >= 640
- || pcx->ymax >= 480)
- {
- Com_Printf ("Bad pcx file %s\n", filename);
- return;
- }
-
- out = Z_Malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
-
- *pic = out;
-
- pix = out;
-
- if (palette)
- {
- *palette = Z_Malloc(768);
- memcpy (*palette, (byte *)pcx + len - 768, 768);
- }
-
- if (width)
- *width = pcx->xmax+1;
- if (height)
- *height = pcx->ymax+1;
-
- for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
- {
- for (x=0 ; x<=pcx->xmax ; )
- {
- dataByte = *raw++;
-
- if((dataByte & 0xC0) == 0xC0)
- {
- runLength = dataByte & 0x3F;
- dataByte = *raw++;
- }
- else
- runLength = 1;
-
- while(runLength-- > 0)
- pix[x++] = dataByte;
- }
-
- }
-
- if ( raw - (byte *)pcx > len)
- {
- Com_Printf ("PCX file %s was malformed", filename);
- Z_Free (*pic);
- *pic = NULL;
- }
-
- FS_FreeFile (pcx);
-}
-
-//=============================================================
-
-/*
-==================
-SCR_StopCinematic
-==================
-*/
-void SCR_StopCinematic (void)
-{
- cl.cinematictime = 0; // done
- if (cin.pic)
- {
- Z_Free (cin.pic);
- cin.pic = NULL;
- }
- if (cin.pic_pending)
- {
- Z_Free (cin.pic_pending);
- cin.pic_pending = NULL;
- }
- if (cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- }
- if (cl.cinematic_file)
- {
- fclose (cl.cinematic_file);
- cl.cinematic_file = NULL;
- }
- if (cin.hnodes1)
- {
- Z_Free (cin.hnodes1);
- cin.hnodes1 = NULL;
- }
-
- // switch back down to 11 khz sound if necessary
- if (cin.restart_sound)
- {
- cin.restart_sound = false;
- CL_Snd_Restart_f ();
- }
-
-}
-
-/*
-====================
-SCR_FinishCinematic
-
-Called when either the cinematic completes, or it is aborted
-====================
-*/
-void SCR_FinishCinematic (void)
-{
- // tell the server to advance to the next map / cinematic
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- SZ_Print (&cls.netchan.message, va("nextserver %i\n", cl.servercount));
-}
-
-//==========================================================================
-
-/*
-==================
-SmallestNode1
-==================
-*/
-int SmallestNode1 (int numhnodes)
-{
- int i;
- int best, bestnode;
-
- best = 99999999;
- bestnode = -1;
- for (i=0 ; i<numhnodes ; i++)
- {
- if (cin.h_used[i])
- continue;
- if (!cin.h_count[i])
- continue;
- if (cin.h_count[i] < best)
- {
- best = cin.h_count[i];
- bestnode = i;
- }
- }
-
- if (bestnode == -1)
- return -1;
-
- cin.h_used[bestnode] = true;
- return bestnode;
-}
-
-
-/*
-==================
-Huff1TableInit
-
-Reads the 64k counts table and initializes the node trees
-==================
-*/
-void Huff1TableInit (void)
-{
- int prev;
- int j;
- int *node, *nodebase;
- byte counts[256];
- int numhnodes;
-
- cin.hnodes1 = Z_Malloc (256*256*2*4);
- memset (cin.hnodes1, 0, 256*256*2*4);
-
- for (prev=0 ; prev<256 ; prev++)
- {
- memset (cin.h_count,0,sizeof(cin.h_count));
- memset (cin.h_used,0,sizeof(cin.h_used));
-
- // read a row of counts
- FS_Read (counts, sizeof(counts), cl.cinematic_file);
- for (j=0 ; j<256 ; j++)
- cin.h_count[j] = counts[j];
-
- // build the nodes
- numhnodes = 256;
- nodebase = cin.hnodes1 + prev*256*2;
-
- while (numhnodes != 511)
- {
- node = nodebase + (numhnodes-256)*2;
-
- // pick two lowest counts
- node[0] = SmallestNode1 (numhnodes);
- if (node[0] == -1)
- break; // no more
-
- node[1] = SmallestNode1 (numhnodes);
- if (node[1] == -1)
- break;
-
- cin.h_count[numhnodes] = cin.h_count[node[0]] + cin.h_count[node[1]];
- numhnodes++;
- }
-
- cin.numhnodes1[prev] = numhnodes-1;
- }
-}
-
-/*
-==================
-Huff1Decompress
-==================
-*/
-cblock_t Huff1Decompress (cblock_t in)
-{
- byte *input;
- byte *out_p;
- int nodenum;
- int count;
- cblock_t out;
- int inbyte;
- int *hnodes, *hnodesbase;
-//int i;
-
- // get decompressed count
- count = in.data[0] + (in.data[1]<<8) + (in.data[2]<<16) + (in.data[3]<<24);
- input = in.data + 4;
- out_p = out.data = Z_Malloc (count);
-
- // read bits
-
- hnodesbase = cin.hnodes1 - 256*2; // nodes 0-255 aren't stored
-
- hnodes = hnodesbase;
- nodenum = cin.numhnodes1[0];
- while (count)
- {
- inbyte = *input++;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- }
-
- if (input - in.data != in.count && input - in.data != in.count+1)
- {
- Com_Printf ("Decompression overread by %i", (input - in.data) - in.count);
- }
- out.count = out_p - out.data;
-
- return out;
-}
-
-/*
-==================
-SCR_ReadNextFrame
-==================
-*/
-byte *SCR_ReadNextFrame (void)
-{
- int r;
- int command;
- byte samples[22050/14*4];
- byte compressed[0x20000];
- int size;
- byte *pic;
- cblock_t in, huf1;
- int start, end, count;
-
- // read the next frame
- r = fread (&command, 4, 1, cl.cinematic_file);
- if (r == 0) // we'll give it one more chance
- r = fread (&command, 4, 1, cl.cinematic_file);
-
- if (r != 1)
- return NULL;
- command = LittleLong(command);
- if (command == 2)
- return NULL; // last frame marker
-
- if (command == 1)
- { // read palette
- FS_Read (cl.cinematicpalette, sizeof(cl.cinematicpalette), cl.cinematic_file);
- cl.cinematicpalette_active=0; // dubious.... exposes an edge case
- }
-
- // decompress the next frame
- FS_Read (&size, 4, cl.cinematic_file);
- size = LittleLong(size);
- if (size > sizeof(compressed) || size < 1)
- Com_Error (ERR_DROP, "Bad compressed frame size");
- FS_Read (compressed, size, cl.cinematic_file);
-
- // read sound
- start = cl.cinematicframe*cin.s_rate/14;
- end = (cl.cinematicframe+1)*cin.s_rate/14;
- count = end - start;
-
- FS_Read (samples, count*cin.s_width*cin.s_channels, cl.cinematic_file);
-
- S_RawSamples (count, cin.s_rate, cin.s_width, cin.s_channels, samples);
-
- in.data = compressed;
- in.count = size;
-
- huf1 = Huff1Decompress (in);
-
- pic = huf1.data;
-
- cl.cinematicframe++;
-
- return pic;
-}
-
-
-/*
-==================
-SCR_RunCinematic
-
-==================
-*/
-void SCR_RunCinematic (void)
-{
- int frame;
-
- if (cl.cinematictime <= 0)
- {
- SCR_StopCinematic ();
- return;
- }
-
- if (cl.cinematicframe == -1)
- return; // static image
-
- if (cls.key_dest != key_game)
- { // pause if menu or console is up
- cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
- return;
- }
-
- frame = (cls.realtime - cl.cinematictime)*14.0/1000;
- if (frame <= cl.cinematicframe)
- return;
- if (frame > cl.cinematicframe+1)
- {
- Com_Printf ("Dropped frame: %i > %i\n", frame, cl.cinematicframe+1);
- cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
- }
- if (cin.pic)
- Z_Free (cin.pic);
- cin.pic = cin.pic_pending;
- cin.pic_pending = NULL;
- cin.pic_pending = SCR_ReadNextFrame ();
- if (!cin.pic_pending)
- {
- SCR_StopCinematic ();
- SCR_FinishCinematic ();
- cl.cinematictime = 1; // hack to get the black screen behind loading
- SCR_BeginLoadingPlaque ();
- cl.cinematictime = 0;
- return;
- }
-}
-
-/*
-==================
-SCR_DrawCinematic
-
-Returns true if a cinematic is active, meaning the view rendering
-should be skipped
-==================
-*/
-qboolean SCR_DrawCinematic (void)
-{
- if (cl.cinematictime <= 0)
- {
- return false;
- }
-
- if (cls.key_dest == key_menu)
- { // blank screen and pause if menu is up
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- return true;
- }
-
- if (!cl.cinematicpalette_active)
- {
- re.CinematicSetPalette((uchar *)cl.cinematicpalette);
- cl.cinematicpalette_active = true;
- }
-
- if (!cin.pic)
- return true;
-
- re.DrawStretchRaw (0, 0, vid.width, vid.height, cin.width, cin.height, cin.pic);
-
- return true;
-}
-
-/*
-==================
-SCR_PlayCinematic
-
-==================
-*/
-void SCR_PlayCinematic (char *arg)
-{
- int width, height;
- byte *palette;
- char name[MAX_OSPATH], *dot;
- int old_khz;
-
- // make sure CD isn't playing music
- CDAudio_Stop();
-
- cl.cinematicframe = 0;
- dot = strstr (arg, ".");
- if (dot && !strcmp (dot, ".pcx"))
- { // static pcx image
- Com_sprintf (name, sizeof(name), "pics/%s", arg);
- SCR_LoadPCX (name, &cin.pic, &palette, &cin.width, &cin.height);
- cl.cinematicframe = -1;
- cl.cinematictime = 1;
- SCR_EndLoadingPlaque ();
- cls.state = ca_active;
- if (!cin.pic)
- {
- Com_Printf ("%s not found.\n", name);
- cl.cinematictime = 0;
- }
- else
- {
- memcpy (cl.cinematicpalette, palette, sizeof(cl.cinematicpalette));
- Z_Free (palette);
- }
- return;
- }
-
- Com_sprintf (name, sizeof(name), "video/%s", arg);
- FS_FOpenFile (name, &cl.cinematic_file);
- if (!cl.cinematic_file)
- {
-// Com_Error (ERR_DROP, "Cinematic %s not found.\n", name);
- SCR_FinishCinematic ();
- cl.cinematictime = 0; // done
- return;
- }
-
- SCR_EndLoadingPlaque ();
-
- cls.state = ca_active;
-
- FS_Read (&width, 4, cl.cinematic_file);
- FS_Read (&height, 4, cl.cinematic_file);
- cin.width = LittleLong(width);
- cin.height = LittleLong(height);
-
- FS_Read (&cin.s_rate, 4, cl.cinematic_file);
- cin.s_rate = LittleLong(cin.s_rate);
- FS_Read (&cin.s_width, 4, cl.cinematic_file);
- cin.s_width = LittleLong(cin.s_width);
- FS_Read (&cin.s_channels, 4, cl.cinematic_file);
- cin.s_channels = LittleLong(cin.s_channels);
-
- Huff1TableInit ();
-
- // switch up to 22 khz sound if necessary
- old_khz = Cvar_VariableValue ("s_khz");
- if (old_khz != cin.s_rate/1000)
- {
- cin.restart_sound = true;
- Cvar_SetValue ("s_khz", cin.s_rate/1000);
- CL_Snd_Restart_f ();
- Cvar_SetValue ("s_khz", old_khz);
- }
-
- cl.cinematicframe = 0;
- cin.pic = SCR_ReadNextFrame ();
- cl.cinematictime = Sys_Milliseconds ();
-}
--- a/client/cl_ents.c
+++ /dev/null
@@ -1,1487 +1,0 @@
-// cl_ents.c -- entity parsing and management
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-
-extern struct model_s *cl_mod_powerscreen;
-
-//PGM
-int vidref_val;
-//PGM
-
-/*
-=========================================================================
-
-FRAME PARSING
-
-=========================================================================
-*/
-
-/* the following are commented out in release
-
-typedef struct
-{
- int modelindex;
- int num; // entity number
- int effects;
- vec3_t origin;
- vec3_t oldorigin;
- vec3_t angles;
- qboolean present;
-} projectile_t;
-
-#define MAX_PROJECTILES 64
-projectile_t cl_projectiles[MAX_PROJECTILES];
-
-void CL_ClearProjectiles (void)
-{
- int i;
-
- for (i = 0; i < MAX_PROJECTILES; i++) {
-// if (cl_projectiles[i].present)
-// Com_DPrintf("PROJ: %d CLEARED\n", cl_projectiles[i].num);
- cl_projectiles[i].present = false;
- }
-}
-
-*/
-
-/*
-=====================
-CL_ParseProjectiles
-
-Flechettes are passed as efficient temporary entities
-=====================
-*/
-/*
-void CL_ParseProjectiles (void)
-{
- int i, c, j;
- byte bits[8];
- byte b;
- projectile_t pr;
- int lastempty = -1;
- qboolean old = false;
-
- c = MSG_ReadByte (&net_message);
- for (i=0 ; i<c ; i++)
- {
- bits[0] = MSG_ReadByte (&net_message);
- bits[1] = MSG_ReadByte (&net_message);
- bits[2] = MSG_ReadByte (&net_message);
- bits[3] = MSG_ReadByte (&net_message);
- bits[4] = MSG_ReadByte (&net_message);
- pr.origin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
- pr.origin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
- pr.origin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
- VectorCopy(pr.origin, pr.oldorigin);
-
- if (bits[4] & 64)
- pr.effects = EF_BLASTER;
- else
- pr.effects = 0;
-
- if (bits[4] & 128) {
- old = true;
- bits[0] = MSG_ReadByte (&net_message);
- bits[1] = MSG_ReadByte (&net_message);
- bits[2] = MSG_ReadByte (&net_message);
- bits[3] = MSG_ReadByte (&net_message);
- bits[4] = MSG_ReadByte (&net_message);
- pr.oldorigin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
- pr.oldorigin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
- pr.oldorigin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
- }
-
- bits[0] = MSG_ReadByte (&net_message);
- bits[1] = MSG_ReadByte (&net_message);
- bits[2] = MSG_ReadByte (&net_message);
-
- pr.angles[0] = 360*bits[0]/256;
- pr.angles[1] = 360*bits[1]/256;
- pr.modelindex = bits[2];
-
- b = MSG_ReadByte (&net_message);
- pr.num = (b & 0x7f);
- if (b & 128) // extra entity number byte
- pr.num |= (MSG_ReadByte (&net_message) << 7);
-
- pr.present = true;
-
- // find if this projectile already exists from previous frame
- for (j = 0; j < MAX_PROJECTILES; j++) {
- if (cl_projectiles[j].modelindex) {
- if (cl_projectiles[j].num == pr.num) {
- // already present, set up oldorigin for interpolation
- if (!old)
- VectorCopy(cl_projectiles[j].origin, pr.oldorigin);
- cl_projectiles[j] = pr;
- break;
- }
- } else
- lastempty = j;
- }
-
- // not present previous frame, add it
- if (j == MAX_PROJECTILES) {
- if (lastempty != -1) {
- cl_projectiles[lastempty] = pr;
- }
- }
- }
-}
-*/
-
-/*
-=============
-CL_LinkProjectiles
-
-=============
-*/
-/*
-void CL_AddProjectiles (void)
-{
- int i, j;
- projectile_t *pr;
- entity_t ent;
-
- memset (&ent, 0, sizeof(ent));
-
- for (i=0, pr=cl_projectiles ; i < MAX_PROJECTILES ; i++, pr++)
- {
- // grab an entity to fill in
- if (pr->modelindex < 1)
- continue;
- if (!pr->present) {
- pr->modelindex = 0;
- continue; // not present this frame (it was in the previous frame)
- }
-
- ent.model = cl.model_draw[pr->modelindex];
-
- // interpolate origin
- for (j=0 ; j<3 ; j++)
- {
- ent.origin[j] = ent.oldorigin[j] = pr->oldorigin[j] + cl.lerpfrac *
- (pr->origin[j] - pr->oldorigin[j]);
-
- }
-
- if (pr->effects & EF_BLASTER)
- CL_BlasterTrail (pr->oldorigin, ent.origin);
- V_AddLight (pr->origin, 200, 1, 1, 0);
-
- VectorCopy (pr->angles, ent.angles);
- V_AddEntity (&ent);
- }
-}
-*/
-
-/*
-=================
-CL_ParseEntityBits
-
-Returns the entity number and the header bits
-=================
-*/
-int bitcounts[32]; /// just for protocol profiling
-int CL_ParseEntityBits (int *bits)
-{
- unsigned b, total;
- int i;
- int number;
-
- total = MSG_ReadByte (&net_message);
- if (total & U_MOREBITS1)
- {
- b = MSG_ReadByte (&net_message);
- total |= b<<8;
- }
- if (total & U_MOREBITS2)
- {
- b = MSG_ReadByte (&net_message);
- total |= b<<16;
- }
- if (total & U_MOREBITS3)
- {
- b = MSG_ReadByte (&net_message);
- total |= b<<24;
- }
-
- // count the bits for net profiling
- for (i=0 ; i<32 ; i++)
- if (total&(1<<i))
- bitcounts[i]++;
-
- if (total & U_NUMBER16)
- number = MSG_ReadShort (&net_message);
- else
- number = MSG_ReadByte (&net_message);
-
- *bits = total;
-
- return number;
-}
-
-/*
-==================
-CL_ParseDelta
-
-Can go from either a baseline or a previous packet_entity
-==================
-*/
-void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits)
-{
- // set everything to the state we are delta'ing from
- *to = *from;
-
- VectorCopy (from->origin, to->old_origin);
- to->number = number;
-
- if (bits & U_MODEL)
- to->modelindex = MSG_ReadByte (&net_message);
- if (bits & U_MODEL2)
- to->modelindex2 = MSG_ReadByte (&net_message);
- if (bits & U_MODEL3)
- to->modelindex3 = MSG_ReadByte (&net_message);
- if (bits & U_MODEL4)
- to->modelindex4 = MSG_ReadByte (&net_message);
-
- if (bits & U_FRAME8)
- to->frame = MSG_ReadByte (&net_message);
- if (bits & U_FRAME16)
- to->frame = MSG_ReadShort (&net_message);
-
- if ((bits & U_SKIN8) && (bits & U_SKIN16)) //used for laser colors
- to->skinnum = MSG_ReadLong(&net_message);
- else if (bits & U_SKIN8)
- to->skinnum = MSG_ReadByte(&net_message);
- else if (bits & U_SKIN16)
- to->skinnum = MSG_ReadShort(&net_message);
-
- if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
- to->effects = MSG_ReadLong(&net_message);
- else if (bits & U_EFFECTS8)
- to->effects = MSG_ReadByte(&net_message);
- else if (bits & U_EFFECTS16)
- to->effects = MSG_ReadShort(&net_message);
-
- if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
- to->renderfx = MSG_ReadLong(&net_message);
- else if (bits & U_RENDERFX8)
- to->renderfx = MSG_ReadByte(&net_message);
- else if (bits & U_RENDERFX16)
- to->renderfx = MSG_ReadShort(&net_message);
-
- if (bits & U_ORIGIN1)
- to->origin[0] = MSG_ReadCoord (&net_message);
- if (bits & U_ORIGIN2)
- to->origin[1] = MSG_ReadCoord (&net_message);
- if (bits & U_ORIGIN3)
- to->origin[2] = MSG_ReadCoord (&net_message);
-
- if (bits & U_ANGLE1)
- to->angles[0] = MSG_ReadAngle(&net_message);
- if (bits & U_ANGLE2)
- to->angles[1] = MSG_ReadAngle(&net_message);
- if (bits & U_ANGLE3)
- to->angles[2] = MSG_ReadAngle(&net_message);
-
- if (bits & U_OLDORIGIN)
- MSG_ReadPos (&net_message, to->old_origin);
-
- if (bits & U_SOUND)
- to->sound = MSG_ReadByte (&net_message);
-
- if (bits & U_EVENT)
- to->event = MSG_ReadByte (&net_message);
- else
- to->event = 0;
-
- if (bits & U_SOLID)
- to->solid = MSG_ReadShort (&net_message);
-}
-
-/*
-==================
-CL_DeltaEntity
-
-Parses deltas from the given base and adds the resulting entity
-to the current frame
-==================
-*/
-void CL_DeltaEntity (frame_t *frame, int newnum, entity_state_t *old, int bits)
-{
- centity_t *ent;
- entity_state_t *state;
-
- ent = &cl_entities[newnum];
-
- state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)];
- cl.parse_entities++;
- frame->num_entities++;
-
- CL_ParseDelta (old, state, newnum, bits);
-
- // some data changes will force no lerping
- if (state->modelindex != ent->current.modelindex
- || state->modelindex2 != ent->current.modelindex2
- || state->modelindex3 != ent->current.modelindex3
- || state->modelindex4 != ent->current.modelindex4
- || abs(state->origin[0] - ent->current.origin[0]) > 512
- || abs(state->origin[1] - ent->current.origin[1]) > 512
- || abs(state->origin[2] - ent->current.origin[2]) > 512
- || state->event == EV_PLAYER_TELEPORT
- || state->event == EV_OTHER_TELEPORT
- )
- {
- ent->serverframe = -99;
- }
-
- if (ent->serverframe != cl.frame.serverframe - 1)
- { // wasn't in last update, so initialize some things
- ent->trailcount = 1024; // for diminishing rocket / grenade trails
- // duplicate the current state so lerping doesn't hurt anything
- ent->prev = *state;
- if (state->event == EV_OTHER_TELEPORT)
- {
- VectorCopy (state->origin, ent->prev.origin);
- VectorCopy (state->origin, ent->lerp_origin);
- }
- else
- {
- VectorCopy (state->old_origin, ent->prev.origin);
- VectorCopy (state->old_origin, ent->lerp_origin);
- }
- }
- else
- { // shuffle the last state to previous
- ent->prev = ent->current;
- }
-
- ent->serverframe = cl.frame.serverframe;
- ent->current = *state;
-}
-
-/*
-==================
-CL_ParsePacketEntities
-
-An svc_packetentities has just been parsed, deal with the
-rest of the data stream.
-==================
-*/
-void CL_ParsePacketEntities (frame_t *oldframe, frame_t *newframe)
-{
- int newnum;
- int bits;
- entity_state_t *oldstate = nil;
- int oldindex, oldnum;
-
- newframe->parse_entities = cl.parse_entities;
- newframe->num_entities = 0;
-
- // delta from the entities present in oldframe
- oldindex = 0;
- if (!oldframe)
- oldnum = 99999;
- else
- {
- if (oldindex >= oldframe->num_entities)
- oldnum = 99999;
- else
- {
- oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- }
-
- while (1)
- {
- newnum = CL_ParseEntityBits (&bits);
- if (newnum >= MAX_EDICTS)
- Com_Error (ERR_DROP,"CL_ParsePacketEntities: bad number:%i", newnum);
-
- if (net_message.readcount > net_message.cursize)
- Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
-
- if (!newnum)
- break;
-
- while (oldnum < newnum)
- { // one or more entities from the old packet are unchanged
- if (cl_shownet->value == 3)
- Com_Printf (" unchanged: %i\n", oldnum);
- CL_DeltaEntity (newframe, oldnum, oldstate, 0);
-
- oldindex++;
-
- if (oldindex >= oldframe->num_entities)
- oldnum = 99999;
- else
- {
- oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- }
-
- if (bits & U_REMOVE)
- { // the entity present in oldframe is not in the current frame
- if (cl_shownet->value == 3)
- Com_Printf (" remove: %i\n", newnum);
- if (oldnum != newnum)
- Com_Printf ("U_REMOVE: oldnum != newnum\n");
-
- oldindex++;
-
- if (oldindex >= oldframe->num_entities)
- oldnum = 99999;
- else
- {
- oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- continue;
- }
-
- if (oldnum == newnum)
- { // delta from previous state
- if (cl_shownet->value == 3)
- Com_Printf (" delta: %i\n", newnum);
- CL_DeltaEntity (newframe, newnum, oldstate, bits);
-
- oldindex++;
-
- if (oldindex >= oldframe->num_entities)
- oldnum = 99999;
- else
- {
- oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- continue;
- }
-
- if (oldnum > newnum)
- { // delta from baseline
- if (cl_shownet->value == 3)
- Com_Printf (" baseline: %i\n", newnum);
- CL_DeltaEntity (newframe, newnum, &cl_entities[newnum].baseline, bits);
- continue;
- }
-
- }
-
- // any remaining entities in the old frame are copied over
- while (oldnum != 99999)
- { // one or more entities from the old packet are unchanged
- if (cl_shownet->value == 3)
- Com_Printf (" unchanged: %i\n", oldnum);
- CL_DeltaEntity (newframe, oldnum, oldstate, 0);
-
- oldindex++;
-
- if (oldindex >= oldframe->num_entities)
- oldnum = 99999;
- else
- {
- oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- }
-}
-
-
-
-/*
-===================
-CL_ParsePlayerstate
-===================
-*/
-void CL_ParsePlayerstate (frame_t *oldframe, frame_t *newframe)
-{
- int flags;
- player_state_t *state;
- int i;
- int statbits;
-
- state = &newframe->playerstate;
-
- // clear to old value before delta parsing
- if (oldframe)
- *state = oldframe->playerstate;
- else
- memset (state, 0, sizeof(*state));
-
- flags = MSG_ReadShort (&net_message);
-
- //
- // parse the pmove_state_t
- //
- if (flags & PS_M_TYPE)
- state->pmove.pm_type = MSG_ReadByte (&net_message);
-
- if (flags & PS_M_ORIGIN)
- {
- state->pmove.origin[0] = MSG_ReadShort (&net_message);
- state->pmove.origin[1] = MSG_ReadShort (&net_message);
- state->pmove.origin[2] = MSG_ReadShort (&net_message);
- }
-
- if (flags & PS_M_VELOCITY)
- {
- state->pmove.velocity[0] = MSG_ReadShort (&net_message);
- state->pmove.velocity[1] = MSG_ReadShort (&net_message);
- state->pmove.velocity[2] = MSG_ReadShort (&net_message);
- }
-
- if (flags & PS_M_TIME)
- state->pmove.pm_time = MSG_ReadByte (&net_message);
-
- if (flags & PS_M_FLAGS)
- state->pmove.pm_flags = MSG_ReadByte (&net_message);
-
- if (flags & PS_M_GRAVITY)
- state->pmove.gravity = MSG_ReadShort (&net_message);
-
- if (flags & PS_M_DELTA_ANGLES)
- {
- state->pmove.delta_angles[0] = MSG_ReadShort (&net_message);
- state->pmove.delta_angles[1] = MSG_ReadShort (&net_message);
- state->pmove.delta_angles[2] = MSG_ReadShort (&net_message);
- }
-
- if (cl.attractloop)
- state->pmove.pm_type = PM_FREEZE; // demo playback
-
- //
- // parse the rest of the player_state_t
- //
- if (flags & PS_VIEWOFFSET)
- {
- state->viewoffset[0] = MSG_ReadChar (&net_message) * 0.25;
- state->viewoffset[1] = MSG_ReadChar (&net_message) * 0.25;
- state->viewoffset[2] = MSG_ReadChar (&net_message) * 0.25;
- }
-
- if (flags & PS_VIEWANGLES)
- {
- state->viewangles[0] = MSG_ReadAngle16 (&net_message);
- state->viewangles[1] = MSG_ReadAngle16 (&net_message);
- state->viewangles[2] = MSG_ReadAngle16 (&net_message);
- }
-
- if (flags & PS_KICKANGLES)
- {
- state->kick_angles[0] = MSG_ReadChar (&net_message) * 0.25;
- state->kick_angles[1] = MSG_ReadChar (&net_message) * 0.25;
- state->kick_angles[2] = MSG_ReadChar (&net_message) * 0.25;
- }
-
- if (flags & PS_WEAPONINDEX)
- {
- state->gunindex = MSG_ReadByte (&net_message);
- }
-
- if (flags & PS_WEAPONFRAME)
- {
- state->gunframe = MSG_ReadByte (&net_message);
- state->gunoffset[0] = MSG_ReadChar (&net_message)*0.25;
- state->gunoffset[1] = MSG_ReadChar (&net_message)*0.25;
- state->gunoffset[2] = MSG_ReadChar (&net_message)*0.25;
- state->gunangles[0] = MSG_ReadChar (&net_message)*0.25;
- state->gunangles[1] = MSG_ReadChar (&net_message)*0.25;
- state->gunangles[2] = MSG_ReadChar (&net_message)*0.25;
- }
-
- if (flags & PS_BLEND)
- {
- state->blend[0] = MSG_ReadByte (&net_message)/255.0;
- state->blend[1] = MSG_ReadByte (&net_message)/255.0;
- state->blend[2] = MSG_ReadByte (&net_message)/255.0;
- state->blend[3] = MSG_ReadByte (&net_message)/255.0;
- }
-
- if (flags & PS_FOV)
- state->fov = MSG_ReadByte (&net_message);
-
- if (flags & PS_RDFLAGS)
- state->rdflags = MSG_ReadByte (&net_message);
-
- // parse stats
- statbits = MSG_ReadLong (&net_message);
- for (i=0 ; i<MAX_STATS ; i++)
- if (statbits & (1<<i) )
- state->stats[i] = MSG_ReadShort(&net_message);
-}
-
-
-/*
-==================
-CL_FireEntityEvents
-
-==================
-*/
-void CL_FireEntityEvents (frame_t *frame)
-{
- entity_state_t *s1;
- int pnum, num;
-
- for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
- {
- num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1);
- s1 = &cl_parse_entities[num];
- if (s1->event)
- CL_EntityEvent (s1);
-
- // EF_TELEPORTER acts like an event, but is not cleared each frame
- if (s1->effects & EF_TELEPORTER)
- CL_TeleporterParticles (s1);
- }
-}
-
-
-/*
-================
-CL_ParseFrame
-================
-*/
-void CL_ParseFrame (void)
-{
- int cmd;
- int len;
- frame_t *old;
-
- memset (&cl.frame, 0, sizeof(cl.frame));
-
-/*
- CL_ClearProjectiles(); // clear projectiles for new frame
-*/
-
- cl.frame.serverframe = MSG_ReadLong (&net_message);
- cl.frame.deltaframe = MSG_ReadLong (&net_message);
- cl.frame.servertime = cl.frame.serverframe*100;
-
- // BIG HACK to let old demos continue to work
- if (cls.serverProtocol != 26)
- cl.surpressCount = MSG_ReadByte (&net_message);
-
- if (cl_shownet->value == 3)
- Com_Printf (" frame:%i delta:%i\n", cl.frame.serverframe,
- cl.frame.deltaframe);
-
- // If the frame is delta compressed from data that we
- // no longer have available, we must suck up the rest of
- // the frame, but not use it, then ask for a non-compressed
- // message
- if (cl.frame.deltaframe <= 0)
- {
- cl.frame.valid = true; // uncompressed frame
- old = NULL;
- cls.demowaiting = false; // we can start recording now
- }
- else
- {
- old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
- if (!old->valid)
- { // should never happen
- Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
- }
- if (old->serverframe != cl.frame.deltaframe)
- { // The frame that the server did the delta from
- // is too old, so we can't reconstruct it properly.
- Com_Printf ("Delta frame too old.\n");
- }
- else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128)
- {
- Com_Printf ("Delta parse_entities too old.\n");
- }
- else
- cl.frame.valid = true; // valid delta parse
- }
-
- // clamp time
- if (cl.time > cl.frame.servertime)
- cl.time = cl.frame.servertime;
- else if (cl.time < cl.frame.servertime - 100)
- cl.time = cl.frame.servertime - 100;
-
- // read areabits
- len = MSG_ReadByte (&net_message);
- MSG_ReadData (&net_message, cl.frame.areabits, len);
-
- // read playerinfo
- cmd = MSG_ReadByte (&net_message);
- SHOWNET(svc_strings[cmd]);
- if (cmd != svc_playerinfo)
- Com_Error (ERR_DROP, "CL_ParseFrame: not playerinfo");
- CL_ParsePlayerstate (old, &cl.frame);
-
- // read packet entities
- cmd = MSG_ReadByte (&net_message);
- SHOWNET(svc_strings[cmd]);
- if (cmd != svc_packetentities)
- Com_Error (ERR_DROP, "CL_ParseFrame: not packetentities");
- CL_ParsePacketEntities (old, &cl.frame);
-
-/*
- if (cmd == svc_packetentities2)
- CL_ParseProjectiles();
-*/
-
- // save the frame off in the backup array for later delta comparisons
- cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;
-
- if (cl.frame.valid)
- {
- // getting a valid frame message ends the connection process
- if (cls.state != ca_active)
- {
- cls.state = ca_active;
- cl.force_refdef = true;
- cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
- cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
- cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125;
- VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles);
- if (cls.disable_servercount != cl.servercount
- && cl.refresh_prepped)
- SCR_EndLoadingPlaque (); // get rid of loading plaque
- }
- cl.sound_prepped = true; // can start mixing ambient sounds
-
- // fire entity events
- CL_FireEntityEvents (&cl.frame);
- CL_CheckPredictionError ();
- }
-}
-
-/*
-==========================================================================
-
-INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
-
-==========================================================================
-*/
-
-struct model_s *S_RegisterSexedModel (entity_state_t *ent, char *base)
-{
- int n;
- char *p;
- struct model_s *mdl;
- char model[MAX_QPATH];
- char buffer[MAX_QPATH];
-
- // determine what model the client is using
- model[0] = 0;
- n = CS_PLAYERSKINS + ent->number - 1;
- if (cl.configstrings[n][0])
- {
- p = strchr(cl.configstrings[n], '\\');
- if (p)
- {
- p += 1;
- strcpy(model, p);
- p = strchr(model, '/');
- if (p)
- *p = 0;
- }
- }
- // if we can't figure it out, they're male
- if (!model[0])
- strcpy(model, "male");
-
- Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", model, base+1);
- mdl = re.RegisterModel(buffer);
- if (!mdl) {
- // not found, try default weapon model
- Com_sprintf (buffer, sizeof(buffer), "players/%s/weapon.md2", model);
- mdl = re.RegisterModel(buffer);
- if (!mdl) {
- // no, revert to the male model
- Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", "male", base+1);
- mdl = re.RegisterModel(buffer);
- if (!mdl) {
- // last try, default male weapon.md2
- Com_sprintf (buffer, sizeof(buffer), "players/male/weapon.md2");
- mdl = re.RegisterModel(buffer);
- }
- }
- }
-
- return mdl;
-}
-
-/*
-===============
-CL_AddPacketEntities
-
-===============
-*/
-void CL_AddPacketEntities (frame_t *frame)
-{
- entity_t ent;
- entity_state_t *s1;
- float autorotate;
- int i;
- int pnum;
- centity_t *cent;
- int autoanim;
- clientinfo_t *ci;
- unsigned int effects, renderfx;
-
- // bonus items rotate at a fixed rate
- autorotate = anglemod(cl.time/10);
-
- // brush models can auto animate their frames
- autoanim = 2*cl.time/1000;
-
- memset (&ent, 0, sizeof(ent));
-
- for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
- {
- s1 = &cl_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)];
-
- cent = &cl_entities[s1->number];
-
- effects = s1->effects;
- renderfx = s1->renderfx;
-
- // set frame
- if (effects & EF_ANIM01)
- ent.frame = autoanim & 1;
- else if (effects & EF_ANIM23)
- ent.frame = 2 + (autoanim & 1);
- else if (effects & EF_ANIM_ALL)
- ent.frame = autoanim;
- else if (effects & EF_ANIM_ALLFAST)
- ent.frame = cl.time / 100;
- else
- ent.frame = s1->frame;
-
- // quad and pent can do different things on client
- if (effects & EF_PENT)
- {
- effects &= ~EF_PENT;
- effects |= EF_COLOR_SHELL;
- renderfx |= RF_SHELL_RED;
- }
-
- if (effects & EF_QUAD)
- {
- effects &= ~EF_QUAD;
- effects |= EF_COLOR_SHELL;
- renderfx |= RF_SHELL_BLUE;
- }
-//======
-// PMM
- if (effects & EF_DOUBLE)
- {
- effects &= ~EF_DOUBLE;
- effects |= EF_COLOR_SHELL;
- renderfx |= RF_SHELL_DOUBLE;
- }
-
- if (effects & EF_HALF_DAMAGE)
- {
- effects &= ~EF_HALF_DAMAGE;
- effects |= EF_COLOR_SHELL;
- renderfx |= RF_SHELL_HALF_DAM;
- }
-// pmm
-//======
- ent.oldframe = cent->prev.frame;
- ent.backlerp = 1.0 - cl.lerpfrac;
-
- if (renderfx & (RF_FRAMELERP|RF_BEAM))
- { // step origin discretely, because the frames
- // do the animation properly
- VectorCopy (cent->current.origin, ent.origin);
- VectorCopy (cent->current.old_origin, ent.oldorigin);
- }
- else
- { // interpolate origin
- for (i=0 ; i<3 ; i++)
- {
- ent.origin[i] = ent.oldorigin[i] = cent->prev.origin[i] + cl.lerpfrac *
- (cent->current.origin[i] - cent->prev.origin[i]);
- }
- }
-
- // create a new entity
-
- // tweak the color of beams
- if ( renderfx & RF_BEAM )
- { // the four beam colors are encoded in 32 bits of skinnum (hack)
- ent.alpha = 0.30;
- ent.skinnum = (s1->skinnum >> ((rand() % 4)*8)) & 0xff;
- ent.model = NULL;
- }
- else
- {
- // set skin
- if (s1->modelindex == 255)
- { // use custom player skin
- ent.skinnum = 0;
- ci = &cl.clientinfo[s1->skinnum & 0xff];
- ent.skin = ci->skin;
- ent.model = ci->model;
- if (!ent.skin || !ent.model)
- {
- ent.skin = cl.baseclientinfo.skin;
- ent.model = cl.baseclientinfo.model;
- }
-
-//============
-//PGM
- if (renderfx & RF_USE_DISGUISE)
- {
- if(!strncmp((char *)ent.skin, "players/male", 12))
- {
- ent.skin = re.RegisterSkin ("players/male/disguise.pcx");
- ent.model = re.RegisterModel ("players/male/tris.md2");
- }
- else if(!strncmp((char *)ent.skin, "players/female", 14))
- {
- ent.skin = re.RegisterSkin ("players/female/disguise.pcx");
- ent.model = re.RegisterModel ("players/female/tris.md2");
- }
- else if(!strncmp((char *)ent.skin, "players/cyborg", 14))
- {
- ent.skin = re.RegisterSkin ("players/cyborg/disguise.pcx");
- ent.model = re.RegisterModel ("players/cyborg/tris.md2");
- }
- }
-//PGM
-//============
- }
- else
- {
- ent.skinnum = s1->skinnum;
- ent.skin = NULL;
- ent.model = cl.model_draw[s1->modelindex];
- }
- }
-
- // only used for black hole model right now, FIXME: do better
- if (renderfx == RF_TRANSLUCENT)
- ent.alpha = 0.70;
-
- // render effects (fullbright, translucent, etc)
- if ((effects & EF_COLOR_SHELL))
- ent.flags = 0; // renderfx go on color shell entity
- else
- ent.flags = renderfx;
-
- // calculate angles
- if (effects & EF_ROTATE)
- { // some bonus items auto-rotate
- ent.angles[0] = 0;
- ent.angles[1] = autorotate;
- ent.angles[2] = 0;
- }
- // RAFAEL
- else if (effects & EF_SPINNINGLIGHTS)
- {
- ent.angles[0] = 0;
- ent.angles[1] = anglemod(cl.time/2) + s1->angles[1];
- ent.angles[2] = 180;
- {
- vec3_t forward;
- vec3_t start;
-
- AngleVectors (ent.angles, forward, NULL, NULL);
- VectorMA (ent.origin, 64, forward, start);
- V_AddLight (start, 100, 1, 0, 0);
- }
- }
- else
- { // interpolate angles
- float a1, a2;
-
- for (i=0 ; i<3 ; i++)
- {
- a1 = cent->current.angles[i];
- a2 = cent->prev.angles[i];
- ent.angles[i] = LerpAngle (a2, a1, cl.lerpfrac);
- }
- }
-
- if (s1->number == cl.playernum+1)
- {
- ent.flags |= RF_VIEWERMODEL; // only draw from mirrors
- // FIXME: still pass to refresh
-
- if (effects & EF_FLAG1)
- V_AddLight (ent.origin, 225, 1.0, 0.1, 0.1);
- else if (effects & EF_FLAG2)
- V_AddLight (ent.origin, 225, 0.1, 0.1, 1.0);
- else if (effects & EF_TAGTRAIL) //PGM
- V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0); //PGM
- else if (effects & EF_TRACKERTRAIL) //PGM
- V_AddLight (ent.origin, 225, -1.0, -1.0, -1.0); //PGM
-
- continue;
- }
-
- // if set to invisible, skip
- if (!s1->modelindex)
- continue;
-
- if (effects & EF_BFG)
- {
- ent.flags |= RF_TRANSLUCENT;
- ent.alpha = 0.30;
- }
-
- // RAFAEL
- if (effects & EF_PLASMA)
- {
- ent.flags |= RF_TRANSLUCENT;
- ent.alpha = 0.6;
- }
-
- if (effects & EF_SPHERETRANS)
- {
- ent.flags |= RF_TRANSLUCENT;
- // PMM - *sigh* yet more EF overloading
- if (effects & EF_TRACKERTRAIL)
- ent.alpha = 0.6;
- else
- ent.alpha = 0.3;
- }
-//pmm
-
- // add to refresh list
- V_AddEntity (&ent);
-
- // color shells generate a seperate entity for the main model
- if (effects & EF_COLOR_SHELL)
- {
- ent.flags = renderfx | RF_TRANSLUCENT;
- ent.alpha = 0.30;
- V_AddEntity (&ent);
- }
-
- ent.skin = NULL; // never use a custom skin on others
- ent.skinnum = 0;
- ent.flags = 0;
- ent.alpha = 0;
-
- // duplicate for linked models
- if (s1->modelindex2)
- {
- if (s1->modelindex2 == 255)
- { // custom weapon
- ci = &cl.clientinfo[s1->skinnum & 0xff];
- i = (s1->skinnum >> 8); // 0 is default weapon model
- if (!cl_vwep->value || i > MAX_CLIENTWEAPONMODELS - 1)
- i = 0;
- ent.model = ci->weaponmodel[i];
- if (!ent.model) {
- if (i != 0)
- ent.model = ci->weaponmodel[0];
- if (!ent.model)
- ent.model = cl.baseclientinfo.weaponmodel[0];
- }
- }
- //PGM - hack to allow translucent linked models (defender sphere's shell)
- // set the high bit 0x80 on modelindex2 to enable translucency
- else if(s1->modelindex2 & 0x80)
- {
- ent.model = cl.model_draw[s1->modelindex2 & 0x7F];
- ent.alpha = 0.32;
- ent.flags = RF_TRANSLUCENT;
- }
- //PGM
- else
- ent.model = cl.model_draw[s1->modelindex2];
- V_AddEntity (&ent);
-
- //PGM - make sure these get reset.
- ent.flags = 0;
- ent.alpha = 0;
- //PGM
- }
- if (s1->modelindex3)
- {
- ent.model = cl.model_draw[s1->modelindex3];
- V_AddEntity (&ent);
- }
- if (s1->modelindex4)
- {
- ent.model = cl.model_draw[s1->modelindex4];
- V_AddEntity (&ent);
- }
-
- if ( effects & EF_POWERSCREEN )
- {
- ent.model = cl_mod_powerscreen;
- ent.oldframe = 0;
- ent.frame = 0;
- ent.flags |= (RF_TRANSLUCENT | RF_SHELL_GREEN);
- ent.alpha = 0.30;
- V_AddEntity (&ent);
- }
-
- // add automatic particle trails
- if ( (effects&~EF_ROTATE) )
- {
- if (effects & EF_ROCKET)
- {
- CL_RocketTrail (cent->lerp_origin, ent.origin, cent);
- V_AddLight (ent.origin, 200, 1, 1, 0);
- }
- // PGM - Do not reorder EF_BLASTER and EF_HYPERBLASTER.
- // EF_BLASTER | EF_TRACKER is a special case for EF_BLASTER2... Cheese!
- else if (effects & EF_BLASTER)
- {
-// CL_BlasterTrail (cent->lerp_origin, ent.origin);
-//PGM
- if (effects & EF_TRACKER) // lame... problematic?
- {
- CL_BlasterTrail2 (cent->lerp_origin, ent.origin);
- V_AddLight (ent.origin, 200, 0, 1, 0);
- }
- else
- {
- CL_BlasterTrail (cent->lerp_origin, ent.origin);
- V_AddLight (ent.origin, 200, 1, 1, 0);
- }
-//PGM
- }
- else if (effects & EF_HYPERBLASTER)
- {
- if (effects & EF_TRACKER) // PGM overloaded for blaster2.
- V_AddLight (ent.origin, 200, 0, 1, 0); // PGM
- else // PGM
- V_AddLight (ent.origin, 200, 1, 1, 0);
- }
- else if (effects & EF_GIB)
- {
- CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
- }
- else if (effects & EF_GRENADE)
- {
- CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
- }
- else if (effects & EF_FLIES)
- {
- CL_FlyEffect (cent, ent.origin);
- }
- else if (effects & EF_BFG)
- {
- static int bfg_lightramp[6] = {300, 400, 600, 300, 150, 75};
-
- if (effects & EF_ANIM_ALLFAST)
- {
- CL_BfgParticles (&ent);
- i = 200;
- }
- else
- {
- i = bfg_lightramp[s1->frame];
- }
- V_AddLight (ent.origin, i, 0, 1, 0);
- }
- // RAFAEL
- else if (effects & EF_TRAP)
- {
- ent.origin[2] += 32;
- CL_TrapParticles (&ent);
- i = (rand()%100) + 100;
- V_AddLight (ent.origin, i, 1, 0.8, 0.1);
- }
- else if (effects & EF_FLAG1)
- {
- CL_FlagTrail (cent->lerp_origin, ent.origin, 242);
- V_AddLight (ent.origin, 225, 1, 0.1, 0.1);
- }
- else if (effects & EF_FLAG2)
- {
- CL_FlagTrail (cent->lerp_origin, ent.origin, 115);
- V_AddLight (ent.origin, 225, 0.1, 0.1, 1);
- }
-//======
-//ROGUE
- else if (effects & EF_TAGTRAIL)
- {
- CL_TagTrail (cent->lerp_origin, ent.origin, 220);
- V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);
- }
- else if (effects & EF_TRACKERTRAIL)
- {
- if (effects & EF_TRACKER)
- {
- float intensity;
-
- intensity = 50 + (500 * (sin(cl.time/500.0) + 1.0));
- // FIXME - check out this effect in rendition
- if(vidref_val == VIDREF_GL)
- V_AddLight (ent.origin, intensity, -1.0, -1.0, -1.0);
- else
- V_AddLight (ent.origin, -1.0 * intensity, 1.0, 1.0, 1.0);
- }
- else
- {
- CL_Tracker_Shell (cent->lerp_origin);
- V_AddLight (ent.origin, 155, -1.0, -1.0, -1.0);
- }
- }
- else if (effects & EF_TRACKER)
- {
- CL_TrackerTrail (cent->lerp_origin, ent.origin, 0);
- // FIXME - check out this effect in rendition
- if(vidref_val == VIDREF_GL)
- V_AddLight (ent.origin, 200, -1, -1, -1);
- else
- V_AddLight (ent.origin, -200, 1, 1, 1);
- }
-//ROGUE
-//======
- // RAFAEL
- else if (effects & EF_GREENGIB)
- {
- CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
- }
- // RAFAEL
- else if (effects & EF_IONRIPPER)
- {
- CL_IonripperTrail (cent->lerp_origin, ent.origin);
- V_AddLight (ent.origin, 100, 1, 0.5, 0.5);
- }
- // RAFAEL
- else if (effects & EF_BLUEHYPERBLASTER)
- {
- V_AddLight (ent.origin, 200, 0, 0, 1);
- }
- // RAFAEL
- else if (effects & EF_PLASMA)
- {
- if (effects & EF_ANIM_ALLFAST)
- {
- CL_BlasterTrail (cent->lerp_origin, ent.origin);
- }
- V_AddLight (ent.origin, 130, 1, 0.5, 0.5);
- }
- }
-
- VectorCopy (ent.origin, cent->lerp_origin);
- }
-}
-
-
-
-/*
-==============
-CL_AddViewWeapon
-==============
-*/
-void CL_AddViewWeapon (player_state_t *ps, player_state_t *ops)
-{
- entity_t gun; // view model
- int i;
-
- // allow the gun to be completely removed
- if (!cl_gun->value)
- return;
-
- // don't draw gun if in wide angle view
- if (ps->fov > 90)
- return;
-
- memset (&gun, 0, sizeof(gun));
-
- if (gun_model)
- gun.model = gun_model; // development tool
- else
- gun.model = cl.model_draw[ps->gunindex];
- if (!gun.model)
- return;
-
- // set up gun position
- for (i=0 ; i<3 ; i++)
- {
- gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i]
- + cl.lerpfrac * (ps->gunoffset[i] - ops->gunoffset[i]);
- gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->gunangles[i],
- ps->gunangles[i], cl.lerpfrac);
- }
-
- if (gun_frame)
- {
- gun.frame = gun_frame; // development tool
- gun.oldframe = gun_frame; // development tool
- }
- else
- {
- gun.frame = ps->gunframe;
- if (gun.frame == 0)
- gun.oldframe = 0; // just changed weapons, don't lerp from old
- else
- gun.oldframe = ops->gunframe;
- }
-
- gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
- gun.backlerp = 1.0 - cl.lerpfrac;
- VectorCopy (gun.origin, gun.oldorigin); // don't lerp at all
- V_AddEntity (&gun);
-}
-
-
-/*
-===============
-CL_CalcViewValues
-
-Sets cl.refdef view values
-===============
-*/
-void CL_CalcViewValues (void)
-{
- int i;
- float lerp, backlerp;
- frame_t *oldframe;
- player_state_t *ps, *ops;
-
- // find the previous frame to interpolate from
- ps = &cl.frame.playerstate;
- i = (cl.frame.serverframe - 1) & UPDATE_MASK;
- oldframe = &cl.frames[i];
- if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
- oldframe = &cl.frame; // previous frame was dropped or involid
- ops = &oldframe->playerstate;
-
- // see if the player entity was teleported this frame
- if ( fabs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256*8
- || abs(ops->pmove.origin[1] - ps->pmove.origin[1]) > 256*8
- || abs(ops->pmove.origin[2] - ps->pmove.origin[2]) > 256*8)
- ops = ps; // don't interpolate
-
- lerp = cl.lerpfrac;
-
- // calculate the origin
- if ((cl_predict->value) && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
- { // use predicted values
- unsigned delta;
-
- backlerp = 1.0 - lerp;
- for (i=0 ; i<3 ; i++)
- {
- cl.refdef.vieworg[i] = cl.predicted_origin[i] + ops->viewoffset[i]
- + cl.lerpfrac * (ps->viewoffset[i] - ops->viewoffset[i])
- - backlerp * cl.prediction_error[i];
- }
-
- // smooth out stair climbing
- delta = cls.realtime - cl.predicted_step_time;
- if (delta < 100)
- cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01;
- }
- else
- { // just use interpolated values
- for (i=0 ; i<3 ; i++)
- cl.refdef.vieworg[i] = ops->pmove.origin[i]*0.125 + ops->viewoffset[i]
- + lerp * (ps->pmove.origin[i]*0.125 + ps->viewoffset[i]
- - (ops->pmove.origin[i]*0.125 + ops->viewoffset[i]) );
- }
-
- // if not running a demo or on a locked frame, add the local angle movement
- if ( cl.frame.playerstate.pmove.pm_type < PM_DEAD )
- { // use predicted values
- for (i=0 ; i<3 ; i++)
- cl.refdef.viewangles[i] = cl.predicted_angles[i];
- }
- else
- { // just use interpolated values
- for (i=0 ; i<3 ; i++)
- cl.refdef.viewangles[i] = LerpAngle (ops->viewangles[i], ps->viewangles[i], lerp);
- }
-
- for (i=0 ; i<3 ; i++)
- cl.refdef.viewangles[i] += LerpAngle (ops->kick_angles[i], ps->kick_angles[i], lerp);
-
- AngleVectors (cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up);
-
- // interpolate field of view
- cl.refdef.fov_x = ops->fov + lerp * (ps->fov - ops->fov);
-
- // don't interpolate blend color
- for (i=0 ; i<4 ; i++)
- cl.refdef.blend[i] = ps->blend[i];
-
- // add the weapon
- CL_AddViewWeapon (ps, ops);
-}
-
-/*
-===============
-CL_AddEntities
-
-Emits all entities, particles, and lights to the refresh
-===============
-*/
-void CL_AddEntities (void)
-{
- if (cls.state != ca_active)
- return;
-
- if (cl.time > cl.frame.servertime)
- {
- if (cl_showclamp->value)
- Com_Printf ("high clamp %i\n", cl.time - cl.frame.servertime);
- cl.time = cl.frame.servertime;
- cl.lerpfrac = 1.0;
- }
- else if (cl.time < cl.frame.servertime - 100)
- {
- if (cl_showclamp->value)
- Com_Printf ("low clamp %i\n", cl.frame.servertime-100 - cl.time);
- cl.time = cl.frame.servertime - 100;
- cl.lerpfrac = 0;
- }
- else
- cl.lerpfrac = 1.0 - (cl.frame.servertime - cl.time) * 0.01;
-
- if (cl_timedemo->value)
- cl.lerpfrac = 1.0;
-
-// CL_AddPacketEntities (&cl.frame);
-// CL_AddTEnts ();
-// CL_AddParticles ();
-// CL_AddDLights ();
-// CL_AddLightStyles ();
-
- CL_CalcViewValues ();
- // PMM - moved this here so the heat beam has the right values for the vieworg, and can lock the beam to the gun
- CL_AddPacketEntities (&cl.frame);
-/*
- CL_AddProjectiles ();
-*/
- CL_AddTEnts ();
- CL_AddParticles ();
- CL_AddDLights ();
- CL_AddLightStyles ();
-}
-
-
-
-/*
-===============
-CL_GetEntitySoundOrigin
-
-Called to get the sound spatialization origin
-===============
-*/
-void CL_GetEntitySoundOrigin (int ent, vec3_t org)
-{
- centity_t *old;
-
- if (ent < 0 || ent >= MAX_EDICTS)
- Com_Error (ERR_DROP, "CL_GetEntitySoundOrigin: bad ent");
- old = &cl_entities[ent];
- VectorCopy (old->lerp_origin, org);
-
- // FIXME: bmodel issues...
-}
--- a/client/cl_fx.c
+++ /dev/null
@@ -1,2286 +1,0 @@
-// cl_fx.c -- entity effects parsing and management
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-void CL_LogoutEffect (vec3_t org, int type);
-void CL_ItemRespawnParticles (vec3_t org);
-
-static vec3_t avelocities [NUMVERTEXNORMALS];
-
-extern struct model_s *cl_mod_smoke;
-extern struct model_s *cl_mod_flash;
-
-/*
-==============================================================
-
-LIGHT STYLE MANAGEMENT
-
-==============================================================
-*/
-
-typedef struct
-{
- int length;
- float value[3];
- float map[MAX_QPATH];
-} clightstyle_t;
-
-clightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
-int lastofs;
-
-/*
-================
-CL_ClearLightStyles
-================
-*/
-void CL_ClearLightStyles (void)
-{
- memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
- lastofs = -1;
-}
-
-/*
-================
-CL_RunLightStyles
-================
-*/
-void CL_RunLightStyles (void)
-{
- int ofs;
- int i;
- clightstyle_t *ls;
-
- ofs = cl.time / 100;
- if (ofs == lastofs)
- return;
- lastofs = ofs;
-
- for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
- {
- if (!ls->length)
- {
- ls->value[0] = ls->value[1] = ls->value[2] = 1.0;
- continue;
- }
- if (ls->length == 1)
- ls->value[0] = ls->value[1] = ls->value[2] = ls->map[0];
- else
- ls->value[0] = ls->value[1] = ls->value[2] = ls->map[ofs%ls->length];
- }
-}
-
-
-void CL_SetLightstyle (int i)
-{
- char *s;
- int j, k;
-
- s = cl.configstrings[i+CS_LIGHTS];
-
- j = strlen (s);
- if (j >= MAX_QPATH)
- Com_Error (ERR_DROP, "svc_lightstyle length=%i", j);
-
- cl_lightstyle[i].length = j;
-
- for (k=0 ; k<j ; k++)
- cl_lightstyle[i].map[k] = (float)(s[k]-'a')/(float)('m'-'a');
-}
-
-/*
-================
-CL_AddLightStyles
-================
-*/
-void CL_AddLightStyles (void)
-{
- int i;
- clightstyle_t *ls;
-
- for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
- V_AddLightStyle (i, ls->value[0], ls->value[1], ls->value[2]);
-}
-
-/*
-==============================================================
-
-DLIGHT MANAGEMENT
-
-==============================================================
-*/
-
-cdlight_t cl_dlights[MAX_DLIGHTS];
-
-/*
-================
-CL_ClearDlights
-================
-*/
-void CL_ClearDlights (void)
-{
- memset (cl_dlights, 0, sizeof(cl_dlights));
-}
-
-/*
-===============
-CL_AllocDlight
-
-===============
-*/
-cdlight_t *CL_AllocDlight (int key)
-{
- int i;
- cdlight_t *dl;
-
-// first look for an exact key match
- if (key)
- {
- dl = cl_dlights;
- for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
- {
- if (dl->key == key)
- {
- memset (dl, 0, sizeof(*dl));
- dl->key = key;
- return dl;
- }
- }
- }
-
-// then look for anything else
- dl = cl_dlights;
- for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
- {
- if (dl->die < cl.time)
- {
- memset (dl, 0, sizeof(*dl));
- dl->key = key;
- return dl;
- }
- }
-
- dl = &cl_dlights[0];
- memset (dl, 0, sizeof(*dl));
- dl->key = key;
- return dl;
-}
-
-/*
-===============
-CL_NewDlight
-===============
-*/
-void CL_NewDlight (int key, float x, float y, float z, float radius, float time)
-{
- cdlight_t *dl;
-
- dl = CL_AllocDlight (key);
- dl->origin[0] = x;
- dl->origin[1] = y;
- dl->origin[2] = z;
- dl->radius = radius;
- dl->die = cl.time + time;
-}
-
-
-/*
-===============
-CL_RunDLights
-
-===============
-*/
-void CL_RunDLights (void)
-{
- int i;
- cdlight_t *dl;
-
- dl = cl_dlights;
- for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
- {
- if (!dl->radius)
- continue;
-
- if (dl->die < cl.time)
- {
- dl->radius = 0;
- return;
- }
- dl->radius -= cls.frametime*dl->decay;
- if (dl->radius < 0)
- dl->radius = 0;
- }
-}
-
-/*
-==============
-CL_ParseMuzzleFlash
-==============
-*/
-void CL_ParseMuzzleFlash (void)
-{
- vec3_t fv, rv;
- cdlight_t *dl;
- int i, weapon;
- centity_t *pl;
- int silenced;
- float volume;
- char soundname[64];
-
- i = MSG_ReadShort (&net_message);
- if (i < 1 || i >= MAX_EDICTS)
- Com_Error (ERR_DROP, "CL_ParseMuzzleFlash: bad entity");
-
- weapon = MSG_ReadByte (&net_message);
- silenced = weapon & MZ_SILENCED;
- weapon &= ~MZ_SILENCED;
-
- pl = &cl_entities[i];
-
- dl = CL_AllocDlight (i);
- VectorCopy (pl->current.origin, dl->origin);
- AngleVectors (pl->current.angles, fv, rv, NULL);
- VectorMA (dl->origin, 18, fv, dl->origin);
- VectorMA (dl->origin, 16, rv, dl->origin);
- if (silenced)
- dl->radius = 100 + (rand()&31);
- else
- dl->radius = 200 + (rand()&31);
- dl->minlight = 32;
- dl->die = cl.time; // + 0.1;
-
- if (silenced)
- volume = 0.2;
- else
- volume = 1;
-
- switch (weapon)
- {
- case MZ_BLASTER:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_BLUEHYPERBLASTER:
- dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_HYPERBLASTER:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_MACHINEGUN:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
- break;
- case MZ_SHOTGUN:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotgf1b.wav"), volume, ATTN_NORM, 0);
- S_StartSound (NULL, i, CHAN_AUTO, S_RegisterSound("weapons/shotgr1b.wav"), volume, ATTN_NORM, 0.1);
- break;
- case MZ_SSHOTGUN:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/sshotf1b.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_CHAINGUN1:
- dl->radius = 200 + (rand()&31);
- dl->color[0] = 1;dl->color[1] = 0.25;dl->color[2] = 0;
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
- break;
- case MZ_CHAINGUN2:
- dl->radius = 225 + (rand()&31);
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
- dl->die = cl.time + 0.1; // long delay
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.05);
- break;
- case MZ_CHAINGUN3:
- dl->radius = 250 + (rand()&31);
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- dl->die = cl.time + 0.1; // long delay
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.033);
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.066);
- break;
- case MZ_RAILGUN:
- dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/railgf1a.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_ROCKET:
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rocklf1a.wav"), volume, ATTN_NORM, 0);
- S_StartSound (NULL, i, CHAN_AUTO, S_RegisterSound("weapons/rocklr1b.wav"), volume, ATTN_NORM, 0.1);
- break;
- case MZ_GRENADE:
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0);
- S_StartSound (NULL, i, CHAN_AUTO, S_RegisterSound("weapons/grenlr1b.wav"), volume, ATTN_NORM, 0.1);
- break;
- case MZ_BFG:
- dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0);
- break;
-
- case MZ_LOGIN:
- dl->color[0] = 0;dl->color[1] = 1; dl->color[2] = 0;
- dl->die = cl.time + 1.0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
- CL_LogoutEffect (pl->current.origin, weapon);
- break;
- case MZ_LOGOUT:
- dl->color[0] = 1;dl->color[1] = 0; dl->color[2] = 0;
- dl->die = cl.time + 1.0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
- CL_LogoutEffect (pl->current.origin, weapon);
- break;
- case MZ_RESPAWN:
- dl->color[0] = 1;dl->color[1] = 1; dl->color[2] = 0;
- dl->die = cl.time + 1.0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
- CL_LogoutEffect (pl->current.origin, weapon);
- break;
- // RAFAEL
- case MZ_PHALANX:
- dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/plasshot.wav"), volume, ATTN_NORM, 0);
- break;
- // RAFAEL
- case MZ_IONRIPPER:
- dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0);
- break;
-
-// ======================
-// PGM
- case MZ_ETF_RIFLE:
- dl->color[0] = 0.9;dl->color[1] = 0.7;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_SHOTGUN2:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_HEATBEAM:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- dl->die = cl.time + 100;
-// S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_BLASTER2:
- dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
- // FIXME - different sound for blaster2 ??
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_TRACKER:
- // negative flashes handled the same in gl/soft until CL_AddDLights
- dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_NUKE1:
- dl->color[0] = 1;dl->color[1] = 0;dl->color[2] = 0;
- dl->die = cl.time + 100;
- break;
- case MZ_NUKE2:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- dl->die = cl.time + 100;
- break;
- case MZ_NUKE4:
- dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
- dl->die = cl.time + 100;
- break;
- case MZ_NUKE8:
- dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 1;
- dl->die = cl.time + 100;
- break;
-// PGM
-// ======================
- }
-}
-
-
-/*
-==============
-CL_ParseMuzzleFlash2
-==============
-*/
-void CL_ParseMuzzleFlash2 (void)
-{
- int ent;
- vec3_t origin;
- int flash_number;
- cdlight_t *dl;
- vec3_t forward, right;
- char soundname[64];
-
- ent = MSG_ReadShort (&net_message);
- if (ent < 1 || ent >= MAX_EDICTS)
- Com_Error (ERR_DROP, "CL_ParseMuzzleFlash2: bad entity");
-
- flash_number = MSG_ReadByte (&net_message);
-
- // locate the origin
- AngleVectors (cl_entities[ent].current.angles, forward, right, NULL);
- origin[0] = cl_entities[ent].current.origin[0] + forward[0] * monster_flash_offset[flash_number][0] + right[0] * monster_flash_offset[flash_number][1];
- origin[1] = cl_entities[ent].current.origin[1] + forward[1] * monster_flash_offset[flash_number][0] + right[1] * monster_flash_offset[flash_number][1];
- origin[2] = cl_entities[ent].current.origin[2] + forward[2] * monster_flash_offset[flash_number][0] + right[2] * monster_flash_offset[flash_number][1] + monster_flash_offset[flash_number][2];
-
- dl = CL_AllocDlight (ent);
- VectorCopy (origin, dl->origin);
- dl->radius = 200 + (rand()&31);
- dl->minlight = 32;
- dl->die = cl.time; // + 0.1;
-
- switch (flash_number)
- {
- case MZ2_INFANTRY_MACHINEGUN_1:
- case MZ2_INFANTRY_MACHINEGUN_2:
- case MZ2_INFANTRY_MACHINEGUN_3:
- case MZ2_INFANTRY_MACHINEGUN_4:
- case MZ2_INFANTRY_MACHINEGUN_5:
- case MZ2_INFANTRY_MACHINEGUN_6:
- case MZ2_INFANTRY_MACHINEGUN_7:
- case MZ2_INFANTRY_MACHINEGUN_8:
- case MZ2_INFANTRY_MACHINEGUN_9:
- case MZ2_INFANTRY_MACHINEGUN_10:
- case MZ2_INFANTRY_MACHINEGUN_11:
- case MZ2_INFANTRY_MACHINEGUN_12:
- case MZ2_INFANTRY_MACHINEGUN_13:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_SOLDIER_MACHINEGUN_1:
- case MZ2_SOLDIER_MACHINEGUN_2:
- case MZ2_SOLDIER_MACHINEGUN_3:
- case MZ2_SOLDIER_MACHINEGUN_4:
- case MZ2_SOLDIER_MACHINEGUN_5:
- case MZ2_SOLDIER_MACHINEGUN_6:
- case MZ2_SOLDIER_MACHINEGUN_7:
- case MZ2_SOLDIER_MACHINEGUN_8:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_GUNNER_MACHINEGUN_1:
- case MZ2_GUNNER_MACHINEGUN_2:
- case MZ2_GUNNER_MACHINEGUN_3:
- case MZ2_GUNNER_MACHINEGUN_4:
- case MZ2_GUNNER_MACHINEGUN_5:
- case MZ2_GUNNER_MACHINEGUN_6:
- case MZ2_GUNNER_MACHINEGUN_7:
- case MZ2_GUNNER_MACHINEGUN_8:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_ACTOR_MACHINEGUN_1:
- case MZ2_SUPERTANK_MACHINEGUN_1:
- case MZ2_SUPERTANK_MACHINEGUN_2:
- case MZ2_SUPERTANK_MACHINEGUN_3:
- case MZ2_SUPERTANK_MACHINEGUN_4:
- case MZ2_SUPERTANK_MACHINEGUN_5:
- case MZ2_SUPERTANK_MACHINEGUN_6:
- case MZ2_TURRET_MACHINEGUN: // PGM
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_BOSS2_MACHINEGUN_L1:
- case MZ2_BOSS2_MACHINEGUN_L2:
- case MZ2_BOSS2_MACHINEGUN_L3:
- case MZ2_BOSS2_MACHINEGUN_L4:
- case MZ2_BOSS2_MACHINEGUN_L5:
- case MZ2_CARRIER_MACHINEGUN_L1: // PMM
- case MZ2_CARRIER_MACHINEGUN_L2: // PMM
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0);
- break;
-
- case MZ2_SOLDIER_BLASTER_1:
- case MZ2_SOLDIER_BLASTER_2:
- case MZ2_SOLDIER_BLASTER_3:
- case MZ2_SOLDIER_BLASTER_4:
- case MZ2_SOLDIER_BLASTER_5:
- case MZ2_SOLDIER_BLASTER_6:
- case MZ2_SOLDIER_BLASTER_7:
- case MZ2_SOLDIER_BLASTER_8:
- case MZ2_TURRET_BLASTER: // PGM
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck2.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_FLYER_BLASTER_1:
- case MZ2_FLYER_BLASTER_2:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("flyer/flyatck3.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_MEDIC_BLASTER_1:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("medic/medatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_HOVER_BLASTER_1:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("hover/hovatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_FLOAT_BLASTER_1:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("floater/fltatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_SOLDIER_SHOTGUN_1:
- case MZ2_SOLDIER_SHOTGUN_2:
- case MZ2_SOLDIER_SHOTGUN_3:
- case MZ2_SOLDIER_SHOTGUN_4:
- case MZ2_SOLDIER_SHOTGUN_5:
- case MZ2_SOLDIER_SHOTGUN_6:
- case MZ2_SOLDIER_SHOTGUN_7:
- case MZ2_SOLDIER_SHOTGUN_8:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_TANK_BLASTER_1:
- case MZ2_TANK_BLASTER_2:
- case MZ2_TANK_BLASTER_3:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_TANK_MACHINEGUN_1:
- case MZ2_TANK_MACHINEGUN_2:
- case MZ2_TANK_MACHINEGUN_3:
- case MZ2_TANK_MACHINEGUN_4:
- case MZ2_TANK_MACHINEGUN_5:
- case MZ2_TANK_MACHINEGUN_6:
- case MZ2_TANK_MACHINEGUN_7:
- case MZ2_TANK_MACHINEGUN_8:
- case MZ2_TANK_MACHINEGUN_9:
- case MZ2_TANK_MACHINEGUN_10:
- case MZ2_TANK_MACHINEGUN_11:
- case MZ2_TANK_MACHINEGUN_12:
- case MZ2_TANK_MACHINEGUN_13:
- case MZ2_TANK_MACHINEGUN_14:
- case MZ2_TANK_MACHINEGUN_15:
- case MZ2_TANK_MACHINEGUN_16:
- case MZ2_TANK_MACHINEGUN_17:
- case MZ2_TANK_MACHINEGUN_18:
- case MZ2_TANK_MACHINEGUN_19:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- Com_sprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + rand() % 5);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound(soundname), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_CHICK_ROCKET_1:
- case MZ2_TURRET_ROCKET: // PGM
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("chick/chkatck2.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_TANK_ROCKET_1:
- case MZ2_TANK_ROCKET_2:
- case MZ2_TANK_ROCKET_3:
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_SUPERTANK_ROCKET_1:
- case MZ2_SUPERTANK_ROCKET_2:
- case MZ2_SUPERTANK_ROCKET_3:
- case MZ2_BOSS2_ROCKET_1:
- case MZ2_BOSS2_ROCKET_2:
- case MZ2_BOSS2_ROCKET_3:
- case MZ2_BOSS2_ROCKET_4:
- case MZ2_CARRIER_ROCKET_1:
-// case MZ2_CARRIER_ROCKET_2:
-// case MZ2_CARRIER_ROCKET_3:
-// case MZ2_CARRIER_ROCKET_4:
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/rocket.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_GUNNER_GRENADE_1:
- case MZ2_GUNNER_GRENADE_2:
- case MZ2_GUNNER_GRENADE_3:
- case MZ2_GUNNER_GRENADE_4:
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck3.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_GLADIATOR_RAILGUN_1:
- // PMM
- case MZ2_CARRIER_RAILGUN:
- case MZ2_WIDOW_RAIL:
- // pmm
- dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
- break;
-
-// --- Xian's shit starts ---
- case MZ2_MAKRON_BFG:
- dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
- //S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_MAKRON_BLASTER_1:
- case MZ2_MAKRON_BLASTER_2:
- case MZ2_MAKRON_BLASTER_3:
- case MZ2_MAKRON_BLASTER_4:
- case MZ2_MAKRON_BLASTER_5:
- case MZ2_MAKRON_BLASTER_6:
- case MZ2_MAKRON_BLASTER_7:
- case MZ2_MAKRON_BLASTER_8:
- case MZ2_MAKRON_BLASTER_9:
- case MZ2_MAKRON_BLASTER_10:
- case MZ2_MAKRON_BLASTER_11:
- case MZ2_MAKRON_BLASTER_12:
- case MZ2_MAKRON_BLASTER_13:
- case MZ2_MAKRON_BLASTER_14:
- case MZ2_MAKRON_BLASTER_15:
- case MZ2_MAKRON_BLASTER_16:
- case MZ2_MAKRON_BLASTER_17:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/blaster.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_JORG_MACHINEGUN_L1:
- case MZ2_JORG_MACHINEGUN_L2:
- case MZ2_JORG_MACHINEGUN_L3:
- case MZ2_JORG_MACHINEGUN_L4:
- case MZ2_JORG_MACHINEGUN_L5:
- case MZ2_JORG_MACHINEGUN_L6:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("boss3/xfire.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_JORG_MACHINEGUN_R1:
- case MZ2_JORG_MACHINEGUN_R2:
- case MZ2_JORG_MACHINEGUN_R3:
- case MZ2_JORG_MACHINEGUN_R4:
- case MZ2_JORG_MACHINEGUN_R5:
- case MZ2_JORG_MACHINEGUN_R6:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- break;
-
- case MZ2_JORG_BFG_1:
- dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
- break;
-
- case MZ2_BOSS2_MACHINEGUN_R1:
- case MZ2_BOSS2_MACHINEGUN_R2:
- case MZ2_BOSS2_MACHINEGUN_R3:
- case MZ2_BOSS2_MACHINEGUN_R4:
- case MZ2_BOSS2_MACHINEGUN_R5:
- case MZ2_CARRIER_MACHINEGUN_R1: // PMM
- case MZ2_CARRIER_MACHINEGUN_R2: // PMM
-
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- break;
-
-// ======
-// ROGUE
- case MZ2_STALKER_BLASTER:
- case MZ2_DAEDALUS_BLASTER:
- case MZ2_MEDIC_BLASTER_2:
- case MZ2_WIDOW_BLASTER:
- case MZ2_WIDOW_BLASTER_SWEEP1:
- case MZ2_WIDOW_BLASTER_SWEEP2:
- case MZ2_WIDOW_BLASTER_SWEEP3:
- case MZ2_WIDOW_BLASTER_SWEEP4:
- case MZ2_WIDOW_BLASTER_SWEEP5:
- case MZ2_WIDOW_BLASTER_SWEEP6:
- case MZ2_WIDOW_BLASTER_SWEEP7:
- case MZ2_WIDOW_BLASTER_SWEEP8:
- case MZ2_WIDOW_BLASTER_SWEEP9:
- case MZ2_WIDOW_BLASTER_100:
- case MZ2_WIDOW_BLASTER_90:
- case MZ2_WIDOW_BLASTER_80:
- case MZ2_WIDOW_BLASTER_70:
- case MZ2_WIDOW_BLASTER_60:
- case MZ2_WIDOW_BLASTER_50:
- case MZ2_WIDOW_BLASTER_40:
- case MZ2_WIDOW_BLASTER_30:
- case MZ2_WIDOW_BLASTER_20:
- case MZ2_WIDOW_BLASTER_10:
- case MZ2_WIDOW_BLASTER_0:
- case MZ2_WIDOW_BLASTER_10L:
- case MZ2_WIDOW_BLASTER_20L:
- case MZ2_WIDOW_BLASTER_30L:
- case MZ2_WIDOW_BLASTER_40L:
- case MZ2_WIDOW_BLASTER_50L:
- case MZ2_WIDOW_BLASTER_60L:
- case MZ2_WIDOW_BLASTER_70L:
- case MZ2_WIDOW_RUN_1:
- case MZ2_WIDOW_RUN_2:
- case MZ2_WIDOW_RUN_3:
- case MZ2_WIDOW_RUN_4:
- case MZ2_WIDOW_RUN_5:
- case MZ2_WIDOW_RUN_6:
- case MZ2_WIDOW_RUN_7:
- case MZ2_WIDOW_RUN_8:
- dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_WIDOW_DISRUPTOR:
- dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_WIDOW_PLASMABEAM:
- case MZ2_WIDOW2_BEAMER_1:
- case MZ2_WIDOW2_BEAMER_2:
- case MZ2_WIDOW2_BEAMER_3:
- case MZ2_WIDOW2_BEAMER_4:
- case MZ2_WIDOW2_BEAMER_5:
- case MZ2_WIDOW2_BEAM_SWEEP_1:
- case MZ2_WIDOW2_BEAM_SWEEP_2:
- case MZ2_WIDOW2_BEAM_SWEEP_3:
- case MZ2_WIDOW2_BEAM_SWEEP_4:
- case MZ2_WIDOW2_BEAM_SWEEP_5:
- case MZ2_WIDOW2_BEAM_SWEEP_6:
- case MZ2_WIDOW2_BEAM_SWEEP_7:
- case MZ2_WIDOW2_BEAM_SWEEP_8:
- case MZ2_WIDOW2_BEAM_SWEEP_9:
- case MZ2_WIDOW2_BEAM_SWEEP_10:
- case MZ2_WIDOW2_BEAM_SWEEP_11:
- dl->radius = 300 + (rand()&100);
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- dl->die = cl.time + 200;
- break;
-// ROGUE
-// ======
-
-// --- Xian's shit ends ---
-
- }
-}
-
-
-/*
-===============
-CL_AddDLights
-
-===============
-*/
-void CL_AddDLights (void)
-{
- int i;
- cdlight_t *dl;
-
- dl = cl_dlights;
-
-//=====
-//PGM
- if(vidref_val == VIDREF_GL)
- {
- for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
- {
- if (!dl->radius)
- continue;
- V_AddLight (dl->origin, dl->radius,
- dl->color[0], dl->color[1], dl->color[2]);
- }
- }
- else
- {
- for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
- {
- if (!dl->radius)
- continue;
-
- // negative light in software. only black allowed
- if ((dl->color[0] < 0) || (dl->color[1] < 0) || (dl->color[2] < 0))
- {
- dl->radius = -(dl->radius);
- dl->color[0] = 1;
- dl->color[1] = 1;
- dl->color[2] = 1;
- }
- V_AddLight (dl->origin, dl->radius,
- dl->color[0], dl->color[1], dl->color[2]);
- }
- }
-//PGM
-//=====
-}
-
-
-
-/*
-==============================================================
-
-PARTICLE MANAGEMENT
-
-==============================================================
-*/
-
-/*
-// THIS HAS BEEN RELOCATED TO CLIENT.H
-typedef struct particle_s
-{
- struct particle_s *next;
-
- float time;
-
- vec3_t org;
- vec3_t vel;
- vec3_t accel;
- float color;
- float colorvel;
- float alpha;
- float alphavel;
-} cparticle_t;
-
-
-#define PARTICLE_GRAVITY 40
-*/
-
-cparticle_t *active_particles, *free_particles;
-
-cparticle_t particles[MAX_PARTICLES];
-int cl_numparticles = MAX_PARTICLES;
-
-
-/*
-===============
-CL_ClearParticles
-===============
-*/
-void CL_ClearParticles (void)
-{
- int i;
-
- free_particles = &particles[0];
- active_particles = NULL;
-
- for (i=0 ;i<cl_numparticles ; i++)
- particles[i].next = &particles[i+1];
- particles[cl_numparticles-1].next = NULL;
-}
-
-
-/*
-===============
-CL_ParticleEffect
-
-Wall impact puffs
-===============
-*/
-void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count)
-{
- int i, j;
- cparticle_t *p;
- float d;
-
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color + (rand()&7);
-
- d = rand()&31;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
- p->vel[j] = crand()*20;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_ParticleEffect2
-===============
-*/
-void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count)
-{
- int i, j;
- cparticle_t *p;
- float d;
-
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color;
-
- d = rand()&7;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
- p->vel[j] = crand()*20;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-
-// RAFAEL
-/*
-===============
-CL_ParticleEffect3
-===============
-*/
-void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count)
-{
- int i, j;
- cparticle_t *p;
- float d;
-
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color;
-
- d = rand()&7;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
- p->vel[j] = crand()*20;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-/*
-===============
-CL_TeleporterParticles
-===============
-*/
-void CL_TeleporterParticles (entity_state_t *ent)
-{
- int i, j;
- cparticle_t *p;
-
- for (i=0 ; i<8 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = 0xdb;
-
- for (j=0 ; j<2 ; j++)
- {
- p->org[j] = ent->origin[j] - 16 + (rand()&31);
- p->vel[j] = crand()*14;
- }
-
- p->org[2] = ent->origin[2] - 8 + (rand()&7);
- p->vel[2] = 80 + (rand()&7);
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -0.5;
- }
-}
-
-
-/*
-===============
-CL_LogoutEffect
-
-===============
-*/
-void CL_LogoutEffect (vec3_t org, int type)
-{
- int i, j;
- cparticle_t *p;
-
- for (i=0 ; i<500 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
-
- if (type == MZ_LOGIN)
- p->color = 0xd0 + (rand()&7); // green
- else if (type == MZ_LOGOUT)
- p->color = 0x40 + (rand()&7); // red
- else
- p->color = 0xe0 + (rand()&7); // yellow
-
- p->org[0] = org[0] - 16 + qfrand()*32;
- p->org[1] = org[1] - 16 + qfrand()*32;
- p->org[2] = org[2] - 24 + qfrand()*56;
-
- for (j=0 ; j<3 ; j++)
- p->vel[j] = crand()*20;
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (1.0 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_ItemRespawnParticles
-
-===============
-*/
-void CL_ItemRespawnParticles (vec3_t org)
-{
- int i, j;
- cparticle_t *p;
-
- for (i=0 ; i<64 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
-
- p->color = 0xd4 + (rand()&3); // green
-
- p->org[0] = org[0] + crand()*8;
- p->org[1] = org[1] + crand()*8;
- p->org[2] = org[2] + crand()*8;
-
- for (j=0 ; j<3 ; j++)
- p->vel[j] = crand()*8;
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY*0.2;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (1.0 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_ExplosionParticles
-===============
-*/
-void CL_ExplosionParticles (vec3_t org)
-{
- int i, j;
- cparticle_t *p;
-
- for (i=0 ; i<256 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = 0xe0 + (rand()&7);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()%32)-16);
- p->vel[j] = (rand()%384)-192;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_BigTeleportParticles
-===============
-*/
-void CL_BigTeleportParticles (vec3_t org)
-{
- int i;
- cparticle_t *p;
- float angle, dist;
- static int colortable[4] = {2*8,13*8,21*8,18*8};
-
- for (i=0 ; i<4096 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
-
- p->color = colortable[rand()&3];
-
- angle = M_PI*2*(rand()&1023)/1023.0;
- dist = rand()&31;
- p->org[0] = org[0] + cos(angle)*dist;
- p->vel[0] = cos(angle)*(70+(rand()&63));
- p->accel[0] = -cos(angle)*100;
-
- p->org[1] = org[1] + sin(angle)*dist;
- p->vel[1] = sin(angle)*(70+(rand()&63));
- p->accel[1] = -sin(angle)*100;
-
- p->org[2] = org[2] + 8 + (rand()%90);
- p->vel[2] = -100 + (rand()&31);
- p->accel[2] = PARTICLE_GRAVITY*4;
- p->alpha = 1.0;
-
- p->alphavel = -0.3 / (0.5 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_BlasterParticles
-
-Wall impact puffs
-===============
-*/
-void CL_BlasterParticles (vec3_t org, vec3_t dir)
-{
- int i, j;
- cparticle_t *p;
- float d;
- int count;
-
- count = 40;
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = 0xe0 + (rand()&7);
-
- d = rand()&15;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
- p->vel[j] = dir[j] * 30 + crand()*40;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_BlasterTrail
-
-===============
-*/
-void CL_BlasterTrail (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- int dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- // FIXME: this is a really silly way to have a loop
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.3+qfrand()*0.2);
- p->color = 0xe0;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand();
- p->vel[j] = crand()*5;
- p->accel[j] = 0;
- }
-
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-===============
-CL_QuadTrail
-
-===============
-*/
-void CL_QuadTrail (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- int dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.8+qfrand()*0.2);
- p->color = 115;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*16;
- p->vel[j] = crand()*5;
- p->accel[j] = 0;
- }
-
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-===============
-CL_FlagTrail
-
-===============
-*/
-void CL_FlagTrail (vec3_t start, vec3_t end, float color)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- int dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.8+qfrand()*0.2);
- p->color = color;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*16;
- p->vel[j] = crand()*5;
- p->accel[j] = 0;
- }
-
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-===============
-CL_DiminishingTrail
-
-===============
-*/
-void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- float dec;
- float orgscale;
- float velscale;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 0.5;
- VectorScale (vec, dec, vec);
-
- if (old->trailcount > 900)
- {
- orgscale = 4;
- velscale = 15;
- }
- else if (old->trailcount > 800)
- {
- orgscale = 2;
- velscale = 10;
- }
- else
- {
- orgscale = 1;
- velscale = 5;
- }
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
-
- // drop less particles as it flies
- if ((rand()&1023) < old->trailcount)
- {
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- if (flags & EF_GIB)
- {
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.4);
- p->color = 0xe8 + (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*orgscale;
- p->vel[j] = crand()*velscale;
- p->accel[j] = 0;
- }
- p->vel[2] -= PARTICLE_GRAVITY;
- }
- else if (flags & EF_GREENGIB)
- {
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.4);
- p->color = 0xdb + (rand()&7);
- for (j=0; j< 3; j++)
- {
- p->org[j] = move[j] + crand()*orgscale;
- p->vel[j] = crand()*velscale;
- p->accel[j] = 0;
- }
- p->vel[2] -= PARTICLE_GRAVITY;
- }
- else
- {
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->color = 4 + (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*orgscale;
- p->vel[j] = crand()*velscale;
- }
- p->accel[2] = 20;
- }
- }
-
- old->trailcount -= 5;
- if (old->trailcount < 100)
- old->trailcount = 100;
- VectorAdd (move, vec, move);
- }
-}
-
-void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up)
-{
- float d;
-
- // this rotate and negat guarantees a vector
- // not colinear with the original
- right[1] = -forward[0];
- right[2] = forward[1];
- right[0] = forward[2];
-
- d = DotProduct (right, forward);
- VectorMA (right, -d, forward, right);
- VectorNormalize (right);
- CrossProduct (right, forward, up);
-}
-
-/*
-===============
-CL_RocketTrail
-
-===============
-*/
-void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- float dec;
-
- // smoke
- CL_DiminishingTrail (start, end, old, EF_ROCKET);
-
- // fire
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 1;
- VectorScale (vec, dec, vec);
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
-
- if ( (rand()&7) == 0)
- {
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- VectorClear (p->accel);
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->color = 0xdc + (rand()&3);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*5;
- p->vel[j] = crand()*20;
- }
- p->accel[2] = -PARTICLE_GRAVITY;
- }
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-===============
-CL_RailTrail
-
-===============
-*/
-void CL_RailTrail (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- float dec;
- vec3_t right, up;
- int i;
- float d, c, s;
- vec3_t dir;
- byte clr = 0x74;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- MakeNormalVectors (vec, right, up);
-
- for (i=0 ; i<len ; i++)
- {
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
-
- d = i * 0.1;
- c = cos(d);
- s = sin(d);
-
- VectorScale (right, c, dir);
- VectorMA (dir, s, up, dir);
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->color = clr + (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + dir[j]*3;
- p->vel[j] = dir[j]*6;
- }
-
- VectorAdd (move, vec, move);
- }
-
- dec = 0.75;
- VectorScale (vec, dec, vec);
- VectorCopy (start, move);
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.6+qfrand()*0.2);
- p->color = 0x0 + rand()&15;
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*3;
- p->vel[j] = crand()*3;
- p->accel[j] = 0;
- }
-
- VectorAdd (move, vec, move);
- }
-}
-
-// RAFAEL
-/*
-===============
-CL_IonripperTrail
-===============
-*/
-void CL_IonripperTrail (vec3_t start, vec3_t ent)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- int dec;
- int left = 0;
-
- VectorCopy (start, move);
- VectorSubtract (ent, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
- p->alpha = 0.5;
- p->alphavel = -1.0 / (0.3 + qfrand() * 0.2);
- p->color = 0xe4 + (rand()&3);
-
- for (j=0; j<3; j++)
- {
- p->org[j] = move[j];
- p->accel[j] = 0;
- }
- if (left)
- {
- left = 0;
- p->vel[0] = 10;
- }
- else
- {
- left = 1;
- p->vel[0] = -10;
- }
-
- p->vel[1] = 0;
- p->vel[2] = 0;
-
- VectorAdd (move, vec, move);
- }
-}
-
-
-/*
-===============
-CL_BubbleTrail
-
-===============
-*/
-void CL_BubbleTrail (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int i, j;
- cparticle_t *p;
- float dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 32;
- VectorScale (vec, dec, vec);
-
- for (i=0 ; i<len ; i+=dec)
- {
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- VectorClear (p->accel);
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->color = 4 + (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*2;
- p->vel[j] = crand()*5;
- }
- p->vel[2] += 6;
-
- VectorAdd (move, vec, move);
- }
-}
-
-
-/*
-===============
-CL_FlyParticles
-===============
-*/
-
-#define BEAMLENGTH 16
-
-void CL_FlyParticles (vec3_t origin, int count)
-{
- int i;
- cparticle_t *p;
- float angle;
- float sp, sy, cp, cy;
- vec3_t forward;
- float dist;
- float ltime;
-
-
- if (count > NUMVERTEXNORMALS)
- count = NUMVERTEXNORMALS;
-
- if (!avelocities[0][0])
- {
- for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
- avelocities[0][i] = (rand()&255) * 0.01;
- }
-
-
- ltime = (float)cl.time / 1000.0;
- for (i=0 ; i<count ; i+=2)
- {
- angle = ltime * avelocities[i][0];
- sy = sin(angle);
- cy = cos(angle);
- angle = ltime * avelocities[i][1];
- sp = sin(angle);
- cp = cos(angle);
- /*
- angle = ltime * avelocities[i][2];
- sr = sin(angle);
- cr = cos(angle);
- */
-
- forward[0] = cp*cy;
- forward[1] = cp*sy;
- forward[2] = -sp;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
-
- dist = sin(ltime + i)*64;
- p->org[0] = origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
- p->org[1] = origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
- p->org[2] = origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
-
- VectorClear (p->vel);
- VectorClear (p->accel);
-
- p->color = 0;
- p->colorvel = 0;
-
- p->alpha = 1;
- p->alphavel = -100;
- }
-}
-
-void CL_FlyEffect (centity_t *ent, vec3_t origin)
-{
- int n;
- int count;
- int starttime;
-
- if (ent->fly_stoptime < cl.time)
- {
- starttime = cl.time;
- ent->fly_stoptime = cl.time + 60000;
- }
- else
- {
- starttime = ent->fly_stoptime - 60000;
- }
-
- n = cl.time - starttime;
- if (n < 20000)
- count = n * 162 / 20000.0;
- else
- {
- n = ent->fly_stoptime - cl.time;
- if (n < 20000)
- count = n * 162 / 20000.0;
- else
- count = 162;
- }
-
- CL_FlyParticles (origin, count);
-}
-
-
-/*
-===============
-CL_BfgParticles
-===============
-*/
-
-void CL_BfgParticles (entity_t *ent)
-{
- int i;
- cparticle_t *p;
- float angle;
- float sp, sy, cp, cy;
- vec3_t forward;
- float dist;
- vec3_t v;
- float ltime;
-
- if (!avelocities[0][0])
- {
- for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
- avelocities[0][i] = (rand()&255) * 0.01;
- }
-
-
- ltime = (float)cl.time / 1000.0;
- for (i=0 ; i<NUMVERTEXNORMALS ; i++)
- {
- angle = ltime * avelocities[i][0];
- sy = sin(angle);
- cy = cos(angle);
- angle = ltime * avelocities[i][1];
- sp = sin(angle);
- cp = cos(angle);
- /*
- angle = ltime * avelocities[i][2];
- sr = sin(angle);
- cr = cos(angle);
- */
-
- forward[0] = cp*cy;
- forward[1] = cp*sy;
- forward[2] = -sp;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
-
- dist = sin(ltime + i)*64;
- p->org[0] = ent->origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
- p->org[1] = ent->origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
- p->org[2] = ent->origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
-
- VectorClear (p->vel);
- VectorClear (p->accel);
-
- VectorSubtract (p->org, ent->origin, v);
- dist = VectorLength(v) / 90.0;
- p->color = floor (0xd0 + dist * 7);
- p->colorvel = 0;
-
- p->alpha = 1.0 - dist;
- p->alphavel = -100;
- }
-}
-
-
-/*
-===============
-CL_TrapParticles
-===============
-*/
-// RAFAEL
-void CL_TrapParticles (entity_t *ent)
-{
- vec3_t move;
- vec3_t vec;
- vec3_t start, end;
- float len;
- int j;
- cparticle_t *p;
- int dec;
-
- ent->origin[2]-=14;
- VectorCopy (ent->origin, start);
- VectorCopy (ent->origin, end);
- end[2]+=64;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- // FIXME: this is a really silly way to have a loop
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.3+qfrand()*0.2);
- p->color = 0xe0;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand();
- p->vel[j] = crand()*15;
- p->accel[j] = 0;
- }
- p->accel[2] = PARTICLE_GRAVITY;
-
- VectorAdd (move, vec, move);
- }
-
- {
-
-
- int i, j, k;
- cparticle_t *p;
- float vel;
- vec3_t dir;
- vec3_t org;
-
-
- ent->origin[2]+=14;
- VectorCopy (ent->origin, org);
-
-
- for (i=-2 ; i<=2 ; i+=4)
- for (j=-2 ; j<=2 ; j+=4)
- for (k=-2 ; k<=4 ; k+=4)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = 0xe0 + (rand()&3);
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
-
- p->org[0] = org[0] + i + ((rand()&23) * crand());
- p->org[1] = org[1] + j + ((rand()&23) * crand());
- p->org[2] = org[2] + k + ((rand()&23) * crand());
-
- dir[0] = j * 8;
- dir[1] = i * 8;
- dir[2] = k * 8;
-
- VectorNormalize (dir);
- vel = 50 + rand()&63;
- VectorScale (dir, vel, p->vel);
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- }
- }
-}
-
-
-/*
-===============
-CL_BFGExplosionParticles
-===============
-*/
-//FIXME combined with CL_ExplosionParticles
-void CL_BFGExplosionParticles (vec3_t org)
-{
- int i, j;
- cparticle_t *p;
-
- for (i=0 ; i<256 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = 0xd0 + (rand()&7);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()%32)-16);
- p->vel[j] = (rand()%384)-192;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_TeleportParticles
-
-===============
-*/
-void CL_TeleportParticles (vec3_t org)
-{
- int i, j, k;
- cparticle_t *p;
- float vel;
- vec3_t dir;
-
- for (i=-16 ; i<=16 ; i+=4)
- for (j=-16 ; j<=16 ; j+=4)
- for (k=-16 ; k<=32 ; k+=4)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = 7 + (rand()&7);
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
-
- p->org[0] = org[0] + i + (rand()&3);
- p->org[1] = org[1] + j + (rand()&3);
- p->org[2] = org[2] + k + (rand()&3);
-
- dir[0] = j*8;
- dir[1] = i*8;
- dir[2] = k*8;
-
- VectorNormalize (dir);
- vel = 50 + (rand()&63);
- VectorScale (dir, vel, p->vel);
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- }
-}
-
-
-/*
-===============
-CL_AddParticles
-===============
-*/
-void CL_AddParticles (void)
-{
- cparticle_t *p, *next;
- float alpha;
- float time = 0, time2;
- vec3_t org;
- int color;
- cparticle_t *active, *tail;
-
- active = NULL;
- tail = NULL;
-
- for (p=active_particles ; p ; p=next)
- {
- next = p->next;
-
- // PMM - added INSTANT_PARTICLE handling for heat beam
- if (p->alphavel != INSTANT_PARTICLE)
- {
- time = (cl.time - p->time)*0.001;
- alpha = p->alpha + time*p->alphavel;
- if (alpha <= 0)
- { // faded out
- p->next = free_particles;
- free_particles = p;
- continue;
- }
- }
- else
- {
- alpha = p->alpha;
- }
-
- p->next = NULL;
- if (!tail)
- active = tail = p;
- else
- {
- tail->next = p;
- tail = p;
- }
-
- if (alpha > 1.0)
- alpha = 1;
- color = p->color;
-
- time2 = time*time;
-
- org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
- org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
- org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
-
- V_AddParticle (org, color, alpha);
- // PMM
- if (p->alphavel == INSTANT_PARTICLE)
- {
- p->alphavel = 0.0;
- p->alpha = 0.0;
- }
- }
-
- active_particles = active;
-}
-
-
-/*
-==============
-CL_EntityEvent
-
-An entity has just been parsed that has an event value
-
-the female events are there for backwards compatability
-==============
-*/
-extern struct sfx_s *cl_sfx_footsteps[4];
-
-void CL_EntityEvent (entity_state_t *ent)
-{
- switch (ent->event)
- {
- case EV_ITEM_RESPAWN:
- S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("items/respawn1.wav"), 1, ATTN_IDLE, 0);
- CL_ItemRespawnParticles (ent->origin);
- break;
- case EV_PLAYER_TELEPORT:
- S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("misc/tele1.wav"), 1, ATTN_IDLE, 0);
- CL_TeleportParticles (ent->origin);
- break;
- case EV_FOOTSTEP:
- if (cl_footsteps->value)
- S_StartSound (NULL, ent->number, CHAN_BODY, cl_sfx_footsteps[rand()&3], 1, ATTN_NORM, 0);
- break;
- case EV_FALLSHORT:
- S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("player/land1.wav"), 1, ATTN_NORM, 0);
- break;
- case EV_FALL:
- S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall2.wav"), 1, ATTN_NORM, 0);
- break;
- case EV_FALLFAR:
- S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall1.wav"), 1, ATTN_NORM, 0);
- break;
- }
-}
-
-
-/*
-==============
-CL_ClearEffects
-
-==============
-*/
-void CL_ClearEffects (void)
-{
- CL_ClearParticles ();
- CL_ClearDlights ();
- CL_ClearLightStyles ();
-}
--- a/client/cl_input.c
+++ /dev/null
@@ -1,525 +1,0 @@
-// cl.input.c -- builds an intended movement command to send to the server
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-cvar_t *cl_nodelta;
-
-unsigned frame_msec;
-unsigned old_sys_frame_time;
-
-/*
-===============================================================================
-
-KEY BUTTONS
-
-Continuous button event tracking is complicated by the fact that two different
-input sources (say, mouse button 1 and the control key) can both press the
-same button, but the button should only be released when both of the
-pressing key have been released.
-
-When a key event issues a button command (+forward, +attack, etc), it appends
-its key number as a parameter to the command so it can be matched up with
-the release.
-
-state bit 0 is the current state of the key
-state bit 1 is edge triggered on the up to down transition
-state bit 2 is edge triggered on the down to up transition
-
-
-Key_Event (int key, qboolean down, unsigned time);
-
- +mlook src time
-
-===============================================================================
-*/
-
-
-kbutton_t in_klook;
-kbutton_t in_left, in_right, in_forward, in_back;
-kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
-kbutton_t in_strafe, in_speed, in_use, in_attack;
-kbutton_t in_up, in_down;
-
-int in_impulse;
-
-
-void KeyDown (kbutton_t *b)
-{
- int k;
- char *c;
-
- c = Cmd_Argv(1);
- if (c[0])
- k = atoi(c);
- else
- k = -1; // typed manually at the console for continuous down
-
- if (k == b->down[0] || k == b->down[1])
- return; // repeating key
-
- if (!b->down[0])
- b->down[0] = k;
- else if (!b->down[1])
- b->down[1] = k;
- else
- {
- Com_Printf ("Three keys down for a button!\n");
- return;
- }
-
- if (b->state & 1)
- return; // still down
-
- // save timestamp
- c = Cmd_Argv(2);
- b->downtime = atoi(c);
- if (!b->downtime)
- b->downtime = sys_frame_time - 100;
-
- b->state |= 1 + 2; // down + impulse down
-}
-
-void KeyUp (kbutton_t *b)
-{
- int k;
- char *c;
- unsigned uptime;
-
- c = Cmd_Argv(1);
- if (c[0])
- k = atoi(c);
- else
- { // typed manually at the console, assume for unsticking, so clear all
- b->down[0] = b->down[1] = 0;
- b->state = 4; // impulse up
- return;
- }
-
- if (b->down[0] == k)
- b->down[0] = 0;
- else if (b->down[1] == k)
- b->down[1] = 0;
- else
- return; // key up without coresponding down (menu pass through)
- if (b->down[0] || b->down[1])
- return; // some other key is still holding it down
-
- if (!(b->state & 1))
- return; // still up (this should not happen)
-
- // save timestamp
- c = Cmd_Argv(2);
- uptime = atoi(c);
- if (uptime)
- b->msec += uptime - b->downtime;
- else
- b->msec += 10;
-
- b->state &= ~1; // now up
- b->state |= 4; // impulse up
-}
-
-void IN_KLookDown (void) {KeyDown(&in_klook);}
-void IN_KLookUp (void) {KeyUp(&in_klook);}
-void IN_UpDown(void) {KeyDown(&in_up);}
-void IN_UpUp(void) {KeyUp(&in_up);}
-void IN_DownDown(void) {KeyDown(&in_down);}
-void IN_DownUp(void) {KeyUp(&in_down);}
-void IN_LeftDown(void) {KeyDown(&in_left);}
-void IN_LeftUp(void) {KeyUp(&in_left);}
-void IN_RightDown(void) {KeyDown(&in_right);}
-void IN_RightUp(void) {KeyUp(&in_right);}
-void IN_ForwardDown(void) {KeyDown(&in_forward);}
-void IN_ForwardUp(void) {KeyUp(&in_forward);}
-void IN_BackDown(void) {KeyDown(&in_back);}
-void IN_BackUp(void) {KeyUp(&in_back);}
-void IN_LookupDown(void) {KeyDown(&in_lookup);}
-void IN_LookupUp(void) {KeyUp(&in_lookup);}
-void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
-void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
-void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
-void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
-void IN_MoverightDown(void) {KeyDown(&in_moveright);}
-void IN_MoverightUp(void) {KeyUp(&in_moveright);}
-
-void IN_SpeedDown(void) {KeyDown(&in_speed);}
-void IN_SpeedUp(void) {KeyUp(&in_speed);}
-void IN_StrafeDown(void) {KeyDown(&in_strafe);}
-void IN_StrafeUp(void) {KeyUp(&in_strafe);}
-
-void IN_AttackDown(void) {KeyDown(&in_attack);}
-void IN_AttackUp(void) {KeyUp(&in_attack);}
-
-void IN_UseDown (void) {KeyDown(&in_use);}
-void IN_UseUp (void) {KeyUp(&in_use);}
-
-void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
-
-/*
-===============
-CL_KeyState
-
-Returns the fraction of the frame that the key was down
-===============
-*/
-float CL_KeyState (kbutton_t *key)
-{
- float val;
- int msec;
-
- key->state &= 1; // clear impulses
-
- msec = key->msec;
- key->msec = 0;
-
- if (key->state)
- { // still down
- msec += sys_frame_time - key->downtime;
- key->downtime = sys_frame_time;
- }
-
-/*
- if (msec)
- {
- Com_Printf ("%i ", msec);
- }
-*/
-
- val = (float)msec / frame_msec;
- if (val < 0)
- val = 0;
- if (val > 1)
- val = 1;
-
- return val;
-}
-
-
-
-
-//==========================================================================
-
-cvar_t *cl_upspeed;
-cvar_t *cl_forwardspeed;
-cvar_t *cl_sidespeed;
-
-cvar_t *cl_yawspeed;
-cvar_t *cl_pitchspeed;
-
-cvar_t *cl_run;
-
-cvar_t *cl_anglespeedkey;
-
-
-/*
-================
-CL_AdjustAngles
-
-Moves the local angle positions
-================
-*/
-void CL_AdjustAngles (void)
-{
- float speed;
- float up, down;
-
- if (in_speed.state & 1)
- speed = cls.frametime * cl_anglespeedkey->value;
- else
- speed = cls.frametime;
-
- if (!(in_strafe.state & 1))
- {
- cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
- cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
- }
- if (in_klook.state & 1)
- {
- cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward);
- cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back);
- }
-
- up = CL_KeyState (&in_lookup);
- down = CL_KeyState(&in_lookdown);
-
- cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * up;
- cl.viewangles[PITCH] += speed*cl_pitchspeed->value * down;
-}
-
-/*
-================
-CL_BaseMove
-
-Send the intended movement message to the server
-================
-*/
-void CL_BaseMove (usercmd_t *cmd)
-{
- CL_AdjustAngles ();
-
- memset (cmd, 0, sizeof(*cmd));
-
- VectorCopy (cl.viewangles, cmd->angles);
- if (in_strafe.state & 1)
- {
- cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right);
- cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left);
- }
-
- cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright);
- cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft);
-
- cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up);
- cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down);
-
- if (! (in_klook.state & 1) )
- {
- cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward);
- cmd->forwardmove -= cl_forwardspeed->value * CL_KeyState (&in_back);
- }
-
-//
-// adjust for speed key / running
-//
- if ( (in_speed.state & 1) ^ (int)(cl_run->value) )
- {
- cmd->forwardmove *= 2;
- cmd->sidemove *= 2;
- cmd->upmove *= 2;
- }
-}
-
-void CL_ClampPitch (void)
-{
- float pitch;
-
- pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
- if (pitch > 180)
- pitch -= 360;
- if (cl.viewangles[PITCH] + pitch > 89)
- cl.viewangles[PITCH] = 89 - pitch;
- if (cl.viewangles[PITCH] + pitch < -89)
- cl.viewangles[PITCH] = -89 - pitch;
-}
-
-/*
-==============
-CL_FinishMove
-==============
-*/
-void CL_FinishMove (usercmd_t *cmd)
-{
- int ms;
- int i;
-
-//
-// figure button bits
-//
- if ( in_attack.state & 3 )
- cmd->buttons |= BUTTON_ATTACK;
- in_attack.state &= ~2;
-
- if (in_use.state & 3)
- cmd->buttons |= BUTTON_USE;
- in_use.state &= ~2;
-
- if (anykeydown && cls.key_dest == key_game)
- cmd->buttons |= BUTTON_ANY;
-
- // send milliseconds of time to apply the move
- ms = cls.frametime * 1000;
- if (ms > 250)
- ms = 100; // time was unreasonable
- cmd->msec = ms;
-
- CL_ClampPitch ();
- for (i=0 ; i<3 ; i++)
- cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
-
- cmd->impulse = in_impulse;
- in_impulse = 0;
-
-// send the ambient light level at the player's current position
- cmd->lightlevel = (byte)cl_lightlevel->value;
-}
-
-/*
-=================
-CL_CreateCmd
-=================
-*/
-usercmd_t CL_CreateCmd (void)
-{
- usercmd_t cmd;
-
- frame_msec = sys_frame_time - old_sys_frame_time;
- if (frame_msec < 1)
- frame_msec = 1;
- if (frame_msec > 200)
- frame_msec = 200;
-
- // get basic movement from keyboard
- CL_BaseMove (&cmd);
-
- // allow mice or other external controllers to add to the move
- IN_Move (&cmd);
-
- CL_FinishMove (&cmd);
-
- old_sys_frame_time = sys_frame_time;
-
-//cmd.impulse = cls.framecount;
-
- return cmd;
-}
-
-
-void IN_CenterView (void)
-{
- cl.viewangles[PITCH] = -SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
-}
-
-/*
-============
-CL_InitInput
-============
-*/
-void CL_InitInput (void)
-{
- Cmd_AddCommand ("centerview",IN_CenterView);
-
- Cmd_AddCommand ("+moveup",IN_UpDown);
- Cmd_AddCommand ("-moveup",IN_UpUp);
- Cmd_AddCommand ("+movedown",IN_DownDown);
- Cmd_AddCommand ("-movedown",IN_DownUp);
- Cmd_AddCommand ("+left",IN_LeftDown);
- Cmd_AddCommand ("-left",IN_LeftUp);
- Cmd_AddCommand ("+right",IN_RightDown);
- Cmd_AddCommand ("-right",IN_RightUp);
- Cmd_AddCommand ("+forward",IN_ForwardDown);
- Cmd_AddCommand ("-forward",IN_ForwardUp);
- Cmd_AddCommand ("+back",IN_BackDown);
- Cmd_AddCommand ("-back",IN_BackUp);
- Cmd_AddCommand ("+lookup", IN_LookupDown);
- Cmd_AddCommand ("-lookup", IN_LookupUp);
- Cmd_AddCommand ("+lookdown", IN_LookdownDown);
- Cmd_AddCommand ("-lookdown", IN_LookdownUp);
- Cmd_AddCommand ("+strafe", IN_StrafeDown);
- Cmd_AddCommand ("-strafe", IN_StrafeUp);
- Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
- Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
- Cmd_AddCommand ("+moveright", IN_MoverightDown);
- Cmd_AddCommand ("-moveright", IN_MoverightUp);
- Cmd_AddCommand ("+speed", IN_SpeedDown);
- Cmd_AddCommand ("-speed", IN_SpeedUp);
- Cmd_AddCommand ("+attack", IN_AttackDown);
- Cmd_AddCommand ("-attack", IN_AttackUp);
- Cmd_AddCommand ("+use", IN_UseDown);
- Cmd_AddCommand ("-use", IN_UseUp);
- Cmd_AddCommand ("impulse", IN_Impulse);
- Cmd_AddCommand ("+klook", IN_KLookDown);
- Cmd_AddCommand ("-klook", IN_KLookUp);
-
- cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
-}
-
-
-
-/*
-=================
-CL_SendCmd
-=================
-*/
-void CL_SendCmd (void)
-{
- sizebuf_t buf;
- byte data[128];
- int i;
- usercmd_t *cmd, *oldcmd;
- usercmd_t nullcmd;
- int checksumIndex;
-
- // build a command even if not connected
-
- // save this command off for prediction
- i = cls.netchan.outgoing_sequence & (CMD_BACKUP-1);
- cmd = &cl.cmds[i];
- cl.cmd_time[i] = cls.realtime; // for netgraph ping calculation
-
- *cmd = CL_CreateCmd ();
-
- cl.cmd = *cmd;
-
- if (cls.state == ca_disconnected || cls.state == ca_connecting)
- return;
-
- if ( cls.state == ca_connected)
- {
- if (cls.netchan.message.cursize || curtime - cls.netchan.last_sent > 1000 )
- Netchan_Transmit (&cls.netchan, 0, buf.data);
- return;
- }
-
- // send a userinfo update if needed
- if (userinfo_modified)
- {
- CL_FixUpGender();
- userinfo_modified = false;
- MSG_WriteByte (&cls.netchan.message, clc_userinfo);
- MSG_WriteString (&cls.netchan.message, Cvar_Userinfo() );
- }
-
- SZ_Init (&buf, data, sizeof(data));
-
- if (cmd->buttons && cl.cinematictime > 0 && !cl.attractloop
- && cls.realtime - cl.cinematictime > 1000)
- { // skip the rest of the cinematic
- SCR_FinishCinematic ();
- }
-
- // begin a client move command
- MSG_WriteByte (&buf, clc_move);
-
- // save the position for a checksum byte
- checksumIndex = buf.cursize;
- MSG_WriteByte (&buf, 0);
-
- // let the server know what the last frame we
- // got was, so the next message can be delta compressed
- if (cl_nodelta->value || !cl.frame.valid || cls.demowaiting)
- MSG_WriteLong (&buf, -1); // no compression
- else
- MSG_WriteLong (&buf, cl.frame.serverframe);
-
- // send this and the previous cmds in the message, so
- // if the last packet was dropped, it can be recovered
- i = (cls.netchan.outgoing_sequence-2) & (CMD_BACKUP-1);
- cmd = &cl.cmds[i];
- memset (&nullcmd, 0, sizeof(nullcmd));
- MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd);
- oldcmd = cmd;
-
- i = (cls.netchan.outgoing_sequence-1) & (CMD_BACKUP-1);
- cmd = &cl.cmds[i];
- MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
- oldcmd = cmd;
-
- i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP-1);
- cmd = &cl.cmds[i];
- MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
-
- // calculate a checksum over the move commands
- buf.data[checksumIndex] = COM_BlockSequenceCRCByte(
- buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,
- cls.netchan.outgoing_sequence);
-
- //
- // deliver the message
- //
- Netchan_Transmit (&cls.netchan, buf.cursize, buf.data);
-}
-
-
--- a/client/cl_inv.c
+++ /dev/null
@@ -1,126 +1,0 @@
-// cl_inv.c -- client inventory screen
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-================
-CL_ParseInventory
-================
-*/
-void CL_ParseInventory (void)
-{
- int i;
-
- for (i=0 ; i<MAX_ITEMS ; i++)
- cl.inventory[i] = MSG_ReadShort (&net_message);
-}
-
-
-/*
-================
-Inv_DrawString
-================
-*/
-void Inv_DrawString (int x, int y, char *string)
-{
- while (*string)
- {
- re.DrawChar (x, y, *string);
- x+=8;
- string++;
- }
-}
-
-void SetStringHighBit (char *s)
-{
- while (*s)
- *s++ |= 128;
-}
-
-/*
-================
-CL_DrawInventory
-================
-*/
-#define DISPLAY_ITEMS 17
-
-void CL_DrawInventory (void)
-{
- int i, j;
- int num, selected_num, item;
- int index[MAX_ITEMS];
- char string[1024];
- int x, y;
- char binding[1024];
- char *bind;
- int selected;
- int top;
-
- selected = cl.frame.playerstate.stats[STAT_SELECTED_ITEM];
-
- num = 0;
- selected_num = 0;
- for (i=0 ; i<MAX_ITEMS ; i++)
- {
- if (i==selected)
- selected_num = num;
- if (cl.inventory[i])
- {
- index[num] = i;
- num++;
- }
- }
-
- // determine scroll point
- top = selected_num - DISPLAY_ITEMS/2;
- if (num - top < DISPLAY_ITEMS)
- top = num - DISPLAY_ITEMS;
- if (top < 0)
- top = 0;
-
- x = (vid.width-256)/2;
- y = (vid.height-240)/2;
-
- // repaint everything next frame
- SCR_DirtyScreen ();
-
- re.DrawPic (x, y+8, "inventory");
-
- y += 24;
- x += 24;
- Inv_DrawString (x, y, "hotkey ### item");
- Inv_DrawString (x, y+8, "------ --- ----");
- y += 16;
- for (i=top ; i<num && i < top+DISPLAY_ITEMS ; i++)
- {
- item = index[i];
- // search for a binding
- Com_sprintf (binding, sizeof(binding), "use %s", cl.configstrings[CS_ITEMS+item]);
- bind = "";
- for (j=0 ; j<256 ; j++)
- if (keybindings[j] && !cistrcmp (keybindings[j], binding))
- {
- bind = Key_KeynumToString(j);
- break;
- }
-
- Com_sprintf (string, sizeof(string), "%6s %3i %s", bind, cl.inventory[item],
- cl.configstrings[CS_ITEMS+item] );
- if (item != selected)
- SetStringHighBit (string);
- else // draw a blinky cursor by the selected item
- {
- if ( (int)(cls.realtime*10) & 1)
- re.DrawChar (x-8, y, 15);
- }
- Inv_DrawString (x, y, string);
- y += 8;
- }
-
-
-}
-
-
--- a/client/cl_main.c
+++ /dev/null
@@ -1,1790 +1,0 @@
-// cl_main.c -- client main loop
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-cvar_t *adr0;
-cvar_t *adr1;
-cvar_t *adr2;
-cvar_t *adr3;
-cvar_t *adr4;
-cvar_t *adr5;
-cvar_t *adr6;
-cvar_t *adr7;
-cvar_t *adr8;
-
-cvar_t *cl_stereo_separation;
-cvar_t *cl_stereo;
-
-cvar_t *rcon_client_password;
-cvar_t *rcon_address;
-
-cvar_t *cl_noskins;
-cvar_t *cl_autoskins;
-cvar_t *cl_footsteps;
-cvar_t *cl_timeout;
-cvar_t *cl_predict;
-//cvar_t *cl_minfps;
-cvar_t *cl_maxfps;
-cvar_t *cl_gun;
-
-cvar_t *cl_add_particles;
-cvar_t *cl_add_lights;
-cvar_t *cl_add_entities;
-cvar_t *cl_add_blend;
-
-cvar_t *cl_shownet;
-cvar_t *cl_showmiss;
-cvar_t *cl_showclamp;
-
-cvar_t *cl_paused;
-cvar_t *cl_timedemo;
-
-cvar_t *cl_lightlevel;
-
-//
-// userinfo
-//
-cvar_t *info_password;
-cvar_t *info_spectator;
-cvar_t *name;
-cvar_t *skin;
-cvar_t *rate;
-cvar_t *fov;
-cvar_t *msg;
-cvar_t *hand;
-cvar_t *gender;
-cvar_t *gender_auto;
-
-cvar_t *cl_vwep;
-
-client_static_t cls;
-client_state_t cl;
-
-centity_t cl_entities[MAX_EDICTS];
-
-entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
-
-extern cvar_t *allow_download;
-extern cvar_t *allow_download_players;
-extern cvar_t *allow_download_models;
-extern cvar_t *allow_download_sounds;
-extern cvar_t *allow_download_maps;
-
-//======================================================================
-
-
-/*
-====================
-CL_WriteDemoMessage
-
-Dumps the current net message, prefixed by the length
-====================
-*/
-void CL_WriteDemoMessage (void)
-{
- int len, swlen;
-
- // the first eight bytes are just packet sequencing stuff
- len = net_message.cursize-8;
- swlen = LittleLong(len);
- fwrite (&swlen, 4, 1, cls.demofile);
- fwrite (net_message.data+8, len, 1, cls.demofile);
-}
-
-
-/*
-====================
-CL_Stop_f
-
-stop recording a demo
-====================
-*/
-void CL_Stop_f (void)
-{
- int len;
-
- if (!cls.demorecording)
- {
- Com_Printf ("Not recording a demo.\n");
- return;
- }
-
-// finish up
- len = -1;
- fwrite (&len, 4, 1, cls.demofile);
- fclose (cls.demofile);
- cls.demofile = NULL;
- cls.demorecording = false;
- Com_Printf ("Stopped demo.\n");
-}
-
-/*
-====================
-CL_Record_f
-
-record <demoname>
-
-Begins recording a demo from the current position
-====================
-*/
-void CL_Record_f (void)
-{
- char name[MAX_OSPATH];
- char buf_data[MAX_MSGLEN];
- sizebuf_t buf;
- int i;
- int len;
- entity_state_t *ent;
- entity_state_t nullstate;
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("record <demoname>\n");
- return;
- }
-
- if (cls.demorecording)
- {
- Com_Printf ("Already recording.\n");
- return;
- }
-
- if (cls.state != ca_active)
- {
- Com_Printf ("You must be in a level to record.\n");
- return;
- }
-
- //
- // open the demo file
- //
- Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
-
- Com_Printf ("recording to %s.\n", name);
- FS_CreatePath (name);
- cls.demofile = fopen (name, "wb");
- if (!cls.demofile)
- {
- Com_Printf ("ERROR: couldn't open.\n");
- return;
- }
- cls.demorecording = true;
-
- // don't start saving messages until a non-delta compressed message is received
- cls.demowaiting = true;
-
- //
- // write out messages to hold the startup information
- //
- SZ_Init (&buf, (uchar *)buf_data, sizeof(buf_data));
-
- // send the serverdata
- MSG_WriteByte (&buf, svc_serverdata);
- MSG_WriteLong (&buf, PROTOCOL_VERSION);
- MSG_WriteLong (&buf, 0x10000 + cl.servercount);
- MSG_WriteByte (&buf, 1); // demos are always attract loops
- MSG_WriteString (&buf, cl.gamedir);
- MSG_WriteShort (&buf, cl.playernum);
-
- MSG_WriteString (&buf, cl.configstrings[CS_NAME]);
-
- // configstrings
- for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
- {
- if (cl.configstrings[i][0])
- {
- if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
- { // write it out
- len = LittleLong (buf.cursize);
- fwrite (&len, 4, 1, cls.demofile);
- fwrite (buf.data, buf.cursize, 1, cls.demofile);
- buf.cursize = 0;
- }
-
- MSG_WriteByte (&buf, svc_configstring);
- MSG_WriteShort (&buf, i);
- MSG_WriteString (&buf, cl.configstrings[i]);
- }
-
- }
-
- // baselines
- memset (&nullstate, 0, sizeof(nullstate));
- for (i=0; i<MAX_EDICTS ; i++)
- {
- ent = &cl_entities[i].baseline;
- if (!ent->modelindex)
- continue;
-
- if (buf.cursize + 64 > buf.maxsize)
- { // write it out
- len = LittleLong (buf.cursize);
- fwrite (&len, 4, 1, cls.demofile);
- fwrite (buf.data, buf.cursize, 1, cls.demofile);
- buf.cursize = 0;
- }
-
- MSG_WriteByte (&buf, svc_spawnbaseline);
- MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
- }
-
- MSG_WriteByte (&buf, svc_stufftext);
- MSG_WriteString (&buf, "precache\n");
-
- // write it to the demo file
-
- len = LittleLong (buf.cursize);
- fwrite (&len, 4, 1, cls.demofile);
- fwrite (buf.data, buf.cursize, 1, cls.demofile);
-
- // the rest of the demo file will be individual frames
-}
-
-//======================================================================
-
-/*
-===================
-Cmd_ForwardToServer
-
-adds the current command line as a clc_stringcmd to the client message.
-things like godmode, noclip, etc, are commands directed to the server,
-so when they are typed in at the console, they will need to be forwarded.
-===================
-*/
-void Cmd_ForwardToServer (void)
-{
- char *cmd;
-
- cmd = Cmd_Argv(0);
- if (cls.state <= ca_connected || *cmd == '-' || *cmd == '+')
- {
- Com_Printf ("Unknown command \"%s\"\n", cmd);
- return;
- }
-
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- SZ_Print (&cls.netchan.message, cmd);
- if (Cmd_Argc() > 1)
- {
- SZ_Print (&cls.netchan.message, " ");
- SZ_Print (&cls.netchan.message, Cmd_Args());
- }
-}
-
-void
-CL_Setenv_f(void)
-{
- int i, l = 0, argc;
- char name[1024], val[1024], *env;
-
- argc = Cmd_Argc();
-
- if(argc > 2){
- strncpy(name, Cmd_Argv(1), sizeof name);
- for(i = 2; i < argc; i++){
- strncpy(val+l, Cmd_Argv(i), sizeof(name) - l - 2);
- val[sizeof(val)-2] = 0;
- strcat(val, " ");
- l = strlen(val);
- }
- putenv(name, val);
- }else if(argc == 2){
- env = getenv(Cmd_Argv(1));
- if(env){
- Com_Printf("%s=%s\n", Cmd_Argv(1), env);
- free(env);
- }else
- Com_Printf("%s undefined\n", Cmd_Argv(1), env);
- }
-}
-
-
-/*
-==================
-CL_ForwardToServer_f
-==================
-*/
-void CL_ForwardToServer_f (void)
-{
- if (cls.state != ca_connected && cls.state != ca_active)
- {
- Com_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
- return;
- }
-
- // don't forward the first argument
- if (Cmd_Argc() > 1)
- {
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- SZ_Print (&cls.netchan.message, Cmd_Args());
- }
-}
-
-
-/*
-==================
-CL_Pause_f
-==================
-*/
-void CL_Pause_f (void)
-{
- // never pause in multiplayer
- if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
- {
- Cvar_SetValue ("paused", 0);
- return;
- }
-
- Cvar_SetValue ("paused", !cl_paused->value);
-}
-
-/*
-==================
-CL_Quit_f
-==================
-*/
-void CL_Quit_f (void)
-{
- CL_Disconnect ();
- Com_Quit ();
-}
-
-/*
-================
-CL_Drop
-
-Called after an ERR_DROP was thrown
-================
-*/
-void CL_Drop (void)
-{
- if (cls.state == ca_uninitialized)
- return;
- if (cls.state == ca_disconnected)
- return;
-
- CL_Disconnect ();
-
- // drop loading plaque unless this is the initial game start
- if (cls.disable_servercount != -1)
- SCR_EndLoadingPlaque (); // get rid of loading plaque
-}
-
-
-/*
-=======================
-CL_SendConnectPacket
-
-We have gotten a challenge from the server, so try and
-connect.
-======================
-*/
-void CL_SendConnectPacket (void)
-{
- netadr_t adr;
- int port;
-
- if (!NET_StringToAdr (cls.servername, &adr))
- {
- Com_Printf ("Bad server address\n");
- cls.connect_time = 0;
- return;
- }
- if (adr.port == 0)
- adr.port = BigShort (PORT_SERVER);
-
- port = Cvar_VariableValue ("qport");
- userinfo_modified = false;
-
- Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n",
- PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );
-}
-
-/*
-=================
-CL_CheckForResend
-
-Resend a connect message if the last one has timed out
-=================
-*/
-void CL_CheckForResend (void)
-{
- netadr_t adr;
-
- // if the local server is running and we aren't
- // then connect
- if (cls.state == ca_disconnected && Com_ServerState() )
- {
- cls.state = ca_connecting;
- strncpy (cls.servername, "localhost", sizeof(cls.servername)-1);
- // we don't need a challenge on the localhost
- CL_SendConnectPacket ();
- return;
-// cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
- }
-
- // resend if we haven't gotten a reply yet
- if (cls.state != ca_connecting)
- return;
-
- if (cls.realtime - cls.connect_time < 3000)
- return;
-
- if (!NET_StringToAdr (cls.servername, &adr))
- {
- Com_Printf ("Bad server address\n");
- cls.state = ca_disconnected;
- return;
- }
- if (adr.port == 0)
- adr.port = BigShort (PORT_SERVER);
-
- cls.connect_time = cls.realtime; // for retransmit requests
-
- Com_Printf ("Connecting to %s...\n", cls.servername);
-
- Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
-}
-
-
-/*
-================
-CL_Connect_f
-
-================
-*/
-void CL_Connect_f (void)
-{
- char *server;
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("usage: connect <server>\n");
- return;
- }
-
- if (Com_ServerState ())
- { // if running a local server, kill it and reissue
- SV_Shutdown (va("Server quit\n", msg), false);
- }
- else
- {
- CL_Disconnect ();
- }
-
- server = Cmd_Argv (1);
-
- NET_Config (true); // allow remote
-
- CL_Disconnect ();
-
- cls.state = ca_connecting;
- strncpy (cls.servername, server, sizeof(cls.servername)-1);
- cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
-}
-
-
-/*
-=====================
-CL_Rcon_f
-
- Send the rest of the command line over as
- an unconnected command.
-=====================
-*/
-void CL_Rcon_f (void)
-{
- char message[1024];
- int i;
- netadr_t to;
-
- if (!rcon_client_password->string)
- {
- Com_Printf ("You must set 'rcon_password' before\n"
- "issuing an rcon command.\n");
- return;
- }
-
- message[0] = (char)255;
- message[1] = (char)255;
- message[2] = (char)255;
- message[3] = (char)255;
- message[4] = 0;
-
- NET_Config (true); // allow remote
-
- strcat (message, "rcon ");
-
- strcat (message, rcon_client_password->string);
- strcat (message, " ");
-
- for (i=1 ; i<Cmd_Argc() ; i++)
- {
- strcat (message, Cmd_Argv(i));
- strcat (message, " ");
- }
-
- if (cls.state >= ca_connected)
- to = cls.netchan.remote_address;
- else
- {
- if (!strlen(rcon_address->string))
- {
- Com_Printf ("You must either be connected,\n"
- "or set the 'rcon_address' cvar\n"
- "to issue rcon commands\n");
-
- return;
- }
- NET_StringToAdr (rcon_address->string, &to);
- if (to.port == 0)
- to.port = BigShort (PORT_SERVER);
- }
-
- NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
-}
-
-
-/*
-=====================
-CL_ClearState
-
-=====================
-*/
-void CL_ClearState (void)
-{
- S_StopAllSounds ();
- CL_ClearEffects ();
- CL_ClearTEnts ();
-
-// wipe the entire cl structure
- memset (&cl, 0, sizeof(cl));
- memset (cl_entities, 0, sizeof(cl_entities));
-
- SZ_Clear (&cls.netchan.message);
-
-}
-
-/*
-=====================
-CL_Disconnect
-
-Goes from a connected state to full screen console state
-Sends a disconnect message to the server
-This is also called on Com_Error, so it shouldn't cause any errors
-=====================
-*/
-void CL_Disconnect (void)
-{
- byte final[32];
-
- if (cls.state == ca_disconnected)
- return;
-
- if (cl_timedemo && cl_timedemo->value)
- {
- int time;
-
- time = Sys_Milliseconds () - cl.timedemo_start;
- if (time > 0)
- Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
- time/1000.0, cl.timedemo_frames*1000.0 / time);
- }
-
- VectorClear (cl.refdef.blend);
- re.CinematicSetPalette(NULL);
-
- M_ForceMenuOff ();
-
- cls.connect_time = 0;
-
- SCR_StopCinematic ();
-
- if (cls.demorecording)
- CL_Stop_f ();
-
- // send a disconnect message to the server
- final[0] = clc_stringcmd;
- strcpy ((char *)final+1, "disconnect");
- Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
- Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
- Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
-
- CL_ClearState ();
-
- // stop download
- if (cls.download) {
- fclose(cls.download);
- cls.download = NULL;
- }
-
- cls.state = ca_disconnected;
-}
-
-void CL_Disconnect_f (void)
-{
- Com_Error (ERR_DROP, "Disconnected from server");
-}
-
-
-/*
-====================
-CL_Packet_f
-
-packet <destination> <contents>
-
-Contents allows \n escape character
-====================
-*/
-void CL_Packet_f (void)
-{
- char send[2048];
- int i, l;
- char *in, *out;
- netadr_t adr;
-
- if (Cmd_Argc() != 3)
- {
- Com_Printf ("packet <destination> <contents>\n");
- return;
- }
-
- NET_Config (true); // allow remote
-
- if (!NET_StringToAdr (Cmd_Argv(1), &adr))
- {
- Com_Printf ("Bad address\n");
- return;
- }
- if (!adr.port)
- adr.port = BigShort (PORT_SERVER);
-
- in = Cmd_Argv(2);
- out = send+4;
- send[0] = send[1] = send[2] = send[3] = (char)0xff;
-
- l = strlen (in);
- for (i=0 ; i<l ; i++)
- {
- if (in[i] == '\\' && in[i+1] == 'n')
- {
- *out++ = '\n';
- i++;
- }
- else
- *out++ = in[i];
- }
- *out = 0;
-
- NET_SendPacket (NS_CLIENT, out-send, send, adr);
-}
-
-/*
-=================
-CL_Changing_f
-
-Just sent as a hint to the client that they should
-drop to full console
-=================
-*/
-void CL_Changing_f (void)
-{
- //ZOID
- //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
- if (cls.download)
- return;
-
- SCR_BeginLoadingPlaque ();
- cls.state = ca_connected; // not active anymore, but not disconnected
- Com_Printf ("\nChanging map...\n");
-}
-
-
-/*
-=================
-CL_Reconnect_f
-
-The server is changing levels
-=================
-*/
-void CL_Reconnect_f (void)
-{
- //ZOID
- //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
- if (cls.download)
- return;
-
- S_StopAllSounds ();
- if (cls.state == ca_connected) {
- Com_Printf ("reconnecting...\n");
- cls.state = ca_connected;
- MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message, "new");
- return;
- }
-
- if (*cls.servername) {
- if (cls.state >= ca_connected) {
- CL_Disconnect();
- cls.connect_time = cls.realtime - 1500;
- } else
- cls.connect_time = -99999; // fire immediately
-
- cls.state = ca_connecting;
- Com_Printf ("reconnecting...\n");
- }
-}
-
-/*
-=================
-CL_ParseStatusMessage
-
-Handle a reply from a ping
-=================
-*/
-void CL_ParseStatusMessage (void)
-{
- char *s;
-
- s = MSG_ReadString(&net_message);
-
- Com_Printf ("%s\n", s);
- M_AddToServerList (net_from, s);
-}
-
-
-/*
-=================
-CL_PingServers_f
-=================
-*/
-void CL_PingServers_f (void)
-{
- int i;
- netadr_t adr;
- char name[32];
- char *adrstring;
- cvar_t *noudp;
- cvar_t *noipx;
-
- NET_Config (true); // allow remote
-
- // send a broadcast packet
- Com_Printf ("pinging broadcast...\n");
-
- noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
- if (!noudp->value)
- {
- adr.type = NA_BROADCAST;
- adr.port = BigShort(PORT_SERVER);
- Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
- }
-
- noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
- if (!noipx->value)
- {
- adr.type = NA_BROADCAST_IPX;
- adr.port = BigShort(PORT_SERVER);
- Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
- }
-
- // send a packet to each address book entry
- for (i=0 ; i<16 ; i++)
- {
- Com_sprintf (name, sizeof(name), "adr%i", i);
- adrstring = Cvar_VariableString (name);
- if (!adrstring || !adrstring[0])
- continue;
-
- Com_Printf ("pinging %s...\n", adrstring);
- if (!NET_StringToAdr (adrstring, &adr))
- {
- Com_Printf ("Bad address: %s\n", adrstring);
- continue;
- }
- if (!adr.port)
- adr.port = BigShort(PORT_SERVER);
- Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
- }
-}
-
-
-/*
-=================
-CL_Skins_f
-
-Load or download any custom player skins and models
-=================
-*/
-void CL_Skins_f (void)
-{
- int i;
-
- for (i=0 ; i<MAX_CLIENTS ; i++)
- {
- if (!cl.configstrings[CS_PLAYERSKINS+i][0])
- continue;
- Com_Printf ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]);
- SCR_UpdateScreen ();
- Sys_SendKeyEvents (); // pump message loop
- CL_ParseClientinfo (i);
- }
-}
-
-
-/*
-=================
-CL_ConnectionlessPacket
-
-Responses to broadcasts, etc
-=================
-*/
-void CL_ConnectionlessPacket (void)
-{
- char *s;
- char *c;
-
- MSG_BeginReading (&net_message);
- MSG_ReadLong (&net_message); // skip the -1
-
- s = MSG_ReadStringLine (&net_message);
-
- Cmd_TokenizeString (s, false);
-
- c = Cmd_Argv(0);
-
- Com_Printf ("%s: %s\n", NET_AdrToString (net_from), c);
-
- // server connection
- if (!strcmp(c, "client_connect"))
- {
- if (cls.state == ca_connected)
- {
- Com_Printf ("Dup connect received. Ignored.\n");
- return;
- }
- Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
- MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message, "new");
- cls.state = ca_connected;
- return;
- }
-
- // server responding to a status broadcast
- if (!strcmp(c, "info"))
- {
- CL_ParseStatusMessage ();
- return;
- }
-
- // remote command from gui front end
- if (!strcmp(c, "cmd"))
- {
- if (!NET_IsLocalAddress(net_from))
- {
- Com_Printf ("Command packet from remote host. Ignored.\n");
- return;
- }
- Sys_AppActivate ();
- s = MSG_ReadString (&net_message);
- Cbuf_AddText (s);
- Cbuf_AddText ("\n");
- return;
- }
- // print command from somewhere
- if (!strcmp(c, "print"))
- {
- s = MSG_ReadString (&net_message);
- Com_Printf ("%s", s);
- return;
- }
-
- // ping from somewhere
- if (!strcmp(c, "ping"))
- {
- Netchan_OutOfBandPrint (NS_CLIENT, net_from, "ack");
- return;
- }
-
- // challenge from the server we are connecting to
- if (!strcmp(c, "challenge"))
- {
- cls.challenge = atoi(Cmd_Argv(1));
- CL_SendConnectPacket ();
- return;
- }
-
- // echo request from server
- if (!strcmp(c, "echo"))
- {
- Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
- return;
- }
-
- Com_Printf ("Unknown command.\n");
-}
-
-
-/*
-=================
-CL_DumpPackets
-
-A vain attempt to help bad TCP stacks that cause problems
-when they overflow
-=================
-*/
-void CL_DumpPackets (void)
-{
- while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
- {
- Com_Printf ("dumnping a packet\n");
- }
-}
-
-/*
-=================
-CL_ReadPackets
-=================
-*/
-void CL_ReadPackets (void)
-{
- while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
- {
-// Com_Printf ("packet\n");
- //
- // remote command packet
- //
- if (*(int *)net_message.data == -1)
- {
- CL_ConnectionlessPacket ();
- continue;
- }
-
- if (cls.state == ca_disconnected || cls.state == ca_connecting)
- continue; // dump it if not connected
-
- if (net_message.cursize < 8)
- {
- Com_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
- continue;
- }
-
- //
- // packet from server
- //
- if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
- {
- Com_DPrintf ("%s:sequenced packet without connection\n"
- ,NET_AdrToString(net_from));
- continue;
- }
- if (!Netchan_Process(&cls.netchan, &net_message))
- continue; // wasn't accepted for some reason
- CL_ParseServerMessage ();
- }
-
- //
- // check timeout
- //
- if (cls.state >= ca_connected
- && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000)
- {
- if (++cl.timeoutcount > 5) // timeoutcount saves debugger
- {
- Com_Printf ("\nServer connection timed out.\n");
- CL_Disconnect ();
- return;
- }
- }
- else
- cl.timeoutcount = 0;
-
-}
-
-
-//=============================================================================
-
-/*
-==============
-CL_FixUpGender_f
-==============
-*/
-void CL_FixUpGender(void)
-{
- char *p;
- char sk[80];
-
- if (gender_auto->value) {
-
- if (gender->modified) {
- // was set directly, don't override the user
- gender->modified = false;
- return;
- }
-
- strncpy(sk, skin->string, sizeof(sk) - 1);
- if ((p = strchr(sk, '/')) != NULL)
- *p = 0;
- if (cistrcmp(sk, "male") == 0 || cistrcmp(sk, "cyborg") == 0)
- Cvar_Set ("gender", "male");
- else if (cistrcmp(sk, "female") == 0 || cistrcmp(sk, "crackhor") == 0)
- Cvar_Set ("gender", "female");
- else
- Cvar_Set ("gender", "none");
- gender->modified = false;
- }
-}
-
-/*
-==============
-CL_Userinfo_f
-==============
-*/
-void CL_Userinfo_f (void)
-{
- Com_Printf ("User info settings:\n");
- Info_Print (Cvar_Userinfo());
-}
-
-/*
-=================
-CL_Snd_Restart_f
-
-Restart the sound subsystem so it can pick up
-new parameters and flush all sounds
-=================
-*/
-void CL_Snd_Restart_f (void)
-{
- S_Shutdown ();
- S_Init ();
- CL_RegisterSounds ();
-}
-
-int precache_check; // for autodownload of precache items
-int precache_spawncount;
-int precache_tex;
-int precache_model_skin;
-
-byte *precache_model; // used for skin checking in alias models
-
-#define PLAYER_MULT 5
-
-// ENV_CNT is map load, ENV_CNT+1 is first env map
-#define ENV_CNT (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
-#define TEXTURE_CNT (ENV_CNT+13)
-
-static const char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
-
-void CL_RequestNextDownload (void)
-{
- unsigned map_checksum; // for detecting cheater maps
- char fn[MAX_OSPATH];
- dmdl_t *pheader;
-
- if (cls.state != ca_connected)
- return;
-
- if (!allow_download->value && precache_check < ENV_CNT)
- precache_check = ENV_CNT;
-
-//ZOID
- if (precache_check == CS_MODELS) { // confirm map
- precache_check = CS_MODELS+2; // 0 isn't used
- if (allow_download_maps->value)
- if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
- return; // started a download
- }
- if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS) {
- if (allow_download_models->value) {
- while (precache_check < CS_MODELS+MAX_MODELS &&
- cl.configstrings[precache_check][0]) {
- if (cl.configstrings[precache_check][0] == '*' ||
- cl.configstrings[precache_check][0] == '#') {
- precache_check++;
- continue;
- }
- if (precache_model_skin == 0) {
- if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
- precache_model_skin = 1;
- return; // started a download
- }
- precache_model_skin = 1;
- }
-
- // checking for skins in the model
- if (!precache_model) {
-
- FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model);
- if (!precache_model) {
- precache_model_skin = 0;
- precache_check++;
- continue; // couldn't load it
- }
- if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER) {
- // not an alias model
- FS_FreeFile(precache_model);
- precache_model = 0;
- precache_model_skin = 0;
- precache_check++;
- continue;
- }
- pheader = (dmdl_t *)precache_model;
- if (LittleLong (pheader->version) != ALIAS_VERSION) {
- precache_check++;
- precache_model_skin = 0;
- continue; // couldn't load it
- }
- }
-
- pheader = (dmdl_t *)precache_model;
-
- while (precache_model_skin - 1 < LittleLong(pheader->num_skins)) {
- if (!CL_CheckOrDownloadFile((char *)precache_model +
- LittleLong(pheader->ofs_skins) +
- (precache_model_skin - 1)*MAX_SKINNAME)) {
- precache_model_skin++;
- return; // started a download
- }
- precache_model_skin++;
- }
- if (precache_model) {
- FS_FreeFile(precache_model);
- precache_model = 0;
- }
- precache_model_skin = 0;
- precache_check++;
- }
- }
- precache_check = CS_SOUNDS;
- }
- if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS) {
- if (allow_download_sounds->value) {
- if (precache_check == CS_SOUNDS)
- precache_check++; // zero is blank
- while (precache_check < CS_SOUNDS+MAX_SOUNDS &&
- cl.configstrings[precache_check][0]) {
- if (cl.configstrings[precache_check][0] == '*') {
- precache_check++;
- continue;
- }
- Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]);
- if (!CL_CheckOrDownloadFile(fn))
- return; // started a download
- }
- }
- precache_check = CS_IMAGES;
- }
- if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES) {
- if (precache_check == CS_IMAGES)
- precache_check++; // zero is blank
- while (precache_check < CS_IMAGES+MAX_IMAGES &&
- cl.configstrings[precache_check][0]) {
- Com_sprintf(fn, sizeof(fn), "pics/%s.pcx", cl.configstrings[precache_check++]);
- if (!CL_CheckOrDownloadFile(fn))
- return; // started a download
- }
- precache_check = CS_PLAYERSKINS;
- }
- // skins are special, since a player has three things to download:
- // model, weapon model and skin
- // so precache_check is now *3
- if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
- if (allow_download_players->value) {
- while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
- int i, n;
- char model[MAX_QPATH], skin[MAX_QPATH], *p;
-
- i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
- n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
-
- if (!cl.configstrings[CS_PLAYERSKINS+i][0]) {
- precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
- continue;
- }
-
- if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
- p++;
- else
- p = cl.configstrings[CS_PLAYERSKINS+i];
- strcpy(model, p);
- p = strchr(model, '/');
- if (!p)
- p = strchr(model, '\\');
- if (p) {
- *p++ = 0;
- strcpy(skin, p);
- } else
- *skin = 0;
-
- switch (n) {
- case 0: // model
- Com_sprintf(fn, sizeof(fn), "players/%s/tris.md2", model);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
- return; // started a download
- }
- /*FALL THROUGH*/
-
- case 1: // weapon model
- Com_sprintf(fn, sizeof(fn), "players/%s/weapon.md2", model);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
- return; // started a download
- }
- /*FALL THROUGH*/
-
- case 2: // weapon skin
- Com_sprintf(fn, sizeof(fn), "players/%s/weapon.pcx", model);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
- return; // started a download
- }
- /*FALL THROUGH*/
-
- case 3: // skin
- Com_sprintf(fn, sizeof(fn), "players/%s/%s.pcx", model, skin);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
- return; // started a download
- }
- /*FALL THROUGH*/
-
- case 4: // skin_i
- Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.pcx", model, skin);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
- return; // started a download
- }
- // move on to next model
- precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
- }
- }
- }
- // precache phase completed
- precache_check = ENV_CNT;
- }
-
- if (precache_check == ENV_CNT) {
- precache_check = ENV_CNT + 1;
-
- CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
-
- if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM])) {
- Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n",
- map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
- return;
- }
- }
-
- if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) {
- if (allow_download->value && allow_download_maps->value) {
- while (precache_check < TEXTURE_CNT) {
- int n = precache_check++ - ENV_CNT - 1;
-
- if (n & 1)
- Com_sprintf(fn, sizeof(fn), "env/%s%s.pcx",
- cl.configstrings[CS_SKY], env_suf[n/2]);
- else
- Com_sprintf(fn, sizeof(fn), "env/%s%s.tga",
- cl.configstrings[CS_SKY], env_suf[n/2]);
- if (!CL_CheckOrDownloadFile(fn))
- return; // started a download
- }
- }
- precache_check = TEXTURE_CNT;
- }
-
- if (precache_check == TEXTURE_CNT) {
- precache_check = TEXTURE_CNT+1;
- precache_tex = 0;
- }
-
- // confirm existance of textures, download any that don't exist
- if (precache_check == TEXTURE_CNT+1) {
- // from qcommon/cmodel.c
- extern int numtexinfo;
- extern mapsurface_t map_surfaces[];
-
- if (allow_download->value && allow_download_maps->value) {
- while (precache_tex < numtexinfo) {
- char fn[MAX_OSPATH];
-
- sprintf(fn, "textures/%s.wal", map_surfaces[precache_tex++].rname);
- if (!CL_CheckOrDownloadFile(fn))
- return; // started a download
- }
- }
- precache_check = TEXTURE_CNT+999;
- }
-
-//ZOID
- CL_RegisterSounds ();
- CL_PrepRefresh ();
-
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) );
-}
-
-/*
-=================
-CL_Precache_f
-
-The server will send this command right
-before allowing the client into the server
-=================
-*/
-void CL_Precache_f (void)
-{
- //Yet another hack to let old demos work
- //the old precache sequence
- if (Cmd_Argc() < 2) {
- unsigned map_checksum; // for detecting cheater maps
-
- CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
- CL_RegisterSounds ();
- CL_PrepRefresh ();
- return;
- }
-
- precache_check = CS_MODELS;
- precache_spawncount = atoi(Cmd_Argv(1));
- precache_model = 0;
- precache_model_skin = 0;
-
- CL_RequestNextDownload();
-}
-
-
-/*
-=================
-CL_InitLocal
-=================
-*/
-void CL_InitLocal (void)
-{
- cls.state = ca_disconnected;
- cls.realtime = Sys_Milliseconds ();
-
- CL_InitInput ();
-
- adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE );
- adr1 = Cvar_Get( "adr1", "", CVAR_ARCHIVE );
- adr2 = Cvar_Get( "adr2", "", CVAR_ARCHIVE );
- adr3 = Cvar_Get( "adr3", "", CVAR_ARCHIVE );
- adr4 = Cvar_Get( "adr4", "", CVAR_ARCHIVE );
- adr5 = Cvar_Get( "adr5", "", CVAR_ARCHIVE );
- adr6 = Cvar_Get( "adr6", "", CVAR_ARCHIVE );
- adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE );
- adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE );
-
-//
-// register our variables
-//
- cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE );
- cl_stereo = Cvar_Get( "cl_stereo", "0", 0 );
-
- cl_add_blend = Cvar_Get ("cl_blend", "1", 0);
- cl_add_lights = Cvar_Get ("cl_lights", "1", 0);
- cl_add_particles = Cvar_Get ("cl_particles", "1", 0);
- cl_add_entities = Cvar_Get ("cl_entities", "1", 0);
- cl_gun = Cvar_Get ("cl_gun", "1", 0);
- cl_footsteps = Cvar_Get ("cl_footsteps", "1", 0);
- cl_noskins = Cvar_Get ("cl_noskins", "0", 0);
- cl_autoskins = Cvar_Get ("cl_autoskins", "0", 0);
- cl_predict = Cvar_Get ("cl_predict", "1", 0);
-// cl_minfps = Cvar_Get ("cl_minfps", "5", 0);
- cl_maxfps = Cvar_Get ("cl_maxfps", "90", 0);
-
- cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0);
- cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0);
- cl_sidespeed = Cvar_Get ("cl_sidespeed", "200", 0);
- cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0);
- cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0);
- cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
-
- cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE);
-
- cl_shownet = Cvar_Get ("cl_shownet", "0", 0);
- cl_showmiss = Cvar_Get ("cl_showmiss", "0", 0);
- cl_showclamp = Cvar_Get ("showclamp", "0", 0);
- cl_timeout = Cvar_Get ("cl_timeout", "120", 0);
- cl_paused = Cvar_Get ("paused", "0", 0);
- cl_timedemo = Cvar_Get ("timedemo", "0", 0);
-
- rcon_client_password = Cvar_Get ("rcon_password", "", 0);
- rcon_address = Cvar_Get ("rcon_address", "", 0);
-
- cl_lightlevel = Cvar_Get ("r_lightlevel", "0", 0);
-
- //
- // userinfo
- //
- info_password = Cvar_Get ("password", "", CVAR_USERINFO);
- info_spectator = Cvar_Get ("spectator", "0", CVAR_USERINFO);
- name = Cvar_Get ("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE);
- skin = Cvar_Get ("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
- rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE); // FIXME
- msg = Cvar_Get ("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
- hand = Cvar_Get ("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
- fov = Cvar_Get ("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE);
- gender = Cvar_Get ("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
- gender_auto = Cvar_Get ("gender_auto", "1", CVAR_ARCHIVE);
- gender->modified = false; // clear this so we know when user sets it manually
-
- cl_vwep = Cvar_Get ("cl_vwep", "1", CVAR_ARCHIVE);
-
-
- //
- // register our commands
- //
- Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
- Cmd_AddCommand ("pause", CL_Pause_f);
- Cmd_AddCommand ("pingservers", CL_PingServers_f);
- Cmd_AddCommand ("skins", CL_Skins_f);
-
- Cmd_AddCommand ("userinfo", CL_Userinfo_f);
- Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
-
- Cmd_AddCommand ("changing", CL_Changing_f);
- Cmd_AddCommand ("disconnect", CL_Disconnect_f);
- Cmd_AddCommand ("record", CL_Record_f);
- Cmd_AddCommand ("stop", CL_Stop_f);
-
- Cmd_AddCommand ("quit", CL_Quit_f);
-
- Cmd_AddCommand ("connect", CL_Connect_f);
- Cmd_AddCommand ("reconnect", CL_Reconnect_f);
-
- Cmd_AddCommand ("rcon", CL_Rcon_f);
-
-// Cmd_AddCommand ("packet", CL_Packet_f); // this is dangerous to leave in
-
- Cmd_AddCommand ("setenv", CL_Setenv_f );
-
- Cmd_AddCommand ("precache", CL_Precache_f);
-
- Cmd_AddCommand ("download", CL_Download_f);
-
- //
- // forward to server commands
- //
- // the only thing this does is allow command completion
- // to work -- all unknown commands are automatically
- // forwarded to the server
- Cmd_AddCommand ("wave", NULL);
- Cmd_AddCommand ("inven", NULL);
- Cmd_AddCommand ("kill", NULL);
- Cmd_AddCommand ("use", NULL);
- Cmd_AddCommand ("drop", NULL);
- Cmd_AddCommand ("say", NULL);
- Cmd_AddCommand ("say_team", NULL);
- Cmd_AddCommand ("info", NULL);
- Cmd_AddCommand ("prog", NULL);
- Cmd_AddCommand ("give", NULL);
- Cmd_AddCommand ("god", NULL);
- Cmd_AddCommand ("notarget", NULL);
- Cmd_AddCommand ("noclip", NULL);
- Cmd_AddCommand ("invuse", NULL);
- Cmd_AddCommand ("invprev", NULL);
- Cmd_AddCommand ("invnext", NULL);
- Cmd_AddCommand ("invdrop", NULL);
- Cmd_AddCommand ("weapnext", NULL);
- Cmd_AddCommand ("weapprev", NULL);
-}
-
-
-
-/*
-===============
-CL_WriteConfiguration
-
-Writes key bindings and archived cvars to config.cfg
-===============
-*/
-void CL_WriteConfiguration (void)
-{
- FILE *f;
- char path[MAX_QPATH];
-
- if (cls.state == ca_uninitialized)
- return;
-
- Com_sprintf (path, sizeof(path),"%s/config.cfg",FS_Gamedir());
- f = fopen (path, "w");
- if (!f)
- {
- Com_Printf ("Couldn't write config.cfg.\n");
- return;
- }
-
- fprintf (f, "// generated by quake, do not modify\n");
- Key_WriteBindings (f);
- fclose (f);
-
- Cvar_WriteVariables (path);
-}
-
-
-/*
-==================
-CL_FixCvarCheats
-
-==================
-*/
-
-typedef struct
-{
- char *name;
- char *value;
- cvar_t *var;
-} cheatvar_t;
-
-cheatvar_t cheatvars[] = {
- {"timescale", "1"},
- {"timedemo", "0"},
- {"r_drawworld", "1"},
- {"cl_testlights", "0"},
- {"r_fullbright", "0"},
- {"r_drawflat", "0"},
- {"paused", "0"},
- {"fixedtime", "0"},
- {"sw_draworder", "0"},
- {"gl_lightmap", "0"},
- {"gl_saturatelighting", "0"},
- {NULL, NULL}
-};
-
-int numcheatvars;
-
-void CL_FixCvarCheats (void)
-{
- int i;
- cheatvar_t *var;
-
- if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1")
- || !cl.configstrings[CS_MAXCLIENTS][0] )
- return; // single player can cheat
-
- // find all the cvars if we haven't done it yet
- if (!numcheatvars)
- {
- while (cheatvars[numcheatvars].name)
- {
- cheatvars[numcheatvars].var = Cvar_Get (cheatvars[numcheatvars].name,
- cheatvars[numcheatvars].value, 0);
- numcheatvars++;
- }
- }
-
- // make sure they are all set to the proper values
- for (i=0, var = cheatvars ; i<numcheatvars ; i++, var++)
- {
- if ( strcmp (var->var->string, var->value) )
- {
- Cvar_Set (var->name, var->value);
- }
- }
-}
-
-//============================================================================
-
-/*
-==================
-CL_SendCommand
-
-==================
-*/
-void CL_SendCommand (void)
-{
- // get new key events
- Sys_SendKeyEvents ();
-
- // allow mice or other external controllers to add commands
- IN_Commands ();
-
- // process console commands
- Cbuf_Execute ();
-
- // fix any cheating cvars
- CL_FixCvarCheats ();
-
- // send intentions now
- CL_SendCmd ();
-
- // resend a connection request if necessary
- CL_CheckForResend ();
-}
-
-
-/*
-==================
-CL_Frame
-
-==================
-*/
-void CL_Frame (int msec)
-{
- static int extratime;
- static int lasttimecalled;
-
- if (dedicated->value)
- return;
-
- extratime += msec;
-
- if (!cl_timedemo->value)
- {
- if (cls.state == ca_connected && extratime < 100)
- return; // don't flood packets out while connecting
- if (extratime < 1000/cl_maxfps->value)
- return; // framerate is too high
- }
-
- // let the mouse activate or deactivate
- IN_Frame ();
-
- // decide the simulation time
- cls.frametime = extratime/1000.0;
- cl.time += extratime;
- cls.realtime = curtime;
-
- extratime = 0;
-/*
- if (cls.frametime > (1.0 / cl_minfps->value))
- cls.frametime = (1.0 / cl_minfps->value);
-*/
- if (cls.frametime > (1.0 / 5))
- cls.frametime = (1.0 / 5);
-
- // if in the debugger last frame, don't timeout
- if (msec > 5000)
- cls.netchan.last_received = Sys_Milliseconds ();
-
- // fetch results from server
- CL_ReadPackets ();
-
- // send a new command message to the server
- CL_SendCommand ();
-
- // predict all unacknowledged movements
- CL_PredictMovement ();
-
- // allow rendering DLL change
- VID_CheckChanges ();
- if (!cl.refresh_prepped && cls.state == ca_active)
- CL_PrepRefresh ();
-
- // update the screen
- if (host_speeds->value)
- time_before_ref = Sys_Milliseconds ();
- SCR_UpdateScreen ();
- if (host_speeds->value)
- time_after_ref = Sys_Milliseconds ();
-
- // update audio
- S_Update (cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up);
-
- CDAudio_Update();
-
- // advance local effects for next frame
- CL_RunDLights ();
- CL_RunLightStyles ();
- SCR_RunCinematic ();
- SCR_RunConsole ();
-
- cls.framecount++;
-
- if ( log_stats->value )
- {
- if ( cls.state == ca_active )
- {
- if ( !lasttimecalled )
- {
- lasttimecalled = Sys_Milliseconds();
- if ( log_stats_file )
- fprintf( log_stats_file, "0\n" );
- }
- else
- {
- int now = Sys_Milliseconds();
-
- if ( log_stats_file )
- fprintf( log_stats_file, "%d\n", now - lasttimecalled );
- lasttimecalled = now;
- }
- }
- }
-}
-
-
-//============================================================================
-
-/*
-====================
-CL_Init
-====================
-*/
-void CL_Init (void)
-{
- IN_Init();
-
- if(dedicated->value)
- return; // nothing running on the client
-
- // all archived variables will now be loaded
-
- Con_Init ();
- S_Init ();
- VID_Init ();
-
- V_Init ();
-
- net_message.data = net_message_buffer;
- net_message.maxsize = sizeof(net_message_buffer);
-
- M_Init ();
-
- SCR_Init ();
- cls.disable_screen = true; // don't draw yet
-
- CDAudio_Init ();
- CL_InitLocal ();
-
-// Cbuf_AddText ("exec autoexec.cfg\n");
- FS_ExecAutoexec ();
- Cbuf_Execute ();
-}
-
-
-/*
-===============
-CL_Shutdown
-
-FIXME: this is a callback from Sys_Quit and Com_Error. It would be better
-to run quit through here before the final handoff to the sys code.
-===============
-*/
-void CL_Shutdown(void)
-{
- static qboolean isdown = false;
-
- if (isdown)
- {
- printf ("recursive shutdown\n");
- return;
- }
- isdown = true;
-
- CL_WriteConfiguration ();
-
- CDAudio_Shutdown ();
- S_Shutdown();
- IN_Shutdown ();
- VID_Shutdown();
-}
-
-
--- a/client/cl_newfx.c
+++ /dev/null
@@ -1,1306 +1,0 @@
-// cl_newfx.c -- MORE entity effects parsing and management
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-extern cparticle_t *active_particles, *free_particles;
-extern cparticle_t particles[MAX_PARTICLES];
-extern int cl_numparticles;
-
-extern void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up);
-
-
-/*
-======
-vectoangles2 - this is duplicated in the game DLL, but I need it here.
-======
-*/
-void vectoangles2 (vec3_t value1, vec3_t angles)
-{
- float forward;
- float yaw, pitch;
-
- if (value1[1] == 0 && value1[0] == 0)
- {
- yaw = 0;
- if (value1[2] > 0)
- pitch = 90;
- else
- pitch = 270;
- }
- else
- {
- // PMM - fixed to correct for pitch of 0
- if (value1[0])
- yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
- else if (value1[1] > 0)
- yaw = 90;
- else
- yaw = 270;
-
- if (yaw < 0)
- yaw += 360;
-
- forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
- pitch = (atan2(value1[2], forward) * 180 / M_PI);
- if (pitch < 0)
- pitch += 360;
- }
-
- angles[PITCH] = -pitch;
- angles[YAW] = yaw;
- angles[ROLL] = 0;
-}
-
-//=============
-//=============
-void CL_Flashlight (int ent, vec3_t pos)
-{
- cdlight_t *dl;
-
- dl = CL_AllocDlight (ent);
- VectorCopy (pos, dl->origin);
- dl->radius = 400;
- dl->minlight = 250;
- dl->die = cl.time + 100;
- dl->color[0] = 1;
- dl->color[1] = 1;
- dl->color[2] = 1;
-}
-
-/*
-======
-CL_ColorFlash - flash of light
-======
-*/
-void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b)
-{
- cdlight_t *dl;
-
- if((vidref_val == VIDREF_SOFT) && ((r < 0) || (g<0) || (b<0)))
- {
- intensity = -intensity;
- r = -r;
- g = -g;
- b = -b;
- }
-
- dl = CL_AllocDlight (ent);
- VectorCopy (pos, dl->origin);
- dl->radius = intensity;
- dl->minlight = 250;
- dl->die = cl.time + 100;
- dl->color[0] = r;
- dl->color[1] = g;
- dl->color[2] = b;
-}
-
-
-/*
-======
-CL_DebugTrail
-======
-*/
-void CL_DebugTrail (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
-// int j;
- cparticle_t *p;
- float dec;
- vec3_t right, up;
-// int i;
-// float d, c, s;
-// vec3_t dir;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- MakeNormalVectors (vec, right, up);
-
-// VectorScale(vec, RT2_SKIP, vec);
-
-// dec = 1.0;
-// dec = 0.75;
- dec = 3;
- VectorScale (vec, dec, vec);
- VectorCopy (start, move);
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
- VectorClear (p->vel);
- p->alpha = 1.0;
- p->alphavel = -0.1;
-// p->alphavel = 0;
- p->color = 0x74 + (rand()&7);
- VectorCopy (move, p->org);
-/*
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*2;
- p->vel[j] = crand()*3;
- p->accel[j] = 0;
- }
-*/
- VectorAdd (move, vec, move);
- }
-
-}
-
-/*
-===============
-CL_SmokeTrail
-===============
-*/
-void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- VectorScale (vec, spacing, vec);
-
- // FIXME: this is a really silly way to have a loop
- while (len > 0)
- {
- len -= spacing;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.5);
- p->color = colorStart + (rand() % colorRun);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*3;
- p->accel[j] = 0;
- }
- p->vel[2] = 20 + crand()*5;
-
- VectorAdd (move, vec, move);
- }
-}
-
-void CL_ForceWall (vec3_t start, vec3_t end, int color)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- VectorScale (vec, 4, vec);
-
- // FIXME: this is a really silly way to have a loop
- while (len > 0)
- {
- len -= 4;
-
- if (!free_particles)
- return;
-
- if (qfrand() > 0.3)
- {
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (3.0+qfrand()*0.5);
- p->color = color;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*3;
- p->accel[j] = 0;
- }
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = -40 - (crand()*10);
- }
-
- VectorAdd (move, vec, move);
- }
-}
-
-void CL_FlameEffects (centity_t */*ent*/, vec3_t origin)
-{
- int n, count;
- int j;
- cparticle_t *p;
-
- count = rand() & 0xF;
-
- for(n=0;n<count;n++)
- {
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- VectorClear (p->accel);
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->color = 226 + (rand() % 4);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = origin[j] + crand()*5;
- p->vel[j] = crand()*5;
- }
- p->vel[2] = crand() * -10;
- p->accel[2] = -PARTICLE_GRAVITY;
- }
-
- count = rand() & 0x7;
-
- for(n=0;n<count;n++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.5);
- p->color = 0 + (rand() % 4);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = origin[j] + crand()*3;
- }
- p->vel[2] = 20 + crand()*5;
- }
-
-}
-
-
-/*
-===============
-CL_GenericParticleEffect
-===============
-*/
-void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel)
-{
- int i, j;
- cparticle_t *p;
- float d;
-
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- if (numcolors > 1)
- p->color = color + (rand() & numcolors);
- else
- p->color = color;
-
- d = rand() & dirspread;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
- p->vel[j] = crand()*20;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
-// VectorCopy (accel, p->accel);
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*alphavel);
-// p->alphavel = alphavel;
- }
-}
-
-/*
-===============
-CL_BubbleTrail2 (lets you control the # of bubbles by setting the distance between the spawns)
-
-===============
-*/
-void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int i, j;
- cparticle_t *p;
- float dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = dist;
- VectorScale (vec, dec, vec);
-
- for (i=0 ; i<len ; i+=dec)
- {
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- VectorClear (p->accel);
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.1);
- p->color = 4 + (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*2;
- p->vel[j] = crand()*10;
- }
- p->org[2] -= 4;
-// p->vel[2] += 6;
- p->vel[2] += 20;
-
- VectorAdd (move, vec, move);
- }
-}
-
-//#define CORKSCREW 1
-//#define DOUBLE_SCREW 1
-#define RINGS 1
-//#define SPRAY 1
-
-#ifdef CORKSCREW
-void CL_Heatbeam (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j,k;
- cparticle_t *p;
- vec3_t right, up;
- int i;
- float d, c, s;
- vec3_t dir;
- float ltime;
- float step = 5.0;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
-// MakeNormalVectors (vec, right, up);
- VectorCopy (cl.v_right, right);
- VectorCopy (cl.v_up, up);
- VectorMA (move, -1, right, move);
- VectorMA (move, -1, up, move);
-
- VectorScale (vec, step, vec);
- ltime = (float) cl.time/1000.0;
-
-// for (i=0 ; i<len ; i++)
- for (i=0 ; i<len ; i+=step)
- {
- d = i * 0.1 - fmod(ltime,16.0)*M_PI;
- c = cos(d)/1.75;
- s = sin(d)/1.75;
-#ifdef DOUBLE_SCREW
- for (k=-1; k<2; k+=2)
- {
-#else
- k=1;
-#endif
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
-
- p->alpha = 0.5;
- // p->alphavel = -1.0 / (1+qfrand()*0.2);
- // only last one frame!
- p->alphavel = INSTANT_PARTICLE;
- // p->color = 0x74 + (rand()&7);
-// p->color = 223 - (rand()&7);
- p->color = 223;
-// p->color = 240;
-
- // trim it so it looks like it's starting at the origin
- if (i < 10)
- {
- VectorScale (right, c*(i/10.0)*k, dir);
- VectorMA (dir, s*(i/10.0)*k, up, dir);
- }
- else
- {
- VectorScale (right, c*k, dir);
- VectorMA (dir, s*k, up, dir);
- }
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + dir[j]*3;
- // p->vel[j] = dir[j]*6;
- p->vel[j] = 0;
- }
-#ifdef DOUBLE_SCREW
- }
-#endif
- VectorAdd (move, vec, move);
- }
-}
-#endif
-#ifdef RINGS
-//void CL_Heatbeam (vec3_t start, vec3_t end)
-void CL_Heatbeam (vec3_t start, vec3_t forward)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- vec3_t right, up;
- int i;
- float c, s;
- vec3_t dir;
- float ltime;
- float step = 32.0, rstep;
- float start_pt;
- float rot;
- float variance;
- vec3_t end;
-
- VectorMA (start, 4096, forward, end);
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- // FIXME - pmm - these might end up using old values?
-// MakeNormalVectors (vec, right, up);
- VectorCopy (cl.v_right, right);
- VectorCopy (cl.v_up, up);
- if (vidref_val == VIDREF_GL)
- { // GL mode
- VectorMA (move, -0.5, right, move);
- VectorMA (move, -0.5, up, move);
- }
- // otherwise assume SOFT
-
- ltime = (float) cl.time/1000.0;
- start_pt = fmod(ltime*96.0,step);
- VectorMA (move, start_pt, vec, move);
-
- VectorScale (vec, step, vec);
-
-// Com_Printf ("%f\n", ltime);
- rstep = M_PI/10.0;
- for (i=start_pt ; i<len ; i+=step)
- {
- if (i>step*5) // don't bother after the 5th ring
- break;
-
- for (rot = 0; rot < M_PI*2; rot += rstep)
- {
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
-// rot+= fmod(ltime, 12.0)*M_PI;
-// c = cos(rot)/2.0;
-// s = sin(rot)/2.0;
-// variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2;
- variance = 0.5;
- c = cos(rot)*variance;
- s = sin(rot)*variance;
-
- // trim it so it looks like it's starting at the origin
- if (i < 10)
- {
- VectorScale (right, c*(i/10.0), dir);
- VectorMA (dir, s*(i/10.0), up, dir);
- }
- else
- {
- VectorScale (right, c, dir);
- VectorMA (dir, s, up, dir);
- }
-
- p->alpha = 0.5;
- // p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->alphavel = -1000.0;
- // p->color = 0x74 + (rand()&7);
- p->color = 223 - (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + dir[j]*3;
- // p->vel[j] = dir[j]*6;
- p->vel[j] = 0;
- }
- }
- VectorAdd (move, vec, move);
- }
-}
-#endif
-#ifdef SPRAY
-void CL_Heatbeam (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- vec3_t forward, right, up;
- int i;
- float d, c, s;
- vec3_t dir;
- float ltime;
- float step = 32.0, rstep;
- float start_pt;
- float rot;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
-// MakeNormalVectors (vec, right, up);
- VectorCopy (cl.v_forward, forward);
- VectorCopy (cl.v_right, right);
- VectorCopy (cl.v_up, up);
- VectorMA (move, -0.5, right, move);
- VectorMA (move, -0.5, up, move);
-
- for (i=0; i<8; i++)
- {
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
-
- d = crand()*M_PI;
- c = cos(d)*30;
- s = sin(d)*30;
-
- p->alpha = 1.0;
- p->alphavel = -5.0 / (1+qfrand());
- p->color = 223 - (rand()&7);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j];
- }
- VectorScale (vec, 450, p->vel);
- VectorMA (p->vel, c, right, p->vel);
- VectorMA (p->vel, s, up, p->vel);
- }
-/*
-
- ltime = (float) cl.time/1000.0;
- start_pt = fmod(ltime*16.0,step);
- VectorMA (move, start_pt, vec, move);
-
- VectorScale (vec, step, vec);
-
-// Com_Printf ("%f\n", ltime);
- rstep = M_PI/12.0;
- for (i=start_pt ; i<len ; i+=step)
- {
- if (i>step*5) // don't bother after the 5th ring
- break;
-
- for (rot = 0; rot < M_PI*2; rot += rstep)
- {
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
-// rot+= fmod(ltime, 12.0)*M_PI;
-// c = cos(rot)/2.0;
-// s = sin(rot)/2.0;
- c = cos(rot)/1.5;
- s = sin(rot)/1.5;
-
- // trim it so it looks like it's starting at the origin
- if (i < 10)
- {
- VectorScale (right, c*(i/10.0), dir);
- VectorMA (dir, s*(i/10.0), up, dir);
- }
- else
- {
- VectorScale (right, c, dir);
- VectorMA (dir, s, up, dir);
- }
-
- p->alpha = 0.5;
- // p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->alphavel = -1000.0;
- // p->color = 0x74 + (rand()&7);
- p->color = 223 - (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + dir[j]*3;
- // p->vel[j] = dir[j]*6;
- p->vel[j] = 0;
- }
- }
- VectorAdd (move, vec, move);
- }
-*/
-}
-#endif
-
-/*
-===============
-CL_ParticleSteamEffect
-
-Puffs with velocity along direction, with some randomness thrown in
-===============
-*/
-void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
-{
- int i, j;
- cparticle_t *p;
- float d;
- vec3_t r, u;
-
-// vectoangles2 (dir, angle_dir);
-// AngleVectors (angle_dir, f, r, u);
-
- MakeNormalVectors (dir, r, u);
-
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color + (rand()&7);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + magnitude*0.1*crand();
-// p->vel[j] = dir[j]*magnitude;
- }
- VectorScale (dir, magnitude, p->vel);
- d = crand()*magnitude/3;
- VectorMA (p->vel, d, r, p->vel);
- d = crand()*magnitude/3;
- VectorMA (p->vel, d, u, p->vel);
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY/2;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-void CL_ParticleSteamEffect2 (cl_sustain_t *self)
-//vec3_t org, vec3_t dir, int color, int count, int magnitude)
-{
- int i, j;
- cparticle_t *p;
- float d;
- vec3_t r, u;
- vec3_t dir;
-
-// vectoangles2 (dir, angle_dir);
-// AngleVectors (angle_dir, f, r, u);
-
- VectorCopy (self->dir, dir);
- MakeNormalVectors (dir, r, u);
-
- for (i=0 ; i<self->count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = self->color + (rand()&7);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = self->org[j] + self->magnitude*0.1*crand();
-// p->vel[j] = dir[j]*magnitude;
- }
- VectorScale (dir, self->magnitude, p->vel);
- d = crand()*self->magnitude/3;
- VectorMA (p->vel, d, r, p->vel);
- d = crand()*self->magnitude/3;
- VectorMA (p->vel, d, u, p->vel);
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY/2;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
- self->nextthink += self->thinkinterval;
-}
-
-/*
-===============
-CL_TrackerTrail
-===============
-*/
-void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor)
-{
- vec3_t move;
- vec3_t vec;
- vec3_t forward,right,up,angle_dir;
- float len;
- int j;
- cparticle_t *p;
- int dec;
- float dist;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- VectorCopy(vec, forward);
- vectoangles2 (forward, angle_dir);
- AngleVectors (angle_dir, forward, right, up);
-
- dec = 3;
- VectorScale (vec, 3, vec);
-
- // FIXME: this is a really silly way to have a loop
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -2.0;
- p->color = particleColor;
- dist = DotProduct(move, forward);
- VectorMA(move, 8 * cos(dist), up, p->org);
- for (j=0 ; j<3 ; j++)
- {
-// p->org[j] = move[j] + crand();
- p->vel[j] = 0;
- p->accel[j] = 0;
- }
- p->vel[2] = 5;
-
- VectorAdd (move, vec, move);
- }
-}
-
-void CL_Tracker_Shell(vec3_t origin)
-{
- vec3_t dir;
- int i;
- cparticle_t *p;
-
- for(i=0;i<300;i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = INSTANT_PARTICLE;
- p->color = 0;
-
- dir[0] = crand();
- dir[1] = crand();
- dir[2] = crand();
- VectorNormalize(dir);
-
- VectorMA(origin, 40, dir, p->org);
- }
-}
-
-void CL_MonsterPlasma_Shell(vec3_t origin)
-{
- vec3_t dir;
- int i;
- cparticle_t *p;
-
- for(i=0;i<40;i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = INSTANT_PARTICLE;
- p->color = 0xe0;
-
- dir[0] = crand();
- dir[1] = crand();
- dir[2] = crand();
- VectorNormalize(dir);
-
- VectorMA(origin, 10, dir, p->org);
-// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
- }
-}
-
-void CL_Widowbeamout (cl_sustain_t *self)
-{
- vec3_t dir;
- int i;
- cparticle_t *p;
- static int colortable[4] = {2*8,13*8,21*8,18*8};
- float ratio;
-
- ratio = 1.0 - (((float)self->endtime - (float)cl.time)/2100.0);
-
- for(i=0;i<300;i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = INSTANT_PARTICLE;
- p->color = colortable[rand()&3];
-
- dir[0] = crand();
- dir[1] = crand();
- dir[2] = crand();
- VectorNormalize(dir);
-
- VectorMA(self->org, (45.0 * ratio), dir, p->org);
-// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
- }
-}
-
-void CL_Nukeblast (cl_sustain_t *self)
-{
- vec3_t dir;
- int i;
- cparticle_t *p;
- static int colortable[4] = {110, 112, 114, 116};
- float ratio;
-
- ratio = 1.0 - (((float)self->endtime - (float)cl.time)/1000.0);
-
- for(i=0;i<700;i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = INSTANT_PARTICLE;
- p->color = colortable[rand()&3];
-
- dir[0] = crand();
- dir[1] = crand();
- dir[2] = crand();
- VectorNormalize(dir);
-
- VectorMA(self->org, (200.0 * ratio), dir, p->org);
-// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
- }
-}
-
-void CL_WidowSplash (vec3_t org)
-{
- static int colortable[4] = {2*8,13*8,21*8,18*8};
- int i;
- cparticle_t *p;
- vec3_t dir;
-
- for (i=0 ; i<256 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = colortable[rand()&3];
-
- dir[0] = crand();
- dir[1] = crand();
- dir[2] = crand();
- VectorNormalize(dir);
- VectorMA(org, 45.0, dir, p->org);
- VectorMA(vec3_origin, 40.0, dir, p->vel);
-
- p->accel[0] = p->accel[1] = 0;
- p->alpha = 1.0;
-
- p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
- }
-
-}
-
-void CL_Tracker_Explode(vec3_t origin)
-{
- vec3_t dir, backdir;
- int i;
- cparticle_t *p;
-
- for(i=0;i<300;i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0;
- p->color = 0;
-
- dir[0] = crand();
- dir[1] = crand();
- dir[2] = crand();
- VectorNormalize(dir);
- VectorScale(dir, -1, backdir);
-
- VectorMA(origin, 64, dir, p->org);
- VectorScale(backdir, 64, p->vel);
- }
-
-}
-
-/*
-===============
-CL_TagTrail
-
-===============
-*/
-void CL_TagTrail (vec3_t start, vec3_t end, float color)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- int dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- while (len >= 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.8+qfrand()*0.2);
- p->color = color;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*16;
- p->vel[j] = crand()*5;
- p->accel[j] = 0;
- }
-
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-===============
-CL_ColorExplosionParticles
-===============
-*/
-void CL_ColorExplosionParticles (vec3_t org, int color, int run)
-{
- int i, j;
- cparticle_t *p;
-
- for (i=0 ; i<128 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color + (rand() % run);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()%32)-16);
- p->vel[j] = (rand()%256)-128;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -0.4 / (0.6 + qfrand()*0.2);
- }
-}
-
-/*
-===============
-CL_ParticleSmokeEffect - like the steam effect, but unaffected by gravity
-===============
-*/
-void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
-{
- int i, j;
- cparticle_t *p;
- float d;
- vec3_t r, u;
-
- MakeNormalVectors (dir, r, u);
-
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color + (rand()&7);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + magnitude*0.1*crand();
-// p->vel[j] = dir[j]*magnitude;
- }
- VectorScale (dir, magnitude, p->vel);
- d = crand()*magnitude/3;
- VectorMA (p->vel, d, r, p->vel);
- d = crand()*magnitude/3;
- VectorMA (p->vel, d, u, p->vel);
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-/*
-===============
-CL_BlasterParticles2
-
-Wall impact puffs (Green)
-===============
-*/
-void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color)
-{
- int i, j;
- cparticle_t *p;
- float d;
- int count;
-
- count = 40;
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color + (rand()&7);
-
- d = rand()&15;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
- p->vel[j] = dir[j] * 30 + crand()*40;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-/*
-===============
-CL_BlasterTrail2
-
-Green!
-===============
-*/
-void CL_BlasterTrail2 (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- int dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- // FIXME: this is a really silly way to have a loop
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.3+qfrand()*0.2);
- p->color = 0xd0;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand();
- p->vel[j] = crand()*5;
- p->accel[j] = 0;
- }
-
- VectorAdd (move, vec, move);
- }
-}
--- a/client/cl_parse.c
+++ /dev/null
@@ -1,802 +1,0 @@
-// cl_parse.c -- parse a message received from the server
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-char *svc_strings[256] =
-{
- "svc_bad",
-
- "svc_muzzleflash",
- "svc_muzzlflash2",
- "svc_temp_entity",
- "svc_layout",
- "svc_inventory",
-
- "svc_nop",
- "svc_disconnect",
- "svc_reconnect",
- "svc_sound",
- "svc_print",
- "svc_stufftext",
- "svc_serverdata",
- "svc_configstring",
- "svc_spawnbaseline",
- "svc_centerprint",
- "svc_download",
- "svc_playerinfo",
- "svc_packetentities",
- "svc_deltapacketentities",
- "svc_frame"
-};
-
-//=============================================================================
-
-void CL_DownloadFileName(char *dest, int destlen, char *fn)
-{
- if (strncmp(fn, "players", 7) == 0)
- Com_sprintf (dest, destlen, "%s/%s", BASEDIRNAME, fn);
- else
- Com_sprintf (dest, destlen, "%s/%s", FS_Gamedir(), fn);
-}
-
-/*
-===============
-CL_CheckOrDownloadFile
-
-Returns true if the file exists, otherwise it attempts
-to start a download from the server.
-===============
-*/
-qboolean CL_CheckOrDownloadFile (char *filename)
-{
- FILE *fp;
- char name[MAX_OSPATH];
-
- if (strstr (filename, ".."))
- {
- Com_Printf ("Refusing to download a path with ..\n");
- return true;
- }
-
- if (FS_LoadFile (filename, NULL) != -1)
- { // it exists, no need to download
- return true;
- }
-
- strcpy (cls.downloadname, filename);
-
- // download to a temp name, and only rename
- // to the real name when done, so if interrupted
- // a runt file wont be left
- COM_StripExtension (cls.downloadname, cls.downloadtempname);
- strcat (cls.downloadtempname, ".tmp");
-
-//ZOID
- // check to see if we already have a tmp for this file, if so, try to resume
- // open the file if not opened yet
- CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
-
-// FS_CreatePath (name);
-
- fp = fopen (name, "r+b");
- if (fp) { // it exists
- int len;
- fseek(fp, 0, SEEK_END);
- len = ftell(fp);
-
- cls.download = fp;
-
- // give the server an offset to start the download
- Com_Printf ("Resuming %s\n", cls.downloadname);
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message,
- va("download %s %i", cls.downloadname, len));
- } else {
- Com_Printf ("Downloading %s\n", cls.downloadname);
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message,
- va("download %s", cls.downloadname));
- }
-
- cls.downloadnumber++;
-
- return false;
-}
-
-/*
-===============
-CL_Download_f
-
-Request a download from the server
-===============
-*/
-void CL_Download_f (void)
-{
- char filename[MAX_OSPATH];
-
- if (Cmd_Argc() != 2) {
- Com_Printf("Usage: download <filename>\n");
- return;
- }
-
- Com_sprintf(filename, sizeof(filename), "%s", Cmd_Argv(1));
-
- if (strstr (filename, ".."))
- {
- Com_Printf ("Refusing to download a path with ..\n");
- return;
- }
-
- if (FS_LoadFile (filename, NULL) != -1)
- { // it exists, no need to download
- Com_Printf("File already exists.\n");
- return;
- }
-
- strcpy (cls.downloadname, filename);
- Com_Printf ("Downloading %s\n", cls.downloadname);
-
- // download to a temp name, and only rename
- // to the real name when done, so if interrupted
- // a runt file wont be left
- COM_StripExtension (cls.downloadname, cls.downloadtempname);
- strcat (cls.downloadtempname, ".tmp");
-
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message,
- va("download %s", cls.downloadname));
-
- cls.downloadnumber++;
-}
-
-/*
-======================
-CL_RegisterSounds
-======================
-*/
-void CL_RegisterSounds (void)
-{
- int i;
-
- S_BeginRegistration ();
- CL_RegisterTEntSounds ();
- for (i=1 ; i<MAX_SOUNDS ; i++)
- {
- if (!cl.configstrings[CS_SOUNDS+i][0])
- break;
- cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
- Sys_SendKeyEvents (); // pump message loop
- }
- S_EndRegistration ();
-}
-
-static void
-rename(char *old, char *new)
-{
- char *p;
- Dir d;
-
- if((p = strrchr(new, '/')) == nil)
- p = new;
- else
- p++;
- nulldir(&d);
- d.name = p;
- if(dirwstat(old, &d) < 0)
- fprint(2, "rename: %r\n");
-}
-
-/*
-=====================
-CL_ParseDownload
-
-A download message has been received from the server
-=====================
-*/
-void CL_ParseDownload (void)
-{
- int size, percent;
- char name[MAX_OSPATH];
-
- // read the data
- size = MSG_ReadShort (&net_message);
- percent = MSG_ReadByte (&net_message);
- if (size == -1)
- {
- Com_Printf ("Server does not have this file.\n");
- if (cls.download)
- {
- // if here, we tried to resume a file but the server said no
- fclose (cls.download);
- cls.download = NULL;
- }
- CL_RequestNextDownload ();
- return;
- }
-
- // open the file if not opened yet
- if (!cls.download)
- {
- CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
-
- FS_CreatePath (name);
-
- cls.download = fopen (name, "wb");
- if (!cls.download)
- {
- net_message.readcount += size;
- Com_Printf ("Failed to open %s\n", cls.downloadtempname);
- CL_RequestNextDownload ();
- return;
- }
- }
-
- fwrite (net_message.data + net_message.readcount, 1, size, cls.download);
- net_message.readcount += size;
-
- if (percent != 100)
- {
- // request next block
-// change display routines by zoid
-/*
- Com_Printf (".");
- if (10*(percent/10) != cls.downloadpercent)
- {
- cls.downloadpercent = 10*(percent/10);
- Com_Printf ("%i%%", cls.downloadpercent);
- }
-*/
- cls.downloadpercent = percent;
-
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- SZ_Print (&cls.netchan.message, "nextdl");
- }
- else
- {
- char oldn[MAX_OSPATH];
- char newn[MAX_OSPATH];
-
-// Com_Printf ("100%%\n");
-
- fclose (cls.download);
-
- // rename the temp file to it's final name
- CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
- CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
- rename (oldn, newn); /* FIXME */
-
- cls.download = NULL;
- cls.downloadpercent = 0;
-
- // get another file if needed
-
- CL_RequestNextDownload ();
- }
-}
-
-
-/*
-=====================================================================
-
- SERVER CONNECTING MESSAGES
-
-=====================================================================
-*/
-
-/*
-==================
-CL_ParseServerData
-==================
-*/
-void CL_ParseServerData (void)
-{
- extern cvar_t *fs_gamedirvar;
- char *str;
- int i;
-
- Com_DPrintf ("Serverdata packet received.\n");
-//
-// wipe the client_state_t struct
-//
- CL_ClearState ();
- cls.state = ca_connected;
-
-// parse protocol version number
- i = MSG_ReadLong (&net_message);
- cls.serverProtocol = i;
-
- // BIG HACK to let demos from release work with the 3.0x patch!!!
- if (Com_ServerState() && PROTOCOL_VERSION == 34)
- {
- }
- else if (i != PROTOCOL_VERSION)
- Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
-
- cl.servercount = MSG_ReadLong (&net_message);
- cl.attractloop = MSG_ReadByte (&net_message);
-
- // game directory
- str = MSG_ReadString (&net_message);
- strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
-
- // set gamedir
- if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
- Cvar_Set("game", str);
-
- // parse player entity number
- cl.playernum = MSG_ReadShort (&net_message);
-
- // get the full level name
- str = MSG_ReadString (&net_message);
-
- if (cl.playernum == -1)
- { // playing a cinematic or showing a pic, not a level
- SCR_PlayCinematic (str);
- }
- else
- {
- // seperate the printfs so the server message can have a color
- Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
- Com_Printf ("%c%s\n", 2, str);
-
- // need to prep refresh at next oportunity
- cl.refresh_prepped = false;
- }
-}
-
-/*
-==================
-CL_ParseBaseline
-==================
-*/
-void CL_ParseBaseline (void)
-{
- entity_state_t *es;
- int bits;
- int newnum;
- entity_state_t nullstate;
-
- memset (&nullstate, 0, sizeof(nullstate));
-
- newnum = CL_ParseEntityBits (&bits);
- es = &cl_entities[newnum].baseline;
- CL_ParseDelta (&nullstate, es, newnum, bits);
-}
-
-
-/*
-================
-CL_LoadClientinfo
-
-================
-*/
-void CL_LoadClientinfo (clientinfo_t *ci, char *s)
-{
- int i;
- char *t;
- char model_name[MAX_QPATH];
- char skin_name[MAX_QPATH];
- char model_filename[MAX_QPATH];
- char skin_filename[MAX_QPATH];
- char weapon_filename[MAX_QPATH];
-
- strncpy(ci->cinfo, s, sizeof(ci->cinfo));
- ci->cinfo[sizeof(ci->cinfo)-1] = 0;
-
- // isolate the player's name
- strncpy(ci->name, s, sizeof(ci->name));
- ci->name[sizeof(ci->name)-1] = 0;
- t = strstr (s, "\\");
- if (t)
- {
- ci->name[t-s] = 0;
- s = t+1;
- }
-
- if (cl_noskins->value || *s == 0)
- {
- Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
- Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/weapon.md2");
- Com_sprintf (skin_filename, sizeof(skin_filename), "players/male/grunt.pcx");
- Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/male/grunt_i.pcx");
- ci->model = re.RegisterModel (model_filename);
- memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
- ci->weaponmodel[0] = re.RegisterModel (weapon_filename);
- ci->skin = re.RegisterSkin (skin_filename);
- ci->icon = re.RegisterPic (ci->iconname);
- }
- else
- {
- // isolate the model name
- strcpy (model_name, s);
- t = strstr(model_name, "/");
- if (!t)
- t = strstr(model_name, "\\");
- if (!t)
- t = model_name;
- *t = 0;
-
- // isolate the skin name
- strcpy (skin_name, s + strlen(model_name) + 1);
-
- // model file
- Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
- ci->model = re.RegisterModel (model_filename);
- if (!ci->model)
- {
- strcpy(model_name, "male");
- Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
- ci->model = re.RegisterModel (model_filename);
- }
-
- // skin file
- Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
- ci->skin = re.RegisterSkin (skin_filename);
-
- // if we don't have the skin and the model wasn't male,
- // see if the male has it (this is for CTF's skins)
- if (!ci->skin && cistrcmp(model_name, "male"))
- {
- // change model to male
- strcpy(model_name, "male");
- Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
- ci->model = re.RegisterModel (model_filename);
-
- // see if the skin exists for the male model
- Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
- ci->skin = re.RegisterSkin (skin_filename);
- }
-
- // if we still don't have a skin, it means that the male model didn't have
- // it, so default to grunt
- if (!ci->skin) {
- // see if the skin exists for the male model
- Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/grunt.pcx", model_name, skin_name);
- ci->skin = re.RegisterSkin (skin_filename);
- }
-
- // weapon file
- for (i = 0; i < num_cl_weaponmodels; i++) {
- Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
- ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
- if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
- // try male
- Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
- ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
- }
- if (!cl_vwep->value)
- break; // only one when vwep is off
- }
-
- // icon file
- Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
- ci->icon = re.RegisterPic (ci->iconname);
- }
-
- // must have loaded all data types to be valud
- if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
- {
- ci->skin = NULL;
- ci->icon = NULL;
- ci->model = NULL;
- ci->weaponmodel[0] = NULL;
- return;
- }
-}
-
-/*
-================
-CL_ParseClientinfo
-
-Load the skin, icon, and model for a client
-================
-*/
-void CL_ParseClientinfo (int player)
-{
- char *s;
- clientinfo_t *ci;
-
- s = cl.configstrings[player+CS_PLAYERSKINS];
-
- ci = &cl.clientinfo[player];
-
- CL_LoadClientinfo (ci, s);
-}
-
-
-/*
-================
-CL_ParseConfigString
-================
-*/
-void CL_ParseConfigString (void)
-{
- int i;
- char *s;
-
- i = MSG_ReadShort (&net_message);
- if (i < 0 || i >= MAX_CONFIGSTRINGS)
- Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
- s = MSG_ReadString(&net_message);
- strcpy (cl.configstrings[i], s);
-
- // do something apropriate
-
- if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
- CL_SetLightstyle (i - CS_LIGHTS);
- else if (i == CS_CDTRACK)
- {
- if (cl.refresh_prepped)
- CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
- }
- else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS)
- {
- if (cl.refresh_prepped)
- {
- cl.model_draw[i-CS_MODELS] = re.RegisterModel (cl.configstrings[i]);
- if (cl.configstrings[i][0] == '*')
- cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
- else
- cl.model_clip[i-CS_MODELS] = NULL;
- }
- }
- else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)
- {
- if (cl.refresh_prepped)
- cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
- }
- else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS)
- {
- if (cl.refresh_prepped)
- cl.image_precache[i-CS_IMAGES] = re.RegisterPic (cl.configstrings[i]);
- }
- else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS)
- {
- if (cl.refresh_prepped)
- CL_ParseClientinfo (i-CS_PLAYERSKINS);
- }
-}
-
-
-/*
-=====================================================================
-
-ACTION MESSAGES
-
-=====================================================================
-*/
-
-/*
-==================
-CL_ParseStartSoundPacket
-==================
-*/
-void CL_ParseStartSoundPacket(void)
-{
- vec3_t pos_v;
- float *pos;
- int channel, ent;
- int sound_num;
- float volume;
- float attenuation;
- int flags;
- float ofs;
-
- flags = MSG_ReadByte (&net_message);
- sound_num = MSG_ReadByte (&net_message);
-
- if (flags & SND_VOLUME)
- volume = MSG_ReadByte (&net_message) / 255.0;
- else
- volume = DEFAULT_SOUND_PACKET_VOLUME;
-
- if (flags & SND_ATTENUATION)
- attenuation = MSG_ReadByte (&net_message) / 64.0;
- else
- attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
-
- if (flags & SND_OFFSET)
- ofs = MSG_ReadByte (&net_message) / 1000.0;
- else
- ofs = 0;
-
- if (flags & SND_ENT)
- { // entity reletive
- channel = MSG_ReadShort(&net_message);
- ent = channel>>3;
- if (ent > MAX_EDICTS)
- Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
-
- channel &= 7;
- }
- else
- {
- ent = 0;
- channel = 0;
- }
-
- if (flags & SND_POS)
- { // positioned in space
- MSG_ReadPos (&net_message, pos_v);
-
- pos = pos_v;
- }
- else // use entity number
- pos = NULL;
-
- if (!cl.sound_precache[sound_num])
- return;
-
- S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
-}
-
-
-void SHOWNET(char *s)
-{
- if (cl_shownet->value>=2)
- Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
-}
-
-/*
-=====================
-CL_ParseServerMessage
-=====================
-*/
-void CL_ParseServerMessage (void)
-{
- int cmd;
- char *s;
- int i;
-
-//
-// if recording demos, copy the message out
-//
- if (cl_shownet->value == 1)
- Com_Printf ("%i ",net_message.cursize);
- else if (cl_shownet->value >= 2)
- Com_Printf ("------------------\n");
-
-
-//
-// parse the message
-//
- while (1)
- {
- if (net_message.readcount > net_message.cursize)
- {
- Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
- break;
- }
-
- cmd = MSG_ReadByte (&net_message);
-
- if (cmd == -1)
- {
- SHOWNET("END OF MESSAGE");
- break;
- }
-
- if (cl_shownet->value>=2)
- {
- if (!svc_strings[cmd])
- Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
- else
- SHOWNET(svc_strings[cmd]);
- }
-
- // other commands
- switch (cmd)
- {
- default:
- Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
- break;
-
- case svc_nop:
-// Com_Printf ("svc_nop\n");
- break;
-
- case svc_disconnect:
- Com_Error (ERR_DISCONNECT,"Server disconnected\n");
- break;
-
- case svc_reconnect:
- Com_Printf ("Server disconnected, reconnecting\n");
- if (cls.download) {
- //ZOID, close download
- fclose (cls.download);
- cls.download = NULL;
- }
- cls.state = ca_connecting;
- cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
- break;
-
- case svc_print:
- i = MSG_ReadByte (&net_message);
- if (i == PRINT_CHAT)
- {
- S_StartLocalSound ("misc/talk.wav");
- con.ormask = 128;
- }
- Com_Printf ("%s", MSG_ReadString (&net_message));
- con.ormask = 0;
- break;
-
- case svc_centerprint:
- SCR_CenterPrint (MSG_ReadString (&net_message));
- break;
-
- case svc_stufftext:
- s = MSG_ReadString (&net_message);
- Com_DPrintf ("stufftext: %s\n", s);
- Cbuf_AddText (s);
- break;
-
- case svc_serverdata:
- Cbuf_Execute (); // make sure any stuffed commands are done
- CL_ParseServerData ();
- break;
-
- case svc_configstring:
- CL_ParseConfigString ();
- break;
-
- case svc_sound:
- CL_ParseStartSoundPacket();
- break;
-
- case svc_spawnbaseline:
- CL_ParseBaseline ();
- break;
-
- case svc_temp_entity:
- CL_ParseTEnt ();
- break;
-
- case svc_muzzleflash:
- CL_ParseMuzzleFlash ();
- break;
-
- case svc_muzzleflash2:
- CL_ParseMuzzleFlash2 ();
- break;
-
- case svc_download:
- CL_ParseDownload ();
- break;
-
- case svc_frame:
- CL_ParseFrame ();
- break;
-
- case svc_inventory:
- CL_ParseInventory ();
- break;
-
- case svc_layout:
- s = MSG_ReadString (&net_message);
- strncpy (cl.layout, s, sizeof(cl.layout)-1);
- break;
-
- case svc_playerinfo:
- case svc_packetentities:
- case svc_deltapacketentities:
- Com_Error (ERR_DROP, "Out of place frame data");
- break;
- }
- }
-
- CL_AddNetgraph ();
-
- //
- // we don't know if it is ok to save a demo message until
- // after we have parsed the frame
- //
- if (cls.demorecording && !cls.demowaiting)
- CL_WriteDemoMessage ();
-
-}
-
-
--- a/client/cl_pred.c
+++ /dev/null
@@ -1,259 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-
-/*
-===================
-CL_CheckPredictionError
-===================
-*/
-void CL_CheckPredictionError (void)
-{
- int frame;
- int delta[3];
- int i;
- int len;
-
- if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
- return;
-
- // calculate the last usercmd_t we sent that the server has processed
- frame = cls.netchan.incoming_acknowledged;
- frame &= (CMD_BACKUP-1);
-
- // compare what the server returned with what we had predicted it to be
- VectorSubtract (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame], delta);
-
- // save the prediction error for interpolation
- len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
- if (len > 640) // 80 world units
- { // a teleport or something
- VectorClear (cl.prediction_error);
- }
- else
- {
- if (cl_showmiss->value && (delta[0] || delta[1] || delta[2]) )
- Com_Printf ("prediction miss on %i: %i\n", cl.frame.serverframe,
- delta[0] + delta[1] + delta[2]);
-
- VectorCopy (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame]);
-
- // save for error itnerpolation
- for (i=0 ; i<3 ; i++)
- cl.prediction_error[i] = delta[i]*0.125;
- }
-}
-
-
-/*
-====================
-CL_ClipMoveToEntities
-
-====================
-*/
-void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
-{
- int i, x, zd, zu;
- trace_t trace;
- int headnode;
- float *angles;
- entity_state_t *ent;
- int num;
- cmodel_t *cmodel;
- vec3_t bmins, bmaxs;
-
- for (i=0 ; i<cl.frame.num_entities ; i++)
- {
- num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
- ent = &cl_parse_entities[num];
-
- if (!ent->solid)
- continue;
-
- if (ent->number == cl.playernum+1)
- continue;
-
- if (ent->solid == 31)
- { // special value for bmodel
- cmodel = cl.model_clip[ent->modelindex];
- if (!cmodel)
- continue;
- headnode = cmodel->headnode;
- angles = ent->angles;
- }
- else
- { // encoded bbox
- x = 8*(ent->solid & 31);
- zd = 8*((ent->solid>>5) & 31);
- zu = 8*((ent->solid>>10) & 63) - 32;
-
- bmins[0] = bmins[1] = -x;
- bmaxs[0] = bmaxs[1] = x;
- bmins[2] = -zd;
- bmaxs[2] = zu;
-
- headnode = CM_HeadnodeForBox (bmins, bmaxs);
- angles = vec3_origin; // boxes don't rotate
- }
-
- if (tr->allsolid)
- return;
-
- trace = CM_TransformedBoxTrace (start, end,
- mins, maxs, headnode, MASK_PLAYERSOLID,
- ent->origin, angles);
-
- if (trace.allsolid || trace.startsolid ||
- trace.fraction < tr->fraction)
- {
- trace.ent = (edict_t *)ent;
- if (tr->startsolid)
- {
- *tr = trace;
- tr->startsolid = true;
- }
- else
- *tr = trace;
- }
- else if (trace.startsolid)
- tr->startsolid = true;
- }
-}
-
-
-/*
-================
-CL_PMTrace
-================
-*/
-trace_t CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
-{
- trace_t t;
-
- // check against world
- t = CM_BoxTrace (start, end, mins, maxs, 0, MASK_PLAYERSOLID);
- if (t.fraction < 1.0)
- t.ent = (edict_t *)1;
-
- // check all other solid models
- CL_ClipMoveToEntities (start, mins, maxs, end, &t);
-
- return t;
-}
-
-int CL_PMpointcontents (vec3_t point)
-{
- int i;
- entity_state_t *ent;
- int num;
- cmodel_t *cmodel;
- int contents;
-
- contents = CM_PointContents (point, 0);
-
- for (i=0 ; i<cl.frame.num_entities ; i++)
- {
- num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
- ent = &cl_parse_entities[num];
-
- if (ent->solid != 31) // special value for bmodel
- continue;
-
- cmodel = cl.model_clip[ent->modelindex];
- if (!cmodel)
- continue;
-
- contents |= CM_TransformedPointContents (point, cmodel->headnode, ent->origin, ent->angles);
- }
-
- return contents;
-}
-
-
-/*
-=================
-CL_PredictMovement
-
-Sets cl.predicted_origin and cl.predicted_angles
-=================
-*/
-void CL_PredictMovement (void)
-{
- int ack, current;
- int frame;
- int oldframe;
- usercmd_t *cmd;
- pmove_t pm;
- int i;
- int step;
- int oldz;
-
- if (cls.state != ca_active)
- return;
-
- if (cl_paused->value)
- return;
-
- if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
- { // just set angles
- for (i=0 ; i<3 ; i++)
- {
- cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]);
- }
- return;
- }
-
- ack = cls.netchan.incoming_acknowledged;
- current = cls.netchan.outgoing_sequence;
-
- // if we are too far out of date, just freeze
- if (current - ack >= CMD_BACKUP)
- {
- if (cl_showmiss->value)
- Com_Printf ("exceeded CMD_BACKUP\n");
- return;
- }
-
- // copy current state to pmove
- memset (&pm, 0, sizeof(pm));
- pm.trace = CL_PMTrace;
- pm.pointcontents = CL_PMpointcontents;
-
- pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
-
- pm.s = cl.frame.playerstate.pmove;
-
-// SCR_DebugGraph (current - ack - 1, 0);
-
- // run frames
- while (++ack < current)
- {
- frame = ack & (CMD_BACKUP-1);
- cmd = &cl.cmds[frame];
-
- pm.cmd = *cmd;
- Pmove (&pm);
-
- // save for debug checking
- VectorCopy (pm.s.origin, cl.predicted_origins[frame]);
- }
-
- oldframe = (ack-2) & (CMD_BACKUP-1);
- oldz = cl.predicted_origins[oldframe][2];
- step = pm.s.origin[2] - oldz;
- if (step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND) )
- {
- cl.predicted_step = step * 0.125;
- cl.predicted_step_time = cls.realtime - cls.frametime * 500;
- }
-
-
- // copy results out for rendering
- cl.predicted_origin[0] = pm.s.origin[0]*0.125;
- cl.predicted_origin[1] = pm.s.origin[1]*0.125;
- cl.predicted_origin[2] = pm.s.origin[2]*0.125;
-
- VectorCopy (pm.viewangles, cl.predicted_angles);
-}
--- a/client/cl_scrn.c
+++ /dev/null
@@ -1,1381 +1,0 @@
-// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
-
-/*
-
- full screen console
- put up loading plaque
- blanked background with loading plaque
- blanked background with menu
- cinematics
- full screen image for quit and victory
-
- end of unit intermissions
-
- */
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-float scr_con_current; // aproaches scr_conlines at scr_conspeed
-float scr_conlines; // 0.0 to 1.0 lines of console to display
-
-qboolean scr_initialized; // ready to draw
-
-int scr_draw_loading;
-
-vrect_t scr_vrect; // position of render window on screen
-
-
-cvar_t *scr_viewsize;
-cvar_t *scr_conspeed;
-cvar_t *scr_centertime;
-cvar_t *scr_showturtle;
-cvar_t *scr_showpause;
-cvar_t *scr_printspeed;
-
-cvar_t *scr_netgraph;
-cvar_t *scr_timegraph;
-cvar_t *scr_debuggraph;
-cvar_t *scr_graphheight;
-cvar_t *scr_graphscale;
-cvar_t *scr_graphshift;
-cvar_t *scr_drawall;
-
-typedef struct
-{
- int x1, y1, x2, y2;
-} dirty_t;
-
-dirty_t scr_dirty, scr_old_dirty[2];
-
-char crosshair_pic[MAX_QPATH];
-int crosshair_width, crosshair_height;
-
-void SCR_TimeRefresh_f (void);
-void SCR_Loading_f (void);
-
-
-/*
-===============================================================================
-
-BAR GRAPHS
-
-===============================================================================
-*/
-
-/*
-==============
-CL_AddNetgraph
-
-A new packet was just parsed
-==============
-*/
-void CL_AddNetgraph (void)
-{
- int i;
- int in;
- int ping;
-
- // if using the debuggraph for something else, don't
- // add the net lines
- if (scr_debuggraph->value || scr_timegraph->value)
- return;
-
- for (i=0 ; i<cls.netchan.dropped ; i++)
- SCR_DebugGraph (30, 0x40);
-
- for (i=0 ; i<cl.surpressCount ; i++)
- SCR_DebugGraph (30, 0xdf);
-
- // see what the latency was on this packet
- in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
- ping = cls.realtime - cl.cmd_time[in];
- ping /= 30;
- if (ping > 30)
- ping = 30;
- SCR_DebugGraph (ping, 0xd0);
-}
-
-
-typedef struct
-{
- float value;
- int color;
-} graphsamp_t;
-
-static int current;
-static graphsamp_t values[1024];
-
-/*
-==============
-SCR_DebugGraph
-==============
-*/
-void SCR_DebugGraph (float value, int color)
-{
- values[current&1023].value = value;
- values[current&1023].color = color;
- current++;
-}
-
-/*
-==============
-SCR_DrawDebugGraph
-==============
-*/
-void SCR_DrawDebugGraph (void)
-{
- int a, x, y, w, i, h;
- float v;
- int color;
-
- //
- // draw the graph
- //
- w = scr_vrect.width;
-
- x = scr_vrect.x;
- y = scr_vrect.y+scr_vrect.height;
- re.DrawFill (x, y-scr_graphheight->value,
- w, scr_graphheight->value, 8);
-
- for (a=0 ; a<w ; a++)
- {
- i = (current-1-a+1024) & 1023;
- v = values[i].value;
- color = values[i].color;
- v = v*scr_graphscale->value + scr_graphshift->value;
-
- if (v < 0)
- v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
- h = (int)v % (int)scr_graphheight->value;
- re.DrawFill (x+w-1-a, y - h, 1, h, color);
- }
-}
-
-/*
-===============================================================================
-
-CENTER PRINTING
-
-===============================================================================
-*/
-
-char scr_centerstring[1024];
-float scr_centertime_start; // for slow victory printing
-float scr_centertime_off;
-int scr_center_lines;
-int scr_erase_center;
-
-/*
-==============
-SCR_CenterPrint
-
-Called for important messages that should stay in the center of the screen
-for a few moments
-==============
-*/
-void SCR_CenterPrint (char *str)
-{
- char *s;
- char line[64];
- int i, j, l;
-
- strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
- scr_centertime_off = scr_centertime->value;
- scr_centertime_start = cl.time;
-
- // count the number of lines for centering
- scr_center_lines = 1;
- s = str;
- while (*s)
- {
- if (*s == '\n')
- scr_center_lines++;
- s++;
- }
-
- // echo it to the console
- Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
-
- s = str;
- do
- {
- // scan the width of the line
- for (l=0 ; l<40 ; l++)
- if (s[l] == '\n' || !s[l])
- break;
- for (i=0 ; i<(40-l)/2 ; i++)
- line[i] = ' ';
-
- for (j=0 ; j<l ; j++)
- {
- line[i++] = s[j];
- }
-
- line[i] = '\n';
- line[i+1] = 0;
-
- Com_Printf ("%s", line);
-
- while (*s && *s != '\n')
- s++;
-
- if (!*s)
- break;
- s++; // skip the \n
- } while (1);
- Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
- Con_ClearNotify ();
-}
-
-
-void SCR_DrawCenterString (void)
-{
- char *start;
- int l;
- int j;
- int x, y;
- int remaining;
-
-// the finale prints the characters one at a time
- remaining = 9999;
-
- scr_erase_center = 0;
- start = scr_centerstring;
-
- if (scr_center_lines <= 4)
- y = vid.height*0.35;
- else
- y = 48;
-
- do
- {
- // scan the width of the line
- for (l=0 ; l<40 ; l++)
- if (start[l] == '\n' || !start[l])
- break;
- x = (vid.width - l*8)/2;
- SCR_AddDirtyPoint (x, y);
- for (j=0 ; j<l ; j++, x+=8)
- {
- re.DrawChar (x, y, start[j]);
- if (!remaining--)
- return;
- }
- SCR_AddDirtyPoint (x, y+8);
-
- y += 8;
-
- while (*start && *start != '\n')
- start++;
-
- if (!*start)
- break;
- start++; // skip the \n
- } while (1);
-}
-
-void SCR_CheckDrawCenterString (void)
-{
- scr_centertime_off -= cls.frametime;
-
- if (scr_centertime_off <= 0)
- return;
-
- SCR_DrawCenterString ();
-}
-
-//=============================================================================
-
-/*
-=================
-SCR_CalcVrect
-
-Sets scr_vrect, the coordinates of the rendered window
-=================
-*/
-static void SCR_CalcVrect (void)
-{
- int size;
-
- // bound viewsize
- if (scr_viewsize->value < 40)
- Cvar_Set ("viewsize","40");
- if (scr_viewsize->value > 100)
- Cvar_Set ("viewsize","100");
-
- size = scr_viewsize->value;
-
- scr_vrect.width = vid.width*size/100;
- scr_vrect.width &= ~7;
-
- scr_vrect.height = vid.height*size/100;
- scr_vrect.height &= ~1;
-
- scr_vrect.x = (vid.width - scr_vrect.width)/2;
- scr_vrect.y = (vid.height - scr_vrect.height)/2;
-}
-
-
-/*
-=================
-SCR_SizeUp_f
-
-Keybinding command
-=================
-*/
-void SCR_SizeUp_f (void)
-{
- Cvar_SetValue ("viewsize",scr_viewsize->value+10);
-}
-
-
-/*
-=================
-SCR_SizeDown_f
-
-Keybinding command
-=================
-*/
-void SCR_SizeDown_f (void)
-{
- Cvar_SetValue ("viewsize",scr_viewsize->value-10);
-}
-
-/*
-=================
-SCR_Sky_f
-
-Set a specific sky and rotation speed
-=================
-*/
-void SCR_Sky_f (void)
-{
- float rotate;
- vec3_t axis;
-
- if (Cmd_Argc() < 2)
- {
- Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
- return;
- }
- if (Cmd_Argc() > 2)
- rotate = atof(Cmd_Argv(2));
- else
- rotate = 0;
- if (Cmd_Argc() == 6)
- {
- axis[0] = atof(Cmd_Argv(3));
- axis[1] = atof(Cmd_Argv(4));
- axis[2] = atof(Cmd_Argv(5));
- }
- else
- {
- axis[0] = 0;
- axis[1] = 0;
- axis[2] = 1;
- }
-
- re.SetSky (Cmd_Argv(1), rotate, axis);
-}
-
-//============================================================================
-
-/*
-==================
-SCR_Init
-==================
-*/
-void SCR_Init (void)
-{
- scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
- scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
- scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
- scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
- scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
- scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
- scr_netgraph = Cvar_Get ("netgraph", "0", 0);
- scr_timegraph = Cvar_Get ("timegraph", "0", 0);
- scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
- scr_graphheight = Cvar_Get ("graphheight", "32", 0);
- scr_graphscale = Cvar_Get ("graphscale", "1", 0);
- scr_graphshift = Cvar_Get ("graphshift", "0", 0);
- scr_drawall = Cvar_Get ("scr_drawall", "0", 0);
-
-//
-// register our commands
-//
- Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
- Cmd_AddCommand ("loading",SCR_Loading_f);
- Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
- Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
- Cmd_AddCommand ("sky",SCR_Sky_f);
-
- scr_initialized = true;
-}
-
-
-/*
-==============
-SCR_DrawNet
-==============
-*/
-void SCR_DrawNet (void)
-{
- if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged
- < CMD_BACKUP-1)
- return;
-
- re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");
-}
-
-/*
-==============
-SCR_DrawPause
-==============
-*/
-void SCR_DrawPause (void)
-{
- int w, h;
-
- if (!scr_showpause->value) // turn off for screenshots
- return;
-
- if (!cl_paused->value)
- return;
-
- re.DrawGetPicSize (&w, &h, "pause");
- re.DrawPic ((vid.width-w)/2, vid.height/2 + 8, "pause");
-}
-
-/*
-==============
-SCR_DrawLoading
-==============
-*/
-void SCR_DrawLoading (void)
-{
- int w, h;
-
- if (!scr_draw_loading)
- return;
-
- scr_draw_loading = false;
- re.DrawGetPicSize (&w, &h, "loading");
- re.DrawPic ((vid.width-w)/2, (vid.height-h)/2, "loading");
-}
-
-//=============================================================================
-
-/*
-==================
-SCR_RunConsole
-
-Scroll it up or down
-==================
-*/
-void SCR_RunConsole (void)
-{
-// decide on the height of the console
- if (cls.key_dest == key_console)
- scr_conlines = 0.5; // half screen
- else
- scr_conlines = 0; // none visible
-
- if (scr_conlines < scr_con_current)
- {
- scr_con_current -= scr_conspeed->value*cls.frametime;
- if (scr_conlines > scr_con_current)
- scr_con_current = scr_conlines;
-
- }
- else if (scr_conlines > scr_con_current)
- {
- scr_con_current += scr_conspeed->value*cls.frametime;
- if (scr_conlines < scr_con_current)
- scr_con_current = scr_conlines;
- }
-
-}
-
-/*
-==================
-SCR_DrawConsole
-==================
-*/
-void SCR_DrawConsole (void)
-{
- Con_CheckResize ();
-
- if (cls.state == ca_disconnected || cls.state == ca_connecting)
- { // forced full screen console
- Con_DrawConsole (1.0);
- return;
- }
-
- if (cls.state != ca_active || !cl.refresh_prepped)
- { // connected, but can't render
- Con_DrawConsole (0.5);
- re.DrawFill (0, vid.height/2, vid.width, vid.height/2, 0);
- return;
- }
-
- if (scr_con_current)
- {
- Con_DrawConsole (scr_con_current);
- }
- else
- {
- if (cls.key_dest == key_game || cls.key_dest == key_message)
- Con_DrawNotify (); // only draw notify in game
- }
-}
-
-//=============================================================================
-
-/*
-================
-SCR_BeginLoadingPlaque
-================
-*/
-void SCR_BeginLoadingPlaque (void)
-{
- S_StopAllSounds ();
- cl.sound_prepped = false; // don't play ambients
- CDAudio_Stop ();
- if (cls.disable_screen)
- return;
- if (developer->value)
- return;
- if (cls.state == ca_disconnected)
- return; // if at console, don't bring up the plaque
- if (cls.key_dest == key_console)
- return;
- if (cl.cinematictime > 0)
- scr_draw_loading = 2; // clear to balack first
- else
- scr_draw_loading = 1;
- SCR_UpdateScreen ();
- cls.disable_screen = Sys_Milliseconds ();
- cls.disable_servercount = cl.servercount;
-}
-
-/*
-================
-SCR_EndLoadingPlaque
-================
-*/
-void SCR_EndLoadingPlaque (void)
-{
- cls.disable_screen = 0;
- Con_ClearNotify ();
-}
-
-/*
-================
-SCR_Loading_f
-================
-*/
-void SCR_Loading_f (void)
-{
- SCR_BeginLoadingPlaque ();
-}
-
-/*
-================
-SCR_TimeRefresh_f
-================
-*/
-int entitycmpfnc( const entity_t *a, const entity_t *b )
-{
- /*
- ** all other models are sorted by model then skin
- */
- if ( a->model == b->model )
- {
- return (uintptr)a->skin - (uintptr)b->skin;
- }
- else
- {
- return (uintptr)a->model - (uintptr)b->model;
- }
-}
-
-void SCR_TimeRefresh_f (void)
-{
- int i;
- int start, stop;
- float time;
-
- if ( cls.state != ca_active )
- return;
-
- start = Sys_Milliseconds ();
-
- if (Cmd_Argc() == 2)
- { // run without page flipping
- re.BeginFrame( 0 );
- for (i=0 ; i<128 ; i++)
- {
- cl.refdef.viewangles[1] = i/128.0*360.0;
- re.RenderFrame (&cl.refdef);
- }
- re.EndFrame();
- }
- else
- {
- for (i=0 ; i<128 ; i++)
- {
- cl.refdef.viewangles[1] = i/128.0*360.0;
-
- re.BeginFrame( 0 );
- re.RenderFrame (&cl.refdef);
- re.EndFrame();
- }
- }
-
- stop = Sys_Milliseconds ();
- time = (stop-start)/1000.0;
- Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
-}
-
-/*
-=================
-SCR_AddDirtyPoint
-=================
-*/
-void SCR_AddDirtyPoint (int x, int y)
-{
- if (x < scr_dirty.x1)
- scr_dirty.x1 = x;
- if (x > scr_dirty.x2)
- scr_dirty.x2 = x;
- if (y < scr_dirty.y1)
- scr_dirty.y1 = y;
- if (y > scr_dirty.y2)
- scr_dirty.y2 = y;
-}
-
-void SCR_DirtyScreen (void)
-{
- SCR_AddDirtyPoint (0, 0);
- SCR_AddDirtyPoint (vid.width-1, vid.height-1);
-}
-
-/*
-==============
-SCR_TileClear
-
-Clear any parts of the tiled background that were drawn on last frame
-==============
-*/
-void SCR_TileClear (void)
-{
- int i;
- int top, bottom, left, right;
- dirty_t clear;
-
- if (scr_drawall->value)
- SCR_DirtyScreen (); // for power vr or broken page flippers...
-
- if (scr_con_current == 1.0)
- return; // full screen console
- if (scr_viewsize->value == 100)
- return; // full screen rendering
- if (cl.cinematictime > 0)
- return; // full screen cinematic
-
- // erase rect will be the union of the past three frames
- // so tripple buffering works properly
- clear = scr_dirty;
- for (i=0 ; i<2 ; i++)
- {
- if (scr_old_dirty[i].x1 < clear.x1)
- clear.x1 = scr_old_dirty[i].x1;
- if (scr_old_dirty[i].x2 > clear.x2)
- clear.x2 = scr_old_dirty[i].x2;
- if (scr_old_dirty[i].y1 < clear.y1)
- clear.y1 = scr_old_dirty[i].y1;
- if (scr_old_dirty[i].y2 > clear.y2)
- clear.y2 = scr_old_dirty[i].y2;
- }
-
- scr_old_dirty[1] = scr_old_dirty[0];
- scr_old_dirty[0] = scr_dirty;
-
- scr_dirty.x1 = 9999;
- scr_dirty.x2 = -9999;
- scr_dirty.y1 = 9999;
- scr_dirty.y2 = -9999;
-
- // don't bother with anything convered by the console)
- top = scr_con_current*vid.height;
- if (top >= clear.y1)
- clear.y1 = top;
-
- if (clear.y2 <= clear.y1)
- return; // nothing disturbed
-
- top = scr_vrect.y;
- bottom = top + scr_vrect.height-1;
- left = scr_vrect.x;
- right = left + scr_vrect.width-1;
-
- if (clear.y1 < top)
- { // clear above view screen
- i = clear.y2 < top-1 ? clear.y2 : top-1;
- re.DrawTileClear (clear.x1 , clear.y1,
- clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
- clear.y1 = top;
- }
- if (clear.y2 > bottom)
- { // clear below view screen
- i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
- re.DrawTileClear (clear.x1, i,
- clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
- clear.y2 = bottom;
- }
- if (clear.x1 < left)
- { // clear left of view screen
- i = clear.x2 < left-1 ? clear.x2 : left-1;
- re.DrawTileClear (clear.x1, clear.y1,
- i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
- clear.x1 = left;
- }
- if (clear.x2 > right)
- { // clear left of view screen
- i = clear.x1 > right+1 ? clear.x1 : right+1;
- re.DrawTileClear (i, clear.y1,
- clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
- clear.x2 = right;
- }
-
-}
-
-
-//===============================================================
-
-
-#define STAT_MINUS 10 // num frame for '-' stats digit
-char *sb_nums[2][11] =
-{
- {"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
- "num_6", "num_7", "num_8", "num_9", "num_minus"},
- {"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
- "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
-};
-
-#define ICON_WIDTH 24
-#define ICON_HEIGHT 24
-#define CHAR_WIDTH 16
-#define ICON_SPACE 8
-
-
-
-/*
-================
-SizeHUDString
-
-Allow embedded \n in the string
-================
-*/
-void SizeHUDString (char *string, int *w, int *h)
-{
- int lines, width, current;
-
- lines = 1;
- width = 0;
-
- current = 0;
- while (*string)
- {
- if (*string == '\n')
- {
- lines++;
- current = 0;
- }
- else
- {
- current++;
- if (current > width)
- width = current;
- }
- string++;
- }
-
- *w = width * 8;
- *h = lines * 8;
-}
-
-void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)
-{
- int margin;
- char line[1024];
- int width;
- int i;
-
- margin = x;
-
- while (*string)
- {
- // scan out one line of text from the string
- width = 0;
- while (*string && *string != '\n')
- line[width++] = *string++;
- line[width] = 0;
-
- if (centerwidth)
- x = margin + (centerwidth - width*8)/2;
- else
- x = margin;
- for (i=0 ; i<width ; i++)
- {
- re.DrawChar (x, y, line[i]^xor);
- x += 8;
- }
- if (*string)
- {
- string++; // skip the \n
- y += 8;
- }
- }
-}
-
-
-/*
-==============
-SCR_DrawField
-==============
-*/
-void SCR_DrawField (int x, int y, int color, int width, int value)
-{
- char num[16], *ptr;
- int l;
- int frame;
-
- if (width < 1)
- return;
-
- // draw number string
- if (width > 5)
- width = 5;
-
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);
-
- Com_sprintf (num, sizeof(num), "%i", value);
- l = strlen(num);
- if (l > width)
- l = width;
- x += 2 + CHAR_WIDTH*(width - l);
-
- ptr = num;
- while (*ptr && l)
- {
- if (*ptr == '-')
- frame = STAT_MINUS;
- else
- frame = *ptr -'0';
-
- re.DrawPic (x,y,sb_nums[color][frame]);
- x += CHAR_WIDTH;
- ptr++;
- l--;
- }
-}
-
-
-/*
-===============
-SCR_TouchPics
-
-Allows rendering code to cache all needed sbar graphics
-===============
-*/
-void SCR_TouchPics (void)
-{
- int i, j;
-
- for (i=0 ; i<2 ; i++)
- for (j=0 ; j<11 ; j++)
- re.RegisterPic (sb_nums[i][j]);
-
- if (crosshair->value)
- {
- if (crosshair->value > 3 || crosshair->value < 0)
- crosshair->value = 3;
-
- Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));
- re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
- if (!crosshair_width)
- crosshair_pic[0] = 0;
- }
-}
-
-/*
-================
-SCR_ExecuteLayoutString
-
-================
-*/
-void SCR_ExecuteLayoutString (char *s)
-{
- int x, y;
- int value;
- char *token;
- int width;
- int index;
- clientinfo_t *ci;
-
- if (cls.state != ca_active || !cl.refresh_prepped)
- return;
-
- if (!s[0])
- return;
-
- x = 0;
- y = 0;
-
- while (s)
- {
- token = COM_Parse (&s);
- if (!strcmp(token, "xl"))
- {
- token = COM_Parse (&s);
- x = atoi(token);
- continue;
- }
- if (!strcmp(token, "xr"))
- {
- token = COM_Parse (&s);
- x = vid.width + atoi(token);
- continue;
- }
- if (!strcmp(token, "xv"))
- {
- token = COM_Parse (&s);
- x = vid.width/2 - 160 + atoi(token);
- continue;
- }
-
- if (!strcmp(token, "yt"))
- {
- token = COM_Parse (&s);
- y = atoi(token);
- continue;
- }
- if (!strcmp(token, "yb"))
- {
- token = COM_Parse (&s);
- y = vid.height + atoi(token);
- continue;
- }
- if (!strcmp(token, "yv"))
- {
- token = COM_Parse (&s);
- y = vid.height/2 - 120 + atoi(token);
- continue;
- }
-
- if (!strcmp(token, "pic"))
- { // draw a pic from a stat number
- token = COM_Parse (&s);
- value = cl.frame.playerstate.stats[atoi(token)];
- if (value >= MAX_IMAGES)
- Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
- if (cl.configstrings[CS_IMAGES+value])
- {
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+23, y+23);
- re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
- }
- continue;
- }
-
- if (!strcmp(token, "client"))
- { // draw a deathmatch client block
- int score, ping, time;
-
- token = COM_Parse (&s);
- x = vid.width/2 - 160 + atoi(token);
- token = COM_Parse (&s);
- y = vid.height/2 - 120 + atoi(token);
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+159, y+31);
-
- token = COM_Parse (&s);
- value = atoi(token);
- if (value >= MAX_CLIENTS || value < 0)
- Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
- ci = &cl.clientinfo[value];
-
- token = COM_Parse (&s);
- score = atoi(token);
-
- token = COM_Parse (&s);
- ping = atoi(token);
-
- token = COM_Parse (&s);
- time = atoi(token);
-
- DrawAltString (x+32, y, ci->name);
- DrawString (x+32, y+8, "Score: ");
- DrawAltString (x+32+7*8, y+8, va("%i", score));
- DrawString (x+32, y+16, va("Ping: %i", ping));
- DrawString (x+32, y+24, va("Time: %i", time));
-
- if (!ci->icon)
- ci = &cl.baseclientinfo;
- re.DrawPic (x, y, ci->iconname);
- continue;
- }
-
- if (!strcmp(token, "ctf"))
- { // draw a ctf client block
- int score, ping;
- char block[80];
-
- token = COM_Parse (&s);
- x = vid.width/2 - 160 + atoi(token);
- token = COM_Parse (&s);
- y = vid.height/2 - 120 + atoi(token);
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+159, y+31);
-
- token = COM_Parse (&s);
- value = atoi(token);
- if (value >= MAX_CLIENTS || value < 0)
- Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
- ci = &cl.clientinfo[value];
-
- token = COM_Parse (&s);
- score = atoi(token);
-
- token = COM_Parse (&s);
- ping = atoi(token);
- if (ping > 999)
- ping = 999;
-
- sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
-
- if (value == cl.playernum)
- DrawAltString (x, y, block);
- else
- DrawString (x, y, block);
- continue;
- }
-
- if (!strcmp(token, "picn"))
- { // draw a pic from a name
- token = COM_Parse (&s);
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+23, y+23);
- re.DrawPic (x, y, token);
- continue;
- }
-
- if (!strcmp(token, "num"))
- { // draw a number
- token = COM_Parse (&s);
- width = atoi(token);
- token = COM_Parse (&s);
- value = cl.frame.playerstate.stats[atoi(token)];
- SCR_DrawField (x, y, 0, width, value);
- continue;
- }
-
- if (!strcmp(token, "hnum"))
- { // health number
- int color;
-
- width = 3;
- value = cl.frame.playerstate.stats[STAT_HEALTH];
- if (value > 25)
- color = 0; // green
- else if (value > 0)
- color = (cl.frame.serverframe>>2) & 1; // flash
- else
- color = 1;
-
- if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)
- re.DrawPic (x, y, "field_3");
-
- SCR_DrawField (x, y, color, width, value);
- continue;
- }
-
- if (!strcmp(token, "anum"))
- { // ammo number
- int color;
-
- width = 3;
- value = cl.frame.playerstate.stats[STAT_AMMO];
- if (value > 5)
- color = 0; // green
- else if (value >= 0)
- color = (cl.frame.serverframe>>2) & 1; // flash
- else
- continue; // negative number = don't show
-
- if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)
- re.DrawPic (x, y, "field_3");
-
- SCR_DrawField (x, y, color, width, value);
- continue;
- }
-
- if (!strcmp(token, "rnum"))
- { // armor number
- int color;
-
- width = 3;
- value = cl.frame.playerstate.stats[STAT_ARMOR];
- if (value < 1)
- continue;
-
- color = 0; // green
-
- if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)
- re.DrawPic (x, y, "field_3");
-
- SCR_DrawField (x, y, color, width, value);
- continue;
- }
-
-
- if (!strcmp(token, "stat_string"))
- {
- token = COM_Parse (&s);
- index = atoi(token);
- if (index < 0 || index >= MAX_CONFIGSTRINGS)
- Com_Error (ERR_DROP, "Bad stat_string index");
- index = cl.frame.playerstate.stats[index];
- if (index < 0 || index >= MAX_CONFIGSTRINGS)
- Com_Error (ERR_DROP, "Bad stat_string index");
- DrawString (x, y, cl.configstrings[index]);
- continue;
- }
-
- if (!strcmp(token, "cstring"))
- {
- token = COM_Parse (&s);
- DrawHUDString (token, x, y, 320, 0);
- continue;
- }
-
- if (!strcmp(token, "string"))
- {
- token = COM_Parse (&s);
- DrawString (x, y, token);
- continue;
- }
-
- if (!strcmp(token, "cstring2"))
- {
- token = COM_Parse (&s);
- DrawHUDString (token, x, y, 320,0x80);
- continue;
- }
-
- if (!strcmp(token, "string2"))
- {
- token = COM_Parse (&s);
- DrawAltString (x, y, token);
- continue;
- }
-
- if (!strcmp(token, "if"))
- { // draw a number
- token = COM_Parse (&s);
- value = cl.frame.playerstate.stats[atoi(token)];
- if (!value)
- { // skip to endif
- while (s && strcmp(token, "endif") )
- {
- token = COM_Parse (&s);
- }
- }
-
- continue;
- }
-
-
- }
-}
-
-
-/*
-================
-SCR_DrawStats
-
-The status bar is a small layout program that
-is based on the stats array
-================
-*/
-void SCR_DrawStats (void)
-{
- SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
-}
-
-
-/*
-================
-SCR_DrawLayout
-
-================
-*/
-void SCR_DrawLayout (void)
-{
- if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
- return;
- SCR_ExecuteLayoutString (cl.layout);
-}
-
-//=======================================================
-
-/*
-==================
-SCR_UpdateScreen
-
-This is called every frame, and can also be called explicitly to flush
-text to the screen.
-==================
-*/
-void SCR_UpdateScreen (void)
-{
- int numframes;
- int i;
- float separation[2] = { 0, 0 };
-
- // if the screen is disabled (loading plaque is up, or vid mode changing)
- // do nothing at all
- if (cls.disable_screen)
- {
- if (Sys_Milliseconds() - cls.disable_screen > 120000)
- {
- cls.disable_screen = 0;
- Com_Printf ("Loading plaque timed out.\n");
- }
- return;
- }
-
- if (!scr_initialized || !con.initialized)
- return; // not initialized yet
-
- /*
- ** range check cl_camera_separation so we don't inadvertently fry someone's
- ** brain
- */
- if ( cl_stereo_separation->value > 1.0 )
- Cvar_SetValue( "cl_stereo_separation", 1.0 );
- else if ( cl_stereo_separation->value < 0 )
- Cvar_SetValue( "cl_stereo_separation", 0.0 );
-
- if ( cl_stereo->value )
- {
- numframes = 2;
- separation[0] = -cl_stereo_separation->value / 2;
- separation[1] = cl_stereo_separation->value / 2;
- }
- else
- {
- separation[0] = 0;
- separation[1] = 0;
- numframes = 1;
- }
-
- for ( i = 0; i < numframes; i++ )
- {
- re.BeginFrame( separation[i] );
-
- if (scr_draw_loading == 2)
- { // loading plaque over black screen
- int w, h;
-
- re.CinematicSetPalette(NULL);
- scr_draw_loading = false;
- re.DrawGetPicSize (&w, &h, "loading");
- re.DrawPic ((vid.width-w)/2, (vid.height-h)/2, "loading");
-// re.EndFrame();
-// return;
- }
- // if a cinematic is supposed to be running, handle menus
- // and console specially
- else if (cl.cinematictime > 0)
- {
- if (cls.key_dest == key_menu)
- {
- if (cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- }
- M_Draw ();
-// re.EndFrame();
-// return;
- }
- else if (cls.key_dest == key_console)
- {
- if (cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- }
- SCR_DrawConsole ();
-// re.EndFrame();
-// return;
- }
- else
- {
- SCR_DrawCinematic();
-// re.EndFrame();
-// return;
- }
- }
- else
- {
-
- // make sure the game palette is active
- if (cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- }
-
- // do 3D refresh drawing, and then update the screen
- SCR_CalcVrect ();
-
- // clear any dirty part of the background
- SCR_TileClear ();
-
- V_RenderView ( separation[i] );
-
- SCR_DrawStats ();
- if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
- SCR_DrawLayout ();
- if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
- CL_DrawInventory ();
-
- SCR_DrawNet ();
- SCR_CheckDrawCenterString ();
-
- if (scr_timegraph->value)
- SCR_DebugGraph (cls.frametime*300, 0);
-
- if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
- SCR_DrawDebugGraph ();
-
- SCR_DrawPause ();
-
- SCR_DrawConsole ();
-
- M_Draw ();
-
- SCR_DrawLoading ();
- }
- }
- re.EndFrame();
-}
--- a/client/cl_tent.c
+++ /dev/null
@@ -1,1729 +1,0 @@
-// cl_tent.c -- client side temporary entities
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-typedef enum
-{
- ex_free, ex_explosion, ex_misc, ex_flash, ex_mflash, ex_poly, ex_poly2
-} exptype_t;
-
-typedef struct
-{
- exptype_t type;
- entity_t ent;
-
- int frames;
- float light;
- vec3_t lightcolor;
- float start;
- int baseframe;
-} explosion_t;
-
-
-
-#define MAX_EXPLOSIONS 32
-explosion_t cl_explosions[MAX_EXPLOSIONS];
-
-
-#define MAX_BEAMS 32
-typedef struct
-{
- int entity;
- int dest_entity;
- struct model_s *model;
- int endtime;
- vec3_t offset;
- vec3_t start, end;
-} beam_t;
-beam_t cl_beams[MAX_BEAMS];
-//PMM - added this for player-linked beams. Currently only used by the plasma beam
-beam_t cl_playerbeams[MAX_BEAMS];
-
-
-#define MAX_LASERS 32
-typedef struct
-{
- entity_t ent;
- int endtime;
-} laser_t;
-laser_t cl_lasers[MAX_LASERS];
-
-//ROGUE
-cl_sustain_t cl_sustains[MAX_SUSTAINS];
-//ROGUE
-
-//PGM
-extern void CL_TeleportParticles (vec3_t org);
-//PGM
-
-void CL_BlasterParticles (vec3_t org, vec3_t dir);
-void CL_ExplosionParticles (vec3_t org);
-void CL_BFGExplosionParticles (vec3_t org);
-// RAFAEL
-void CL_BlueBlasterParticles (vec3_t org, vec3_t dir);
-
-struct sfx_s *cl_sfx_ric1;
-struct sfx_s *cl_sfx_ric2;
-struct sfx_s *cl_sfx_ric3;
-struct sfx_s *cl_sfx_lashit;
-struct sfx_s *cl_sfx_spark5;
-struct sfx_s *cl_sfx_spark6;
-struct sfx_s *cl_sfx_spark7;
-struct sfx_s *cl_sfx_railg;
-struct sfx_s *cl_sfx_rockexp;
-struct sfx_s *cl_sfx_grenexp;
-struct sfx_s *cl_sfx_watrexp;
-// RAFAEL
-struct sfx_s *cl_sfx_plasexp;
-struct sfx_s *cl_sfx_footsteps[4];
-
-struct model_s *cl_mod_explode;
-struct model_s *cl_mod_smoke;
-struct model_s *cl_mod_flash;
-struct model_s *cl_mod_parasite_segment;
-struct model_s *cl_mod_grapple_cable;
-struct model_s *cl_mod_parasite_tip;
-struct model_s *cl_mod_explo4;
-struct model_s *cl_mod_bfg_explo;
-struct model_s *cl_mod_powerscreen;
-// RAFAEL
-struct model_s *cl_mod_plasmaexplo;
-
-//ROGUE
-struct sfx_s *cl_sfx_lightning;
-struct sfx_s *cl_sfx_disrexp;
-struct model_s *cl_mod_lightning;
-struct model_s *cl_mod_heatbeam;
-struct model_s *cl_mod_monster_heatbeam;
-struct model_s *cl_mod_explo4_big;
-
-//ROGUE
-/*
-=================
-CL_RegisterTEntSounds
-=================
-*/
-void CL_RegisterTEntSounds (void)
-{
- int i;
- char name[MAX_QPATH];
-
- // PMM - version stuff
-// Com_Printf ("%s\n", ROGUE_VERSION_STRING);
- // PMM
- cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav");
- cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav");
- cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav");
- cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav");
- cl_sfx_spark5 = S_RegisterSound ("world/spark5.wav");
- cl_sfx_spark6 = S_RegisterSound ("world/spark6.wav");
- cl_sfx_spark7 = S_RegisterSound ("world/spark7.wav");
- cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav");
- cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav");
- cl_sfx_grenexp = S_RegisterSound ("weapons/grenlx1a.wav");
- cl_sfx_watrexp = S_RegisterSound ("weapons/xpld_wat.wav");
- // RAFAEL
- // cl_sfx_plasexp = S_RegisterSound ("weapons/plasexpl.wav");
- S_RegisterSound ("player/land1.wav");
-
- S_RegisterSound ("player/fall2.wav");
- S_RegisterSound ("player/fall1.wav");
-
- for (i=0 ; i<4 ; i++)
- {
- Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
- cl_sfx_footsteps[i] = S_RegisterSound (name);
- }
-
-//PGM
- cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav");
- cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav");
- // version stuff
- sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID);
- if (name[0] == 'w')
- name[0] = 'W';
-//PGM
-}
-
-/*
-=================
-CL_RegisterTEntModels
-=================
-*/
-void CL_RegisterTEntModels (void)
-{
- cl_mod_explode = re.RegisterModel ("models/objects/explode/tris.md2");
- cl_mod_smoke = re.RegisterModel ("models/objects/smoke/tris.md2");
- cl_mod_flash = re.RegisterModel ("models/objects/flash/tris.md2");
- cl_mod_parasite_segment = re.RegisterModel ("models/monsters/parasite/segment/tris.md2");
- cl_mod_grapple_cable = re.RegisterModel ("models/ctf/segment/tris.md2");
- cl_mod_parasite_tip = re.RegisterModel ("models/monsters/parasite/tip/tris.md2");
- cl_mod_explo4 = re.RegisterModel ("models/objects/r_explode/tris.md2");
- cl_mod_bfg_explo = re.RegisterModel ("sprites/s_bfg2.sp2");
- cl_mod_powerscreen = re.RegisterModel ("models/items/armor/effect/tris.md2");
-
-re.RegisterModel ("models/objects/laser/tris.md2");
-re.RegisterModel ("models/objects/grenade2/tris.md2");
-re.RegisterModel ("models/weapons/v_machn/tris.md2");
-re.RegisterModel ("models/weapons/v_handgr/tris.md2");
-re.RegisterModel ("models/weapons/v_shotg2/tris.md2");
-re.RegisterModel ("models/objects/gibs/bone/tris.md2");
-re.RegisterModel ("models/objects/gibs/sm_meat/tris.md2");
-re.RegisterModel ("models/objects/gibs/bone2/tris.md2");
-// RAFAEL
-// re.RegisterModel ("models/objects/blaser/tris.md2");
-
-re.RegisterPic ("w_machinegun");
-re.RegisterPic ("a_bullets");
-re.RegisterPic ("i_health");
-re.RegisterPic ("a_grenades");
-
-//ROGUE
- cl_mod_explo4_big = re.RegisterModel ("models/objects/r_explode2/tris.md2");
- cl_mod_lightning = re.RegisterModel ("models/proj/lightning/tris.md2");
- cl_mod_heatbeam = re.RegisterModel ("models/proj/beam/tris.md2");
- cl_mod_monster_heatbeam = re.RegisterModel ("models/proj/widowbeam/tris.md2");
-//ROGUE
-}
-
-/*
-=================
-CL_ClearTEnts
-=================
-*/
-void CL_ClearTEnts (void)
-{
- memset (cl_beams, 0, sizeof(cl_beams));
- memset (cl_explosions, 0, sizeof(cl_explosions));
- memset (cl_lasers, 0, sizeof(cl_lasers));
-
-//ROGUE
- memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
- memset (cl_sustains, 0, sizeof(cl_sustains));
-//ROGUE
-}
-
-/*
-=================
-CL_AllocExplosion
-=================
-*/
-explosion_t *CL_AllocExplosion (void)
-{
- int i;
- int time;
- int index;
-
- for (i=0 ; i<MAX_EXPLOSIONS ; i++)
- {
- if (cl_explosions[i].type == ex_free)
- {
- memset (&cl_explosions[i], 0, sizeof (cl_explosions[i]));
- return &cl_explosions[i];
- }
- }
-// find the oldest explosion
- time = cl.time;
- index = 0;
-
- for (i=0 ; i<MAX_EXPLOSIONS ; i++)
- if (cl_explosions[i].start < time)
- {
- time = cl_explosions[i].start;
- index = i;
- }
- memset (&cl_explosions[index], 0, sizeof (cl_explosions[index]));
- return &cl_explosions[index];
-}
-
-/*
-=================
-CL_SmokeAndFlash
-=================
-*/
-void CL_SmokeAndFlash(vec3_t origin)
-{
- explosion_t *ex;
-
- ex = CL_AllocExplosion ();
- VectorCopy (origin, ex->ent.origin);
- ex->type = ex_misc;
- ex->frames = 4;
- ex->ent.flags = RF_TRANSLUCENT;
- ex->start = cl.frame.servertime - 100;
- ex->ent.model = cl_mod_smoke;
-
- ex = CL_AllocExplosion ();
- VectorCopy (origin, ex->ent.origin);
- ex->type = ex_flash;
- ex->ent.flags = RF_FULLBRIGHT;
- ex->frames = 2;
- ex->start = cl.frame.servertime - 100;
- ex->ent.model = cl_mod_flash;
-}
-
-/*
-=================
-CL_ParseParticles
-=================
-*/
-void CL_ParseParticles (void)
-{
- int color, count;
- vec3_t pos, dir;
-
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
-
- color = MSG_ReadByte (&net_message);
-
- count = MSG_ReadByte (&net_message);
-
- CL_ParticleEffect (pos, dir, color, count);
-}
-
-/*
-=================
-CL_ParseBeam
-=================
-*/
-int CL_ParseBeam (struct model_s *model)
-{
- int ent;
- vec3_t start, end;
- beam_t *b;
- int i;
-
- ent = MSG_ReadShort (&net_message);
-
- MSG_ReadPos (&net_message, start);
- MSG_ReadPos (&net_message, end);
-
-// override any beam with the same entity
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- if (b->entity == ent)
- {
- b->entity = ent;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorClear (b->offset);
- return ent;
- }
-
-// find a free beam
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- {
- if (!b->model || b->endtime < cl.time)
- {
- b->entity = ent;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorClear (b->offset);
- return ent;
- }
- }
- Com_Printf ("beam list overflow!\n");
- return ent;
-}
-
-/*
-=================
-CL_ParseBeam2
-=================
-*/
-int CL_ParseBeam2 (struct model_s *model)
-{
- int ent;
- vec3_t start, end, offset;
- beam_t *b;
- int i;
-
- ent = MSG_ReadShort (&net_message);
-
- MSG_ReadPos (&net_message, start);
- MSG_ReadPos (&net_message, end);
- MSG_ReadPos (&net_message, offset);
-
-// Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
-
-// override any beam with the same entity
-
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- if (b->entity == ent)
- {
- b->entity = ent;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorCopy (offset, b->offset);
- return ent;
- }
-
-// find a free beam
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- {
- if (!b->model || b->endtime < cl.time)
- {
- b->entity = ent;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorCopy (offset, b->offset);
- return ent;
- }
- }
- Com_Printf ("beam list overflow!\n");
- return ent;
-}
-
-// ROGUE
-/*
-=================
-CL_ParsePlayerBeam
- - adds to the cl_playerbeam array instead of the cl_beams array
-=================
-*/
-int CL_ParsePlayerBeam (struct model_s *model)
-{
- int ent;
- vec3_t start, end, offset;
- beam_t *b;
- int i;
-
- ent = MSG_ReadShort (&net_message);
-
- MSG_ReadPos (&net_message, start);
- MSG_ReadPos (&net_message, end);
- // PMM - network optimization
- if (model == cl_mod_heatbeam)
- VectorSet(offset, 2, 7, -3);
- else if (model == cl_mod_monster_heatbeam)
- {
- model = cl_mod_heatbeam;
- VectorSet(offset, 0, 0, 0);
- }
- else
- MSG_ReadPos (&net_message, offset);
-
-// Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
-
-// override any beam with the same entity
-// PMM - For player beams, we only want one per player (entity) so..
- for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
- {
- if (b->entity == ent)
- {
- b->entity = ent;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorCopy (offset, b->offset);
- return ent;
- }
- }
-
-// find a free beam
- for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
- {
- if (!b->model || b->endtime < cl.time)
- {
- b->entity = ent;
- b->model = model;
- b->endtime = cl.time + 100; // PMM - this needs to be 100 to prevent multiple heatbeams
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorCopy (offset, b->offset);
- return ent;
- }
- }
- Com_Printf ("beam list overflow!\n");
- return ent;
-}
-//rogue
-
-/*
-=================
-CL_ParseLightning
-=================
-*/
-int CL_ParseLightning (struct model_s *model)
-{
- int srcEnt, destEnt;
- vec3_t start, end;
- beam_t *b;
- int i;
-
- srcEnt = MSG_ReadShort (&net_message);
- destEnt = MSG_ReadShort (&net_message);
-
- MSG_ReadPos (&net_message, start);
- MSG_ReadPos (&net_message, end);
-
-// override any beam with the same source AND destination entities
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- if (b->entity == srcEnt && b->dest_entity == destEnt)
- {
-// Com_Printf("%d: OVERRIDE %d -> %d\n", cl.time, srcEnt, destEnt);
- b->entity = srcEnt;
- b->dest_entity = destEnt;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorClear (b->offset);
- return srcEnt;
- }
-
-// find a free beam
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- {
- if (!b->model || b->endtime < cl.time)
- {
-// Com_Printf("%d: NORMAL %d -> %d\n", cl.time, srcEnt, destEnt);
- b->entity = srcEnt;
- b->dest_entity = destEnt;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorClear (b->offset);
- return srcEnt;
- }
- }
- Com_Printf ("beam list overflow!\n");
- return srcEnt;
-}
-
-/*
-=================
-CL_ParseLaser
-=================
-*/
-void CL_ParseLaser (int colors)
-{
- vec3_t start;
- vec3_t end;
- laser_t *l;
- int i;
-
- MSG_ReadPos (&net_message, start);
- MSG_ReadPos (&net_message, end);
-
- for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
- {
- if (l->endtime < cl.time)
- {
- l->ent.flags = RF_TRANSLUCENT | RF_BEAM;
- VectorCopy (start, l->ent.origin);
- VectorCopy (end, l->ent.oldorigin);
- l->ent.alpha = 0.30;
- l->ent.skinnum = (colors >> ((rand() % 4)*8)) & 0xff;
- l->ent.model = NULL;
- l->ent.frame = 4;
- l->endtime = cl.time + 100;
- return;
- }
- }
-}
-
-//=============
-//ROGUE
-void CL_ParseSteam (void)
-{
- vec3_t pos, dir;
- int id, i;
- int r;
- int cnt;
- int color;
- int magnitude;
- cl_sustain_t *s, *free_sustain;
-
- id = MSG_ReadShort (&net_message); // an id of -1 is an instant effect
- if (id != -1) // sustains
- {
-// Com_Printf ("Sustain effect id %d\n", id);
- free_sustain = NULL;
- for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
- {
- if (s->id == 0)
- {
- free_sustain = s;
- break;
- }
- }
- if (free_sustain)
- {
- s->id = id;
- s->count = MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, s->org);
- MSG_ReadDir (&net_message, s->dir);
- r = MSG_ReadByte (&net_message);
- s->color = r & 0xff;
- s->magnitude = MSG_ReadShort (&net_message);
- s->endtime = cl.time + MSG_ReadLong (&net_message);
- s->think = CL_ParticleSteamEffect2;
- s->thinkinterval = 100;
- s->nextthink = cl.time;
- }
- else
- {
-// Com_Printf ("No free sustains!\n");
- // FIXME - read the stuff anyway /* and toss the results */
- MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- MSG_ReadByte (&net_message);
- MSG_ReadShort (&net_message);
- MSG_ReadLong (&net_message); // really interval
- }
- }
- else // instant
- {
- cnt = MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- r = MSG_ReadByte (&net_message);
- magnitude = MSG_ReadShort (&net_message);
- color = r & 0xff;
- CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
-// S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- }
-}
-
-void CL_ParseWidow (void)
-{
- vec3_t pos;
- int id, i;
- cl_sustain_t *s, *free_sustain;
-
- id = MSG_ReadShort (&net_message);
-
- free_sustain = NULL;
- for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
- {
- if (s->id == 0)
- {
- free_sustain = s;
- break;
- }
- }
- if (free_sustain)
- {
- s->id = id;
- MSG_ReadPos (&net_message, s->org);
- s->endtime = cl.time + 2100;
- s->think = CL_Widowbeamout;
- s->thinkinterval = 1;
- s->nextthink = cl.time;
- }
- else // no free sustains
- {
- // FIXME - read the stuff anyway
- MSG_ReadPos (&net_message, pos);
- }
-}
-
-void CL_ParseNuke (void)
-{
- vec3_t pos;
- int i;
- cl_sustain_t *s, *free_sustain;
-
- free_sustain = NULL;
- for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
- {
- if (s->id == 0)
- {
- free_sustain = s;
- break;
- }
- }
- if (free_sustain)
- {
- s->id = 21000;
- MSG_ReadPos (&net_message, s->org);
- s->endtime = cl.time + 1000;
- s->think = CL_Nukeblast;
- s->thinkinterval = 1;
- s->nextthink = cl.time;
- }
- else // no free sustains
- {
- // FIXME - read the stuff anyway
- MSG_ReadPos (&net_message, pos);
- }
-}
-
-//ROGUE
-//=============
-
-
-/*
-=================
-CL_ParseTEnt
-=================
-*/
-static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
-
-void CL_ParseTEnt (void)
-{
- int type;
- vec3_t pos, pos2, dir;
- explosion_t *ex;
- int cnt;
- int color;
- int r;
- int ent;
- int magnitude;
-
- type = MSG_ReadByte (&net_message);
-
- switch (type)
- {
- case TE_BLOOD: // bullet hitting flesh
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- CL_ParticleEffect (pos, dir, 0xe8, 60);
- break;
-
- case TE_GUNSHOT: // bullet hitting wall
- case TE_SPARKS:
- case TE_BULLET_SPARKS:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- if (type == TE_GUNSHOT)
- CL_ParticleEffect (pos, dir, 0, 40);
- else
- CL_ParticleEffect (pos, dir, 0xe0, 6);
-
- if (type != TE_SPARKS)
- {
- CL_SmokeAndFlash(pos);
-
- // impact sound
- cnt = rand()&15;
- if (cnt == 1)
- S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
- else if (cnt == 2)
- S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
- else if (cnt == 3)
- S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
- }
-
- break;
-
- case TE_SCREEN_SPARKS:
- case TE_SHIELD_SPARKS:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- if (type == TE_SCREEN_SPARKS)
- CL_ParticleEffect (pos, dir, 0xd0, 40);
- else
- CL_ParticleEffect (pos, dir, 0xb0, 40);
- //FIXME : replace or remove this sound
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
- case TE_SHOTGUN: // bullet hitting wall
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- CL_ParticleEffect (pos, dir, 0, 20);
- CL_SmokeAndFlash(pos);
- break;
-
- case TE_SPLASH: // bullet hitting water
- cnt = MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- r = MSG_ReadByte (&net_message);
- if (r > 6)
- color = 0x00;
- else
- color = splash_color[r];
- CL_ParticleEffect (pos, dir, color, cnt);
-
- if (r == SPLASH_SPARKS)
- {
- r = rand() & 3;
- if (r == 0)
- S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
- else if (r == 1)
- S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
- else
- S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
- }
- break;
-
- case TE_LASER_SPARKS:
- cnt = MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- color = MSG_ReadByte (&net_message);
- CL_ParticleEffect2 (pos, dir, color, cnt);
- break;
-
- // RAFAEL
- case TE_BLUEHYPERBLASTER:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadPos (&net_message, dir);
- CL_BlasterParticles (pos, dir);
- break;
-
- case TE_BLASTER: // blaster hitting wall
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- CL_BlasterParticles (pos, dir);
-
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->ent.angles[0] = acos(dir[2])/M_PI*180;
- // PMM - fixed to correct for pitch of 0
- if (dir[0])
- ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
- else if (dir[1] > 0)
- ex->ent.angles[1] = 90;
- else if (dir[1] < 0)
- ex->ent.angles[1] = 270;
- else
- ex->ent.angles[1] = 0;
-
- ex->type = ex_misc;
- ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
- ex->start = cl.frame.servertime - 100;
- ex->light = 150;
- ex->lightcolor[0] = 1;
- ex->lightcolor[1] = 1;
- ex->ent.model = cl_mod_explode;
- ex->frames = 4;
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
- case TE_RAILTRAIL: // railgun effect
- MSG_ReadPos (&net_message, pos);
- MSG_ReadPos (&net_message, pos2);
- CL_RailTrail (pos, pos2);
- S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
- break;
-
- case TE_EXPLOSION2:
- case TE_GRENADE_EXPLOSION:
- case TE_GRENADE_EXPLOSION_WATER:
- MSG_ReadPos (&net_message, pos);
-
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->type = ex_poly;
- ex->ent.flags = RF_FULLBRIGHT;
- ex->start = cl.frame.servertime - 100;
- ex->light = 350;
- ex->lightcolor[0] = 1.0;
- ex->lightcolor[1] = 0.5;
- ex->lightcolor[2] = 0.5;
- ex->ent.model = cl_mod_explo4;
- ex->frames = 19;
- ex->baseframe = 30;
- ex->ent.angles[1] = rand() % 360;
- CL_ExplosionParticles (pos);
- if (type == TE_GRENADE_EXPLOSION_WATER)
- S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
- else
- S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
- break;
-
- // RAFAEL
- case TE_PLASMA_EXPLOSION:
- MSG_ReadPos (&net_message, pos);
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->type = ex_poly;
- ex->ent.flags = RF_FULLBRIGHT;
- ex->start = cl.frame.servertime - 100;
- ex->light = 350;
- ex->lightcolor[0] = 1.0;
- ex->lightcolor[1] = 0.5;
- ex->lightcolor[2] = 0.5;
- ex->ent.angles[1] = rand() % 360;
- ex->ent.model = cl_mod_explo4;
- if (qfrand() < 0.5)
- ex->baseframe = 15;
- ex->frames = 15;
- CL_ExplosionParticles (pos);
- S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
- break;
-
- case TE_EXPLOSION1:
- case TE_EXPLOSION1_BIG: // PMM
- case TE_ROCKET_EXPLOSION:
- case TE_ROCKET_EXPLOSION_WATER:
- case TE_EXPLOSION1_NP: // PMM
- MSG_ReadPos (&net_message, pos);
-
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->type = ex_poly;
- ex->ent.flags = RF_FULLBRIGHT;
- ex->start = cl.frame.servertime - 100;
- ex->light = 350;
- ex->lightcolor[0] = 1.0;
- ex->lightcolor[1] = 0.5;
- ex->lightcolor[2] = 0.5;
- ex->ent.angles[1] = rand() % 360;
- if (type != TE_EXPLOSION1_BIG) // PMM
- ex->ent.model = cl_mod_explo4; // PMM
- else
- ex->ent.model = cl_mod_explo4_big;
- if (qfrand() < 0.5)
- ex->baseframe = 15;
- ex->frames = 15;
- if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP)) // PMM
- CL_ExplosionParticles (pos); // PMM
- if (type == TE_ROCKET_EXPLOSION_WATER)
- S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
- else
- S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
- break;
-
- case TE_BFG_EXPLOSION:
- MSG_ReadPos (&net_message, pos);
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->type = ex_poly;
- ex->ent.flags = RF_FULLBRIGHT;
- ex->start = cl.frame.servertime - 100;
- ex->light = 350;
- ex->lightcolor[0] = 0.0;
- ex->lightcolor[1] = 1.0;
- ex->lightcolor[2] = 0.0;
- ex->ent.model = cl_mod_bfg_explo;
- ex->ent.flags |= RF_TRANSLUCENT;
- ex->ent.alpha = 0.30;
- ex->frames = 4;
- break;
-
- case TE_BFG_BIGEXPLOSION:
- MSG_ReadPos (&net_message, pos);
- CL_BFGExplosionParticles (pos);
- break;
-
- case TE_BFG_LASER:
- CL_ParseLaser (0xd0d1d2d3);
- break;
-
- case TE_BUBBLETRAIL:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadPos (&net_message, pos2);
- CL_BubbleTrail (pos, pos2);
- break;
-
- case TE_PARASITE_ATTACK:
- case TE_MEDIC_CABLE_ATTACK:
- CL_ParseBeam (cl_mod_parasite_segment); /* toss result */
- break;
-
- case TE_BOSSTPORT: // boss teleporting to station
- MSG_ReadPos (&net_message, pos);
- CL_BigTeleportParticles (pos);
- S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0);
- break;
-
- case TE_GRAPPLE_CABLE:
- CL_ParseBeam2 (cl_mod_grapple_cable); /* toss result */
- break;
-
- // RAFAEL
- case TE_WELDING_SPARKS:
- cnt = MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- color = MSG_ReadByte (&net_message);
- CL_ParticleEffect2 (pos, dir, color, cnt);
-
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->type = ex_flash;
- // note to self
- // we need a better no draw flag
- ex->ent.flags = RF_BEAM;
- ex->start = cl.frame.servertime - 0.1;
- ex->light = 100 + (rand()%75);
- ex->lightcolor[0] = 1.0;
- ex->lightcolor[1] = 1.0;
- ex->lightcolor[2] = 0.3;
- ex->ent.model = cl_mod_flash;
- ex->frames = 2;
- break;
-
- case TE_GREENBLOOD:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- CL_ParticleEffect2 (pos, dir, 0xdf, 30);
- break;
-
- // RAFAEL
- case TE_TUNNEL_SPARKS:
- cnt = MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- color = MSG_ReadByte (&net_message);
- CL_ParticleEffect3 (pos, dir, color, cnt);
- break;
-
-//=============
-//PGM
- // PMM -following code integrated for flechette (different color)
- case TE_BLASTER2: // green blaster hitting wall
- case TE_FLECHETTE: // flechette
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
-
- // PMM
- if (type == TE_BLASTER2)
- CL_BlasterParticles2 (pos, dir, 0xd0);
- else
- CL_BlasterParticles2 (pos, dir, 0x6f); // 75
-
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->ent.angles[0] = acos(dir[2])/M_PI*180;
- // PMM - fixed to correct for pitch of 0
- if (dir[0])
- ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
- else if (dir[1] > 0)
- ex->ent.angles[1] = 90;
- else if (dir[1] < 0)
- ex->ent.angles[1] = 270;
- else
- ex->ent.angles[1] = 0;
-
- ex->type = ex_misc;
- ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
-
- // PMM
- if (type == TE_BLASTER2)
- ex->ent.skinnum = 1;
- else // flechette
- ex->ent.skinnum = 2;
-
- ex->start = cl.frame.servertime - 100;
- ex->light = 150;
- // PMM
- if (type == TE_BLASTER2)
- ex->lightcolor[1] = 1;
- else // flechette
- {
- ex->lightcolor[0] = 0.19;
- ex->lightcolor[1] = 0.41;
- ex->lightcolor[2] = 0.75;
- }
- ex->ent.model = cl_mod_explode;
- ex->frames = 4;
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
-
- case TE_LIGHTNING:
- ent = CL_ParseLightning (cl_mod_lightning);
- S_StartSound (NULL, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0);
- break;
-
- case TE_DEBUGTRAIL:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadPos (&net_message, pos2);
- CL_DebugTrail (pos, pos2);
- break;
-
- case TE_PLAIN_EXPLOSION:
- MSG_ReadPos (&net_message, pos);
-
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->type = ex_poly;
- ex->ent.flags = RF_FULLBRIGHT;
- ex->start = cl.frame.servertime - 100;
- ex->light = 350;
- ex->lightcolor[0] = 1.0;
- ex->lightcolor[1] = 0.5;
- ex->lightcolor[2] = 0.5;
- ex->ent.angles[1] = rand() % 360;
- ex->ent.model = cl_mod_explo4;
- if (qfrand() < 0.5)
- ex->baseframe = 15;
- ex->frames = 15;
- if (type == TE_ROCKET_EXPLOSION_WATER)
- S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
- else
- S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
- break;
-
- case TE_FLASHLIGHT:
- MSG_ReadPos(&net_message, pos);
- ent = MSG_ReadShort(&net_message);
- CL_Flashlight(ent, pos);
- break;
-
- case TE_FORCEWALL:
- MSG_ReadPos(&net_message, pos);
- MSG_ReadPos(&net_message, pos2);
- color = MSG_ReadByte (&net_message);
- CL_ForceWall(pos, pos2, color);
- break;
-
- case TE_HEATBEAM:
- CL_ParsePlayerBeam (cl_mod_heatbeam); /* toss result */
- break;
-
- case TE_MONSTER_HEATBEAM:
- CL_ParsePlayerBeam (cl_mod_monster_heatbeam); /* toss result */
- break;
-
- case TE_HEATBEAM_SPARKS:
-// cnt = MSG_ReadByte (&net_message);
- cnt = 50;
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
-// r = MSG_ReadByte (&net_message);
-// magnitude = MSG_ReadShort (&net_message);
- r = 8;
- magnitude = 60;
- color = r & 0xff;
- CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
- case TE_HEATBEAM_STEAM:
-// cnt = MSG_ReadByte (&net_message);
- cnt = 20;
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
-// r = MSG_ReadByte (&net_message);
-// magnitude = MSG_ReadShort (&net_message);
-// color = r & 0xff;
- color = 0xe0;
- magnitude = 60;
- CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
- case TE_STEAM:
- CL_ParseSteam();
- break;
-
- case TE_BUBBLETRAIL2:
-// cnt = MSG_ReadByte (&net_message);
- cnt = 8;
- MSG_ReadPos (&net_message, pos);
- MSG_ReadPos (&net_message, pos2);
- CL_BubbleTrail2 (pos, pos2, cnt);
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
- case TE_MOREBLOOD:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- CL_ParticleEffect (pos, dir, 0xe8, 250);
- break;
-
- case TE_CHAINFIST_SMOKE:
- dir[0]=0; dir[1]=0; dir[2]=1;
- MSG_ReadPos(&net_message, pos);
- CL_ParticleSmokeEffect (pos, dir, 0, 20, 20);
- break;
-
- case TE_ELECTRIC_SPARKS:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
-// CL_ParticleEffect (pos, dir, 109, 40);
- CL_ParticleEffect (pos, dir, 0x75, 40);
- //FIXME : replace or remove this sound
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
- case TE_TRACKER_EXPLOSION:
- MSG_ReadPos (&net_message, pos);
- CL_ColorFlash (pos, 0, 150, -1, -1, -1);
- CL_ColorExplosionParticles (pos, 0, 1);
-// CL_Tracker_Explode (pos);
- S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
- break;
-
- case TE_TELEPORT_EFFECT:
- case TE_DBALL_GOAL:
- MSG_ReadPos (&net_message, pos);
- CL_TeleportParticles (pos);
- break;
-
- case TE_WIDOWBEAMOUT:
- CL_ParseWidow ();
- break;
-
- case TE_NUKEBLAST:
- CL_ParseNuke ();
- break;
-
- case TE_WIDOWSPLASH:
- MSG_ReadPos (&net_message, pos);
- CL_WidowSplash (pos);
- break;
-//PGM
-//==============
-
- default:
- Com_Error (ERR_DROP, "CL_ParseTEnt: bad type");
- }
-}
-
-/*
-=================
-CL_AddBeams
-=================
-*/
-void CL_AddBeams (void)
-{
- int i,j;
- beam_t *b;
- vec3_t dist, org;
- float d;
- entity_t ent;
- float yaw, pitch;
- float forward;
- float len, steps;
- float model_length;
-
-// update beams
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- {
- if (!b->model || b->endtime < cl.time)
- continue;
-
- // if coming from the player, update the start position
- if (b->entity == cl.playernum+1) // entity 0 is the world
- {
- VectorCopy (cl.refdef.vieworg, b->start);
- b->start[2] -= 22; // adjust for view height
- }
- VectorAdd (b->start, b->offset, org);
-
- // calculate pitch and yaw
- VectorSubtract (b->end, org, dist);
-
- if (dist[1] == 0 && dist[0] == 0)
- {
- yaw = 0;
- if (dist[2] > 0)
- pitch = 90;
- else
- pitch = 270;
- }
- else
- {
- // PMM - fixed to correct for pitch of 0
- if (dist[0])
- yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
- else if (dist[1] > 0)
- yaw = 90;
- else
- yaw = 270;
- if (yaw < 0)
- yaw += 360;
-
- forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
- pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
- if (pitch < 0)
- pitch += 360.0;
- }
-
- // add new entities for the beams
- d = VectorNormalize(dist);
-
- memset (&ent, 0, sizeof(ent));
- if (b->model == cl_mod_lightning)
- {
- model_length = 35.0;
- d-= 20.0; // correction so it doesn't end in middle of tesla
- }
- else
- {
- model_length = 30.0;
- }
- steps = ceil(d/model_length);
- len = (d-model_length)/(steps-1);
-
- // PMM - special case for lightning model .. if the real length is shorter than the model,
- // flip it around & draw it from the end to the start. This prevents the model from going
- // through the tesla mine (instead it goes through the target)
- if ((b->model == cl_mod_lightning) && (d <= model_length))
- {
-// Com_Printf ("special case\n");
- VectorCopy (b->end, ent.origin);
- // offset to push beam outside of tesla model (negative because dist is from end to start
- // for this beam)
-// for (j=0 ; j<3 ; j++)
-// ent.origin[j] -= dist[j]*10.0;
- ent.model = b->model;
- ent.flags = RF_FULLBRIGHT;
- ent.angles[0] = pitch;
- ent.angles[1] = yaw;
- ent.angles[2] = rand()%360;
- V_AddEntity (&ent);
- return;
- }
- while (d > 0)
- {
- VectorCopy (org, ent.origin);
- ent.model = b->model;
- if (b->model == cl_mod_lightning)
- {
- ent.flags = RF_FULLBRIGHT;
- ent.angles[0] = -pitch;
- ent.angles[1] = yaw + 180.0;
- ent.angles[2] = rand()%360;
- }
- else
- {
- ent.angles[0] = pitch;
- ent.angles[1] = yaw;
- ent.angles[2] = rand()%360;
- }
-
-// Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
- V_AddEntity (&ent);
-
- for (j=0 ; j<3 ; j++)
- org[j] += dist[j]*len;
- d -= model_length;
- }
- }
-}
-
-
-/*
-// Com_Printf ("Endpoint: %f %f %f\n", b->end[0], b->end[1], b->end[2]);
-// Com_Printf ("Pred View Angles: %f %f %f\n", cl.predicted_angles[0], cl.predicted_angles[1], cl.predicted_angles[2]);
-// Com_Printf ("Act View Angles: %f %f %f\n", cl.refdef.viewangles[0], cl.refdef.viewangles[1], cl.refdef.viewangles[2]);
-// VectorCopy (cl.predicted_origin, b->start);
-// b->start[2] += 22; // adjust for view height
-// if (fabs(cl.refdef.vieworg[2] - b->start[2]) >= 10) {
-// b->start[2] = cl.refdef.vieworg[2];
-// }
-
-// Com_Printf ("Time: %d %d %f\n", cl.time, cls.realtime, cls.frametime);
-*/
-
-extern cvar_t *hand;
-
-/*
-=================
-ROGUE - draw player locked beams
-CL_AddPlayerBeams
-=================
-*/
-void CL_AddPlayerBeams (void)
-{
- int i,j;
- beam_t *b;
- vec3_t dist, org;
- float d;
- entity_t ent;
- float yaw, pitch;
- float forward;
- float len, steps;
- int framenum = 0;
- float model_length;
-
- float hand_multiplier;
- frame_t *oldframe;
- player_state_t *ps, *ops;
-
-//PMM
- if (hand)
- {
- if (hand->value == 2)
- hand_multiplier = 0;
- else if (hand->value == 1)
- hand_multiplier = -1;
- else
- hand_multiplier = 1;
- }
- else
- {
- hand_multiplier = 1;
- }
-//PMM
-
-// update beams
- for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
- {
- vec3_t f,r,u;
- if (!b->model || b->endtime < cl.time)
- continue;
-
- if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
- {
-
- // if coming from the player, update the start position
- if (b->entity == cl.playernum+1) // entity 0 is the world
- {
- // set up gun position
- // code straight out of CL_AddViewWeapon
- ps = &cl.frame.playerstate;
- j = (cl.frame.serverframe - 1) & UPDATE_MASK;
- oldframe = &cl.frames[j];
- if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
- oldframe = &cl.frame; // previous frame was dropped or involid
- ops = &oldframe->playerstate;
- for (j=0 ; j<3 ; j++)
- {
- b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j]
- + cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]);
- }
- VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org);
- VectorMA ( org, b->offset[1], cl.v_forward, org);
- VectorMA ( org, b->offset[2], cl.v_up, org);
- if ((hand) && (hand->value == 2)) {
- VectorMA (org, -1, cl.v_up, org);
- }
- // FIXME - take these out when final
- VectorCopy (cl.v_right, r);
- VectorCopy (cl.v_forward, f);
- VectorCopy (cl.v_up, u);
-
- }
- else
- VectorCopy (b->start, org);
- }
- else
- {
- // if coming from the player, update the start position
- if (b->entity == cl.playernum+1) // entity 0 is the world
- {
- VectorCopy (cl.refdef.vieworg, b->start);
- b->start[2] -= 22; // adjust for view height
- }
- VectorAdd (b->start, b->offset, org);
- }
-
- // calculate pitch and yaw
- VectorSubtract (b->end, org, dist);
-
-//PMM
- if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1))
- {
- vec_t len;
-
- len = VectorLength (dist);
- VectorScale (f, len, dist);
- VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist);
- VectorMA (dist, b->offset[1], f, dist);
- VectorMA (dist, b->offset[2], u, dist);
- if ((hand) && (hand->value == 2)) {
- VectorMA (org, -1, cl.v_up, org);
- }
- }
-//PMM
-
- if (dist[1] == 0 && dist[0] == 0)
- {
- yaw = 0;
- if (dist[2] > 0)
- pitch = 90;
- else
- pitch = 270;
- }
- else
- {
- // PMM - fixed to correct for pitch of 0
- if (dist[0])
- yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
- else if (dist[1] > 0)
- yaw = 90;
- else
- yaw = 270;
- if (yaw < 0)
- yaw += 360;
-
- forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
- pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
- if (pitch < 0)
- pitch += 360.0;
- }
-
- if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
- {
- if (b->entity != cl.playernum+1)
- {
- framenum = 2;
-// Com_Printf ("Third person\n");
- ent.angles[0] = -pitch;
- ent.angles[1] = yaw + 180.0;
- ent.angles[2] = 0;
-// Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b->offset[0], b->offset[1], b->offset[2]);
- AngleVectors(ent.angles, f, r, u);
-
- // if it's a non-origin offset, it's a player, so use the hardcoded player offset
- if (!VectorCompare (b->offset, vec3_origin))
- {
- VectorMA (org, -(b->offset[0])+1, r, org);
- VectorMA (org, -(b->offset[1]), f, org);
- VectorMA (org, -(b->offset[2])-10, u, org);
- }
- else
- {
- // if it's a monster, do the particle effect
- CL_MonsterPlasma_Shell(b->start);
- }
- }
- else
- {
- framenum = 1;
- }
- }
-
- // if it's the heatbeam, draw the particle effect
- if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1)))
- {
- CL_Heatbeam (org, dist);
- }
-
- // add new entities for the beams
- d = VectorNormalize(dist);
-
- memset (&ent, 0, sizeof(ent));
- if (b->model == cl_mod_heatbeam)
- {
- model_length = 32.0;
- }
- else if (b->model == cl_mod_lightning)
- {
- model_length = 35.0;
- d-= 20.0; // correction so it doesn't end in middle of tesla
- }
- else
- {
- model_length = 30.0;
- }
- steps = ceil(d/model_length);
- len = (d-model_length)/(steps-1);
-
- // PMM - special case for lightning model .. if the real length is shorter than the model,
- // flip it around & draw it from the end to the start. This prevents the model from going
- // through the tesla mine (instead it goes through the target)
- if ((b->model == cl_mod_lightning) && (d <= model_length))
- {
-// Com_Printf ("special case\n");
- VectorCopy (b->end, ent.origin);
- // offset to push beam outside of tesla model (negative because dist is from end to start
- // for this beam)
-// for (j=0 ; j<3 ; j++)
-// ent.origin[j] -= dist[j]*10.0;
- ent.model = b->model;
- ent.flags = RF_FULLBRIGHT;
- ent.angles[0] = pitch;
- ent.angles[1] = yaw;
- ent.angles[2] = rand()%360;
- V_AddEntity (&ent);
- return;
- }
- while (d > 0)
- {
- VectorCopy (org, ent.origin);
- ent.model = b->model;
- if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
- {
-// ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
-// ent.alpha = 0.3;
- ent.flags = RF_FULLBRIGHT;
- ent.angles[0] = -pitch;
- ent.angles[1] = yaw + 180.0;
- ent.angles[2] = (cl.time) % 360;
-// ent.angles[2] = rand()%360;
- ent.frame = framenum;
- }
- else if (b->model == cl_mod_lightning)
- {
- ent.flags = RF_FULLBRIGHT;
- ent.angles[0] = -pitch;
- ent.angles[1] = yaw + 180.0;
- ent.angles[2] = rand()%360;
- }
- else
- {
- ent.angles[0] = pitch;
- ent.angles[1] = yaw;
- ent.angles[2] = rand()%360;
- }
-
-// Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
- V_AddEntity (&ent);
-
- for (j=0 ; j<3 ; j++)
- org[j] += dist[j]*len;
- d -= model_length;
- }
- }
-}
-
-/*
-=================
-CL_AddExplosions
-=================
-*/
-void CL_AddExplosions (void)
-{
- entity_t *ent;
- int i;
- explosion_t *ex;
- float frac;
- int f;
-
- memset (&ent, 0, sizeof(ent));
-
- for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++)
- {
- if (ex->type == ex_free)
- continue;
- frac = (cl.time - ex->start)/100.0;
- f = floor(frac);
-
- ent = &ex->ent;
-
- switch (ex->type)
- {
- case ex_mflash:
- if (f >= ex->frames-1)
- ex->type = ex_free;
- break;
- case ex_misc:
- if (f >= ex->frames-1)
- {
- ex->type = ex_free;
- break;
- }
- ent->alpha = 1.0 - frac/(ex->frames-1);
- break;
- case ex_flash:
- if (f >= 1)
- {
- ex->type = ex_free;
- break;
- }
- ent->alpha = 1.0;
- break;
- case ex_poly:
- if (f >= ex->frames-1)
- {
- ex->type = ex_free;
- break;
- }
-
- ent->alpha = (16.0 - (float)f)/16.0;
-
- if (f < 10)
- {
- ent->skinnum = (f>>1);
- if (ent->skinnum < 0)
- ent->skinnum = 0;
- }
- else
- {
- ent->flags |= RF_TRANSLUCENT;
- if (f < 13)
- ent->skinnum = 5;
- else
- ent->skinnum = 6;
- }
- break;
- case ex_poly2:
- if (f >= ex->frames-1)
- {
- ex->type = ex_free;
- break;
- }
-
- ent->alpha = (5.0 - (float)f)/5.0;
- ent->skinnum = 0;
- ent->flags |= RF_TRANSLUCENT;
- break;
- }
-
- if (ex->type == ex_free)
- continue;
- if (ex->light)
- {
- V_AddLight (ent->origin, ex->light*ent->alpha,
- ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]);
- }
-
- VectorCopy (ent->origin, ent->oldorigin);
-
- if (f < 0)
- f = 0;
- ent->frame = ex->baseframe + f + 1;
- ent->oldframe = ex->baseframe + f;
- ent->backlerp = 1.0 - cl.lerpfrac;
-
- V_AddEntity (ent);
- }
-}
-
-
-/*
-=================
-CL_AddLasers
-=================
-*/
-void CL_AddLasers (void)
-{
- laser_t *l;
- int i;
-
- for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
- {
- if (l->endtime >= cl.time)
- V_AddEntity (&l->ent);
- }
-}
-
-/* PMM - CL_Sustains */
-void CL_ProcessSustain (void)
-{
- cl_sustain_t *s;
- int i;
-
- for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++)
- {
- if (s->id)
- if ((s->endtime >= cl.time) && (cl.time >= s->nextthink))
- {
-// Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval);
- s->think (s);
- }
- else if (s->endtime < cl.time)
- s->id = 0;
- }
-}
-
-/*
-=================
-CL_AddTEnts
-=================
-*/
-void CL_AddTEnts (void)
-{
- CL_AddBeams ();
- // PMM - draw plasma beams
- CL_AddPlayerBeams ();
- CL_AddExplosions ();
- CL_AddLasers ();
- // PMM - set up sustain
- CL_ProcessSustain();
-}
--- a/client/cl_view.c
+++ /dev/null
@@ -1,568 +1,0 @@
-// cl_view.c -- player rendering positioning
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-//=============
-//
-// development tools for weapons
-//
-int gun_frame;
-struct model_s *gun_model;
-
-//=============
-
-cvar_t *crosshair;
-cvar_t *cl_testparticles;
-cvar_t *cl_testentities;
-cvar_t *cl_testlights;
-cvar_t *cl_testblend;
-
-cvar_t *cl_stats;
-
-
-int r_numdlights;
-dlight_t r_dlights[MAX_DLIGHTS];
-
-int r_numentities;
-entity_t r_entities[MAX_ENTITIES];
-
-int r_numparticles;
-particle_t r_particles[MAX_PARTICLES];
-
-lightstyle_t r_lightstyles[MAX_LIGHTSTYLES];
-
-char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
-int num_cl_weaponmodels;
-
-/*
-====================
-V_ClearScene
-
-Specifies the model that will be used as the world
-====================
-*/
-void V_ClearScene (void)
-{
- r_numdlights = 0;
- r_numentities = 0;
- r_numparticles = 0;
-}
-
-
-/*
-=====================
-V_AddEntity
-
-=====================
-*/
-void V_AddEntity (entity_t *ent)
-{
- if (r_numentities >= MAX_ENTITIES)
- return;
- r_entities[r_numentities++] = *ent;
-}
-
-
-/*
-=====================
-V_AddParticle
-
-=====================
-*/
-void V_AddParticle (vec3_t org, int color, float alpha)
-{
- particle_t *p;
-
- if (r_numparticles >= MAX_PARTICLES)
- return;
- p = &r_particles[r_numparticles++];
- VectorCopy (org, p->origin);
- p->color = color;
- p->alpha = alpha;
-}
-
-/*
-=====================
-V_AddLight
-
-=====================
-*/
-void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
-{
- dlight_t *dl;
-
- if (r_numdlights >= MAX_DLIGHTS)
- return;
- dl = &r_dlights[r_numdlights++];
- VectorCopy (org, dl->origin);
- dl->intensity = intensity;
- dl->color[0] = r;
- dl->color[1] = g;
- dl->color[2] = b;
-}
-
-
-/*
-=====================
-V_AddLightStyle
-
-=====================
-*/
-void V_AddLightStyle (int style, float r, float g, float b)
-{
- lightstyle_t *ls;
-
- if (style < 0 || style > MAX_LIGHTSTYLES)
- Com_Error (ERR_DROP, "Bad light style %i", style);
- ls = &r_lightstyles[style];
-
- ls->white = r+g+b;
- ls->rgb[0] = r;
- ls->rgb[1] = g;
- ls->rgb[2] = b;
-}
-
-/*
-================
-V_TestParticles
-
-If cl_testparticles is set, create 4096 particles in the view
-================
-*/
-void V_TestParticles (void)
-{
- particle_t *p;
- int i, j;
- float d, r, u;
-
- r_numparticles = MAX_PARTICLES;
- for (i=0 ; i<r_numparticles ; i++)
- {
- d = i*0.25;
- r = 4*((i&7)-3.5);
- u = 4*(((i>>3)&7)-3.5);
- p = &r_particles[i];
-
- for (j=0 ; j<3 ; j++)
- p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*d +
- cl.v_right[j]*r + cl.v_up[j]*u;
-
- p->color = 8;
- p->alpha = cl_testparticles->value;
- }
-}
-
-/*
-================
-V_TestEntities
-
-If cl_testentities is set, create 32 player models
-================
-*/
-void V_TestEntities (void)
-{
- int i, j;
- float f, r;
- entity_t *ent;
-
- r_numentities = 32;
- memset (r_entities, 0, sizeof(r_entities));
-
- for (i=0 ; i<r_numentities ; i++)
- {
- ent = &r_entities[i];
-
- r = 64 * ( (i%4) - 1.5 );
- f = 64 * (i/4) + 128;
-
- for (j=0 ; j<3 ; j++)
- ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
- cl.v_right[j]*r;
-
- ent->model = cl.baseclientinfo.model;
- ent->skin = cl.baseclientinfo.skin;
- }
-}
-
-/*
-================
-V_TestLights
-
-If cl_testlights is set, create 32 lights models
-================
-*/
-void V_TestLights (void)
-{
- int i, j;
- float f, r;
- dlight_t *dl;
-
- r_numdlights = 32;
- memset (r_dlights, 0, sizeof(r_dlights));
-
- for (i=0 ; i<r_numdlights ; i++)
- {
- dl = &r_dlights[i];
-
- r = 64 * ( (i%4) - 1.5 );
- f = 64 * (i/4) + 128;
-
- for (j=0 ; j<3 ; j++)
- dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
- cl.v_right[j]*r;
- dl->color[0] = ((i%6)+1) & 1;
- dl->color[1] = (((i%6)+1) & 2)>>1;
- dl->color[2] = (((i%6)+1) & 4)>>2;
- dl->intensity = 200;
- }
-}
-
-//===================================================================
-
-/*
-=================
-CL_PrepRefresh
-
-Call before entering a new level, or after changing dlls
-=================
-*/
-void CL_PrepRefresh (void)
-{
- char mapname[32];
- int i;
- char name[MAX_QPATH];
- float rotate;
- vec3_t axis;
-
- if (!cl.configstrings[CS_MODELS+1][0])
- return; // no map loaded
-
- SCR_AddDirtyPoint (0, 0);
- SCR_AddDirtyPoint (vid.width-1, vid.height-1);
-
- // let the render dll load the map
- strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5); // skip "maps/"
- mapname[strlen(mapname)-4] = 0; // cut off ".bsp"
-
- // register models, pics, and skins
- Com_Printf ("Map: %s\r", mapname);
- SCR_UpdateScreen ();
- re.BeginRegistration (mapname);
- Com_Printf (" \r");
-
- // precache status bar pics
- Com_Printf ("pics\r");
- SCR_UpdateScreen ();
- SCR_TouchPics ();
- Com_Printf (" \r");
-
- CL_RegisterTEntModels ();
-
- num_cl_weaponmodels = 1;
- strcpy(cl_weaponmodels[0], "weapon.md2");
-
- for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
- {
- strcpy (name, cl.configstrings[CS_MODELS+i]);
- name[37] = 0; // never go beyond one line
- if (name[0] != '*')
- Com_Printf ("%s\r", name);
- SCR_UpdateScreen ();
- Sys_SendKeyEvents (); // pump message loop
- if (name[0] == '#')
- {
- // special player weapon model
- if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
- {
- strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
- sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
- num_cl_weaponmodels++;
- }
- }
- else
- {
- cl.model_draw[i] = re.RegisterModel (cl.configstrings[CS_MODELS+i]);
- if (name[0] == '*')
- cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
- else
- cl.model_clip[i] = NULL;
- }
- if (name[0] != '*')
- Com_Printf (" \r");
- }
-
- Com_Printf ("images\r", i);
- SCR_UpdateScreen ();
- for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
- {
- cl.image_precache[i] = re.RegisterPic (cl.configstrings[CS_IMAGES+i]);
- Sys_SendKeyEvents (); // pump message loop
- }
-
- Com_Printf (" \r");
- for (i=0 ; i<MAX_CLIENTS ; i++)
- {
- if (!cl.configstrings[CS_PLAYERSKINS+i][0])
- continue;
- Com_Printf ("client %i\r", i);
- SCR_UpdateScreen ();
- Sys_SendKeyEvents (); // pump message loop
- CL_ParseClientinfo (i);
- Com_Printf (" \r");
- }
-
- CL_LoadClientinfo (&cl.baseclientinfo, "unnamed\\male/grunt");
-
- // set sky textures and speed
- Com_Printf ("sky\r", i);
- SCR_UpdateScreen ();
- rotate = atof (cl.configstrings[CS_SKYROTATE]);
- sscanf (cl.configstrings[CS_SKYAXIS], "%f %f %f",
- &axis[0], &axis[1], &axis[2]);
- re.SetSky (cl.configstrings[CS_SKY], rotate, axis);
- Com_Printf (" \r");
-
- // the renderer can now free unneeded stuff
- re.EndRegistration ();
-
- // clear any lines of console text
- Con_ClearNotify ();
-
- SCR_UpdateScreen ();
- cl.refresh_prepped = true;
- cl.force_refdef = true; // make sure we have a valid refdef
-
- // start the cd track
- CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
-}
-
-/*
-====================
-CalcFov
-====================
-*/
-float CalcFov (float fov_x, float width, float height)
-{
- float a;
- float x;
-
- if (fov_x < 1 || fov_x > 179)
- Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
-
- x = width/tan(fov_x/360*M_PI);
-
- a = atan (height/x);
-
- a = a*360/M_PI;
-
- return a;
-}
-
-//============================================================================
-
-// gun frame debugging functions
-void V_Gun_Next_f (void)
-{
- gun_frame++;
- Com_Printf ("frame %i\n", gun_frame);
-}
-
-void V_Gun_Prev_f (void)
-{
- gun_frame--;
- if (gun_frame < 0)
- gun_frame = 0;
- Com_Printf ("frame %i\n", gun_frame);
-}
-
-void V_Gun_Model_f (void)
-{
- char name[MAX_QPATH];
-
- if (Cmd_Argc() != 2)
- {
- gun_model = NULL;
- return;
- }
- Com_sprintf (name, sizeof(name), "models/%s/tris.md2", Cmd_Argv(1));
- gun_model = re.RegisterModel (name);
-}
-
-//============================================================================
-
-
-/*
-=================
-SCR_DrawCrosshair
-=================
-*/
-void SCR_DrawCrosshair (void)
-{
- if (!crosshair->value)
- return;
-
- if (crosshair->modified)
- {
- crosshair->modified = false;
- SCR_TouchPics ();
- }
-
- if (!crosshair_pic[0])
- return;
-
- re.DrawPic (scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1)
- , scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1), crosshair_pic);
-}
-
-/*
-==================
-V_RenderView
-
-==================
-*/
-void V_RenderView( float stereo_separation )
-{
- extern int entitycmpfnc( const entity_t *, const entity_t * );
-
- if (cls.state != ca_active)
- return;
-
- if (!cl.refresh_prepped)
- return; // still loading
-
- if (cl_timedemo->value)
- {
- if (!cl.timedemo_start)
- cl.timedemo_start = Sys_Milliseconds ();
- cl.timedemo_frames++;
- }
-
- // an invalid frame will just use the exact previous refdef
- // we can't use the old frame if the video mode has changed, though...
- if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
- {
- cl.force_refdef = false;
-
- V_ClearScene ();
-
- // build a refresh entity list and calc cl.sim*
- // this also calls CL_CalcViewValues which loads
- // v_forward, etc.
- CL_AddEntities ();
-
- if (cl_testparticles->value)
- V_TestParticles ();
- if (cl_testentities->value)
- V_TestEntities ();
- if (cl_testlights->value)
- V_TestLights ();
- if (cl_testblend->value)
- {
- cl.refdef.blend[0] = 1;
- cl.refdef.blend[1] = 0.5;
- cl.refdef.blend[2] = 0.25;
- cl.refdef.blend[3] = 0.5;
- }
-
- // offset vieworg appropriately if we're doing stereo separation
- if ( stereo_separation != 0 )
- {
- vec3_t tmp;
-
- VectorScale( cl.v_right, stereo_separation, tmp );
- VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
- }
-
- // never let it sit exactly on a node line, because a water plane can
- // dissapear when viewed with the eye exactly on it.
- // the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
- cl.refdef.vieworg[0] += 1.0/16;
- cl.refdef.vieworg[1] += 1.0/16;
- cl.refdef.vieworg[2] += 1.0/16;
-
- cl.refdef.x = scr_vrect.x;
- cl.refdef.y = scr_vrect.y;
- cl.refdef.width = scr_vrect.width;
- cl.refdef.height = scr_vrect.height;
- cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
- cl.refdef.time = cl.time*0.001;
-
- cl.refdef.areabits = cl.frame.areabits;
-
- if (!cl_add_entities->value)
- r_numentities = 0;
- if (!cl_add_particles->value)
- r_numparticles = 0;
- if (!cl_add_lights->value)
- r_numdlights = 0;
- if (!cl_add_blend->value)
- {
- VectorClear (cl.refdef.blend);
- }
-
- cl.refdef.num_entities = r_numentities;
- cl.refdef.entities = r_entities;
- cl.refdef.num_particles = r_numparticles;
- cl.refdef.particles = r_particles;
- cl.refdef.num_dlights = r_numdlights;
- cl.refdef.dlights = r_dlights;
- cl.refdef.lightstyles = r_lightstyles;
-
- cl.refdef.rdflags = cl.frame.playerstate.rdflags;
-
- // sort entities for better cache locality
- qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(const void *, const void *))entitycmpfnc );
- }
-
- re.RenderFrame (&cl.refdef);
- if (cl_stats->value)
- Com_Printf ("ent:%i lt:%i part:%i\n", r_numentities, r_numdlights, r_numparticles);
- if ( log_stats->value && ( log_stats_file != 0 ) )
- fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
-
-
- SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y);
- SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1,
- scr_vrect.y+scr_vrect.height-1);
-
- SCR_DrawCrosshair ();
-}
-
-
-/*
-=============
-V_Viewpos_f
-=============
-*/
-void V_Viewpos_f (void)
-{
- Com_Printf ("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
- (int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2],
- (int)cl.refdef.viewangles[YAW]);
-}
-
-/*
-=============
-V_Init
-=============
-*/
-void V_Init (void)
-{
- Cmd_AddCommand ("gun_next", V_Gun_Next_f);
- Cmd_AddCommand ("gun_prev", V_Gun_Prev_f);
- Cmd_AddCommand ("gun_model", V_Gun_Model_f);
-
- Cmd_AddCommand ("viewpos", V_Viewpos_f);
-
- crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
-
- cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
- cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
- cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
- cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
-
- cl_stats = Cvar_Get ("cl_stats", "0", 0);
-}
--- a/client/client.h
+++ /dev/null
@@ -1,536 +1,0 @@
-// client.h -- primary header for client
-
-//#define PARANOID // speed sapping error checking
-
-//=============================================================================
-typedef struct
-{
- qboolean valid; // cleared if delta parsing was invalid
- int serverframe;
- int servertime; // server time the message is valid for (in msec)
- int deltaframe;
- byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits
- player_state_t playerstate;
- int num_entities;
- int parse_entities; // non-masked index into cl_parse_entities array
-} frame_t;
-
-typedef struct
-{
- entity_state_t baseline; // delta from this if not from a previous frame
- entity_state_t current;
- entity_state_t prev; // will always be valid, but might just be a copy of current
-
- int serverframe; // if not current, this ent isn't in the frame
-
- int trailcount; // for diminishing grenade trails
- vec3_t lerp_origin; // for trails (variable hz)
-
- int fly_stoptime;
-} centity_t;
-
-#define MAX_CLIENTWEAPONMODELS 20 // PGM -- upped from 16 to fit the chainfist vwep
-
-typedef struct
-{
- char name[MAX_QPATH];
- char cinfo[MAX_QPATH];
- struct image_s *skin;
- struct image_s *icon;
- char iconname[MAX_QPATH];
- struct model_s *model;
- struct model_s *weaponmodel[MAX_CLIENTWEAPONMODELS];
-} clientinfo_t;
-
-extern char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
-extern int num_cl_weaponmodels;
-
-#define CMD_BACKUP 64 // allow a lot of command backups for very fast systems
-
-//
-// the client_state_t structure is wiped completely at every
-// server map change
-//
-typedef struct
-{
- int timeoutcount;
-
- int timedemo_frames;
- int timedemo_start;
-
- qboolean refresh_prepped; // false if on new level or new ref dll
- qboolean sound_prepped; // ambient sounds can start
- qboolean force_refdef; // vid has changed, so we can't use a paused refdef
-
- int parse_entities; // index (not anded off) into cl_parse_entities[]
-
- usercmd_t cmd;
- usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds
- int cmd_time[CMD_BACKUP]; // time sent, for calculating pings
- short predicted_origins[CMD_BACKUP][3]; // for debug comparing against server
-
- float predicted_step; // for stair up smoothing
- unsigned predicted_step_time;
-
- vec3_t predicted_origin; // generated by CL_PredictMovement
- vec3_t predicted_angles;
- vec3_t prediction_error;
-
- frame_t frame; // received from server
- int surpressCount; // number of messages rate supressed
- frame_t frames[UPDATE_BACKUP];
-
- // the client maintains its own idea of view angles, which are
- // sent to the server each frame. It is cleared to 0 upon entering each level.
- // the server sends a delta each frame which is added to the locally
- // tracked view angles to account for standing on rotating objects,
- // and teleport direction changes
- vec3_t viewangles;
-
- int time; // this is the time value that the client
- // is rendering at. always <= cls.realtime
- float lerpfrac; // between oldframe and frame
-
- refdef_t refdef;
-
- vec3_t v_forward, v_right, v_up; // set when refdef.angles is set
-
- //
- // transient data from server
- //
- char layout[1024]; // general 2D overlay
- int inventory[MAX_ITEMS];
-
- //
- // non-gameserver infornamtion
- // FIXME: move this cinematic stuff into the cin_t structure
- FILE *cinematic_file;
- int cinematictime; // cls.realtime for first cinematic frame
- int cinematicframe;
- char cinematicpalette[768];
- qboolean cinematicpalette_active;
-
- //
- // server state information
- //
- qboolean attractloop; // running the attract loop, any key will menu
- int servercount; // server identification for prespawns
- char gamedir[MAX_QPATH];
- int playernum;
-
- char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
-
- //
- // locally derived information from server state
- //
- struct model_s *model_draw[MAX_MODELS];
- struct cmodel_s *model_clip[MAX_MODELS];
-
- struct sfx_s *sound_precache[MAX_SOUNDS];
- struct image_s *image_precache[MAX_IMAGES];
-
- clientinfo_t clientinfo[MAX_CLIENTS];
- clientinfo_t baseclientinfo;
-} client_state_t;
-
-extern client_state_t cl;
-/*
-==================================================================
-
-the client_static_t structure is persistant through an arbitrary number
-of server connections
-
-==================================================================
-*/
-
-typedef enum {
- ca_uninitialized,
- ca_disconnected, // not talking to a server
- ca_connecting, // sending request packets to the server
- ca_connected, // netchan_t established, waiting for svc_serverdata
- ca_active // game views should be displayed
-} connstate_t;
-
-typedef enum {
- dl_none,
- dl_model,
- dl_sound,
- dl_skin,
- dl_single
-} dltype_t; // download type
-
-typedef enum {key_game, key_console, key_message, key_menu} keydest_t;
-
-typedef struct
-{
- connstate_t state;
- keydest_t key_dest;
-
- int framecount;
- int realtime; // always increasing, no clamping, etc
- float frametime; // seconds since last frame
-
-// screen rendering information
- float disable_screen; // showing loading plaque between levels
- // or changing rendering dlls
- // if time gets > 30 seconds ahead, break it
- int disable_servercount; // when we receive a frame and cl.servercount
- // > cls.disable_servercount, clear disable_screen
-
-// connection information
- char servername[MAX_OSPATH]; // name of server from original connect
- float connect_time; // for connection retransmits
-
- int quakePort; // a 16 bit value that allows quake servers
- // to work around address translating routers
- netchan_t netchan;
- int serverProtocol; // in case we are doing some kind of version hack
-
- int challenge; // from the server to use for connecting
-
- FILE *download; // file transfer from server
- char downloadtempname[MAX_OSPATH];
- char downloadname[MAX_OSPATH];
- int downloadnumber;
- dltype_t downloadtype;
- int downloadpercent;
-
-// demo recording info must be here, so it isn't cleared on level change
- qboolean demorecording;
- qboolean demowaiting; // don't record until a non-delta message is received
- FILE *demofile;
-} client_static_t;
-
-extern client_static_t cls;
-
-//=============================================================================
-
-//
-// cvars
-//
-extern cvar_t *cl_stereo_separation;
-extern cvar_t *cl_stereo;
-
-extern cvar_t *cl_gun;
-extern cvar_t *cl_add_blend;
-extern cvar_t *cl_add_lights;
-extern cvar_t *cl_add_particles;
-extern cvar_t *cl_add_entities;
-extern cvar_t *cl_predict;
-extern cvar_t *cl_footsteps;
-extern cvar_t *cl_noskins;
-extern cvar_t *cl_autoskins;
-
-extern cvar_t *cl_upspeed;
-extern cvar_t *cl_forwardspeed;
-extern cvar_t *cl_sidespeed;
-
-extern cvar_t *cl_yawspeed;
-extern cvar_t *cl_pitchspeed;
-
-extern cvar_t *cl_run;
-
-extern cvar_t *cl_anglespeedkey;
-
-extern cvar_t *cl_shownet;
-extern cvar_t *cl_showmiss;
-extern cvar_t *cl_showclamp;
-
-extern cvar_t *cl_lightlevel; // FIXME HACK
-
-extern cvar_t *cl_paused;
-extern cvar_t *cl_timedemo;
-
-extern cvar_t *cl_vwep;
-
-typedef struct
-{
- int key; // so entities can reuse same entry
- vec3_t color;
- vec3_t origin;
- float radius;
- float die; // stop lighting after this time
- float decay; // drop this each second
- float minlight; // don't add when contributing less
-} cdlight_t;
-
-extern centity_t cl_entities[MAX_EDICTS];
-extern cdlight_t cl_dlights[MAX_DLIGHTS];
-
-// the cl_parse_entities must be large enough to hold UPDATE_BACKUP frames of
-// entities, so that when a delta compressed message arives from the server
-// it can be un-deltad from the original
-#define MAX_PARSE_ENTITIES 1024
-extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
-
-//=============================================================================
-
-extern netadr_t net_from;
-extern sizebuf_t net_message;
-
-void DrawString (int x, int y, char *s);
-void DrawAltString (int x, int y, char *s); // toggle high bit
-qboolean CL_CheckOrDownloadFile (char *filename);
-
-void CL_AddNetgraph (void);
-
-//ROGUE
-typedef struct cl_sustain
-{
- int id;
- int type;
- int endtime;
- int nextthink;
- int thinkinterval;
- vec3_t org;
- vec3_t dir;
- int color;
- int count;
- int magnitude;
- void (*think)(struct cl_sustain *self);
-} cl_sustain_t;
-
-#define MAX_SUSTAINS 32
-void CL_ParticleSteamEffect2(cl_sustain_t *self);
-
-void CL_TeleporterParticles (entity_state_t *ent);
-void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count);
-void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count);
-
-// RAFAEL
-void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count);
-
-
-//=================================================
-
-// ========
-// PGM
-typedef struct particle_s
-{
- struct particle_s *next;
-
- float time;
-
- vec3_t org;
- vec3_t vel;
- vec3_t accel;
- float color;
- float colorvel;
- float alpha;
- float alphavel;
-} cparticle_t;
-
-
-#define PARTICLE_GRAVITY 40
-#define BLASTER_PARTICLE_COLOR 0xe0
-// PMM
-#define INSTANT_PARTICLE -10000.0
-// PGM
-// ========
-
-void CL_ClearEffects (void);
-void CL_ClearTEnts (void);
-void CL_BlasterTrail (vec3_t start, vec3_t end);
-void CL_QuadTrail (vec3_t start, vec3_t end);
-void CL_RailTrail (vec3_t start, vec3_t end);
-void CL_BubbleTrail (vec3_t start, vec3_t end);
-void CL_FlagTrail (vec3_t start, vec3_t end, float color);
-
-// RAFAEL
-void CL_IonripperTrail (vec3_t start, vec3_t end);
-
-// ========
-// PGM
-void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color);
-void CL_BlasterTrail2 (vec3_t start, vec3_t end);
-void CL_DebugTrail (vec3_t start, vec3_t end);
-void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing);
-void CL_Flashlight (int ent, vec3_t pos);
-void CL_ForceWall (vec3_t start, vec3_t end, int color);
-void CL_FlameEffects (centity_t *ent, vec3_t origin);
-void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel);
-void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist);
-void CL_Heatbeam (vec3_t start, vec3_t end);
-void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude);
-void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor);
-void CL_Tracker_Explode(vec3_t origin);
-void CL_TagTrail (vec3_t start, vec3_t end, float color);
-void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b);
-void CL_Tracker_Shell(vec3_t origin);
-void CL_MonsterPlasma_Shell(vec3_t origin);
-void CL_ColorExplosionParticles (vec3_t org, int color, int run);
-void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude);
-void CL_Widowbeamout (cl_sustain_t *self);
-void CL_Nukeblast (cl_sustain_t *self);
-void CL_WidowSplash (vec3_t org);
-// PGM
-// ========
-
-int CL_ParseEntityBits (int *bits);
-void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits);
-void CL_ParseFrame (void);
-
-void CL_ParseTEnt (void);
-void CL_ParseConfigString (void);
-void CL_ParseMuzzleFlash (void);
-void CL_ParseMuzzleFlash2 (void);
-void SmokeAndFlash(vec3_t origin);
-
-void CL_SetLightstyle (int i);
-
-void CL_RunParticles (void);
-void CL_RunDLights (void);
-void CL_RunLightStyles (void);
-
-void CL_AddEntities (void);
-void CL_AddDLights (void);
-void CL_AddTEnts (void);
-void CL_AddLightStyles (void);
-
-//=================================================
-
-void CL_PrepRefresh (void);
-void CL_RegisterSounds (void);
-
-void CL_Quit_f (void);
-
-void IN_Accumulate (void);
-
-void CL_ParseLayout (void);
-
-
-//
-// cl_main
-//
-extern refexport_t re; // interface to refresh .dll
-
-void CL_Init (void);
-
-void CL_FixUpGender(void);
-void CL_Disconnect (void);
-void CL_Disconnect_f (void);
-void CL_GetChallengePacket (void);
-void CL_PingServers_f (void);
-void CL_Snd_Restart_f (void);
-void CL_RequestNextDownload (void);
-
-//
-// cl_input
-//
-typedef struct
-{
- int down[2]; // key nums holding it down
- unsigned downtime; // msec timestamp
- unsigned msec; // msec down this frame
- int state;
-} kbutton_t;
-
-extern kbutton_t in_mlook, in_klook;
-extern kbutton_t in_strafe;
-extern kbutton_t in_speed;
-
-void CL_InitInput (void);
-void CL_SendCmd (void);
-void CL_SendMove (usercmd_t *cmd);
-
-void CL_ClearState (void);
-
-void CL_ReadPackets (void);
-
-int CL_ReadFromServer (void);
-void CL_WriteToServer (usercmd_t *cmd);
-void CL_BaseMove (usercmd_t *cmd);
-
-void IN_CenterView (void);
-
-float CL_KeyState (kbutton_t *key);
-char *Key_KeynumToString (int keynum);
-
-//
-// cl_demo.c
-//
-void CL_WriteDemoMessage (void);
-void CL_Stop_f (void);
-void CL_Record_f (void);
-
-//
-// cl_parse.c
-//
-extern char *svc_strings[256];
-
-void CL_ParseServerMessage (void);
-void CL_LoadClientinfo (clientinfo_t *ci, char *s);
-void SHOWNET(char *s);
-void CL_ParseClientinfo (int player);
-void CL_Download_f (void);
-
-//
-// cl_view.c
-//
-extern int gun_frame;
-extern struct model_s *gun_model;
-
-void V_Init (void);
-void V_RenderView( float stereo_separation );
-void V_AddEntity (entity_t *ent);
-void V_AddParticle (vec3_t org, int color, float alpha);
-void V_AddLight (vec3_t org, float intensity, float r, float g, float b);
-void V_AddLightStyle (int style, float r, float g, float b);
-
-//
-// cl_tent.c
-//
-void CL_RegisterTEntSounds (void);
-void CL_RegisterTEntModels (void);
-void CL_SmokeAndFlash(vec3_t origin);
-
-
-//
-// cl_pred.c
-//
-void CL_InitPrediction (void);
-void CL_PredictMove (void);
-void CL_CheckPredictionError (void);
-
-//
-// cl_fx.c
-//
-cdlight_t *CL_AllocDlight (int key);
-void CL_BigTeleportParticles (vec3_t org);
-void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old);
-void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags);
-void CL_FlyEffect (centity_t *ent, vec3_t origin);
-void CL_BfgParticles (entity_t *ent);
-void CL_AddParticles (void);
-void CL_EntityEvent (entity_state_t *ent);
-// RAFAEL
-void CL_TrapParticles (entity_t *ent);
-
-//
-// menus
-//
-void M_Init (void);
-void M_Keydown (int key);
-void M_Draw (void);
-void M_Menu_Main_f (void);
-void M_ForceMenuOff (void);
-void M_AddToServerList (netadr_t adr, char *info);
-
-//
-// cl_inv.c
-//
-void CL_ParseInventory (void);
-void CL_KeyInventory (int key);
-void CL_DrawInventory (void);
-
-//
-// cl_pred.c
-//
-void CL_PredictMovement (void);
-
-#ifdef id386
-void x86_TimerStart( void );
-void x86_TimerStop( void );
-void x86_TimerInit( unsigned long smallest, unsigned longest );
-unsigned long *x86_TimerGetHistogram( void );
-#endif
--- a/client/console.c
+++ /dev/null
@@ -1,660 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-console_t con;
-
-cvar_t *con_notifytime;
-
-
-#define MAXCMDLINE 256
-extern char key_lines[32][MAXCMDLINE];
-extern int edit_line;
-extern int key_linepos;
-
-
-void DrawString (int x, int y, char *s)
-{
- while (*s)
- {
- re.DrawChar (x, y, *s);
- x+=8;
- s++;
- }
-}
-
-void DrawAltString (int x, int y, char *s)
-{
- while (*s)
- {
- re.DrawChar (x, y, *s ^ 0x80);
- x+=8;
- s++;
- }
-}
-
-
-void Key_ClearTyping (void)
-{
- key_lines[edit_line][1] = 0; // clear any typing
- key_linepos = 1;
-}
-
-/*
-================
-Con_ToggleConsole_f
-================
-*/
-void Con_ToggleConsole_f (void)
-{
- SCR_EndLoadingPlaque (); // get rid of loading plaque
-
- if (cl.attractloop)
- {
- Cbuf_AddText ("killserver\n");
- return;
- }
-
- if (cls.state == ca_disconnected)
- { // start the demo loop again
- Cbuf_AddText ("d1\n");
- return;
- }
-
- Key_ClearTyping ();
- Con_ClearNotify ();
-
- if (cls.key_dest == key_console)
- {
- M_ForceMenuOff ();
- Cvar_Set ("paused", "0");
- IN_Grabm (1);
- }
- else
- {
- M_ForceMenuOff ();
- cls.key_dest = key_console;
-
- if (Cvar_VariableValue ("maxclients") == 1
- && Com_ServerState ())
- Cvar_Set ("paused", "1");
- IN_Grabm (0);
- }
-}
-
-/*
-================
-Con_ToggleChat_f
-================
-*/
-void Con_ToggleChat_f (void)
-{
- Key_ClearTyping ();
-
- if (cls.key_dest == key_console)
- {
- if (cls.state == ca_active)
- {
- M_ForceMenuOff ();
- cls.key_dest = key_game;
- }
- }
- else
- cls.key_dest = key_console;
-
- Con_ClearNotify ();
-}
-
-/*
-================
-Con_Clear_f
-================
-*/
-void Con_Clear_f (void)
-{
- memset (con.text, ' ', CON_TEXTSIZE);
-}
-
-
-/*
-================
-Con_Dump_f
-
-Save the console contents out to a file
-================
-*/
-void Con_Dump_f (void)
-{
- int l, x;
- char *line;
- FILE *f;
- char buffer[1024];
- char name[MAX_OSPATH];
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("usage: condump <filename>\n");
- return;
- }
-
- Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1));
-
- Com_Printf ("Dumped console text to %s.\n", name);
- FS_CreatePath (name);
- f = fopen (name, "w");
- if (!f)
- {
- Com_Printf ("ERROR: couldn't open.\n");
- return;
- }
-
- // skip empty lines
- for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
- {
- line = con.text + (l%con.totallines)*con.linewidth;
- for (x=0 ; x<con.linewidth ; x++)
- if (line[x] != ' ')
- break;
- if (x != con.linewidth)
- break;
- }
-
- // write the remaining lines
- buffer[con.linewidth] = 0;
- for ( ; l <= con.current ; l++)
- {
- line = con.text + (l%con.totallines)*con.linewidth;
- strncpy (buffer, line, con.linewidth);
- for (x=con.linewidth-1 ; x>=0 ; x--)
- {
- if (buffer[x] == ' ')
- buffer[x] = 0;
- else
- break;
- }
- for (x=0; buffer[x]; x++)
- buffer[x] &= 0x7f;
-
- fprintf (f, "%s\n", buffer);
- }
-
- fclose (f);
-}
-
-
-/*
-================
-Con_ClearNotify
-================
-*/
-void Con_ClearNotify (void)
-{
- int i;
-
- for (i=0 ; i<NUM_CON_TIMES ; i++)
- con.times[i] = 0;
-}
-
-
-/*
-================
-Con_MessageMode_f
-================
-*/
-void Con_MessageMode_f (void)
-{
- chat_team = false;
- cls.key_dest = key_message;
-}
-
-/*
-================
-Con_MessageMode2_f
-================
-*/
-void Con_MessageMode2_f (void)
-{
- chat_team = true;
- cls.key_dest = key_message;
-}
-
-/*
-================
-Con_CheckResize
-
-If the line width has changed, reformat the buffer.
-================
-*/
-void Con_CheckResize (void)
-{
- int i, j, width, oldwidth, oldtotallines, numlines, numchars;
- char tbuf[CON_TEXTSIZE];
-
- width = (vid.width >> 3) - 2;
-
- if (width == con.linewidth)
- return;
-
- if (width < 1) // video hasn't been initialized yet
- {
- width = 38;
- con.linewidth = width;
- con.totallines = CON_TEXTSIZE / con.linewidth;
- memset (con.text, ' ', CON_TEXTSIZE);
- }
- else
- {
- oldwidth = con.linewidth;
- con.linewidth = width;
- oldtotallines = con.totallines;
- con.totallines = CON_TEXTSIZE / con.linewidth;
- numlines = oldtotallines;
-
- if (con.totallines < numlines)
- numlines = con.totallines;
-
- numchars = oldwidth;
-
- if (con.linewidth < numchars)
- numchars = con.linewidth;
-
- memcpy (tbuf, con.text, CON_TEXTSIZE);
- memset (con.text, ' ', CON_TEXTSIZE);
-
- for (i=0 ; i<numlines ; i++)
- {
- for (j=0 ; j<numchars ; j++)
- {
- con.text[(con.totallines - 1 - i) * con.linewidth + j] =
- tbuf[((con.current - i + oldtotallines) %
- oldtotallines) * oldwidth + j];
- }
- }
-
- Con_ClearNotify ();
- }
-
- con.current = con.totallines - 1;
- con.display = con.current;
-}
-
-
-/*
-================
-Con_Init
-================
-*/
-void Con_Init (void)
-{
- con.linewidth = -1;
-
- Con_CheckResize ();
-
- Com_Printf ("Console initialized.\n");
-
-//
-// register our commands
-//
- con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
-
- Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
- Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
- Cmd_AddCommand ("messagemode", Con_MessageMode_f);
- Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
- Cmd_AddCommand ("clear", Con_Clear_f);
- Cmd_AddCommand ("condump", Con_Dump_f);
- con.initialized = true;
-}
-
-
-/*
-===============
-Con_Linefeed
-===============
-*/
-void Con_Linefeed (void)
-{
- con.x = 0;
- if (con.display == con.current)
- con.display++;
- con.current++;
- memset (&con.text[(con.current%con.totallines)*con.linewidth]
- , ' ', con.linewidth);
-}
-
-/*
-================
-Con_Print
-
-Handles cursor positioning, line wrapping, etc
-All console printing must go through this in order to be logged to disk
-If no console is visible, the text will appear at the top of the game window
-================
-*/
-void Con_Print (char *txt)
-{
- int y;
- int c, l;
- static int cr;
- int mask;
-
- if (!con.initialized)
- return;
-
- if (txt[0] == 1 || txt[0] == 2)
- {
- mask = 128; // go to colored text
- txt++;
- }
- else
- mask = 0;
-
-
- while ( (c = *txt) )
- {
- // count word length
- for (l=0 ; l< con.linewidth ; l++)
- if ( txt[l] <= ' ')
- break;
-
- // word wrap
- if (l != con.linewidth && (con.x + l > con.linewidth) )
- con.x = 0;
-
- txt++;
-
- if (cr)
- {
- con.current--;
- cr = false;
- }
-
-
- if (!con.x)
- {
- Con_Linefeed ();
- // mark time for transparent overlay
- if (con.current >= 0)
- con.times[con.current % NUM_CON_TIMES] = cls.realtime;
- }
-
- switch (c)
- {
- case '\n':
- con.x = 0;
- break;
-
- case '\r':
- con.x = 0;
- cr = 1;
- break;
-
- default: // display character and advance
- y = con.current % con.totallines;
- con.text[y*con.linewidth+con.x] = c | mask | con.ormask;
- con.x++;
- if (con.x >= con.linewidth)
- con.x = 0;
- break;
- }
-
- }
-}
-
-
-/*
-==============
-Con_CenteredPrint
-==============
-*/
-void Con_CenteredPrint (char *text)
-{
- int l;
- char buffer[1024];
-
- l = strlen(text);
- l = (con.linewidth-l)/2;
- if (l < 0)
- l = 0;
- memset (buffer, ' ', l);
- strcpy (buffer+l, text);
- strcat (buffer, "\n");
- Con_Print (buffer);
-}
-
-/*
-==============================================================================
-
-DRAWING
-
-==============================================================================
-*/
-
-
-/*
-================
-Con_DrawInput
-
-The input line scrolls horizontally if typing goes beyond the right edge
-================
-*/
-void Con_DrawInput (void)
-{
- int i;
- char *text;
-
- if (cls.key_dest == key_menu)
- return;
- if (cls.key_dest != key_console && cls.state == ca_active)
- return; // don't draw anything (always draw if not active)
-
- text = key_lines[edit_line];
-
-// add the cursor frame
- text[key_linepos] = 10+((int)(cls.realtime>>8)&1);
-
-// fill out remainder with spaces
- for (i=key_linepos+1 ; i< con.linewidth ; i++)
- text[i] = ' ';
-
-// prestep if horizontally scrolling
- if (key_linepos >= con.linewidth)
- text += 1 + key_linepos - con.linewidth;
-
-// draw it
- for (i=0 ; i<con.linewidth ; i++)
- re.DrawChar ( (i+1)<<3, con.vislines - 22, text[i]);
-
-// remove cursor
- key_lines[edit_line][key_linepos] = 0;
-}
-
-
-/*
-================
-Con_DrawNotify
-
-Draws the last few lines of output transparently over the game top
-================
-*/
-void Con_DrawNotify (void)
-{
- int x, v;
- char *text;
- int i;
- int time;
- char *s;
- int skip;
-
- v = 0;
- for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
- {
- if (i < 0)
- continue;
- time = con.times[i % NUM_CON_TIMES];
- if (time == 0)
- continue;
- time = cls.realtime - time;
- if (time > con_notifytime->value*1000)
- continue;
- text = con.text + (i % con.totallines)*con.linewidth;
-
- for (x = 0 ; x < con.linewidth ; x++)
- re.DrawChar ( (x+1)<<3, v, text[x]);
-
- v += 8;
- }
-
-
- if (cls.key_dest == key_message)
- {
- if (chat_team)
- {
- DrawString (8, v, "say_team:");
- skip = 11;
- }
- else
- {
- DrawString (8, v, "say:");
- skip = 5;
- }
-
- s = chat_buffer;
- if (chat_bufferlen > (vid.width>>3)-(skip+1))
- s += chat_bufferlen - ((vid.width>>3)-(skip+1));
- x = 0;
- while(s[x])
- {
- re.DrawChar ( (x+skip)<<3, v, s[x]);
- x++;
- }
- re.DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1));
- v += 8;
- }
-
- if (v)
- {
- SCR_AddDirtyPoint (0,0);
- SCR_AddDirtyPoint (vid.width-1, v);
- }
-}
-
-/*
-================
-Con_DrawConsole
-
-Draws the console with the solid background
-================
-*/
-void Con_DrawConsole (float frac)
-{
- int i, j, x, y, n;
- int rows;
- char *text;
- int row;
- int lines;
- char version[64];
- char dlbar[1024];
-
- lines = vid.height * frac;
- if (lines <= 0)
- return;
-
- if (lines > vid.height)
- lines = vid.height;
-
-// draw the background
- re.DrawStretchPic (0, -vid.height+lines, vid.width, vid.height, "conback");
- SCR_AddDirtyPoint (0,0);
- SCR_AddDirtyPoint (vid.width-1,lines-1);
-
- Com_sprintf (version, sizeof(version), "v%4.2f", VERSION);
- for (x=0 ; x<5 ; x++)
- re.DrawChar (vid.width-44+x*8, lines-12, 128 + version[x] );
-
-// draw the text
- con.vislines = lines;
-
-/*
- rows = (lines-8)>>3; // rows of text to draw
-
- y = lines - 24;
-*/
- rows = (lines-22)>>3; // rows of text to draw
-
- y = lines - 30;
-
-// draw from the bottom up
- if (con.display != con.current)
- {
- // draw arrows to show the buffer is backscrolled
- for (x=0 ; x<con.linewidth ; x+=4)
- re.DrawChar ( (x+1)<<3, y, '^');
-
- y -= 8;
- rows--;
- }
-
- row = con.display;
- for (i=0 ; i<rows ; i++, y-=8, row--)
- {
- if (row < 0)
- break;
- if (con.current - row >= con.totallines)
- break; // past scrollback wrap point
-
- text = con.text + (row % con.totallines)*con.linewidth;
-
- for (x=0 ; x<con.linewidth ; x++)
- re.DrawChar ( (x+1)<<3, y, text[x]);
- }
-
-//ZOID
- // draw the download bar
- // figure out width
- if (cls.download) {
- if ((text = strrchr(cls.downloadname, '/')) != NULL)
- text++;
- else
- text = cls.downloadname;
-
- x = con.linewidth - ((con.linewidth * 7) / 40);
- y = x - strlen(text) - 8;
- i = con.linewidth/3;
- if (strlen(text) > i) {
- y = x - i - 11;
- strncpy(dlbar, text, i);
- dlbar[i] = 0;
- strcat(dlbar, "...");
- } else
- strcpy(dlbar, text);
- strcat(dlbar, ": ");
- i = strlen(dlbar);
- dlbar[i++] = 0x80;
- // where's the dot go?
- if (cls.downloadpercent == 0)
- n = 0;
- else
- n = y * cls.downloadpercent / 100;
-
- for (j = 0; j < y; j++)
- if (j == n)
- dlbar[i++] = 0x83;
- else
- dlbar[i++] = 0x81;
- dlbar[i++] = 0x82;
- dlbar[i] = 0;
-
- sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
-
- // draw it
- y = con.vislines-12;
- for (i = 0; i < strlen(dlbar); i++)
- re.DrawChar ( (i+1)<<3, y, dlbar[i]);
- }
-//ZOID
-
-// draw the input prompt, user text, and cursor if desired
- Con_DrawInput ();
-}
--- a/client/console.h
+++ /dev/null
@@ -1,38 +1,0 @@
-#define NUM_CON_TIMES 4
-
-#define CON_TEXTSIZE 32768
-typedef struct
-{
- qboolean initialized;
-
- char text[CON_TEXTSIZE];
- int current; // line where next message will be printed
- int x; // offset in current line for next print
- int display; // bottom of console displays this line
-
- int ormask; // high bit mask for colored characters
-
- int linewidth; // characters across screen
- int totallines; // total lines in console scrollback
-
- float cursorspeed;
-
- int vislines;
-
- float times[NUM_CON_TIMES]; // cls.realtime time the line was generated
- // for transparent notify lines
-} console_t;
-
-extern console_t con;
-
-void Con_DrawCharacter (int cx, int line, int num);
-
-void Con_CheckResize (void);
-void Con_Init (void);
-void Con_DrawConsole (float frac);
-void Con_Print (char *txt);
-void Con_CenteredPrint (char *text);
-void Con_Clear_f (void);
-void Con_DrawNotify (void);
-void Con_ClearNotify (void);
-void Con_ToggleConsole_f (void);
--- a/client/input.h
+++ /dev/null
@@ -1,24 +1,0 @@
-// input.h -- external (non-keyboard) input devices
-
-extern cvar_t *in_joystick;
-extern cvar_t *lookspring;
-extern cvar_t *lookstrafe;
-extern cvar_t *sensitivity;
-extern cvar_t *freelook;
-extern cvar_t *m_pitch;
-
-void IN_Init (void);
-
-void IN_Shutdown (void);
-
-void IN_Commands (void);
-// oportunity for devices to stick commands on the script buffer
-
-void IN_Frame (void);
-
-void IN_Move (usercmd_t *cmd);
-// add additional movement on top of the keyboard move cmd
-
-void IN_Activate (qboolean active);
-
-void IN_Grabm(int on);
--- a/client/keys.c
+++ /dev/null
@@ -1,927 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-
-key up events are sent even if in console mode
-
-*/
-
-
-#define MAXCMDLINE 256
-char key_lines[32][MAXCMDLINE];
-int key_linepos;
-int shift_down=false;
-int anykeydown;
-
-int edit_line=0;
-int history_line=0;
-
-int key_waiting;
-char *keybindings[256];
-qboolean consolekeys[256]; // if true, can't be rebound while in console
-qboolean menubound[256]; // if true, can't be rebound while in menu
-int keyshift[256]; // key to map to if shift held down in console
-int key_repeats[256]; // if > 1, it is autorepeating
-qboolean keydown[256];
-
-typedef struct
-{
- char *name;
- int keynum;
-} keyname_t;
-
-keyname_t keynames[] =
-{
- {"TAB", K_TAB},
- {"ENTER", K_ENTER},
- {"ESCAPE", K_ESCAPE},
- {"SPACE", K_SPACE},
- {"BACKSPACE", K_BACKSPACE},
- {"UPARROW", K_UPARROW},
- {"DOWNARROW", K_DOWNARROW},
- {"LEFTARROW", K_LEFTARROW},
- {"RIGHTARROW", K_RIGHTARROW},
-
- {"ALT", K_ALT},
- {"CTRL", K_CTRL},
- {"SHIFT", K_SHIFT},
-
- {"F1", K_F1},
- {"F2", K_F2},
- {"F3", K_F3},
- {"F4", K_F4},
- {"F5", K_F5},
- {"F6", K_F6},
- {"F7", K_F7},
- {"F8", K_F8},
- {"F9", K_F9},
- {"F10", K_F10},
- {"F11", K_F11},
- {"F12", K_F12},
-
- {"INS", K_INS},
- {"DEL", K_DEL},
- {"PGDN", K_PGDN},
- {"PGUP", K_PGUP},
- {"HOME", K_HOME},
- {"END", K_END},
-
- {"MOUSE1", K_MOUSE1},
- {"MOUSE2", K_MOUSE2},
- {"MOUSE3", K_MOUSE3},
-
- {"JOY1", K_JOY1},
- {"JOY2", K_JOY2},
- {"JOY3", K_JOY3},
- {"JOY4", K_JOY4},
-
- {"AUX1", K_AUX1},
- {"AUX2", K_AUX2},
- {"AUX3", K_AUX3},
- {"AUX4", K_AUX4},
- {"AUX5", K_AUX5},
- {"AUX6", K_AUX6},
- {"AUX7", K_AUX7},
- {"AUX8", K_AUX8},
- {"AUX9", K_AUX9},
- {"AUX10", K_AUX10},
- {"AUX11", K_AUX11},
- {"AUX12", K_AUX12},
- {"AUX13", K_AUX13},
- {"AUX14", K_AUX14},
- {"AUX15", K_AUX15},
- {"AUX16", K_AUX16},
- {"AUX17", K_AUX17},
- {"AUX18", K_AUX18},
- {"AUX19", K_AUX19},
- {"AUX20", K_AUX20},
- {"AUX21", K_AUX21},
- {"AUX22", K_AUX22},
- {"AUX23", K_AUX23},
- {"AUX24", K_AUX24},
- {"AUX25", K_AUX25},
- {"AUX26", K_AUX26},
- {"AUX27", K_AUX27},
- {"AUX28", K_AUX28},
- {"AUX29", K_AUX29},
- {"AUX30", K_AUX30},
- {"AUX31", K_AUX31},
- {"AUX32", K_AUX32},
-
- {"KP_HOME", K_KP_HOME },
- {"KP_UPARROW", K_KP_UPARROW },
- {"KP_PGUP", K_KP_PGUP },
- {"KP_LEFTARROW", K_KP_LEFTARROW },
- {"KP_5", K_KP_5 },
- {"KP_RIGHTARROW", K_KP_RIGHTARROW },
- {"KP_END", K_KP_END },
- {"KP_DOWNARROW", K_KP_DOWNARROW },
- {"KP_PGDN", K_KP_PGDN },
- {"KP_ENTER", K_KP_ENTER },
- {"KP_INS", K_KP_INS },
- {"KP_DEL", K_KP_DEL },
- {"KP_SLASH", K_KP_SLASH },
- {"KP_MINUS", K_KP_MINUS },
- {"KP_PLUS", K_KP_PLUS },
-
- {"MWHEELUP", K_MWHEELUP },
- {"MWHEELDOWN", K_MWHEELDOWN },
-
- {"PAUSE", K_PAUSE},
-
- {"SEMICOLON", ';'}, // because a raw semicolon seperates commands
-
- {NULL,0}
-};
-
-/*
-==============================================================================
-
- LINE TYPING INTO THE CONSOLE
-
-==============================================================================
-*/
-
-void CompleteCommand (void)
-{
- char *cmd, *s;
-
- s = key_lines[edit_line]+1;
- if (*s == '\\' || *s == '/')
- s++;
-
- cmd = Cmd_CompleteCommand (s);
- if (!cmd)
- cmd = Cvar_CompleteVariable (s);
- if (cmd)
- {
- key_lines[edit_line][1] = '/';
- strcpy (key_lines[edit_line]+2, cmd);
- key_linepos = strlen(cmd)+2;
- key_lines[edit_line][key_linepos] = ' ';
- key_linepos++;
- key_lines[edit_line][key_linepos] = 0;
- return;
- }
-}
-
-/*
-====================
-Key_Console
-
-Interactive line editing and console scrollback
-====================
-*/
-void Key_Console (int key)
-{
-
- switch ( key )
- {
- case K_KP_SLASH:
- key = '/';
- break;
- case K_KP_MINUS:
- key = '-';
- break;
- case K_KP_PLUS:
- key = '+';
- break;
- case K_KP_HOME:
- key = '7';
- break;
- case K_KP_UPARROW:
- key = '8';
- break;
- case K_KP_PGUP:
- key = '9';
- break;
- case K_KP_LEFTARROW:
- key = '4';
- break;
- case K_KP_5:
- key = '5';
- break;
- case K_KP_RIGHTARROW:
- key = '6';
- break;
- case K_KP_END:
- key = '1';
- break;
- case K_KP_DOWNARROW:
- key = '2';
- break;
- case K_KP_PGDN:
- key = '3';
- break;
- case K_KP_INS:
- key = '0';
- break;
- case K_KP_DEL:
- key = '.';
- break;
- }
-
- if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
- ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
- {
- char *cbd;
-
- if ( ( cbd = Sys_GetClipboardData() ) != 0 )
- {
- int i;
-
- strtok( cbd, "\n\r\b" );
-
- i = strlen( cbd );
- if ( i + key_linepos >= MAXCMDLINE)
- i= MAXCMDLINE - key_linepos;
-
- if ( i > 0 )
- {
- cbd[i]=0;
- strcat( key_lines[edit_line], cbd );
- key_linepos += i;
- }
- free( cbd );
- }
-
- return;
- }
-
- if ( key == 'l' )
- {
- if ( keydown[K_CTRL] )
- {
- Cbuf_AddText ("clear\n");
- return;
- }
- }
-
- if ( key == K_ENTER || key == K_KP_ENTER )
- { // backslash text are commands, else chat
- if (key_lines[edit_line][1] == '\\' || key_lines[edit_line][1] == '/')
- Cbuf_AddText (key_lines[edit_line]+2); // skip the >
- else
- Cbuf_AddText (key_lines[edit_line]+1); // valid command
-
- Cbuf_AddText ("\n");
- Com_Printf ("%s\n",key_lines[edit_line]);
- edit_line = (edit_line + 1) & 31;
- history_line = edit_line;
- key_lines[edit_line][0] = ']';
- key_linepos = 1;
- if (cls.state == ca_disconnected)
- SCR_UpdateScreen (); // force an update, because the command
- // may take some time
- return;
- }
-
- if (key == K_TAB)
- { // command completion
- CompleteCommand ();
- return;
- }
-
- if ( ( key == K_BACKSPACE ) || ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) || ( ( key == 'h' ) && ( keydown[K_CTRL] ) ) )
- {
- if (key_linepos > 1)
- key_linepos--;
- return;
- }
-
- if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
- ( ( key == 'p' ) && keydown[K_CTRL] ) )
- {
- do
- {
- history_line = (history_line - 1) & 31;
- } while (history_line != edit_line
- && !key_lines[history_line][1]);
- if (history_line == edit_line)
- history_line = (edit_line+1)&31;
- strcpy(key_lines[edit_line], key_lines[history_line]);
- key_linepos = strlen(key_lines[edit_line]);
- return;
- }
-
- if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
- ( ( key == 'n' ) && keydown[K_CTRL] ) )
- {
- if (history_line == edit_line) return;
- do
- {
- history_line = (history_line + 1) & 31;
- }
- while (history_line != edit_line
- && !key_lines[history_line][1]);
- if (history_line == edit_line)
- {
- key_lines[edit_line][0] = ']';
- key_linepos = 1;
- }
- else
- {
- strcpy(key_lines[edit_line], key_lines[history_line]);
- key_linepos = strlen(key_lines[edit_line]);
- }
- return;
- }
-
- if (key == K_PGUP || key == K_KP_PGUP )
- {
- con.display -= 2;
- return;
- }
-
- if (key == K_PGDN || key == K_KP_PGDN )
- {
- con.display += 2;
- if (con.display > con.current)
- con.display = con.current;
- return;
- }
-
- if (key == K_HOME || key == K_KP_HOME )
- {
- con.display = con.current - con.totallines + 10;
- return;
- }
-
- if (key == K_END || key == K_KP_END )
- {
- con.display = con.current;
- return;
- }
-
- if (key < 32 || key > 127)
- return; // non printable
-
- if (key_linepos < MAXCMDLINE-1)
- {
- key_lines[edit_line][key_linepos] = key;
- key_linepos++;
- key_lines[edit_line][key_linepos] = 0;
- }
-
-}
-
-//============================================================================
-
-qboolean chat_team;
-char chat_buffer[MAXCMDLINE];
-int chat_bufferlen = 0;
-
-void Key_Message (int key)
-{
-
- if ( key == K_ENTER || key == K_KP_ENTER )
- {
- if (chat_team)
- Cbuf_AddText ("say_team \"");
- else
- Cbuf_AddText ("say \"");
- Cbuf_AddText(chat_buffer);
- Cbuf_AddText("\"\n");
-
- cls.key_dest = key_game;
- chat_bufferlen = 0;
- chat_buffer[0] = 0;
- return;
- }
-
- if (key == K_ESCAPE)
- {
- cls.key_dest = key_game;
- chat_bufferlen = 0;
- chat_buffer[0] = 0;
- return;
- }
-
- if (key < 32 || key > 127)
- return; // non printable
-
- if (key == K_BACKSPACE)
- {
- if (chat_bufferlen)
- {
- chat_bufferlen--;
- chat_buffer[chat_bufferlen] = 0;
- }
- return;
- }
-
- if (chat_bufferlen == sizeof(chat_buffer)-1)
- return; // all full
-
- chat_buffer[chat_bufferlen++] = key;
- chat_buffer[chat_bufferlen] = 0;
-}
-
-//============================================================================
-
-
-/*
-===================
-Key_StringToKeynum
-
-Returns a key number to be used to index keybindings[] by looking at
-the given string. Single ascii characters return themselves, while
-the K_* names are matched up.
-===================
-*/
-int Key_StringToKeynum (char *str)
-{
- keyname_t *kn;
-
- if (!str || !str[0])
- return -1;
- if (!str[1])
- return str[0];
-
- for (kn=keynames ; kn->name ; kn++)
- {
- if (!cistrcmp(str,kn->name))
- return kn->keynum;
- }
- return -1;
-}
-
-/*
-===================
-Key_KeynumToString
-
-Returns a string (either a single ascii char, or a K_* name) for the
-given keynum.
-FIXME: handle quote special (general escape sequence?)
-===================
-*/
-char *Key_KeynumToString (int keynum)
-{
- keyname_t *kn;
- static char tinystr[2];
-
- if (keynum == -1)
- return "<KEY NOT FOUND>";
- if (keynum > 32 && keynum < 127)
- { // printable ascii
- tinystr[0] = keynum;
- tinystr[1] = 0;
- return tinystr;
- }
-
- for (kn=keynames ; kn->name ; kn++)
- if (keynum == kn->keynum)
- return kn->name;
-
- return "<UNKNOWN KEYNUM>";
-}
-
-
-/*
-===================
-Key_SetBinding
-===================
-*/
-void Key_SetBinding (int keynum, char *binding)
-{
- char *new;
- int l;
-
- if (keynum == -1)
- return;
-
-// free old bindings
- if (keybindings[keynum])
- {
- Z_Free (keybindings[keynum]);
- keybindings[keynum] = NULL;
- }
-
-// allocate memory for new binding
- l = strlen (binding);
- new = Z_Malloc (l+1);
- strcpy (new, binding);
- new[l] = 0;
- keybindings[keynum] = new;
-}
-
-/*
-===================
-Key_Unbind_f
-===================
-*/
-void Key_Unbind_f (void)
-{
- int b;
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("unbind <key> : remove commands from a key\n");
- return;
- }
-
- b = Key_StringToKeynum (Cmd_Argv(1));
- if (b==-1)
- {
- Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
- return;
- }
-
- Key_SetBinding (b, "");
-}
-
-void Key_Unbindall_f (void)
-{
- int i;
-
- for (i=0 ; i<256 ; i++)
- if (keybindings[i])
- Key_SetBinding (i, "");
-}
-
-
-/*
-===================
-Key_Bind_f
-===================
-*/
-void Key_Bind_f (void)
-{
- int i, c, b;
- char cmd[1024];
-
- c = Cmd_Argc();
-
- if (c < 2)
- {
- Com_Printf ("bind <key> [command] : attach a command to a key\n");
- return;
- }
- b = Key_StringToKeynum (Cmd_Argv(1));
- if (b==-1)
- {
- Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
- return;
- }
-
- if (c == 2)
- {
- if (keybindings[b])
- Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
- else
- Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
- return;
- }
-
-// copy the rest of the command line
- cmd[0] = 0; // start out with a null string
- for (i=2 ; i< c ; i++)
- {
- strcat (cmd, Cmd_Argv(i));
- if (i != (c-1))
- strcat (cmd, " ");
- }
-
- Key_SetBinding (b, cmd);
-}
-
-/*
-============
-Key_WriteBindings
-
-Writes lines containing "bind key value"
-============
-*/
-void Key_WriteBindings (FILE *f)
-{
- int i;
-
- for (i=0 ; i<256 ; i++)
- if (keybindings[i] && keybindings[i][0])
- fprintf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
-}
-
-
-/*
-============
-Key_Bindlist_f
-
-============
-*/
-void Key_Bindlist_f (void)
-{
- int i;
-
- for (i=0 ; i<256 ; i++)
- if (keybindings[i] && keybindings[i][0])
- Com_Printf ("%s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
-}
-
-
-/*
-===================
-Key_Init
-===================
-*/
-void Key_Init (void)
-{
- int i;
-
- for (i=0 ; i<32 ; i++)
- {
- key_lines[i][0] = ']';
- key_lines[i][1] = 0;
- }
- key_linepos = 1;
-
-//
-// init ascii characters in console mode
-//
- for (i=32 ; i<128 ; i++)
- consolekeys[i] = true;
- consolekeys[K_ENTER] = true;
- consolekeys[K_KP_ENTER] = true;
- consolekeys[K_TAB] = true;
- consolekeys[K_LEFTARROW] = true;
- consolekeys[K_KP_LEFTARROW] = true;
- consolekeys[K_RIGHTARROW] = true;
- consolekeys[K_KP_RIGHTARROW] = true;
- consolekeys[K_UPARROW] = true;
- consolekeys[K_KP_UPARROW] = true;
- consolekeys[K_DOWNARROW] = true;
- consolekeys[K_KP_DOWNARROW] = true;
- consolekeys[K_BACKSPACE] = true;
- consolekeys[K_HOME] = true;
- consolekeys[K_KP_HOME] = true;
- consolekeys[K_END] = true;
- consolekeys[K_KP_END] = true;
- consolekeys[K_PGUP] = true;
- consolekeys[K_KP_PGUP] = true;
- consolekeys[K_PGDN] = true;
- consolekeys[K_KP_PGDN] = true;
- consolekeys[K_SHIFT] = true;
- consolekeys[K_INS] = true;
- consolekeys[K_KP_INS] = true;
- consolekeys[K_KP_DEL] = true;
- consolekeys[K_KP_SLASH] = true;
- consolekeys[K_KP_PLUS] = true;
- consolekeys[K_KP_MINUS] = true;
- consolekeys[K_KP_5] = true;
-
- consolekeys['`'] = false;
- consolekeys['~'] = false;
-
- for (i=0 ; i<256 ; i++)
- keyshift[i] = i;
- for (i='a' ; i<='z' ; i++)
- keyshift[i] = i - 'a' + 'A';
- keyshift['1'] = '!';
- keyshift['2'] = '@';
- keyshift['3'] = '#';
- keyshift['4'] = '$';
- keyshift['5'] = '%';
- keyshift['6'] = '^';
- keyshift['7'] = '&';
- keyshift['8'] = '*';
- keyshift['9'] = '(';
- keyshift['0'] = ')';
- keyshift['-'] = '_';
- keyshift['='] = '+';
- keyshift[','] = '<';
- keyshift['.'] = '>';
- keyshift['/'] = '?';
- keyshift[';'] = ':';
- keyshift['\''] = '"';
- keyshift['['] = '{';
- keyshift[']'] = '}';
- keyshift['`'] = '~';
- keyshift['\\'] = '|';
-
- menubound[K_ESCAPE] = true;
- for (i=0 ; i<12 ; i++)
- menubound[K_F1+i] = true;
-
-//
-// register our functions
-//
- Cmd_AddCommand ("bind",Key_Bind_f);
- Cmd_AddCommand ("unbind",Key_Unbind_f);
- Cmd_AddCommand ("unbindall",Key_Unbindall_f);
- Cmd_AddCommand ("bindlist",Key_Bindlist_f);
-}
-
-/*
-===================
-Key_Event
-
-Called by the system between frames for both key up and key down events
-Should NOT be called during an interrupt!
-===================
-*/
-void Key_Event (int key, qboolean down, unsigned time)
-{
- char *kb;
- char cmd[1024];
-
- // hack for modal presses
- if (key_waiting == -1)
- {
- if (down)
- key_waiting = key;
- return;
- }
-
- // update auto-repeat status
- if (down)
- {
- key_repeats[key]++;
- if (key != K_BACKSPACE
- && key != K_PAUSE
- && key != K_PGUP
- && key != K_KP_PGUP
- && key != K_PGDN
- && key != K_KP_PGDN
- && key_repeats[key] > 1)
- return; // ignore most autorepeats
-
- if (key >= 200 && !keybindings[key])
- Com_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
- }
- else
- {
- key_repeats[key] = 0;
- }
-
- if (key == K_SHIFT)
- shift_down = down;
-
- // console key is hardcoded, so the user can never unbind it
- if (key == '`' || key == '~')
- {
- if (!down)
- return;
- Con_ToggleConsole_f ();
- return;
- }
-
- // any key during the attract mode will bring up the menu
- if (cl.attractloop && cls.key_dest != key_menu)
- key = K_ESCAPE;
-
- // menu key is hardcoded, so the user can never unbind it
- if (key == K_ESCAPE)
- {
- if (!down)
- return;
-
- if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
- { // put away help computer / inventory
- Cbuf_AddText ("cmd putaway\n");
- return;
- }
- switch (cls.key_dest)
- {
- case key_message:
- Key_Message (key);
- break;
- case key_menu:
- M_Keydown (key);
- break;
- case key_game:
- case key_console:
- M_Menu_Main_f ();
- break;
- default:
- Com_Error (ERR_FATAL, "Bad cls.key_dest");
- }
- return;
- }
-
- // track if any key is down for BUTTON_ANY
- keydown[key] = down;
- if (down)
- {
- if (key_repeats[key] == 1)
- anykeydown++;
- }
- else
- {
- anykeydown--;
- if (anykeydown < 0)
- anykeydown = 0;
- }
-
-//
-// key up events only generate commands if the game key binding is
-// a button command (leading + sign). These will occur even in console mode,
-// to keep the character from continuing an action started before a console
-// switch. Button commands include the kenum as a parameter, so multiple
-// downs can be matched with ups
-//
- if (!down)
- {
- kb = keybindings[key];
- if (kb && kb[0] == '+')
- {
- Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
- Cbuf_AddText (cmd);
- }
- if (keyshift[key] != key)
- {
- kb = keybindings[keyshift[key]];
- if (kb && kb[0] == '+')
- {
- Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
- Cbuf_AddText (cmd);
- }
- }
- return;
- }
-
-//
-// if not a consolekey, send to the interpreter no matter what mode is
-//
- if ( (cls.key_dest == key_menu && menubound[key])
- || (cls.key_dest == key_console && !consolekeys[key])
- || (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
- {
- kb = keybindings[key];
- if (kb)
- {
- if (kb[0] == '+')
- { // button commands add keynum and time as a parm
- Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
- Cbuf_AddText (cmd);
- }
- else
- {
- Cbuf_AddText (kb);
- Cbuf_AddText ("\n");
- }
- }
- return;
- }
-
- if (!down)
- return; // other systems only care about key down events
-
- if (shift_down)
- key = keyshift[key];
-
- switch (cls.key_dest)
- {
- case key_message:
- Key_Message (key);
- break;
- case key_menu:
- M_Keydown (key);
- break;
-
- case key_game:
- case key_console:
- Key_Console (key);
- break;
- default:
- Com_Error (ERR_FATAL, "Bad cls.key_dest");
- }
-}
-
-/*
-===================
-Key_ClearStates
-===================
-*/
-void Key_ClearStates (void)
-{
- int i;
-
- anykeydown = false;
-
- for (i=0 ; i<256 ; i++)
- {
- if ( keydown[i] || key_repeats[i] )
- Key_Event( i, false, 0 );
- keydown[i] = 0;
- key_repeats[i] = 0;
- }
-}
-
-
-/*
-===================
-Key_GetKey
-===================
-*/
-int Key_GetKey (void)
-{
- key_waiting = -1;
-
- while (key_waiting == -1)
- Sys_SendKeyEvents ();
-
- return key_waiting;
-}
-
--- a/client/keys.h
+++ /dev/null
@@ -1,125 +1,0 @@
-//
-// these are the key numbers that should be passed to Key_Event
-//
-#define K_TAB 9
-#define K_ENTER 13
-#define K_ESCAPE 27
-#define K_SPACE 32
-
-// normal keys should be passed as lowercased ascii
-
-#define K_BACKSPACE 127
-#define K_UPARROW 128
-#define K_DOWNARROW 129
-#define K_LEFTARROW 130
-#define K_RIGHTARROW 131
-
-#define K_ALT 132
-#define K_CTRL 133
-#define K_SHIFT 134
-#define K_F1 135
-#define K_F2 136
-#define K_F3 137
-#define K_F4 138
-#define K_F5 139
-#define K_F6 140
-#define K_F7 141
-#define K_F8 142
-#define K_F9 143
-#define K_F10 144
-#define K_F11 145
-#define K_F12 146
-#define K_INS 147
-#define K_DEL 148
-#define K_PGDN 149
-#define K_PGUP 150
-#define K_HOME 151
-#define K_END 152
-
-#define K_KP_HOME 160
-#define K_KP_UPARROW 161
-#define K_KP_PGUP 162
-#define K_KP_LEFTARROW 163
-#define K_KP_5 164
-#define K_KP_RIGHTARROW 165
-#define K_KP_END 166
-#define K_KP_DOWNARROW 167
-#define K_KP_PGDN 168
-#define K_KP_ENTER 169
-#define K_KP_INS 170
-#define K_KP_DEL 171
-#define K_KP_SLASH 172
-#define K_KP_MINUS 173
-#define K_KP_PLUS 174
-
-//
-// mouse buttons generate virtual keys
-//
-#define K_MOUSE1 200
-#define K_MOUSE3 201
-#define K_MOUSE2 202
-#define K_MWHEELUP 203
-#define K_MWHEELDOWN 204
-
-//
-// joystick buttons
-//
-#define K_JOY1 205
-#define K_JOY2 206
-#define K_JOY3 207
-#define K_JOY4 208
-
-//
-// aux keys are for multi-buttoned joysticks to generate so they can use
-// the normal binding process
-//
-#define K_AUX1 209
-#define K_AUX2 210
-#define K_AUX3 211
-#define K_AUX4 212
-#define K_AUX5 213
-#define K_AUX6 214
-#define K_AUX7 215
-#define K_AUX8 216
-#define K_AUX9 217
-#define K_AUX10 218
-#define K_AUX11 219
-#define K_AUX12 220
-#define K_AUX13 221
-#define K_AUX14 222
-#define K_AUX15 223
-#define K_AUX16 224
-#define K_AUX17 225
-#define K_AUX18 226
-#define K_AUX19 227
-#define K_AUX20 228
-#define K_AUX21 229
-#define K_AUX22 230
-#define K_AUX23 231
-#define K_AUX24 232
-#define K_AUX25 233
-#define K_AUX26 234
-#define K_AUX27 235
-#define K_AUX28 236
-#define K_AUX29 237
-#define K_AUX30 238
-#define K_AUX31 239
-#define K_AUX32 240
-
-#define K_PAUSE 255
-
-extern char *keybindings[256];
-extern int key_repeats[256];
-
-extern int anykeydown;
-extern char chat_buffer[];
-extern int chat_bufferlen;
-extern qboolean chat_team;
-
-void Key_Event (int key, qboolean down, unsigned time);
-void Key_Init (void);
-void Key_WriteBindings (FILE *f);
-void Key_SetBinding (int keynum, char *binding);
-void Key_ClearStates (void);
-int Key_GetKey (void);
-
--- a/client/menu.c
+++ /dev/null
@@ -1,3997 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <ctype.h>
-#include "../q_shared.h"
-
-static int m_main_cursor;
-
-#define NUM_CURSOR_FRAMES 15
-
-static char *menu_in_sound = "misc/menu1.wav";
-static char *menu_move_sound = "misc/menu2.wav";
-static char *menu_out_sound = "misc/menu3.wav";
-
-void M_Menu_Main_f (void);
- void M_Menu_Game_f (void);
- void M_Menu_LoadGame_f (void);
- void M_Menu_SaveGame_f (void);
- void M_Menu_PlayerConfig_f (void);
- void M_Menu_DownloadOptions_f (void);
- void M_Menu_Credits_f( void );
- void M_Menu_Multiplayer_f( void );
- void M_Menu_JoinServer_f (void);
- void M_Menu_AddressBook_f( void );
- void M_Menu_StartServer_f (void);
- void M_Menu_DMOptions_f (void);
- void M_Menu_Video_f (void);
- void M_Menu_Options_f (void);
- void M_Menu_Keys_f (void);
- void M_Menu_Quit_f (void);
-
- void M_Menu_Credits( void );
-
-qboolean m_entersound; // play after drawing a frame, so caching
- // won't disrupt the sound
-
-void (*m_drawfunc) (void);
-const char *(*m_keyfunc) (int key);
-
-//=============================================================================
-/* Support Routines */
-
-#define MAX_MENU_DEPTH 8
-
-
-typedef struct
-{
- void (*draw) (void);
- const char *(*key) (int k);
-} menulayer_t;
-
-menulayer_t m_layers[MAX_MENU_DEPTH];
-int m_menudepth;
-
-static void M_Banner( char *name )
-{
- int w, h;
-
- re.DrawGetPicSize (&w, &h, name );
- re.DrawPic( vid.width / 2 - w / 2, vid.height / 2 - 110, name );
-}
-
-void M_PushMenu ( void (*draw) (void), const char *(*key) (int k) )
-{
- int i;
-
- if (Cvar_VariableValue ("maxclients") == 1
- && Com_ServerState ())
- Cvar_Set ("paused", "1");
-
- // if this menu is already present, drop back to that level
- // to avoid stacking menus by hotkeys
- for (i=0 ; i<m_menudepth ; i++)
- if (m_layers[i].draw == draw &&
- m_layers[i].key == key)
- {
- m_menudepth = i;
- }
-
- if (i == m_menudepth)
- {
- if (m_menudepth >= MAX_MENU_DEPTH)
- Com_Error (ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH");
- m_layers[m_menudepth].draw = m_drawfunc;
- m_layers[m_menudepth].key = m_keyfunc;
- m_menudepth++;
- }
-
- m_drawfunc = draw;
- m_keyfunc = key;
-
- m_entersound = true;
-
- cls.key_dest = key_menu;
-}
-
-void M_ForceMenuOff (void)
-{
- m_drawfunc = 0;
- m_keyfunc = 0;
- cls.key_dest = key_game;
- m_menudepth = 0;
- Key_ClearStates ();
- Cvar_Set ("paused", "0");
- IN_Grabm (1);
-}
-
-void M_PopMenu (void)
-{
- S_StartLocalSound( menu_out_sound );
- if (m_menudepth < 1)
- Com_Error (ERR_FATAL, "M_PopMenu: depth < 1");
- m_menudepth--;
-
- m_drawfunc = m_layers[m_menudepth].draw;
- m_keyfunc = m_layers[m_menudepth].key;
-
- if (!m_menudepth)
- M_ForceMenuOff ();
-}
-
-
-const char *Default_MenuKey( menuframework_s *m, int key )
-{
- const char *sound = NULL;
- menucommon_s *item;
-
- if ( m )
- {
- if ( ( item = Menu_ItemAtCursor( m ) ) != 0 )
- {
- if ( item->type == MTYPE_FIELD )
- {
- if ( Field_Key( ( menufield_s * ) item, key ) )
- return NULL;
- }
- }
- }
-
- switch ( key )
- {
- case K_ESCAPE:
- M_PopMenu();
- return menu_out_sound;
- case K_KP_UPARROW:
- case K_UPARROW:
- if ( m )
- {
- m->cursor--;
- Menu_AdjustCursor( m, -1 );
- sound = menu_move_sound;
- }
- break;
- case K_TAB:
- if ( m )
- {
- m->cursor++;
- Menu_AdjustCursor( m, 1 );
- sound = menu_move_sound;
- }
- break;
- case K_KP_DOWNARROW:
- case K_DOWNARROW:
- if ( m )
- {
- m->cursor++;
- Menu_AdjustCursor( m, 1 );
- sound = menu_move_sound;
- }
- break;
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- if ( m )
- {
- Menu_SlideItem( m, -1 );
- sound = menu_move_sound;
- }
- break;
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- if ( m )
- {
- Menu_SlideItem( m, 1 );
- sound = menu_move_sound;
- }
- break;
-
- case K_MOUSE1:
- case K_MOUSE2:
- case K_MOUSE3:
- case K_JOY1:
- case K_JOY2:
- case K_JOY3:
- case K_JOY4:
- case K_AUX1:
- case K_AUX2:
- case K_AUX3:
- case K_AUX4:
- case K_AUX5:
- case K_AUX6:
- case K_AUX7:
- case K_AUX8:
- case K_AUX9:
- case K_AUX10:
- case K_AUX11:
- case K_AUX12:
- case K_AUX13:
- case K_AUX14:
- case K_AUX15:
- case K_AUX16:
- case K_AUX17:
- case K_AUX18:
- case K_AUX19:
- case K_AUX20:
- case K_AUX21:
- case K_AUX22:
- case K_AUX23:
- case K_AUX24:
- case K_AUX25:
- case K_AUX26:
- case K_AUX27:
- case K_AUX28:
- case K_AUX29:
- case K_AUX30:
- case K_AUX31:
- case K_AUX32:
-
- case K_KP_ENTER:
- case K_ENTER:
- if ( m )
- Menu_SelectItem( m );
- sound = menu_move_sound;
- break;
- }
-
- return sound;
-}
-
-//=============================================================================
-
-/*
-================
-M_DrawCharacter
-
-Draws one solid graphics character
-cx and cy are in 320*240 coordinates, and will be centered on
-higher res screens.
-================
-*/
-void M_DrawCharacter (int cx, int cy, int num)
-{
- re.DrawChar ( cx + ((vid.width - 320)>>1), cy + ((vid.height - 240)>>1), num);
-}
-
-void M_Print (int cx, int cy, char *str)
-{
- while (*str)
- {
- M_DrawCharacter (cx, cy, (*str)+128);
- str++;
- cx += 8;
- }
-}
-
-void M_PrintWhite (int cx, int cy, char *str)
-{
- while (*str)
- {
- M_DrawCharacter (cx, cy, *str);
- str++;
- cx += 8;
- }
-}
-
-void M_DrawPic (int x, int y, char *pic)
-{
- re.DrawPic (x + ((vid.width - 320)>>1), y + ((vid.height - 240)>>1), pic);
-}
-
-
-/*
-=============
-M_DrawCursor
-
-Draws an animating cursor with the point at
-x,y. The pic will extend to the left of x,
-and both above and below y.
-=============
-*/
-void M_DrawCursor( int x, int y, int f )
-{
- char cursorname[80];
- static qboolean cached;
-
- if ( !cached )
- {
- int i;
-
- for ( i = 0; i < NUM_CURSOR_FRAMES; i++ )
- {
- Com_sprintf( cursorname, sizeof( cursorname ), "m_cursor%d", i );
-
- re.RegisterPic( cursorname );
- }
- cached = true;
- }
-
- Com_sprintf( cursorname, sizeof(cursorname), "m_cursor%d", f );
- re.DrawPic( x, y, cursorname );
-}
-
-void M_DrawTextBox (int x, int y, int width, int lines)
-{
- int cx, cy;
- int n;
-
- // draw left side
- cx = x;
- cy = y;
- M_DrawCharacter (cx, cy, 1);
- for (n = 0; n < lines; n++)
- {
- cy += 8;
- M_DrawCharacter (cx, cy, 4);
- }
- M_DrawCharacter (cx, cy+8, 7);
-
- // draw middle
- cx += 8;
- while (width > 0)
- {
- cy = y;
- M_DrawCharacter (cx, cy, 2);
- for (n = 0; n < lines; n++)
- {
- cy += 8;
- M_DrawCharacter (cx, cy, 5);
- }
- M_DrawCharacter (cx, cy+8, 8);
- width -= 1;
- cx += 8;
- }
-
- // draw right side
- cy = y;
- M_DrawCharacter (cx, cy, 3);
- for (n = 0; n < lines; n++)
- {
- cy += 8;
- M_DrawCharacter (cx, cy, 6);
- }
- M_DrawCharacter (cx, cy+8, 9);
-}
-
-
-/*
-=======================================================================
-
-MAIN MENU
-
-=======================================================================
-*/
-#define MAIN_ITEMS 5
-
-
-void M_Main_Draw (void)
-{
- int i;
- int w, h;
- int ystart;
- int xoffset;
- int widest = -1;
- int totalheight = 0;
- char litname[80];
- char *names[] =
- {
- "m_main_game",
- "m_main_multiplayer",
- "m_main_options",
- "m_main_video",
- "m_main_quit",
- 0
- };
-
- for ( i = 0; names[i] != 0; i++ )
- {
- re.DrawGetPicSize( &w, &h, names[i] );
-
- if ( w > widest )
- widest = w;
- totalheight += ( h + 12 );
- }
-
- ystart = ( vid.height / 2 - 110 );
- xoffset = ( vid.width - widest + 70 ) / 2;
-
- for ( i = 0; names[i] != 0; i++ )
- {
- if ( i != m_main_cursor )
- re.DrawPic( xoffset, ystart + i * 40 + 13, names[i] );
- }
- strcpy( litname, names[m_main_cursor] );
- strcat( litname, "_sel" );
- re.DrawPic( xoffset, ystart + m_main_cursor * 40 + 13, litname );
-
- M_DrawCursor( xoffset - 25, ystart + m_main_cursor * 40 + 11, (int)(cls.realtime / 100)%NUM_CURSOR_FRAMES );
-
- re.DrawGetPicSize( &w, &h, "m_main_plaque" );
- re.DrawPic( xoffset - 30 - w, ystart, "m_main_plaque" );
-
- re.DrawPic( xoffset - 30 - w, ystart + h + 5, "m_main_logo" );
-}
-
-
-const char *M_Main_Key (int key)
-{
- const char *sound = menu_move_sound;
-
- switch (key)
- {
- case K_ESCAPE:
- M_PopMenu ();
- break;
-
- case K_KP_DOWNARROW:
- case K_DOWNARROW:
- if (++m_main_cursor >= MAIN_ITEMS)
- m_main_cursor = 0;
- return sound;
-
- case K_KP_UPARROW:
- case K_UPARROW:
- if (--m_main_cursor < 0)
- m_main_cursor = MAIN_ITEMS - 1;
- return sound;
-
- case K_KP_ENTER:
- case K_ENTER:
- m_entersound = true;
-
- switch (m_main_cursor)
- {
- case 0:
- M_Menu_Game_f ();
- break;
-
- case 1:
- M_Menu_Multiplayer_f();
- break;
-
- case 2:
- M_Menu_Options_f ();
- break;
-
- case 3:
- M_Menu_Video_f ();
- break;
-
- case 4:
- M_Menu_Quit_f ();
- break;
- }
- }
-
- return NULL;
-}
-
-
-void M_Menu_Main_f (void)
-{
- IN_Grabm (0);
- M_PushMenu (M_Main_Draw, M_Main_Key);
-}
-
-/*
-=======================================================================
-
-MULTIPLAYER MENU
-
-=======================================================================
-*/
-static menuframework_s s_multiplayer_menu;
-static menuaction_s s_join_network_server_action;
-static menuaction_s s_start_network_server_action;
-static menuaction_s s_player_setup_action;
-
-static void Multiplayer_MenuDraw (void)
-{
- M_Banner( "m_banner_multiplayer" );
-
- Menu_AdjustCursor( &s_multiplayer_menu, 1 );
- Menu_Draw( &s_multiplayer_menu );
-}
-
-static void PlayerSetupFunc( void * )
-{
- M_Menu_PlayerConfig_f();
-}
-
-static void JoinNetworkServerFunc( void * )
-{
- M_Menu_JoinServer_f();
-}
-
-static void StartNetworkServerFunc( void * )
-{
- M_Menu_StartServer_f ();
-}
-
-void Multiplayer_MenuInit( void )
-{
- s_multiplayer_menu.x = vid.width * 0.50 - 64;
- s_multiplayer_menu.nitems = 0;
-
- s_join_network_server_action.generic.type = MTYPE_ACTION;
- s_join_network_server_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_join_network_server_action.generic.x = 0;
- s_join_network_server_action.generic.y = 0;
- s_join_network_server_action.generic.name = " join network server";
- s_join_network_server_action.generic.callback = JoinNetworkServerFunc;
-
- s_start_network_server_action.generic.type = MTYPE_ACTION;
- s_start_network_server_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_start_network_server_action.generic.x = 0;
- s_start_network_server_action.generic.y = 10;
- s_start_network_server_action.generic.name = " start network server";
- s_start_network_server_action.generic.callback = StartNetworkServerFunc;
-
- s_player_setup_action.generic.type = MTYPE_ACTION;
- s_player_setup_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_player_setup_action.generic.x = 0;
- s_player_setup_action.generic.y = 20;
- s_player_setup_action.generic.name = " player setup";
- s_player_setup_action.generic.callback = PlayerSetupFunc;
-
- Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_join_network_server_action );
- Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_start_network_server_action );
- Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_player_setup_action );
-
- Menu_SetStatusBar( &s_multiplayer_menu, NULL );
-
- Menu_Center( &s_multiplayer_menu );
-}
-
-const char *Multiplayer_MenuKey( int key )
-{
- return Default_MenuKey( &s_multiplayer_menu, key );
-}
-
-void M_Menu_Multiplayer_f( void )
-{
- Multiplayer_MenuInit();
- M_PushMenu( Multiplayer_MenuDraw, Multiplayer_MenuKey );
-}
-
-/*
-=======================================================================
-
-KEYS MENU
-
-=======================================================================
-*/
-char *bindnames[][2] =
-{
-{"+attack", "attack"},
-{"weapnext", "next weapon"},
-{"+forward", "walk forward"},
-{"+back", "backpedal"},
-{"+left", "turn left"},
-{"+right", "turn right"},
-{"+speed", "run"},
-{"+moveleft", "step left"},
-{"+moveright", "step right"},
-{"+strafe", "sidestep"},
-{"+lookup", "look up"},
-{"+lookdown", "look down"},
-{"centerview", "center view"},
-{"+mlook", "mouse look"},
-{"+klook", "keyboard look"},
-{"+moveup", "up / jump"},
-{"+movedown", "down / crouch"},
-
-{"inven", "inventory"},
-{"invuse", "use item"},
-{"invdrop", "drop item"},
-{"invprev", "prev item"},
-{"invnext", "next item"},
-
-{"cmd help", "help computer" },
-{ 0, 0 }
-};
-
-int keys_cursor;
-static int bind_grab;
-
-static menuframework_s s_keys_menu;
-static menuaction_s s_keys_attack_action;
-static menuaction_s s_keys_change_weapon_action;
-static menuaction_s s_keys_walk_forward_action;
-static menuaction_s s_keys_backpedal_action;
-static menuaction_s s_keys_turn_left_action;
-static menuaction_s s_keys_turn_right_action;
-static menuaction_s s_keys_run_action;
-static menuaction_s s_keys_step_left_action;
-static menuaction_s s_keys_step_right_action;
-static menuaction_s s_keys_sidestep_action;
-static menuaction_s s_keys_look_up_action;
-static menuaction_s s_keys_look_down_action;
-static menuaction_s s_keys_center_view_action;
-static menuaction_s s_keys_mouse_look_action;
-static menuaction_s s_keys_keyboard_look_action;
-static menuaction_s s_keys_move_up_action;
-static menuaction_s s_keys_move_down_action;
-static menuaction_s s_keys_inventory_action;
-static menuaction_s s_keys_inv_use_action;
-static menuaction_s s_keys_inv_drop_action;
-static menuaction_s s_keys_inv_prev_action;
-static menuaction_s s_keys_inv_next_action;
-
-static menuaction_s s_keys_help_computer_action;
-
-static void M_UnbindCommand (char *command)
-{
- int j;
- int l;
- char *b;
-
- l = strlen(command);
-
- for (j=0 ; j<256 ; j++)
- {
- b = keybindings[j];
- if (!b)
- continue;
- if (!strncmp (b, command, l) )
- Key_SetBinding (j, "");
- }
-}
-
-static void M_FindKeysForCommand (char *command, int *twokeys)
-{
- int count;
- int j;
- int l;
- char *b;
-
- twokeys[0] = twokeys[1] = -1;
- l = strlen(command);
- count = 0;
-
- for (j=0 ; j<256 ; j++)
- {
- b = keybindings[j];
- if (!b)
- continue;
- if (!strncmp (b, command, l) )
- {
- twokeys[count] = j;
- count++;
- if (count == 2)
- break;
- }
- }
-}
-
-static void KeyCursorDrawFunc( menuframework_s *menu )
-{
- if ( bind_grab )
- re.DrawChar( menu->x, menu->y + menu->cursor * 9, '=' );
- else
- re.DrawChar( menu->x, menu->y + menu->cursor * 9, 12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ) );
-}
-
-static void DrawKeyBindingFunc( void *self )
-{
- int keys[2];
- menuaction_s *a = ( menuaction_s * ) self;
-
- M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys);
-
- if (keys[0] == -1)
- {
- Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, "???" );
- }
- else
- {
- int x;
- const char *name;
-
- name = Key_KeynumToString (keys[0]);
-
- Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, name );
-
- x = strlen(name) * 8;
-
- if (keys[1] != -1)
- {
- Menu_DrawString( a->generic.x + a->generic.parent->x + 24 + x, a->generic.y + a->generic.parent->y, "or" );
- Menu_DrawString( a->generic.x + a->generic.parent->x + 48 + x, a->generic.y + a->generic.parent->y, Key_KeynumToString (keys[1]) );
- }
- }
-}
-
-static void KeyBindingFunc( void *self )
-{
- menuaction_s *a = ( menuaction_s * ) self;
- int keys[2];
-
- M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys );
-
- if (keys[1] != -1)
- M_UnbindCommand( bindnames[a->generic.localdata[0]][0]);
-
- bind_grab = true;
-
- Menu_SetStatusBar( &s_keys_menu, "press a key or button for this action" );
-}
-
-static void Keys_MenuInit( void )
-{
- int y = 0;
- int i = 0;
-
- s_keys_menu.x = vid.width * 0.50;
- s_keys_menu.nitems = 0;
- s_keys_menu.cursordraw = KeyCursorDrawFunc;
-
- s_keys_attack_action.generic.type = MTYPE_ACTION;
- s_keys_attack_action.generic.flags = QMF_GRAYED;
- s_keys_attack_action.generic.x = 0;
- s_keys_attack_action.generic.y = y;
- s_keys_attack_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_attack_action.generic.localdata[0] = i;
- s_keys_attack_action.generic.name = bindnames[s_keys_attack_action.generic.localdata[0]][1];
-
- s_keys_change_weapon_action.generic.type = MTYPE_ACTION;
- s_keys_change_weapon_action.generic.flags = QMF_GRAYED;
- s_keys_change_weapon_action.generic.x = 0;
- s_keys_change_weapon_action.generic.y = y += 9;
- s_keys_change_weapon_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_change_weapon_action.generic.localdata[0] = ++i;
- s_keys_change_weapon_action.generic.name = bindnames[s_keys_change_weapon_action.generic.localdata[0]][1];
-
- s_keys_walk_forward_action.generic.type = MTYPE_ACTION;
- s_keys_walk_forward_action.generic.flags = QMF_GRAYED;
- s_keys_walk_forward_action.generic.x = 0;
- s_keys_walk_forward_action.generic.y = y += 9;
- s_keys_walk_forward_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_walk_forward_action.generic.localdata[0] = ++i;
- s_keys_walk_forward_action.generic.name = bindnames[s_keys_walk_forward_action.generic.localdata[0]][1];
-
- s_keys_backpedal_action.generic.type = MTYPE_ACTION;
- s_keys_backpedal_action.generic.flags = QMF_GRAYED;
- s_keys_backpedal_action.generic.x = 0;
- s_keys_backpedal_action.generic.y = y += 9;
- s_keys_backpedal_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_backpedal_action.generic.localdata[0] = ++i;
- s_keys_backpedal_action.generic.name = bindnames[s_keys_backpedal_action.generic.localdata[0]][1];
-
- s_keys_turn_left_action.generic.type = MTYPE_ACTION;
- s_keys_turn_left_action.generic.flags = QMF_GRAYED;
- s_keys_turn_left_action.generic.x = 0;
- s_keys_turn_left_action.generic.y = y += 9;
- s_keys_turn_left_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_turn_left_action.generic.localdata[0] = ++i;
- s_keys_turn_left_action.generic.name = bindnames[s_keys_turn_left_action.generic.localdata[0]][1];
-
- s_keys_turn_right_action.generic.type = MTYPE_ACTION;
- s_keys_turn_right_action.generic.flags = QMF_GRAYED;
- s_keys_turn_right_action.generic.x = 0;
- s_keys_turn_right_action.generic.y = y += 9;
- s_keys_turn_right_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_turn_right_action.generic.localdata[0] = ++i;
- s_keys_turn_right_action.generic.name = bindnames[s_keys_turn_right_action.generic.localdata[0]][1];
-
- s_keys_run_action.generic.type = MTYPE_ACTION;
- s_keys_run_action.generic.flags = QMF_GRAYED;
- s_keys_run_action.generic.x = 0;
- s_keys_run_action.generic.y = y += 9;
- s_keys_run_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_run_action.generic.localdata[0] = ++i;
- s_keys_run_action.generic.name = bindnames[s_keys_run_action.generic.localdata[0]][1];
-
- s_keys_step_left_action.generic.type = MTYPE_ACTION;
- s_keys_step_left_action.generic.flags = QMF_GRAYED;
- s_keys_step_left_action.generic.x = 0;
- s_keys_step_left_action.generic.y = y += 9;
- s_keys_step_left_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_step_left_action.generic.localdata[0] = ++i;
- s_keys_step_left_action.generic.name = bindnames[s_keys_step_left_action.generic.localdata[0]][1];
-
- s_keys_step_right_action.generic.type = MTYPE_ACTION;
- s_keys_step_right_action.generic.flags = QMF_GRAYED;
- s_keys_step_right_action.generic.x = 0;
- s_keys_step_right_action.generic.y = y += 9;
- s_keys_step_right_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_step_right_action.generic.localdata[0] = ++i;
- s_keys_step_right_action.generic.name = bindnames[s_keys_step_right_action.generic.localdata[0]][1];
-
- s_keys_sidestep_action.generic.type = MTYPE_ACTION;
- s_keys_sidestep_action.generic.flags = QMF_GRAYED;
- s_keys_sidestep_action.generic.x = 0;
- s_keys_sidestep_action.generic.y = y += 9;
- s_keys_sidestep_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_sidestep_action.generic.localdata[0] = ++i;
- s_keys_sidestep_action.generic.name = bindnames[s_keys_sidestep_action.generic.localdata[0]][1];
-
- s_keys_look_up_action.generic.type = MTYPE_ACTION;
- s_keys_look_up_action.generic.flags = QMF_GRAYED;
- s_keys_look_up_action.generic.x = 0;
- s_keys_look_up_action.generic.y = y += 9;
- s_keys_look_up_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_look_up_action.generic.localdata[0] = ++i;
- s_keys_look_up_action.generic.name = bindnames[s_keys_look_up_action.generic.localdata[0]][1];
-
- s_keys_look_down_action.generic.type = MTYPE_ACTION;
- s_keys_look_down_action.generic.flags = QMF_GRAYED;
- s_keys_look_down_action.generic.x = 0;
- s_keys_look_down_action.generic.y = y += 9;
- s_keys_look_down_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_look_down_action.generic.localdata[0] = ++i;
- s_keys_look_down_action.generic.name = bindnames[s_keys_look_down_action.generic.localdata[0]][1];
-
- s_keys_center_view_action.generic.type = MTYPE_ACTION;
- s_keys_center_view_action.generic.flags = QMF_GRAYED;
- s_keys_center_view_action.generic.x = 0;
- s_keys_center_view_action.generic.y = y += 9;
- s_keys_center_view_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_center_view_action.generic.localdata[0] = ++i;
- s_keys_center_view_action.generic.name = bindnames[s_keys_center_view_action.generic.localdata[0]][1];
-
- s_keys_mouse_look_action.generic.type = MTYPE_ACTION;
- s_keys_mouse_look_action.generic.flags = QMF_GRAYED;
- s_keys_mouse_look_action.generic.x = 0;
- s_keys_mouse_look_action.generic.y = y += 9;
- s_keys_mouse_look_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_mouse_look_action.generic.localdata[0] = ++i;
- s_keys_mouse_look_action.generic.name = bindnames[s_keys_mouse_look_action.generic.localdata[0]][1];
-
- s_keys_keyboard_look_action.generic.type = MTYPE_ACTION;
- s_keys_keyboard_look_action.generic.flags = QMF_GRAYED;
- s_keys_keyboard_look_action.generic.x = 0;
- s_keys_keyboard_look_action.generic.y = y += 9;
- s_keys_keyboard_look_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_keyboard_look_action.generic.localdata[0] = ++i;
- s_keys_keyboard_look_action.generic.name = bindnames[s_keys_keyboard_look_action.generic.localdata[0]][1];
-
- s_keys_move_up_action.generic.type = MTYPE_ACTION;
- s_keys_move_up_action.generic.flags = QMF_GRAYED;
- s_keys_move_up_action.generic.x = 0;
- s_keys_move_up_action.generic.y = y += 9;
- s_keys_move_up_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_move_up_action.generic.localdata[0] = ++i;
- s_keys_move_up_action.generic.name = bindnames[s_keys_move_up_action.generic.localdata[0]][1];
-
- s_keys_move_down_action.generic.type = MTYPE_ACTION;
- s_keys_move_down_action.generic.flags = QMF_GRAYED;
- s_keys_move_down_action.generic.x = 0;
- s_keys_move_down_action.generic.y = y += 9;
- s_keys_move_down_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_move_down_action.generic.localdata[0] = ++i;
- s_keys_move_down_action.generic.name = bindnames[s_keys_move_down_action.generic.localdata[0]][1];
-
- s_keys_inventory_action.generic.type = MTYPE_ACTION;
- s_keys_inventory_action.generic.flags = QMF_GRAYED;
- s_keys_inventory_action.generic.x = 0;
- s_keys_inventory_action.generic.y = y += 9;
- s_keys_inventory_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_inventory_action.generic.localdata[0] = ++i;
- s_keys_inventory_action.generic.name = bindnames[s_keys_inventory_action.generic.localdata[0]][1];
-
- s_keys_inv_use_action.generic.type = MTYPE_ACTION;
- s_keys_inv_use_action.generic.flags = QMF_GRAYED;
- s_keys_inv_use_action.generic.x = 0;
- s_keys_inv_use_action.generic.y = y += 9;
- s_keys_inv_use_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_inv_use_action.generic.localdata[0] = ++i;
- s_keys_inv_use_action.generic.name = bindnames[s_keys_inv_use_action.generic.localdata[0]][1];
-
- s_keys_inv_drop_action.generic.type = MTYPE_ACTION;
- s_keys_inv_drop_action.generic.flags = QMF_GRAYED;
- s_keys_inv_drop_action.generic.x = 0;
- s_keys_inv_drop_action.generic.y = y += 9;
- s_keys_inv_drop_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_inv_drop_action.generic.localdata[0] = ++i;
- s_keys_inv_drop_action.generic.name = bindnames[s_keys_inv_drop_action.generic.localdata[0]][1];
-
- s_keys_inv_prev_action.generic.type = MTYPE_ACTION;
- s_keys_inv_prev_action.generic.flags = QMF_GRAYED;
- s_keys_inv_prev_action.generic.x = 0;
- s_keys_inv_prev_action.generic.y = y += 9;
- s_keys_inv_prev_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_inv_prev_action.generic.localdata[0] = ++i;
- s_keys_inv_prev_action.generic.name = bindnames[s_keys_inv_prev_action.generic.localdata[0]][1];
-
- s_keys_inv_next_action.generic.type = MTYPE_ACTION;
- s_keys_inv_next_action.generic.flags = QMF_GRAYED;
- s_keys_inv_next_action.generic.x = 0;
- s_keys_inv_next_action.generic.y = y += 9;
- s_keys_inv_next_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_inv_next_action.generic.localdata[0] = ++i;
- s_keys_inv_next_action.generic.name = bindnames[s_keys_inv_next_action.generic.localdata[0]][1];
-
- s_keys_help_computer_action.generic.type = MTYPE_ACTION;
- s_keys_help_computer_action.generic.flags = QMF_GRAYED;
- s_keys_help_computer_action.generic.x = 0;
- s_keys_help_computer_action.generic.y = y += 9;
- s_keys_help_computer_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_help_computer_action.generic.localdata[0] = ++i;
- s_keys_help_computer_action.generic.name = bindnames[s_keys_help_computer_action.generic.localdata[0]][1];
-
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_attack_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_change_weapon_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_walk_forward_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_backpedal_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_left_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_right_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_run_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_left_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_right_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_sidestep_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_up_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_down_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_center_view_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_mouse_look_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_keyboard_look_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_up_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_down_action );
-
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inventory_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_use_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_drop_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_prev_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_next_action );
-
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_help_computer_action );
-
- Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
- Menu_Center( &s_keys_menu );
-}
-
-static void Keys_MenuDraw (void)
-{
- Menu_AdjustCursor( &s_keys_menu, 1 );
- Menu_Draw( &s_keys_menu );
-}
-
-static const char *Keys_MenuKey( int key )
-{
- menuaction_s *item = ( menuaction_s * ) Menu_ItemAtCursor( &s_keys_menu );
-
- if ( bind_grab )
- {
- if ( key != K_ESCAPE && key != '`' )
- {
- char cmd[1024];
-
- Com_sprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item->generic.localdata[0]][0]);
- Cbuf_InsertText (cmd);
- }
-
- Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
- bind_grab = false;
- return menu_out_sound;
- }
-
- switch ( key )
- {
- case K_KP_ENTER:
- case K_ENTER:
- KeyBindingFunc( item );
- return menu_in_sound;
- case K_BACKSPACE: // delete bindings
- case K_DEL: // delete bindings
- case K_KP_DEL:
- M_UnbindCommand( bindnames[item->generic.localdata[0]][0] );
- return menu_out_sound;
- default:
- return Default_MenuKey( &s_keys_menu, key );
- }
-}
-
-void M_Menu_Keys_f (void)
-{
- Keys_MenuInit();
- M_PushMenu( Keys_MenuDraw, Keys_MenuKey );
-}
-
-
-/*
-=======================================================================
-
-CONTROLS MENU
-
-=======================================================================
-*/
-static cvar_t *win_noalttab;
-
-static menuframework_s s_options_menu;
-static menuaction_s s_options_defaults_action;
-static menuaction_s s_options_customize_options_action;
-static menuslider_s s_options_sensitivity_slider;
-static menulist_s s_options_freelook_box;
-static menulist_s s_options_noalttab_box;
-static menulist_s s_options_alwaysrun_box;
-static menulist_s s_options_invertmouse_box;
-static menulist_s s_options_lookspring_box;
-static menulist_s s_options_lookstrafe_box;
-static menulist_s s_options_crosshair_box;
-static menuslider_s s_options_sfxvolume_slider;
-static menulist_s s_options_joystick_box;
-static menulist_s s_options_cdvolume_box;
-static menulist_s s_options_quality_list;
-static menulist_s s_options_compatibility_list;
-static menulist_s s_options_console_action;
-
-static void CrosshairFunc( void * )
-{
- Cvar_SetValue( "crosshair", s_options_crosshair_box.curvalue );
-}
-
-static void JoystickFunc( void * )
-{
- Cvar_SetValue( "in_joystick", s_options_joystick_box.curvalue );
-}
-
-static void CustomizeControlsFunc( void * )
-{
- M_Menu_Keys_f();
-}
-
-static void AlwaysRunFunc( void * )
-{
- Cvar_SetValue( "cl_run", s_options_alwaysrun_box.curvalue );
-}
-
-static void FreeLookFunc( void * )
-{
- Cvar_SetValue( "freelook", s_options_freelook_box.curvalue );
-}
-
-static void MouseSpeedFunc( void * )
-{
- Cvar_SetValue( "sensitivity", s_options_sensitivity_slider.curvalue / 2.0F );
-}
-
-static void NoAltTabFunc( void * )
-{
- Cvar_SetValue( "win_noalttab", s_options_noalttab_box.curvalue );
-}
-
-static float ClampCvar( float min, float max, float value )
-{
- if ( value < min ) return min;
- if ( value > max ) return max;
- return value;
-}
-
-static void ControlsSetMenuItemValues( void )
-{
- s_options_sfxvolume_slider.curvalue = Cvar_VariableValue( "s_volume" ) * 10;
- s_options_cdvolume_box.curvalue = !Cvar_VariableValue("cd_nocd");
- s_options_quality_list.curvalue = !Cvar_VariableValue( "s_loadas8bit" );
- s_options_sensitivity_slider.curvalue = ( sensitivity->value ) * 2;
-
- Cvar_SetValue( "cl_run", ClampCvar( 0, 1, cl_run->value ) );
- s_options_alwaysrun_box.curvalue = cl_run->value;
-
- s_options_invertmouse_box.curvalue = m_pitch->value < 0;
-
- Cvar_SetValue( "lookspring", ClampCvar( 0, 1, lookspring->value ) );
- s_options_lookspring_box.curvalue = lookspring->value;
-
- Cvar_SetValue( "lookstrafe", ClampCvar( 0, 1, lookstrafe->value ) );
- s_options_lookstrafe_box.curvalue = lookstrafe->value;
-
- Cvar_SetValue( "freelook", ClampCvar( 0, 1, freelook->value ) );
- s_options_freelook_box.curvalue = freelook->value;
-
- Cvar_SetValue( "crosshair", ClampCvar( 0, 3, crosshair->value ) );
- s_options_crosshair_box.curvalue = crosshair->value;
-
- Cvar_SetValue( "in_joystick", ClampCvar( 0, 1, in_joystick->value ) );
- s_options_joystick_box.curvalue = in_joystick->value;
-
- s_options_noalttab_box.curvalue = win_noalttab->value;
-}
-
-static void ControlsResetDefaultsFunc( void * )
-{
- Cbuf_AddText ("exec default.cfg\n");
- Cbuf_Execute();
-
- ControlsSetMenuItemValues();
-}
-
-static void InvertMouseFunc( void * )
-{
- if ( s_options_invertmouse_box.curvalue == 0 )
- {
- Cvar_SetValue( "m_pitch", fabs( m_pitch->value ) );
- }
- else
- {
- Cvar_SetValue( "m_pitch", -fabs( m_pitch->value ) );
- }
-}
-
-static void LookspringFunc( void * )
-{
- Cvar_SetValue( "lookspring", s_options_lookspring_box.curvalue );
-}
-
-static void LookstrafeFunc( void * )
-{
- Cvar_SetValue( "lookstrafe", s_options_lookstrafe_box.curvalue );
-}
-
-static void UpdateVolumeFunc( void * )
-{
- Cvar_SetValue( "s_volume", s_options_sfxvolume_slider.curvalue / 10 );
-}
-
-static void UpdateCDVolumeFunc( void * )
-{
- Cvar_SetValue( "cd_nocd", !s_options_cdvolume_box.curvalue );
-}
-
-static void ConsoleFunc( void * )
-{
- /*
- ** the proper way to do this is probably to have ToggleConsole_f accept a parameter
- */
- extern void Key_ClearTyping( void );
-
- if ( cl.attractloop )
- {
- Cbuf_AddText ("killserver\n");
- return;
- }
-
- Key_ClearTyping ();
- Con_ClearNotify ();
-
- M_ForceMenuOff ();
- cls.key_dest = key_console;
-}
-
-static void UpdateSoundQualityFunc( void * )
-{
- if ( s_options_quality_list.curvalue )
- {
- Cvar_SetValue( "s_khz", 22 );
- Cvar_SetValue( "s_loadas8bit", false );
- }
- else
- {
- Cvar_SetValue( "s_khz", 11 );
- Cvar_SetValue( "s_loadas8bit", true );
- }
-
- Cvar_SetValue( "s_primary", s_options_compatibility_list.curvalue );
-
- M_DrawTextBox( 8, 120 - 48, 36, 3 );
- M_Print( 16 + 16, 120 - 48 + 8, "Restarting the sound system. This" );
- M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
- M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
-
- // the text box won't show up unless we do a buffer swap
- re.EndFrame();
-
- CL_Snd_Restart_f();
-}
-
-void Options_MenuInit( void )
-{
- static const char *cd_music_items[] =
- {
- "disabled",
- "enabled",
- 0
- };
- static const char *quality_items[] =
- {
- "low", "high", 0
- };
-
- static const char *compatibility_items[] =
- {
- "max compatibility", "max performance", 0
- };
-
- static const char *yesno_names[] =
- {
- "no",
- "yes",
- 0
- };
-
- static const char *crosshair_names[] =
- {
- "none",
- "cross",
- "dot",
- "angle",
- 0
- };
-
- win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
-
- /*
- ** configure controls menu and menu items
- */
- s_options_menu.x = vid.width / 2;
- s_options_menu.y = vid.height / 2 - 58;
- s_options_menu.nitems = 0;
-
- s_options_sfxvolume_slider.generic.type = MTYPE_SLIDER;
- s_options_sfxvolume_slider.generic.x = 0;
- s_options_sfxvolume_slider.generic.y = 0;
- s_options_sfxvolume_slider.generic.name = "effects volume";
- s_options_sfxvolume_slider.generic.callback = UpdateVolumeFunc;
- s_options_sfxvolume_slider.minvalue = 0;
- s_options_sfxvolume_slider.maxvalue = 10;
- s_options_sfxvolume_slider.curvalue = Cvar_VariableValue( "s_volume" ) * 10;
-
- s_options_cdvolume_box.generic.type = MTYPE_SPINCONTROL;
- s_options_cdvolume_box.generic.x = 0;
- s_options_cdvolume_box.generic.y = 10;
- s_options_cdvolume_box.generic.name = "CD music";
- s_options_cdvolume_box.generic.callback = UpdateCDVolumeFunc;
- s_options_cdvolume_box.itemnames = cd_music_items;
- s_options_cdvolume_box.curvalue = !Cvar_VariableValue("cd_nocd");
-
- s_options_quality_list.generic.type = MTYPE_SPINCONTROL;
- s_options_quality_list.generic.x = 0;
- s_options_quality_list.generic.y = 20;;
- s_options_quality_list.generic.name = "sound quality";
- s_options_quality_list.generic.callback = UpdateSoundQualityFunc;
- s_options_quality_list.itemnames = quality_items;
- s_options_quality_list.curvalue = !Cvar_VariableValue( "s_loadas8bit" );
-
- s_options_compatibility_list.generic.type = MTYPE_SPINCONTROL;
- s_options_compatibility_list.generic.x = 0;
- s_options_compatibility_list.generic.y = 30;
- s_options_compatibility_list.generic.name = "sound compatibility";
- s_options_compatibility_list.generic.callback = UpdateSoundQualityFunc;
- s_options_compatibility_list.itemnames = compatibility_items;
- s_options_compatibility_list.curvalue = Cvar_VariableValue( "s_primary" );
-
- s_options_sensitivity_slider.generic.type = MTYPE_SLIDER;
- s_options_sensitivity_slider.generic.x = 0;
- s_options_sensitivity_slider.generic.y = 50;
- s_options_sensitivity_slider.generic.name = "mouse speed";
- s_options_sensitivity_slider.generic.callback = MouseSpeedFunc;
- s_options_sensitivity_slider.minvalue = 2;
- s_options_sensitivity_slider.maxvalue = 22;
-
- s_options_alwaysrun_box.generic.type = MTYPE_SPINCONTROL;
- s_options_alwaysrun_box.generic.x = 0;
- s_options_alwaysrun_box.generic.y = 60;
- s_options_alwaysrun_box.generic.name = "always run";
- s_options_alwaysrun_box.generic.callback = AlwaysRunFunc;
- s_options_alwaysrun_box.itemnames = yesno_names;
-
- s_options_invertmouse_box.generic.type = MTYPE_SPINCONTROL;
- s_options_invertmouse_box.generic.x = 0;
- s_options_invertmouse_box.generic.y = 70;
- s_options_invertmouse_box.generic.name = "invert mouse";
- s_options_invertmouse_box.generic.callback = InvertMouseFunc;
- s_options_invertmouse_box.itemnames = yesno_names;
-
- s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL;
- s_options_lookspring_box.generic.x = 0;
- s_options_lookspring_box.generic.y = 80;
- s_options_lookspring_box.generic.name = "lookspring";
- s_options_lookspring_box.generic.callback = LookspringFunc;
- s_options_lookspring_box.itemnames = yesno_names;
-
- s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL;
- s_options_lookstrafe_box.generic.x = 0;
- s_options_lookstrafe_box.generic.y = 90;
- s_options_lookstrafe_box.generic.name = "lookstrafe";
- s_options_lookstrafe_box.generic.callback = LookstrafeFunc;
- s_options_lookstrafe_box.itemnames = yesno_names;
-
- s_options_freelook_box.generic.type = MTYPE_SPINCONTROL;
- s_options_freelook_box.generic.x = 0;
- s_options_freelook_box.generic.y = 100;
- s_options_freelook_box.generic.name = "free look";
- s_options_freelook_box.generic.callback = FreeLookFunc;
- s_options_freelook_box.itemnames = yesno_names;
-
- s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL;
- s_options_crosshair_box.generic.x = 0;
- s_options_crosshair_box.generic.y = 110;
- s_options_crosshair_box.generic.name = "crosshair";
- s_options_crosshair_box.generic.callback = CrosshairFunc;
- s_options_crosshair_box.itemnames = crosshair_names;
-/*
- s_options_noalttab_box.generic.type = MTYPE_SPINCONTROL;
- s_options_noalttab_box.generic.x = 0;
- s_options_noalttab_box.generic.y = 110;
- s_options_noalttab_box.generic.name = "disable alt-tab";
- s_options_noalttab_box.generic.callback = NoAltTabFunc;
- s_options_noalttab_box.itemnames = yesno_names;
-*/
- s_options_joystick_box.generic.type = MTYPE_SPINCONTROL;
- s_options_joystick_box.generic.x = 0;
- s_options_joystick_box.generic.y = 120;
- s_options_joystick_box.generic.name = "use joystick";
- s_options_joystick_box.generic.callback = JoystickFunc;
- s_options_joystick_box.itemnames = yesno_names;
-
- s_options_customize_options_action.generic.type = MTYPE_ACTION;
- s_options_customize_options_action.generic.x = 0;
- s_options_customize_options_action.generic.y = 140;
- s_options_customize_options_action.generic.name = "customize controls";
- s_options_customize_options_action.generic.callback = CustomizeControlsFunc;
-
- s_options_defaults_action.generic.type = MTYPE_ACTION;
- s_options_defaults_action.generic.x = 0;
- s_options_defaults_action.generic.y = 150;
- s_options_defaults_action.generic.name = "reset defaults";
- s_options_defaults_action.generic.callback = ControlsResetDefaultsFunc;
-
- s_options_console_action.generic.type = MTYPE_ACTION;
- s_options_console_action.generic.x = 0;
- s_options_console_action.generic.y = 160;
- s_options_console_action.generic.name = "go to console";
- s_options_console_action.generic.callback = ConsoleFunc;
-
- ControlsSetMenuItemValues();
-
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_sfxvolume_slider );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_cdvolume_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_quality_list );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_compatibility_list );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_sensitivity_slider );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_alwaysrun_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_invertmouse_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookspring_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookstrafe_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_freelook_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_crosshair_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_joystick_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_customize_options_action );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_defaults_action );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_console_action );
-}
-
-void Options_MenuDraw (void)
-{
- M_Banner( "m_banner_options" );
- Menu_AdjustCursor( &s_options_menu, 1 );
- Menu_Draw( &s_options_menu );
-}
-
-const char *Options_MenuKey( int key )
-{
- return Default_MenuKey( &s_options_menu, key );
-}
-
-void M_Menu_Options_f (void)
-{
- Options_MenuInit();
- M_PushMenu ( Options_MenuDraw, Options_MenuKey );
-}
-
-/*
-=======================================================================
-
-VIDEO MENU
-
-=======================================================================
-*/
-
-void M_Menu_Video_f (void)
-{
- VID_MenuInit();
- M_PushMenu( VID_MenuDraw, VID_MenuKey );
-}
-
-/*
-=============================================================================
-
-END GAME MENU
-
-=============================================================================
-*/
-static int credits_start_time;
-static const char **credits;
-static char *creditsIndex[256];
-static char *creditsBuffer;
-static const char *idcredits[] =
-{
- "+QUAKE II BY ID SOFTWARE",
- "",
- "+PROGRAMMING",
- "John Carmack",
- "John Cash",
- "Brian Hook",
- "",
- "+ART",
- "Adrian Carmack",
- "Kevin Cloud",
- "Paul Steed",
- "",
- "+LEVEL DESIGN",
- "Tim Willits",
- "American McGee",
- "Christian Antkow",
- "Paul Jaquays",
- "Brandon James",
- "",
- "+BIZ",
- "Todd Hollenshead",
- "Barrett (Bear) Alexander",
- "Donna Jackson",
- "",
- "",
- "+SPECIAL THANKS",
- "Ben Donges for beta testing",
- "",
- "",
- "",
- "",
- "",
- "",
- "+ADDITIONAL SUPPORT",
- "",
- "+LINUX PORT AND CTF",
- "Dave \"Zoid\" Kirsch",
- "",
- "+CINEMATIC SEQUENCES",
- "Ending Cinematic by Blur Studio - ",
- "Venice, CA",
- "",
- "Environment models for Introduction",
- "Cinematic by Karl Dolgener",
- "",
- "Assistance with environment design",
- "by Cliff Iwai",
- "",
- "+SOUND EFFECTS AND MUSIC",
- "Sound Design by Soundelux Media Labs.",
- "Music Composed and Produced by",
- "Soundelux Media Labs. Special thanks",
- "to Bill Brown, Tom Ozanich, Brian",
- "Celano, Jeff Eisner, and The Soundelux",
- "Players.",
- "",
- "\"Level Music\" by Sonic Mayhem",
- "www.sonicmayhem.com",
- "",
- "\"Quake II Theme Song\"",
- "(C) 1997 Rob Zombie. All Rights",
- "Reserved.",
- "",
- "Track 10 (\"Climb\") by Jer Sypult",
- "",
- "Voice of computers by",
- "Carly Staehlin-Taylor",
- "",
- "+THANKS TO ACTIVISION",
- "+IN PARTICULAR:",
- "",
- "John Tam",
- "Steve Rosenthal",
- "Marty Stratton",
- "Henk Hartong",
- "",
- "Quake II(tm) (C)1997 Id Software, Inc.",
- "All Rights Reserved. Distributed by",
- "Activision, Inc. under license.",
- "Quake II(tm), the Id Software name,",
- "the \"Q II\"(tm) logo and id(tm)",
- "logo are trademarks of Id Software,",
- "Inc. Activision(R) is a registered",
- "trademark of Activision, Inc. All",
- "other trademarks and trade names are",
- "properties of their respective owners.",
- 0
-};
-
-static const char *xatcredits[] =
-{
- "+QUAKE II MISSION PACK: THE RECKONING",
- "+BY",
- "+XATRIX ENTERTAINMENT, INC.",
- "",
- "+DESIGN AND DIRECTION",
- "Drew Markham",
- "",
- "+PRODUCED BY",
- "Greg Goodrich",
- "",
- "+PROGRAMMING",
- "Rafael Paiz",
- "",
- "+LEVEL DESIGN / ADDITIONAL GAME DESIGN",
- "Alex Mayberry",
- "",
- "+LEVEL DESIGN",
- "Mal Blackwell",
- "Dan Koppel",
- "",
- "+ART DIRECTION",
- "Michael \"Maxx\" Kaufman",
- "",
- "+COMPUTER GRAPHICS SUPERVISOR AND",
- "+CHARACTER ANIMATION DIRECTION",
- "Barry Dempsey",
- "",
- "+SENIOR ANIMATOR AND MODELER",
- "Jason Hoover",
- "",
- "+CHARACTER ANIMATION AND",
- "+MOTION CAPTURE SPECIALIST",
- "Amit Doron",
- "",
- "+ART",
- "Claire Praderie-Markham",
- "Viktor Antonov",
- "Corky Lehmkuhl",
- "",
- "+INTRODUCTION ANIMATION",
- "Dominique Drozdz",
- "",
- "+ADDITIONAL LEVEL DESIGN",
- "Aaron Barber",
- "Rhett Baldwin",
- "",
- "+3D CHARACTER ANIMATION TOOLS",
- "Gerry Tyra, SA Technology",
- "",
- "+ADDITIONAL EDITOR TOOL PROGRAMMING",
- "Robert Duffy",
- "",
- "+ADDITIONAL PROGRAMMING",
- "Ryan Feltrin",
- "",
- "+PRODUCTION COORDINATOR",
- "Victoria Sylvester",
- "",
- "+SOUND DESIGN",
- "Gary Bradfield",
- "",
- "+MUSIC BY",
- "Sonic Mayhem",
- "",
- "",
- "",
- "+SPECIAL THANKS",
- "+TO",
- "+OUR FRIENDS AT ID SOFTWARE",
- "",
- "John Carmack",
- "John Cash",
- "Brian Hook",
- "Adrian Carmack",
- "Kevin Cloud",
- "Paul Steed",
- "Tim Willits",
- "Christian Antkow",
- "Paul Jaquays",
- "Brandon James",
- "Todd Hollenshead",
- "Barrett (Bear) Alexander",
- "Dave \"Zoid\" Kirsch",
- "Donna Jackson",
- "",
- "",
- "",
- "+THANKS TO ACTIVISION",
- "+IN PARTICULAR:",
- "",
- "Marty Stratton",
- "Henk \"The Original Ripper\" Hartong",
- "Kevin Kraff",
- "Jamey Gottlieb",
- "Chris Hepburn",
- "",
- "+AND THE GAME TESTERS",
- "",
- "Tim Vanlaw",
- "Doug Jacobs",
- "Steven Rosenthal",
- "David Baker",
- "Chris Campbell",
- "Aaron Casillas",
- "Steve Elwell",
- "Derek Johnstone",
- "Igor Krinitskiy",
- "Samantha Lee",
- "Michael Spann",
- "Chris Toft",
- "Juan Valdes",
- "",
- "+THANKS TO INTERGRAPH COMPUTER SYTEMS",
- "+IN PARTICULAR:",
- "",
- "Michael T. Nicolaou",
- "",
- "",
- "Quake II Mission Pack: The Reckoning",
- "(tm) (C)1998 Id Software, Inc. All",
- "Rights Reserved. Developed by Xatrix",
- "Entertainment, Inc. for Id Software,",
- "Inc. Distributed by Activision Inc.",
- "under license. Quake(R) is a",
- "registered trademark of Id Software,",
- "Inc. Quake II Mission Pack: The",
- "Reckoning(tm), Quake II(tm), the Id",
- "Software name, the \"Q II\"(tm) logo",
- "and id(tm) logo are trademarks of Id",
- "Software, Inc. Activision(R) is a",
- "registered trademark of Activision,",
- "Inc. Xatrix(R) is a registered",
- "trademark of Xatrix Entertainment,",
- "Inc. All other trademarks and trade",
- "names are properties of their",
- "respective owners.",
- 0
-};
-
-static const char *roguecredits[] =
-{
- "+QUAKE II MISSION PACK 2: GROUND ZERO",
- "+BY",
- "+ROGUE ENTERTAINMENT, INC.",
- "",
- "+PRODUCED BY",
- "Jim Molinets",
- "",
- "+PROGRAMMING",
- "Peter Mack",
- "Patrick Magruder",
- "",
- "+LEVEL DESIGN",
- "Jim Molinets",
- "Cameron Lamprecht",
- "Berenger Fish",
- "Robert Selitto",
- "Steve Tietze",
- "Steve Thoms",
- "",
- "+ART DIRECTION",
- "Rich Fleider",
- "",
- "+ART",
- "Rich Fleider",
- "Steve Maines",
- "Won Choi",
- "",
- "+ANIMATION SEQUENCES",
- "Creat Studios",
- "Steve Maines",
- "",
- "+ADDITIONAL LEVEL DESIGN",
- "Rich Fleider",
- "Steve Maines",
- "Peter Mack",
- "",
- "+SOUND",
- "James Grunke",
- "",
- "+GROUND ZERO THEME",
- "+AND",
- "+MUSIC BY",
- "Sonic Mayhem",
- "",
- "+VWEP MODELS",
- "Brent \"Hentai\" Dill",
- "",
- "",
- "",
- "+SPECIAL THANKS",
- "+TO",
- "+OUR FRIENDS AT ID SOFTWARE",
- "",
- "John Carmack",
- "John Cash",
- "Brian Hook",
- "Adrian Carmack",
- "Kevin Cloud",
- "Paul Steed",
- "Tim Willits",
- "Christian Antkow",
- "Paul Jaquays",
- "Brandon James",
- "Todd Hollenshead",
- "Barrett (Bear) Alexander",
- "Katherine Anna Kang",
- "Donna Jackson",
- "Dave \"Zoid\" Kirsch",
- "",
- "",
- "",
- "+THANKS TO ACTIVISION",
- "+IN PARTICULAR:",
- "",
- "Marty Stratton",
- "Henk Hartong",
- "Mitch Lasky",
- "Steve Rosenthal",
- "Steve Elwell",
- "",
- "+AND THE GAME TESTERS",
- "",
- "The Ranger Clan",
- "Dave \"Zoid\" Kirsch",
- "Nihilistic Software",
- "Robert Duffy",
- "",
- "And Countless Others",
- "",
- "",
- "",
- "Quake II Mission Pack 2: Ground Zero",
- "(tm) (C)1998 Id Software, Inc. All",
- "Rights Reserved. Developed by Rogue",
- "Entertainment, Inc. for Id Software,",
- "Inc. Distributed by Activision Inc.",
- "under license. Quake(R) is a",
- "registered trademark of Id Software,",
- "Inc. Quake II Mission Pack 2: Ground",
- "Zero(tm), Quake II(tm), the Id",
- "Software name, the \"Q II\"(tm) logo",
- "and id(tm) logo are trademarks of Id",
- "Software, Inc. Activision(R) is a",
- "registered trademark of Activision,",
- "Inc. Rogue(R) is a registered",
- "trademark of Rogue Entertainment,",
- "Inc. All other trademarks and trade",
- "names are properties of their",
- "respective owners.",
- 0
-};
-
-
-void M_Credits_MenuDraw( void )
-{
- int i, y;
-
- /*
- ** draw the credits
- */
- for ( i = 0, y = vid.height - ( ( cls.realtime - credits_start_time ) / 40.0F ); credits[i] && y < vid.height; y += 10, i++ )
- {
- int j, stringoffset;
- int bold;
-
- if ( y <= -8 )
- continue;
-
- if ( credits[i][0] == '+' )
- {
- bold = true;
- stringoffset = 1;
- }
- else
- {
- bold = false;
- stringoffset = 0;
- }
-
- for ( j = 0; credits[i][j+stringoffset]; j++ )
- {
- int x;
-
- x = ( vid.width - strlen( credits[i] ) * 8 - stringoffset * 8 ) / 2 + ( j + stringoffset ) * 8;
-
- if ( bold )
- re.DrawChar( x, y, credits[i][j+stringoffset] + 128 );
- else
- re.DrawChar( x, y, credits[i][j+stringoffset] );
- }
- }
-
- if ( y < 0 )
- credits_start_time = cls.realtime;
-}
-
-const char *M_Credits_Key( int key )
-{
- switch (key)
- {
- case K_ESCAPE:
- if (creditsBuffer)
- FS_FreeFile (creditsBuffer);
- M_PopMenu ();
- break;
- }
-
- return menu_out_sound;
-
-}
-
-extern int Developer_searchpath (int who);
-
-void M_Menu_Credits_f( void )
-{
- int n;
- int count;
- char *p;
- int isdeveloper;
-
- creditsBuffer = NULL;
- count = FS_LoadFile ("credits", &creditsBuffer);
- if (count != -1)
- {
- p = creditsBuffer;
- for (n = 0; n < 255; n++)
- {
- creditsIndex[n] = p;
- while (*p != '\r' && *p != '\n')
- {
- p++;
- if (--count == 0)
- break;
- }
- if (*p == '\r')
- {
- *p++ = 0;
- if (--count == 0)
- break;
- }
- *p++ = 0;
- if (--count == 0)
- break;
- }
- creditsIndex[++n] = 0;
- credits = creditsIndex;
- }
- else
- {
- isdeveloper = Developer_searchpath (1);
-
- if (isdeveloper == 1) // xatrix
- credits = xatcredits;
- else if (isdeveloper == 2) // ROGUE
- credits = roguecredits;
- else
- {
- credits = idcredits;
- }
-
- }
-
- credits_start_time = cls.realtime;
- M_PushMenu( M_Credits_MenuDraw, M_Credits_Key);
-}
-
-/*
-=============================================================================
-
-GAME MENU
-
-=============================================================================
-*/
-
-static int m_game_cursor;
-
-static menuframework_s s_game_menu;
-static menuaction_s s_easy_game_action;
-static menuaction_s s_medium_game_action;
-static menuaction_s s_hard_game_action;
-static menuaction_s s_load_game_action;
-static menuaction_s s_save_game_action;
-static menuaction_s s_credits_action;
-static menuseparator_s s_blankline;
-
-static void StartGame( void )
-{
- // disable updates and start the cinematic going
- cl.servercount = -1;
- M_ForceMenuOff ();
- Cvar_SetValue( "deathmatch", 0 );
- Cvar_SetValue( "coop", 0 );
-
- Cvar_SetValue( "gamerules", 0 ); //PGM
-
- Cbuf_AddText ("loading ; killserver ; wait ; newgame\n");
- cls.key_dest = key_game;
-}
-
-static void EasyGameFunc( void * )
-{
- Cvar_ForceSet( "skill", "0" );
- StartGame();
-}
-
-static void MediumGameFunc( void * )
-{
- Cvar_ForceSet( "skill", "1" );
- StartGame();
-}
-
-static void HardGameFunc( void * )
-{
- Cvar_ForceSet( "skill", "2" );
- StartGame();
-}
-
-static void LoadGameFunc( void * )
-{
- M_Menu_LoadGame_f ();
-}
-
-static void SaveGameFunc( void * )
-{
- M_Menu_SaveGame_f();
-}
-
-static void CreditsFunc( void * )
-{
- M_Menu_Credits_f();
-}
-
-void Game_MenuInit( void )
-{
- static const char *difficulty_names[] =
- {
- "easy",
- "medium",
- "hard",
- 0
- };
-
- s_game_menu.x = vid.width * 0.50;
- s_game_menu.nitems = 0;
-
- s_easy_game_action.generic.type = MTYPE_ACTION;
- s_easy_game_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_easy_game_action.generic.x = 0;
- s_easy_game_action.generic.y = 0;
- s_easy_game_action.generic.name = "easy";
- s_easy_game_action.generic.callback = EasyGameFunc;
-
- s_medium_game_action.generic.type = MTYPE_ACTION;
- s_medium_game_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_medium_game_action.generic.x = 0;
- s_medium_game_action.generic.y = 10;
- s_medium_game_action.generic.name = "medium";
- s_medium_game_action.generic.callback = MediumGameFunc;
-
- s_hard_game_action.generic.type = MTYPE_ACTION;
- s_hard_game_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_hard_game_action.generic.x = 0;
- s_hard_game_action.generic.y = 20;
- s_hard_game_action.generic.name = "hard";
- s_hard_game_action.generic.callback = HardGameFunc;
-
- s_blankline.generic.type = MTYPE_SEPARATOR;
-
- s_load_game_action.generic.type = MTYPE_ACTION;
- s_load_game_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_load_game_action.generic.x = 0;
- s_load_game_action.generic.y = 40;
- s_load_game_action.generic.name = "load game";
- s_load_game_action.generic.callback = LoadGameFunc;
-
- s_save_game_action.generic.type = MTYPE_ACTION;
- s_save_game_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_save_game_action.generic.x = 0;
- s_save_game_action.generic.y = 50;
- s_save_game_action.generic.name = "save game";
- s_save_game_action.generic.callback = SaveGameFunc;
-
- s_credits_action.generic.type = MTYPE_ACTION;
- s_credits_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_credits_action.generic.x = 0;
- s_credits_action.generic.y = 60;
- s_credits_action.generic.name = "credits";
- s_credits_action.generic.callback = CreditsFunc;
-
- Menu_AddItem( &s_game_menu, ( void * ) &s_easy_game_action );
- Menu_AddItem( &s_game_menu, ( void * ) &s_medium_game_action );
- Menu_AddItem( &s_game_menu, ( void * ) &s_hard_game_action );
- Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
- Menu_AddItem( &s_game_menu, ( void * ) &s_load_game_action );
- Menu_AddItem( &s_game_menu, ( void * ) &s_save_game_action );
- Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
- Menu_AddItem( &s_game_menu, ( void * ) &s_credits_action );
-
- Menu_Center( &s_game_menu );
-}
-
-void Game_MenuDraw( void )
-{
- M_Banner( "m_banner_game" );
- Menu_AdjustCursor( &s_game_menu, 1 );
- Menu_Draw( &s_game_menu );
-}
-
-const char *Game_MenuKey( int key )
-{
- return Default_MenuKey( &s_game_menu, key );
-}
-
-void M_Menu_Game_f (void)
-{
- Game_MenuInit();
- M_PushMenu( Game_MenuDraw, Game_MenuKey );
- m_game_cursor = 1;
-}
-
-/*
-=============================================================================
-
-LOADGAME MENU
-
-=============================================================================
-*/
-
-#define MAX_SAVEGAMES 15
-
-static menuframework_s s_savegame_menu;
-
-static menuframework_s s_loadgame_menu;
-static menuaction_s s_loadgame_actions[MAX_SAVEGAMES];
-
-char m_savestrings[MAX_SAVEGAMES][32];
-qboolean m_savevalid[MAX_SAVEGAMES];
-
-void Create_Savestrings (void)
-{
- int i;
- FILE *f;
- char name[MAX_OSPATH];
-
- for (i=0 ; i<MAX_SAVEGAMES ; i++)
- {
- Com_sprintf (name, sizeof(name), "%s/save/save%i/server.ssv", FS_Gamedir(), i);
- f = fopen (name, "rb");
- if (!f)
- {
- strcpy (m_savestrings[i], "<EMPTY>");
- m_savevalid[i] = false;
- }
- else
- {
- FS_Read (m_savestrings[i], sizeof(m_savestrings[i]), f);
- fclose (f);
- m_savevalid[i] = true;
- }
- }
-}
-
-void LoadGameCallback( void *self )
-{
- menuaction_s *a = ( menuaction_s * ) self;
-
- if ( m_savevalid[ a->generic.localdata[0] ] )
- Cbuf_AddText (va("load save%i\n", a->generic.localdata[0] ) );
- M_ForceMenuOff ();
-}
-
-void LoadGame_MenuInit( void )
-{
- int i;
-
- s_loadgame_menu.x = vid.width / 2 - 120;
- s_loadgame_menu.y = vid.height / 2 - 58;
- s_loadgame_menu.nitems = 0;
-
- Create_Savestrings();
-
- for ( i = 0; i < MAX_SAVEGAMES; i++ )
- {
- s_loadgame_actions[i].generic.name = m_savestrings[i];
- s_loadgame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
- s_loadgame_actions[i].generic.localdata[0] = i;
- s_loadgame_actions[i].generic.callback = LoadGameCallback;
-
- s_loadgame_actions[i].generic.x = 0;
- s_loadgame_actions[i].generic.y = ( i ) * 10;
- if (i>0) // separate from autosave
- s_loadgame_actions[i].generic.y += 10;
-
- s_loadgame_actions[i].generic.type = MTYPE_ACTION;
-
- Menu_AddItem( &s_loadgame_menu, &s_loadgame_actions[i] );
- }
-}
-
-void LoadGame_MenuDraw( void )
-{
- M_Banner( "m_banner_load_game" );
-// Menu_AdjustCursor( &s_loadgame_menu, 1 );
- Menu_Draw( &s_loadgame_menu );
-}
-
-const char *LoadGame_MenuKey( int key )
-{
- if ( key == K_ESCAPE || key == K_ENTER )
- {
- s_savegame_menu.cursor = s_loadgame_menu.cursor - 1;
- if ( s_savegame_menu.cursor < 0 )
- s_savegame_menu.cursor = 0;
- }
- return Default_MenuKey( &s_loadgame_menu, key );
-}
-
-void M_Menu_LoadGame_f (void)
-{
- LoadGame_MenuInit();
- M_PushMenu( LoadGame_MenuDraw, LoadGame_MenuKey );
-}
-
-
-/*
-=============================================================================
-
-SAVEGAME MENU
-
-=============================================================================
-*/
-static menuframework_s s_savegame_menu;
-static menuaction_s s_savegame_actions[MAX_SAVEGAMES];
-
-void SaveGameCallback( void *self )
-{
- menuaction_s *a = ( menuaction_s * ) self;
-
- Cbuf_AddText (va("save save%i\n", a->generic.localdata[0] ));
- M_ForceMenuOff ();
-}
-
-void SaveGame_MenuDraw( void )
-{
- M_Banner( "m_banner_save_game" );
- Menu_AdjustCursor( &s_savegame_menu, 1 );
- Menu_Draw( &s_savegame_menu );
-}
-
-void SaveGame_MenuInit( void )
-{
- int i;
-
- s_savegame_menu.x = vid.width / 2 - 120;
- s_savegame_menu.y = vid.height / 2 - 58;
- s_savegame_menu.nitems = 0;
-
- Create_Savestrings();
-
- // don't include the autosave slot
- for ( i = 0; i < MAX_SAVEGAMES-1; i++ )
- {
- s_savegame_actions[i].generic.name = m_savestrings[i+1];
- s_savegame_actions[i].generic.localdata[0] = i+1;
- s_savegame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
- s_savegame_actions[i].generic.callback = SaveGameCallback;
-
- s_savegame_actions[i].generic.x = 0;
- s_savegame_actions[i].generic.y = ( i ) * 10;
-
- s_savegame_actions[i].generic.type = MTYPE_ACTION;
-
- Menu_AddItem( &s_savegame_menu, &s_savegame_actions[i] );
- }
-}
-
-const char *SaveGame_MenuKey( int key )
-{
- if ( key == K_ENTER || key == K_ESCAPE )
- {
- s_loadgame_menu.cursor = s_savegame_menu.cursor - 1;
- if ( s_loadgame_menu.cursor < 0 )
- s_loadgame_menu.cursor = 0;
- }
- return Default_MenuKey( &s_savegame_menu, key );
-}
-
-void M_Menu_SaveGame_f (void)
-{
- if (!Com_ServerState())
- return; // not playing a game
-
- SaveGame_MenuInit();
- M_PushMenu( SaveGame_MenuDraw, SaveGame_MenuKey );
- Create_Savestrings ();
-}
-
-
-/*
-=============================================================================
-
-JOIN SERVER MENU
-
-=============================================================================
-*/
-#define MAX_LOCAL_SERVERS 8
-
-static menuframework_s s_joinserver_menu;
-static menuseparator_s s_joinserver_server_title;
-static menuaction_s s_joinserver_search_action;
-static menuaction_s s_joinserver_address_book_action;
-static menuaction_s s_joinserver_server_actions[MAX_LOCAL_SERVERS];
-
-int m_num_servers;
-#define NO_SERVER_STRING "<no server>"
-
-// user readable information
-static char local_server_names[MAX_LOCAL_SERVERS][80];
-
-// network address
-static netadr_t local_server_netadr[MAX_LOCAL_SERVERS];
-
-void M_AddToServerList (netadr_t adr, char *info)
-{
- int i;
-
- if (m_num_servers == MAX_LOCAL_SERVERS)
- return;
- while ( *info == ' ' )
- info++;
-
- // ignore if duplicated
- for (i=0 ; i<m_num_servers ; i++)
- if (!strcmp(info, local_server_names[i]))
- return;
-
- local_server_netadr[m_num_servers] = adr;
- strncpy (local_server_names[m_num_servers], info, sizeof(local_server_names[0])-1);
- m_num_servers++;
-}
-
-
-void JoinServerFunc( void *self )
-{
- char buffer[128];
- int index;
-
- index = ( menuaction_s * ) self - s_joinserver_server_actions;
-
- if ( cistrcmp( local_server_names[index], NO_SERVER_STRING ) == 0 )
- return;
-
- if (index >= m_num_servers)
- return;
-
- Com_sprintf (buffer, sizeof(buffer), "connect %s\n", NET_AdrToString (local_server_netadr[index]));
- Cbuf_AddText (buffer);
- M_ForceMenuOff ();
-}
-
-void AddressBookFunc( void * )
-{
- M_Menu_AddressBook_f();
-}
-
-void NullCursorDraw( void * )
-{
-}
-
-void SearchLocalGames( void )
-{
- int i;
-
- m_num_servers = 0;
- for (i=0 ; i<MAX_LOCAL_SERVERS ; i++)
- strcpy (local_server_names[i], NO_SERVER_STRING);
-
- M_DrawTextBox( 8, 120 - 48, 36, 3 );
- M_Print( 16 + 16, 120 - 48 + 8, "Searching for local servers, this" );
- M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
- M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
-
- // the text box won't show up unless we do a buffer swap
- re.EndFrame();
-
- // send out info packets
- CL_PingServers_f();
-}
-
-void SearchLocalGamesFunc( void * )
-{
- SearchLocalGames();
-}
-
-void JoinServer_MenuInit( void )
-{
- int i;
-
- s_joinserver_menu.x = vid.width * 0.50 - 120;
- s_joinserver_menu.nitems = 0;
-
- s_joinserver_address_book_action.generic.type = MTYPE_ACTION;
- s_joinserver_address_book_action.generic.name = "address book";
- s_joinserver_address_book_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_joinserver_address_book_action.generic.x = 0;
- s_joinserver_address_book_action.generic.y = 0;
- s_joinserver_address_book_action.generic.callback = AddressBookFunc;
-
- s_joinserver_search_action.generic.type = MTYPE_ACTION;
- s_joinserver_search_action.generic.name = "refresh server list";
- s_joinserver_search_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_joinserver_search_action.generic.x = 0;
- s_joinserver_search_action.generic.y = 10;
- s_joinserver_search_action.generic.callback = SearchLocalGamesFunc;
- s_joinserver_search_action.generic.statusbar = "search for servers";
-
- s_joinserver_server_title.generic.type = MTYPE_SEPARATOR;
- s_joinserver_server_title.generic.name = "connect to...";
- s_joinserver_server_title.generic.x = 80;
- s_joinserver_server_title.generic.y = 30;
-
- for ( i = 0; i < MAX_LOCAL_SERVERS; i++ )
- {
- s_joinserver_server_actions[i].generic.type = MTYPE_ACTION;
- strcpy (local_server_names[i], NO_SERVER_STRING);
- s_joinserver_server_actions[i].generic.name = local_server_names[i];
- s_joinserver_server_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
- s_joinserver_server_actions[i].generic.x = 0;
- s_joinserver_server_actions[i].generic.y = 40 + i*10;
- s_joinserver_server_actions[i].generic.callback = JoinServerFunc;
- s_joinserver_server_actions[i].generic.statusbar = "press ENTER to connect";
- }
-
- Menu_AddItem( &s_joinserver_menu, &s_joinserver_address_book_action );
- Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_title );
- Menu_AddItem( &s_joinserver_menu, &s_joinserver_search_action );
-
- for ( i = 0; i < 8; i++ )
- Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_actions[i] );
-
- Menu_Center( &s_joinserver_menu );
-
- SearchLocalGames();
-}
-
-void JoinServer_MenuDraw(void)
-{
- M_Banner( "m_banner_join_server" );
- Menu_Draw( &s_joinserver_menu );
-}
-
-
-const char *JoinServer_MenuKey( int key )
-{
- return Default_MenuKey( &s_joinserver_menu, key );
-}
-
-void M_Menu_JoinServer_f (void)
-{
- JoinServer_MenuInit();
- M_PushMenu( JoinServer_MenuDraw, JoinServer_MenuKey );
-}
-
-
-/*
-=============================================================================
-
-START SERVER MENU
-
-=============================================================================
-*/
-static menuframework_s s_startserver_menu;
-static char **mapnames;
-static int nummaps;
-
-static menuaction_s s_startserver_start_action;
-static menuaction_s s_startserver_dmoptions_action;
-static menufield_s s_timelimit_field;
-static menufield_s s_fraglimit_field;
-static menufield_s s_maxclients_field;
-static menufield_s s_hostname_field;
-static menulist_s s_startmap_list;
-static menulist_s s_rules_box;
-
-void DMOptionsFunc( void * )
-{
- if (s_rules_box.curvalue == 1)
- return;
- M_Menu_DMOptions_f();
-}
-
-void RulesChangeFunc ( void * )
-{
- // DM
- if (s_rules_box.curvalue == 0)
- {
- s_maxclients_field.generic.statusbar = NULL;
- s_startserver_dmoptions_action.generic.statusbar = NULL;
- }
- else if(s_rules_box.curvalue == 1) // coop // PGM
- {
- s_maxclients_field.generic.statusbar = "4 maximum for cooperative";
- if (atoi(s_maxclients_field.buffer) > 4)
- strcpy( s_maxclients_field.buffer, "4" );
- s_startserver_dmoptions_action.generic.statusbar = "N/A for cooperative";
- }
-//=====
-//PGM
- // ROGUE GAMES
- else if(Developer_searchpath(2) == 2)
- {
- if (s_rules_box.curvalue == 2) // tag
- {
- s_maxclients_field.generic.statusbar = NULL;
- s_startserver_dmoptions_action.generic.statusbar = NULL;
- }
-/*
- else if(s_rules_box.curvalue == 3) // deathball
- {
- s_maxclients_field.generic.statusbar = NULL;
- s_startserver_dmoptions_action.generic.statusbar = NULL;
- }
-*/
- }
-//PGM
-//=====
-}
-
-void StartServerActionFunc( void * )
-{
- char startmap[1024];
- int timelimit;
- int fraglimit;
- int maxclients;
- char *spot;
-
- strcpy( startmap, strchr( mapnames[s_startmap_list.curvalue], '\n' ) + 1 );
-
- maxclients = atoi( s_maxclients_field.buffer );
- timelimit = atoi( s_timelimit_field.buffer );
- fraglimit = atoi( s_fraglimit_field.buffer );
-
- Cvar_SetValue( "maxclients", ClampCvar( 0, maxclients, maxclients ) );
- Cvar_SetValue ("timelimit", ClampCvar( 0, timelimit, timelimit ) );
- Cvar_SetValue ("fraglimit", ClampCvar( 0, fraglimit, fraglimit ) );
- Cvar_Set("hostname", s_hostname_field.buffer );
-// Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
-// Cvar_SetValue ("coop", s_rules_box.curvalue );
-
-//PGM
- if((s_rules_box.curvalue < 2) || (Developer_searchpath(2) != 2))
- {
- Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
- Cvar_SetValue ("coop", s_rules_box.curvalue );
- Cvar_SetValue ("gamerules", 0 );
- }
- else
- {
- Cvar_SetValue ("deathmatch", 1 ); // deathmatch is always true for rogue games, right?
- Cvar_SetValue ("coop", 0 ); // FIXME - this might need to depend on which game we're running
- Cvar_SetValue ("gamerules", s_rules_box.curvalue );
- }
-//PGM
-
- spot = NULL;
- if (s_rules_box.curvalue == 1) // PGM
- {
- if(cistrcmp(startmap, "bunk1") == 0)
- spot = "start";
- else if(cistrcmp(startmap, "mintro") == 0)
- spot = "start";
- else if(cistrcmp(startmap, "fact1") == 0)
- spot = "start";
- else if(cistrcmp(startmap, "power1") == 0)
- spot = "pstart";
- else if(cistrcmp(startmap, "biggun") == 0)
- spot = "bstart";
- else if(cistrcmp(startmap, "hangar1") == 0)
- spot = "unitstart";
- else if(cistrcmp(startmap, "city1") == 0)
- spot = "unitstart";
- else if(cistrcmp(startmap, "boss1") == 0)
- spot = "bosstart";
- }
-
- if (spot)
- {
- if (Com_ServerState())
- Cbuf_AddText ("disconnect\n");
- Cbuf_AddText (va("gamemap \"*%s$%s\"\n", startmap, spot));
- }
- else
- {
- Cbuf_AddText (va("map %s\n", startmap));
- }
-
- M_ForceMenuOff ();
-}
-
-void StartServer_MenuInit( void )
-{
- static const char *dm_coop_names[] =
- {
- "deathmatch",
- "cooperative",
- 0
- };
-//=======
-//PGM
- static const char *dm_coop_names_rogue[] =
- {
- "deathmatch",
- "cooperative",
- "tag",
-// "deathball",
- 0
- };
-//PGM
-//=======
- char *buffer;
- char mapsname[1024];
- char *s;
- int length;
- int i;
- FILE *fp;
-
- /*
- ** load the list of map names
- */
- Com_sprintf( mapsname, sizeof( mapsname ), "%s/maps.lst", FS_Gamedir() );
- if ( ( fp = fopen( mapsname, "rb" ) ) == 0 )
- {
- if ( ( length = FS_LoadFile( "maps.lst", ( void ** ) &buffer ) ) == -1 )
- Com_Error( ERR_DROP, "couldn't find maps.lst\n" );
- }
- else
- {
-#ifdef _WIN32
- length = filelength( fileno( fp ) );
-#else
- fseek(fp, 0, SEEK_END);
- length = ftell(fp);
- fseek(fp, 0, SEEK_SET);
-#endif
- buffer = malloc( length );
- fread( buffer, length, 1, fp );
- }
-
- s = buffer;
-
- i = 0;
- while ( i < length )
- {
- if ( s[i] == '\r' )
- nummaps++;
- i++;
- }
-
- if ( nummaps == 0 )
- Com_Error( ERR_DROP, "no maps in maps.lst\n" );
-
- mapnames = malloc( sizeof( char * ) * ( nummaps + 1 ) );
- memset( mapnames, 0, sizeof( char * ) * ( nummaps + 1 ) );
-
- s = buffer;
-
- for ( i = 0; i < nummaps; i++ )
- {
- char shortname[MAX_TOKEN_CHARS];
- char longname[MAX_TOKEN_CHARS];
- char scratch[200];
- int j, l;
-
- strcpy( shortname, COM_Parse( &s ) );
- l = strlen(shortname);
- for (j=0 ; j<l ; j++)
- shortname[j] = toupper(shortname[j]);
- strcpy( longname, COM_Parse( &s ) );
- Com_sprintf( scratch, sizeof( scratch ), "%s\n%s", longname, shortname );
-
- mapnames[i] = malloc( strlen( scratch ) + 1 );
- strcpy( mapnames[i], scratch );
- }
- mapnames[nummaps] = 0;
-
- if ( fp != 0 )
- {
- free( buffer );
- }
- else
- {
- FS_FreeFile( buffer );
- }
-
- /*
- ** initialize the menu stuff
- */
- s_startserver_menu.x = vid.width * 0.50;
- s_startserver_menu.nitems = 0;
-
- s_startmap_list.generic.type = MTYPE_SPINCONTROL;
- s_startmap_list.generic.x = 0;
- s_startmap_list.generic.y = 0;
- s_startmap_list.generic.name = "initial map";
- s_startmap_list.itemnames = mapnames;
-
- s_rules_box.generic.type = MTYPE_SPINCONTROL;
- s_rules_box.generic.x = 0;
- s_rules_box.generic.y = 20;
- s_rules_box.generic.name = "rules";
-
-//PGM - rogue games only available with rogue DLL.
- if(Developer_searchpath(2) == 2)
- s_rules_box.itemnames = dm_coop_names_rogue;
- else
- s_rules_box.itemnames = dm_coop_names;
-//PGM
-
- if (Cvar_VariableValue("coop"))
- s_rules_box.curvalue = 1;
- else
- s_rules_box.curvalue = 0;
- s_rules_box.generic.callback = RulesChangeFunc;
-
- s_timelimit_field.generic.type = MTYPE_FIELD;
- s_timelimit_field.generic.name = "time limit";
- s_timelimit_field.generic.flags = QMF_NUMBERSONLY;
- s_timelimit_field.generic.x = 0;
- s_timelimit_field.generic.y = 36;
- s_timelimit_field.generic.statusbar = "0 = no limit";
- s_timelimit_field.length = 3;
- s_timelimit_field.visible_length = 3;
- strcpy( s_timelimit_field.buffer, Cvar_VariableString("timelimit") );
-
- s_fraglimit_field.generic.type = MTYPE_FIELD;
- s_fraglimit_field.generic.name = "frag limit";
- s_fraglimit_field.generic.flags = QMF_NUMBERSONLY;
- s_fraglimit_field.generic.x = 0;
- s_fraglimit_field.generic.y = 54;
- s_fraglimit_field.generic.statusbar = "0 = no limit";
- s_fraglimit_field.length = 3;
- s_fraglimit_field.visible_length = 3;
- strcpy( s_fraglimit_field.buffer, Cvar_VariableString("fraglimit") );
-
- /*
- ** maxclients determines the maximum number of players that can join
- ** the game. If maxclients is only "1" then we should default the menu
- ** option to 8 players, otherwise use whatever its current value is.
- ** Clamping will be done when the server is actually started.
- */
- s_maxclients_field.generic.type = MTYPE_FIELD;
- s_maxclients_field.generic.name = "max players";
- s_maxclients_field.generic.flags = QMF_NUMBERSONLY;
- s_maxclients_field.generic.x = 0;
- s_maxclients_field.generic.y = 72;
- s_maxclients_field.generic.statusbar = NULL;
- s_maxclients_field.length = 3;
- s_maxclients_field.visible_length = 3;
- if ( Cvar_VariableValue( "maxclients" ) == 1 )
- strcpy( s_maxclients_field.buffer, "8" );
- else
- strcpy( s_maxclients_field.buffer, Cvar_VariableString("maxclients") );
-
- s_hostname_field.generic.type = MTYPE_FIELD;
- s_hostname_field.generic.name = "hostname";
- s_hostname_field.generic.flags = 0;
- s_hostname_field.generic.x = 0;
- s_hostname_field.generic.y = 90;
- s_hostname_field.generic.statusbar = NULL;
- s_hostname_field.length = 12;
- s_hostname_field.visible_length = 12;
- strcpy( s_hostname_field.buffer, Cvar_VariableString("hostname") );
-
- s_startserver_dmoptions_action.generic.type = MTYPE_ACTION;
- s_startserver_dmoptions_action.generic.name = " deathmatch flags";
- s_startserver_dmoptions_action.generic.flags= QMF_LEFT_JUSTIFY;
- s_startserver_dmoptions_action.generic.x = 24;
- s_startserver_dmoptions_action.generic.y = 108;
- s_startserver_dmoptions_action.generic.statusbar = NULL;
- s_startserver_dmoptions_action.generic.callback = DMOptionsFunc;
-
- s_startserver_start_action.generic.type = MTYPE_ACTION;
- s_startserver_start_action.generic.name = " begin";
- s_startserver_start_action.generic.flags= QMF_LEFT_JUSTIFY;
- s_startserver_start_action.generic.x = 24;
- s_startserver_start_action.generic.y = 128;
- s_startserver_start_action.generic.callback = StartServerActionFunc;
-
- Menu_AddItem( &s_startserver_menu, &s_startmap_list );
- Menu_AddItem( &s_startserver_menu, &s_rules_box );
- Menu_AddItem( &s_startserver_menu, &s_timelimit_field );
- Menu_AddItem( &s_startserver_menu, &s_fraglimit_field );
- Menu_AddItem( &s_startserver_menu, &s_maxclients_field );
- Menu_AddItem( &s_startserver_menu, &s_hostname_field );
- Menu_AddItem( &s_startserver_menu, &s_startserver_dmoptions_action );
- Menu_AddItem( &s_startserver_menu, &s_startserver_start_action );
-
- Menu_Center( &s_startserver_menu );
-
- // call this now to set proper inital state
- RulesChangeFunc ( NULL );
-}
-
-void StartServer_MenuDraw(void)
-{
- Menu_Draw( &s_startserver_menu );
-}
-
-const char *StartServer_MenuKey( int key )
-{
- if ( key == K_ESCAPE )
- {
- if ( mapnames )
- {
- int i;
-
- for ( i = 0; i < nummaps; i++ )
- free( mapnames[i] );
- free( mapnames );
- }
- mapnames = 0;
- nummaps = 0;
- }
-
- return Default_MenuKey( &s_startserver_menu, key );
-}
-
-void M_Menu_StartServer_f (void)
-{
- StartServer_MenuInit();
- M_PushMenu( StartServer_MenuDraw, StartServer_MenuKey );
-}
-
-/*
-=============================================================================
-
-DMOPTIONS BOOK MENU
-
-=============================================================================
-*/
-static char dmoptions_statusbar[128];
-
-static menuframework_s s_dmoptions_menu;
-
-static menulist_s s_friendlyfire_box;
-static menulist_s s_falls_box;
-static menulist_s s_weapons_stay_box;
-static menulist_s s_instant_powerups_box;
-static menulist_s s_powerups_box;
-static menulist_s s_health_box;
-static menulist_s s_spawn_farthest_box;
-static menulist_s s_teamplay_box;
-static menulist_s s_samelevel_box;
-static menulist_s s_force_respawn_box;
-static menulist_s s_armor_box;
-static menulist_s s_allow_exit_box;
-static menulist_s s_infinite_ammo_box;
-static menulist_s s_fixed_fov_box;
-static menulist_s s_quad_drop_box;
-
-//ROGUE
-static menulist_s s_no_mines_box;
-static menulist_s s_no_nukes_box;
-static menulist_s s_stack_double_box;
-static menulist_s s_no_spheres_box;
-//ROGUE
-
-static void DMFlagCallback( void *self )
-{
- menulist_s *f = ( menulist_s * ) self;
- int flags;
- int bit = 0;
-
- flags = Cvar_VariableValue( "dmflags" );
-
- if ( f == &s_friendlyfire_box )
- {
- if ( f->curvalue )
- flags &= ~DF_NO_FRIENDLY_FIRE;
- else
- flags |= DF_NO_FRIENDLY_FIRE;
- goto setvalue;
- }
- else if ( f == &s_falls_box )
- {
- if ( f->curvalue )
- flags &= ~DF_NO_FALLING;
- else
- flags |= DF_NO_FALLING;
- goto setvalue;
- }
- else if ( f == &s_weapons_stay_box )
- {
- bit = DF_WEAPONS_STAY;
- }
- else if ( f == &s_instant_powerups_box )
- {
- bit = DF_INSTANT_ITEMS;
- }
- else if ( f == &s_allow_exit_box )
- {
- bit = DF_ALLOW_EXIT;
- }
- else if ( f == &s_powerups_box )
- {
- if ( f->curvalue )
- flags &= ~DF_NO_ITEMS;
- else
- flags |= DF_NO_ITEMS;
- goto setvalue;
- }
- else if ( f == &s_health_box )
- {
- if ( f->curvalue )
- flags &= ~DF_NO_HEALTH;
- else
- flags |= DF_NO_HEALTH;
- goto setvalue;
- }
- else if ( f == &s_spawn_farthest_box )
- {
- bit = DF_SPAWN_FARTHEST;
- }
- else if ( f == &s_teamplay_box )
- {
- if ( f->curvalue == 1 )
- {
- flags |= DF_SKINTEAMS;
- flags &= ~DF_MODELTEAMS;
- }
- else if ( f->curvalue == 2 )
- {
- flags |= DF_MODELTEAMS;
- flags &= ~DF_SKINTEAMS;
- }
- else
- {
- flags &= ~( DF_MODELTEAMS | DF_SKINTEAMS );
- }
-
- goto setvalue;
- }
- else if ( f == &s_samelevel_box )
- {
- bit = DF_SAME_LEVEL;
- }
- else if ( f == &s_force_respawn_box )
- {
- bit = DF_FORCE_RESPAWN;
- }
- else if ( f == &s_armor_box )
- {
- if ( f->curvalue )
- flags &= ~DF_NO_ARMOR;
- else
- flags |= DF_NO_ARMOR;
- goto setvalue;
- }
- else if ( f == &s_infinite_ammo_box )
- {
- bit = DF_INFINITE_AMMO;
- }
- else if ( f == &s_fixed_fov_box )
- {
- bit = DF_FIXED_FOV;
- }
- else if ( f == &s_quad_drop_box )
- {
- bit = DF_QUAD_DROP;
- }
-
-//=======
-//ROGUE
- else if (Developer_searchpath(2) == 2)
- {
- if ( f == &s_no_mines_box)
- {
- bit = DF_NO_MINES;
- }
- else if ( f == &s_no_nukes_box)
- {
- bit = DF_NO_NUKES;
- }
- else if ( f == &s_stack_double_box)
- {
- bit = DF_NO_STACK_DOUBLE;
- }
- else if ( f == &s_no_spheres_box)
- {
- bit = DF_NO_SPHERES;
- }
- }
-//ROGUE
-//=======
-
- if ( f )
- {
- if ( f->curvalue == 0 )
- flags &= ~bit;
- else
- flags |= bit;
- }
-
-setvalue:
- Cvar_SetValue ("dmflags", flags);
-
- Com_sprintf( dmoptions_statusbar, sizeof( dmoptions_statusbar ), "dmflags = %d", flags );
-
-}
-
-void DMOptions_MenuInit( void )
-{
- static const char *yes_no_names[] =
- {
- "no", "yes", 0
- };
- static const char *teamplay_names[] =
- {
- "disabled", "by skin", "by model", 0
- };
- int dmflags = Cvar_VariableValue( "dmflags" );
- int y = 0;
-
- s_dmoptions_menu.x = vid.width * 0.50;
- s_dmoptions_menu.nitems = 0;
-
- s_falls_box.generic.type = MTYPE_SPINCONTROL;
- s_falls_box.generic.x = 0;
- s_falls_box.generic.y = y;
- s_falls_box.generic.name = "falling damage";
- s_falls_box.generic.callback = DMFlagCallback;
- s_falls_box.itemnames = yes_no_names;
- s_falls_box.curvalue = ( dmflags & DF_NO_FALLING ) == 0;
-
- s_weapons_stay_box.generic.type = MTYPE_SPINCONTROL;
- s_weapons_stay_box.generic.x = 0;
- s_weapons_stay_box.generic.y = y += 10;
- s_weapons_stay_box.generic.name = "weapons stay";
- s_weapons_stay_box.generic.callback = DMFlagCallback;
- s_weapons_stay_box.itemnames = yes_no_names;
- s_weapons_stay_box.curvalue = ( dmflags & DF_WEAPONS_STAY ) != 0;
-
- s_instant_powerups_box.generic.type = MTYPE_SPINCONTROL;
- s_instant_powerups_box.generic.x = 0;
- s_instant_powerups_box.generic.y = y += 10;
- s_instant_powerups_box.generic.name = "instant powerups";
- s_instant_powerups_box.generic.callback = DMFlagCallback;
- s_instant_powerups_box.itemnames = yes_no_names;
- s_instant_powerups_box.curvalue = ( dmflags & DF_INSTANT_ITEMS ) != 0;
-
- s_powerups_box.generic.type = MTYPE_SPINCONTROL;
- s_powerups_box.generic.x = 0;
- s_powerups_box.generic.y = y += 10;
- s_powerups_box.generic.name = "allow powerups";
- s_powerups_box.generic.callback = DMFlagCallback;
- s_powerups_box.itemnames = yes_no_names;
- s_powerups_box.curvalue = ( dmflags & DF_NO_ITEMS ) == 0;
-
- s_health_box.generic.type = MTYPE_SPINCONTROL;
- s_health_box.generic.x = 0;
- s_health_box.generic.y = y += 10;
- s_health_box.generic.callback = DMFlagCallback;
- s_health_box.generic.name = "allow health";
- s_health_box.itemnames = yes_no_names;
- s_health_box.curvalue = ( dmflags & DF_NO_HEALTH ) == 0;
-
- s_armor_box.generic.type = MTYPE_SPINCONTROL;
- s_armor_box.generic.x = 0;
- s_armor_box.generic.y = y += 10;
- s_armor_box.generic.name = "allow armor";
- s_armor_box.generic.callback = DMFlagCallback;
- s_armor_box.itemnames = yes_no_names;
- s_armor_box.curvalue = ( dmflags & DF_NO_ARMOR ) == 0;
-
- s_spawn_farthest_box.generic.type = MTYPE_SPINCONTROL;
- s_spawn_farthest_box.generic.x = 0;
- s_spawn_farthest_box.generic.y = y += 10;
- s_spawn_farthest_box.generic.name = "spawn farthest";
- s_spawn_farthest_box.generic.callback = DMFlagCallback;
- s_spawn_farthest_box.itemnames = yes_no_names;
- s_spawn_farthest_box.curvalue = ( dmflags & DF_SPAWN_FARTHEST ) != 0;
-
- s_samelevel_box.generic.type = MTYPE_SPINCONTROL;
- s_samelevel_box.generic.x = 0;
- s_samelevel_box.generic.y = y += 10;
- s_samelevel_box.generic.name = "same map";
- s_samelevel_box.generic.callback = DMFlagCallback;
- s_samelevel_box.itemnames = yes_no_names;
- s_samelevel_box.curvalue = ( dmflags & DF_SAME_LEVEL ) != 0;
-
- s_force_respawn_box.generic.type = MTYPE_SPINCONTROL;
- s_force_respawn_box.generic.x = 0;
- s_force_respawn_box.generic.y = y += 10;
- s_force_respawn_box.generic.name = "force respawn";
- s_force_respawn_box.generic.callback = DMFlagCallback;
- s_force_respawn_box.itemnames = yes_no_names;
- s_force_respawn_box.curvalue = ( dmflags & DF_FORCE_RESPAWN ) != 0;
-
- s_teamplay_box.generic.type = MTYPE_SPINCONTROL;
- s_teamplay_box.generic.x = 0;
- s_teamplay_box.generic.y = y += 10;
- s_teamplay_box.generic.name = "teamplay";
- s_teamplay_box.generic.callback = DMFlagCallback;
- s_teamplay_box.itemnames = teamplay_names;
-
- s_allow_exit_box.generic.type = MTYPE_SPINCONTROL;
- s_allow_exit_box.generic.x = 0;
- s_allow_exit_box.generic.y = y += 10;
- s_allow_exit_box.generic.name = "allow exit";
- s_allow_exit_box.generic.callback = DMFlagCallback;
- s_allow_exit_box.itemnames = yes_no_names;
- s_allow_exit_box.curvalue = ( dmflags & DF_ALLOW_EXIT ) != 0;
-
- s_infinite_ammo_box.generic.type = MTYPE_SPINCONTROL;
- s_infinite_ammo_box.generic.x = 0;
- s_infinite_ammo_box.generic.y = y += 10;
- s_infinite_ammo_box.generic.name = "infinite ammo";
- s_infinite_ammo_box.generic.callback = DMFlagCallback;
- s_infinite_ammo_box.itemnames = yes_no_names;
- s_infinite_ammo_box.curvalue = ( dmflags & DF_INFINITE_AMMO ) != 0;
-
- s_fixed_fov_box.generic.type = MTYPE_SPINCONTROL;
- s_fixed_fov_box.generic.x = 0;
- s_fixed_fov_box.generic.y = y += 10;
- s_fixed_fov_box.generic.name = "fixed FOV";
- s_fixed_fov_box.generic.callback = DMFlagCallback;
- s_fixed_fov_box.itemnames = yes_no_names;
- s_fixed_fov_box.curvalue = ( dmflags & DF_FIXED_FOV ) != 0;
-
- s_quad_drop_box.generic.type = MTYPE_SPINCONTROL;
- s_quad_drop_box.generic.x = 0;
- s_quad_drop_box.generic.y = y += 10;
- s_quad_drop_box.generic.name = "quad drop";
- s_quad_drop_box.generic.callback = DMFlagCallback;
- s_quad_drop_box.itemnames = yes_no_names;
- s_quad_drop_box.curvalue = ( dmflags & DF_QUAD_DROP ) != 0;
-
- s_friendlyfire_box.generic.type = MTYPE_SPINCONTROL;
- s_friendlyfire_box.generic.x = 0;
- s_friendlyfire_box.generic.y = y += 10;
- s_friendlyfire_box.generic.name = "friendly fire";
- s_friendlyfire_box.generic.callback = DMFlagCallback;
- s_friendlyfire_box.itemnames = yes_no_names;
- s_friendlyfire_box.curvalue = ( dmflags & DF_NO_FRIENDLY_FIRE ) == 0;
-
-//============
-//ROGUE
- if(Developer_searchpath(2) == 2)
- {
- s_no_mines_box.generic.type = MTYPE_SPINCONTROL;
- s_no_mines_box.generic.x = 0;
- s_no_mines_box.generic.y = y += 10;
- s_no_mines_box.generic.name = "remove mines";
- s_no_mines_box.generic.callback = DMFlagCallback;
- s_no_mines_box.itemnames = yes_no_names;
- s_no_mines_box.curvalue = ( dmflags & DF_NO_MINES ) != 0;
-
- s_no_nukes_box.generic.type = MTYPE_SPINCONTROL;
- s_no_nukes_box.generic.x = 0;
- s_no_nukes_box.generic.y = y += 10;
- s_no_nukes_box.generic.name = "remove nukes";
- s_no_nukes_box.generic.callback = DMFlagCallback;
- s_no_nukes_box.itemnames = yes_no_names;
- s_no_nukes_box.curvalue = ( dmflags & DF_NO_NUKES ) != 0;
-
- s_stack_double_box.generic.type = MTYPE_SPINCONTROL;
- s_stack_double_box.generic.x = 0;
- s_stack_double_box.generic.y = y += 10;
- s_stack_double_box.generic.name = "2x/4x stacking off";
- s_stack_double_box.generic.callback = DMFlagCallback;
- s_stack_double_box.itemnames = yes_no_names;
- s_stack_double_box.curvalue = ( dmflags & DF_NO_STACK_DOUBLE ) != 0;
-
- s_no_spheres_box.generic.type = MTYPE_SPINCONTROL;
- s_no_spheres_box.generic.x = 0;
- s_no_spheres_box.generic.y = y += 10;
- s_no_spheres_box.generic.name = "remove spheres";
- s_no_spheres_box.generic.callback = DMFlagCallback;
- s_no_spheres_box.itemnames = yes_no_names;
- s_no_spheres_box.curvalue = ( dmflags & DF_NO_SPHERES ) != 0;
-
- }
-//ROGUE
-//============
-
- Menu_AddItem( &s_dmoptions_menu, &s_falls_box );
- Menu_AddItem( &s_dmoptions_menu, &s_weapons_stay_box );
- Menu_AddItem( &s_dmoptions_menu, &s_instant_powerups_box );
- Menu_AddItem( &s_dmoptions_menu, &s_powerups_box );
- Menu_AddItem( &s_dmoptions_menu, &s_health_box );
- Menu_AddItem( &s_dmoptions_menu, &s_armor_box );
- Menu_AddItem( &s_dmoptions_menu, &s_spawn_farthest_box );
- Menu_AddItem( &s_dmoptions_menu, &s_samelevel_box );
- Menu_AddItem( &s_dmoptions_menu, &s_force_respawn_box );
- Menu_AddItem( &s_dmoptions_menu, &s_teamplay_box );
- Menu_AddItem( &s_dmoptions_menu, &s_allow_exit_box );
- Menu_AddItem( &s_dmoptions_menu, &s_infinite_ammo_box );
- Menu_AddItem( &s_dmoptions_menu, &s_fixed_fov_box );
- Menu_AddItem( &s_dmoptions_menu, &s_quad_drop_box );
- Menu_AddItem( &s_dmoptions_menu, &s_friendlyfire_box );
-
-//=======
-//ROGUE
- if(Developer_searchpath(2) == 2)
- {
- Menu_AddItem( &s_dmoptions_menu, &s_no_mines_box );
- Menu_AddItem( &s_dmoptions_menu, &s_no_nukes_box );
- Menu_AddItem( &s_dmoptions_menu, &s_stack_double_box );
- Menu_AddItem( &s_dmoptions_menu, &s_no_spheres_box );
- }
-//ROGUE
-//=======
-
- Menu_Center( &s_dmoptions_menu );
-
- // set the original dmflags statusbar
- DMFlagCallback( 0 );
- Menu_SetStatusBar( &s_dmoptions_menu, dmoptions_statusbar );
-}
-
-void DMOptions_MenuDraw(void)
-{
- Menu_Draw( &s_dmoptions_menu );
-}
-
-const char *DMOptions_MenuKey( int key )
-{
- return Default_MenuKey( &s_dmoptions_menu, key );
-}
-
-void M_Menu_DMOptions_f (void)
-{
- DMOptions_MenuInit();
- M_PushMenu( DMOptions_MenuDraw, DMOptions_MenuKey );
-}
-
-/*
-=============================================================================
-
-DOWNLOADOPTIONS BOOK MENU
-
-=============================================================================
-*/
-static menuframework_s s_downloadoptions_menu;
-
-static menuseparator_s s_download_title;
-static menulist_s s_allow_download_box;
-static menulist_s s_allow_download_maps_box;
-static menulist_s s_allow_download_models_box;
-static menulist_s s_allow_download_players_box;
-static menulist_s s_allow_download_sounds_box;
-
-static void DownloadCallback( void *self )
-{
- menulist_s *f = ( menulist_s * ) self;
-
- if (f == &s_allow_download_box)
- {
- Cvar_SetValue("allow_download", f->curvalue);
- }
-
- else if (f == &s_allow_download_maps_box)
- {
- Cvar_SetValue("allow_download_maps", f->curvalue);
- }
-
- else if (f == &s_allow_download_models_box)
- {
- Cvar_SetValue("allow_download_models", f->curvalue);
- }
-
- else if (f == &s_allow_download_players_box)
- {
- Cvar_SetValue("allow_download_players", f->curvalue);
- }
-
- else if (f == &s_allow_download_sounds_box)
- {
- Cvar_SetValue("allow_download_sounds", f->curvalue);
- }
-}
-
-void DownloadOptions_MenuInit( void )
-{
- static const char *yes_no_names[] =
- {
- "no", "yes", 0
- };
- int y = 0;
-
- s_downloadoptions_menu.x = vid.width * 0.50;
- s_downloadoptions_menu.nitems = 0;
-
- s_download_title.generic.type = MTYPE_SEPARATOR;
- s_download_title.generic.name = "Download Options";
- s_download_title.generic.x = 48;
- s_download_title.generic.y = y;
-
- s_allow_download_box.generic.type = MTYPE_SPINCONTROL;
- s_allow_download_box.generic.x = 0;
- s_allow_download_box.generic.y = y += 20;
- s_allow_download_box.generic.name = "allow downloading";
- s_allow_download_box.generic.callback = DownloadCallback;
- s_allow_download_box.itemnames = yes_no_names;
- s_allow_download_box.curvalue = (Cvar_VariableValue("allow_download") != 0);
-
- s_allow_download_maps_box.generic.type = MTYPE_SPINCONTROL;
- s_allow_download_maps_box.generic.x = 0;
- s_allow_download_maps_box.generic.y = y += 20;
- s_allow_download_maps_box.generic.name = "maps";
- s_allow_download_maps_box.generic.callback = DownloadCallback;
- s_allow_download_maps_box.itemnames = yes_no_names;
- s_allow_download_maps_box.curvalue = (Cvar_VariableValue("allow_download_maps") != 0);
-
- s_allow_download_players_box.generic.type = MTYPE_SPINCONTROL;
- s_allow_download_players_box.generic.x = 0;
- s_allow_download_players_box.generic.y = y += 10;
- s_allow_download_players_box.generic.name = "player models/skins";
- s_allow_download_players_box.generic.callback = DownloadCallback;
- s_allow_download_players_box.itemnames = yes_no_names;
- s_allow_download_players_box.curvalue = (Cvar_VariableValue("allow_download_players") != 0);
-
- s_allow_download_models_box.generic.type = MTYPE_SPINCONTROL;
- s_allow_download_models_box.generic.x = 0;
- s_allow_download_models_box.generic.y = y += 10;
- s_allow_download_models_box.generic.name = "models";
- s_allow_download_models_box.generic.callback = DownloadCallback;
- s_allow_download_models_box.itemnames = yes_no_names;
- s_allow_download_models_box.curvalue = (Cvar_VariableValue("allow_download_models") != 0);
-
- s_allow_download_sounds_box.generic.type = MTYPE_SPINCONTROL;
- s_allow_download_sounds_box.generic.x = 0;
- s_allow_download_sounds_box.generic.y = y += 10;
- s_allow_download_sounds_box.generic.name = "sounds";
- s_allow_download_sounds_box.generic.callback = DownloadCallback;
- s_allow_download_sounds_box.itemnames = yes_no_names;
- s_allow_download_sounds_box.curvalue = (Cvar_VariableValue("allow_download_sounds") != 0);
-
- Menu_AddItem( &s_downloadoptions_menu, &s_download_title );
- Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_box );
- Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_maps_box );
- Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_players_box );
- Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_models_box );
- Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_sounds_box );
-
- Menu_Center( &s_downloadoptions_menu );
-
- // skip over title
- if (s_downloadoptions_menu.cursor == 0)
- s_downloadoptions_menu.cursor = 1;
-}
-
-void DownloadOptions_MenuDraw(void)
-{
- Menu_Draw( &s_downloadoptions_menu );
-}
-
-const char *DownloadOptions_MenuKey( int key )
-{
- return Default_MenuKey( &s_downloadoptions_menu, key );
-}
-
-void M_Menu_DownloadOptions_f (void)
-{
- DownloadOptions_MenuInit();
- M_PushMenu( DownloadOptions_MenuDraw, DownloadOptions_MenuKey );
-}
-/*
-=============================================================================
-
-ADDRESS BOOK MENU
-
-=============================================================================
-*/
-#define NUM_ADDRESSBOOK_ENTRIES 9
-
-static menuframework_s s_addressbook_menu;
-static menufield_s s_addressbook_fields[NUM_ADDRESSBOOK_ENTRIES];
-
-void AddressBook_MenuInit( void )
-{
- int i;
-
- s_addressbook_menu.x = vid.width / 2 - 142;
- s_addressbook_menu.y = vid.height / 2 - 58;
- s_addressbook_menu.nitems = 0;
-
- for ( i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++ )
- {
- cvar_t *adr;
- char buffer[20];
-
- Com_sprintf( buffer, sizeof( buffer ), "adr%d", i );
-
- adr = Cvar_Get( buffer, "", CVAR_ARCHIVE );
-
- s_addressbook_fields[i].generic.type = MTYPE_FIELD;
- s_addressbook_fields[i].generic.name = 0;
- s_addressbook_fields[i].generic.callback = 0;
- s_addressbook_fields[i].generic.x = 0;
- s_addressbook_fields[i].generic.y = i * 18 + 0;
- s_addressbook_fields[i].generic.localdata[0] = i;
- s_addressbook_fields[i].cursor = 0;
- s_addressbook_fields[i].length = 60;
- s_addressbook_fields[i].visible_length = 30;
-
- strcpy( s_addressbook_fields[i].buffer, adr->string );
-
- Menu_AddItem( &s_addressbook_menu, &s_addressbook_fields[i] );
- }
-}
-
-const char *AddressBook_MenuKey( int key )
-{
- if ( key == K_ESCAPE )
- {
- int index;
- char buffer[20];
-
- for ( index = 0; index < NUM_ADDRESSBOOK_ENTRIES; index++ )
- {
- Com_sprintf( buffer, sizeof( buffer ), "adr%d", index );
- Cvar_Set( buffer, s_addressbook_fields[index].buffer );
- }
- }
- return Default_MenuKey( &s_addressbook_menu, key );
-}
-
-void AddressBook_MenuDraw(void)
-{
- M_Banner( "m_banner_addressbook" );
- Menu_Draw( &s_addressbook_menu );
-}
-
-void M_Menu_AddressBook_f(void)
-{
- AddressBook_MenuInit();
- M_PushMenu( AddressBook_MenuDraw, AddressBook_MenuKey );
-}
-
-/*
-=============================================================================
-
-PLAYER CONFIG MENU
-
-=============================================================================
-*/
-static menuframework_s s_player_config_menu;
-static menufield_s s_player_name_field;
-static menulist_s s_player_model_box;
-static menulist_s s_player_skin_box;
-static menulist_s s_player_handedness_box;
-static menulist_s s_player_rate_box;
-static menuseparator_s s_player_skin_title;
-static menuseparator_s s_player_model_title;
-static menuseparator_s s_player_hand_title;
-static menuseparator_s s_player_rate_title;
-static menuaction_s s_player_download_action;
-
-#define MAX_DISPLAYNAME 16
-#define MAX_PLAYERMODELS 1024
-
-typedef struct
-{
- int nskins;
- char **skindisplaynames;
- char displayname[MAX_DISPLAYNAME];
- char directory[MAX_QPATH];
-} playermodelinfo_s;
-
-static playermodelinfo_s s_pmi[MAX_PLAYERMODELS];
-static char *s_pmnames[MAX_PLAYERMODELS];
-static int s_numplayermodels;
-
-static int rate_tbl[] = { 2500, 3200, 5000, 10000, 25000, 0 };
-static const char *rate_names[] = { "28.8 Modem", "33.6 Modem", "Single ISDN",
- "Dual ISDN/Cable", "T1/LAN", "User defined", 0 };
-
-void DownloadOptionsFunc( void * )
-{
- M_Menu_DownloadOptions_f();
-}
-
-static void HandednessCallback( void * )
-{
- Cvar_SetValue( "hand", s_player_handedness_box.curvalue );
-}
-
-static void RateCallback( void * )
-{
- if (s_player_rate_box.curvalue != sizeof(rate_tbl) / sizeof(*rate_tbl) - 1)
- Cvar_SetValue( "rate", rate_tbl[s_player_rate_box.curvalue] );
-}
-
-static void ModelCallback( void * )
-{
- s_player_skin_box.itemnames = s_pmi[s_player_model_box.curvalue].skindisplaynames;
- s_player_skin_box.curvalue = 0;
-}
-
-static void FreeFileList( char **list, int n )
-{
- int i;
-
- for ( i = 0; i < n; i++ )
- {
- if ( list[i] )
- {
- free( list[i] );
- list[i] = 0;
- }
- }
- free( list );
-}
-
-static qboolean IconOfSkinExists( char *skin, char **pcxfiles, int npcxfiles )
-{
- int i;
- char scratch[1024];
-
- strcpy( scratch, skin );
- *strrchr( scratch, '.' ) = 0;
- strcat( scratch, "_i.pcx" );
-
- for ( i = 0; i < npcxfiles; i++ )
- {
- if ( strcmp( pcxfiles[i], scratch ) == 0 )
- return true;
- }
-
- return false;
-}
-
-static qboolean PlayerConfig_ScanDirectories( void )
-{
- char findname[1024];
- char scratch[1024];
- int ndirs = 0, npms;
- char **dirnames = NULL;
- char *path = NULL;
- int i;
-
- extern char **FS_ListFiles( char *, int *, unsigned, unsigned );
-
- s_numplayermodels = 0;
-
- /*
- ** get a list of directories
- */
- do
- {
- if ( ( path = FS_NextPath( path ) ) == NULL)
- break;
- Com_sprintf( findname, sizeof(findname), "%s/players/*.*", path );
-
- if ( ( dirnames = FS_ListFiles( findname, &ndirs, SFF_SUBDIR, 0 ) ) != 0 )
- break;
- } while ( path );
-
- if ( !dirnames )
- return false;
-
- /*
- ** go through the subdirectories
- */
- npms = ndirs;
- if ( npms > MAX_PLAYERMODELS )
- npms = MAX_PLAYERMODELS;
-
- for ( i = 0; i < npms; i++ )
- {
- int k, s;
- char *a, *b, *c;
- char **pcxnames;
- char **skinnames;
- int npcxfiles;
- int nskins = 0;
-
- if ( dirnames[i] == 0 )
- continue;
-
- // verify the existence of tris.md2
- strcpy( scratch, dirnames[i] );
- strcat( scratch, "/tris.md2" );
- if ( !Sys_FindFirst( scratch, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM ) )
- {
- free( dirnames[i] );
- dirnames[i] = 0;
- Sys_FindClose();
- continue;
- }
- Sys_FindClose();
-
- // verify the existence of at least one pcx skin
- strcpy( scratch, dirnames[i] );
- strcat( scratch, "/*.pcx" );
- pcxnames = FS_ListFiles( scratch, &npcxfiles, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM );
-
- if ( !pcxnames )
- {
- free( dirnames[i] );
- dirnames[i] = 0;
- continue;
- }
-
- // count valid skins, which consist of a skin with a matching "_i" icon
- for ( k = 0; k < npcxfiles-1; k++ )
- {
- if ( !strstr( pcxnames[k], "_i.pcx" ) )
- {
- if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
- {
- nskins++;
- }
- }
- }
- if ( !nskins )
- continue;
-
- skinnames = malloc( sizeof( char * ) * ( nskins + 1 ) );
- memset( skinnames, 0, sizeof( char * ) * ( nskins + 1 ) );
-
- // copy the valid skins
- for ( s = 0, k = 0; k < npcxfiles-1; k++ )
- {
- char *a, *b, *c;
-
- if ( !strstr( pcxnames[k], "_i.pcx" ) )
- {
- if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
- {
- a = strrchr( pcxnames[k], '/' );
- b = strrchr( pcxnames[k], '\\' );
-
- if ( a > b )
- c = a;
- else
- c = b;
-
- strcpy( scratch, c + 1 );
-
- if ( strrchr( scratch, '.' ) )
- *strrchr( scratch, '.' ) = 0;
-
- skinnames[s] = strdup( scratch );
- s++;
- }
- }
- }
-
- // at this point we have a valid player model
- s_pmi[s_numplayermodels].nskins = nskins;
- s_pmi[s_numplayermodels].skindisplaynames = skinnames;
-
- // make short name for the model
- a = strrchr( dirnames[i], '/' );
- b = strrchr( dirnames[i], '\\' );
-
- if ( a > b )
- c = a;
- else
- c = b;
-
- strncpy( s_pmi[s_numplayermodels].displayname, c + 1, MAX_DISPLAYNAME-1 );
- strcpy( s_pmi[s_numplayermodels].directory, c + 1 );
-
- FreeFileList( pcxnames, npcxfiles );
-
- s_numplayermodels++;
- }
- if ( dirnames )
- FreeFileList( dirnames, ndirs );
- return true;
-}
-
-static int pmicmpfnc( const void *_a, const void *_b )
-{
- const playermodelinfo_s *a = ( const playermodelinfo_s * ) _a;
- const playermodelinfo_s *b = ( const playermodelinfo_s * ) _b;
-
- /*
- ** sort by male, female, then alphabetical
- */
- if ( strcmp( a->directory, "male" ) == 0 )
- return -1;
- else if ( strcmp( b->directory, "male" ) == 0 )
- return 1;
-
- if ( strcmp( a->directory, "female" ) == 0 )
- return -1;
- else if ( strcmp( b->directory, "female" ) == 0 )
- return 1;
-
- return strcmp( a->directory, b->directory );
-}
-
-
-qboolean PlayerConfig_MenuInit( void )
-{
- extern cvar_t *name;
- extern cvar_t *team;
- extern cvar_t *skin;
- char currentdirectory[1024];
- char currentskin[1024];
- int i;
-
- int currentdirectoryindex = 0;
- int currentskinindex = 0;
-
- cvar_t *hand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
-
- static const char *handedness[] = { "right", "left", "center", 0 };
-
- PlayerConfig_ScanDirectories();
-
- if (s_numplayermodels == 0)
- return false;
-
- if ( hand->value < 0 || hand->value > 2 )
- Cvar_SetValue( "hand", 0 );
-
- strcpy( currentdirectory, skin->string );
-
- if ( strchr( currentdirectory, '/' ) )
- {
- strcpy( currentskin, strchr( currentdirectory, '/' ) + 1 );
- *strchr( currentdirectory, '/' ) = 0;
- }
- else if ( strchr( currentdirectory, '\\' ) )
- {
- strcpy( currentskin, strchr( currentdirectory, '\\' ) + 1 );
- *strchr( currentdirectory, '\\' ) = 0;
- }
- else
- {
- strcpy( currentdirectory, "male" );
- strcpy( currentskin, "grunt" );
- }
-
- qsort( s_pmi, s_numplayermodels, sizeof( s_pmi[0] ), pmicmpfnc );
-
- memset( s_pmnames, 0, sizeof( s_pmnames ) );
- for ( i = 0; i < s_numplayermodels; i++ )
- {
- s_pmnames[i] = s_pmi[i].displayname;
- if ( cistrcmp( s_pmi[i].directory, currentdirectory ) == 0 )
- {
- int j;
-
- currentdirectoryindex = i;
-
- for ( j = 0; j < s_pmi[i].nskins; j++ )
- {
- if ( cistrcmp( s_pmi[i].skindisplaynames[j], currentskin ) == 0 )
- {
- currentskinindex = j;
- break;
- }
- }
- }
- }
-
- s_player_config_menu.x = vid.width / 2 - 95;
- s_player_config_menu.y = vid.height / 2 - 97;
- s_player_config_menu.nitems = 0;
-
- s_player_name_field.generic.type = MTYPE_FIELD;
- s_player_name_field.generic.name = "name";
- s_player_name_field.generic.callback = 0;
- s_player_name_field.generic.x = 0;
- s_player_name_field.generic.y = 0;
- s_player_name_field.length = 20;
- s_player_name_field.visible_length = 20;
- strcpy( s_player_name_field.buffer, name->string );
- s_player_name_field.cursor = strlen( name->string );
-
- s_player_model_title.generic.type = MTYPE_SEPARATOR;
- s_player_model_title.generic.name = "model";
- s_player_model_title.generic.x = -8;
- s_player_model_title.generic.y = 60;
-
- s_player_model_box.generic.type = MTYPE_SPINCONTROL;
- s_player_model_box.generic.x = -56;
- s_player_model_box.generic.y = 70;
- s_player_model_box.generic.callback = ModelCallback;
- s_player_model_box.generic.cursor_offset = -48;
- s_player_model_box.curvalue = currentdirectoryindex;
- s_player_model_box.itemnames = s_pmnames;
-
- s_player_skin_title.generic.type = MTYPE_SEPARATOR;
- s_player_skin_title.generic.name = "skin";
- s_player_skin_title.generic.x = -16;
- s_player_skin_title.generic.y = 84;
-
- s_player_skin_box.generic.type = MTYPE_SPINCONTROL;
- s_player_skin_box.generic.x = -56;
- s_player_skin_box.generic.y = 94;
- s_player_skin_box.generic.name = 0;
- s_player_skin_box.generic.callback = 0;
- s_player_skin_box.generic.cursor_offset = -48;
- s_player_skin_box.curvalue = currentskinindex;
- s_player_skin_box.itemnames = s_pmi[currentdirectoryindex].skindisplaynames;
-
- s_player_hand_title.generic.type = MTYPE_SEPARATOR;
- s_player_hand_title.generic.name = "handedness";
- s_player_hand_title.generic.x = 32;
- s_player_hand_title.generic.y = 108;
-
- s_player_handedness_box.generic.type = MTYPE_SPINCONTROL;
- s_player_handedness_box.generic.x = -56;
- s_player_handedness_box.generic.y = 118;
- s_player_handedness_box.generic.name = 0;
- s_player_handedness_box.generic.cursor_offset = -48;
- s_player_handedness_box.generic.callback = HandednessCallback;
- s_player_handedness_box.curvalue = Cvar_VariableValue( "hand" );
- s_player_handedness_box.itemnames = handedness;
-
- for (i = 0; i < sizeof(rate_tbl) / sizeof(*rate_tbl) - 1; i++)
- if (Cvar_VariableValue("rate") == rate_tbl[i])
- break;
-
- s_player_rate_title.generic.type = MTYPE_SEPARATOR;
- s_player_rate_title.generic.name = "connect speed";
- s_player_rate_title.generic.x = 56;
- s_player_rate_title.generic.y = 156;
-
- s_player_rate_box.generic.type = MTYPE_SPINCONTROL;
- s_player_rate_box.generic.x = -56;
- s_player_rate_box.generic.y = 166;
- s_player_rate_box.generic.name = 0;
- s_player_rate_box.generic.cursor_offset = -48;
- s_player_rate_box.generic.callback = RateCallback;
- s_player_rate_box.curvalue = i;
- s_player_rate_box.itemnames = rate_names;
-
- s_player_download_action.generic.type = MTYPE_ACTION;
- s_player_download_action.generic.name = "download options";
- s_player_download_action.generic.flags= QMF_LEFT_JUSTIFY;
- s_player_download_action.generic.x = -24;
- s_player_download_action.generic.y = 186;
- s_player_download_action.generic.statusbar = NULL;
- s_player_download_action.generic.callback = DownloadOptionsFunc;
-
- Menu_AddItem( &s_player_config_menu, &s_player_name_field );
- Menu_AddItem( &s_player_config_menu, &s_player_model_title );
- Menu_AddItem( &s_player_config_menu, &s_player_model_box );
- if ( s_player_skin_box.itemnames )
- {
- Menu_AddItem( &s_player_config_menu, &s_player_skin_title );
- Menu_AddItem( &s_player_config_menu, &s_player_skin_box );
- }
- Menu_AddItem( &s_player_config_menu, &s_player_hand_title );
- Menu_AddItem( &s_player_config_menu, &s_player_handedness_box );
- Menu_AddItem( &s_player_config_menu, &s_player_rate_title );
- Menu_AddItem( &s_player_config_menu, &s_player_rate_box );
- Menu_AddItem( &s_player_config_menu, &s_player_download_action );
-
- return true;
-}
-
-void PlayerConfig_MenuDraw( void )
-{
- extern float CalcFov( float fov_x, float w, float h );
- refdef_t refdef;
- char scratch[MAX_QPATH];
-
- memset( &refdef, 0, sizeof( refdef ) );
-
- refdef.x = vid.width / 2;
- refdef.y = vid.height / 2 - 72;
- refdef.width = 144;
- refdef.height = 168;
- refdef.fov_x = 40;
- refdef.fov_y = CalcFov( refdef.fov_x, refdef.width, refdef.height );
- refdef.time = cls.realtime*0.001;
-
- if ( s_pmi[s_player_model_box.curvalue].skindisplaynames )
- {
- static int yaw;
- entity_t entity;
-
- memset( &entity, 0, sizeof( entity ) );
-
- Com_sprintf( scratch, sizeof( scratch ), "players/%s/tris.md2", s_pmi[s_player_model_box.curvalue].directory );
- entity.model = re.RegisterModel( scratch );
- Com_sprintf( scratch, sizeof( scratch ), "players/%s/%s.pcx", s_pmi[s_player_model_box.curvalue].directory, s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
- entity.skin = re.RegisterSkin( scratch );
- entity.flags = RF_FULLBRIGHT;
- entity.origin[0] = 80;
- entity.origin[1] = 0;
- entity.origin[2] = 0;
- VectorCopy( entity.origin, entity.oldorigin );
- entity.frame = 0;
- entity.oldframe = 0;
- entity.backlerp = 0.0;
- entity.angles[1] = yaw++;
- if ( ++yaw > 360 )
- yaw -= 360;
-
- refdef.areabits = 0;
- refdef.num_entities = 1;
- refdef.entities = &entity;
- refdef.lightstyles = 0;
- refdef.rdflags = RDF_NOWORLDMODEL;
-
- Menu_Draw( &s_player_config_menu );
-
- M_DrawTextBox( ( refdef.x ) * ( 320.0F / vid.width ) - 8, ( vid.height / 2 ) * ( 240.0F / vid.height) - 77, refdef.width / 8, refdef.height / 8 );
- refdef.height += 4;
-
- re.RenderFrame( &refdef );
-
- Com_sprintf( scratch, sizeof( scratch ), "/players/%s/%s_i.pcx",
- s_pmi[s_player_model_box.curvalue].directory,
- s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
- re.DrawPic( s_player_config_menu.x - 40, refdef.y, scratch );
- }
-}
-
-const char *PlayerConfig_MenuKey (int key)
-{
- int i;
-
- if ( key == K_ESCAPE )
- {
- char scratch[1024];
-
- Cvar_Set( "name", s_player_name_field.buffer );
-
- Com_sprintf( scratch, sizeof( scratch ), "%s/%s",
- s_pmi[s_player_model_box.curvalue].directory,
- s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
-
- Cvar_Set( "skin", scratch );
-
- for ( i = 0; i < s_numplayermodels; i++ )
- {
- int j;
-
- for ( j = 0; j < s_pmi[i].nskins; j++ )
- {
- if ( s_pmi[i].skindisplaynames[j] )
- free( s_pmi[i].skindisplaynames[j] );
- s_pmi[i].skindisplaynames[j] = 0;
- }
- free( s_pmi[i].skindisplaynames );
- s_pmi[i].skindisplaynames = 0;
- s_pmi[i].nskins = 0;
- }
- }
- return Default_MenuKey( &s_player_config_menu, key );
-}
-
-
-void M_Menu_PlayerConfig_f (void)
-{
- if (!PlayerConfig_MenuInit())
- {
- Menu_SetStatusBar( &s_multiplayer_menu, "No valid player models found" );
- return;
- }
- Menu_SetStatusBar( &s_multiplayer_menu, NULL );
- M_PushMenu( PlayerConfig_MenuDraw, PlayerConfig_MenuKey );
-}
-
-
-/*
-=======================================================================
-
-GALLERY MENU
-
-=======================================================================
-*/
-/* commented out in release
-void M_Menu_Gallery_f( void )
-{
- extern void Gallery_MenuDraw( void );
- extern const char *Gallery_MenuKey( int key );
-
- M_PushMenu( Gallery_MenuDraw, Gallery_MenuKey );
-}
-*/
-
-/*
-=======================================================================
-
-QUIT MENU
-
-=======================================================================
-*/
-
-const char *M_Quit_Key (int key)
-{
- switch (key)
- {
- case K_ESCAPE:
- case 'n':
- case 'N':
- M_PopMenu ();
- break;
-
- case 'Y':
- case 'y':
- cls.key_dest = key_console;
- CL_Quit_f ();
- break;
-
- default:
- break;
- }
-
- return NULL;
-
-}
-
-
-void M_Quit_Draw (void)
-{
- int w, h;
-
- re.DrawGetPicSize (&w, &h, "quit");
- re.DrawPic ( (vid.width-w)/2, (vid.height-h)/2, "quit");
-}
-
-
-void M_Menu_Quit_f (void)
-{
- M_PushMenu (M_Quit_Draw, M_Quit_Key);
-}
-
-
-
-//=============================================================================
-/* Menu Subsystem */
-
-
-/*
-=================
-M_Init
-=================
-*/
-void M_Init (void)
-{
- Cmd_AddCommand ("menu_main", M_Menu_Main_f);
- Cmd_AddCommand ("menu_game", M_Menu_Game_f);
- Cmd_AddCommand ("menu_loadgame", M_Menu_LoadGame_f);
- Cmd_AddCommand ("menu_savegame", M_Menu_SaveGame_f);
- Cmd_AddCommand ("menu_joinserver", M_Menu_JoinServer_f);
- Cmd_AddCommand ("menu_addressbook", M_Menu_AddressBook_f);
- Cmd_AddCommand ("menu_startserver", M_Menu_StartServer_f);
- Cmd_AddCommand ("menu_dmoptions", M_Menu_DMOptions_f);
- Cmd_AddCommand ("menu_playerconfig", M_Menu_PlayerConfig_f);
- Cmd_AddCommand ("menu_downloadoptions", M_Menu_DownloadOptions_f);
- Cmd_AddCommand ("menu_credits", M_Menu_Credits_f );
- Cmd_AddCommand ("menu_multiplayer", M_Menu_Multiplayer_f );
- Cmd_AddCommand ("menu_video", M_Menu_Video_f);
- Cmd_AddCommand ("menu_options", M_Menu_Options_f);
- Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
- Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
-}
-
-
-/*
-=================
-M_Draw
-=================
-*/
-void M_Draw (void)
-{
- if (cls.key_dest != key_menu)
- return;
-
- // repaint everything next frame
- SCR_DirtyScreen ();
-
- // dim everything behind it down
- if (cl.cinematictime > 0)
- re.DrawFill (0,0,vid.width, vid.height, 0);
- else
- re.DrawFadeScreen ();
-
- m_drawfunc ();
-
- // delay playing the enter sound until after the
- // menu has been drawn, to avoid delay while
- // caching images
- if (m_entersound)
- {
- S_StartLocalSound( menu_in_sound );
- m_entersound = false;
- }
-}
-
-
-/*
-=================
-M_Keydown
-=================
-*/
-void M_Keydown (int key)
-{
- const char *s;
-
- if (m_keyfunc)
- if ( ( s = m_keyfunc( key ) ) != 0 )
- S_StartLocalSound( ( char * ) s );
-}
-
-
--- a/client/qmenu.c
+++ /dev/null
@@ -1,651 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <ctype.h>
-#include "../q_shared.h"
-
-void Action_DoEnter( menuaction_s *a );
-void Action_Draw( menuaction_s *a );
-void Menu_DrawStatusBar( const char *string );
-void Menulist_DoEnter( menulist_s *l );
-void MenuList_Draw( menulist_s *l );
-void Separator_Draw( menuseparator_s *s );
-void Slider_DoSlide( menuslider_s *s, int dir );
-void Slider_Draw( menuslider_s *s );
-void SpinControl_DoEnter( menulist_s *s );
-void SpinControl_Draw( menulist_s *s );
-void SpinControl_DoSlide( menulist_s *s, int dir );
-
-#define RCOLUMN_OFFSET 16
-#define LCOLUMN_OFFSET -16
-
-extern refexport_t re;
-
-#define Draw_Char re.DrawChar
-#define Draw_Fill re.DrawFill
-
-void Action_DoEnter( menuaction_s *a )
-{
- if ( a->generic.callback )
- a->generic.callback( a );
-}
-
-void Action_Draw( menuaction_s *a )
-{
- if ( a->generic.flags & QMF_LEFT_JUSTIFY )
- {
- if ( a->generic.flags & QMF_GRAYED )
- Menu_DrawStringDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
- else
- Menu_DrawString( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
- }
- else
- {
- if ( a->generic.flags & QMF_GRAYED )
- Menu_DrawStringR2LDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
- else
- Menu_DrawStringR2L( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
- }
- if ( a->generic.ownerdraw )
- a->generic.ownerdraw( a );
-}
-
-qboolean Field_DoEnter( menufield_s *f )
-{
- if ( f->generic.callback )
- {
- f->generic.callback( f );
- return true;
- }
- return false;
-}
-
-void Field_Draw( menufield_s *f )
-{
- int i;
- char tempbuffer[128]="";
-
- if ( f->generic.name )
- Menu_DrawStringR2LDark( f->generic.x + f->generic.parent->x + LCOLUMN_OFFSET, f->generic.y + f->generic.parent->y, f->generic.name );
-
- strncpy( tempbuffer, f->buffer + f->visible_offset, f->visible_length );
-
- Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y - 4, 18 );
- Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y + 4, 24 );
-
- Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y - 4, 20 );
- Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y + 4, 26 );
-
- for ( i = 0; i < f->visible_length; i++ )
- {
- Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y - 4, 19 );
- Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y + 4, 25 );
- }
-
- Menu_DrawString( f->generic.x + f->generic.parent->x + 24, f->generic.y + f->generic.parent->y, tempbuffer );
-
- if ( Menu_ItemAtCursor( f->generic.parent ) == f )
- {
- int offset;
-
- if ( f->visible_offset )
- offset = f->visible_length;
- else
- offset = f->cursor;
-
- if ( ( ( int ) ( Sys_Milliseconds() / 250 ) ) & 1 )
- {
- Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8,
- f->generic.y + f->generic.parent->y,
- 11 );
- }
- else
- {
- Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8,
- f->generic.y + f->generic.parent->y,
- ' ' );
- }
- }
-}
-
-qboolean Field_Key( menufield_s *f, int key )
-{
- extern int keydown[];
-
- switch ( key )
- {
- case K_KP_SLASH:
- key = '/';
- break;
- case K_KP_MINUS:
- key = '-';
- break;
- case K_KP_PLUS:
- key = '+';
- break;
- case K_KP_HOME:
- key = '7';
- break;
- case K_KP_UPARROW:
- key = '8';
- break;
- case K_KP_PGUP:
- key = '9';
- break;
- case K_KP_LEFTARROW:
- key = '4';
- break;
- case K_KP_5:
- key = '5';
- break;
- case K_KP_RIGHTARROW:
- key = '6';
- break;
- case K_KP_END:
- key = '1';
- break;
- case K_KP_DOWNARROW:
- key = '2';
- break;
- case K_KP_PGDN:
- key = '3';
- break;
- case K_KP_INS:
- key = '0';
- break;
- case K_KP_DEL:
- key = '.';
- break;
- }
-
- if ( key > 127 )
- {
- switch ( key )
- {
- case K_DEL:
- default:
- return false;
- }
- }
-
- /*
- ** support pasting from the clipboard
- */
- if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
- ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
- {
- char *cbd;
-
- if ( ( cbd = Sys_GetClipboardData() ) != 0 )
- {
- strtok( cbd, "\n\r\b" );
-
- strncpy( f->buffer, cbd, f->length - 1 );
- f->cursor = strlen( f->buffer );
- f->visible_offset = f->cursor - f->visible_length;
- if ( f->visible_offset < 0 )
- f->visible_offset = 0;
-
- free( cbd );
- }
- return true;
- }
-
- switch ( key )
- {
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- case K_BACKSPACE:
- if ( f->cursor > 0 )
- {
- memmove( &f->buffer[f->cursor-1], &f->buffer[f->cursor], strlen( &f->buffer[f->cursor] ) + 1 );
- f->cursor--;
-
- if ( f->visible_offset )
- {
- f->visible_offset--;
- }
- }
- break;
-
- case K_KP_DEL:
- case K_DEL:
- memmove( &f->buffer[f->cursor], &f->buffer[f->cursor+1], strlen( &f->buffer[f->cursor+1] ) + 1 );
- break;
-
- case K_KP_ENTER:
- case K_ENTER:
- case K_ESCAPE:
- case K_TAB:
- return false;
-
- case K_SPACE:
- default:
- if ( !isdigit( key ) && ( f->generic.flags & QMF_NUMBERSONLY ) )
- return false;
-
- if ( f->cursor < f->length )
- {
- f->buffer[f->cursor++] = key;
- f->buffer[f->cursor] = 0;
-
- if ( f->cursor > f->visible_length )
- {
- f->visible_offset++;
- }
- }
- }
-
- return true;
-}
-
-void Menu_AddItem( menuframework_s *menu, void *item )
-{
- if ( menu->nitems == 0 )
- menu->nslots = 0;
-
- if ( menu->nitems < MAXMENUITEMS )
- {
- menu->items[menu->nitems] = item;
- ( ( menucommon_s * ) menu->items[menu->nitems] )->parent = menu;
- menu->nitems++;
- }
-
- menu->nslots = Menu_TallySlots( menu );
-}
-
-/*
-** Menu_AdjustCursor
-**
-** This function takes the given menu, the direction, and attempts
-** to adjust the menu's cursor so that it's at the next available
-** slot.
-*/
-void Menu_AdjustCursor( menuframework_s *m, int dir )
-{
- menucommon_s *citem;
-
- /*
- ** see if it's in a valid spot
- */
- if ( m->cursor >= 0 && m->cursor < m->nitems )
- {
- if ( ( citem = Menu_ItemAtCursor( m ) ) != 0 )
- {
- if ( citem->type != MTYPE_SEPARATOR )
- return;
- }
- }
-
- /*
- ** it's not in a valid spot, so crawl in the direction indicated until we
- ** find a valid spot
- */
- if ( dir == 1 )
- {
- while ( 1 )
- {
- citem = Menu_ItemAtCursor( m );
- if ( citem )
- if ( citem->type != MTYPE_SEPARATOR )
- break;
- m->cursor += dir;
- if ( m->cursor >= m->nitems )
- m->cursor = 0;
- }
- }
- else
- {
- while ( 1 )
- {
- citem = Menu_ItemAtCursor( m );
- if ( citem )
- if ( citem->type != MTYPE_SEPARATOR )
- break;
- m->cursor += dir;
- if ( m->cursor < 0 )
- m->cursor = m->nitems - 1;
- }
- }
-}
-
-void Menu_Center( menuframework_s *menu )
-{
- int height;
-
- height = ( ( menucommon_s * ) menu->items[menu->nitems-1])->y;
- height += 10;
-
- menu->y = ( vid.height - height ) / 2;
-}
-
-void Menu_Draw( menuframework_s *menu )
-{
- int i;
- menucommon_s *item;
-
- /*
- ** draw contents
- */
- for ( i = 0; i < menu->nitems; i++ )
- {
- switch ( ( ( menucommon_s * ) menu->items[i] )->type )
- {
- case MTYPE_FIELD:
- Field_Draw( ( menufield_s * ) menu->items[i] );
- break;
- case MTYPE_SLIDER:
- Slider_Draw( ( menuslider_s * ) menu->items[i] );
- break;
- case MTYPE_LIST:
- MenuList_Draw( ( menulist_s * ) menu->items[i] );
- break;
- case MTYPE_SPINCONTROL:
- SpinControl_Draw( ( menulist_s * ) menu->items[i] );
- break;
- case MTYPE_ACTION:
- Action_Draw( ( menuaction_s * ) menu->items[i] );
- break;
- case MTYPE_SEPARATOR:
- Separator_Draw( ( menuseparator_s * ) menu->items[i] );
- break;
- }
- }
-
- item = Menu_ItemAtCursor( menu );
-
- if ( item && item->cursordraw )
- {
- item->cursordraw( item );
- }
- else if ( menu->cursordraw )
- {
- menu->cursordraw( menu );
- }
- else if ( item && item->type != MTYPE_FIELD )
- {
- if ( item->flags & QMF_LEFT_JUSTIFY )
- {
- Draw_Char( menu->x + item->x - 24 + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) );
- }
- else
- {
- Draw_Char( menu->x + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) );
- }
- }
-
- if ( item )
- {
- if ( item->statusbarfunc )
- item->statusbarfunc( ( void * ) item );
- else if ( item->statusbar )
- Menu_DrawStatusBar( item->statusbar );
- else
- Menu_DrawStatusBar( menu->statusbar );
-
- }
- else
- {
- Menu_DrawStatusBar( menu->statusbar );
- }
-}
-
-void Menu_DrawStatusBar( const char *string )
-{
- if ( string )
- {
- int l = strlen( string );
- //int maxrow = vid.height / 8;
- int maxcol = vid.width / 8;
- int col = maxcol / 2 - l / 2;
-
- Draw_Fill( 0, vid.height-8, vid.width, 8, 4 );
- Menu_DrawString( col*8, vid.height - 8, string );
- }
- else
- {
- Draw_Fill( 0, vid.height-8, vid.width, 8, 0 );
- }
-}
-
-void Menu_DrawString( int x, int y, const char *string )
-{
- unsigned i;
-
- for ( i = 0; i < strlen( string ); i++ )
- {
- Draw_Char( ( x + i*8 ), y, string[i] );
- }
-}
-
-void Menu_DrawStringDark( int x, int y, const char *string )
-{
- unsigned i;
-
- for ( i = 0; i < strlen( string ); i++ )
- {
- Draw_Char( ( x + i*8 ), y, string[i] + 128 );
- }
-}
-
-void Menu_DrawStringR2L( int x, int y, const char *string )
-{
- unsigned i;
-
- for ( i = 0; i < strlen( string ); i++ )
- {
- Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1] );
- }
-}
-
-void Menu_DrawStringR2LDark( int x, int y, const char *string )
-{
- unsigned i;
-
- for ( i = 0; i < strlen( string ); i++ )
- {
- Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1]+128 );
- }
-}
-
-void *Menu_ItemAtCursor( menuframework_s *m )
-{
- if ( m->cursor < 0 || m->cursor >= m->nitems )
- return 0;
-
- return m->items[m->cursor];
-}
-
-qboolean Menu_SelectItem( menuframework_s *s )
-{
- menucommon_s *item = ( menucommon_s * ) Menu_ItemAtCursor( s );
-
- if ( item )
- {
- switch ( item->type )
- {
- case MTYPE_FIELD:
- return Field_DoEnter( ( menufield_s * ) item ) ;
- case MTYPE_ACTION:
- Action_DoEnter( ( menuaction_s * ) item );
- return true;
- case MTYPE_LIST:
-// Menulist_DoEnter( ( menulist_s * ) item );
- return false;
- case MTYPE_SPINCONTROL:
-// SpinControl_DoEnter( ( menulist_s * ) item );
- return false;
- }
- }
- return false;
-}
-
-void Menu_SetStatusBar( menuframework_s *m, const char *string )
-{
- m->statusbar = string;
-}
-
-void Menu_SlideItem( menuframework_s *s, int dir )
-{
- menucommon_s *item = ( menucommon_s * ) Menu_ItemAtCursor( s );
-
- if ( item )
- {
- switch ( item->type )
- {
- case MTYPE_SLIDER:
- Slider_DoSlide( ( menuslider_s * ) item, dir );
- break;
- case MTYPE_SPINCONTROL:
- SpinControl_DoSlide( ( menulist_s * ) item, dir );
- break;
- }
- }
-}
-
-int Menu_TallySlots( menuframework_s *menu )
-{
- int i;
- int total = 0;
-
- for ( i = 0; i < menu->nitems; i++ )
- {
- if ( ( ( menucommon_s * ) menu->items[i] )->type == MTYPE_LIST )
- {
- int nitems = 0;
- const char **n = ( ( menulist_s * ) menu->items[i] )->itemnames;
-
- while (*n)
- nitems++, n++;
-
- total += nitems;
- }
- else
- {
- total++;
- }
- }
-
- return total;
-}
-
-void Menulist_DoEnter( menulist_s *l )
-{
- int start;
-
- start = l->generic.y / 10 + 1;
-
- l->curvalue = l->generic.parent->cursor - start;
-
- if ( l->generic.callback )
- l->generic.callback( l );
-}
-
-void MenuList_Draw( menulist_s *l )
-{
- const char **n;
- int y = 0;
-
- Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y, l->generic.name );
-
- n = l->itemnames;
-
- Draw_Fill( l->generic.x - 112 + l->generic.parent->x, l->generic.parent->y + l->generic.y + l->curvalue*10 + 10, 128, 10, 16 );
- while ( *n )
- {
- Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y + y + 10, *n );
-
- n++;
- y += 10;
- }
-}
-
-void Separator_Draw( menuseparator_s *s )
-{
- if ( s->generic.name )
- Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->generic.name );
-}
-
-void Slider_DoSlide( menuslider_s *s, int dir )
-{
- s->curvalue += dir;
-
- if ( s->curvalue > s->maxvalue )
- s->curvalue = s->maxvalue;
- else if ( s->curvalue < s->minvalue )
- s->curvalue = s->minvalue;
-
- if ( s->generic.callback )
- s->generic.callback( s );
-}
-
-#define SLIDER_RANGE 10
-
-void Slider_Draw( menuslider_s *s )
-{
- int i;
-
- Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET,
- s->generic.y + s->generic.parent->y,
- s->generic.name );
-
- s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
-
- if ( s->range < 0)
- s->range = 0;
- if ( s->range > 1)
- s->range = 1;
- Draw_Char( s->generic.x + s->generic.parent->x + RCOLUMN_OFFSET, s->generic.y + s->generic.parent->y, 128);
- for ( i = 0; i < SLIDER_RANGE; i++ )
- Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 129);
- Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 130);
- Draw_Char( ( int ) ( 8 + RCOLUMN_OFFSET + s->generic.parent->x + s->generic.x + (SLIDER_RANGE-1)*8 * s->range ), s->generic.y + s->generic.parent->y, 131);
-}
-
-void SpinControl_DoEnter( menulist_s *s )
-{
- s->curvalue++;
- if ( s->itemnames[s->curvalue] == 0 )
- s->curvalue = 0;
-
- if ( s->generic.callback )
- s->generic.callback( s );
-}
-
-void SpinControl_DoSlide( menulist_s *s, int dir )
-{
- s->curvalue += dir;
-
- if ( s->curvalue < 0 )
- s->curvalue = 0;
- else if ( s->itemnames[s->curvalue] == 0 )
- s->curvalue--;
-
- if ( s->generic.callback )
- s->generic.callback( s );
-}
-
-void SpinControl_Draw( menulist_s *s )
-{
- char buffer[100];
-
- if ( s->generic.name )
- {
- Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET,
- s->generic.y + s->generic.parent->y,
- s->generic.name );
- }
- if ( !strchr( s->itemnames[s->curvalue], '\n' ) )
- {
- Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->itemnames[s->curvalue] );
- }
- else
- {
- strcpy( buffer, s->itemnames[s->curvalue] );
- *strchr( buffer, '\n' ) = 0;
- Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, buffer );
- strcpy( buffer, strchr( s->itemnames[s->curvalue], '\n' ) + 1 );
- Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y + 10, buffer );
- }
-}
-
--- a/client/qmenu.h
+++ /dev/null
@@ -1,108 +1,0 @@
-#ifndef __QMENU_H__
-#define __QMENU_H__
-
-#define MAXMENUITEMS 64
-
-#define MTYPE_SLIDER 0
-#define MTYPE_LIST 1
-#define MTYPE_ACTION 2
-#define MTYPE_SPINCONTROL 3
-#define MTYPE_SEPARATOR 4
-#define MTYPE_FIELD 5
-
-#define QMF_LEFT_JUSTIFY 0x00000001
-#define QMF_GRAYED 0x00000002
-#define QMF_NUMBERSONLY 0x00000004
-
-typedef struct _tag_menuframework
-{
- int x, y;
- int cursor;
-
- int nitems;
- int nslots;
- void *items[64];
-
- const char *statusbar;
-
- void (*cursordraw)( struct _tag_menuframework *m );
-
-} menuframework_s;
-
-typedef struct
-{
- int type;
- const char *name;
- int x, y;
- menuframework_s *parent;
- int cursor_offset;
- int localdata[4];
- unsigned flags;
-
- const char *statusbar;
-
- void (*callback)( void *self );
- void (*statusbarfunc)( void *self );
- void (*ownerdraw)( void *self );
- void (*cursordraw)( void *self );
-} menucommon_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- char buffer[80];
- int cursor;
- int length;
- int visible_length;
- int visible_offset;
-} menufield_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- float minvalue;
- float maxvalue;
- float curvalue;
-
- float range;
-} menuslider_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- int curvalue;
-
- const char **itemnames;
-} menulist_s;
-
-typedef struct
-{
- menucommon_s generic;
-} menuaction_s;
-
-typedef struct
-{
- menucommon_s generic;
-} menuseparator_s;
-
-qboolean Field_Key( menufield_s *field, int key );
-
-void Menu_AddItem( menuframework_s *menu, void *item );
-void Menu_AdjustCursor( menuframework_s *menu, int dir );
-void Menu_Center( menuframework_s *menu );
-void Menu_Draw( menuframework_s *menu );
-void *Menu_ItemAtCursor( menuframework_s *m );
-qboolean Menu_SelectItem( menuframework_s *s );
-void Menu_SetStatusBar( menuframework_s *s, const char *string );
-void Menu_SlideItem( menuframework_s *s, int dir );
-int Menu_TallySlots( menuframework_s *menu );
-
-void Menu_DrawString( int, int, const char * );
-void Menu_DrawStringDark( int, int, const char * );
-void Menu_DrawStringR2L( int, int, const char * );
-void Menu_DrawStringR2LDark( int, int, const char * );
-
-#endif
--- a/client/ref.h
+++ /dev/null
@@ -1,205 +1,0 @@
-#define MAX_DLIGHTS 32
-#define MAX_ENTITIES 128
-#define MAX_PARTICLES 4096
-//#define MAX_LIGHTSTYLES 256 /* macro redifinition */
-
-#define POWERSUIT_SCALE 4.0F
-
-#define SHELL_RED_COLOR 0xF2
-#define SHELL_GREEN_COLOR 0xD0
-#define SHELL_BLUE_COLOR 0xF3
-
-#define SHELL_RG_COLOR 0xDC
-//#define SHELL_RB_COLOR 0x86
-#define SHELL_RB_COLOR 0x68
-#define SHELL_BG_COLOR 0x78
-
-//ROGUE
-#define SHELL_DOUBLE_COLOR 0xDF // 223
-#define SHELL_HALF_DAM_COLOR 0x90
-#define SHELL_CYAN_COLOR 0x72
-//ROGUE
-
-#define SHELL_WHITE_COLOR 0xD7
-
-typedef struct entity_s
-{
- struct model_s *model; // opaque type outside refresh
- float angles[3];
-
- /*
- ** most recent data
- */
- float origin[3]; // also used as RF_BEAM's "from"
- int frame; // also used as RF_BEAM's diameter
-
- /*
- ** previous data for lerping
- */
- float oldorigin[3]; // also used as RF_BEAM's "to"
- int oldframe;
-
- /*
- ** misc
- */
- float backlerp; // 0.0 = current, 1.0 = old
- int skinnum; // also used as RF_BEAM's palette index
-
- int lightstyle; // for flashing entities
- float alpha; // ignore if RF_TRANSLUCENT isn't set
-
- struct image_s *skin; // NULL for inline skin
- int flags;
-
-} entity_t;
-
-#define ENTITY_FLAGS 68
-
-typedef struct
-{
- vec3_t origin;
- vec3_t color;
- float intensity;
-} dlight_t;
-
-typedef struct
-{
- vec3_t origin;
- int color;
- float alpha;
-} particle_t;
-
-typedef struct
-{
- float rgb[3]; // 0.0 - 2.0
- float white; // highest of rgb
-} lightstyle_t;
-
-typedef struct
-{
- int x, y, width, height;// in virtual screen coordinates
- float fov_x, fov_y;
- float vieworg[3];
- float viewangles[3];
- float blend[4]; // rgba 0-1 full screen blend
- float time; // time is uesed to auto animate
- int rdflags; // RDF_UNDERWATER, etc
-
- byte *areabits; // if not NULL, only areas with set bits will be drawn
-
- lightstyle_t *lightstyles; // [MAX_LIGHTSTYLES]
-
- int num_entities;
- entity_t *entities;
-
- int num_dlights;
- dlight_t *dlights;
-
- int num_particles;
- particle_t *particles;
-} refdef_t;
-
-
-
-#define API_VERSION 3
-
-//
-// these are the functions exported by the refresh module
-//
-typedef struct
-{
- // if api_version is different, the dll cannot be used
- int api_version;
-
- // called when the library is loaded
- qboolean (*Init) ( void *hinstance, void *wndproc );
-
- // called before the library is unloaded
- void (*Shutdown) (void);
-
- // All data that will be used in a level should be
- // registered before rendering any frames to prevent disk hits,
- // but they can still be registered at a later time
- // if necessary.
- //
- // EndRegistration will free any remaining data that wasn't registered.
- // Any model_s or skin_s pointers from before the BeginRegistration
- // are no longer valid after EndRegistration.
- //
- // Skins and images need to be differentiated, because skins
- // are flood filled to eliminate mip map edge errors, and pics have
- // an implicit "pics/" prepended to the name. (a pic name that starts with a
- // slash will not use the "pics/" prefix or the ".pcx" postfix)
- void (*BeginRegistration) (char *map);
- struct model_s *(*RegisterModel) (char *name);
- struct image_s *(*RegisterSkin) (char *name);
- struct image_s *(*RegisterPic) (char *name);
- void (*SetSky) (char *name, float rotate, vec3_t axis);
- void (*EndRegistration) (void);
-
- void (*RenderFrame) (refdef_t *fd);
-
- void (*DrawGetPicSize) (int *w, int *h, char *name); // will return 0 0 if not found
- void (*DrawPic) (int x, int y, char *name);
- void (*DrawStretchPic) (int x, int y, int w, int h, char *name);
- void (*DrawChar) (int x, int y, int c);
- void (*DrawTileClear) (int x, int y, int w, int h, char *name);
- void (*DrawFill) (int x, int y, int w, int h, int c);
- void (*DrawFadeScreen) (void);
-
- // Draw images for cinematic rendering (which can have a different palette). Note that calls
- void (*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, byte *data);
-
- /*
- ** video mode and refresh state management entry points
- */
- void (*CinematicSetPalette)( const unsigned char *palette); // NULL = game palette
- void (*BeginFrame)( float camera_separation );
- void (*EndFrame) (void);
-
- void (*AppActivate)( qboolean activate );
-
-} refexport_t;
-
-//
-// these are the functions imported by the refresh module
-//
-typedef struct
-{
- void (*Sys_Error) (int err_level, char *str, ...);
-
- void (*Cmd_AddCommand) (char *name, void(*cmd)(void));
- void (*Cmd_RemoveCommand) (char *name);
- int (*Cmd_Argc) (void);
- char *(*Cmd_Argv) (int i);
- void (*Cmd_ExecuteText) (int exec_when, char *text);
-
- void (*Con_Printf) (int print_level, char *str, ...);
-
- // files will be memory mapped read only
- // the returned buffer may be part of a larger pak file,
- // or a discrete file from anywhere in the quake search path
- // a -1 return means the file does not exist
- // NULL can be passed for buf to just determine existance
- int (*FS_LoadFile) (char *name, void **buf);
- void (*FS_FreeFile) (void *buf);
-
- // gamedir will be the current directory that generated
- // files should be stored to, ie: "f:\quake\id1"
- char *(*FS_Gamedir) (void);
-
- cvar_t *(*Cvar_Get) (char *name, char *value, int flags);
- cvar_t *(*Cvar_Set)( char *name, char *value );
- void (*Cvar_SetValue)( char *name, float value );
-
- qboolean (*Vid_GetModeInfo)( int *width, int *height, int mode );
- void (*Vid_MenuInit)( void );
- void (*Vid_NewWindow)( int width, int height );
-} refimport_t;
-
-
-// this is the only function actually exported at the linker level
-typedef refexport_t (*GetRefAPI_t) (refimport_t);
-
-extern cvar_t *vid_fullscreen;
-extern cvar_t *vid_gamma;
--- a/client/screen.h
+++ /dev/null
@@ -1,41 +1,0 @@
-void SCR_Init (void);
-
-void SCR_UpdateScreen (void);
-
-void SCR_SizeUp (void);
-void SCR_SizeDown (void);
-void SCR_CenterPrint (char *str);
-void SCR_BeginLoadingPlaque (void);
-void SCR_EndLoadingPlaque (void);
-
-void SCR_DebugGraph (float value, int color);
-
-void SCR_TouchPics (void);
-
-void SCR_RunConsole (void);
-
-extern float scr_con_current;
-extern float scr_conlines; // lines of console to display
-
-extern int sb_lines;
-
-extern cvar_t *scr_viewsize;
-extern cvar_t *crosshair;
-
-extern vrect_t scr_vrect; // position of render window
-
-extern char crosshair_pic[MAX_QPATH];
-extern int crosshair_width, crosshair_height;
-
-void SCR_AddDirtyPoint (int x, int y);
-void SCR_DirtyScreen (void);
-
-//
-// scr_cin.c
-//
-void SCR_PlayCinematic (char *name);
-qboolean SCR_DrawCinematic (void);
-void SCR_RunCinematic (void);
-void SCR_StopCinematic (void);
-void SCR_FinishCinematic (void);
-
--- a/client/snd_dma.c
+++ /dev/null
@@ -1,1194 +1,0 @@
-// snd_dma.c -- main control for any streaming sound output device
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-void S_Play(void);
-void S_SoundList(void);
-void S_Update_(void);
-void S_StopAllSounds(void);
-
-
-// =======================================================================
-// Internal sound data & structures
-// =======================================================================
-
-// only begin attenuating sound volumes when outside the FULLVOLUME range
-#define SOUND_FULLVOLUME 80
-
-#define SOUND_LOOPATTENUATE 0.003
-
-int s_registration_sequence;
-
-channel_t channels[MAX_CHANNELS];
-
-qboolean snd_initialized = false;
-int sound_started=0;
-
-dma_t dma;
-
-vec3_t listener_origin;
-vec3_t listener_forward;
-vec3_t listener_right;
-vec3_t listener_up;
-
-qboolean s_registering;
-
-int soundtime; // sample PAIRS
-int paintedtime; // sample PAIRS
-
-// during registration it is possible to have more sounds
-// than could actually be referenced during gameplay,
-// because we don't want to free anything until we are
-// sure we won't need it.
-#define MAX_SFX (MAX_SOUNDS*2)
-sfx_t known_sfx[MAX_SFX];
-int num_sfx;
-
-#define MAX_PLAYSOUNDS 128
-playsound_t s_playsounds[MAX_PLAYSOUNDS];
-playsound_t s_freeplays;
-playsound_t s_pendingplays;
-
-int s_beginofs;
-
-cvar_t *s_volume;
-cvar_t *s_testsound;
-cvar_t *s_loadas8bit;
-cvar_t *s_khz;
-cvar_t *s_show;
-cvar_t *s_mixahead;
-cvar_t *s_primary;
-
-
-int s_rawend;
-portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
-
-
-// ====================================================================
-// User-setable variables
-// ====================================================================
-
-
-void S_SoundInfo_f(void)
-{
- if (!sound_started)
- {
- Com_Printf ("sound system not started\n");
- return;
- }
-
- Com_Printf("%5d stereo\n", dma.channels - 1);
- Com_Printf("%5d samples\n", dma.samples);
- Com_Printf("%5d samplepos\n", dma.samplepos);
- Com_Printf("%5d samplebits\n", dma.samplebits);
- Com_Printf("%5d submission_chunk\n", dma.submission_chunk);
- Com_Printf("%5d speed\n", dma.speed);
- Com_Printf("0x%x dma buffer\n", dma.buffer);
-}
-
-
-
-/*
-================
-S_Init
-================
-*/
-void S_Init (void)
-{
- cvar_t *cv;
-
- Com_Printf("\n------- sound initialization -------\n");
-
- cv = Cvar_Get ("s_initsound", "1", 0);
- if (!cv->value)
- Com_Printf ("not initializing.\n");
- else
- {
- s_volume = Cvar_Get ("s_volume", "0.7", CVAR_ARCHIVE);
- s_khz = Cvar_Get ("s_khz", "11", CVAR_ARCHIVE);
- s_loadas8bit = Cvar_Get ("s_loadas8bit", "1", CVAR_ARCHIVE);
- s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
- s_show = Cvar_Get ("s_show", "0", 0);
- s_testsound = Cvar_Get ("s_testsound", "0", 0);
- s_primary = Cvar_Get ("s_primary", "0", CVAR_ARCHIVE); // win32 specific
-
- Cmd_AddCommand("play", S_Play);
- Cmd_AddCommand("stopsound", S_StopAllSounds);
- Cmd_AddCommand("soundlist", S_SoundList);
- Cmd_AddCommand("soundinfo", S_SoundInfo_f);
-
- if (!SNDDMA_Init())
- return;
-
- S_InitScaletable ();
-
- sound_started = 1;
- num_sfx = 0;
-
- soundtime = 0;
- paintedtime = 0;
-
- Com_Printf ("sound sampling rate: %i\n", dma.speed);
-
- S_StopAllSounds ();
- }
-
- Com_Printf("------------------------------------\n");
-}
-
-
-// =======================================================================
-// Shutdown sound engine
-// =======================================================================
-
-void S_Shutdown(void)
-{
- int i;
- sfx_t *sfx;
-
- if (!sound_started)
- return;
-
- SNDDMA_Shutdown();
-
- sound_started = 0;
-
- Cmd_RemoveCommand("play");
- Cmd_RemoveCommand("stopsound");
- Cmd_RemoveCommand("soundlist");
- Cmd_RemoveCommand("soundinfo");
-
- // free all sounds
- for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
- {
- if (!sfx->name[0])
- continue;
- if (sfx->cache)
- Z_Free (sfx->cache);
- memset (sfx, 0, sizeof(*sfx));
- }
-
- num_sfx = 0;
-}
-
-
-// =======================================================================
-// Load a sound
-// =======================================================================
-
-/*
-==================
-S_FindName
-
-==================
-*/
-sfx_t *S_FindName (char *name, qboolean create)
-{
- int i;
- sfx_t *sfx;
-
- if (!name)
- Com_Error (ERR_FATAL, "S_FindName: NULL\n");
- if (!name[0])
- Com_Error (ERR_FATAL, "S_FindName: empty name\n");
-
- if (strlen(name) >= MAX_QPATH)
- Com_Error (ERR_FATAL, "Sound name too long: %s", name);
-
- // see if already loaded
- for (i=0 ; i < num_sfx ; i++)
- if (!strcmp(known_sfx[i].name, name))
- {
- return &known_sfx[i];
- }
-
- if (!create)
- return NULL;
-
- // find a free sfx
- for (i=0 ; i < num_sfx ; i++)
- if (!known_sfx[i].name[0])
-// registration_sequence < s_registration_sequence)
- break;
-
- if (i == num_sfx)
- {
- if (num_sfx == MAX_SFX)
- Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
- num_sfx++;
- }
-
- sfx = &known_sfx[i];
- memset (sfx, 0, sizeof(*sfx));
- strcpy (sfx->name, name);
- sfx->registration_sequence = s_registration_sequence;
-
- return sfx;
-}
-
-
-/*
-==================
-S_AliasName
-
-==================
-*/
-sfx_t *S_AliasName (char *aliasname, char *truename)
-{
- sfx_t *sfx;
- char *s;
- int i;
-
- s = Z_Malloc (MAX_QPATH);
- strcpy (s, truename);
-
- // find a free sfx
- for (i=0 ; i < num_sfx ; i++)
- if (!known_sfx[i].name[0])
- break;
-
- if (i == num_sfx)
- {
- if (num_sfx == MAX_SFX)
- Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
- num_sfx++;
- }
-
- sfx = &known_sfx[i];
- memset (sfx, 0, sizeof(*sfx));
- strcpy (sfx->name, aliasname);
- sfx->registration_sequence = s_registration_sequence;
- sfx->truename = s;
-
- return sfx;
-}
-
-
-/*
-=====================
-S_BeginRegistration
-
-=====================
-*/
-void S_BeginRegistration (void)
-{
- s_registration_sequence++;
- s_registering = true;
-}
-
-/*
-==================
-S_RegisterSound
-
-==================
-*/
-sfx_t *S_RegisterSound (char *name)
-{
- sfx_t *sfx;
-
- if (!sound_started)
- return NULL;
-
- sfx = S_FindName (name, true);
- sfx->registration_sequence = s_registration_sequence;
-
- if (!s_registering)
- S_LoadSound (sfx);
-
- return sfx;
-}
-
-
-/*
-=====================
-S_EndRegistration
-
-=====================
-*/
-void S_EndRegistration (void)
-{
- int i;
- sfx_t *sfx;
- int size;
-
- // free any sounds not from this registration sequence
- for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
- {
- if (!sfx->name[0])
- continue;
- if (sfx->registration_sequence != s_registration_sequence)
- { // don't need this sound
- if (sfx->cache) // it is possible to have a leftover
- Z_Free (sfx->cache); // from a server that didn't finish loading
- memset (sfx, 0, sizeof(*sfx));
- }
- else
- { // make sure it is paged in
- if (sfx->cache)
- {
- size = sfx->cache->length*sfx->cache->width;
- Com_PageInMemory ((byte *)sfx->cache, size);
- }
- }
-
- }
-
- // load everything in
- for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
- {
- if (!sfx->name[0])
- continue;
- S_LoadSound (sfx);
- }
-
- s_registering = false;
-}
-
-
-//=============================================================================
-
-/*
-=================
-S_PickChannel
-=================
-*/
-channel_t *S_PickChannel(int entnum, int entchannel)
-{
- int ch_idx;
- int first_to_die;
- int life_left;
- channel_t *ch;
-
- if (entchannel<0)
- Com_Error (ERR_DROP, "S_PickChannel: entchannel<0");
-
-// Check for replacement sound, or find the best one to replace
- first_to_die = -1;
- life_left = 0x7fffffff;
- for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++)
- {
- if (entchannel != 0 // channel 0 never overrides
- && channels[ch_idx].entnum == entnum
- && channels[ch_idx].entchannel == entchannel)
- { // always override sound from same entity
- first_to_die = ch_idx;
- break;
- }
-
- // don't let monster sounds override player sounds
- if (channels[ch_idx].entnum == cl.playernum+1 && entnum != cl.playernum+1 && channels[ch_idx].sfx)
- continue;
-
- if (channels[ch_idx].end - paintedtime < life_left)
- {
- life_left = channels[ch_idx].end - paintedtime;
- first_to_die = ch_idx;
- }
- }
-
- if (first_to_die == -1)
- return NULL;
-
- ch = &channels[first_to_die];
- memset (ch, 0, sizeof(*ch));
-
- return ch;
-}
-
-/*
-=================
-S_SpatializeOrigin
-
-Used for spatializing channels and autosounds
-=================
-*/
-void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
-{
- vec_t dot;
- vec_t dist;
- vec_t lscale, rscale, scale;
- vec3_t source_vec;
-
- if (cls.state != ca_active)
- {
- *left_vol = *right_vol = 255;
- return;
- }
-
-// calculate stereo seperation and distance attenuation
- VectorSubtract(origin, listener_origin, source_vec);
-
- dist = VectorNormalize(source_vec);
- dist -= SOUND_FULLVOLUME;
- if (dist < 0)
- dist = 0; // close enough to be at full volume
- dist *= dist_mult; // different attenuation levels
-
- dot = DotProduct(listener_right, source_vec);
-
- if (dma.channels == 1 || !dist_mult)
- { // no attenuation = no spatialization
- rscale = 1.0;
- lscale = 1.0;
- }
- else
- {
- rscale = 0.5 * (1.0 + dot);
- lscale = 0.5*(1.0 - dot);
- }
-
- // add in distance effect
- scale = (1.0 - dist) * rscale;
- *right_vol = (int) (master_vol * scale);
- if (*right_vol < 0)
- *right_vol = 0;
-
- scale = (1.0 - dist) * lscale;
- *left_vol = (int) (master_vol * scale);
- if (*left_vol < 0)
- *left_vol = 0;
-}
-
-/*
-=================
-S_Spatialize
-=================
-*/
-void S_Spatialize(channel_t *ch)
-{
- vec3_t origin;
-
- // anything coming from the view entity will always be full volume
- if (ch->entnum == cl.playernum+1)
- {
- ch->leftvol = ch->master_vol;
- ch->rightvol = ch->master_vol;
- return;
- }
-
- if (ch->fixed_origin)
- {
- VectorCopy (ch->origin, origin);
- }
- else
- CL_GetEntitySoundOrigin (ch->entnum, origin);
-
- S_SpatializeOrigin (origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol);
-}
-
-
-/*
-=================
-S_AllocPlaysound
-=================
-*/
-playsound_t *S_AllocPlaysound (void)
-{
- playsound_t *ps;
-
- ps = s_freeplays.next;
- if (ps == &s_freeplays)
- return NULL; // no free playsounds
-
- // unlink from freelist
- ps->prev->next = ps->next;
- ps->next->prev = ps->prev;
-
- return ps;
-}
-
-
-/*
-=================
-S_FreePlaysound
-=================
-*/
-void S_FreePlaysound (playsound_t *ps)
-{
- // unlink from channel
- ps->prev->next = ps->next;
- ps->next->prev = ps->prev;
-
- // add to free list
- ps->next = s_freeplays.next;
- s_freeplays.next->prev = ps;
- ps->prev = &s_freeplays;
- s_freeplays.next = ps;
-}
-
-
-
-/*
-===============
-S_IssuePlaysound
-
-Take the next playsound and begin it on the channel
-This is never called directly by S_Play*, but only
-by the update loop.
-===============
-*/
-void S_IssuePlaysound (playsound_t *ps)
-{
- channel_t *ch;
- sfxcache_t *sc;
-
- if (s_show->value)
- Com_Printf ("Issue %i\n", ps->begin);
- // pick a channel to play on
- ch = S_PickChannel(ps->entnum, ps->entchannel);
- if (!ch)
- {
- S_FreePlaysound (ps);
- return;
- }
-
- // spatialize
- if (ps->attenuation == ATTN_STATIC)
- ch->dist_mult = ps->attenuation * 0.001;
- else
- ch->dist_mult = ps->attenuation * 0.0005;
- ch->master_vol = ps->volume;
- ch->entnum = ps->entnum;
- ch->entchannel = ps->entchannel;
- ch->sfx = ps->sfx;
- VectorCopy (ps->origin, ch->origin);
- ch->fixed_origin = ps->fixed_origin;
-
- S_Spatialize(ch);
-
- ch->pos = 0;
- sc = S_LoadSound (ch->sfx);
- ch->end = paintedtime + sc->length;
-
- // free the playsound
- S_FreePlaysound (ps);
-}
-
-struct sfx_s *S_RegisterSexedSound (entity_state_t *ent, char *base)
-{
- int n;
- char *p;
- struct sfx_s *sfx;
- FILE *f;
- char model[MAX_QPATH];
- char sexedFilename[MAX_QPATH];
- char maleFilename[MAX_QPATH];
-
- // determine what model the client is using
- model[0] = 0;
- n = CS_PLAYERSKINS + ent->number - 1;
- if (cl.configstrings[n][0])
- {
- p = strchr(cl.configstrings[n], '\\');
- if (p)
- {
- p += 1;
- strcpy(model, p);
- p = strchr(model, '/');
- if (p)
- *p = 0;
- }
- }
- // if we can't figure it out, they're male
- if (!model[0])
- strcpy(model, "male");
-
- // see if we already know of the model specific sound
- Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
- sfx = S_FindName (sexedFilename, false);
-
- if (!sfx)
- {
- // no, so see if it exists
- FS_FOpenFile (&sexedFilename[1], &f);
- if (f)
- {
- // yes, close the file and register it
- FS_FCloseFile (f);
- sfx = S_RegisterSound (sexedFilename);
- }
- else
- {
- // no, revert to the male sound in the pak0.pak
- Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1);
- sfx = S_AliasName (sexedFilename, maleFilename);
- }
- }
-
- return sfx;
-}
-
-
-// =======================================================================
-// Start a sound effect
-// =======================================================================
-
-/*
-====================
-S_StartSound
-
-Validates the parms and ques the sound up
-if pos is NULL, the sound will be dynamically sourced from the entity
-Entchannel 0 will never override a playing sound
-====================
-*/
-void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
-{
- sfxcache_t *sc;
- int vol;
- playsound_t *ps, *sort;
- int start;
-
- if (!sound_started)
- return;
-
- if (!sfx)
- return;
-
- if (sfx->name[0] == '*')
- sfx = S_RegisterSexedSound(&cl_entities[entnum].current, sfx->name);
-
- // make sure the sound is loaded
- sc = S_LoadSound (sfx);
- if (!sc)
- return; // couldn't load the sound's data
-
- vol = fvol*255;
-
- // make the playsound_t
- ps = S_AllocPlaysound ();
- if (!ps)
- return;
-
- if (origin)
- {
- VectorCopy (origin, ps->origin);
- ps->fixed_origin = true;
- }
- else
- ps->fixed_origin = false;
-
- ps->entnum = entnum;
- ps->entchannel = entchannel;
- ps->attenuation = attenuation;
- ps->volume = vol;
- ps->sfx = sfx;
-
- // drift s_beginofs
- start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs;
- if (start < paintedtime)
- {
- start = paintedtime;
- s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
- }
- else if (start > paintedtime + 0.3 * dma.speed)
- {
- start = paintedtime + 0.1 * dma.speed;
- s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
- }
- else
- {
- s_beginofs-=10;
- }
-
- if (!timeofs)
- ps->begin = paintedtime;
- else
- ps->begin = start + timeofs * dma.speed;
-
- // sort into the pending sound list
- for (sort = s_pendingplays.next ;
- sort != &s_pendingplays && sort->begin < ps->begin ;
- sort = sort->next)
- ;
-
- ps->next = sort;
- ps->prev = sort->prev;
-
- ps->next->prev = ps;
- ps->prev->next = ps;
-}
-
-
-/*
-==================
-S_StartLocalSound
-==================
-*/
-void S_StartLocalSound (char *sound)
-{
- sfx_t *sfx;
-
- if (!sound_started)
- return;
-
- sfx = S_RegisterSound (sound);
- if (!sfx)
- {
- Com_Printf ("S_StartLocalSound: can't cache %s\n", sound);
- return;
- }
- S_StartSound (NULL, cl.playernum+1, 0, sfx, 1, 1, 0);
-}
-
-
-/*
-==================
-S_ClearBuffer
-==================
-*/
-void S_ClearBuffer (void)
-{
- int clear;
-
- if (!sound_started)
- return;
-
- s_rawend = 0;
-
- if (dma.samplebits == 8)
- clear = 0x80;
- else
- clear = 0;
-
- SNDDMA_BeginPainting ();
- if (dma.buffer)
- memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
- SNDDMA_Submit ();
-}
-
-/*
-==================
-S_StopAllSounds
-==================
-*/
-void S_StopAllSounds(void)
-{
- int i;
-
- if (!sound_started)
- return;
-
- // clear all the playsounds
- memset(s_playsounds, 0, sizeof(s_playsounds));
- s_freeplays.next = s_freeplays.prev = &s_freeplays;
- s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
-
- for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
- {
- s_playsounds[i].prev = &s_freeplays;
- s_playsounds[i].next = s_freeplays.next;
- s_playsounds[i].prev->next = &s_playsounds[i];
- s_playsounds[i].next->prev = &s_playsounds[i];
- }
-
- // clear all the channels
- memset(channels, 0, sizeof(channels));
-
- S_ClearBuffer ();
-}
-
-/*
-==================
-S_AddLoopSounds
-
-Entities with a ->sound field will generated looped sounds
-that are automatically started, stopped, and merged together
-as the entities are sent to the client
-==================
-*/
-void S_AddLoopSounds (void)
-{
- int i, j;
- int sounds[MAX_EDICTS];
- int left, right, left_total, right_total;
- channel_t *ch;
- sfx_t *sfx;
- sfxcache_t *sc;
- int num;
- entity_state_t *ent;
-
- if (cl_paused->value)
- return;
-
- if (cls.state != ca_active)
- return;
-
- if (!cl.sound_prepped)
- return;
-
- for (i=0 ; i<cl.frame.num_entities ; i++)
- {
- num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
- ent = &cl_parse_entities[num];
- sounds[i] = ent->sound;
- }
-
- for (i=0 ; i<cl.frame.num_entities ; i++)
- {
- if (!sounds[i])
- continue;
-
- sfx = cl.sound_precache[sounds[i]];
- if (!sfx)
- continue; // bad sound effect
- sc = sfx->cache;
- if (!sc)
- continue;
-
- num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
- ent = &cl_parse_entities[num];
-
- // find the total contribution of all sounds of this type
- S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
- &left_total, &right_total);
- for (j=i+1 ; j<cl.frame.num_entities ; j++)
- {
- if (sounds[j] != sounds[i])
- continue;
- sounds[j] = 0; // don't check this again later
-
- num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1);
- ent = &cl_parse_entities[num];
-
- S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
- &left, &right);
- left_total += left;
- right_total += right;
- }
-
- if (left_total == 0 && right_total == 0)
- continue; // not audible
-
- // allocate a channel
- ch = S_PickChannel(0, 0);
- if (!ch)
- return;
-
- if (left_total > 255)
- left_total = 255;
- if (right_total > 255)
- right_total = 255;
- ch->leftvol = left_total;
- ch->rightvol = right_total;
- ch->autosound = true; // remove next frame
- ch->sfx = sfx;
- ch->pos = paintedtime % sc->length;
- ch->end = paintedtime + sc->length - ch->pos;
- }
-}
-
-//=============================================================================
-
-/*
-============
-S_RawSamples
-
-Cinematic streaming and voice over network
-============
-*/
-void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
-{
- int i;
- int src, dst;
- float scale;
-
- if (!sound_started)
- return;
-
- if (s_rawend < paintedtime)
- s_rawend = paintedtime;
- scale = (float)rate / dma.speed;
-
-//Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
- if (channels == 2 && width == 2)
- {
- if (scale == 1.0)
- { // optimized case
- for (i=0 ; i<samples ; i++)
- {
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- LittleShort(((short *)data)[i*2]) << 8;
- s_rawsamples[dst].right =
- LittleShort(((short *)data)[i*2+1]) << 8;
- }
- }
- else
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- LittleShort(((short *)data)[src*2]) << 8;
- s_rawsamples[dst].right =
- LittleShort(((short *)data)[src*2+1]) << 8;
- }
- }
- }
- else if (channels == 1 && width == 2)
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- LittleShort(((short *)data)[src]) << 8;
- s_rawsamples[dst].right =
- LittleShort(((short *)data)[src]) << 8;
- }
- }
- else if (channels == 2 && width == 1)
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- ((char *)data)[src*2] << 16;
- s_rawsamples[dst].right =
- ((char *)data)[src*2+1] << 16;
- }
- }
- else if (channels == 1 && width == 1)
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- (((byte *)data)[src]-128) << 16;
- s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
- }
- }
-}
-
-//=============================================================================
-
-/*
-============
-S_Update
-
-Called once each time through the main loop
-============
-*/
-void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
-{
- int i;
- int total;
- channel_t *ch;
-
- if (!sound_started)
- return;
-
- // if the laoding plaque is up, clear everything
- // out to make sure we aren't looping a dirty
- // dma buffer while loading
- if (cls.disable_screen)
- {
- S_ClearBuffer ();
- return;
- }
-
- // rebuild scale tables if volume is modified
- if (s_volume->modified)
- S_InitScaletable ();
-
- VectorCopy(origin, listener_origin);
- VectorCopy(forward, listener_forward);
- VectorCopy(right, listener_right);
- VectorCopy(up, listener_up);
-
- // update spatialization for dynamic sounds
- ch = channels;
- for (i=0 ; i<MAX_CHANNELS; i++, ch++)
- {
- if (!ch->sfx)
- continue;
- if (ch->autosound)
- { // autosounds are regenerated fresh each frame
- memset (ch, 0, sizeof(*ch));
- continue;
- }
- S_Spatialize(ch); // respatialize channel
- if (!ch->leftvol && !ch->rightvol)
- {
- memset (ch, 0, sizeof(*ch));
- continue;
- }
- }
-
- // add loopsounds
- S_AddLoopSounds ();
-
- //
- // debugging output
- //
- if (s_show->value)
- {
- total = 0;
- ch = channels;
- for (i=0 ; i<MAX_CHANNELS; i++, ch++)
- if (ch->sfx && (ch->leftvol || ch->rightvol) )
- {
- Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
- total++;
- }
-
- Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime);
- }
-
-// mix some sound
- S_Update_();
-}
-
-void GetSoundtime(void)
-{
- int samplepos;
- static int buffers;
- static int oldsamplepos;
- int fullsamples;
-
- fullsamples = dma.samples / dma.channels;
-
-// it is possible to miscount buffers if it has wrapped twice between
-// calls to S_Update. Oh well.
- samplepos = SNDDMA_GetDMAPos();
-
- if (samplepos < oldsamplepos)
- {
- buffers++; // buffer wrapped
-
- if (paintedtime > 0x40000000)
- { // time to chop things off to avoid 32 bit limits
- buffers = 0;
- paintedtime = fullsamples;
- S_StopAllSounds ();
- }
- }
- oldsamplepos = samplepos;
-
- soundtime = buffers*fullsamples + samplepos/dma.channels;
-}
-
-
-void S_Update_(void)
-{
- unsigned endtime;
- int samps;
-
- if (!sound_started)
- return;
-
- SNDDMA_BeginPainting ();
-
- if (!dma.buffer)
- return;
-
-// Updates DMA time
- GetSoundtime();
-
-// check to make sure that we haven't overshot
- if (paintedtime < soundtime)
- {
- Com_DPrintf ("S_Update_ : overflow\n");
- paintedtime = soundtime;
- }
-
-// mix ahead of current position
- endtime = soundtime + s_mixahead->value * dma.speed;
-//endtime = (soundtime + 4096) & ~4095;
-
- // mix to an even submission block size
- endtime = (endtime + dma.submission_chunk-1)
- & ~(dma.submission_chunk-1);
- samps = dma.samples >> (dma.channels-1);
- if (endtime - soundtime > samps)
- endtime = soundtime + samps;
-
- S_PaintChannels (endtime);
-
- SNDDMA_Submit ();
-}
-
-/*
-===============================================================================
-
-console functions
-
-===============================================================================
-*/
-
-void S_Play(void)
-{
- int i;
- char name[256];
- sfx_t *sfx;
-
- i = 1;
- while (i<Cmd_Argc())
- {
- if (!strrchr(Cmd_Argv(i), '.'))
- {
- strcpy(name, Cmd_Argv(i));
- strcat(name, ".wav");
- }
- else
- strcpy(name, Cmd_Argv(i));
- sfx = S_RegisterSound(name);
- S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
- i++;
- }
-}
-
-void S_SoundList(void)
-{
- int i;
- sfx_t *sfx;
- sfxcache_t *sc;
- int size, total;
-
- total = 0;
- for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
- {
- if (!sfx->registration_sequence)
- continue;
- sc = sfx->cache;
- if (sc)
- {
- size = sc->length*sc->width*(sc->stereo+1);
- total += size;
- if (sc->loopstart >= 0)
- Com_Printf ("L");
- else
- Com_Printf (" ");
- Com_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name);
- }
- else
- {
- if (sfx->name[0] == '*')
- Com_Printf(" placeholder : %s\n", sfx->name);
- else
- Com_Printf(" not loaded : %s\n", sfx->name);
- }
- }
- Com_Printf ("Total resident: %i\n", total);
-}
-
--- a/client/snd_loc.h
+++ /dev/null
@@ -1,144 +1,0 @@
-// snd_loc.h -- private sound functions
-
-// !!! if this is changed, the asm code must change !!!
-typedef struct
-{
- int left;
- int right;
-} portable_samplepair_t;
-
-typedef struct
-{
- int length;
- int loopstart;
- int speed; // not needed, because converted on load?
- int width;
- int stereo;
- byte data[1]; // variable sized
-} sfxcache_t;
-
-typedef struct sfx_s
-{
- char name[MAX_QPATH];
- int registration_sequence;
- sfxcache_t *cache;
- char *truename;
-} sfx_t;
-
-// a playsound_t will be generated by each call to S_StartSound,
-// when the mixer reaches playsound->begin, the playsound will
-// be assigned to a channel
-typedef struct playsound_s
-{
- struct playsound_s *prev, *next;
- sfx_t *sfx;
- float volume;
- float attenuation;
- int entnum;
- int entchannel;
- qboolean fixed_origin; // use origin field instead of entnum's origin
- vec3_t origin;
- unsigned begin; // begin on this sample
-} playsound_t;
-
-typedef struct
-{
- int channels;
- int samples; // mono samples in buffer
- int submission_chunk; // don't mix less than this #
- int samplepos; // in mono samples
- int samplebits;
- int speed;
- byte *buffer;
-} dma_t;
-
-// !!! if this is changed, the asm code must change !!!
-typedef struct
-{
- sfx_t *sfx; // sfx number
- int leftvol; // 0-255 volume
- int rightvol; // 0-255 volume
- int end; // end time in global paintsamples
- int pos; // sample position in sfx
- int looping; // where to loop, -1 = no looping OBSOLETE?
- int entnum; // to allow overriding a specific sound
- int entchannel; //
- vec3_t origin; // only use if fixed_origin is set
- vec_t dist_mult; // distance multiplier (attenuation/clipK)
- int master_vol; // 0-255 master volume
- qboolean fixed_origin; // use origin instead of fetching entnum's origin
- qboolean autosound; // from an entity->sound, cleared each frame
-} channel_t;
-
-typedef struct
-{
- int rate;
- int width;
- int channels;
- int loopstart;
- int samples;
- int dataofs; // chunk starts this many bytes from file start
-} wavinfo_t;
-
-
-/*
-====================================================================
-
- SYSTEM SPECIFIC FUNCTIONS
-
-====================================================================
-*/
-
-// initializes cycling through a DMA buffer and returns information on it
-qboolean SNDDMA_Init(void);
-
-// gets the current DMA position
-int SNDDMA_GetDMAPos(void);
-
-// shutdown the DMA xfer.
-void SNDDMA_Shutdown(void);
-
-void SNDDMA_BeginPainting (void);
-
-void SNDDMA_Submit(void);
-
-//====================================================================
-
-#define MAX_CHANNELS 32
-extern channel_t channels[MAX_CHANNELS];
-
-extern int paintedtime;
-extern int s_rawend;
-extern vec3_t listener_origin;
-extern vec3_t listener_forward;
-extern vec3_t listener_right;
-extern vec3_t listener_up;
-extern dma_t dma;
-extern playsound_t s_pendingplays;
-
-#define MAX_RAW_SAMPLES 8192
-extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
-
-extern cvar_t *s_volume;
-extern cvar_t *s_loadas8bit;
-extern cvar_t *s_khz;
-extern cvar_t *s_show;
-extern cvar_t *s_mixahead;
-extern cvar_t *s_testsound;
-extern cvar_t *s_primary;
-
-wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength);
-
-void S_InitScaletable (void);
-
-sfxcache_t *S_LoadSound (sfx_t *s);
-
-void S_IssuePlaysound (playsound_t *ps);
-
-void S_PaintChannels(int endtime);
-
-// picks a channel based on priorities, empty slots, number of channels
-channel_t *S_PickChannel(int entnum, int entchannel);
-
-// spatializes a channel
-void S_Spatialize(channel_t *ch);
--- a/client/snd_mem.c
+++ /dev/null
@@ -1,341 +1,0 @@
-// snd_mem.c: sound caching
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-int cache_full_cycle;
-
-byte *S_Alloc (int size);
-
-/*
-================
-ResampleSfx
-================
-*/
-void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
-{
- int outcount;
- int srcsample;
- float stepscale;
- int i;
- int sample, samplefrac, fracstep;
- sfxcache_t *sc;
-
- sc = sfx->cache;
- if (!sc)
- return;
-
- stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
-
- outcount = sc->length / stepscale;
- sc->length = outcount;
- if (sc->loopstart != -1)
- sc->loopstart = sc->loopstart / stepscale;
-
- sc->speed = dma.speed;
- if (s_loadas8bit->value)
- sc->width = 1;
- else
- sc->width = inwidth;
- sc->stereo = 0;
-
-// resample / decimate to the current source rate
-
- if (stepscale == 1 && inwidth == 1 && sc->width == 1)
- {
-// fast special case
- for (i=0 ; i<outcount ; i++)
- ((signed char *)sc->data)[i]
- = (int)( (unsigned char)(data[i]) - 128);
- }
- else
- {
-// general case
- samplefrac = 0;
- fracstep = stepscale*256;
- for (i=0 ; i<outcount ; i++)
- {
- srcsample = samplefrac >> 8;
- samplefrac += fracstep;
- if (inwidth == 2)
- sample = LittleShort ( ((short *)data)[srcsample] );
- else
- sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
- if (sc->width == 2)
- ((short *)sc->data)[i] = sample;
- else
- ((signed char *)sc->data)[i] = sample >> 8;
- }
- }
-}
-
-//=============================================================================
-
-/*
-==============
-S_LoadSound
-==============
-*/
-sfxcache_t *S_LoadSound (sfx_t *s)
-{
- char namebuffer[MAX_QPATH];
- byte *data;
- wavinfo_t info;
- int len;
- float stepscale;
- sfxcache_t *sc;
- int size;
- char *name;
-
- if (s->name[0] == '*')
- return NULL;
-
-// see if still in memory
- sc = s->cache;
- if (sc)
- return sc;
-
-//Com_Printf ("S_LoadSound: %x\n", (int)stackbuf);
-// load it in
- if (s->truename)
- name = s->truename;
- else
- name = s->name;
-
- if (name[0] == '#')
- strcpy(namebuffer, &name[1]);
- else
- Com_sprintf (namebuffer, sizeof(namebuffer), "sound/%s", name);
-
-// Com_Printf ("loading %s\n",namebuffer);
-
- size = FS_LoadFile (namebuffer, (void **)&data);
-
- if (!data)
- {
- Com_DPrintf ("Couldn't load %s\n", namebuffer);
- return NULL;
- }
-
- info = GetWavinfo (s->name, data, size);
- if (info.channels != 1)
- {
- Com_Printf ("%s is a stereo sample\n",s->name);
- FS_FreeFile (data);
- return NULL;
- }
-
- stepscale = (float)info.rate / dma.speed;
- len = info.samples / stepscale;
-
- len = len * info.width * info.channels;
-
- sc = s->cache = Z_Malloc (len + sizeof(sfxcache_t));
- if (!sc)
- {
- FS_FreeFile (data);
- return NULL;
- }
-
- sc->length = info.samples;
- sc->loopstart = info.loopstart;
- sc->speed = info.rate;
- sc->width = info.width;
- sc->stereo = info.channels;
-
- ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
-
- FS_FreeFile (data);
-
- return sc;
-}
-
-
-
-/*
-===============================================================================
-
-WAV loading
-
-===============================================================================
-*/
-
-
-byte *data_p;
-byte *iff_end;
-byte *last_chunk;
-byte *iff_data;
-int iff_chunk_len;
-
-
-short GetLittleShort(void)
-{
- short val;
- val = *data_p;
- val = val + (*(data_p+1)<<8);
- data_p += 2;
- return val;
-}
-
-int GetLittleLong(void)
-{
- int val;
- val = *data_p;
- val = val + (*(data_p+1)<<8);
- val = val + (*(data_p+2)<<16);
- val = val + (*(data_p+3)<<24);
- data_p += 4;
- return val;
-}
-
-void FindNextChunk(char *name)
-{
- while (1)
- {
- data_p=last_chunk;
-
- if (data_p >= iff_end)
- { // didn't find the chunk
- data_p = NULL;
- return;
- }
-
- data_p += 4;
- iff_chunk_len = GetLittleLong();
- if (iff_chunk_len < 0)
- {
- data_p = NULL;
- return;
- }
-// if (iff_chunk_len > 1024*1024)
-// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
- data_p -= 8;
- last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
- if (!strncmp((char *)data_p, name, 4))
- return;
- }
-}
-
-void FindChunk(char *name)
-{
- last_chunk = iff_data;
- FindNextChunk (name);
-}
-
-
-void DumpChunks(void)
-{
- char str[5];
-
- str[4] = 0;
- data_p=iff_data;
- do
- {
- memcpy (str, data_p, 4);
- data_p += 4;
- iff_chunk_len = GetLittleLong();
- Com_Printf ("0x%x : %s (%p)\n", (uintptr)(data_p - 4), str, iff_chunk_len);
- data_p += (iff_chunk_len + 1) & ~1;
- } while (data_p < iff_end);
-}
-
-/*
-============
-GetWavinfo
-============
-*/
-wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
-{
- wavinfo_t info;
- int i;
- int format;
- int samples;
-
- memset (&info, 0, sizeof(info));
-
- if (!wav)
- return info;
-
- iff_data = wav;
- iff_end = wav + wavlength;
-
-// find "RIFF" chunk
- FindChunk("RIFF");
- if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4)))
- {
- Com_Printf("Missing RIFF/WAVE chunks\n");
- return info;
- }
-
-// get "fmt " chunk
- iff_data = data_p + 12;
-// DumpChunks ();
-
- FindChunk("fmt ");
- if (!data_p)
- {
- Com_Printf("Missing fmt chunk\n");
- return info;
- }
- data_p += 8;
- format = GetLittleShort();
- if (format != 1)
- {
- Com_Printf("Microsoft PCM format only\n");
- return info;
- }
-
- info.channels = GetLittleShort();
- info.rate = GetLittleLong();
- data_p += 4+2;
- info.width = GetLittleShort() / 8;
-
-// get cue chunk
- FindChunk("cue ");
- if (data_p)
- {
- data_p += 32;
- info.loopstart = GetLittleLong();
-// Com_Printf("loopstart=%d\n", sfx->loopstart);
-
- // if the next chunk is a LIST chunk, look for a cue length marker
- FindNextChunk ("LIST");
- if (data_p)
- {
- if (!strncmp ((char *)data_p + 28, "mark", 4))
- { // this is not a proper parse, but it works with cooledit...
- data_p += 24;
- i = GetLittleLong (); // samples in loop
- info.samples = info.loopstart + i;
-// Com_Printf("looped length: %i\n", i);
- }
- }
- }
- else
- info.loopstart = -1;
-
-// find data chunk
- FindChunk("data");
- if (!data_p)
- {
- Com_Printf("Missing data chunk\n");
- return info;
- }
-
- data_p += 4;
- samples = GetLittleLong () / info.width;
-
- if (info.samples)
- {
- if (samples < info.samples)
- Com_Error (ERR_DROP, "Sound %s has a bad loop length", name);
- }
- else
- info.samples = samples;
-
- info.dataofs = data_p - wav;
-
- return info;
-}
-
--- a/client/snd_mix.c
+++ /dev/null
@@ -1,349 +1,0 @@
-// snd_mix.c -- portable code to mix sounds for snd_dma.c
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-#define PAINTBUFFER_SIZE 2048
-portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
-int snd_scaletable[32][256];
-int *snd_p, snd_linear_count, snd_vol;
-short *snd_out;
-
-
-void S_WriteLinearBlastStereo16 (void)
-{
- int i;
- int val;
-
- for (i=0 ; i<snd_linear_count ; i+=2)
- {
- val = snd_p[i]>>8;
- if (val > 0x7fff)
- snd_out[i] = 0x7fff;
- else if (val < (short)0x8000)
- snd_out[i] = (short)0x8000;
- else
- snd_out[i] = val;
-
- val = snd_p[i+1]>>8;
- if (val > 0x7fff)
- snd_out[i+1] = 0x7fff;
- else if (val < (short)0x8000)
- snd_out[i+1] = (short)0x8000;
- else
- snd_out[i+1] = val;
- }
-}
-
-void S_TransferStereo16 (unsigned long *pbuf, int endtime)
-{
- int lpos;
- int lpaintedtime;
-
- snd_p = (int *) paintbuffer;
- lpaintedtime = paintedtime;
-
- while (lpaintedtime < endtime)
- {
- // handle recirculating buffer issues
- lpos = lpaintedtime & ((dma.samples>>1)-1);
-
- snd_out = (short *) pbuf + (lpos<<1);
-
- snd_linear_count = (dma.samples>>1) - lpos;
- if (lpaintedtime + snd_linear_count > endtime)
- snd_linear_count = endtime - lpaintedtime;
-
- snd_linear_count <<= 1;
-
- // write a linear blast of samples
- S_WriteLinearBlastStereo16 ();
-
- snd_p += snd_linear_count;
- lpaintedtime += (snd_linear_count>>1);
- }
-}
-
-/*
-===================
-S_TransferPaintBuffer
-
-===================
-*/
-void S_TransferPaintBuffer(int endtime)
-{
- int out_idx;
- int count;
- int out_mask;
- int *p;
- int step;
- int val;
- unsigned long *pbuf;
-
- pbuf = (unsigned long *)dma.buffer;
-
- if (s_testsound->value)
- {
- int i;
- int count;
-
- // write a fixed sine wave
- count = (endtime - paintedtime);
- for (i=0 ; i<count ; i++)
- paintbuffer[i].left = paintbuffer[i].right = sin((paintedtime+i)*0.1)*20000*256;
- }
-
-
- if (dma.samplebits == 16 && dma.channels == 2)
- { // optimized case
- S_TransferStereo16 (pbuf, endtime);
- }
- else
- { // general case
- p = (int *) paintbuffer;
- count = (endtime - paintedtime) * dma.channels;
- out_mask = dma.samples - 1;
- out_idx = paintedtime * dma.channels & out_mask;
- step = 3 - dma.channels;
-
- if (dma.samplebits == 16)
- {
- short *out = (short *) pbuf;
- while (count--)
- {
- val = *p >> 8;
- p+= step;
- if (val > 0x7fff)
- val = 0x7fff;
- else if (val < (short)0x8000)
- val = (short)0x8000;
- out[out_idx] = val;
- out_idx = (out_idx + 1) & out_mask;
- }
- }
- else if (dma.samplebits == 8)
- {
- unsigned char *out = (unsigned char *) pbuf;
- while (count--)
- {
- val = *p >> 8;
- p+= step;
- if (val > 0x7fff)
- val = 0x7fff;
- else if (val < (short)0x8000)
- val = (short)0x8000;
- out[out_idx] = (val>>8) + 128;
- out_idx = (out_idx + 1) & out_mask;
- }
- }
- }
-}
-
-
-/*
-===============================================================================
-
-CHANNEL MIXING
-
-===============================================================================
-*/
-
-void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
-void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
-
-void S_PaintChannels(int endtime)
-{
- int i;
- int end;
- channel_t *ch;
- sfxcache_t *sc;
- int ltime, count;
- playsound_t *ps;
-
- snd_vol = s_volume->value*256;
-
-//Com_Printf ("%i to %i\n", paintedtime, endtime);
- while (paintedtime < endtime)
- {
- // if paintbuffer is smaller than DMA buffer
- end = endtime;
- if (endtime - paintedtime > PAINTBUFFER_SIZE)
- end = paintedtime + PAINTBUFFER_SIZE;
-
- // start any playsounds
- while (1)
- {
- ps = s_pendingplays.next;
- if (ps == &s_pendingplays)
- break; // no more pending sounds
- if (ps->begin <= paintedtime)
- {
- S_IssuePlaysound (ps);
- continue;
- }
-
- if (ps->begin < end)
- end = ps->begin; // stop here
- break;
- }
-
- // clear the paint buffer
- if (s_rawend < paintedtime)
- {
-// Com_Printf ("clear\n");
- memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
- }
- else
- { // copy from the streaming sound source
- int s;
- int stop;
-
- stop = (end < s_rawend) ? end : s_rawend;
-
- for (i=paintedtime ; i<stop ; i++)
- {
- s = i&(MAX_RAW_SAMPLES-1);
- paintbuffer[i-paintedtime] = s_rawsamples[s];
- }
-// if (i != end)
-// Com_Printf ("partial stream\n");
-// else
-// Com_Printf ("full stream\n");
- for ( ; i<end ; i++)
- {
- paintbuffer[i-paintedtime].left =
- paintbuffer[i-paintedtime].right = 0;
- }
- }
-
-
- // paint in the channels.
- ch = channels;
- for (i=0; i<MAX_CHANNELS ; i++, ch++)
- {
- ltime = paintedtime;
-
- while (ltime < end)
- {
- if (!ch->sfx || (!ch->leftvol && !ch->rightvol) )
- break;
-
- // max painting is to the end of the buffer
- count = end - ltime;
-
- // might be stopped by running out of data
- if (ch->end - ltime < count)
- count = ch->end - ltime;
-
- sc = S_LoadSound (ch->sfx);
- if (!sc)
- break;
-
- if (count > 0 && ch->sfx)
- {
- if (sc->width == 1)// FIXME; 8 bit asm is wrong now
- S_PaintChannelFrom8(ch, sc, count, ltime - paintedtime);
- else
- S_PaintChannelFrom16(ch, sc, count, ltime - paintedtime);
-
- ltime += count;
- }
-
- // if at end of loop, restart
- if (ltime >= ch->end)
- {
- if (ch->autosound)
- { // autolooping sounds always go back to start
- ch->pos = 0;
- ch->end = ltime + sc->length;
- }
- else if (sc->loopstart >= 0)
- {
- ch->pos = sc->loopstart;
- ch->end = ltime + sc->length - ch->pos;
- }
- else
- { // channel just stopped
- ch->sfx = NULL;
- }
- }
- }
-
- }
-
- // transfer out according to DMA format
- S_TransferPaintBuffer(end);
- paintedtime = end;
- }
-}
-
-void S_InitScaletable (void)
-{
- int i, j;
- int scale;
-
- s_volume->modified = false;
- for (i=0 ; i<32 ; i++)
- {
- scale = i * 8 * 256 * s_volume->value;
- for (j=0 ; j<256 ; j++)
- snd_scaletable[i][j] = ((signed char)j) * scale;
- }
-}
-
-void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
-{
- int data;
- int *lscale, *rscale;
- unsigned char *sfx;
- int i;
- portable_samplepair_t *samp;
-
- if (ch->leftvol > 255)
- ch->leftvol = 255;
- if (ch->rightvol > 255)
- ch->rightvol = 255;
-
- lscale = snd_scaletable[ ch->leftvol >> 11];
- rscale = snd_scaletable[ ch->rightvol >> 11];
- sfx = (uchar *)sc->data + ch->pos;
-
- samp = &paintbuffer[offset];
-
- for (i=0 ; i<count ; i++, samp++)
- {
- data = sfx[i];
- samp->left += lscale[data];
- samp->right += rscale[data];
- }
-
- ch->pos += count;
-}
-
-void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count, int offset)
-{
- int data;
- int left, right;
- int leftvol, rightvol;
- signed short *sfx;
- int i;
- portable_samplepair_t *samp;
-
- leftvol = ch->leftvol*snd_vol;
- rightvol = ch->rightvol*snd_vol;
- sfx = (signed short *)sc->data + ch->pos;
-
- samp = &paintbuffer[offset];
- for (i=0 ; i<count ; i++, samp++)
- {
- data = sfx[i];
- left = (data * leftvol)>>8;
- right = (data * rightvol)>>8;
- samp->left += left;
- samp->right += right;
- }
-
- ch->pos += count;
-}
--- a/client/sound.h
+++ /dev/null
@@ -1,21 +1,0 @@
-void S_Init (void);
-void S_Shutdown (void);
-
-// if origin is NULL, the sound will be dynamically sourced from the entity
-void S_StartSound (vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs);
-void S_StartLocalSound (char *s);
-
-void S_RawSamples (int samples, int rate, int width, int channels, byte *data);
-
-void S_StopAllSounds(void);
-void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up);
-
-void S_Activate (qboolean active);
-
-void S_BeginRegistration (void);
-sfx_t *S_RegisterSound (char *sample);
-void S_EndRegistration (void);
-
-// the sound code makes callbacks to the client for entitiy position
-// information, so entities can be dynamically re-spatialized
-void CL_GetEntitySoundOrigin (int ent, vec3_t org);
--- a/client/vid.h
+++ /dev/null
@@ -1,33 +1,0 @@
-// vid.h -- video driver defs
-
-typedef uchar pixel_t;
-
-typedef struct vrect_t vrect_t;
-typedef struct viddef_t viddef_t;
-
-struct vrect_t
-{
- int x, y, width, height;
- vrect_t *pnext;
-};
-
-struct viddef_t
-{
- int width;
- int height;
- pixel_t *buffer; // invisible buffer
- pixel_t *colormap; // 256 * VID_GRADES size
- pixel_t *alphamap; // 256 * 256 translucency map
- int rowbytes; // may be > width if displayed in a window
- // can be negative for stupid dibs
-};
-extern viddef_t vid;
-
-// Video module initialisation etc
-void VID_Init (void);
-void VID_Shutdown (void);
-void VID_CheckChanges (void);
-
-void VID_MenuInit( void );
-void VID_MenuDraw( void );
-const char *VID_MenuKey( int );
--- /dev/null
+++ b/cmd.c
@@ -1,0 +1,633 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/* Command text buffering and command execution
+ *
+ * Any number of commands can be added in a frame, from several different
+ * sources. Most commands come from either keybindings or console line input,
+ * but remote servers can also send across commands and entire text files can
+ * be execed. The '+' command line options are also added to the command buffer.
+ * The game starts with a Cbuf_AddText("exec quake.rc\n"); Cbuf_Execute();.
+ * Command execution takes a null terminated string, breaks it into tokens,
+ * then searches for a command or variable that matches the first token. */
+
+typedef struct cmdalias_t cmdalias_t;
+typedef struct cmd_function_t cmd_function_t;
+
+enum{
+ MAX_ALIAS_NAME = 32,
+ ALIAS_LOOP_COUNT = 16
+};
+struct cmdalias_t{
+ cmdalias_t *next;
+ char name[MAX_ALIAS_NAME];
+ char *value;
+};
+cmdalias_t *cmd_alias;
+int alias_count; // for detecting runaway loops
+
+qboolean cmd_wait;
+
+sizebuf_t cmd_text;
+uchar cmd_text_buf[8192];
+uchar defer_text_buf[8192];
+
+static int cmd_argc;
+static char *cmd_argv[MAX_STRING_TOKENS];
+static char *cmd_null_string = "";
+static char cmd_args[MAX_STRING_CHARS];
+
+struct cmd_function_t{
+ cmd_function_t *next;
+ char *name;
+ xcommand_t function;
+};
+static cmd_function_t *cmd_functions; // possible commands to execute
+
+
+/* Causes execution of the remainder of the command buffer to be delayed until
+ * next frame. This allows commands like:
+ * bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2" */
+void
+Cmd_Wait_f(void)
+{
+ cmd_wait = true;
+}
+
+/* allocates an initial text buffer that will grow as needed */
+void
+Cbuf_Init(void)
+{
+ SZ_Init(&cmd_text, cmd_text_buf, sizeof cmd_text_buf);
+}
+
+/* adds command text at the end of the buffer */
+void
+Cbuf_AddText(char *text)
+{
+ int l;
+
+ l = strlen(text);
+
+ if(cmd_text.cursize + l >= cmd_text.maxsize){
+ Com_Printf("Cbuf_AddText: overflow\n");
+ return;
+ }
+ SZ_Write(&cmd_text, text, l);
+}
+
+// FIXME: actually change the command buffer to do less copying
+/* Adds command text immediately after the current command and '\n' to the text */
+void
+Cbuf_InsertText(char *text)
+{
+ char *temp = nil;
+ int templen;
+
+ /* copy off any commands still remaining in the exec buffer */
+ templen = cmd_text.cursize;
+ if(templen){
+ temp = Z_Malloc(templen);
+ memcpy(temp, cmd_text.data, templen);
+ SZ_Clear(&cmd_text);
+ }
+
+ Cbuf_AddText(text);
+ if(templen){
+ SZ_Write(&cmd_text, temp, templen);
+ Z_Free(temp);
+ }
+}
+
+void
+Cbuf_CopyToDefer(void)
+{
+ memcpy(defer_text_buf, cmd_text_buf, cmd_text.cursize);
+ defer_text_buf[cmd_text.cursize] = 0;
+ cmd_text.cursize = 0;
+}
+
+void
+Cbuf_InsertFromDefer(void)
+{
+ Cbuf_InsertText((char *)defer_text_buf);
+ defer_text_buf[0] = 0;
+}
+
+void
+Cbuf_ExecuteText(int exec_when, char *text)
+{
+ switch(exec_when){
+ case EXEC_NOW:
+ Cmd_ExecuteString(text);
+ break;
+ case EXEC_INSERT:
+ Cbuf_InsertText(text);
+ break;
+ case EXEC_APPEND:
+ Cbuf_AddText(text);
+ break;
+ default:
+ Com_Error(ERR_FATAL, "Cbuf_ExecuteText: bad exec_when");
+ }
+}
+
+/* normally called once per frame, but may be explicitly invoked.
+ * do not call inside a command function! */
+void
+Cbuf_Execute(void)
+{
+ int i, quotes;
+ char *text, line[1024];
+
+ alias_count = 0; // don't allow infinite alias loops
+
+ while(cmd_text.cursize){
+ text = (char *)cmd_text.data;
+
+ /* find a \n or ; line break */
+ quotes = 0;
+ for(i=0; i<cmd_text.cursize; i++){
+ if(text[i] == '"')
+ quotes++;
+ if(~quotes & 1 && text[i] == ';')
+ break; // don't break if inside a quoted string
+ if(text[i] == '\n')
+ break;
+ }
+ memcpy(line, text, i);
+ line[i] = 0;
+
+ /* delete the text from the command buffer and move remaining
+ * commands down. this is necessary because commands (exec,
+ * alias) can insert data at the beginning of the text buffer */
+ if(i == cmd_text.cursize)
+ cmd_text.cursize = 0;
+ else{
+ i++;
+ cmd_text.cursize -= i;
+ memmove(text, text+i, cmd_text.cursize);
+ }
+
+ Cmd_ExecuteString(line);
+
+ /* skip out while text still remains in buffer, leaving it for
+ * next frame */
+ if(cmd_wait){
+ cmd_wait = false;
+ break;
+ }
+ }
+}
+
+/* Adds command line parameters as script statements. Commands lead with a '+',
+ * and continue until another '+'. Set commands are added early, so they are
+ * guaranteed to be set before the client and server initialize for the first
+ * time. Other commands are added late, after all initialization is complete. */
+void
+Cbuf_AddEarlyCommands(qboolean clear)
+{
+ int i;
+ char *s;
+
+ for(i=0; i<COM_Argc(); i++){
+ s = COM_Argv(i);
+ if(strcmp(s, "+set"))
+ continue;
+ Cbuf_AddText(va("set %s %s\n", COM_Argv(i+1), COM_Argv(i+2)));
+ if(clear){
+ COM_ClearArgv(i);
+ COM_ClearArgv(i+1);
+ COM_ClearArgv(i+2);
+ }
+ i += 2;
+ }
+}
+
+/* Adds command line parameters as script statements. Commands lead with a '+'
+ * and continue until another '+' or '-'. Returns true if any late commands
+ * were added, which will keep the demoloop from immediately starting. */
+qboolean
+Cbuf_AddLateCommands(void)
+{
+ int i, j, s, argc;
+ char *text, *build, c;
+ qboolean ret;
+
+ /* build the combined string to parse from */
+ s = 0;
+ argc = COM_Argc();
+ for(i=1; i<argc; i++)
+ s += strlen(COM_Argv(i)) + 1;
+ if(!s)
+ return false;
+
+ text = Z_Malloc(s+1);
+ text[0] = 0;
+ for(i=1; i<argc; i++){
+ strcat(text, COM_Argv(i));
+ if(i != argc-1)
+ strcat(text, " ");
+ }
+
+ /* pull out the commands */
+ build = Z_Malloc(s+1);
+ build[0] = 0;
+ for(i=0; i<s-1; i++)
+ if(text[i] == '+'){
+ i++;
+ for(j=i; text[j] != '+' && text[j] != '-' && text[j] != 0 ; j++)
+ ;
+ c = text[j];
+ text[j] = 0;
+ strcat(build, text+i);
+ strcat(build, "\n");
+ text[j] = c;
+ i = j-1;
+ }
+
+ ret = build[0] != 0;
+ if(ret)
+ Cbuf_AddText(build);
+ Z_Free(text);
+ Z_Free(build);
+ return ret;
+}
+
+void
+Cmd_Exec_f(void)
+{
+ char *f, *f2;
+ int len;
+
+ if(Cmd_Argc() != 2){
+ Com_Printf("exec <filename> : execute a script file\n");
+ return;
+ }
+
+ len = FS_LoadFile(Cmd_Argv(1), (void **)&f);
+ if(!f){
+ Com_Printf("couldn't exec %s\n", Cmd_Argv(1));
+ return;
+ }
+ Com_Printf("execing %s\n", Cmd_Argv(1));
+
+ /* the file doesn't have a trailing 0, so we need to copy it off */
+ f2 = Z_Malloc(len+1);
+ memcpy(f2, f, len);
+ f2[len] = 0;
+ Cbuf_InsertText(f2);
+ Z_Free(f2);
+ FS_FreeFile(f);
+}
+
+/* just prints the rest of the line to the console */
+void
+Cmd_Echo_f(void)
+{
+ int i;
+
+ for(i=1; i<Cmd_Argc(); i++)
+ Com_Printf("%s ", Cmd_Argv(i));
+ Com_Printf("\n");
+}
+
+/* Creates a new command that executes a command string (possibly ; seperated) */
+void
+Cmd_Alias_f(void)
+{
+ int i, c;
+ char cmd[1024], *s;
+ cmdalias_t *p;
+
+ if(Cmd_Argc() == 1){
+ Com_Printf("Current alias commands:\n");
+ for(p = cmd_alias; p != nil; p = p->next)
+ Com_Printf("%s : %s\n", p->name, p->value);
+ return;
+ }
+
+ s = Cmd_Argv(1);
+ if(strlen(s) >= MAX_ALIAS_NAME){
+ Com_Printf("Alias name is too long\n");
+ return;
+ }
+
+ /* if the alias already exists, reuse it */
+ for(p = cmd_alias; p != nil; p = p->next)
+ if(!strcmp(s, p->name)){
+ Z_Free(p->value);
+ break;
+ }
+
+ if(p == nil){
+ p = Z_Malloc(sizeof *p);
+ p->next = cmd_alias;
+ cmd_alias = p;
+ }
+ strcpy(p->name, s);
+
+ /* copy the rest of the command line */
+ cmd[0] = 0; // start out with a null string
+ c = Cmd_Argc();
+ for(i=2; i<c; i++){
+ strcat(cmd, Cmd_Argv(i));
+ if(i != c-1)
+ strcat(cmd, " ");
+ }
+ strcat(cmd, "\n");
+ p->value = CopyString(cmd);
+}
+
+int
+Cmd_Argc(void)
+{
+ return cmd_argc;
+}
+
+char *
+Cmd_Argv(int arg)
+{
+ if((unsigned)arg >= cmd_argc)
+ return cmd_null_string;
+ return cmd_argv[arg];
+}
+
+/* returns a single string containing argv(1) to argv(argc()-1) */
+char *
+Cmd_Args(void)
+{
+ return cmd_args;
+}
+
+char *
+Cmd_MacroExpandString(char *text)
+{
+ int i, j, count, len;
+ qboolean inquote;
+ char *scan, *token, *start;
+ char temporary[MAX_STRING_CHARS];
+ static char expanded[MAX_STRING_CHARS];
+
+ inquote = false;
+ scan = text;
+ len = strlen (scan);
+ if(len >= MAX_STRING_CHARS){
+ Com_Printf("Line exceeded %d chars, discarded.\n", MAX_STRING_CHARS);
+ return nil;
+ }
+
+ count = 0;
+ for(i=0; i<len ; i++){
+ if(scan[i] == '"')
+ inquote ^= 1;
+ if(inquote)
+ continue; // don't expand inside quotes
+ if(scan[i] != '$')
+ continue;
+
+ /* scan out the complete macro */
+ start = scan+i+1;
+ token = COM_Parse(&start);
+ if(!start)
+ continue;
+
+ token = Cvar_VariableString(token);
+ j = strlen(token);
+ len += j;
+ if(len >= MAX_STRING_CHARS){
+ Com_Printf("Expanded line exceeded %d chars, discarded.\n", MAX_STRING_CHARS);
+ return nil;
+ }
+
+ strncpy(temporary, scan, i);
+ strcpy(temporary+i, token);
+ strcpy(temporary+i+j, start);
+ strcpy(expanded, temporary);
+ scan = expanded;
+ i--;
+
+ if(++count == 100){
+ Com_Printf("Macro expansion loop, discarded.\n");
+ return nil;
+ }
+ }
+
+ if(inquote){
+ Com_Printf("Line has unmatched quote, discarded.\n");
+ return nil;
+ }
+ return scan;
+}
+
+/* Parses the given string into command line tokens. $Cvars will be expanded
+ * unless they are in a quoted token */
+void
+Cmd_TokenizeString(char *text, qboolean macroExpand)
+{
+ int i, l;
+ char *com_token;
+
+ /* clear the args from the last string */
+ for(i=0; i<cmd_argc; i++)
+ Z_Free(cmd_argv[i]);
+ cmd_argc = 0;
+ cmd_args[0] = 0;
+
+ /* macro expand the text */
+ if(macroExpand)
+ text = Cmd_MacroExpandString(text);
+ if(text == nil)
+ return;
+
+ for(;;){
+ while(*text && *text <= ' ' && *text != '\n')
+ text++;
+
+ /* a newline separates commands in the buffer */
+ if(*text == '\n'){
+ text++;
+ break;
+ }
+
+ if(!*text)
+ return;
+
+ // set cmd_args to everything after the first arg
+ if(cmd_argc == 1){
+ strcpy(cmd_args, text);
+ /* strip off any trailing whitespace */
+ for(l = strlen(cmd_args) - 1; l >= 0 ; l--)
+ if(cmd_args[l] <= ' ')
+ cmd_args[l] = 0;
+ else
+ break;
+ }
+
+ com_token = COM_Parse(&text);
+ if(text == nil)
+ return;
+
+ if(cmd_argc < MAX_STRING_TOKENS){
+ cmd_argv[cmd_argc] = Z_Malloc(strlen(com_token)+1);
+ strcpy(cmd_argv[cmd_argc], com_token);
+ cmd_argc++;
+ }
+ }
+}
+
+/* called by the init functions of other parts of the program to register
+ * commands and functions to call for them. rhe cmd_name is referenced later,
+ * so it should not be in temp memory if function is nil, the command will be
+ * forwarded to the server as a clc_stringcmd instead of executed locally */
+void
+Cmd_AddCommand(char *name, xcommand_t function)
+{
+ cmd_function_t *p;
+
+ /* fail if the command is a variable name */
+ if(Cvar_VariableString(name)[0]){
+ Com_Printf("Cmd_AddCommand: %s already defined as a var\n", name);
+ return;
+ }
+
+ /* fail if the command already exists */
+ for(p = cmd_functions; p != nil; p = p->next)
+ if(!strcmp(name, p->name)){
+ Com_Printf("Cmd_AddCommand: %s already defined\n", name);
+ return;
+ }
+
+ p = Z_Malloc(sizeof *p);
+ p->name = name;
+ p->function = function;
+ p->next = cmd_functions;
+ cmd_functions = p;
+}
+
+void
+Cmd_RemoveCommand(char *name)
+{
+ cmd_function_t *p, **back;
+
+ back = &cmd_functions;
+ for(;;){
+ p = *back;
+ if(p == nil){
+ Com_Printf("Cmd_RemoveCommand: %s not added\n", name);
+ return;
+ }
+ if(!strcmp(name, p->name)){
+ *back = p->next;
+ Z_Free(p);
+ return;
+ }
+ back = &p->next;
+ }
+}
+
+/* used by the cvar code to check for cvar / command name overlap */
+qboolean
+Cmd_Exists(char *name)
+{
+ cmd_function_t *p;
+
+ for(p = cmd_functions; p != nil; p = p->next)
+ if(!strcmp(name, p->name))
+ return true;
+ return false;
+}
+
+/* attempts to match a partial command for automatic command line completion */
+char *
+Cmd_CompleteCommand(char *partial)
+{
+ cmd_function_t *p;
+ int len;
+ cmdalias_t *a;
+
+ len = strlen(partial);
+ if(!len)
+ return nil;
+
+ /* check for exact match */
+ for(p = cmd_functions; p != nil; p = p->next)
+ if(!strcmp(partial, p->name))
+ return p->name;
+ for(a = cmd_alias; a != nil; a = a->next)
+ if(!strcmp(partial, a->name))
+ return a->name;
+
+ /* check for partial match */
+ for(p = cmd_functions; p != nil; p = p->next)
+ if(!strncmp(partial, p->name, len))
+ return p->name;
+ for(a = cmd_alias; a != nil; a = a->next)
+ if(!strncmp(partial, a->name, len))
+ return a->name;
+ return nil;
+}
+
+// FIXME: lookupnoadd the token to speed search?
+/* Parses a single line of text into arguments and tries to execute it as if it
+ * was typed at the console */
+void
+Cmd_ExecuteString(char *text)
+{
+ cmd_function_t *p;
+ cmdalias_t *a;
+
+ Cmd_TokenizeString(text, true);
+ if(!Cmd_Argc())
+ return; // no tokens
+
+ /* check functions */
+ for(p = cmd_functions; p != nil; p = p->next)
+ if(!cistrcmp(cmd_argv[0], p->name)){
+ if(!p->function) // forward to server command
+ Cmd_ExecuteString(va("cmd %s", text));
+ else
+ p->function();
+ return;
+ }
+ /* check alias */
+ for(a = cmd_alias; a != nil; a = a->next)
+ if(!cistrcmp(cmd_argv[0], a->name)){
+ if(++alias_count == ALIAS_LOOP_COUNT){
+ Com_Printf("ALIAS_LOOP_COUNT\n");
+ return;
+ }
+ Cbuf_InsertText(a->value);
+ return;
+ }
+ /* check cvars */
+ if(Cvar_Command())
+ return;
+
+ /* send it as a server command if we are connected */
+ Cmd_ForwardToServer();
+}
+
+void
+Cmd_List_f(void)
+{
+ cmd_function_t *p;
+ int i;
+
+ for(p = cmd_functions, i = 0; p != nil; p = p->next, i++)
+ Com_Printf("%s\n", p->name);
+ Com_Printf("%d commands\n", i);
+}
+
+void
+Cmd_Init(void)
+{
+ Cmd_AddCommand("cmdlist", Cmd_List_f);
+ Cmd_AddCommand("exec", Cmd_Exec_f);
+ Cmd_AddCommand("echo", Cmd_Echo_f);
+ Cmd_AddCommand("alias", Cmd_Alias_f);
+ Cmd_AddCommand("wait", Cmd_Wait_f);
+}
--- /dev/null
+++ b/cmodel.c
@@ -1,0 +1,1750 @@
+// cmodel.c -- model loading
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef struct
+{
+ cplane_t *plane;
+ int children[2]; // negative numbers are leafs
+} cnode_t;
+
+typedef struct
+{
+ cplane_t *plane;
+ mapsurface_t *surface;
+} cbrushside_t;
+
+typedef struct
+{
+ int contents;
+ int cluster;
+ int area;
+ unsigned short firstleafbrush;
+ unsigned short numleafbrushes;
+} cleaf_t;
+
+typedef struct
+{
+ int contents;
+ int numsides;
+ int firstbrushside;
+ int checkcount; // to avoid repeated testings
+} cbrush_t;
+
+typedef struct
+{
+ int numareaportals;
+ int firstareaportal;
+ int floodnum; // if two areas have equal floodnums, they are connected
+ int floodvalid;
+} carea_t;
+
+int checkcount;
+
+char map_name[MAX_QPATH];
+
+int numbrushsides;
+cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES];
+
+int numtexinfo;
+mapsurface_t map_surfaces[MAX_MAP_TEXINFO];
+
+int numplanes;
+cplane_t map_planes[MAX_MAP_PLANES+6]; // extra for box hull
+
+int numnodes;
+cnode_t map_nodes[MAX_MAP_NODES+6]; // extra for box hull
+
+int numleafs = 1; // allow leaf funcs to be called without a map
+cleaf_t map_leafs[MAX_MAP_LEAFS];
+int emptyleaf, solidleaf;
+
+int numleafbrushes;
+unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES];
+
+int numcmodels;
+cmodel_t map_cmodels[MAX_MAP_MODELS];
+
+int numbrushes;
+cbrush_t map_brushes[MAX_MAP_BRUSHES];
+
+int numvisibility;
+byte map_visibility[MAX_MAP_VISIBILITY];
+dvis_t *map_vis = (dvis_t *)map_visibility;
+
+int numentitychars;
+char map_entitystring[MAX_MAP_ENTSTRING];
+
+int numareas = 1;
+carea_t map_areas[MAX_MAP_AREAS];
+
+int numareaportals;
+dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS];
+
+int numclusters = 1;
+
+mapsurface_t nullsurface;
+
+int floodvalid;
+
+qboolean portalopen[MAX_MAP_AREAPORTALS];
+
+
+cvar_t *map_noareas;
+
+void CM_InitBoxHull (void);
+void FloodAreaConnections (void);
+
+
+int c_pointcontents;
+int c_traces, c_brush_traces;
+
+
+/*
+===============================================================================
+
+ MAP LOADING
+
+===============================================================================
+*/
+
+byte *cmod_base;
+
+/*
+=================
+CMod_LoadSubmodels
+=================
+*/
+void CMod_LoadSubmodels (lump_t *l)
+{
+ dmodel_t *in;
+ cmodel_t *out;
+ int i, j, count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no models");
+ if (count > MAX_MAP_MODELS)
+ Com_Error (ERR_DROP, "Map has too many models");
+
+ numcmodels = count;
+
+ for ( i=0 ; i<count ; i++, in++)
+ {
+ out = &map_cmodels[i];
+
+ for (j=0 ; j<3 ; j++)
+ { // spread the mins / maxs by a pixel
+ out->mins[j] = LittleFloat (in->mins[j]) - 1;
+ out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
+ out->origin[j] = LittleFloat (in->origin[j]);
+ }
+ out->headnode = LittleLong (in->headnode);
+ }
+}
+
+
+/*
+=================
+CMod_LoadSurfaces
+=================
+*/
+void CMod_LoadSurfaces (lump_t *l)
+{
+ texinfo_t *in;
+ mapsurface_t *out;
+ int i, count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no surfaces");
+ if (count > MAX_MAP_TEXINFO)
+ Com_Error (ERR_DROP, "Map has too many surfaces");
+
+ numtexinfo = count;
+ out = map_surfaces;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ strncpy (out->c.name, in->texture, sizeof(out->c.name)-1);
+ strncpy (out->rname, in->texture, sizeof(out->rname)-1);
+ out->c.flags = LittleLong (in->flags);
+ out->c.value = LittleLong (in->value);
+ }
+}
+
+
+/*
+=================
+CMod_LoadNodes
+
+=================
+*/
+void CMod_LoadNodes (lump_t *l)
+{
+ dnode_t *in;
+ int child;
+ cnode_t *out;
+ int i, j, count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map has no nodes");
+ if (count > MAX_MAP_NODES)
+ Com_Error (ERR_DROP, "Map has too many nodes");
+
+ out = map_nodes;
+
+ numnodes = count;
+
+ for (i=0 ; i<count ; i++, out++, in++)
+ {
+ out->plane = map_planes + LittleLong(in->planenum);
+ for (j=0 ; j<2 ; j++)
+ {
+ child = LittleLong (in->children[j]);
+ out->children[j] = child;
+ }
+ }
+
+}
+
+/*
+=================
+CMod_LoadBrushes
+
+=================
+*/
+void CMod_LoadBrushes (lump_t *l)
+{
+ dbrush_t *in;
+ cbrush_t *out;
+ int i, count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count > MAX_MAP_BRUSHES)
+ Com_Error (ERR_DROP, "Map has too many brushes");
+
+ out = map_brushes;
+
+ numbrushes = count;
+
+ for (i=0 ; i<count ; i++, out++, in++)
+ {
+ out->firstbrushside = LittleLong(in->firstside);
+ out->numsides = LittleLong(in->numsides);
+ out->contents = LittleLong(in->contents);
+ }
+
+}
+
+/*
+=================
+CMod_LoadLeafs
+=================
+*/
+void CMod_LoadLeafs (lump_t *l)
+{
+ int i;
+ cleaf_t *out;
+ dleaf_t *in;
+ int count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no leafs");
+ // need to save space for box planes
+ if (count > MAX_MAP_PLANES)
+ Com_Error (ERR_DROP, "Map has too many planes");
+
+ out = map_leafs;
+ numleafs = count;
+ numclusters = 0;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ out->contents = LittleLong (in->contents);
+ out->cluster = LittleShort (in->cluster);
+ out->area = LittleShort (in->area);
+ out->firstleafbrush = LittleShort (in->firstleafbrush);
+ out->numleafbrushes = LittleShort (in->numleafbrushes);
+
+ if (out->cluster >= numclusters)
+ numclusters = out->cluster + 1;
+ }
+
+ if (map_leafs[0].contents != CONTENTS_SOLID)
+ Com_Error (ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID");
+ solidleaf = 0;
+ emptyleaf = -1;
+ for (i=1 ; i<numleafs ; i++)
+ {
+ if (!map_leafs[i].contents)
+ {
+ emptyleaf = i;
+ break;
+ }
+ }
+ if (emptyleaf == -1)
+ Com_Error (ERR_DROP, "Map does not have an empty leaf");
+}
+
+/*
+=================
+CMod_LoadPlanes
+=================
+*/
+void CMod_LoadPlanes (lump_t *l)
+{
+ int i, j;
+ cplane_t *out;
+ dplane_t *in;
+ int count;
+ int bits;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no planes");
+ // need to save space for box planes
+ if (count > MAX_MAP_PLANES)
+ Com_Error (ERR_DROP, "Map has too many planes");
+
+ out = map_planes;
+ numplanes = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ bits = 0;
+ for (j=0 ; j<3 ; j++)
+ {
+ out->normal[j] = LittleFloat (in->normal[j]);
+ if (out->normal[j] < 0)
+ bits |= 1<<j;
+ }
+
+ out->dist = LittleFloat (in->dist);
+ out->type = LittleLong (in->type);
+ out->signbits = bits;
+ }
+}
+
+/*
+=================
+CMod_LoadLeafBrushes
+=================
+*/
+void CMod_LoadLeafBrushes (lump_t *l)
+{
+ int i;
+ unsigned short *out;
+ unsigned short *in;
+ int count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no planes");
+ // need to save space for box planes
+ if (count > MAX_MAP_LEAFBRUSHES)
+ Com_Error (ERR_DROP, "Map has too many leafbrushes");
+
+ out = map_leafbrushes;
+ numleafbrushes = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ *out = LittleShort (*in);
+}
+
+/*
+=================
+CMod_LoadBrushSides
+=================
+*/
+void CMod_LoadBrushSides (lump_t *l)
+{
+ int i, j;
+ cbrushside_t *out;
+ dbrushside_t *in;
+ int count;
+ int num;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ // need to save space for box planes
+ if (count > MAX_MAP_BRUSHSIDES)
+ Com_Error (ERR_DROP, "Map has too many planes");
+
+ out = map_brushsides;
+ numbrushsides = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ num = LittleShort (in->planenum);
+ out->plane = &map_planes[num];
+ j = LittleShort (in->texinfo);
+ if (j >= numtexinfo)
+ Com_Error (ERR_DROP, "Bad brushside texinfo");
+ out->surface = &map_surfaces[j];
+ }
+}
+
+/*
+=================
+CMod_LoadAreas
+=================
+*/
+void CMod_LoadAreas (lump_t *l)
+{
+ int i;
+ carea_t *out;
+ darea_t *in;
+ int count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count > MAX_MAP_AREAS)
+ Com_Error (ERR_DROP, "Map has too many areas");
+
+ out = map_areas;
+ numareas = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ out->numareaportals = LittleLong (in->numareaportals);
+ out->firstareaportal = LittleLong (in->firstareaportal);
+ out->floodvalid = 0;
+ out->floodnum = 0;
+ }
+}
+
+/*
+=================
+CMod_LoadAreaPortals
+=================
+*/
+void CMod_LoadAreaPortals (lump_t *l)
+{
+ int i;
+ dareaportal_t *out;
+ dareaportal_t *in;
+ int count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count > MAX_MAP_AREAS)
+ Com_Error (ERR_DROP, "Map has too many areas");
+
+ out = map_areaportals;
+ numareaportals = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ out->portalnum = LittleLong (in->portalnum);
+ out->otherarea = LittleLong (in->otherarea);
+ }
+}
+
+/*
+=================
+CMod_LoadVisibility
+=================
+*/
+void CMod_LoadVisibility (lump_t *l)
+{
+ int i;
+
+ numvisibility = l->filelen;
+ if (l->filelen > MAX_MAP_VISIBILITY)
+ Com_Error (ERR_DROP, "Map has too large visibility lump");
+
+ memcpy (map_visibility, cmod_base + l->fileofs, l->filelen);
+
+ map_vis->numclusters = LittleLong (map_vis->numclusters);
+ for (i=0 ; i<map_vis->numclusters ; i++)
+ {
+ map_vis->bitofs[i][0] = LittleLong (map_vis->bitofs[i][0]);
+ map_vis->bitofs[i][1] = LittleLong (map_vis->bitofs[i][1]);
+ }
+}
+
+
+/*
+=================
+CMod_LoadEntityString
+=================
+*/
+void CMod_LoadEntityString (lump_t *l)
+{
+ numentitychars = l->filelen;
+ if (l->filelen > MAX_MAP_ENTSTRING)
+ Com_Error (ERR_DROP, "Map has too large entity lump");
+
+ memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen);
+}
+
+
+
+/*
+==================
+CM_LoadMap
+
+Loads in the map and all submodels
+==================
+*/
+cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum)
+{
+ unsigned *buf;
+ int i;
+ dheader_t header;
+ int length;
+ static unsigned last_checksum;
+
+ map_noareas = Cvar_Get ("map_noareas", "0", 0);
+
+ if ( !strcmp (map_name, name) && (clientload || !Cvar_VariableValue ("flushmap")) )
+ {
+ *checksum = last_checksum;
+ if (!clientload)
+ {
+ memset (portalopen, 0, sizeof(portalopen));
+ FloodAreaConnections ();
+ }
+ return &map_cmodels[0]; // still have the right version
+ }
+
+ // free old stuff
+ numplanes = 0;
+ numnodes = 0;
+ numleafs = 0;
+ numcmodels = 0;
+ numvisibility = 0;
+ numentitychars = 0;
+ map_entitystring[0] = 0;
+ map_name[0] = 0;
+
+ if (!name || !name[0])
+ {
+ numleafs = 1;
+ numclusters = 1;
+ numareas = 1;
+ *checksum = 0;
+ return &map_cmodels[0]; // cinematic servers won't have anything at all
+ }
+
+ //
+ // load the file
+ //
+ length = FS_LoadFile (name, (void **)&buf);
+ if (!buf)
+ Com_Error (ERR_DROP, "Couldn't load %s", name);
+
+ last_checksum = LittleLong (Com_BlockChecksum (buf, length));
+ *checksum = last_checksum;
+
+ header = *(dheader_t *)buf;
+ for (i=0 ; i<sizeof(dheader_t)/sizeof(int) ; i++)
+ ((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
+
+ if (header.version != BSPVERSION)
+ Com_Error (ERR_DROP, "CMod_LoadBrushModel: %s has wrong version number (%i should be %i)"
+ , name, header.version, BSPVERSION);
+
+ cmod_base = (byte *)buf;
+
+ // load into heap
+ CMod_LoadSurfaces (&header.lumps[LUMP_TEXINFO]);
+ CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);
+ CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);
+ CMod_LoadPlanes (&header.lumps[LUMP_PLANES]);
+ CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);
+ CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);
+ CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);
+ CMod_LoadNodes (&header.lumps[LUMP_NODES]);
+ CMod_LoadAreas (&header.lumps[LUMP_AREAS]);
+ CMod_LoadAreaPortals (&header.lumps[LUMP_AREAPORTALS]);
+ CMod_LoadVisibility (&header.lumps[LUMP_VISIBILITY]);
+ CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);
+
+ FS_FreeFile (buf);
+
+ CM_InitBoxHull ();
+
+ memset (portalopen, 0, sizeof(portalopen));
+ FloodAreaConnections ();
+
+ strcpy (map_name, name);
+
+ return &map_cmodels[0];
+}
+
+/*
+==================
+CM_InlineModel
+==================
+*/
+cmodel_t *CM_InlineModel (char *name)
+{
+ int num;
+
+ if (!name || name[0] != '*')
+ Com_Error (ERR_DROP, "CM_InlineModel: bad name");
+ num = atoi (name+1);
+ if (num < 1 || num >= numcmodels)
+ Com_Error (ERR_DROP, "CM_InlineModel: bad number");
+
+ return &map_cmodels[num];
+}
+
+int CM_NumClusters (void)
+{
+ return numclusters;
+}
+
+int CM_NumInlineModels (void)
+{
+ return numcmodels;
+}
+
+char *CM_EntityString (void)
+{
+ return map_entitystring;
+}
+
+int CM_LeafContents (int leafnum)
+{
+ if (leafnum < 0 || leafnum >= numleafs)
+ Com_Error (ERR_DROP, "CM_LeafContents: bad number");
+ return map_leafs[leafnum].contents;
+}
+
+int CM_LeafCluster (int leafnum)
+{
+ if (leafnum < 0 || leafnum >= numleafs)
+ Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
+ return map_leafs[leafnum].cluster;
+}
+
+int CM_LeafArea (int leafnum)
+{
+ if (leafnum < 0 || leafnum >= numleafs)
+ Com_Error (ERR_DROP, "CM_LeafArea: bad number");
+ return map_leafs[leafnum].area;
+}
+
+//=======================================================================
+
+
+cplane_t *box_planes;
+int box_headnode;
+cbrush_t *box_brush;
+cleaf_t *box_leaf;
+
+/*
+===================
+CM_InitBoxHull
+
+Set up the planes and nodes so that the six floats of a bounding box
+can just be stored out and get a proper clipping hull structure.
+===================
+*/
+void CM_InitBoxHull (void)
+{
+ int i;
+ int side;
+ cnode_t *c;
+ cplane_t *p;
+ cbrushside_t *s;
+
+ box_headnode = numnodes;
+ box_planes = &map_planes[numplanes];
+ if (numnodes+6 > MAX_MAP_NODES
+ || numbrushes+1 > MAX_MAP_BRUSHES
+ || numleafbrushes+1 > MAX_MAP_LEAFBRUSHES
+ || numbrushsides+6 > MAX_MAP_BRUSHSIDES
+ || numplanes+12 > MAX_MAP_PLANES)
+ Com_Error (ERR_DROP, "Not enough room for box tree");
+
+ box_brush = &map_brushes[numbrushes];
+ box_brush->numsides = 6;
+ box_brush->firstbrushside = numbrushsides;
+ box_brush->contents = CONTENTS_MONSTER;
+
+ box_leaf = &map_leafs[numleafs];
+ box_leaf->contents = CONTENTS_MONSTER;
+ box_leaf->firstleafbrush = numleafbrushes;
+ box_leaf->numleafbrushes = 1;
+
+ map_leafbrushes[numleafbrushes] = numbrushes;
+
+ for (i=0 ; i<6 ; i++)
+ {
+ side = i&1;
+
+ // brush sides
+ s = &map_brushsides[numbrushsides+i];
+ s->plane = map_planes + (numplanes+i*2+side);
+ s->surface = &nullsurface;
+
+ // nodes
+ c = &map_nodes[box_headnode+i];
+ c->plane = map_planes + (numplanes+i*2);
+ c->children[side] = -1 - emptyleaf;
+ if (i != 5)
+ c->children[side^1] = box_headnode+i + 1;
+ else
+ c->children[side^1] = -1 - numleafs;
+
+ // planes
+ p = &box_planes[i*2];
+ p->type = i>>1;
+ p->signbits = 0;
+ VectorClear (p->normal);
+ p->normal[i>>1] = 1;
+
+ p = &box_planes[i*2+1];
+ p->type = 3 + (i>>1);
+ p->signbits = 0;
+ VectorClear (p->normal);
+ p->normal[i>>1] = -1;
+ }
+}
+
+
+/*
+===================
+CM_HeadnodeForBox
+
+Creates a clipping hull for an arbitrary box
+
+To keep everything totally uniform, bounding boxes are turned into small
+BSP trees instead of being compared directly.
+===================
+*/
+int CM_HeadnodeForBox (vec3_t mins, vec3_t maxs)
+{
+ box_planes[0].dist = maxs[0];
+ box_planes[1].dist = -maxs[0];
+ box_planes[2].dist = mins[0];
+ box_planes[3].dist = -mins[0];
+ box_planes[4].dist = maxs[1];
+ box_planes[5].dist = -maxs[1];
+ box_planes[6].dist = mins[1];
+ box_planes[7].dist = -mins[1];
+ box_planes[8].dist = maxs[2];
+ box_planes[9].dist = -maxs[2];
+ box_planes[10].dist = mins[2];
+ box_planes[11].dist = -mins[2];
+
+ return box_headnode;
+}
+
+
+/*
+==================
+CM_PointLeafnum_r
+
+==================
+*/
+int CM_PointLeafnum_r (vec3_t p, int num)
+{
+ float d;
+ cnode_t *node;
+ cplane_t *plane;
+
+ while (num >= 0)
+ {
+ node = map_nodes + num;
+ plane = node->plane;
+
+ if (plane->type < 3)
+ d = p[plane->type] - plane->dist;
+ else
+ d = DotProduct (plane->normal, p) - plane->dist;
+ if (d < 0)
+ num = node->children[1];
+ else
+ num = node->children[0];
+ }
+
+ c_pointcontents++; // optimize counter
+
+ return -1 - num;
+}
+
+/* call with topnode set to the headnode, returns with topnode set to the first
+ * node that splits the box */
+int CM_PointLeafnum (vec3_t p)
+{
+ if (!numplanes)
+ return 0; // sound may call this without map loaded
+ return CM_PointLeafnum_r (p, 0);
+}
+
+
+
+/*
+=============
+CM_BoxLeafnums
+
+Fills in a list of all the leafs touched
+=============
+*/
+int leaf_count, leaf_maxcount;
+int *leaf_list;
+float *leaf_mins, *leaf_maxs;
+int leaf_topnode;
+
+void CM_BoxLeafnums_r (int nodenum)
+{
+ cplane_t *plane;
+ cnode_t *node;
+ int s;
+
+ while (1)
+ {
+ if (nodenum < 0)
+ {
+ if (leaf_count >= leaf_maxcount)
+ {
+// Com_Printf ("CM_BoxLeafnums_r: overflow\n");
+ return;
+ }
+ leaf_list[leaf_count++] = -1 - nodenum;
+ return;
+ }
+
+ node = &map_nodes[nodenum];
+ plane = node->plane;
+// s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane);
+ s = BOX_ON_PLANE_SIDE(leaf_mins, leaf_maxs, plane);
+ if (s == 1)
+ nodenum = node->children[0];
+ else if (s == 2)
+ nodenum = node->children[1];
+ else
+ { // go down both
+ if (leaf_topnode == -1)
+ leaf_topnode = nodenum;
+ CM_BoxLeafnums_r (node->children[0]);
+ nodenum = node->children[1];
+ }
+
+ }
+}
+
+int CM_BoxLeafnums_headnode (vec3_t mins, vec3_t maxs, int *list, int listsize, int headnode, int *topnode)
+{
+ leaf_list = list;
+ leaf_count = 0;
+ leaf_maxcount = listsize;
+ leaf_mins = mins;
+ leaf_maxs = maxs;
+
+ leaf_topnode = -1;
+
+ CM_BoxLeafnums_r (headnode);
+
+ if (topnode)
+ *topnode = leaf_topnode;
+
+ return leaf_count;
+}
+
+int CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode)
+{
+ return CM_BoxLeafnums_headnode (mins, maxs, list,
+ listsize, map_cmodels[0].headnode, topnode);
+}
+
+
+
+/*
+==================
+CM_PointContents
+
+==================
+*/
+int CM_PointContents (vec3_t p, int headnode)
+{
+ int l;
+
+ if (!numnodes) // map not loaded
+ return 0;
+
+ l = CM_PointLeafnum_r (p, headnode);
+
+ return map_leafs[l].contents;
+}
+
+/*
+==================
+CM_TransformedPointContents
+
+Handles offseting and rotation of the end points for moving and
+rotating entities
+==================
+*/
+int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles)
+{
+ vec3_t p_l;
+ vec3_t temp;
+ vec3_t forward, right, up;
+ int l;
+
+ // subtract origin offset
+ VectorSubtract (p, origin, p_l);
+
+ // rotate start and end into the models frame of reference
+ if (headnode != box_headnode &&
+ (angles[0] || angles[1] || angles[2]) )
+ {
+ AngleVectors (angles, forward, right, up);
+
+ VectorCopy (p_l, temp);
+ p_l[0] = DotProduct (temp, forward);
+ p_l[1] = -DotProduct (temp, right);
+ p_l[2] = DotProduct (temp, up);
+ }
+
+ l = CM_PointLeafnum_r (p_l, headnode);
+
+ return map_leafs[l].contents;
+}
+
+
+/*
+===============================================================================
+
+BOX TRACING
+
+===============================================================================
+*/
+
+// 1/32 epsilon to keep floating point happy
+#define DIST_EPSILON (0.03125)
+
+vec3_t trace_start, trace_end;
+vec3_t trace_mins, trace_maxs;
+vec3_t trace_extents;
+
+trace_t trace_trace;
+int trace_contents;
+qboolean trace_ispoint; // optimized case
+
+/*
+================
+CM_ClipBoxToBrush
+================
+*/
+void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
+ trace_t *trace, cbrush_t *brush)
+{
+ int i, j;
+ cplane_t *plane, *clipplane;
+ float dist;
+ float enterfrac, leavefrac;
+ vec3_t ofs;
+ float d1, d2;
+ qboolean getout, startout;
+ float f;
+ cbrushside_t *side, *leadside;
+
+ enterfrac = -1;
+ leavefrac = 1;
+ clipplane = NULL;
+
+ if (!brush->numsides)
+ return;
+
+ c_brush_traces++;
+
+ getout = false;
+ startout = false;
+ leadside = NULL;
+
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ side = &map_brushsides[brush->firstbrushside+i];
+ plane = side->plane;
+
+ // FIXME: special case for axial
+
+ if (!trace_ispoint)
+ { // general box case
+
+ // push the plane out apropriately for mins/maxs
+
+ // FIXME: use signbits into 8 way lookup for each mins/maxs
+ for (j=0 ; j<3 ; j++)
+ {
+ if (plane->normal[j] < 0)
+ ofs[j] = maxs[j];
+ else
+ ofs[j] = mins[j];
+ }
+ dist = DotProduct (ofs, plane->normal);
+ dist = plane->dist - dist;
+ }
+ else
+ { // special point case
+ dist = plane->dist;
+ }
+
+ d1 = DotProduct (p1, plane->normal) - dist;
+ d2 = DotProduct (p2, plane->normal) - dist;
+
+ if (d2 > 0)
+ getout = true; // endpoint is not in solid
+ if (d1 > 0)
+ startout = true;
+
+ // if completely in front of face, no intersection
+ if (d1 > 0 && d2 >= d1)
+ return;
+
+ if (d1 <= 0 && d2 <= 0)
+ continue;
+
+ // crosses face
+ if (d1 > d2)
+ { // enter
+ f = (d1-DIST_EPSILON) / (d1-d2);
+ if (f > enterfrac)
+ {
+ enterfrac = f;
+ clipplane = plane;
+ leadside = side;
+ }
+ }
+ else
+ { // leave
+ f = (d1+DIST_EPSILON) / (d1-d2);
+ if (f < leavefrac)
+ leavefrac = f;
+ }
+ }
+
+ if (!startout)
+ { // original point was inside brush
+ trace->startsolid = true;
+ if (!getout)
+ trace->allsolid = true;
+ return;
+ }
+ if (enterfrac < leavefrac)
+ {
+ if (enterfrac > -1 && enterfrac < trace->fraction)
+ {
+ if (enterfrac < 0)
+ enterfrac = 0;
+ trace->fraction = enterfrac;
+ trace->plane = *clipplane;
+ trace->surface = &(leadside->surface->c);
+ trace->contents = brush->contents;
+ }
+ }
+}
+
+/*
+================
+CM_TestBoxInBrush
+================
+*/
+void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1,
+ trace_t *trace, cbrush_t *brush)
+{
+ int i, j;
+ cplane_t *plane;
+ float dist;
+ vec3_t ofs;
+ float d1;
+ cbrushside_t *side;
+
+ if (!brush->numsides)
+ return;
+
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ side = &map_brushsides[brush->firstbrushside+i];
+ plane = side->plane;
+
+ // FIXME: special case for axial
+
+ // general box case
+
+ // push the plane out apropriately for mins/maxs
+
+ // FIXME: use signbits into 8 way lookup for each mins/maxs
+ for (j=0 ; j<3 ; j++)
+ {
+ if (plane->normal[j] < 0)
+ ofs[j] = maxs[j];
+ else
+ ofs[j] = mins[j];
+ }
+ dist = DotProduct (ofs, plane->normal);
+ dist = plane->dist - dist;
+
+ d1 = DotProduct (p1, plane->normal) - dist;
+
+ // if completely in front of face, no intersection
+ if (d1 > 0)
+ return;
+
+ }
+
+ // inside this brush
+ trace->startsolid = trace->allsolid = true;
+ trace->fraction = 0;
+ trace->contents = brush->contents;
+}
+
+
+/*
+================
+CM_TraceToLeaf
+================
+*/
+void CM_TraceToLeaf (int leafnum)
+{
+ int k;
+ int brushnum;
+ cleaf_t *leaf;
+ cbrush_t *b;
+
+ leaf = &map_leafs[leafnum];
+ if ( !(leaf->contents & trace_contents))
+ return;
+ // trace line against all brushes in the leaf
+ for (k=0 ; k<leaf->numleafbrushes ; k++)
+ {
+ brushnum = map_leafbrushes[leaf->firstleafbrush+k];
+ b = &map_brushes[brushnum];
+ if (b->checkcount == checkcount)
+ continue; // already checked this brush in another leaf
+ b->checkcount = checkcount;
+
+ if ( !(b->contents & trace_contents))
+ continue;
+ CM_ClipBoxToBrush (trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, b);
+ if (!trace_trace.fraction)
+ return;
+ }
+
+}
+
+
+/*
+================
+CM_TestInLeaf
+================
+*/
+void CM_TestInLeaf (int leafnum)
+{
+ int k;
+ int brushnum;
+ cleaf_t *leaf;
+ cbrush_t *b;
+
+ leaf = &map_leafs[leafnum];
+ if ( !(leaf->contents & trace_contents))
+ return;
+ // trace line against all brushes in the leaf
+ for (k=0 ; k<leaf->numleafbrushes ; k++)
+ {
+ brushnum = map_leafbrushes[leaf->firstleafbrush+k];
+ b = &map_brushes[brushnum];
+ if (b->checkcount == checkcount)
+ continue; // already checked this brush in another leaf
+ b->checkcount = checkcount;
+
+ if ( !(b->contents & trace_contents))
+ continue;
+ CM_TestBoxInBrush (trace_mins, trace_maxs, trace_start, &trace_trace, b);
+ if (!trace_trace.fraction)
+ return;
+ }
+
+}
+
+
+/*
+==================
+CM_RecursiveHullCheck
+
+==================
+*/
+void CM_RecursiveHullCheck (int num, float p1f, float p2f, vec3_t p1, vec3_t p2)
+{
+ cnode_t *node;
+ cplane_t *plane;
+ float t1, t2, offset;
+ float frac, frac2;
+ float idist;
+ int i;
+ vec3_t mid;
+ int side;
+ float midf;
+
+ if (trace_trace.fraction <= p1f)
+ return; // already hit something nearer
+
+ // if < 0, we are in a leaf node
+ if (num < 0)
+ {
+ CM_TraceToLeaf (-1-num);
+ return;
+ }
+
+ //
+ // find the point distances to the seperating plane
+ // and the offset for the size of the box
+ //
+ node = map_nodes + num;
+ plane = node->plane;
+
+ if (plane->type < 3)
+ {
+ t1 = p1[plane->type] - plane->dist;
+ t2 = p2[plane->type] - plane->dist;
+ offset = trace_extents[plane->type];
+ }
+ else
+ {
+ t1 = DotProduct (plane->normal, p1) - plane->dist;
+ t2 = DotProduct (plane->normal, p2) - plane->dist;
+ if (trace_ispoint)
+ offset = 0;
+ else
+ offset = fabs(trace_extents[0]*plane->normal[0]) +
+ fabs(trace_extents[1]*plane->normal[1]) +
+ fabs(trace_extents[2]*plane->normal[2]);
+ }
+
+
+ /*
+ CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
+ CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
+ return;
+ */
+
+ // see which sides we need to consider
+ if (t1 >= offset && t2 >= offset)
+ {
+ CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
+ return;
+ }
+ if (t1 < -offset && t2 < -offset)
+ {
+ CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
+ return;
+ }
+
+ // put the crosspoint DIST_EPSILON pixels on the near side
+ if (t1 < t2)
+ {
+ idist = 1.0/(t1-t2);
+ side = 1;
+ frac2 = (t1 + offset + DIST_EPSILON)*idist;
+ frac = (t1 - offset + DIST_EPSILON)*idist;
+ }
+ else if (t1 > t2)
+ {
+ idist = 1.0/(t1-t2);
+ side = 0;
+ frac2 = (t1 - offset - DIST_EPSILON)*idist;
+ frac = (t1 + offset + DIST_EPSILON)*idist;
+ }
+ else
+ {
+ side = 0;
+ frac = 1;
+ frac2 = 0;
+ }
+
+ // move up to the node
+ if (frac < 0)
+ frac = 0;
+ if (frac > 1)
+ frac = 1;
+
+ midf = p1f + (p2f - p1f)*frac;
+ for (i=0 ; i<3 ; i++)
+ mid[i] = p1[i] + frac*(p2[i] - p1[i]);
+
+ CM_RecursiveHullCheck (node->children[side], p1f, midf, p1, mid);
+
+
+ // go past the node
+ if (frac2 < 0)
+ frac2 = 0;
+ if (frac2 > 1)
+ frac2 = 1;
+
+ midf = p1f + (p2f - p1f)*frac2;
+ for (i=0 ; i<3 ; i++)
+ mid[i] = p1[i] + frac2*(p2[i] - p1[i]);
+
+ CM_RecursiveHullCheck (node->children[side^1], midf, p2f, mid, p2);
+}
+
+
+
+//======================================================================
+
+/*
+==================
+CM_BoxTrace
+==================
+*/
+trace_t CM_BoxTrace (vec3_t start, vec3_t end,
+ vec3_t mins, vec3_t maxs,
+ int headnode, int brushmask)
+{
+ int i;
+
+ checkcount++; // for multi-check avoidance
+
+ c_traces++; // for statistics, may be zeroed
+
+ // fill in a default trace
+ memset (&trace_trace, 0, sizeof(trace_trace));
+ trace_trace.fraction = 1;
+ trace_trace.surface = &(nullsurface.c);
+
+ if (!numnodes) // map not loaded
+ return trace_trace;
+
+ trace_contents = brushmask;
+ VectorCopy (start, trace_start);
+ VectorCopy (end, trace_end);
+ VectorCopy (mins, trace_mins);
+ VectorCopy (maxs, trace_maxs);
+
+ //
+ // check for position test special case
+ //
+ if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2])
+ {
+ int leafs[1024];
+ int i, numleafs;
+ vec3_t c1, c2;
+ int topnode;
+
+ VectorAdd (start, mins, c1);
+ VectorAdd (start, maxs, c2);
+ for (i=0 ; i<3 ; i++)
+ {
+ c1[i] -= 1;
+ c2[i] += 1;
+ }
+
+ numleafs = CM_BoxLeafnums_headnode (c1, c2, leafs, 1024, headnode, &topnode);
+ for (i=0 ; i<numleafs ; i++)
+ {
+ CM_TestInLeaf (leafs[i]);
+ if (trace_trace.allsolid)
+ break;
+ }
+ VectorCopy (start, trace_trace.endpos);
+ return trace_trace;
+ }
+
+ //
+ // check for point special case
+ //
+ if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0
+ && maxs[0] == 0 && maxs[1] == 0 && maxs[2] == 0)
+ {
+ trace_ispoint = true;
+ VectorClear (trace_extents);
+ }
+ else
+ {
+ trace_ispoint = false;
+ trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0];
+ trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1];
+ trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2];
+ }
+
+ //
+ // general sweeping through world
+ //
+ CM_RecursiveHullCheck (headnode, 0, 1, start, end);
+
+ if (trace_trace.fraction == 1)
+ {
+ VectorCopy (end, trace_trace.endpos);
+ }
+ else
+ {
+ for (i=0 ; i<3 ; i++)
+ trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]);
+ }
+ return trace_trace;
+}
+
+
+/*
+==================
+CM_TransformedBoxTrace
+
+Handles offseting and rotation of the end points for moving and
+rotating entities
+==================
+*/
+
+
+trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end,
+ vec3_t mins, vec3_t maxs,
+ int headnode, int brushmask,
+ vec3_t origin, vec3_t angles)
+{
+ trace_t trace;
+ vec3_t start_l, end_l;
+ vec3_t a;
+ vec3_t forward, right, up;
+ vec3_t temp;
+ qboolean rotated;
+
+ // subtract origin offset
+ VectorSubtract (start, origin, start_l);
+ VectorSubtract (end, origin, end_l);
+
+ // rotate start and end into the models frame of reference
+ if (headnode != box_headnode &&
+ (angles[0] || angles[1] || angles[2]) )
+ rotated = true;
+ else
+ rotated = false;
+
+ if (rotated)
+ {
+ AngleVectors (angles, forward, right, up);
+
+ VectorCopy (start_l, temp);
+ start_l[0] = DotProduct (temp, forward);
+ start_l[1] = -DotProduct (temp, right);
+ start_l[2] = DotProduct (temp, up);
+
+ VectorCopy (end_l, temp);
+ end_l[0] = DotProduct (temp, forward);
+ end_l[1] = -DotProduct (temp, right);
+ end_l[2] = DotProduct (temp, up);
+ }
+
+ // sweep the box through the model
+ trace = CM_BoxTrace (start_l, end_l, mins, maxs, headnode, brushmask);
+
+ if (rotated && trace.fraction != 1.0)
+ {
+ // FIXME: figure out how to do this with existing angles
+ VectorNegate (angles, a);
+ AngleVectors (a, forward, right, up);
+
+ VectorCopy (trace.plane.normal, temp);
+ trace.plane.normal[0] = DotProduct (temp, forward);
+ trace.plane.normal[1] = -DotProduct (temp, right);
+ trace.plane.normal[2] = DotProduct (temp, up);
+ }
+
+ trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
+ trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
+ trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
+
+ return trace;
+}
+
+/*
+===============================================================================
+
+PVS / PHS
+
+===============================================================================
+*/
+
+/*
+===================
+CM_DecompressVis
+===================
+*/
+void CM_DecompressVis (byte *in, byte *out)
+{
+ int c;
+ byte *out_p;
+ int row;
+
+ row = (numclusters+7)>>3;
+ out_p = out;
+
+ if (!in || !numvisibility)
+ { // no vis info, so make all visible
+ while (row)
+ {
+ *out_p++ = 0xff;
+ row--;
+ }
+ return;
+ }
+
+ do
+ {
+ if (*in)
+ {
+ *out_p++ = *in++;
+ continue;
+ }
+
+ c = in[1];
+ in += 2;
+ if ((out_p - out) + c > row)
+ {
+ c = row - (out_p - out);
+ Com_DPrintf ("warning: Vis decompression overrun\n");
+ }
+ while (c)
+ {
+ *out_p++ = 0;
+ c--;
+ }
+ } while (out_p - out < row);
+}
+
+byte pvsrow[MAX_MAP_LEAFS/8];
+byte phsrow[MAX_MAP_LEAFS/8];
+
+byte *CM_ClusterPVS (int cluster)
+{
+ if (cluster == -1)
+ memset (pvsrow, 0, (numclusters+7)>>3);
+ else
+ CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PVS], pvsrow);
+ return pvsrow;
+}
+
+byte *CM_ClusterPHS (int cluster)
+{
+ if (cluster == -1)
+ memset (phsrow, 0, (numclusters+7)>>3);
+ else
+ CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PHS], phsrow);
+ return phsrow;
+}
+
+
+/*
+===============================================================================
+
+AREAPORTALS
+
+===============================================================================
+*/
+
+void FloodArea_r (carea_t *area, int floodnum)
+{
+ int i;
+ dareaportal_t *p;
+
+ if (area->floodvalid == floodvalid)
+ {
+ if (area->floodnum == floodnum)
+ return;
+ Com_Error (ERR_DROP, "FloodArea_r: reflooded");
+ }
+
+ area->floodnum = floodnum;
+ area->floodvalid = floodvalid;
+ p = &map_areaportals[area->firstareaportal];
+ for (i=0 ; i<area->numareaportals ; i++, p++)
+ {
+ if (portalopen[p->portalnum])
+ FloodArea_r (&map_areas[p->otherarea], floodnum);
+ }
+}
+
+/*
+====================
+FloodAreaConnections
+
+
+====================
+*/
+void FloodAreaConnections (void)
+{
+ int i;
+ carea_t *area;
+ int floodnum;
+
+ // all current floods are now invalid
+ floodvalid++;
+ floodnum = 0;
+
+ // area 0 is not used
+ for (i=1 ; i<numareas ; i++)
+ {
+ area = &map_areas[i];
+ if (area->floodvalid == floodvalid)
+ continue; // already flooded into
+ floodnum++;
+ FloodArea_r (area, floodnum);
+ }
+
+}
+
+void CM_SetAreaPortalState (int portalnum, qboolean open)
+{
+ if (portalnum > numareaportals)
+ Com_Error (ERR_DROP, "areaportal > numareaportals");
+
+ portalopen[portalnum] = open;
+ FloodAreaConnections ();
+}
+
+qboolean CM_AreasConnected (int area1, int area2)
+{
+ if (map_noareas->value)
+ return true;
+
+ if (area1 > numareas || area2 > numareas)
+ Com_Error (ERR_DROP, "area > numareas");
+
+ if (map_areas[area1].floodnum == map_areas[area2].floodnum)
+ return true;
+ return false;
+}
+
+
+/*
+=================
+CM_WriteAreaBits
+
+Writes a length byte followed by a bit vector of all the areas
+that area in the same flood as the area parameter
+
+This is used by the client refreshes to cull visibility
+=================
+*/
+int CM_WriteAreaBits (byte *buffer, int area)
+{
+ int i;
+ int floodnum;
+ int bytes;
+
+ bytes = (numareas+7)>>3;
+
+ if (map_noareas->value)
+ { // for debugging, send everything
+ memset (buffer, 255, bytes);
+ }
+ else
+ {
+ memset (buffer, 0, bytes);
+
+ floodnum = map_areas[area].floodnum;
+ for (i=0 ; i<numareas ; i++)
+ {
+ if (map_areas[i].floodnum == floodnum || !area)
+ buffer[i>>3] |= 1<<(i&7);
+ }
+ }
+
+ return bytes;
+}
+
+
+/*
+===================
+CM_WritePortalState
+
+Writes the portal state to a savegame file
+===================
+*/
+void CM_WritePortalState (FILE *f)
+{
+ fwrite (portalopen, sizeof(portalopen), 1, f);
+}
+
+/*
+===================
+CM_ReadPortalState
+
+Reads the portal state from a savegame file
+and recalculates the area connections
+===================
+*/
+void CM_ReadPortalState (FILE *f)
+{
+ FS_Read (portalopen, sizeof(portalopen), f);
+ FloodAreaConnections ();
+}
+
+/*
+=============
+CM_HeadnodeVisible
+
+Returns true if any leaf under headnode has a cluster that
+is potentially visible
+=============
+*/
+qboolean CM_HeadnodeVisible (int nodenum, byte *visbits)
+{
+ int leafnum;
+ int cluster;
+ cnode_t *node;
+
+ if (nodenum < 0)
+ {
+ leafnum = -1-nodenum;
+ cluster = map_leafs[leafnum].cluster;
+ if (cluster == -1)
+ return false;
+ if (visbits[cluster>>3] & (1<<(cluster&7)))
+ return true;
+ return false;
+ }
+
+ node = &map_nodes[nodenum];
+ if (CM_HeadnodeVisible(node->children[0], visbits))
+ return true;
+ return CM_HeadnodeVisible(node->children[1], visbits);
+}
+
--- /dev/null
+++ b/common.c
@@ -1,0 +1,1570 @@
+// common.c -- misc functions used in client and server
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+#define MAXPRINTMSG 4096
+
+#define MAX_NUM_ARGVS 50
+
+
+int com_argc;
+char *com_argv[MAX_NUM_ARGVS+1];
+
+int realtime;
+
+jmp_buf abortframe; // an ERR_DROP occured, exit the entire frame
+
+
+FILE *log_stats_file;
+
+cvar_t *host_speeds;
+cvar_t *log_stats;
+cvar_t *developer;
+cvar_t *timescale;
+cvar_t *fixedtime;
+cvar_t *logfile_active; // 1 = buffer log, 2 = flush after each print
+cvar_t *showtrace;
+cvar_t *dedicated;
+
+FILE *logfile;
+
+int server_state;
+
+// host_speeds times
+int time_before_game;
+int time_after_game;
+int time_before_ref;
+int time_after_ref;
+
+
+
+/*
+============================================================================
+
+CLIENT / SERVER interactions
+
+============================================================================
+*/
+
+static int rd_target;
+static char *rd_buffer;
+static int rd_buffersize;
+static void (*rd_flush)(int target, char *buffer);
+
+void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush))
+{
+ if (!target || !buffer || !buffersize || !flush)
+ return;
+ rd_target = target;
+ rd_buffer = buffer;
+ rd_buffersize = buffersize;
+ rd_flush = flush;
+
+ *rd_buffer = 0;
+}
+
+void Com_EndRedirect (void)
+{
+ rd_flush(rd_target, rd_buffer);
+
+ rd_target = 0;
+ rd_buffer = NULL;
+ rd_buffersize = 0;
+ rd_flush = NULL;
+}
+
+/*
+=============
+Com_Printf
+
+Both client and server can use this, and it will output
+to the apropriate place.
+=============
+*/
+void Com_Printf (char *fmt, ...)
+{
+ va_list argptr;
+ char msg[MAXPRINTMSG];
+
+ va_start (argptr,fmt);
+ vsprintf (msg,fmt,argptr);
+ va_end (argptr);
+
+ if (rd_target)
+ {
+ if ((strlen (msg) + strlen(rd_buffer)) > (rd_buffersize - 1))
+ {
+ rd_flush(rd_target, rd_buffer);
+ *rd_buffer = 0;
+ }
+ strcat (rd_buffer, msg);
+ return;
+ }
+
+ Con_Print (msg);
+
+ // also echo to debugging console
+ Sys_ConsoleOutput (msg);
+
+ // logfile
+ if (logfile_active && logfile_active->value)
+ {
+ char name[MAX_QPATH];
+
+ if (!logfile)
+ {
+ Com_sprintf (name, sizeof(name), "%s/qconsole.log", FS_Gamedir ());
+ logfile = fopen (name, "w");
+ }
+ if (logfile)
+ fprintf (logfile, "%s", msg);
+ if (logfile_active->value > 1)
+ fflush (logfile); // force it to save every time
+ }
+}
+
+
+/*
+================
+Com_DPrintf
+
+A Com_Printf that only shows up if the "developer" cvar is set
+================
+*/
+void Com_DPrintf (char *fmt, ...)
+{
+ va_list argptr;
+ char msg[MAXPRINTMSG];
+
+ if (!developer || !developer->value)
+ return; // don't confuse non-developers with techie stuff...
+
+ va_start (argptr,fmt);
+ vsprintf (msg,fmt,argptr);
+ va_end (argptr);
+
+ Com_Printf ("%s", msg);
+}
+
+
+/*
+=============
+Com_Error
+
+Both client and server can use this, and it will
+do the apropriate things.
+=============
+*/
+void Com_Error (int code, char *fmt, ...)
+{
+ va_list argptr;
+ static char msg[MAXPRINTMSG];
+ static qboolean recursive;
+
+ if (recursive)
+ Sys_Error ("recursive error after: %s", msg);
+ recursive = true;
+
+ va_start (argptr,fmt);
+ vsprintf (msg,fmt,argptr);
+ va_end (argptr);
+
+ if (code == ERR_DISCONNECT)
+ {
+ CL_Drop ();
+ recursive = false;
+ longjmp (abortframe, -1);
+ }
+ else if (code == ERR_DROP)
+ {
+ Com_Printf ("********************\nERROR: %s\n********************\n", msg);
+ SV_Shutdown (va("Server crashed: %s\n", msg), false);
+ CL_Drop ();
+ recursive = false;
+ longjmp (abortframe, -1);
+ }
+ else
+ {
+ SV_Shutdown (va("Server fatal crashed: %s\n", msg), false);
+ CL_Shutdown ();
+ }
+
+ if (logfile)
+ {
+ fclose (logfile);
+ logfile = NULL;
+ }
+
+ Sys_Error ("%s", msg);
+}
+
+
+/*
+=============
+Com_Quit
+
+Both client and server can use this, and it will
+do the apropriate things.
+=============
+*/
+void Com_Quit (void)
+{
+ SV_Shutdown ("Server quit\n", false);
+ CL_Shutdown ();
+
+ if (logfile)
+ {
+ fclose (logfile);
+ logfile = NULL;
+ }
+
+ Sys_Quit ();
+}
+
+
+/*
+==================
+Com_ServerState
+==================
+*/
+// this should've just been a cvar...
+int Com_ServerState (void)
+{
+ return server_state;
+}
+
+/*
+==================
+Com_SetServerState
+==================
+*/
+void Com_SetServerState (int state)
+{
+ server_state = state;
+}
+
+
+/*
+==============================================================================
+
+ MESSAGE IO FUNCTIONS
+
+Handles byte ordering and avoids alignment errors
+==============================================================================
+*/
+
+vec3_t bytedirs[NUMVERTEXNORMALS] =
+{
+#include "anorms.h"
+};
+
+//
+// writing functions
+//
+
+void MSG_WriteChar (sizebuf_t *sb, int c)
+{
+ byte *buf;
+
+#ifdef PARANOID
+ if (c < -128 || c > 127)
+ Com_Error (ERR_FATAL, "MSG_WriteChar: range error");
+#endif
+
+ buf = SZ_GetSpace (sb, 1);
+ buf[0] = c;
+}
+
+void MSG_WriteByte (sizebuf_t *sb, int c)
+{
+ byte *buf;
+
+#ifdef PARANOID
+ if (c < 0 || c > 255)
+ Com_Error (ERR_FATAL, "MSG_WriteByte: range error");
+#endif
+
+ buf = SZ_GetSpace (sb, 1);
+ buf[0] = c;
+}
+
+void MSG_WriteShort (sizebuf_t *sb, int c)
+{
+ byte *buf;
+
+#ifdef PARANOID
+ if (c < ((short)0x8000) || c > (short)0x7fff)
+ Com_Error (ERR_FATAL, "MSG_WriteShort: range error");
+#endif
+
+ buf = SZ_GetSpace (sb, 2);
+ buf[0] = c&0xff;
+ buf[1] = c>>8;
+}
+
+void MSG_WriteLong (sizebuf_t *sb, int c)
+{
+ byte *buf;
+
+ buf = SZ_GetSpace (sb, 4);
+ buf[0] = c&0xff;
+ buf[1] = (c>>8)&0xff;
+ buf[2] = (c>>16)&0xff;
+ buf[3] = c>>24;
+}
+
+void MSG_WriteFloat (sizebuf_t *sb, float f)
+{
+ union
+ {
+ float f;
+ int l;
+ } dat;
+
+
+ dat.f = f;
+ dat.l = LittleLong (dat.l);
+
+ SZ_Write (sb, &dat.l, 4);
+}
+
+void MSG_WriteString (sizebuf_t *sb, char *s)
+{
+ if (!s)
+ SZ_Write (sb, "", 1);
+ else
+ SZ_Write (sb, s, strlen(s)+1);
+}
+
+void MSG_WriteCoord (sizebuf_t *sb, float f)
+{
+ MSG_WriteShort (sb, (int)(f*8));
+}
+
+void MSG_WritePos (sizebuf_t *sb, vec3_t pos)
+{
+ MSG_WriteShort (sb, (int)(pos[0]*8));
+ MSG_WriteShort (sb, (int)(pos[1]*8));
+ MSG_WriteShort (sb, (int)(pos[2]*8));
+}
+
+void MSG_WriteAngle (sizebuf_t *sb, float f)
+{
+ MSG_WriteByte (sb, (int)(f*256/360) & 255);
+}
+
+void MSG_WriteAngle16 (sizebuf_t *sb, float f)
+{
+ MSG_WriteShort (sb, ANGLE2SHORT(f));
+}
+
+
+void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd)
+{
+ int bits;
+
+//
+// send the movement message
+//
+ bits = 0;
+ if (cmd->angles[0] != from->angles[0])
+ bits |= CM_ANGLE1;
+ if (cmd->angles[1] != from->angles[1])
+ bits |= CM_ANGLE2;
+ if (cmd->angles[2] != from->angles[2])
+ bits |= CM_ANGLE3;
+ if (cmd->forwardmove != from->forwardmove)
+ bits |= CM_FORWARD;
+ if (cmd->sidemove != from->sidemove)
+ bits |= CM_SIDE;
+ if (cmd->upmove != from->upmove)
+ bits |= CM_UP;
+ if (cmd->buttons != from->buttons)
+ bits |= CM_BUTTONS;
+ if (cmd->impulse != from->impulse)
+ bits |= CM_IMPULSE;
+
+ MSG_WriteByte (buf, bits);
+
+ if (bits & CM_ANGLE1)
+ MSG_WriteShort (buf, cmd->angles[0]);
+ if (bits & CM_ANGLE2)
+ MSG_WriteShort (buf, cmd->angles[1]);
+ if (bits & CM_ANGLE3)
+ MSG_WriteShort (buf, cmd->angles[2]);
+
+ if (bits & CM_FORWARD)
+ MSG_WriteShort (buf, cmd->forwardmove);
+ if (bits & CM_SIDE)
+ MSG_WriteShort (buf, cmd->sidemove);
+ if (bits & CM_UP)
+ MSG_WriteShort (buf, cmd->upmove);
+
+ if (bits & CM_BUTTONS)
+ MSG_WriteByte (buf, cmd->buttons);
+ if (bits & CM_IMPULSE)
+ MSG_WriteByte (buf, cmd->impulse);
+
+ MSG_WriteByte (buf, cmd->msec);
+ MSG_WriteByte (buf, cmd->lightlevel);
+}
+
+
+void MSG_WriteDir (sizebuf_t *sb, vec3_t dir)
+{
+ int i, best;
+ float d, bestd;
+
+ if (!dir)
+ {
+ MSG_WriteByte (sb, 0);
+ return;
+ }
+
+ bestd = 0;
+ best = 0;
+ for (i=0 ; i<NUMVERTEXNORMALS ; i++)
+ {
+ d = DotProduct (dir, bytedirs[i]);
+ if (d > bestd)
+ {
+ bestd = d;
+ best = i;
+ }
+ }
+ MSG_WriteByte (sb, best);
+}
+
+
+void MSG_ReadDir (sizebuf_t *sb, vec3_t dir)
+{
+ int b;
+
+ b = MSG_ReadByte (sb);
+ if (b >= NUMVERTEXNORMALS)
+ Com_Error (ERR_DROP, "MSF_ReadDir: out of range");
+ VectorCopy (bytedirs[b], dir);
+}
+
+
+/*
+==================
+MSG_WriteDeltaEntity
+
+Writes part of a packetentities message.
+Can delta from either a baseline or a previous packet_entity
+==================
+*/
+void MSG_WriteDeltaEntity (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean newentity)
+{
+ int bits;
+
+ if (!to->number)
+ Com_Error (ERR_FATAL, "Unset entity number");
+ if (to->number >= MAX_EDICTS)
+ Com_Error (ERR_FATAL, "Entity number >= MAX_EDICTS");
+
+// send an update
+ bits = 0;
+
+ if (to->number >= 256)
+ bits |= U_NUMBER16; // number8 is implicit otherwise
+
+ if (to->origin[0] != from->origin[0])
+ bits |= U_ORIGIN1;
+ if (to->origin[1] != from->origin[1])
+ bits |= U_ORIGIN2;
+ if (to->origin[2] != from->origin[2])
+ bits |= U_ORIGIN3;
+
+ if ( to->angles[0] != from->angles[0] )
+ bits |= U_ANGLE1;
+ if ( to->angles[1] != from->angles[1] )
+ bits |= U_ANGLE2;
+ if ( to->angles[2] != from->angles[2] )
+ bits |= U_ANGLE3;
+
+ if ( to->skinnum != from->skinnum )
+ {
+ if ((unsigned)to->skinnum < 256)
+ bits |= U_SKIN8;
+ else if ((unsigned)to->skinnum < 0x10000)
+ bits |= U_SKIN16;
+ else
+ bits |= (U_SKIN8|U_SKIN16);
+ }
+
+ if ( to->frame != from->frame )
+ {
+ if (to->frame < 256)
+ bits |= U_FRAME8;
+ else
+ bits |= U_FRAME16;
+ }
+
+ if ( to->effects != from->effects )
+ {
+ if (to->effects < 256)
+ bits |= U_EFFECTS8;
+ else if (to->effects < 0x8000)
+ bits |= U_EFFECTS16;
+ else
+ bits |= U_EFFECTS8|U_EFFECTS16;
+ }
+
+ if ( to->renderfx != from->renderfx )
+ {
+ if (to->renderfx < 256)
+ bits |= U_RENDERFX8;
+ else if (to->renderfx < 0x8000)
+ bits |= U_RENDERFX16;
+ else
+ bits |= U_RENDERFX8|U_RENDERFX16;
+ }
+
+ if ( to->solid != from->solid )
+ bits |= U_SOLID;
+
+ // event is not delta compressed, just 0 compressed
+ if ( to->event )
+ bits |= U_EVENT;
+
+ if ( to->modelindex != from->modelindex )
+ bits |= U_MODEL;
+ if ( to->modelindex2 != from->modelindex2 )
+ bits |= U_MODEL2;
+ if ( to->modelindex3 != from->modelindex3 )
+ bits |= U_MODEL3;
+ if ( to->modelindex4 != from->modelindex4 )
+ bits |= U_MODEL4;
+
+ if ( to->sound != from->sound )
+ bits |= U_SOUND;
+
+ if (newentity || (to->renderfx & RF_BEAM))
+ bits |= U_OLDORIGIN;
+
+ //
+ // write the message
+ //
+ if (!bits && !force)
+ return; // nothing to send!
+
+ //----------
+
+ if (bits & 0xff000000)
+ bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1;
+ else if (bits & 0x00ff0000)
+ bits |= U_MOREBITS2 | U_MOREBITS1;
+ else if (bits & 0x0000ff00)
+ bits |= U_MOREBITS1;
+
+ MSG_WriteByte (msg, bits&255 );
+
+ if (bits & 0xff000000)
+ {
+ MSG_WriteByte (msg, (bits>>8)&255 );
+ MSG_WriteByte (msg, (bits>>16)&255 );
+ MSG_WriteByte (msg, (bits>>24)&255 );
+ }
+ else if (bits & 0x00ff0000)
+ {
+ MSG_WriteByte (msg, (bits>>8)&255 );
+ MSG_WriteByte (msg, (bits>>16)&255 );
+ }
+ else if (bits & 0x0000ff00)
+ {
+ MSG_WriteByte (msg, (bits>>8)&255 );
+ }
+
+ //----------
+
+ if (bits & U_NUMBER16)
+ MSG_WriteShort (msg, to->number);
+ else
+ MSG_WriteByte (msg, to->number);
+
+ if (bits & U_MODEL)
+ MSG_WriteByte (msg, to->modelindex);
+ if (bits & U_MODEL2)
+ MSG_WriteByte (msg, to->modelindex2);
+ if (bits & U_MODEL3)
+ MSG_WriteByte (msg, to->modelindex3);
+ if (bits & U_MODEL4)
+ MSG_WriteByte (msg, to->modelindex4);
+
+ if (bits & U_FRAME8)
+ MSG_WriteByte (msg, to->frame);
+ if (bits & U_FRAME16)
+ MSG_WriteShort (msg, to->frame);
+
+ if ((bits & U_SKIN8) && (bits & U_SKIN16)) //used for laser colors
+ MSG_WriteLong (msg, to->skinnum);
+ else if (bits & U_SKIN8)
+ MSG_WriteByte (msg, to->skinnum);
+ else if (bits & U_SKIN16)
+ MSG_WriteShort (msg, to->skinnum);
+
+
+ if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
+ MSG_WriteLong (msg, to->effects);
+ else if (bits & U_EFFECTS8)
+ MSG_WriteByte (msg, to->effects);
+ else if (bits & U_EFFECTS16)
+ MSG_WriteShort (msg, to->effects);
+
+ if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
+ MSG_WriteLong (msg, to->renderfx);
+ else if (bits & U_RENDERFX8)
+ MSG_WriteByte (msg, to->renderfx);
+ else if (bits & U_RENDERFX16)
+ MSG_WriteShort (msg, to->renderfx);
+
+ if (bits & U_ORIGIN1)
+ MSG_WriteCoord (msg, to->origin[0]);
+ if (bits & U_ORIGIN2)
+ MSG_WriteCoord (msg, to->origin[1]);
+ if (bits & U_ORIGIN3)
+ MSG_WriteCoord (msg, to->origin[2]);
+
+ if (bits & U_ANGLE1)
+ MSG_WriteAngle(msg, to->angles[0]);
+ if (bits & U_ANGLE2)
+ MSG_WriteAngle(msg, to->angles[1]);
+ if (bits & U_ANGLE3)
+ MSG_WriteAngle(msg, to->angles[2]);
+
+ if (bits & U_OLDORIGIN)
+ {
+ MSG_WriteCoord (msg, to->old_origin[0]);
+ MSG_WriteCoord (msg, to->old_origin[1]);
+ MSG_WriteCoord (msg, to->old_origin[2]);
+ }
+
+ if (bits & U_SOUND)
+ MSG_WriteByte (msg, to->sound);
+ if (bits & U_EVENT)
+ MSG_WriteByte (msg, to->event);
+ if (bits & U_SOLID)
+ MSG_WriteShort (msg, to->solid);
+}
+
+
+//============================================================
+
+//
+// reading functions
+//
+
+void MSG_BeginReading (sizebuf_t *msg)
+{
+ msg->readcount = 0;
+}
+
+// returns -1 if no more characters are available
+int MSG_ReadChar (sizebuf_t *msg_read)
+{
+ int c;
+
+ if (msg_read->readcount+1 > msg_read->cursize)
+ c = -1;
+ else
+ c = (signed char)msg_read->data[msg_read->readcount];
+ msg_read->readcount++;
+
+ return c;
+}
+
+int MSG_ReadByte (sizebuf_t *msg_read)
+{
+ int c;
+
+ if (msg_read->readcount+1 > msg_read->cursize)
+ c = -1;
+ else
+ c = (unsigned char)msg_read->data[msg_read->readcount];
+ msg_read->readcount++;
+
+ return c;
+}
+
+int MSG_ReadShort (sizebuf_t *msg_read)
+{
+ int c;
+
+ if (msg_read->readcount+2 > msg_read->cursize)
+ c = -1;
+ else
+ c = (short)(msg_read->data[msg_read->readcount]
+ + (msg_read->data[msg_read->readcount+1]<<8));
+
+ msg_read->readcount += 2;
+
+ return c;
+}
+
+int MSG_ReadLong (sizebuf_t *msg_read)
+{
+ int c;
+
+ if (msg_read->readcount+4 > msg_read->cursize)
+ c = -1;
+ else
+ c = msg_read->data[msg_read->readcount]
+ + (msg_read->data[msg_read->readcount+1]<<8)
+ + (msg_read->data[msg_read->readcount+2]<<16)
+ + (msg_read->data[msg_read->readcount+3]<<24);
+
+ msg_read->readcount += 4;
+
+ return c;
+}
+
+float MSG_ReadFloat (sizebuf_t *msg_read)
+{
+ union
+ {
+ byte b[4];
+ float f;
+ int l;
+ } dat;
+
+ if (msg_read->readcount+4 > msg_read->cursize)
+ dat.f = -1;
+ else
+ {
+ dat.b[0] = msg_read->data[msg_read->readcount];
+ dat.b[1] = msg_read->data[msg_read->readcount+1];
+ dat.b[2] = msg_read->data[msg_read->readcount+2];
+ dat.b[3] = msg_read->data[msg_read->readcount+3];
+ }
+ msg_read->readcount += 4;
+
+ dat.l = LittleLong (dat.l);
+
+ return dat.f;
+}
+
+char *MSG_ReadString (sizebuf_t *msg_read)
+{
+ static char string[2048];
+ int l,c;
+
+ l = 0;
+ do
+ {
+ c = MSG_ReadChar (msg_read);
+ if (c == -1 || c == 0)
+ break;
+ string[l] = c;
+ l++;
+ } while (l < sizeof(string)-1);
+
+ string[l] = 0;
+
+ return string;
+}
+
+char *MSG_ReadStringLine (sizebuf_t *msg_read)
+{
+ static char string[2048];
+ int l,c;
+
+ l = 0;
+ do
+ {
+ c = MSG_ReadChar (msg_read);
+ if (c == -1 || c == 0 || c == '\n')
+ break;
+ string[l] = c;
+ l++;
+ } while (l < sizeof(string)-1);
+
+ string[l] = 0;
+
+ return string;
+}
+
+float MSG_ReadCoord (sizebuf_t *msg_read)
+{
+ return MSG_ReadShort(msg_read) * (1.0/8);
+}
+
+void MSG_ReadPos (sizebuf_t *msg_read, vec3_t pos)
+{
+ pos[0] = MSG_ReadShort(msg_read) * (1.0/8);
+ pos[1] = MSG_ReadShort(msg_read) * (1.0/8);
+ pos[2] = MSG_ReadShort(msg_read) * (1.0/8);
+}
+
+float MSG_ReadAngle (sizebuf_t *msg_read)
+{
+ return MSG_ReadChar(msg_read) * (360.0/256);
+}
+
+float MSG_ReadAngle16 (sizebuf_t *msg_read)
+{
+ return SHORT2ANGLE(MSG_ReadShort(msg_read));
+}
+
+void MSG_ReadDeltaUsercmd (sizebuf_t *msg_read, usercmd_t *from, usercmd_t *move)
+{
+ int bits;
+
+ memcpy (move, from, sizeof(*move));
+
+ bits = MSG_ReadByte (msg_read);
+
+// read current angles
+ if (bits & CM_ANGLE1)
+ move->angles[0] = MSG_ReadShort (msg_read);
+ if (bits & CM_ANGLE2)
+ move->angles[1] = MSG_ReadShort (msg_read);
+ if (bits & CM_ANGLE3)
+ move->angles[2] = MSG_ReadShort (msg_read);
+
+// read movement
+ if (bits & CM_FORWARD)
+ move->forwardmove = MSG_ReadShort (msg_read);
+ if (bits & CM_SIDE)
+ move->sidemove = MSG_ReadShort (msg_read);
+ if (bits & CM_UP)
+ move->upmove = MSG_ReadShort (msg_read);
+
+// read buttons
+ if (bits & CM_BUTTONS)
+ move->buttons = MSG_ReadByte (msg_read);
+
+ if (bits & CM_IMPULSE)
+ move->impulse = MSG_ReadByte (msg_read);
+
+// read time to run command
+ move->msec = MSG_ReadByte (msg_read);
+
+// read the light level
+ move->lightlevel = MSG_ReadByte (msg_read);
+}
+
+
+void MSG_ReadData (sizebuf_t *msg_read, void *data, int len)
+{
+ int i;
+
+ for (i=0 ; i<len ; i++)
+ ((byte *)data)[i] = MSG_ReadByte (msg_read);
+}
+
+
+//===========================================================================
+
+void SZ_Init (sizebuf_t *buf, byte *data, int length)
+{
+ memset (buf, 0, sizeof(*buf));
+ buf->data = data;
+ buf->maxsize = length;
+}
+
+void SZ_Clear (sizebuf_t *buf)
+{
+ buf->cursize = 0;
+ buf->overflowed = false;
+}
+
+void *SZ_GetSpace (sizebuf_t *buf, int length)
+{
+ void *data;
+
+ if (buf->cursize + length > buf->maxsize)
+ {
+ if (!buf->allowoverflow)
+ Com_Error (ERR_FATAL, "SZ_GetSpace: overflow without allowoverflow set");
+
+ if (length > buf->maxsize)
+ Com_Error (ERR_FATAL, "SZ_GetSpace: %i is > full buffer size", length);
+
+ Com_Printf ("SZ_GetSpace: overflow\n");
+ SZ_Clear (buf);
+ buf->overflowed = true;
+ }
+
+ data = buf->data + buf->cursize;
+ buf->cursize += length;
+
+ return data;
+}
+
+void SZ_Write (sizebuf_t *buf, void *data, int length)
+{
+ memcpy (SZ_GetSpace(buf,length),data,length);
+}
+
+void SZ_Print (sizebuf_t *buf, char *data)
+{
+ int len;
+
+ len = strlen(data)+1;
+
+ if (buf->cursize)
+ {
+ if (buf->data[buf->cursize-1])
+ memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
+ else
+ memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
+ }
+ else
+ memcpy ((byte *)SZ_GetSpace(buf, len),data,len);
+}
+
+
+//============================================================================
+
+
+/*
+================
+COM_CheckParm
+
+Returns the position (1 to argc-1) in the program's argument list
+where the given parameter apears, or 0 if not present
+================
+*/
+int COM_CheckParm (char *parm)
+{
+ int i;
+
+ for (i=1 ; i<com_argc ; i++)
+ {
+ if (!strcmp (parm,com_argv[i]))
+ return i;
+ }
+
+ return 0;
+}
+
+int COM_Argc (void)
+{
+ return com_argc;
+}
+
+char *COM_Argv (int arg)
+{
+ if (arg < 0 || arg >= com_argc || !com_argv[arg])
+ return "";
+ return com_argv[arg];
+}
+
+void COM_ClearArgv (int arg)
+{
+ if (arg < 0 || arg >= com_argc || !com_argv[arg])
+ return;
+ com_argv[arg] = "";
+}
+
+
+/*
+================
+COM_InitArgv
+================
+*/
+void COM_InitArgv (int argc, char **argv)
+{
+ int i;
+
+ if (argc > MAX_NUM_ARGVS)
+ Com_Error (ERR_FATAL, "argc > MAX_NUM_ARGVS");
+ com_argc = argc;
+ for (i=0 ; i<argc ; i++)
+ {
+ if (!argv[i] || strlen(argv[i]) >= MAX_TOKEN_CHARS )
+ com_argv[i] = "";
+ else
+ com_argv[i] = argv[i];
+ }
+}
+
+/*
+================
+COM_AddParm
+
+Adds the given string at the end of the current argument list
+================
+*/
+void COM_AddParm (char *parm)
+{
+ if (com_argc == MAX_NUM_ARGVS)
+ Com_Error (ERR_FATAL, "COM_AddParm: MAX_NUM)ARGS");
+ com_argv[com_argc++] = parm;
+}
+
+
+
+
+/// just for debugging
+int memsearch (byte *start, int count, int search)
+{
+ int i;
+
+ for (i=0 ; i<count ; i++)
+ if (start[i] == search)
+ return i;
+ return -1;
+}
+
+
+char *CopyString (char *in)
+{
+ char *out;
+
+ out = Z_Malloc (strlen(in)+1);
+ strcpy (out, in);
+ return out;
+}
+
+
+
+void Info_Print (char *s)
+{
+ char key[512];
+ char value[512];
+ char *o;
+ int l;
+
+ if (*s == '\\')
+ s++;
+ while (*s)
+ {
+ o = key;
+ while (*s && *s != '\\')
+ *o++ = *s++;
+
+ l = o - key;
+ if (l < 20)
+ {
+ memset (o, ' ', 20-l);
+ key[20] = 0;
+ }
+ else
+ *o = 0;
+ Com_Printf ("%s", key);
+
+ if (!*s)
+ {
+ Com_Printf ("MISSING VALUE\n");
+ return;
+ }
+
+ o = value;
+ s++;
+ while (*s && *s != '\\')
+ *o++ = *s++;
+ *o = 0;
+
+ if (*s)
+ s++;
+ Com_Printf ("%s\n", value);
+ }
+}
+
+
+/*
+==============================================================================
+
+ ZONE MEMORY ALLOCATION
+
+just cleared malloc with counters now...
+
+==============================================================================
+*/
+
+#define Z_MAGIC 0x1d1d
+
+typedef struct zhead_t zhead_t;
+struct zhead_t{
+ zhead_t *prev;
+ zhead_t *next;
+ short magic;
+ short tag; // for group free
+ int size;
+};
+zhead_t z_chain;
+int z_count;
+int z_bytes;
+
+
+/*
+========================
+Z_Free
+========================
+*/
+void Z_Free (void *ptr)
+{
+ zhead_t *z;
+
+ z = ((zhead_t *)ptr) - 1;
+
+ if (z->magic != Z_MAGIC)
+ Com_Error (ERR_FATAL, "Z_Free: bad magic");
+
+ z->prev->next = z->next;
+ z->next->prev = z->prev;
+
+ z_count--;
+ z_bytes -= z->size;
+ free (z);
+}
+
+
+/*
+========================
+Z_Stats_f
+========================
+*/
+void Z_Stats_f (void)
+{
+ Com_Printf ("%i bytes in %i blocks\n", z_bytes, z_count);
+}
+
+/*
+========================
+Z_FreeTags
+========================
+*/
+void Z_FreeTags (int tag)
+{
+ zhead_t *z, *next;
+
+ for (z=z_chain.next ; z != &z_chain ; z=next)
+ {
+ next = z->next;
+ if (z->tag == tag)
+ Z_Free ((void *)(z+1));
+ }
+}
+
+/*
+========================
+Z_TagMalloc
+========================
+*/
+void *Z_TagMalloc (int size, int tag)
+{
+ zhead_t *z;
+
+ size = size + sizeof(*z);
+ z = malloc(size);
+ if (!z)
+ Com_Error (ERR_FATAL, "Z_Malloc: failed on allocation of %i bytes",size);
+ memset (z, 0, size);
+ z_count++;
+ z_bytes += size;
+ z->magic = Z_MAGIC;
+ z->tag = tag;
+ z->size = size;
+
+ z->next = z_chain.next;
+ z->prev = &z_chain;
+ z_chain.next->prev = z;
+ z_chain.next = z;
+
+ return (void *)(z+1);
+}
+
+/*
+========================
+Z_Malloc
+========================
+*/
+void *Z_Malloc (int size)
+{
+ return Z_TagMalloc (size, 0);
+}
+
+
+//============================================================================
+
+
+/*
+====================
+COM_BlockSequenceCheckByte
+
+For proxy protecting
+
+// THIS IS MASSIVELY BROKEN! CHALLENGE MAY BE NEGATIVE
+// DON'T USE THIS FUNCTION!!!!!
+
+====================
+*/
+byte COM_BlockSequenceCheckByte (byte */*base*/, int /*length*/, int /*sequence*/, int /*challenge*/)
+{
+ Sys_Error("COM_BlockSequenceCheckByte called\n");
+
+/*
+ int checksum;
+ byte buf[68];
+ byte *p;
+ float temp;
+ byte c;
+
+ temp = bytedirs[(sequence/3) % NUMVERTEXNORMALS][sequence % 3];
+ temp = LittleFloat(temp);
+ p = ((byte *)&temp);
+
+ if (length > 60)
+ length = 60;
+ memcpy (buf, base, length);
+
+ buf[length] = (sequence & 0xff) ^ p[0];
+ buf[length+1] = p[1];
+ buf[length+2] = ((sequence>>8) & 0xff) ^ p[2];
+ buf[length+3] = p[3];
+
+ temp = bytedirs[((sequence+challenge)/3) % NUMVERTEXNORMALS][(sequence+challenge) % 3];
+ temp = LittleFloat(temp);
+ p = ((byte *)&temp);
+
+ buf[length+4] = (sequence & 0xff) ^ p[3];
+ buf[length+5] = (challenge & 0xff) ^ p[2];
+ buf[length+6] = ((sequence>>8) & 0xff) ^ p[1];
+ buf[length+7] = ((challenge >> 7) & 0xff) ^ p[0];
+
+ length += 8;
+
+ checksum = LittleLong(Com_BlockChecksum (buf, length));
+
+ checksum &= 0xff;
+
+ return checksum;
+*/
+ return 0;
+}
+
+static byte chktbl[1024] = {
+0x84, 0x47, 0x51, 0xc1, 0x93, 0x22, 0x21, 0x24, 0x2f, 0x66, 0x60, 0x4d, 0xb0, 0x7c, 0xda,
+0x88, 0x54, 0x15, 0x2b, 0xc6, 0x6c, 0x89, 0xc5, 0x9d, 0x48, 0xee, 0xe6, 0x8a, 0xb5, 0xf4,
+0xcb, 0xfb, 0xf1, 0x0c, 0x2e, 0xa0, 0xd7, 0xc9, 0x1f, 0xd6, 0x06, 0x9a, 0x09, 0x41, 0x54,
+0x67, 0x46, 0xc7, 0x74, 0xe3, 0xc8, 0xb6, 0x5d, 0xa6, 0x36, 0xc4, 0xab, 0x2c, 0x7e, 0x85,
+0xa8, 0xa4, 0xa6, 0x4d, 0x96, 0x19, 0x19, 0x9a, 0xcc, 0xd8, 0xac, 0x39, 0x5e, 0x3c, 0xf2,
+0xf5, 0x5a, 0x72, 0xe5, 0xa9, 0xd1, 0xb3, 0x23, 0x82, 0x6f, 0x29, 0xcb, 0xd1, 0xcc, 0x71,
+0xfb, 0xea, 0x92, 0xeb, 0x1c, 0xca, 0x4c, 0x70, 0xfe, 0x4d, 0xc9, 0x67, 0x43, 0x47, 0x94,
+0xb9, 0x47, 0xbc, 0x3f, 0x01, 0xab, 0x7b, 0xa6, 0xe2, 0x76, 0xef, 0x5a, 0x7a, 0x29, 0x0b,
+0x51, 0x54, 0x67, 0xd8, 0x1c, 0x14, 0x3e, 0x29, 0xec, 0xe9, 0x2d, 0x48, 0x67, 0xff, 0xed,
+0x54, 0x4f, 0x48, 0xc0, 0xaa, 0x61, 0xf7, 0x78, 0x12, 0x03, 0x7a, 0x9e, 0x8b, 0xcf, 0x83,
+0x7b, 0xae, 0xca, 0x7b, 0xd9, 0xe9, 0x53, 0x2a, 0xeb, 0xd2, 0xd8, 0xcd, 0xa3, 0x10, 0x25,
+0x78, 0x5a, 0xb5, 0x23, 0x06, 0x93, 0xb7, 0x84, 0xd2, 0xbd, 0x96, 0x75, 0xa5, 0x5e, 0xcf,
+0x4e, 0xe9, 0x50, 0xa1, 0xe6, 0x9d, 0xb1, 0xe3, 0x85, 0x66, 0x28, 0x4e, 0x43, 0xdc, 0x6e,
+0xbb, 0x33, 0x9e, 0xf3, 0x0d, 0x00, 0xc1, 0xcf, 0x67, 0x34, 0x06, 0x7c, 0x71, 0xe3, 0x63,
+0xb7, 0xb7, 0xdf, 0x92, 0xc4, 0xc2, 0x25, 0x5c, 0xff, 0xc3, 0x6e, 0xfc, 0xaa, 0x1e, 0x2a,
+0x48, 0x11, 0x1c, 0x36, 0x68, 0x78, 0x86, 0x79, 0x30, 0xc3, 0xd6, 0xde, 0xbc, 0x3a, 0x2a,
+0x6d, 0x1e, 0x46, 0xdd, 0xe0, 0x80, 0x1e, 0x44, 0x3b, 0x6f, 0xaf, 0x31, 0xda, 0xa2, 0xbd,
+0x77, 0x06, 0x56, 0xc0, 0xb7, 0x92, 0x4b, 0x37, 0xc0, 0xfc, 0xc2, 0xd5, 0xfb, 0xa8, 0xda,
+0xf5, 0x57, 0xa8, 0x18, 0xc0, 0xdf, 0xe7, 0xaa, 0x2a, 0xe0, 0x7c, 0x6f, 0x77, 0xb1, 0x26,
+0xba, 0xf9, 0x2e, 0x1d, 0x16, 0xcb, 0xb8, 0xa2, 0x44, 0xd5, 0x2f, 0x1a, 0x79, 0x74, 0x87,
+0x4b, 0x00, 0xc9, 0x4a, 0x3a, 0x65, 0x8f, 0xe6, 0x5d, 0xe5, 0x0a, 0x77, 0xd8, 0x1a, 0x14,
+0x41, 0x75, 0xb1, 0xe2, 0x50, 0x2c, 0x93, 0x38, 0x2b, 0x6d, 0xf3, 0xf6, 0xdb, 0x1f, 0xcd,
+0xff, 0x14, 0x70, 0xe7, 0x16, 0xe8, 0x3d, 0xf0, 0xe3, 0xbc, 0x5e, 0xb6, 0x3f, 0xcc, 0x81,
+0x24, 0x67, 0xf3, 0x97, 0x3b, 0xfe, 0x3a, 0x96, 0x85, 0xdf, 0xe4, 0x6e, 0x3c, 0x85, 0x05,
+0x0e, 0xa3, 0x2b, 0x07, 0xc8, 0xbf, 0xe5, 0x13, 0x82, 0x62, 0x08, 0x61, 0x69, 0x4b, 0x47,
+0x62, 0x73, 0x44, 0x64, 0x8e, 0xe2, 0x91, 0xa6, 0x9a, 0xb7, 0xe9, 0x04, 0xb6, 0x54, 0x0c,
+0xc5, 0xa9, 0x47, 0xa6, 0xc9, 0x08, 0xfe, 0x4e, 0xa6, 0xcc, 0x8a, 0x5b, 0x90, 0x6f, 0x2b,
+0x3f, 0xb6, 0x0a, 0x96, 0xc0, 0x78, 0x58, 0x3c, 0x76, 0x6d, 0x94, 0x1a, 0xe4, 0x4e, 0xb8,
+0x38, 0xbb, 0xf5, 0xeb, 0x29, 0xd8, 0xb0, 0xf3, 0x15, 0x1e, 0x99, 0x96, 0x3c, 0x5d, 0x63,
+0xd5, 0xb1, 0xad, 0x52, 0xb8, 0x55, 0x70, 0x75, 0x3e, 0x1a, 0xd5, 0xda, 0xf6, 0x7a, 0x48,
+0x7d, 0x44, 0x41, 0xf9, 0x11, 0xce, 0xd7, 0xca, 0xa5, 0x3d, 0x7a, 0x79, 0x7e, 0x7d, 0x25,
+0x1b, 0x77, 0xbc, 0xf7, 0xc7, 0x0f, 0x84, 0x95, 0x10, 0x92, 0x67, 0x15, 0x11, 0x5a, 0x5e,
+0x41, 0x66, 0x0f, 0x38, 0x03, 0xb2, 0xf1, 0x5d, 0xf8, 0xab, 0xc0, 0x02, 0x76, 0x84, 0x28,
+0xf4, 0x9d, 0x56, 0x46, 0x60, 0x20, 0xdb, 0x68, 0xa7, 0xbb, 0xee, 0xac, 0x15, 0x01, 0x2f,
+0x20, 0x09, 0xdb, 0xc0, 0x16, 0xa1, 0x89, 0xf9, 0x94, 0x59, 0x00, 0xc1, 0x76, 0xbf, 0xc1,
+0x4d, 0x5d, 0x2d, 0xa9, 0x85, 0x2c, 0xd6, 0xd3, 0x14, 0xcc, 0x02, 0xc3, 0xc2, 0xfa, 0x6b,
+0xb7, 0xa6, 0xef, 0xdd, 0x12, 0x26, 0xa4, 0x63, 0xe3, 0x62, 0xbd, 0x56, 0x8a, 0x52, 0x2b,
+0xb9, 0xdf, 0x09, 0xbc, 0x0e, 0x97, 0xa9, 0xb0, 0x82, 0x46, 0x08, 0xd5, 0x1a, 0x8e, 0x1b,
+0xa7, 0x90, 0x98, 0xb9, 0xbb, 0x3c, 0x17, 0x9a, 0xf2, 0x82, 0xba, 0x64, 0x0a, 0x7f, 0xca,
+0x5a, 0x8c, 0x7c, 0xd3, 0x79, 0x09, 0x5b, 0x26, 0xbb, 0xbd, 0x25, 0xdf, 0x3d, 0x6f, 0x9a,
+0x8f, 0xee, 0x21, 0x66, 0xb0, 0x8d, 0x84, 0x4c, 0x91, 0x45, 0xd4, 0x77, 0x4f, 0xb3, 0x8c,
+0xbc, 0xa8, 0x99, 0xaa, 0x19, 0x53, 0x7c, 0x02, 0x87, 0xbb, 0x0b, 0x7c, 0x1a, 0x2d, 0xdf,
+0x48, 0x44, 0x06, 0xd6, 0x7d, 0x0c, 0x2d, 0x35, 0x76, 0xae, 0xc4, 0x5f, 0x71, 0x85, 0x97,
+0xc4, 0x3d, 0xef, 0x52, 0xbe, 0x00, 0xe4, 0xcd, 0x49, 0xd1, 0xd1, 0x1c, 0x3c, 0xd0, 0x1c,
+0x42, 0xaf, 0xd4, 0xbd, 0x58, 0x34, 0x07, 0x32, 0xee, 0xb9, 0xb5, 0xea, 0xff, 0xd7, 0x8c,
+0x0d, 0x2e, 0x2f, 0xaf, 0x87, 0xbb, 0xe6, 0x52, 0x71, 0x22, 0xf5, 0x25, 0x17, 0xa1, 0x82,
+0x04, 0xc2, 0x4a, 0xbd, 0x57, 0xc6, 0xab, 0xc8, 0x35, 0x0c, 0x3c, 0xd9, 0xc2, 0x43, 0xdb,
+0x27, 0x92, 0xcf, 0xb8, 0x25, 0x60, 0xfa, 0x21, 0x3b, 0x04, 0x52, 0xc8, 0x96, 0xba, 0x74,
+0xe3, 0x67, 0x3e, 0x8e, 0x8d, 0x61, 0x90, 0x92, 0x59, 0xb6, 0x1a, 0x1c, 0x5e, 0x21, 0xc1,
+0x65, 0xe5, 0xa6, 0x34, 0x05, 0x6f, 0xc5, 0x60, 0xb1, 0x83, 0xc1, 0xd5, 0xd5, 0xed, 0xd9,
+0xc7, 0x11, 0x7b, 0x49, 0x7a, 0xf9, 0xf9, 0x84, 0x47, 0x9b, 0xe2, 0xa5, 0x82, 0xe0, 0xc2,
+0x88, 0xd0, 0xb2, 0x58, 0x88, 0x7f, 0x45, 0x09, 0x67, 0x74, 0x61, 0xbf, 0xe6, 0x40, 0xe2,
+0x9d, 0xc2, 0x47, 0x05, 0x89, 0xed, 0xcb, 0xbb, 0xb7, 0x27, 0xe7, 0xdc, 0x7a, 0xfd, 0xbf,
+0xa8, 0xd0, 0xaa, 0x10, 0x39, 0x3c, 0x20, 0xf0, 0xd3, 0x6e, 0xb1, 0x72, 0xf8, 0xe6, 0x0f,
+0xef, 0x37, 0xe5, 0x09, 0x33, 0x5a, 0x83, 0x43, 0x80, 0x4f, 0x65, 0x2f, 0x7c, 0x8c, 0x6a,
+0xa0, 0x82, 0x0c, 0xd4, 0xd4, 0xfa, 0x81, 0x60, 0x3d, 0xdf, 0x06, 0xf1, 0x5f, 0x08, 0x0d,
+0x6d, 0x43, 0xf2, 0xe3, 0x11, 0x7d, 0x80, 0x32, 0xc5, 0xfb, 0xc5, 0xd9, 0x27, 0xec, 0xc6,
+0x4e, 0x65, 0x27, 0x76, 0x87, 0xa6, 0xee, 0xee, 0xd7, 0x8b, 0xd1, 0xa0, 0x5c, 0xb0, 0x42,
+0x13, 0x0e, 0x95, 0x4a, 0xf2, 0x06, 0xc6, 0x43, 0x33, 0xf4, 0xc7, 0xf8, 0xe7, 0x1f, 0xdd,
+0xe4, 0x46, 0x4a, 0x70, 0x39, 0x6c, 0xd0, 0xed, 0xca, 0xbe, 0x60, 0x3b, 0xd1, 0x7b, 0x57,
+0x48, 0xe5, 0x3a, 0x79, 0xc1, 0x69, 0x33, 0x53, 0x1b, 0x80, 0xb8, 0x91, 0x7d, 0xb4, 0xf6,
+0x17, 0x1a, 0x1d, 0x5a, 0x32, 0xd6, 0xcc, 0x71, 0x29, 0x3f, 0x28, 0xbb, 0xf3, 0x5e, 0x71,
+0xb8, 0x43, 0xaf, 0xf8, 0xb9, 0x64, 0xef, 0xc4, 0xa5, 0x6c, 0x08, 0x53, 0xc7, 0x00, 0x10,
+0x39, 0x4f, 0xdd, 0xe4, 0xb6, 0x19, 0x27, 0xfb, 0xb8, 0xf5, 0x32, 0x73, 0xe5, 0xcb, 0x32
+};
+
+/*
+====================
+COM_BlockSequenceCRCByte
+
+For proxy protecting
+====================
+*/
+byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence)
+{
+ int n;
+ byte *p;
+ int x;
+ byte chkb[60 + 4];
+ unsigned short crc;
+
+
+ if (sequence < 0)
+ Sys_Error("sequence < 0, this shouldn't happen\n");
+
+ p = chktbl + (sequence % (sizeof(chktbl) - 4));
+
+ if (length > 60)
+ length = 60;
+ memcpy (chkb, base, length);
+
+ chkb[length] = p[0];
+ chkb[length+1] = p[1];
+ chkb[length+2] = p[2];
+ chkb[length+3] = p[3];
+
+ length += 4;
+
+ crc = CRC_Block(chkb, length);
+
+ for (x=0, n=0; n<length; n++)
+ x += chkb[n];
+
+ crc = (crc ^ x) & 0xff;
+
+ return crc;
+}
+
+//========================================================
+
+/* 0 to 1 */
+float qfrand(void)
+{
+ return (rand()&32767)* (1.0/32767);
+}
+
+/* -1 to 1 */
+float crand(void)
+{
+ return (rand()&32767)* (2.0/32767) - 1;
+}
+
+void Key_Init (void);
+void SCR_EndLoadingPlaque (void);
+
+/*
+=============
+Com_Error_f
+
+Just throw a fatal error to
+test error shutdown procedures
+=============
+*/
+void Com_Error_f (void)
+{
+ Com_Error (ERR_FATAL, "%s", Cmd_Argv(1));
+}
+
+
+/*
+=================
+Qcommon_Init
+=================
+*/
+void Qcommon_Init (int argc, char **argv)
+{
+ char *s;
+
+ if (setjmp (abortframe) )
+ Sys_Error ("Error during initialization");
+
+ z_chain.next = z_chain.prev = &z_chain;
+
+ // prepare enough of the subsystems to handle
+ // cvar and command buffer management
+ COM_InitArgv (argc, argv);
+
+ Swap_Init ();
+ Cbuf_Init ();
+
+ Cmd_Init ();
+ Cvar_Init ();
+
+ Key_Init ();
+
+ // we need to add the early commands twice, because
+ // a basedir or cddir needs to be set before execing
+ // config files, but we want other parms to override
+ // the settings of the config files
+ Cbuf_AddEarlyCommands (false);
+ Cbuf_Execute ();
+
+ FS_InitFilesystem ();
+
+ Cbuf_AddText ("exec default.cfg\n");
+ Cbuf_AddText ("exec config.cfg\n");
+
+ Cbuf_AddEarlyCommands (true);
+ Cbuf_Execute ();
+
+ //
+ // init commands and vars
+ //
+ Cmd_AddCommand ("z_stats", Z_Stats_f);
+ Cmd_AddCommand ("error", Com_Error_f);
+
+ host_speeds = Cvar_Get ("host_speeds", "0", 0);
+ log_stats = Cvar_Get ("log_stats", "0", 0);
+ developer = Cvar_Get ("developer", "0", 0);
+ timescale = Cvar_Get ("timescale", "1", 0);
+ fixedtime = Cvar_Get ("fixedtime", "0", 0);
+ logfile_active = Cvar_Get ("logfile", "0", 0);
+ showtrace = Cvar_Get ("showtrace", "0", 0);
+#ifdef DEDICATED_ONLY
+ dedicated = Cvar_Get ("dedicated", "1", CVAR_NOSET);
+#else
+ dedicated = Cvar_Get ("dedicated", "0", CVAR_NOSET);
+#endif
+
+ s = va("%4.2f 9front Nov 30 1997 9front", VERSION);
+ Cvar_Get ("version", s, CVAR_SERVERINFO|CVAR_NOSET);
+
+
+ if (dedicated->value)
+ Cmd_AddCommand ("quit", Com_Quit);
+
+ Sys_Init ();
+
+ NET_Init ();
+ Netchan_Init ();
+
+ SV_Init ();
+ CL_Init ();
+
+ // add + commands from command line
+ if (!Cbuf_AddLateCommands ())
+ { // if the user didn't give any commands, run default action
+ if (!dedicated->value)
+ Cbuf_AddText ("d1\n");
+ else
+ Cbuf_AddText ("dedicated_start\n");
+ Cbuf_Execute ();
+ }
+ else
+ { // the user asked for something explicit
+ // so drop the loading plaque
+ SCR_EndLoadingPlaque ();
+ }
+
+ Com_Printf ("====== Quake2 Initialized ======\n\n");
+}
+
+/*
+=================
+Qcommon_Frame
+=================
+*/
+void Qcommon_Frame (int msec)
+{
+ char *s;
+ int time_before = 0, time_between = 0, time_after = 0;
+
+ if (setjmp (abortframe) )
+ return; // an ERR_DROP was thrown
+
+ if ( log_stats->modified )
+ {
+ log_stats->modified = false;
+ if ( log_stats->value )
+ {
+ if ( log_stats_file )
+ {
+ fclose( log_stats_file );
+ log_stats_file = 0;
+ }
+ log_stats_file = fopen( "stats.log", "w" );
+ if ( log_stats_file )
+ fprintf( log_stats_file, "entities,dlights,parts,frame time\n" );
+ }
+ else
+ {
+ if ( log_stats_file )
+ {
+ fclose( log_stats_file );
+ log_stats_file = 0;
+ }
+ }
+ }
+
+ if (fixedtime->value)
+ msec = fixedtime->value;
+ else if (timescale->value)
+ {
+ msec *= timescale->value;
+ if (msec < 1)
+ msec = 1;
+ }
+
+ if (showtrace->value)
+ {
+ extern int c_traces, c_brush_traces;
+ extern int c_pointcontents;
+
+ Com_Printf ("%4i traces %4i points\n", c_traces, c_pointcontents);
+ c_traces = 0;
+ c_brush_traces = 0;
+ c_pointcontents = 0;
+ }
+
+ do
+ {
+ s = Sys_ConsoleInput ();
+ if (s)
+ Cbuf_AddText (va("%s\n",s));
+ } while (s);
+ Cbuf_Execute ();
+
+ if (host_speeds->value)
+ time_before = Sys_Milliseconds ();
+
+ SV_Frame (msec);
+
+ if (host_speeds->value)
+ time_between = Sys_Milliseconds ();
+
+ CL_Frame (msec);
+
+ if (host_speeds->value)
+ time_after = Sys_Milliseconds ();
+
+
+ if (host_speeds->value)
+ {
+ int all, sv, gm, cl, rf;
+
+ all = time_after - time_before;
+ sv = time_between - time_before;
+ cl = time_after - time_between;
+ gm = time_after_game - time_before_game;
+ rf = time_after_ref - time_before_ref;
+ sv -= gm;
+ cl -= rf;
+ Com_Printf ("all:%3i sv:%3i gm:%3i cl:%3i rf:%3i\n",
+ all, sv, gm, cl, rf);
+ }
+}
--- /dev/null
+++ b/console.c
@@ -1,0 +1,661 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+console_t con;
+
+cvar_t *con_notifytime;
+
+
+#define MAXCMDLINE 256
+extern char key_lines[32][MAXCMDLINE];
+extern int edit_line;
+extern int key_linepos;
+
+
+void DrawString (int x, int y, char *s)
+{
+ while (*s)
+ {
+ re.DrawChar (x, y, *s);
+ x+=8;
+ s++;
+ }
+}
+
+void DrawAltString (int x, int y, char *s)
+{
+ while (*s)
+ {
+ re.DrawChar (x, y, *s ^ 0x80);
+ x+=8;
+ s++;
+ }
+}
+
+
+void Key_ClearTyping (void)
+{
+ key_lines[edit_line][1] = 0; // clear any typing
+ key_linepos = 1;
+}
+
+/*
+================
+Con_ToggleConsole_f
+================
+*/
+void Con_ToggleConsole_f (void)
+{
+ SCR_EndLoadingPlaque (); // get rid of loading plaque
+
+ if (cl.attractloop)
+ {
+ Cbuf_AddText ("killserver\n");
+ return;
+ }
+
+ if (cls.state == ca_disconnected)
+ { // start the demo loop again
+ Cbuf_AddText ("d1\n");
+ return;
+ }
+
+ Key_ClearTyping ();
+ Con_ClearNotify ();
+
+ if (cls.key_dest == key_console)
+ {
+ M_ForceMenuOff ();
+ Cvar_Set ("paused", "0");
+ IN_Grabm (1);
+ }
+ else
+ {
+ M_ForceMenuOff ();
+ cls.key_dest = key_console;
+
+ if (Cvar_VariableValue ("maxclients") == 1
+ && Com_ServerState ())
+ Cvar_Set ("paused", "1");
+ IN_Grabm (0);
+ }
+}
+
+/*
+================
+Con_ToggleChat_f
+================
+*/
+void Con_ToggleChat_f (void)
+{
+ Key_ClearTyping ();
+
+ if (cls.key_dest == key_console)
+ {
+ if (cls.state == ca_active)
+ {
+ M_ForceMenuOff ();
+ cls.key_dest = key_game;
+ }
+ }
+ else
+ cls.key_dest = key_console;
+
+ Con_ClearNotify ();
+}
+
+/*
+================
+Con_Clear_f
+================
+*/
+void Con_Clear_f (void)
+{
+ memset (con.text, ' ', CON_TEXTSIZE);
+}
+
+
+/*
+================
+Con_Dump_f
+
+Save the console contents out to a file
+================
+*/
+void Con_Dump_f (void)
+{
+ int l, x;
+ char *line;
+ FILE *f;
+ char buffer[1024];
+ char name[MAX_OSPATH];
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("usage: condump <filename>\n");
+ return;
+ }
+
+ Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1));
+
+ Com_Printf ("Dumped console text to %s.\n", name);
+ FS_CreatePath (name);
+ f = fopen (name, "w");
+ if (!f)
+ {
+ Com_Printf ("ERROR: couldn't open.\n");
+ return;
+ }
+
+ // skip empty lines
+ for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
+ {
+ line = con.text + (l%con.totallines)*con.linewidth;
+ for (x=0 ; x<con.linewidth ; x++)
+ if (line[x] != ' ')
+ break;
+ if (x != con.linewidth)
+ break;
+ }
+
+ // write the remaining lines
+ buffer[con.linewidth] = 0;
+ for ( ; l <= con.current ; l++)
+ {
+ line = con.text + (l%con.totallines)*con.linewidth;
+ strncpy (buffer, line, con.linewidth);
+ for (x=con.linewidth-1 ; x>=0 ; x--)
+ {
+ if (buffer[x] == ' ')
+ buffer[x] = 0;
+ else
+ break;
+ }
+ for (x=0; buffer[x]; x++)
+ buffer[x] &= 0x7f;
+
+ fprintf (f, "%s\n", buffer);
+ }
+
+ fclose (f);
+}
+
+
+/*
+================
+Con_ClearNotify
+================
+*/
+void Con_ClearNotify (void)
+{
+ int i;
+
+ for (i=0 ; i<NUM_CON_TIMES ; i++)
+ con.times[i] = 0;
+}
+
+
+/*
+================
+Con_MessageMode_f
+================
+*/
+void Con_MessageMode_f (void)
+{
+ chat_team = false;
+ cls.key_dest = key_message;
+}
+
+/*
+================
+Con_MessageMode2_f
+================
+*/
+void Con_MessageMode2_f (void)
+{
+ chat_team = true;
+ cls.key_dest = key_message;
+}
+
+/*
+================
+Con_CheckResize
+
+If the line width has changed, reformat the buffer.
+================
+*/
+void Con_CheckResize (void)
+{
+ int i, j, width, oldwidth, oldtotallines, numlines, numchars;
+ char tbuf[CON_TEXTSIZE];
+
+ width = (vid.width >> 3) - 2;
+
+ if (width == con.linewidth)
+ return;
+
+ if (width < 1) // video hasn't been initialized yet
+ {
+ width = 38;
+ con.linewidth = width;
+ con.totallines = CON_TEXTSIZE / con.linewidth;
+ memset (con.text, ' ', CON_TEXTSIZE);
+ }
+ else
+ {
+ oldwidth = con.linewidth;
+ con.linewidth = width;
+ oldtotallines = con.totallines;
+ con.totallines = CON_TEXTSIZE / con.linewidth;
+ numlines = oldtotallines;
+
+ if (con.totallines < numlines)
+ numlines = con.totallines;
+
+ numchars = oldwidth;
+
+ if (con.linewidth < numchars)
+ numchars = con.linewidth;
+
+ memcpy (tbuf, con.text, CON_TEXTSIZE);
+ memset (con.text, ' ', CON_TEXTSIZE);
+
+ for (i=0 ; i<numlines ; i++)
+ {
+ for (j=0 ; j<numchars ; j++)
+ {
+ con.text[(con.totallines - 1 - i) * con.linewidth + j] =
+ tbuf[((con.current - i + oldtotallines) %
+ oldtotallines) * oldwidth + j];
+ }
+ }
+
+ Con_ClearNotify ();
+ }
+
+ con.current = con.totallines - 1;
+ con.display = con.current;
+}
+
+
+/*
+================
+Con_Init
+================
+*/
+void Con_Init (void)
+{
+ con.linewidth = -1;
+
+ Con_CheckResize ();
+
+ Com_Printf ("Console initialized.\n");
+
+//
+// register our commands
+//
+ con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
+
+ Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
+ Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
+ Cmd_AddCommand ("messagemode", Con_MessageMode_f);
+ Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
+ Cmd_AddCommand ("clear", Con_Clear_f);
+ Cmd_AddCommand ("condump", Con_Dump_f);
+ con.initialized = true;
+}
+
+
+/*
+===============
+Con_Linefeed
+===============
+*/
+void Con_Linefeed (void)
+{
+ con.x = 0;
+ if (con.display == con.current)
+ con.display++;
+ con.current++;
+ memset (&con.text[(con.current%con.totallines)*con.linewidth]
+ , ' ', con.linewidth);
+}
+
+/*
+================
+Con_Print
+
+Handles cursor positioning, line wrapping, etc
+All console printing must go through this in order to be logged to disk
+If no console is visible, the text will appear at the top of the game window
+================
+*/
+void Con_Print (char *txt)
+{
+ int y;
+ int c, l;
+ static int cr;
+ int mask;
+
+ if (!con.initialized)
+ return;
+
+ if (txt[0] == 1 || txt[0] == 2)
+ {
+ mask = 128; // go to colored text
+ txt++;
+ }
+ else
+ mask = 0;
+
+
+ while ( (c = *txt) )
+ {
+ // count word length
+ for (l=0 ; l< con.linewidth ; l++)
+ if ( txt[l] <= ' ')
+ break;
+
+ // word wrap
+ if (l != con.linewidth && (con.x + l > con.linewidth) )
+ con.x = 0;
+
+ txt++;
+
+ if (cr)
+ {
+ con.current--;
+ cr = false;
+ }
+
+
+ if (!con.x)
+ {
+ Con_Linefeed ();
+ // mark time for transparent overlay
+ if (con.current >= 0)
+ con.times[con.current % NUM_CON_TIMES] = cls.realtime;
+ }
+
+ switch (c)
+ {
+ case '\n':
+ con.x = 0;
+ break;
+
+ case '\r':
+ con.x = 0;
+ cr = 1;
+ break;
+
+ default: // display character and advance
+ y = con.current % con.totallines;
+ con.text[y*con.linewidth+con.x] = c | mask | con.ormask;
+ con.x++;
+ if (con.x >= con.linewidth)
+ con.x = 0;
+ break;
+ }
+
+ }
+}
+
+
+/*
+==============
+Con_CenteredPrint
+==============
+*/
+void Con_CenteredPrint (char *text)
+{
+ int l;
+ char buffer[1024];
+
+ l = strlen(text);
+ l = (con.linewidth-l)/2;
+ if (l < 0)
+ l = 0;
+ memset (buffer, ' ', l);
+ strcpy (buffer+l, text);
+ strcat (buffer, "\n");
+ Con_Print (buffer);
+}
+
+/*
+==============================================================================
+
+DRAWING
+
+==============================================================================
+*/
+
+
+/*
+================
+Con_DrawInput
+
+The input line scrolls horizontally if typing goes beyond the right edge
+================
+*/
+void Con_DrawInput (void)
+{
+ int i;
+ char *text;
+
+ if (cls.key_dest == key_menu)
+ return;
+ if (cls.key_dest != key_console && cls.state == ca_active)
+ return; // don't draw anything (always draw if not active)
+
+ text = key_lines[edit_line];
+
+// add the cursor frame
+ text[key_linepos] = 10+((int)(cls.realtime>>8)&1);
+
+// fill out remainder with spaces
+ for (i=key_linepos+1 ; i< con.linewidth ; i++)
+ text[i] = ' ';
+
+// prestep if horizontally scrolling
+ if (key_linepos >= con.linewidth)
+ text += 1 + key_linepos - con.linewidth;
+
+// draw it
+ for (i=0 ; i<con.linewidth ; i++)
+ re.DrawChar ( (i+1)<<3, con.vislines - 22, text[i]);
+
+// remove cursor
+ key_lines[edit_line][key_linepos] = 0;
+}
+
+
+/*
+================
+Con_DrawNotify
+
+Draws the last few lines of output transparently over the game top
+================
+*/
+void Con_DrawNotify (void)
+{
+ int x, v;
+ char *text;
+ int i;
+ int time;
+ char *s;
+ int skip;
+
+ v = 0;
+ for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
+ {
+ if (i < 0)
+ continue;
+ time = con.times[i % NUM_CON_TIMES];
+ if (time == 0)
+ continue;
+ time = cls.realtime - time;
+ if (time > con_notifytime->value*1000)
+ continue;
+ text = con.text + (i % con.totallines)*con.linewidth;
+
+ for (x = 0 ; x < con.linewidth ; x++)
+ re.DrawChar ( (x+1)<<3, v, text[x]);
+
+ v += 8;
+ }
+
+
+ if (cls.key_dest == key_message)
+ {
+ if (chat_team)
+ {
+ DrawString (8, v, "say_team:");
+ skip = 11;
+ }
+ else
+ {
+ DrawString (8, v, "say:");
+ skip = 5;
+ }
+
+ s = chat_buffer;
+ if (chat_bufferlen > (vid.width>>3)-(skip+1))
+ s += chat_bufferlen - ((vid.width>>3)-(skip+1));
+ x = 0;
+ while(s[x])
+ {
+ re.DrawChar ( (x+skip)<<3, v, s[x]);
+ x++;
+ }
+ re.DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1));
+ v += 8;
+ }
+
+ if (v)
+ {
+ SCR_AddDirtyPoint (0,0);
+ SCR_AddDirtyPoint (vid.width-1, v);
+ }
+}
+
+/*
+================
+Con_DrawConsole
+
+Draws the console with the solid background
+================
+*/
+void Con_DrawConsole (float frac)
+{
+ int i, j, x, y, n;
+ int rows;
+ char *text;
+ int row;
+ int lines;
+ char version[64];
+ char dlbar[1024];
+
+ lines = vid.height * frac;
+ if (lines <= 0)
+ return;
+
+ if (lines > vid.height)
+ lines = vid.height;
+
+// draw the background
+ re.DrawStretchPic (0, -vid.height+lines, vid.width, vid.height, "conback");
+ SCR_AddDirtyPoint (0,0);
+ SCR_AddDirtyPoint (vid.width-1,lines-1);
+
+ Com_sprintf (version, sizeof(version), "v%4.2f", VERSION);
+ for (x=0 ; x<5 ; x++)
+ re.DrawChar (vid.width-44+x*8, lines-12, 128 + version[x] );
+
+// draw the text
+ con.vislines = lines;
+
+/*
+ rows = (lines-8)>>3; // rows of text to draw
+
+ y = lines - 24;
+*/
+ rows = (lines-22)>>3; // rows of text to draw
+
+ y = lines - 30;
+
+// draw from the bottom up
+ if (con.display != con.current)
+ {
+ // draw arrows to show the buffer is backscrolled
+ for (x=0 ; x<con.linewidth ; x+=4)
+ re.DrawChar ( (x+1)<<3, y, '^');
+
+ y -= 8;
+ rows--;
+ }
+
+ row = con.display;
+ for (i=0 ; i<rows ; i++, y-=8, row--)
+ {
+ if (row < 0)
+ break;
+ if (con.current - row >= con.totallines)
+ break; // past scrollback wrap point
+
+ text = con.text + (row % con.totallines)*con.linewidth;
+
+ for (x=0 ; x<con.linewidth ; x++)
+ re.DrawChar ( (x+1)<<3, y, text[x]);
+ }
+
+//ZOID
+ // draw the download bar
+ // figure out width
+ if (cls.download) {
+ if ((text = strrchr(cls.downloadname, '/')) != NULL)
+ text++;
+ else
+ text = cls.downloadname;
+
+ x = con.linewidth - ((con.linewidth * 7) / 40);
+ y = x - strlen(text) - 8;
+ i = con.linewidth/3;
+ if (strlen(text) > i) {
+ y = x - i - 11;
+ strncpy(dlbar, text, i);
+ dlbar[i] = 0;
+ strcat(dlbar, "...");
+ } else
+ strcpy(dlbar, text);
+ strcat(dlbar, ": ");
+ i = strlen(dlbar);
+ dlbar[i++] = 0x80;
+ // where's the dot go?
+ if (cls.downloadpercent == 0)
+ n = 0;
+ else
+ n = y * cls.downloadpercent / 100;
+
+ for (j = 0; j < y; j++)
+ if (j == n)
+ dlbar[i++] = 0x83;
+ else
+ dlbar[i++] = 0x81;
+ dlbar[i++] = 0x82;
+ dlbar[i] = 0;
+
+ sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
+
+ // draw it
+ y = con.vislines-12;
+ for (i = 0; i < strlen(dlbar); i++)
+ re.DrawChar ( (i+1)<<3, y, dlbar[i]);
+ }
+//ZOID
+
+// draw the input prompt, user text, and cursor if desired
+ Con_DrawInput ();
+}
--- /dev/null
+++ b/crc.c
@@ -1,0 +1,75 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
+// and the initial and final xor values shown below... in other words, the
+// CCITT standard CRC used by XMODEM
+
+#define CRC_INIT_VALUE 0xffff
+#define CRC_XOR_VALUE 0x0000
+
+static unsigned short crctable[256] =
+{
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+void CRC_Init(unsigned short *crcvalue)
+{
+ *crcvalue = CRC_INIT_VALUE;
+}
+
+void CRC_ProcessByte(unsigned short *crcvalue, byte data)
+{
+ *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
+}
+
+unsigned short CRC_Value(unsigned short crcvalue)
+{
+ return crcvalue ^ CRC_XOR_VALUE;
+}
+
+unsigned short CRC_Block (byte *start, int count)
+{
+ unsigned short crc;
+
+ CRC_Init (&crc);
+ while (count--)
+ crc = (crc << 8) ^ crctable[(crc >> 8) ^ *start++];
+
+ return crc;
+}
+
--- a/ctf/g_ai.c
+++ b/ctf/g_ai.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
qboolean FindTarget (edict_t *self);
extern cvar_t *maxclients;
--- a/ctf/g_chase.c
+++ b/ctf/g_chase.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
void UpdateChaseCam(edict_t *ent)
--- a/ctf/g_cmds.c
+++ b/ctf/g_cmds.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
#include "m_player.h"
--- a/ctf/g_combat.c
+++ b/ctf/g_combat.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*
============
--- a/ctf/g_ctf.c
+++ b/ctf/g_ctf.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
#include "m_player.h"
typedef enum match_s {
--- a/ctf/g_func.c
+++ b/ctf/g_func.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*
=========================================================
--- a/ctf/g_items.c
+++ b/ctf/g_items.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
qboolean Pickup_Weapon (edict_t *ent, edict_t *other);
--- a/ctf/g_main.c
+++ b/ctf/g_main.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
game_locals_t game;
level_locals_t level;
--- a/ctf/g_misc.c
+++ b/ctf/g_misc.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*QUAKED func_group (0 0 0) ?
--- a/ctf/g_monster.c
+++ b/ctf/g_monster.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
//
--- a/ctf/g_phys.c
+++ b/ctf/g_phys.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*
--- a/ctf/g_save.c
+++ b/ctf/g_save.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
field_t fields[] = {
{"classname", FOFS(classname), F_LSTRING},
--- a/ctf/g_spawn.c
+++ b/ctf/g_spawn.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
typedef struct
{
--- a/ctf/g_svcmds.c
+++ b/ctf/g_svcmds.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
void Svcmd_Test_f (void)
--- a/ctf/g_target.c
+++ b/ctf/g_target.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8)
Fire an origin based temp entity event to the clients.
--- a/ctf/g_trigger.c
+++ b/ctf/g_trigger.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
void InitTrigger (edict_t *self)
--- a/ctf/g_utils.c
+++ b/ctf/g_utils.c
@@ -1,8 +1,9 @@
+#include <u.h>
+#include <libc.h>
// g_utils.c -- misc utility functions for game module
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
--- a/ctf/g_weapon.c
+++ b/ctf/g_weapon.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*
--- a/ctf/m_move.c
+++ b/ctf/m_move.c
@@ -1,8 +1,9 @@
+#include <u.h>
+#include <libc.h>
// m_move.c -- monster movement
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
#define STEPSIZE 18
--- a/ctf/p_client.c
+++ b/ctf/p_client.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
#include "m_player.h"
void ClientUserinfoChanged (edict_t *ent, char *userinfo);
--- a/ctf/p_hud.c
+++ b/ctf/p_hud.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
--- a/ctf/p_menu.c
+++ b/ctf/p_menu.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
// Note that the pmenu entries are duplicated
// this is so that a static set of pmenu entries can be used
--- a/ctf/p_trail.c
+++ b/ctf/p_trail.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*
--- a/ctf/p_view.c
+++ b/ctf/p_view.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
#include "m_player.h"
--- a/ctf/p_weapon.c
+++ b/ctf/p_weapon.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
#include "m_player.h"
--- a/ctf/q_shared.c
+++ b/ctf/q_shared.c
@@ -1,3 +1,5 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
@@ -249,7 +251,7 @@
// this is the slow, general version
-int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, cplane_t *p)
{
int i;
float dist1, dist2;
@@ -287,7 +289,7 @@
Returns 1, 2, or 1 + 2
==================
*/
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, cplane_t *p)
{
float dist1, dist2;
int sides;
--- /dev/null
+++ b/cvar.c
@@ -1,0 +1,387 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/* Dynamic variable tracking
+ *
+ * cvar_t variables are used to hold scalar or string variables that can be
+ * changed or displayed at the console or prog code as well as accessed
+ * directly in C code. The user can access cvars from the console in three ways:
+ * r_draworder prints the current value
+ * r_draworder 0 sets the current value to 0
+ * set r_draworder 0 as above, but creates the cvar if not present
+ * Cvars are restricted from having the same names as commands to keep this
+ * interface from being ambiguous. */
+
+cvar_t *cvar_vars;
+
+/* if set, each time a CVAR_USERINFO var is changed, the client will send it
+ * to the server */
+qboolean userinfo_modified;
+
+
+static qboolean
+Cvar_InfoValidate(char *s)
+{
+ if(strstr(s, "\\"))
+ return false;
+ if(strstr(s, "\""))
+ return false;
+ if(strstr(s, ";"))
+ return false;
+ return true;
+}
+
+static cvar_t *
+Cvar_FindVar(char *name)
+{
+ cvar_t *p;
+
+ for(p = cvar_vars; p != nil; p = p->next)
+ if(!strcmp(name, p->name))
+ return p;
+ return nil;
+}
+
+float
+Cvar_VariableValue(char *name)
+{
+ cvar_t *p;
+
+ if((p = Cvar_FindVar(name)) == nil)
+ return 0;
+ return atof(p->string);
+}
+
+char *
+Cvar_VariableString(char *name)
+{
+ cvar_t *p;
+
+ if((p = Cvar_FindVar(name)) == nil)
+ return "";
+ return p->string;
+}
+
+char *
+Cvar_CompleteVariable(char *partial)
+{
+ cvar_t *p;
+ int len;
+
+ len = strlen(partial);
+ if(!len)
+ return nil;
+
+ /* check exact match */
+ for(p = cvar_vars; p != nil; p = p->next)
+ if(!strcmp(partial, p->name))
+ return p->name;
+ /* check partial match */
+ for(p = cvar_vars; p != nil; p = p->next)
+ if(!strncmp(partial, p->name, len))
+ return p->name;
+ return nil;
+}
+
+/* If the variable already exists, the value will not be set. The flags will be
+ * or'ed in if the variable exists. */
+cvar_t *
+Cvar_Get(char *var_name, char *var_value, int flags)
+{
+ cvar_t *p;
+
+ if(flags & (CVAR_USERINFO|CVAR_SERVERINFO)){
+ if(!Cvar_InfoValidate(var_name)){
+ Com_Printf("invalid info cvar name\n");
+ return nil;
+ }
+ }
+
+ if((p = Cvar_FindVar(var_name)) != nil){
+ p->flags |= flags;
+ return p;
+ }
+
+ if(!var_value)
+ return nil;
+
+ if(flags & (CVAR_USERINFO|CVAR_SERVERINFO)){
+ if(!Cvar_InfoValidate(var_value)){
+ Com_Printf("invalid info cvar value\n");
+ return nil;
+ }
+ }
+
+ p = Z_Malloc(sizeof(*p));
+ p->name = CopyString(var_name);
+ p->string = CopyString(var_value);
+ p->modified = true;
+ p->value = atof(p->string);
+ p->next = cvar_vars;
+ cvar_vars = p;
+ p->flags = flags;
+ return p;
+}
+
+cvar_t *
+Cvar_Set2(char *var_name, char *value, qboolean force)
+{
+ cvar_t *var;
+
+ var = Cvar_FindVar(var_name);
+ if(!var)
+ return Cvar_Get(var_name, value, 0); // create it
+
+ if(var->flags & (CVAR_USERINFO|CVAR_SERVERINFO)){
+ if(!Cvar_InfoValidate(value)){
+ Com_Printf("invalid info cvar value\n");
+ return var;
+ }
+ }
+ if(!force){
+ if(var->flags & CVAR_NOSET){
+ Com_Printf("%s is write protected.\n", var_name);
+ return var;
+ }
+ if(var->flags & CVAR_LATCH){
+ if(var->latched_string){
+ if(!strcmp(value, var->latched_string))
+ return var;
+ Z_Free(var->latched_string);
+ }else if(!strcmp(value, var->string))
+ return var;
+
+ if(Com_ServerState()){
+ Com_Printf("%s will be changed for next game.\n", var_name);
+ var->latched_string = CopyString(value);
+ }else{
+ var->string = CopyString(value);
+ var->value = atof(var->string);
+ if(!strcmp(var->name, "game")){
+ FS_SetGamedir(var->string);
+ FS_ExecAutoexec();
+ }
+ }
+ return var;
+ }
+ }else{
+ if(var->latched_string){
+ Z_Free(var->latched_string);
+ var->latched_string = nil;
+ }
+ }
+
+ if(!strcmp(value, var->string))
+ return var; // not changed
+
+ var->modified = true;
+
+ if(var->flags & CVAR_USERINFO)
+ userinfo_modified = true; // transmit at next oportunity
+
+ Z_Free(var->string); // free the old value string
+ var->string = CopyString(value);
+ var->value = atof(var->string);
+ return var;
+}
+
+/* set the variable even if NOSET or LATCH */
+cvar_t *
+Cvar_ForceSet(char *var_name, char *value)
+{
+ return Cvar_Set2(var_name, value, true);
+}
+
+cvar_t *
+Cvar_Set(char *var_name, char *value)
+{
+ return Cvar_Set2(var_name, value, false);
+}
+
+cvar_t *
+Cvar_FullSet(char *var_name, char *value, int flags)
+{
+ cvar_t *var;
+
+ var = Cvar_FindVar(var_name);
+ if(!var)
+ return Cvar_Get(var_name, value, flags); // create it
+
+ var->modified = true;
+
+ if(var->flags & CVAR_USERINFO)
+ userinfo_modified = true; // transmit at next oportunity
+
+ Z_Free(var->string); // free the old value string
+ var->string = CopyString(value);
+ var->value = atof(var->string);
+ var->flags = flags;
+ return var;
+}
+
+void
+Cvar_SetValue(char *var_name, float value)
+{
+ char val[32];
+
+ if(value == (int)value)
+ Com_sprintf(val, sizeof val, "%d", (int)value);
+ else
+ Com_sprintf(val, sizeof val, "%f", value);
+ Cvar_Set(var_name, val);
+}
+
+/* Any variables with latched values will now be updated */
+void
+Cvar_GetLatchedVars(void)
+{
+ cvar_t *p;
+
+ for(p = cvar_vars; p != nil; p = p->next){
+ if(!p->latched_string)
+ continue;
+ Z_Free(p->string);
+ p->string = p->latched_string;
+ p->latched_string = nil;
+ p->value = atof(p->string);
+ if(!strcmp(p->name, "game")){
+ FS_SetGamedir(p->string);
+ FS_ExecAutoexec();
+ }
+ }
+}
+
+/* called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known command.
+ * Returns true if the command was a variable reference that was handled (print
+ * or change). */
+qboolean
+Cvar_Command(void)
+{
+ cvar_t *p;
+
+ /* check variables */
+ if((p = Cvar_FindVar(Cmd_Argv(0))) == nil)
+ return false;
+
+ /* perform a variable print or set */
+ if(Cmd_Argc() == 1){
+ Com_Printf("\"%s\" is \"%s\"\n", p->name, p->string);
+ return true;
+ }
+
+ Cvar_Set(p->name, Cmd_Argv(1));
+ return true;
+}
+
+/* Allows setting and defining of arbitrary cvars from console */
+void
+Cvar_Set_f(void)
+{
+ int c;
+ int flags;
+
+ c = Cmd_Argc();
+ if(c != 3 && c != 4){
+ Com_Printf("usage: set <variable> <value> [u / s]\n");
+ return;
+ }
+ if(c == 4){
+ if(!strcmp(Cmd_Argv(3), "u"))
+ flags = CVAR_USERINFO;
+ else if(!strcmp(Cmd_Argv(3), "s"))
+ flags = CVAR_SERVERINFO;
+ else{
+ Com_Printf("flags can only be 'u' or 's'\n");
+ return;
+ }
+ Cvar_FullSet(Cmd_Argv(1), Cmd_Argv(2), flags);
+ }else
+ Cvar_Set(Cmd_Argv(1), Cmd_Argv(2));
+}
+
+/* Appends lines containing "set variable value" for all variables with the
+ * archive flag set to true. */
+void
+Cvar_WriteVariables(char *path)
+{
+ int fd;
+ cvar_t *p;
+
+ if((fd = open(path, OWRITE)) < 0){
+ fprint(2, "Cvar_WriteVariables:open: %r\n");
+ return;
+ }
+ seek(fd, 0, 2);
+ for(p = cvar_vars; p != nil; p = p->next)
+ if(p->flags & CVAR_ARCHIVE)
+ if(fprint(fd, "set %s \"%s\"\n", p->name, p->string) < 0)
+ sysfatal("Cvar_WriteVariables:fprint: %r");
+ close(fd);
+}
+
+void
+Cvar_List_f(void)
+{
+ cvar_t *p;
+ int i;
+
+ for(p = cvar_vars, i = 0; p != nil; p = p->next, i++){
+ if(p->flags & CVAR_ARCHIVE)
+ Com_Printf("*");
+ else
+ Com_Printf(" ");
+ if(p->flags & CVAR_USERINFO)
+ Com_Printf("U");
+ else
+ Com_Printf(" ");
+ if(p->flags & CVAR_SERVERINFO)
+ Com_Printf("S");
+ else
+ Com_Printf(" ");
+ if(p->flags & CVAR_NOSET)
+ Com_Printf("-");
+ else if(p->flags & CVAR_LATCH)
+ Com_Printf("L");
+ else
+ Com_Printf(" ");
+ Com_Printf(" %s \"%s\"\n", p->name, p->string);
+ }
+ Com_Printf("%d cvars\n", i);
+}
+
+char *
+Cvar_BitInfo(int bit)
+{
+ static char info[MAX_INFO_STRING];
+ cvar_t *p;
+
+ info[0] = 0;
+ for(p = cvar_vars; p != nil; p = p->next)
+ if(p->flags & bit)
+ Info_SetValueForKey(info, p->name, p->string);
+ return info;
+}
+
+/* returns an info string containing all the CVAR_USERINFO cvars */
+char *
+Cvar_Userinfo(void)
+{
+ return Cvar_BitInfo(CVAR_USERINFO);
+}
+
+/* returns an info string containing all the CVAR_SERVERINFO cvars */
+char *
+Cvar_Serverinfo(void)
+{
+ return Cvar_BitInfo(CVAR_SERVERINFO);
+}
+
+void
+Cvar_Init(void)
+{
+ Cmd_AddCommand("set", Cvar_Set_f);
+ Cmd_AddCommand("cvarlist", Cvar_List_f);
+}
--- /dev/null
+++ b/dat.h
@@ -1,0 +1,2931 @@
+//#define PARANOID // speed sapping error checking
+//#define SMALL_FINALVERT
+
+typedef uchar byte;
+typedef float vec_t;
+typedef vec_t vec3_t[3];
+typedef vec_t vec5_t[5];
+typedef int fixed4_t;
+typedef int fixed8_t;
+typedef int fixed16_t;
+typedef uchar pixel_t;
+
+typedef enum qboolean {false, true} qboolean;
+
+typedef struct edict_t edict_t;
+typedef struct cvar_t cvar_t;
+typedef struct cplane_t cplane_t;
+typedef struct cmodel_t cmodel_t;
+typedef struct csurface_t csurface_t;
+typedef struct mapsurface_t mapsurface_t;
+typedef struct trace_t trace_t;
+typedef struct pmove_state_t pmove_state_t;
+typedef struct usercmd_t usercmd_t;
+typedef struct pmove_t pmove_t;
+typedef struct entity_state_t entity_state_t;
+typedef struct player_state_t player_state_t;
+typedef struct sizebuf_t sizebuf_t;
+typedef struct netadr_t netadr_t;
+typedef struct netchan_t netchan_t;
+typedef struct dpackfile_t dpackfile_t;
+typedef struct dpackheader_t dpackheader_t;
+typedef struct pcx_t pcx_t;
+typedef struct dstvert_t dstvert_t;
+typedef struct dtriangle_t dtriangle_t;
+typedef struct dtrivertx_t dtrivertx_t;
+typedef struct daliasframe_t daliasframe_t;
+typedef struct dmdl_t dmdl_t;
+typedef struct dsprframe_t dsprframe_t;
+typedef struct dsprite_t dsprite_t;
+typedef struct miptex_t miptex_t;
+typedef struct lump_t lump_t;
+typedef struct dheader_t dheader_t;
+typedef struct dmodel_t dmodel_t;
+typedef struct dvertex_t dvertex_t;
+typedef struct dplane_t dplane_t;
+typedef struct dnode_t dnode_t;
+typedef struct texinfo_t texinfo_t;
+typedef struct dedge_t dedge_t;
+typedef struct dface_t dface_t;
+typedef struct dleaf_t dleaf_t;
+typedef struct dbrushside_t dbrushside_t;
+typedef struct dbrush_t dbrush_t;
+typedef struct dvis_t dvis_t;
+typedef struct dareaportal_t dareaportal_t;
+typedef struct darea_t darea_t;
+typedef struct vrect_t vrect_t;
+typedef struct viddef_t viddef_t;
+typedef struct image_t image_t;
+typedef struct oldrefdef_t oldrefdef_t;
+typedef struct mvertex_t mvertex_t;
+typedef struct mplane_t mplane_t;
+typedef struct medge_t medge_t;
+typedef struct mtexinfo_t mtexinfo_t;
+typedef struct msurface_t msurface_t;
+typedef struct mnode_t mnode_t;
+typedef struct mleaf_t mleaf_t;
+typedef struct model_t model_t;
+typedef struct emitpoint_t emitpoint_t;
+typedef struct finalvert_t finalvert_t;
+typedef struct affinetridesc_t affinetridesc_t;
+typedef struct drawsurf_t drawsurf_t;
+typedef struct alight_t alight_t;
+typedef struct bedge_t bedge_t;
+typedef struct clipplane_t clipplane_t;
+typedef struct surfcache_t surfcache_t;
+typedef struct espan_t espan_t;
+typedef struct polydesc_t polydesc_t;
+typedef struct surf_t surf_t;
+typedef struct edge_t edge_t;
+typedef struct aliastriangleparms_t aliastriangleparms_t;
+typedef struct swstate_t swstate_t;
+typedef struct entity_t entity_t;
+typedef struct dlight_t dlight_t;
+typedef struct particle_t particle_t;
+typedef struct lightstyle_t lightstyle_t;
+typedef struct refdef_t refdef_t;
+typedef struct refexport_t refexport_t;
+typedef struct refimport_t refimport_t;
+typedef struct portable_samplepair_t portable_samplepair_t;
+typedef struct sfxcache_t sfxcache_t;
+typedef struct sfx_t sfx_t;
+typedef struct playsound_t playsound_t;
+typedef struct dma_t dma_t;
+typedef struct channel_t channel_t;
+typedef struct wavinfo_t wavinfo_t;
+typedef struct console_t console_t;
+typedef struct frame_t frame_t;
+typedef struct centity_t centity_t;
+typedef struct clientinfo_t clientinfo_t;
+typedef struct client_state_t client_state_t;
+typedef struct client_static_t client_static_t;
+typedef struct cdlight_t cdlight_t;
+typedef struct cl_sustain_t cl_sustain_t;
+typedef struct cparticle_t cparticle_t;
+typedef struct kbutton_t kbutton_t;
+typedef struct menuframework_t menuframework_t;
+typedef struct menucommon_t menucommon_t;
+typedef struct menufield_t menufield_t;
+typedef struct menuslider_t menuslider_t;
+typedef struct menulist_t menulist_t;
+typedef struct menuaction_t menuaction_t;
+typedef struct menuseparator_t menuseparator_t;
+typedef struct server_t server_t;
+typedef struct client_frame_t client_frame_t;
+typedef struct client_t client_t;
+typedef struct challenge_t challenge_t;
+typedef struct server_static_t server_static_t;
+
+typedef void (*xcommand_t)(void);
+typedef refexport_t (*GetRefAPI_t)(refimport_t);
+
+enum{
+ /* angle indexes */
+ PITCH = 0,
+ YAW = 1,
+ ROLL = 2,
+
+ MAX_STRING_CHARS = 1024, // char* passed to Cmd_TokenizeString, max strlen
+ MAX_STRING_TOKENS = 80, // max tokens resulting from Cmd_TokenizeString
+ MAX_TOKEN_CHARS = 128, // max length of an individual token
+
+ /* max length of quake game and fs pathname */
+ MAX_QPATH = 64,
+ MAX_OSPATH = 128,
+
+ /* per-level limits */
+ MAX_CLIENTS = 256, // absolute limit
+ MAX_EDICTS = 1024, // must change protocol to increase more
+ MAX_LIGHTSTYLES = 256,
+
+ /* these are sent over the net as bytes so they cannot be blindly increased */
+ MAX_MODELS = 256,
+ MAX_SOUNDS = 256,
+ MAX_IMAGES = 256,
+ MAX_ITEMS = 256,
+
+ MAX_GENERAL = MAX_CLIENTS*2, // general config strings
+
+ /* game print flags */
+ PRINT_LOW = 0, // pickup messages
+ PRINT_MEDIUM = 1, // death messages
+ PRINT_HIGH = 2, // critical messages
+ PRINT_CHAT = 3, // chat messages
+
+ /* key / value info strings */
+ MAX_INFO_KEY = 64,
+ MAX_INFO_VALUE = 64,
+ MAX_INFO_STRING = 512,
+
+ MAX_PARSE_ENTITIES = 1024,
+};
+
+/* destination class for gi.multicast() */
+typedef enum multicast_t{
+ MULTICAST_ALL,
+ MULTICAST_PHS,
+ MULTICAST_PVS,
+ MULTICAST_ALL_R,
+ MULTICAST_PHS_R,
+ MULTICAST_PVS_R
+}multicast_t;
+
+#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
+
+extern vec3_t vec3_origin;
+
+#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
+#define VectorSubtract(a,b,c) (c[0]=a[0]-b[0],c[1]=a[1]-b[1],c[2]=a[2]-b[2])
+#define VectorAdd(a,b,c) (c[0]=a[0]+b[0],c[1]=a[1]+b[1],c[2]=a[2]+b[2])
+#define VectorCopy(a,b) (b[0]=a[0],b[1]=a[1],b[2]=a[2])
+#define VectorClear(a) (a[0]=a[1]=a[2]=0)
+#define VectorNegate(a,b) (b[0]=-a[0],b[1]=-a[1],b[2]=-a[2])
+#define VectorSet(v, x, y, z) (v[0]=(x), v[1]=(y), v[2]=(z))
+#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \
+ (((p)->type < 3)? \
+ ( \
+ ((p)->dist <= (emins)[(p)->type])? \
+ 1 \
+ : \
+ ( \
+ ((p)->dist >= (emaxs)[(p)->type])?\
+ 2 \
+ : \
+ 3 \
+ ) \
+ ) \
+ : \
+ BoxOnPlaneSide( (emins), (emaxs), (p)))
+
+extern int curtime; // current time in ms, from Sys_Milliseconds()
+
+enum{
+ SFF_SUBDIR = 1<<3
+};
+
+enum{
+ CVAR_ARCHIVE = 1<<0, // save to vars.rc
+ CVAR_USERINFO = 1<<1, // add to userinfo on change
+ CVAR_SERVERINFO = 1<<2, // add to serverinfo on change
+ CVAR_NOSET = 1<<3, // only allow setting from commandline
+ CVAR_LATCH= 1<<4 // save changes until server restart
+};
+/* nothing outside the Cvar_*() functions should modify these fields! */
+struct cvar_t{
+ char *name;
+ char *string;
+ char *latched_string; // for CVAR_LATCH vars
+ int flags;
+ qboolean modified; // set each time the cvar is changed
+ float value;
+ cvar_t *next;
+};
+extern cvar_t *cvar_vars;
+extern qboolean userinfo_modified;
+
+enum{
+ /* contents flags are separate bits. a given brush can contribute
+ * multiple content bits. multiple brushes can be in a single leaf
+ * lower bits are stronger, and will eat weaker brushes completely */
+ CONTENTS_SOLID = 1<<0, // an eye is never valid in a solid
+ CONTENTS_WINDOW = 1<<1, // translucent, but not watery
+ CONTENTS_AUX = 1<<2,
+ CONTENTS_LAVA = 1<<3,
+ CONTENTS_SLIME = 1<<4,
+ CONTENTS_WATER = 1<<5,
+ CONTENTS_MIST = 1<<6,
+ LAST_VISIBLE_CONTENTS = 1<<6,
+ /* remaining contents are non-visible, and don't eat brushes */
+ CONTENTS_AREAPORTAL = 1<<15,
+ CONTENTS_PLAYERCLIP = 1<<16,
+ CONTENTS_MONSTERCLIP = 1<<17,
+ /* currents can be added to any other contents, and may be mixed */
+ CONTENTS_CURRENT_0 = 1<<18,
+ CONTENTS_CURRENT_90 = 1<<19,
+ CONTENTS_CURRENT_180 = 1<<20,
+ CONTENTS_CURRENT_270 = 1<<21,
+ CONTENTS_CURRENT_UP = 1<<22,
+ CONTENTS_CURRENT_DOWN = 1<<23,
+ CONTENTS_ORIGIN = 1<<24, // removed before bsping an entity
+ CONTENTS_MONSTER = 1<<25, // should never be on a brush, only in game
+ CONTENTS_DEADMONSTER = 1<<26,
+ CONTENTS_DETAIL = 1<<27, // brushes to be added after vis leafs
+ CONTENTS_TRANSLUCENT = 1<<28, // auto set if any surface has trans
+ CONTENTS_LADDER = 1<<29,
+
+ SURF_LIGHT = 1<<0, // value will hold the light strength
+ SURF_SLICK = 1<<1, // effects game physics
+ SURF_SKY = 1<<2, // don't draw, but add to skybox
+ SURF_WARP = 1<<3, // turbulent water warp
+ SURF_TRANS33 = 1<<4,
+ SURF_TRANS66 = 1<<5,
+ SURF_FLOWING = 1<<6, // scroll towards angle
+ SURF_NODRAW = 1<<7, // don't bother referencing the texture
+
+ /* content masks */
+ MASK_ALL = -1,
+ MASK_SOLID = CONTENTS_SOLID|CONTENTS_WINDOW,
+ MASK_PLAYERSOLID = CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER,
+ MASK_DEADSOLID = CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW,
+ MASK_MONSTERSOLID = CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER,
+ MASK_WATER = CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME,
+ MASK_OPAQUE = CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA,
+ MASK_SHOT = CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEADMONSTER,
+ MASK_CURRENT = CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN,
+
+ // FIXME: eliminate AREA_ distinction?
+ /* SV_AreaEdicts() can return a list of either solid or trigger entities */
+ AREA_SOLID = 1<<0,
+ AREA_TRIGGERS = 1<<1
+};
+
+/* !!! if this is changed, it must be changed in asm code too !!! */
+struct cplane_t{
+ vec3_t normal;
+ float dist;
+ uchar type; // for fast side tests
+ uchar signbits; // signx + (signy<<1) + (signz<<1)
+ uchar pad[2];
+};
+struct cmodel_t{
+ vec3_t mins;
+ vec3_t maxs;
+ vec3_t origin; // for sounds or lights
+ int headnode;
+};
+struct csurface_t{
+ char name[16];
+ int flags;
+ int value;
+};
+/* used internally due to name len probs */
+struct mapsurface_t{
+ csurface_t c;
+ char rname[32];
+};
+/* a trace is returned when a box is swept through the world */
+struct trace_t{
+ qboolean allsolid; // if true, plane is not valid
+ qboolean startsolid; // if true, the initial point was in a solid area
+ float fraction; // time completed, 1.0 = didn't hit anything
+ vec3_t endpos; // final position
+ cplane_t plane; // surface normal at impact
+ csurface_t *surface; // surface hit
+ int contents; // contents on other side of surface hit
+ edict_t *ent; // not set by CM_*() functions
+};
+
+/* information necessary for client side movement prediction */
+typedef enum pmtype_t{
+ /* can accelerate and turn */
+ PM_NORMAL,
+ PM_SPECTATOR,
+ /* no acceleration or turning */
+ PM_DEAD,
+ PM_GIB, // different bounding box
+ PM_FREEZE
+}pmtype_t;
+
+enum{
+ PMF_DUCKED = 1<<0,
+ PMF_JUMP_HELD = 1<<1,
+ PMF_ON_GROUND = 1<<2,
+ PMF_TIME_WATERJUMP = 1<<3, // pm_time is waterjump
+ PMF_TIME_LAND = 1<<4, // pm_time is time before rejump
+ PMF_TIME_TELEPORT = 1<<5, // pm_time is non-moving time
+ /* temporarily disables prediction (used for grappling hook) */
+ PMF_NO_PREDICTION = 1<<6,
+};
+/* this structure needs to be communicated bit-accurate from the server to the
+ * client to guarantee that prediction stays in sync, so no floats are used.
+ * if any part of the game code modifies this struct, it will result in a
+ * prediction error of some degree. */
+struct pmove_state_t{
+ pmtype_t pm_type;
+ short origin[3]; // 12.3
+ short velocity[3]; // 12.3
+ uchar pm_flags; // ducked, jump_held, etc
+ uchar pm_time; // each unit = 8 ms
+ short gravity;
+ /* add to command angles to get view direction changed by spawns,
+ * rotating objects and teleporters */
+ short delta_angles[3];
+};
+
+enum{
+ BUTTON_ATTACK = 1<<0,
+ BUTTON_USE = 1<<1,
+ BUTTON_ANY = 1<<7, // any key whatsoever
+
+ MAXTOUCH = 32
+};
+/* sent to the server each client frame */
+struct usercmd_t{
+ uchar msec;
+ uchar buttons;
+ short angles[3];
+ short forwardmove;
+ short sidemove;
+ short upmove;
+ uchar impulse; // remove?
+ uchar lightlevel; // light level the player is standing on
+};
+struct pmove_t{
+ pmove_state_t s; // state (in / out)
+ /* command (in) */
+ usercmd_t cmd;
+ qboolean snapinitial; // if s has been changed outside pmove
+ /* results (out) */
+ int numtouch;
+ edict_t *touchents[MAXTOUCH];
+
+ vec3_t viewangles; // clamped
+ float viewheight;
+ vec3_t mins; // bounding box size
+ vec3_t maxs;
+ edict_t *groundentity;
+ int watertype;
+ int waterlevel;
+ /* callbacks to test the world */
+ trace_t (*trace)(vec3_t, vec3_t, vec3_t, vec3_t);
+ int (*pointcontents)(vec3_t);
+};
+
+enum{
+ /* entity_state_t->effects
+ * Effects are things handled on the client side (lights, particles, frame
+ * animations) that happen constantly on the given entity. An entity that has
+ * effects will be sent to the client even if it has a zero index model. */
+ EF_ROTATE = 1<<0, // rotate (bonus items)
+ EF_GIB = 1<<1, // leave a trail
+ EF_BLASTER = 1<<3, // redlight + trail
+ EF_ROCKET = 1<<4, // redlight + trail
+ EF_GRENADE = 1<<5,
+ EF_HYPERBLASTER = 1<<6,
+ EF_BFG = 1<<7,
+ EF_COLOR_SHELL = 1<<8,
+ EF_POWERSCREEN = 1<<9,
+ EF_ANIM01 = 1<<10, // automatically cycle between frames 0 and 1 at 2 hz
+ EF_ANIM23 = 1<<11, // automatically cycle between frames 2 and 3 at 2 hz
+ EF_ANIM_ALL = 1<<12, // automatically cycle through all frames at 2hz
+ EF_ANIM_ALLFAST = 1<<13, // automatically cycle through all frames at 10hz
+ EF_FLIES = 1<<14,
+ EF_QUAD = 1<<15,
+ EF_PENT = 1<<16,
+ EF_TELEPORTER = 1<<17, // particle fountain
+ EF_FLAG1 = 1<<18,
+ EF_FLAG2 = 1<<19,
+ EF_IONRIPPER = 1<<20,
+ EF_GREENGIB = 1<<21,
+ EF_BLUEHYPERBLASTER = 1<<22,
+ EF_SPINNINGLIGHTS = 1<<23,
+ EF_PLASMA = 1<<24,
+ EF_TRAP = 1<<25,
+ /* ROGUE */
+ EF_TRACKER = 1<<26,
+ EF_DOUBLE = 1<<27,
+ EF_SPHERETRANS = 1<<28,
+ EF_TAGTRAIL = 1<<29,
+ EF_HALF_DAMAGE = 1<<30,
+ EF_TRACKERTRAIL = 1<<31,
+
+ /* entity_state_t->renderfx */
+ RF_MINLIGHT = 1<<0, // allways have some light (viewmodel)
+ RF_VIEWERMODEL = 1<<1, // don't draw through eyes, only mirrors
+ RF_WEAPONMODEL = 1<<2, // only draw through eyes
+ RF_FULLBRIGHT = 1<<3, // allways draw full intensity
+ RF_DEPTHHACK = 1<<4, // for view weapon Z crunching
+ RF_TRANSLUCENT = 1<<5,
+ RF_FRAMELERP = 1<<6,
+ RF_BEAM = 1<<7,
+ RF_CUSTOMSKIN = 1<<8, // skin is an index in image_precache
+ RF_GLOW = 1<<9, // pulse lighting for bonus items
+ RF_SHELL_RED = 1<<10,
+ RF_SHELL_GREEN = 1<<11,
+ RF_SHELL_BLUE = 1<<12,
+ /* ROGUE */
+ RF_IR_VISIBLE = 1<<15,
+ RF_SHELL_DOUBLE = 1<<16,
+ RF_SHELL_HALF_DAM = 1<<17,
+ RF_USE_DISGUISE = 1<<18,
+
+ /* player_state_t->refdef */
+ RDF_UNDERWATER = 1<<0, // warp the screen as apropriate
+ RDF_NOWORLDMODEL = 1<<1, // used for player configuration screen
+ /* ROGUE */
+ RDF_IRGOGGLES = 1<<2,
+ RDF_UVGOGGLES = 1<<3,
+
+ /* muzzle flashes, player effects */
+ MZ_BLASTER = 0,
+ MZ_MACHINEGUN = 1,
+ MZ_SHOTGUN = 2,
+ MZ_CHAINGUN1 = 3,
+ MZ_CHAINGUN2 = 4,
+ MZ_CHAINGUN3 = 5,
+ MZ_RAILGUN = 6,
+ MZ_ROCKET = 7,
+ MZ_GRENADE = 8,
+ MZ_LOGIN = 9,
+ MZ_LOGOUT = 10,
+ MZ_RESPAWN = 11,
+ MZ_BFG = 12,
+ MZ_SSHOTGUN = 13,
+ MZ_HYPERBLASTER = 14,
+ MZ_ITEMRESPAWN = 15,
+ MZ_IONRIPPER = 16,
+ MZ_BLUEHYPERBLASTER = 17,
+ MZ_PHALANX = 18,
+ MZ_SILENCED = 128, // bit flag ORed with one of the above numbers
+ /* ROGUE */
+ MZ_ETF_RIFLE = 30,
+ MZ_UNUSED = 31,
+ MZ_SHOTGUN2 = 32,
+ MZ_HEATBEAM = 33,
+ MZ_BLASTER2 = 34,
+ MZ_TRACKER = 35,
+ MZ_NUKE1 = 36,
+ MZ_NUKE2 = 37,
+ MZ_NUKE4 = 38,
+ MZ_NUKE8 = 39,
+
+ /* monster muzzle flashes */
+ MZ2_TANK_BLASTER_1 = 1,
+ MZ2_TANK_BLASTER_2 = 2,
+ MZ2_TANK_BLASTER_3 = 3,
+ MZ2_TANK_MACHINEGUN_1 = 4,
+ MZ2_TANK_MACHINEGUN_2 = 5,
+ MZ2_TANK_MACHINEGUN_3 = 6,
+ MZ2_TANK_MACHINEGUN_4 = 7,
+ MZ2_TANK_MACHINEGUN_5 = 8,
+ MZ2_TANK_MACHINEGUN_6 = 9,
+ MZ2_TANK_MACHINEGUN_7 = 10,
+ MZ2_TANK_MACHINEGUN_8 = 11,
+ MZ2_TANK_MACHINEGUN_9 = 12,
+ MZ2_TANK_MACHINEGUN_10 = 13,
+ MZ2_TANK_MACHINEGUN_11 = 14,
+ MZ2_TANK_MACHINEGUN_12 = 15,
+ MZ2_TANK_MACHINEGUN_13 = 16,
+ MZ2_TANK_MACHINEGUN_14 = 17,
+ MZ2_TANK_MACHINEGUN_15 = 18,
+ MZ2_TANK_MACHINEGUN_16 = 19,
+ MZ2_TANK_MACHINEGUN_17 = 20,
+ MZ2_TANK_MACHINEGUN_18 = 21,
+ MZ2_TANK_MACHINEGUN_19 = 22,
+ MZ2_TANK_ROCKET_1 = 23,
+ MZ2_TANK_ROCKET_2 = 24,
+ MZ2_TANK_ROCKET_3 = 25,
+ MZ2_INFANTRY_MACHINEGUN_1 = 26,
+ MZ2_INFANTRY_MACHINEGUN_2 = 27,
+ MZ2_INFANTRY_MACHINEGUN_3 = 28,
+ MZ2_INFANTRY_MACHINEGUN_4 = 29,
+ MZ2_INFANTRY_MACHINEGUN_5 = 30,
+ MZ2_INFANTRY_MACHINEGUN_6 = 31,
+ MZ2_INFANTRY_MACHINEGUN_7 = 32,
+ MZ2_INFANTRY_MACHINEGUN_8 = 33,
+ MZ2_INFANTRY_MACHINEGUN_9 = 34,
+ MZ2_INFANTRY_MACHINEGUN_10 = 35,
+ MZ2_INFANTRY_MACHINEGUN_11 = 36,
+ MZ2_INFANTRY_MACHINEGUN_12 = 37,
+ MZ2_INFANTRY_MACHINEGUN_13 = 38,
+ MZ2_SOLDIER_BLASTER_1 = 39,
+ MZ2_SOLDIER_BLASTER_2 = 40,
+ MZ2_SOLDIER_SHOTGUN_1 = 41,
+ MZ2_SOLDIER_SHOTGUN_2 = 42,
+ MZ2_SOLDIER_MACHINEGUN_1 = 43,
+ MZ2_SOLDIER_MACHINEGUN_2 = 44,
+ MZ2_GUNNER_MACHINEGUN_1 = 45,
+ MZ2_GUNNER_MACHINEGUN_2 = 46,
+ MZ2_GUNNER_MACHINEGUN_3 = 47,
+ MZ2_GUNNER_MACHINEGUN_4 = 48,
+ MZ2_GUNNER_MACHINEGUN_5 = 49,
+ MZ2_GUNNER_MACHINEGUN_6 = 50,
+ MZ2_GUNNER_MACHINEGUN_7 = 51,
+ MZ2_GUNNER_MACHINEGUN_8 = 52,
+ MZ2_GUNNER_GRENADE_1 = 53,
+ MZ2_GUNNER_GRENADE_2 = 54,
+ MZ2_GUNNER_GRENADE_3 = 55,
+ MZ2_GUNNER_GRENADE_4 = 56,
+ MZ2_CHICK_ROCKET_1 = 57,
+ MZ2_FLYER_BLASTER_1 = 58,
+ MZ2_FLYER_BLASTER_2 = 59,
+ MZ2_MEDIC_BLASTER_1 = 60,
+ MZ2_GLADIATOR_RAILGUN_1 = 61,
+ MZ2_HOVER_BLASTER_1 = 62,
+ MZ2_ACTOR_MACHINEGUN_1 = 63,
+ MZ2_SUPERTANK_MACHINEGUN_1 = 64,
+ MZ2_SUPERTANK_MACHINEGUN_2 = 65,
+ MZ2_SUPERTANK_MACHINEGUN_3 = 66,
+ MZ2_SUPERTANK_MACHINEGUN_4 = 67,
+ MZ2_SUPERTANK_MACHINEGUN_5 = 68,
+ MZ2_SUPERTANK_MACHINEGUN_6 = 69,
+ MZ2_SUPERTANK_ROCKET_1 = 70,
+ MZ2_SUPERTANK_ROCKET_2 = 71,
+ MZ2_SUPERTANK_ROCKET_3 = 72,
+ MZ2_BOSS2_MACHINEGUN_L1 = 73,
+ MZ2_BOSS2_MACHINEGUN_L2 = 74,
+ MZ2_BOSS2_MACHINEGUN_L3 = 75,
+ MZ2_BOSS2_MACHINEGUN_L4 = 76,
+ MZ2_BOSS2_MACHINEGUN_L5 = 77,
+ MZ2_BOSS2_ROCKET_1 = 78,
+ MZ2_BOSS2_ROCKET_2 = 79,
+ MZ2_BOSS2_ROCKET_3 = 80,
+ MZ2_BOSS2_ROCKET_4 = 81,
+ MZ2_FLOAT_BLASTER_1 = 82,
+ MZ2_SOLDIER_BLASTER_3 = 83,
+ MZ2_SOLDIER_SHOTGUN_3 = 84,
+ MZ2_SOLDIER_MACHINEGUN_3 = 85,
+ MZ2_SOLDIER_BLASTER_4 = 86,
+ MZ2_SOLDIER_SHOTGUN_4 = 87,
+ MZ2_SOLDIER_MACHINEGUN_4 = 88,
+ MZ2_SOLDIER_BLASTER_5 = 89,
+ MZ2_SOLDIER_SHOTGUN_5 = 90,
+ MZ2_SOLDIER_MACHINEGUN_5 = 91,
+ MZ2_SOLDIER_BLASTER_6 = 92,
+ MZ2_SOLDIER_SHOTGUN_6 = 93,
+ MZ2_SOLDIER_MACHINEGUN_6 = 94,
+ MZ2_SOLDIER_BLASTER_7 = 95,
+ MZ2_SOLDIER_SHOTGUN_7 = 96,
+ MZ2_SOLDIER_MACHINEGUN_7 = 97,
+ MZ2_SOLDIER_BLASTER_8 = 98,
+ MZ2_SOLDIER_SHOTGUN_8 = 99,
+ MZ2_SOLDIER_MACHINEGUN_8 = 100,
+ /* --- Xian shit below --- */
+ MZ2_MAKRON_BFG = 101,
+ MZ2_MAKRON_BLASTER_1 = 102,
+ MZ2_MAKRON_BLASTER_2 = 103,
+ MZ2_MAKRON_BLASTER_3 = 104,
+ MZ2_MAKRON_BLASTER_4 = 105,
+ MZ2_MAKRON_BLASTER_5 = 106,
+ MZ2_MAKRON_BLASTER_6 = 107,
+ MZ2_MAKRON_BLASTER_7 = 108,
+ MZ2_MAKRON_BLASTER_8 = 109,
+ MZ2_MAKRON_BLASTER_9 = 110,
+ MZ2_MAKRON_BLASTER_10 = 111,
+ MZ2_MAKRON_BLASTER_11 = 112,
+ MZ2_MAKRON_BLASTER_12 = 113,
+ MZ2_MAKRON_BLASTER_13 = 114,
+ MZ2_MAKRON_BLASTER_14 = 115,
+ MZ2_MAKRON_BLASTER_15 = 116,
+ MZ2_MAKRON_BLASTER_16 = 117,
+ MZ2_MAKRON_BLASTER_17 = 118,
+ MZ2_MAKRON_RAILGUN_1 = 119,
+ MZ2_JORG_MACHINEGUN_L1 = 120,
+ MZ2_JORG_MACHINEGUN_L2 = 121,
+ MZ2_JORG_MACHINEGUN_L3 = 122,
+ MZ2_JORG_MACHINEGUN_L4 = 123,
+ MZ2_JORG_MACHINEGUN_L5 = 124,
+ MZ2_JORG_MACHINEGUN_L6 = 125,
+ MZ2_JORG_MACHINEGUN_R1 = 126,
+ MZ2_JORG_MACHINEGUN_R2 = 127,
+ MZ2_JORG_MACHINEGUN_R3 = 128,
+ MZ2_JORG_MACHINEGUN_R4 = 129,
+ MZ2_JORG_MACHINEGUN_R5 = 130,
+ MZ2_JORG_MACHINEGUN_R6 = 131,
+ MZ2_JORG_BFG_1 = 132,
+ MZ2_BOSS2_MACHINEGUN_R1 = 133,
+ MZ2_BOSS2_MACHINEGUN_R2 = 134,
+ MZ2_BOSS2_MACHINEGUN_R3 = 135,
+ MZ2_BOSS2_MACHINEGUN_R4 = 136,
+ MZ2_BOSS2_MACHINEGUN_R5 = 137,
+ /* ROGUE */
+ MZ2_CARRIER_MACHINEGUN_L1 = 138,
+ MZ2_CARRIER_MACHINEGUN_R1 = 139,
+ MZ2_CARRIER_GRENADE = 140,
+ MZ2_TURRET_MACHINEGUN = 141,
+ MZ2_TURRET_ROCKET = 142,
+ MZ2_TURRET_BLASTER = 143,
+ MZ2_STALKER_BLASTER = 144,
+ MZ2_DAEDALUS_BLASTER = 145,
+ MZ2_MEDIC_BLASTER_2 = 146,
+ MZ2_CARRIER_RAILGUN = 147,
+ MZ2_WIDOW_DISRUPTOR = 148,
+ MZ2_WIDOW_BLASTER = 149,
+ MZ2_WIDOW_RAIL = 150,
+ MZ2_WIDOW_PLASMABEAM = 151, // PMM - not used
+ MZ2_CARRIER_MACHINEGUN_L2 = 152,
+ MZ2_CARRIER_MACHINEGUN_R2 = 153,
+ MZ2_WIDOW_RAIL_LEFT = 154,
+ MZ2_WIDOW_RAIL_RIGHT = 155,
+ MZ2_WIDOW_BLASTER_SWEEP1 = 156,
+ MZ2_WIDOW_BLASTER_SWEEP2 = 157,
+ MZ2_WIDOW_BLASTER_SWEEP3 = 158,
+ MZ2_WIDOW_BLASTER_SWEEP4 = 159,
+ MZ2_WIDOW_BLASTER_SWEEP5 = 160,
+ MZ2_WIDOW_BLASTER_SWEEP6 = 161,
+ MZ2_WIDOW_BLASTER_SWEEP7 = 162,
+ MZ2_WIDOW_BLASTER_SWEEP8 = 163,
+ MZ2_WIDOW_BLASTER_SWEEP9 = 164,
+ MZ2_WIDOW_BLASTER_100 = 165,
+ MZ2_WIDOW_BLASTER_90 = 166,
+ MZ2_WIDOW_BLASTER_80 = 167,
+ MZ2_WIDOW_BLASTER_70 = 168,
+ MZ2_WIDOW_BLASTER_60 = 169,
+ MZ2_WIDOW_BLASTER_50 = 170,
+ MZ2_WIDOW_BLASTER_40 = 171,
+ MZ2_WIDOW_BLASTER_30 = 172,
+ MZ2_WIDOW_BLASTER_20 = 173,
+ MZ2_WIDOW_BLASTER_10 = 174,
+ MZ2_WIDOW_BLASTER_0 = 175,
+ MZ2_WIDOW_BLASTER_10L = 176,
+ MZ2_WIDOW_BLASTER_20L = 177,
+ MZ2_WIDOW_BLASTER_30L = 178,
+ MZ2_WIDOW_BLASTER_40L = 179,
+ MZ2_WIDOW_BLASTER_50L = 180,
+ MZ2_WIDOW_BLASTER_60L = 181,
+ MZ2_WIDOW_BLASTER_70L = 182,
+ MZ2_WIDOW_RUN_1 = 183,
+ MZ2_WIDOW_RUN_2 = 184,
+ MZ2_WIDOW_RUN_3 = 185,
+ MZ2_WIDOW_RUN_4 = 186,
+ MZ2_WIDOW_RUN_5 = 187,
+ MZ2_WIDOW_RUN_6 = 188,
+ MZ2_WIDOW_RUN_7 = 189,
+ MZ2_WIDOW_RUN_8 = 190,
+ MZ2_CARRIER_ROCKET_1 = 191,
+ MZ2_CARRIER_ROCKET_2 = 192,
+ MZ2_CARRIER_ROCKET_3 = 193,
+ MZ2_CARRIER_ROCKET_4 = 194,
+ MZ2_WIDOW2_BEAMER_1 = 195,
+ MZ2_WIDOW2_BEAMER_2 = 196,
+ MZ2_WIDOW2_BEAMER_3 = 197,
+ MZ2_WIDOW2_BEAMER_4 = 198,
+ MZ2_WIDOW2_BEAMER_5 = 199,
+ MZ2_WIDOW2_BEAM_SWEEP_1 = 200,
+ MZ2_WIDOW2_BEAM_SWEEP_2 = 201,
+ MZ2_WIDOW2_BEAM_SWEEP_3 = 202,
+ MZ2_WIDOW2_BEAM_SWEEP_4 = 203,
+ MZ2_WIDOW2_BEAM_SWEEP_5 = 204,
+ MZ2_WIDOW2_BEAM_SWEEP_6 = 205,
+ MZ2_WIDOW2_BEAM_SWEEP_7 = 206,
+ MZ2_WIDOW2_BEAM_SWEEP_8 = 207,
+ MZ2_WIDOW2_BEAM_SWEEP_9 = 208,
+ MZ2_WIDOW2_BEAM_SWEEP_10 = 209,
+ MZ2_WIDOW2_BEAM_SWEEP_11 = 210
+};
+
+extern vec3_t monster_flash_offset[];
+
+/* Temp entity events are for things that happen at a location seperate from
+ * any existing entity. Temporary entity messages are explicitly constructed
+ * and broadcast. */
+typedef enum temp_event_t{
+ TE_GUNSHOT,
+ TE_BLOOD,
+ TE_BLASTER,
+ TE_RAILTRAIL,
+ TE_SHOTGUN,
+ TE_EXPLOSION1,
+ TE_EXPLOSION2,
+ TE_ROCKET_EXPLOSION,
+ TE_GRENADE_EXPLOSION,
+ TE_SPARKS,
+ TE_SPLASH,
+ TE_BUBBLETRAIL,
+ TE_SCREEN_SPARKS,
+ TE_SHIELD_SPARKS,
+ TE_BULLET_SPARKS,
+ TE_LASER_SPARKS,
+ TE_PARASITE_ATTACK,
+ TE_ROCKET_EXPLOSION_WATER,
+ TE_GRENADE_EXPLOSION_WATER,
+ TE_MEDIC_CABLE_ATTACK,
+ TE_BFG_EXPLOSION,
+ TE_BFG_BIGEXPLOSION,
+ TE_BOSSTPORT, // used as '22' in a map, so DON'T RENUMBER!!!
+ TE_BFG_LASER,
+ TE_GRAPPLE_CABLE,
+ TE_WELDING_SPARKS,
+ TE_GREENBLOOD,
+ TE_BLUEHYPERBLASTER,
+ TE_PLASMA_EXPLOSION,
+ TE_TUNNEL_SPARKS,
+ /* ROGUE */
+ TE_BLASTER2,
+ TE_RAILTRAIL2,
+ TE_FLAME,
+ TE_LIGHTNING,
+ TE_DEBUGTRAIL,
+ TE_PLAIN_EXPLOSION,
+ TE_FLASHLIGHT,
+ TE_FORCEWALL,
+ TE_HEATBEAM,
+ TE_MONSTER_HEATBEAM,
+ TE_STEAM,
+ TE_BUBBLETRAIL2,
+ TE_MOREBLOOD,
+ TE_HEATBEAM_SPARKS,
+ TE_HEATBEAM_STEAM,
+ TE_CHAINFIST_SMOKE,
+ TE_ELECTRIC_SPARKS,
+ TE_TRACKER_EXPLOSION,
+ TE_TELEPORT_EFFECT,
+ TE_DBALL_GOAL,
+ TE_WIDOWBEAMOUT,
+ TE_NUKEBLAST,
+ TE_WIDOWSPLASH,
+ TE_EXPLOSION1_BIG,
+ TE_EXPLOSION1_NP,
+ TE_FLECHETTE
+}temp_event_t;
+
+enum{
+ SPLASH_UNKNOWN = 0,
+ SPLASH_SPARKS = 1,
+ SPLASH_BLUE_WATER = 2,
+ SPLASH_BROWN_WATER = 3,
+ SPLASH_SLIME = 4,
+ SPLASH_LAVA = 5,
+ SPLASH_BLOOD = 6,
+
+ /* sound channels
+ * channel 0 never willingly overrides
+ * other channels (1-7) allways override a playing sound on that channel */
+ CHAN_AUTO = 0,
+ CHAN_WEAPON = 1,
+ CHAN_VOICE = 2,
+ CHAN_ITEM = 3,
+ CHAN_BODY = 4,
+ /* modifier flags */
+ CHAN_NO_PHS_ADD = 1<<3, // send to all clients, not just ones in PHS (ATTN 0 will also do this)
+ CHAN_RELIABLE = 1<<4, // send by reliable message, not datagram
+
+ /* sound attenuation values */
+ ATTN_NONE = 0, // full volume the entire level
+ ATTN_NORM = 1,
+ ATTN_IDLE = 2,
+ ATTN_STATIC = 3, // diminish very rapidly with distance
+
+ /* player_state->stats[] */
+ STAT_HEALTH_ICON = 0,
+ STAT_HEALTH = 1,
+ STAT_AMMO_ICON = 2,
+ STAT_AMMO = 3,
+ STAT_ARMOR_ICON = 4,
+ STAT_ARMOR = 5,
+ STAT_SELECTED_ICON = 6,
+ STAT_PICKUP_ICON = 7,
+ STAT_PICKUP_STRING = 8,
+ STAT_TIMER_ICON = 9,
+ STAT_TIMER = 10,
+ STAT_HELPICON = 11,
+ STAT_SELECTED_ITEM = 12,
+ STAT_LAYOUTS = 13,
+ STAT_FRAGS = 14,
+ STAT_FLASHES = 15, // cleared each frame, 1 = health, 2 = armor
+ STAT_CHASE = 16,
+ STAT_SPECTATOR = 17,
+ MAX_STATS = 32,
+
+ /* dmflags->value */
+ DF_NO_HEALTH = 1<<0,
+ DF_NO_ITEMS = 1<<1,
+ DF_WEAPONS_STAY = 1<<2,
+ DF_NO_FALLING = 1<<3,
+ DF_INSTANT_ITEMS = 1<<4,
+ DF_SAME_LEVEL = 1<<5,
+ DF_SKINTEAMS = 1<<6,
+ DF_MODELTEAMS = 1<<7,
+ DF_NO_FRIENDLY_FIRE = 1<<8,
+ DF_SPAWN_FARTHEST = 1<<9,
+ DF_FORCE_RESPAWN = 1<<10,
+ DF_NO_ARMOR = 1<<11,
+ DF_ALLOW_EXIT = 1<<12,
+ DF_INFINITE_AMMO = 1<<13,
+ DF_QUAD_DROP = 1<<14,
+ DF_FIXED_FOV = 1<<15,
+ DF_QUADFIRE_DROP = 1<<16,
+ /* ROGUE */
+ DF_NO_MINES = 1<<17,
+ DF_NO_STACK_DOUBLE = 1<<18,
+ DF_NO_NUKES = 1<<19,
+ DF_NO_SPHERES = 1<<20,
+
+ ROGUE_VERSION_ID = 1278 // probably bs
+};
+
+/* communicated accross the net */
+
+#define ANGLE2SHORT(x) ((int)((x)*65536/360) & 65535)
+#define SHORT2ANGLE(x) ((x)*(360.0/65536))
+
+enum{
+ /* config strings are a general means of communication from the server
+ * to all connected clients. each config string can be at most
+ * MAX_QPATH characters. */
+ CS_NAME = 0,
+ CS_CDTRACK = 1,
+ CS_SKY = 2,
+ CS_SKYAXIS = 3, // %f %f %f format
+ CS_SKYROTATE = 4,
+ CS_STATUSBAR = 5, // display program string
+ CS_AIRACCEL = 29, // air acceleration control
+ CS_MAXCLIENTS = 30,
+ CS_MAPCHECKSUM = 31, // for catching cheater maps
+ CS_MODELS = 32,
+ CS_SOUNDS = CS_MODELS+MAX_MODELS,
+ CS_IMAGES = CS_SOUNDS+MAX_SOUNDS,
+ CS_LIGHTS = CS_IMAGES+MAX_IMAGES,
+ CS_ITEMS = CS_LIGHTS+MAX_LIGHTSTYLES,
+ CS_PLAYERSKINS = CS_ITEMS+MAX_ITEMS,
+ CS_GENERAL = CS_PLAYERSKINS+MAX_CLIENTS,
+ MAX_CONFIGSTRINGS = CS_GENERAL+MAX_GENERAL
+};
+
+/* entity events are for effects that take place relative to an existing
+ * entitiy origin. Very network efficient. All muzzle flashes really should be
+ * converted to events... */
+typedef enum entity_event_t{
+ EV_NONE,
+ EV_ITEM_RESPAWN,
+ EV_FOOTSTEP,
+ EV_FALLSHORT,
+ EV_FALL,
+ EV_FALLFAR,
+ EV_PLAYER_TELEPORT,
+ EV_OTHER_TELEPORT
+}entity_event_t;
+
+/* information conveyed from the server in an update message about entities
+ * that the client will need to render in some way */
+struct entity_state_t{
+ int number; // edict index
+ vec3_t origin;
+ vec3_t angles;
+ vec3_t old_origin; // for lerping
+ int modelindex;
+ int modelindex2; // weapons, CTF flags, etc
+ int modelindex3;
+ int modelindex4;
+ int frame;
+ int skinnum;
+ uint effects; // PGM - we're filling it, so it needs to be unsigned
+ int renderfx;
+ /* for client side prediction; SV_LinkEdict() sets .solid properly:
+ * 8*(bits 0-4) is x/y radius
+ * 8*(bits 5-9) is z down distance
+ * 8(bits10-15) is z up */
+ int solid;
+ int sound; // for looping sounds, to guarantee shutoff
+ /* impulse events: muzzle flashes, footsteps, etc.
+ * events only go out for a single frame, they are automatically
+ * cleared each frame */
+ int event;
+};
+/* the cl_parse_entities must be large enough to hold UPDATE_BACKUP frames of
+ * entities, so that when a delta compressed message arives from the server it
+ * can be un-deltad from the original */
+extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
+
+/* information needed in addition to pmove_state_t to render a view. There will
+ * only be 10 player_state_t sent each second, but the number of pmove_state_t
+ * changes will be reletive to client frame rates */
+struct player_state_t{
+ pmove_state_t pmove; // for prediction
+ /* these fields do not need to be communicated bit-precise */
+ vec3_t viewangles; // for fixed views
+ vec3_t viewoffset; // add to pmovestate->origin
+ /* set by weapon kicks, pain effects, etc. */
+ vec3_t kick_angles; // add to view direction to get render angles
+ vec3_t gunangles;
+ vec3_t gunoffset;
+ int gunindex;
+ int gunframe;
+ float blend[4]; // rgba full screen effect
+ float fov; // horizontal field of view
+ int rdflags; // refdef flags
+ short stats[MAX_STATS]; // fast status bar updates
+};
+
+enum{
+ VIDREF_GL = 1,
+ VIDREF_SOFT = 2
+};
+extern int vidref_val;
+
+
+#include "game/game.h" // ugh
+extern game_export_t *ge;
+
+
+#define VERSION 3.19
+#define BASEDIRNAME "baseq2"
+
+struct sizebuf_t{
+ qboolean allowoverflow; // if false, do a Com_Error
+ qboolean overflowed; // set to true if the buffer size failed
+ uchar *data;
+ int maxsize;
+ int cursize;
+ int readcount;
+};
+extern sizebuf_t net_message;
+
+#define DEFAULT_SOUND_PACKET_VOLUME 1.0
+#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
+enum{
+ PROTOCOL_VERSION = 34,
+ PORT_MASTER = 27900,
+ PORT_CLIENT = 27901,
+ PORT_SERVER = 27910,
+ UPDATE_BACKUP = 16, // buffered copies of entity_state_t; must be power of two
+ UPDATE_MASK = UPDATE_BACKUP-1,
+
+ /* server to client: protocol bytes that can be directly added to
+ * messages; the svc_strings[] array in cl_parse.c should mirror this */
+ svc_bad = 0,
+ /* these ops are known to the game dll */
+ svc_muzzleflash,
+ svc_muzzleflash2,
+ svc_temp_entity,
+ svc_layout,
+ svc_inventory,
+ /* the rest are private to the client and server */
+ svc_nop,
+ svc_disconnect,
+ svc_reconnect,
+ svc_sound,
+ svc_print, // [byte] id [string] null terminated string
+ svc_stufftext, // [string] stuffed into client's console buffer, should be \n terminated
+ svc_serverdata, // [long] protocol ...
+ svc_configstring, // [short] [string]
+ svc_spawnbaseline,
+ svc_centerprint, // [string] to put in center of the screen
+ svc_download, // [short] size [size bytes]
+ svc_playerinfo, // variable
+ svc_packetentities, // [...]
+ svc_deltapacketentities, // [...]
+ svc_frame,
+
+ /* client to server */
+ clc_bad = 0,
+ clc_nop,
+ clc_move, // [[usercmd_t]
+ clc_userinfo, // [[userinfo string]
+ clc_stringcmd, // [string] message
+
+ /* player_state_t communication */
+ PS_M_TYPE = 1<<0,
+ PS_M_ORIGIN = 1<<1,
+ PS_M_VELOCITY = 1<<2,
+ PS_M_TIME = 1<<3,
+ PS_M_FLAGS = 1<<4,
+ PS_M_GRAVITY = 1<<5,
+ PS_M_DELTA_ANGLES = 1<<6,
+ PS_VIEWOFFSET = 1<<7,
+ PS_VIEWANGLES = 1<<8,
+ PS_KICKANGLES = 1<<9,
+ PS_BLEND = 1<<10,
+ PS_FOV = 1<<11,
+ PS_WEAPONINDEX = 1<<12,
+ PS_WEAPONFRAME = 1<<13,
+ PS_RDFLAGS = 1<<14,
+
+ /* user_cmd_t communication: ms and light always sent, the others are
+ * optional */
+ CM_ANGLE1 = 1<<0,
+ CM_ANGLE2 = 1<<1,
+ CM_ANGLE3 = 1<<2,
+ CM_FORWARD = 1<<3,
+ CM_SIDE = 1<<4,
+ CM_UP = 1<<5,
+ CM_BUTTONS = 1<<6,
+ CM_IMPULSE = 1<<7,
+
+ /* a sound without an ent or pos will be a local only sound */
+ SND_VOLUME = 1<<0, // a byte
+ SND_ATTENUATION = 1<<1, // a byte
+ SND_POS = 1<<2, // three coordinates
+ SND_ENT = 1<<3, // a short 0-2: channel, 3-12: entity
+ SND_OFFSET = 1<<4, // a byte, msec offset from frame start
+
+ /* entity_state_t communication */
+ /* try to pack the common update flags into the first byte */
+ U_ORIGIN1 = 1<<0,
+ U_ORIGIN2 = 1<<1,
+ U_ANGLE2 = 1<<2,
+ U_ANGLE3 = 1<<3,
+ U_FRAME8 = 1<<4, // frame is a byte
+ U_EVENT = 1<<5,
+ U_REMOVE = 1<<6, // REMOVE this entity, don't add it
+ U_MOREBITS1 = 1<<7, // read one additional byte
+ U_NUMBER16 = 1<<8, // NUMBER8 is implicit if not set
+ U_ORIGIN3 = 1<<9,
+ U_ANGLE1 = 1<<10,
+ U_MODEL = 1<<11,
+ U_RENDERFX8 = 1<<12, // fullbright, etc
+ U_EFFECTS8 = 1<<14, // autorotate, trails, etc
+ U_MOREBITS2 = 1<<15, // read one additional byte
+ U_SKIN8 = 1<<16,
+ U_FRAME16 = 1<<17, // frame is a short
+ U_RENDERFX16 = 1<<18, // 8 + 16 = 32
+ U_EFFECTS16 = 1<<19, // 8 + 16 = 32
+ U_MODEL2 = 1<<20, // weapons, flags, etc
+ U_MODEL3 = 1<<21,
+ U_MODEL4 = 1<<22,
+ U_MOREBITS3 = 1<<23, // read one additional byte
+ U_OLDORIGIN = 1<<24, // FIXME: get rid of this
+ U_SKIN16 = 1<<25,
+ U_SOUND = 1<<26,
+ U_SOLID = 1<<27,
+};
+extern char *svc_strings[256];
+
+typedef enum netsrc_t{
+ NS_CLIENT,
+ NS_SERVER
+}netsrc_t;
+typedef enum netadrtype_t{
+ NA_LOOPBACK,
+ NA_BROADCAST,
+ NA_IP,
+ NA_IPX,
+ NA_BROADCAST_IPX
+}netadrtype_t;
+
+#define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG)
+enum{
+ PORT_ANY = -1,
+ MAX_MSGLEN = 1400, // max length of a message
+ PACKET_HEADER = 10, // two ints and a short
+ MAX_LATENT = 32,
+ MAX_MASTERS = 8 // max recipients for heartbeat packets
+};
+struct netadr_t{
+ netadrtype_t type;
+ uchar ip[4];
+ uchar ipx[10];
+ ushort port;
+};
+extern netadr_t net_from;
+extern netadr_t master_adr[MAX_MASTERS]; // address of the master server
+
+struct netchan_t{
+ qboolean fatal_error;
+ netsrc_t sock;
+ int dropped; // between last packet and previous
+ int last_received; // for timeouts
+ int last_sent; // for retransmits
+ netadr_t remote_address;
+ int qport; // qport value to write when transmitting
+ /* sequencing variables */
+ int incoming_sequence;
+ int incoming_acknowledged;
+ int incoming_reliable_acknowledged; // single bit
+ int incoming_reliable_sequence; // single bit, maintained local
+ int outgoing_sequence;
+ int reliable_sequence; // single bit
+ int last_reliable_sequence; // sequence number of last send
+ /* reliable staging and holding areas */
+ sizebuf_t message; // writing buffer to send to server
+ uchar message_buf[MAX_MSGLEN-16]; // leave space for header
+ /* message is copied to this buffer when it is first transfered */
+ int reliable_length;
+ uchar reliable_buf[MAX_MSGLEN-16]; // unacked reliable message
+};
+extern uchar net_message_buffer[MAX_MSGLEN];
+
+extern float pm_airaccelerate;
+
+extern cvar_t *developer;
+extern cvar_t *dedicated;
+extern cvar_t *host_speeds;
+extern cvar_t *log_stats;
+
+enum{
+ ERR_FATAL = 0, // exit the entire game with a popup window
+ ERR_DROP = 1, // print to console and disconnect from game
+ ERR_QUIT = 2, // not an error, just a normal exit
+ ERR_DISCONNECT = 2, // don't kill server
+ EXEC_NOW = 0, // don't return until completed
+ EXEC_INSERT = 1, // insert at current position, but don't run yet
+ EXEC_APPEND = 2, // add to end of the command buffer
+ PRINT_ALL = 0,
+ PRINT_DEVELOPER = 1, // only print when "developer 1"
+
+ NUMVERTEXNORMALS = 162,
+
+ /* thread groups */
+ THin = 1,
+ THsnd = 2,
+ THnet = 3
+};
+
+extern FILE *log_stats_file;
+/* host_speeds times */
+extern int time_before_game;
+extern int time_after_game;
+extern int time_before_ref;
+extern int time_after_ref;
+
+extern vec3_t bytedirs[NUMVERTEXNORMALS];
+
+extern uint sys_frame_time;
+
+#pragma pack on
+
+/* .pak files are just a linear collapse of a directory tree */
+enum{
+ IDPAKHEADER = ('K'<<24)+('C'<<16)+('A'<<8)+'P',
+ MAX_FILES_IN_PACK = 4096
+};
+struct dpackfile_t{
+ char name[56];
+ int filepos;
+ int filelen;
+};
+struct dpackheader_t{
+ int ident; // == IDPAKHEADER
+ int dirofs;
+ int dirlen;
+};
+
+/* PCX images */
+struct pcx_t{
+ char manufacturer;
+ char version;
+ char encoding;
+ char bits_per_pixel;
+ ushort xmin;
+ ushort ymin;
+ ushort xmax;
+ ushort ymax;
+ ushort hres;
+ ushort vres;
+ uchar palette[48];
+ char reserved;
+ char color_planes;
+ ushort bytes_per_line;
+ ushort palette_type;
+ char filler[58];
+ uchar data; // unbounded
+};
+
+/* .md2 triangle model file format */
+enum{
+ IDALIASHEADER = ('2'<<24)+('P'<<16)+('D'<<8)+'I',
+ ALIAS_VERSION = 8,
+ MAX_TRIANGLES = 4096,
+ MAX_VERTS = 2048,
+ MAX_FRAMES = 512,
+ MAX_MD2SKINS = 32,
+ MAX_SKINNAME = 64
+};
+struct dstvert_t{
+ short s;
+ short t;
+};
+struct dtriangle_t{
+ short index_xyz[3];
+ short index_st[3];
+};
+struct dtrivertx_t{
+ uchar v[3]; // scaled byte to fit in frame mins/maxs
+ uchar lightnormalindex;
+};
+struct daliasframe_t{
+ float scale[3]; // multiply byte verts by this
+ float translate[3]; // then add this
+ char name[16]; // frame name from grabbing
+ dtrivertx_t verts[1]; // variable sized
+};
+
+/* glcmd format
+ * a positive integer starts a tristrip command, followed by that many vertex
+ * structures. a negative integer starts a trifan command, followed by -x
+ * vertexes a zero indicates the end of the command list. a vertex consists of
+ * a floating point s, a floating point t, and an integer vertex index. */
+struct dmdl_t{
+ int ident;
+ int version;
+ int skinwidth;
+ int skinheight;
+ int framesize; // byte size of each frame
+ int num_skins;
+ int num_xyz;
+ int num_st; // greater than num_xyz for seams
+ int num_tris;
+ int num_glcmds; // dwords in strip/fan command lis
+ int num_frames;
+ int ofs_skins; // each skin is a MAX_SKINNAME string
+ int ofs_st; // byte offset from start for stverts
+ int ofs_tris; // offset for dtriangles
+ int ofs_frames; // offset for first frame
+ int ofs_glcmds;
+ int ofs_end; // end of file
+};
+
+/* .sp2 sprite file format */
+enum{
+ IDSPRITEHEADER = ('2'<<24)+('S'<<16)+('D'<<8)+'I',
+ SPRITE_VERSION = 2
+};
+struct dsprframe_t{
+ int width;
+ int height;
+ int origin_x;
+ int origin_y; // raster coordinates inside pic
+ char name[MAX_SKINNAME]; // name of pcx file
+};
+struct dsprite_t{
+ int ident;
+ int version;
+ int numframes;
+ dsprframe_t frames[1]; // variable sized
+};
+
+/* .wal texture file format */
+enum{
+ MIPLEVELS = 4
+};
+struct miptex_t{
+ char name[32];
+ uint width;
+ uint height;
+ uint offsets[MIPLEVELS]; // four mip maps stored
+ char animname[32]; // next frame in animation chain
+ int flags;
+ int contents;
+ int value;
+};
+
+/* .bsp file format */
+enum{
+ IDBSPHEADER = ('P'<<24)+('S'<<16)+('B'<<8)+'I',
+ BSPVERSION = 38,
+
+ /* upper design bounds; leaffaces, leafbrushes, planes, and verts are
+ * still bounded by 16 bit short limits */
+ MAX_MAP_MODELS = 1024,
+ MAX_MAP_BRUSHES = 8192,
+ MAX_MAP_ENTITIES = 2048,
+ MAX_MAP_ENTSTRING = 0x40000,
+ MAX_MAP_TEXINFO = 8192,
+ MAX_MAP_AREAS = 256,
+ MAX_MAP_AREAPORTALS = 1024,
+ MAX_MAP_PLANES = 65536,
+ MAX_MAP_NODES = 65536,
+ MAX_MAP_BRUSHSIDES = 65536,
+ MAX_MAP_LEAFS = 65536,
+ MAX_MAP_VERTS = 65536,
+ MAX_MAP_FACES = 65536,
+ MAX_MAP_LEAFFACES = 65536,
+ MAX_MAP_LEAFBRUSHES = 65536,
+ MAX_MAP_PORTALS = 65536,
+ MAX_MAP_EDGES = 128000,
+ MAX_MAP_SURFEDGES = 256000,
+ MAX_MAP_LIGHTING = 0x200000,
+ MAX_MAP_VISIBILITY = 0x100000,
+
+ /* key / value pair sizes */
+ MAX_KEY = 32,
+ MAX_VALUE = 1024,
+
+ LUMP_ENTITIES = 0,
+ LUMP_PLANES = 1,
+ LUMP_VERTEXES = 2,
+ LUMP_VISIBILITY = 3,
+ LUMP_NODES = 4,
+ LUMP_TEXINFO = 5,
+ LUMP_FACES = 6,
+ LUMP_LIGHTING = 7,
+ LUMP_LEAFS = 8,
+ LUMP_LEAFFACES = 9,
+ LUMP_LEAFBRUSHES = 10,
+ LUMP_EDGES = 11,
+ LUMP_SURFEDGES = 12,
+ LUMP_MODELS = 13,
+ LUMP_BRUSHES = 14,
+ LUMP_BRUSHSIDES = 15,
+ LUMP_POP = 16,
+ LUMP_AREAS = 17,
+ LUMP_AREAPORTALS = 18,
+ HEADER_LUMPS = 19,
+
+ /* 0-2 are axial planes */
+ PLANE_X = 0,
+ PLANE_Y = 1,
+ PLANE_Z = 2,
+ /* 3-5 are non-axial planes snapped to the nearest */
+ PLANE_ANYX = 3,
+ PLANE_ANYY = 4,
+ PLANE_ANYZ = 5
+ /* planes (x&~1) and (x&~1)+1 are always opposites */
+};
+struct lump_t{
+ int fileofs;
+ int filelen;
+};
+struct dheader_t{
+ int ident;
+ int version;
+ lump_t lumps[HEADER_LUMPS];
+};
+
+struct dmodel_t{
+ float mins[3];
+ float maxs[3];
+ float origin[3]; // for sounds or lights
+ int headnode;
+ int firstface;
+ /* submodels just draw faces without walking the bsp tree */
+ int numfaces;
+};
+struct dvertex_t{
+ float point[3];
+};
+struct dplane_t{
+ float normal[3];
+ float dist;
+ int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
+};
+struct dnode_t{
+ int planenum;
+ int children[2]; // negative numbers are -(leafs+1), not nodes
+ short mins[3]; // for frustom culling
+ short maxs[3];
+ ushort firstface;
+ ushort numfaces; // counting both sides
+};
+struct texinfo_t{
+ float vecs[2][4]; // [s/t][xyz offset]
+ int flags; // miptex flags + overrides
+ int value; // light emission, etc
+ char texture[32]; // texture name (textures/*.wal)
+ int nexttexinfo; // for animations, -1 = end of chain
+};
+
+enum{
+ MAXLIGHTMAPS = 4,
+ ANGLE_UP = -1,
+ ANGLE_DOWN = -2
+};
+/* note that edge 0 is never used, because negative edge nums are used for
+ * counterclockwise use of the edge in a face */
+struct dedge_t{
+ ushort v[2]; // vertex numbers
+};
+struct dface_t{
+ ushort planenum;
+ short side;
+ int firstedge; // we must support > 64k edges
+ short numedges;
+ short texinfo;
+ /* lighting info */
+ uchar styles[MAXLIGHTMAPS];
+ int lightofs; // start of [numstyles*surfsize] samples
+};
+struct dleaf_t{
+ int contents; // OR of all brushes (not needed?)
+ short cluster;
+ short area;
+ short mins[3]; // for frustum culling
+ short maxs[3];
+ ushort firstleafface;
+ ushort numleaffaces;
+ ushort firstleafbrush;
+ ushort numleafbrushes;
+};
+struct dbrushside_t{
+ ushort planenum; // facing out of the leaf
+ short texinfo;
+};
+struct dbrush_t{
+ int firstside;
+ int numsides;
+ int contents;
+};
+
+/* the visibility lump consists of a header with a count, then byte offsets for
+ * the PVS and PHS of each cluster, then the raw compressed bit vectors */
+enum{
+ DVIS_PVS = 0,
+ DVIS_PHS = 1
+};
+struct dvis_t{
+ int numclusters;
+ int bitofs[8][2]; // bitofs[numclusters][2]
+};
+/* each area has a list of portals that lead into other areas; when portals are
+ * closed, other areas may not be visible or hearable even if the vis info says
+ * that it should be */
+struct dareaportal_t{
+ int portalnum;
+ int otherarea;
+};
+struct darea_t{
+ int numareaportals;
+ int firstareaportal;
+};
+
+#pragma pack off
+
+struct vrect_t{
+ int x;
+ int y;
+ int width;
+ int height;
+ vrect_t *pnext;
+};
+struct viddef_t{
+ int width;
+ int height;
+ pixel_t *buffer; // invisible buffer
+ pixel_t *colormap; // 256 * VID_GRADES size
+ pixel_t *alphamap; // 256 * 256 translucency map
+ int rowbytes; // may be > width if displayed in a window or <0 for stupid dibs
+};
+extern viddef_t vid;
+
+#define REF_VERSION "SOFT 0.01"
+/* skins are outline flood filled and mip mapped; pics and sprites with alpha
+ * will be outline flood filled pic won't be mip mapped */
+
+extern cvar_t *sw_aliasstats;
+extern cvar_t *sw_clearcolor;
+extern cvar_t *sw_drawflat;
+extern cvar_t *sw_draworder;
+extern cvar_t *sw_maxedges;
+extern cvar_t *sw_maxsurfs;
+extern cvar_t *sw_mipcap;
+extern cvar_t *sw_mipscale;
+extern cvar_t *sw_mode;
+extern cvar_t *sw_reportsurfout;
+extern cvar_t *sw_reportedgeout;
+extern cvar_t *sw_stipplealpha;
+extern cvar_t *sw_surfcacheoverride;
+extern cvar_t *sw_waterwarp;
+extern cvar_t *r_fullbright;
+extern cvar_t *r_lefthand;
+extern cvar_t *r_drawentities;
+extern cvar_t *r_drawworld;
+extern cvar_t *r_dspeeds;
+extern cvar_t *r_lerpmodels;
+extern cvar_t *r_speeds;
+extern cvar_t *r_lightlevel; //FIXME HACK
+
+typedef enum imagetype_t{
+ it_skin,
+ it_sprite,
+ it_wall,
+ it_pic,
+ it_sky
+}imagetype_t;
+struct image_t{
+ char name[MAX_QPATH]; // game path, including extension
+ imagetype_t type;
+ int width;
+ int height;
+ qboolean transparent; // true if any 255 pixels in image
+ int registration_sequence; // 0 = free
+ uchar *pixels[4]; // mip levels
+};
+
+typedef enum rserr_t{
+ rserr_ok,
+ rserr_invalid_fullscreen,
+ rserr_invalid_mode,
+ rserr_unknown
+}rserr_t;
+
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct oldrefdef_t{
+ vrect_t vrect; // subwindow in video for refresh
+ // FIXME: not need vrect next field here?
+ vrect_t aliasvrect; // scaled Alias version
+ int vrectright;
+ int vrectbottom; // right & bottom screen coords
+ int aliasvrectright;
+ int aliasvrectbottom; // scaled Alias versions
+ /* rightmost right edge we care about, for use in edge list */
+ float vrectrightedge;
+ float fvrectx;
+ float fvrecty; // for floating-point compares
+ float fvrectx_adj;
+ float fvrecty_adj; // left and top edges, for clamping
+ int vrect_x_adj_shift20; // vrect.x+0.5-epsilon << 20
+ int vrectright_adj_shift20; // vrectright+0.5-epsilon << 20
+ float fvrectright_adj;
+ float fvrectbottom_adj;
+ /* right and bottom edges, for clamping */
+ float fvrectright; // rightmost edge, for Alias clamping
+ float fvrectbottom; // bottommost edge, for Alias clamping
+ /* at Z = 1.0, this many X is visible; 2.0 = 90 degrees */
+ float horizontalFieldOfView;
+ float xOrigin; // should probably always be 0.5
+ float yOrigin; // between be around 0.3 to 0.5
+ vec3_t vieworg;
+ vec3_t viewangles;
+ int ambientlight;
+};
+extern oldrefdef_t r_refdef;
+
+/* d*_t structures are on-disk representations; m*_t structures are in-memory */
+
+enum{
+ SIDE_FRONT = 0,
+ SIDE_BACK = 1,
+ SIDE_ON = 2,
+
+ // FIXME: differentiate from texinfo SURF_ flags
+ SURF_PLANEBACK = 1<<1,
+ SURF_DRAWSKY = 1<<2, // sky brush face
+ SURF_DRAWTURB = 1<<4,
+ SURF_DRAWBACKGROUND = 1<<6,
+ SURF_DRAWSKYBOX = 1<<7, // sky box
+ SURF_FLOW = 1<<8,
+
+ CONTENTS_NODE = -1
+};
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct mvertex_t{
+ vec3_t position;
+};
+/* !!! if this is changed, it must be changed in asm_i386.h too !!! */
+struct mplane_t{
+ vec3_t normal;
+ float dist;
+ uchar type; // for texture axis selection and fast side tests
+ uchar signbits; // signx + signy<<1 + signz<<1
+ uchar pad[2];
+};
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct medge_t{
+ ushort v[2];
+ uint cachededgeoffset;
+};
+struct mtexinfo_t{
+ float vecs[2][4];
+ float mipadjust;
+ image_t *image;
+ int flags;
+ int numframes;
+ mtexinfo_t *next; // animation chain
+};
+struct msurface_t{
+ int visframe; // should be drawn when node is crossed
+ int dlightframe;
+ int dlightbits;
+ mplane_t *plane;
+ int flags;
+ int firstedge; // look up in model->surfedges[], negative numbers
+ int numedges; // are backwards edges
+ /* surface generation data */
+ surfcache_t *cachespots[MIPLEVELS];
+ short texturemins[2];
+ short extents[2];
+ mtexinfo_t *texinfo;
+ /* lighting info */
+ uchar styles[MAXLIGHTMAPS];
+ uchar *samples; // [numstyles*surfsize]
+ msurface_t *nextalphasurface;
+};
+
+struct mnode_t{
+ /* common with leaf */
+ int contents; // CONTENTS_NODE, to differentiate from leafs
+ int visframe; // node needs to be traversed if current
+ short minmaxs[6]; // for bounding box culling
+ mnode_t *parent;
+ /* node specific */
+ mplane_t *plane;
+ mnode_t *children[2];
+ ushort firstsurface;
+ ushort numsurfaces;
+};
+struct mleaf_t{
+ /* common with node */
+ int contents; // wil be something other than CONTENTS_NODE
+ int visframe; // node needs to be traversed if current
+ short minmaxs[6]; // for bounding box culling
+ mnode_t *parent;
+ /* leaf specific */
+ int cluster;
+ int area;
+ msurface_t **firstmarksurface;
+ int nummarksurfaces;
+ int key; // BSP sequence number for leaf's contents
+};
+
+typedef enum modtype_t{
+ mod_bad,
+ mod_brush,
+ mod_sprite,
+ mod_alias
+}modtype_t;
+struct model_t{
+ char name[MAX_QPATH];
+ int registration_sequence;
+ modtype_t type;
+ int numframes;
+ int flags;
+ /* volume occupied by the model graphics */
+ vec3_t mins;
+ vec3_t maxs;
+ /* solid volume for clipping (sent from server) */
+ qboolean clipbox;
+ vec3_t clipmins;
+ vec3_t clipmaxs;
+ /* brush model */
+ int firstmodelsurface;
+ int nummodelsurfaces;
+ int numsubmodels;
+ dmodel_t *submodels;
+ int numplanes;
+ mplane_t *planes;
+ int numleafs; // number of visible leafs, not counting 0
+ mleaf_t *leafs;
+ int numvertexes;
+ mvertex_t *vertexes;
+ int numedges;
+ medge_t *edges;
+ int numnodes;
+ int firstnode;
+ mnode_t *nodes;
+ int numtexinfo;
+ mtexinfo_t *texinfo;
+ int numsurfaces;
+ msurface_t *surfaces;
+ int numsurfedges;
+ int *surfedges;
+ int nummarksurfaces;
+ msurface_t **marksurfaces;
+ dvis_t *vis;
+ uchar *lightdata;
+ /* for alias models and sprites */
+ image_t *skins[MAX_MD2SKINS];
+ void *extradata;
+ int extradatasize;
+};
+
+extern int registration_sequence;
+
+#define PARTICLE_Z_CLIP 8.0
+#define XCENTERING (1.0 / 2.0)
+#define YCENTERING (1.0 / 2.0)
+#define CLIP_EPSILON 0.001
+#define BACKFACE_EPSILON 0.01
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+#define NEAR_CLIP 0.01
+enum{
+ CACHE_SIZE = 32,
+ VID_CBITS = 6,
+ VID_GRADES = 1<<VID_CBITS,
+ MAXVERTS = 64, // max points in a surface polygon
+ /* max points in an intermediate polygon (while processing) */
+ MAXWORKINGVERTS = MAXVERTS+4,
+ /* !!! if this is changed, it must be changed in d_ifacea.h too !!! */
+ MAXHEIGHT = 4096,
+ MAXWIDTH = 4096,
+ /* distance that's always guaranteed to be farther away than anything
+ * in the scene */
+ INFINITE_DISTANCE = 0x10000,
+ WARP_WIDTH = 320,
+ WARP_HEIGHT = 240,
+ MAX_LBM_HEIGHT = 480,
+
+ /* !!! must be kept the same as in quakeasm.h !!! */
+ TRANSPARENT_COLOR = 0xff,
+ /* !!! if this is changed, it must be changed in d_ifacea.h too !!! */
+ TURB_TEX_SIZE = 64, // base turbulent texture size
+ /* !!! if this is changed, it must be changed in d_ifacea.h too !!! */
+ CYCLE = 128, // turbulent cycle size
+
+ SCANBUFFERPAD = 0x1000,
+ DS_SPAN_LIST_END = -128,
+ NUMSTACKEDGES = 2000,
+ MINEDGES = NUMSTACKEDGES,
+ NUMSTACKSURFACES = 1000,
+ MINSURFACES = NUMSTACKSURFACES,
+ MAXSPANS = 3000,
+
+ /* finalvert_t.flags */
+ ALIAS_LEFT_CLIP = 1<<0,
+ ALIAS_TOP_CLIP = 1<<1,
+ ALIAS_RIGHT_CLIP = 1<<2,
+ ALIAS_BOTTOM_CLIP = 1<<3,
+ ALIAS_Z_CLIP = 1<<4,
+ ALIAS_XY_CLIP_MASK = 0xf,
+
+ SURFCACHE_SIZE_AT_320X240 = 1024*768,
+ /* value returned by R_BmodelCheckBBox() if bbox is trivially rejected */
+ BMODEL_FULLY_CLIPPED = 1<<4,
+ MAXALIASVERTS = 2000, // TODO: tune this
+ ALIAS_Z_CLIP_PLANE = 4,
+ /* turbulence stuff */
+ AMP = 0x80000,
+ AMP2 = 3,
+ SPEED = 20
+};
+struct emitpoint_t{
+ float u;
+ float v;
+ float s;
+ float t;
+ float zi;
+};
+
+/* asm: if you modidify finalvert_t's definition, make sure to change the
+ * associated offsets too! */
+#ifdef SMALL_FINALVERT
+struct finalvert_t{
+ short u;
+ short v;
+ short s;
+ short t;
+ int l;
+ int zi;
+ int flags;
+ float xyz[3]; // eye space
+};
+#else // !SMALL_FINALVERT
+struct finalvert_t{
+ int u;
+ int v;
+ int s;
+ int t;
+ int l;
+ int zi;
+ int flags;
+ float xyz[3]; // eye space
+};
+#endif // SMALL_FINALVERT
+
+struct affinetridesc_t{
+ void *pskin;
+ int pskindesc;
+ int skinwidth;
+ int skinheight;
+ dtriangle_t *ptriangles;
+ finalvert_t *pfinalverts;
+ int numtriangles;
+ int drawtype;
+ int seamfixupX16;
+ qboolean do_vis_thresh;
+ int vis_thresh;
+};
+extern affinetridesc_t r_affinetridesc;
+
+struct drawsurf_t{
+ uchar *surfdat; // destination for generated surface
+ int rowbytes; // destination logical width in bytes
+ msurface_t *surf; // description for surface to generate
+ /* adjust for lightmap levels for dynamic lighting */
+ fixed8_t lightadj[MAXLIGHTMAPS];
+ image_t *image;
+ int surfmip; // mipmapped ratio of surface texels / world pixels
+ int surfwidth; // in mipmapped texels
+ int surfheight; // in mipmapped texels
+};
+extern drawsurf_t r_drawsurf;
+
+struct alight_t{
+ int ambientlight;
+ int shadelight;
+ float *plightvec;
+};
+
+/* clipped bmodel edges */
+struct bedge_t{
+ mvertex_t *v[2];
+ bedge_t *pnext;
+};
+
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct clipplane_t{
+ vec3_t normal;
+ float dist;
+ clipplane_t *next;
+ uchar leftedge;
+ uchar rightedge;
+ uchar reserved[2];
+};
+
+struct surfcache_t{
+ surfcache_t *next;
+ surfcache_t **owner; // nil is an empty chunk of memory
+ int lightadj[MAXLIGHTMAPS]; // checked for strobe flush
+ int dlight;
+ int size; // including header
+ uint width;
+ uint height; // DEBUG only needed for debug
+ float mipscale;
+ image_t *image;
+ uchar data[4]; // width*height elements
+};
+extern surfcache_t *sc_rover;
+extern surfcache_t *d_initial_rover;
+
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct espan_t{
+ int u;
+ int v;
+ int count;
+ espan_t *pnext;
+};
+
+/* used by the polygon drawer (R_POLY.C) and sprite setup code (R_SPRITE.C) */
+struct polydesc_t{
+ int nump;
+ emitpoint_t *pverts;
+ uchar *pixels; // image
+ int pixel_width; // image width
+ int pixel_height; // image height
+ vec3_t vup;
+ vec3_t vright;
+ vec3_t vpn; // in worldspace, for plane eq
+ float dist;
+ float s_offset;
+ float t_offset;
+ float viewer_position[3];
+ void (*drawspanlet)(void);
+ int stipple_parity;
+};
+
+// FIXME: compress, make a union if that will help
+// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte
+struct surf_t{
+ surf_t *next; // active surface stack in r_edge.c
+ surf_t *prev; // used in r_edge.c for active surf stack
+ espan_t *spans; // pointer to linked list of spans to draw
+ int key; // sorting key (BSP order)
+ int last_u; // set during tracing
+ int spanstate; // 0 = not in span; 1 = in span; -1 in inverted span (end before start)
+ int flags; // currentface flags
+ msurface_t *msurf;
+ entity_t *entity;
+ float nearzi; // nearest 1/z on surface, for mipmapping
+ qboolean insubmodel;
+ float d_ziorigin;
+ float d_zistepu;
+ float d_zistepv;
+ int pad[2]; // to 64 bytes
+};
+
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct edge_t{
+ fixed16_t u;
+ fixed16_t u_step;
+ edge_t *prev;
+ edge_t *next;
+ ushort surfs[2];
+ edge_t *nextremove;
+ float nearzi;
+ medge_t *owner;
+};
+
+struct aliastriangleparms_t{
+ finalvert_t *a;
+ finalvert_t *b;
+ finalvert_t *c;
+};
+extern aliastriangleparms_t aliastriangleparms;
+
+struct swstate_t{
+ qboolean fullscreen;
+ int prev_mode; // last valid SW mode
+ uchar gammatable[256];
+ uchar currentpalette[1024];
+
+};
+extern swstate_t sw_state;
+
+extern int d_spanpixcount;
+extern int r_framecount; // sequence # of current frame since quake started
+/* scale-up factor for screen u and v on Alias vertices passed to driver */
+extern float r_aliasuvscale;
+extern qboolean r_dowarp;
+extern vec3_t r_pright;
+extern vec3_t r_pup;
+extern vec3_t r_ppn;
+extern void *acolormap; // FIXME: should go away
+extern int c_surf;
+extern uchar r_warpbuffer[WARP_WIDTH*WARP_HEIGHT];
+extern float scale_for_mip;
+extern qboolean d_roverwrapped;
+
+extern float d_sdivzstepu;
+extern float d_tdivzstepu;
+extern float d_zistepu;
+extern float d_sdivzstepv;
+extern float d_tdivzstepv;
+extern float d_zistepv;
+extern float d_sdivzorigin;
+extern float d_tdivzorigin;
+extern float d_ziorigin;
+extern fixed16_t sadjust;
+extern fixed16_t tadjust;
+extern fixed16_t bbextents;
+extern fixed16_t bbextentt;
+
+extern int d_vrectx;
+extern int d_vrecty;
+extern int d_vrectright_particle;
+extern int d_vrectbottom_particle;
+extern int d_pix_min;
+extern int d_pix_max;
+extern int d_pix_shift;
+
+extern pixel_t *d_viewbuffer;
+extern short *d_pzbuffer;
+extern uint d_zrowbytes;
+extern uint d_zwidth;
+extern short *zspantable[MAXHEIGHT];
+extern int d_scantable[MAXHEIGHT];
+extern int d_minmip;
+extern float d_scalemip[3];
+
+/* surfaces are generated in back to front order by the bsp, so if a surf
+ * pointer is greater than another one, it should be drawn in front.
+ * surfaces[1] is the background, and is used as the active surface stack.
+ * surfaces[0] is a dummy, because index 0 is used to indicate no surface
+ * attached to an edge_t */
+extern int cachewidth;
+extern pixel_t *cacheblock;
+extern int r_screenwidth;
+extern int r_drawnpolycount;
+extern int sintable[1280];
+extern int intsintable[1280];
+extern int blanktable[1280];
+extern vec3_t vup;
+extern vec3_t base_vup;
+extern vec3_t vpn;
+extern vec3_t base_vpn;
+extern vec3_t vright;
+extern vec3_t base_vright;
+extern surf_t *surfaces;
+extern surf_t *surface_p;
+extern surf_t *surf_max;
+
+extern vec3_t sxformaxis[4]; // s axis transformed into viewspace
+extern vec3_t txformaxis[4]; // t axis transformed into viewspac
+extern float xcenter;
+extern float ycenter;
+extern float xscale;
+extern float yscale;
+extern float xscaleinv;
+extern float yscaleinv;
+extern float xscaleshrink;
+extern float yscaleshrink;
+extern int ubasestep;
+extern int errorterm;
+extern int erroradjustup;
+extern int erroradjustdown;
+
+extern clipplane_t view_clipplanes[4];
+extern int *pfrustum_indexes[4];
+
+extern mplane_t screenedge[4];
+extern vec3_t r_origin;
+extern entity_t r_worldentity;
+extern model_t *currentmodel;
+extern entity_t *currententity;
+extern vec3_t modelorg;
+extern vec3_t r_entorigin;
+extern float verticalFieldOfView;
+extern float xOrigin;
+extern float yOrigin;
+extern int r_visframecount;
+extern msurface_t *r_alpha_surfaces;
+
+extern qboolean insubmodel;
+
+extern int c_faceclip;
+extern int r_polycount;
+extern int r_wholepolycount;
+extern int ubasestep;
+extern int errorterm;
+extern int erroradjustup;
+extern int erroradjustdown;
+extern fixed16_t sadjust;
+extern fixed16_t tadjust;
+extern fixed16_t bbextents;
+extern fixed16_t bbextentt;
+extern mvertex_t *r_ptverts;
+extern mvertex_t *r_ptvertsmax;
+extern float entity_rotation[3][3];
+extern int r_currentkey;
+extern int r_currentbkey;
+extern int r_amodels_drawn;
+extern edge_t *auxedges;
+extern int r_numallocatededges;
+extern edge_t *r_edges;
+extern edge_t *edge_p;
+extern edge_t *edge_max;
+extern edge_t *newedges[MAXHEIGHT];
+extern edge_t *removeedges[MAXHEIGHT];
+extern edge_t edge_head; // FIXME: make stack vars when debugging done
+extern edge_t edge_tail;
+extern edge_t edge_aftertail;
+extern int r_aliasblendcolor;
+extern float aliasxscale;
+extern float aliasyscale;
+extern float aliasxcenter;
+extern float aliasycenter;
+extern int r_outofsurfaces;
+extern int r_outofedges;
+extern mvertex_t *r_pcurrentvertbase;
+extern int r_maxvalidedgeoffset;
+
+extern float r_time1;
+extern float da_time1;
+extern float da_time2;
+extern float dp_time1;
+extern float dp_time2;
+extern float db_time1;
+extern float db_time2;
+extern float rw_time1;
+extern float rw_time2;
+extern float se_time1;
+extern float se_time2;
+extern float de_time1;
+extern float de_time2;
+extern float dv_time1;
+extern float dv_time2;
+extern int r_frustum_indexes[4*6];
+extern int r_maxsurfsseen;
+extern int r_maxedgesseen;
+extern int r_cnumsurfs;
+extern qboolean r_surfsonstack;
+extern mleaf_t *r_viewleaf;
+extern int r_viewcluster;
+extern int r_oldviewcluster;
+extern int r_clipflags;
+extern int r_dlightframecount;
+extern qboolean r_fov_greater_than_90;
+extern image_t *r_notexture_mip;
+extern model_t *r_worldmodel;
+
+extern refdef_t r_newrefdef;
+extern surfcache_t *sc_rover;
+extern surfcache_t *sc_base;
+extern void *colormap;
+
+extern unsigned d_8to24table[256]; // base
+extern mtexinfo_t *sky_texinfo[6];
+
+extern cvar_t *vid_fullscreen;
+extern cvar_t *vid_gamma;
+extern cvar_t *scr_viewsize;
+extern cvar_t *crosshair;
+
+#define POWERSUIT_SCALE 4.0F
+enum{
+ API_VERSION = 3,
+ MAX_DLIGHTS = 32,
+ MAX_ENTITIES = 128,
+ MAX_PARTICLES = 4096,
+
+ SHELL_RED_COLOR = 0xf2,
+ SHELL_GREEN_COLOR = 0xd0,
+ SHELL_BLUE_COLOR = 0xf3,
+ SHELL_RG_COLOR = 0xdc,
+ SHELL_RB_COLOR = 0x68,
+ SHELL_BG_COLOR = 0x78,
+ SHELL_WHITE_COLOR = 0xd7,
+ /* ROGUE */
+ SHELL_DOUBLE_COLOR = 0xdf,
+ SHELL_HALF_DAM_COLOR = 0x90,
+ SHELL_CYAN_COLOR = 0x72,
+
+ ENTITY_FLAGS = 68
+};
+
+struct entity_t{
+ model_t *model; // opaque type outside refresh
+ float angles[3];
+
+ /* most recent data */
+ float origin[3]; // also used as RF_BEAM's "from"
+ int frame; // also used as RF_BEAM's diameter
+ /* previous data for lerping */
+ float oldorigin[3]; // also used as RF_BEAM's "to"
+ int oldframe;
+
+ float backlerp; // 0.0 = current, 1.0 = old
+ int skinnum; // also used as RF_BEAM's palette index
+ int lightstyle; // for flashing entities
+ float alpha; // ignore if RF_TRANSLUCENT isn't set
+ image_t *skin; // nil for inline skin
+ int flags;
+};
+struct dlight_t{
+ vec3_t origin;
+ vec3_t color;
+ float intensity;
+};
+struct particle_t{
+ vec3_t origin;
+ int color;
+ float alpha;
+};
+struct lightstyle_t{
+ float rgb[3]; // 0.0 - 2.0
+ float white; // highest of rgb
+};
+
+struct refdef_t{
+ int x; // in virtual screen coordinates
+ int y;
+ int width;
+ int height;
+ float fov_x;
+ float fov_y;
+ float vieworg[3];
+ float viewangles[3];
+ float blend[4]; // rgba 0-1 full screen blend
+ float time; // time is uesed to auto animate
+ int rdflags; // RDF_UNDERWATER, etc
+ uchar *areabits; // if not nil, only areas with set bits will be drawn
+
+ lightstyle_t *lightstyles; // [MAX_LIGHTSTYLES]
+ int num_entities;
+ entity_t *entities;
+ int num_dlights;
+ dlight_t *dlights;
+ int num_particles;
+ particle_t *particles;
+};
+
+struct refexport_t{
+ int api_version;
+ /* All data that will be used in a level should be registered before
+ * rendering any frames to prevent disk hits, but they can still be
+ * registered at a later time if necessary.
+ * EndRegistration will free any remaining data that wasn't registered.
+ * Any model_s or skin_s pointers from before the BeginRegistration are
+ * no longer valid after EndRegistration.
+ * Skins and images need to be differentiated, because skins are flood
+ * filled to eliminate mip map edge errors, and pics have an implicit
+ * "pics/" prepended to the name. (a pic name that starts with a slash
+ * will not use the "pics/" prefix or the ".pcx" postfix) */
+ qboolean (*Init)(void *, void *);
+ void (*Shutdown)(void);
+ void (*BeginRegistration)(char *);
+ model_t* (*RegisterModel)(char *);
+ image_t* (*RegisterSkin)(char *);
+ image_t* (*RegisterPic)(char *);
+ void (*SetSky)(char *, float, vec3_t);
+ void (*EndRegistration)(void);
+ void (*RenderFrame)(refdef_t *);
+ void (*DrawGetPicSize)(int *, int *, char *);
+ void (*DrawPic)(int, int, char *);
+ void (*DrawStretchPic)(int, int, int, int, char *);
+ void (*DrawChar)(int, int, int);
+ void (*DrawTileClear)(int, int, int, int, char *);
+ void (*DrawFill)(int, int, int, int, int);
+ void (*DrawFadeScreen)(void);
+ void (*DrawStretchRaw)(int, int, int, int, int, int, uchar *);
+ void (*CinematicSetPalette)(uchar *);
+ void (*BeginFrame)(float);
+ void (*EndFrame)(void);
+ void (*AppActivate)(qboolean);
+};
+extern refexport_t re;
+
+struct refimport_t{
+ void (*Sys_Error)(int, char *, ...);
+ void (*Cmd_AddCommand)(char *, void(*)(void));
+ void (*Cmd_RemoveCommand)(char *);
+ int (*Cmd_Argc)(void);
+ char* (*Cmd_Argv)(int);
+ void (*Cmd_ExecuteText)(int, char *);
+ void (*Con_Printf)(int, char *, ...);
+ /* files will be memory mapped read only; the returned buffer may be
+ * part of a larger pak file, or a discrete file from anywhere in the
+ * quake search path
+ * a -1 return means the file does not exist
+ * nil can be passed for buf to just determine existance */
+ int (*FS_LoadFile)(char *, void **);
+ void (*FS_FreeFile)(void *);
+ char* (*FS_Gamedir)(void);
+ cvar_t* (*Cvar_Get)(char *, char *, int);
+ cvar_t* (*Cvar_Set)(char *, char *);
+ void (*Cvar_SetValue)(char *, float);
+ qboolean (*Vid_GetModeInfo)(int *, int *, int);
+ void (*Vid_MenuInit)(void);
+ void (*Vid_NewWindow)(int, int);
+};
+extern refimport_t ri;
+
+extern float scr_con_current;
+extern float scr_conlines; // lines of console to display
+extern int sb_lines;
+extern vrect_t scr_vrect; // position of render window
+extern char crosshair_pic[MAX_QPATH];
+extern int crosshair_width;
+extern int crosshair_height;
+
+extern cvar_t *s_volume;
+extern cvar_t *s_loadas8bit;
+extern cvar_t *s_khz;
+extern cvar_t *s_show;
+extern cvar_t *s_mixahead;
+extern cvar_t *s_testsound;
+extern cvar_t *s_primary;
+
+enum{
+ MAX_CHANNELS = 32,
+ MAX_RAW_SAMPLES = 8192
+};
+
+/* !!! if this is changed, the asm code must change !!! */
+struct portable_samplepair_t{
+ int left;
+ int right;
+};
+extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
+
+struct sfxcache_t{
+ int length;
+ int loopstart;
+ int speed; // not needed, because converted on load?
+ int width;
+ int stereo;
+ uchar data[1]; // variable sized
+};
+
+struct sfx_t{
+ char name[MAX_QPATH];
+ int registration_sequence;
+ sfxcache_t *cache;
+ char *truename;
+};
+
+/* a playsound_t will be generated by each call to S_StartSound, when the mixer
+ * reaches playsound->begin, the playsound will be assigned to a channel */
+struct playsound_t{
+ playsound_t *prev;
+ playsound_t *next;
+ sfx_t *sfx;
+ float volume;
+ float attenuation;
+ int entnum;
+ int entchannel;
+ qboolean fixed_origin; // use origin field instead of entnum's origin
+ vec3_t origin;
+ uint begin; // begin on this sample
+};
+extern playsound_t s_pendingplays;
+
+struct dma_t{
+ int channels;
+ int samples; // mono samples in buffer
+ int submission_chunk; // don't mix less than this #
+ int samplepos; // in mono samples
+ int samplebits;
+ int speed;
+ uchar *buffer;
+};
+extern dma_t dma;
+
+/* !!! if this is changed, the asm code must change !!! */
+struct channel_t{
+ sfx_t *sfx; // sfx number
+ int leftvol; // 0-255 volume
+ int rightvol; // 0-255 volume
+ int end; // end time in global paintsamples
+ int pos; // sample position in sfx
+ int looping; // where to loop, -1 = no looping OBSOLETE?
+ int entnum; // to allow overriding a specific sound
+ int entchannel;
+ vec3_t origin; // only use if fixed_origin is set
+ vec_t dist_mult; // distance multiplier (attenuation/clipK)
+ int master_vol; // 0-255 master volume
+ qboolean fixed_origin; // use origin instead of fetching entnum's origin
+ qboolean autosound; // from an entity->sound, cleared each frame
+};
+extern channel_t channels[MAX_CHANNELS];
+
+struct wavinfo_t{
+ int rate;
+ int width;
+ int channels;
+ int loopstart;
+ int samples;
+ int dataofs; // chunk starts this many bytes from file start
+};
+
+extern int paintedtime;
+extern int s_rawend;
+extern vec3_t listener_origin;
+extern vec3_t listener_forward;
+extern vec3_t listener_right;
+extern vec3_t listener_up;
+
+extern cvar_t *in_joystick;
+extern cvar_t *lookspring;
+extern cvar_t *lookstrafe;
+extern cvar_t *sensitivity;
+extern cvar_t *freelook;
+extern cvar_t *m_pitch;
+
+/* key numbers passed to Key_Event() */
+enum{
+ K_TAB = 9,
+ K_ENTER = 13,
+ K_ESCAPE = 27,
+ K_SPACE = 32,
+ /* normal keys should be passed as lowercased ascii */
+ K_BACKSPACE = 127,
+ K_UPARROW = 128,
+ K_DOWNARROW = 129,
+ K_LEFTARROW = 130,
+ K_RIGHTARROW = 131,
+ K_ALT = 132,
+ K_CTRL = 133,
+ K_SHIFT = 134,
+ K_F1 = 135,
+ K_F2 = 136,
+ K_F3 = 137,
+ K_F4 = 138,
+ K_F5 = 139,
+ K_F6 = 140,
+ K_F7 = 141,
+ K_F8 = 142,
+ K_F9 = 143,
+ K_F10 = 144,
+ K_F11 = 145,
+ K_F12 = 146,
+ K_INS = 147,
+ K_DEL = 148,
+ K_PGDN = 149,
+ K_PGUP = 150,
+ K_HOME = 151,
+ K_END = 152,
+ K_KP_HOME = 160,
+ K_KP_UPARROW = 161,
+ K_KP_PGUP = 162,
+ K_KP_LEFTARROW = 163,
+ K_KP_5 = 164,
+ K_KP_RIGHTARROW = 165,
+ K_KP_END = 166,
+ K_KP_DOWNARROW = 167,
+ K_KP_PGDN = 168,
+ K_KP_ENTER = 169,
+ K_KP_INS = 170,
+ K_KP_DEL = 171,
+ K_KP_SLASH = 172,
+ K_KP_MINUS = 173,
+ K_KP_PLUS = 174,
+ /* mouse buttons generate virtual keys */
+ K_MOUSE1 = 200,
+ K_MOUSE3 = 201,
+ K_MOUSE2 = 202,
+ K_MWHEELUP = 203,
+ K_MWHEELDOWN = 204,
+ /* joystick buttons */
+ K_JOY1 = 205,
+ K_JOY2 = 206,
+ K_JOY3 = 207,
+ K_JOY4 = 208,
+ /* aux keys are for multi-buttoned joysticks to generate so they can
+ * use the normal binding process */
+ K_AUX1 = 209,
+ K_AUX2 = 210,
+ K_AUX3 = 211,
+ K_AUX4 = 212,
+ K_AUX5 = 213,
+ K_AUX6 = 214,
+ K_AUX7 = 215,
+ K_AUX8 = 216,
+ K_AUX9 = 217,
+ K_AUX10 = 218,
+ K_AUX11 = 219,
+ K_AUX12 = 220,
+ K_AUX13 = 221,
+ K_AUX14 = 222,
+ K_AUX15 = 223,
+ K_AUX16 = 224,
+ K_AUX17 = 225,
+ K_AUX18 = 226,
+ K_AUX19 = 227,
+ K_AUX20 = 228,
+ K_AUX21 = 229,
+ K_AUX22 = 230,
+ K_AUX23 = 231,
+ K_AUX24 = 232,
+ K_AUX25 = 233,
+ K_AUX26 = 234,
+ K_AUX27 = 235,
+ K_AUX28 = 236,
+ K_AUX29 = 237,
+ K_AUX30 = 238,
+ K_AUX31 = 239,
+ K_AUX32 = 240,
+ K_PAUSE = 255
+};
+extern char *keybindings[256];
+extern int key_repeats[256];
+extern int anykeydown;
+extern char chat_buffer[];
+extern int chat_bufferlen;
+extern qboolean chat_team;
+
+enum{
+ NUM_CON_TIMES = 4,
+ CON_TEXTSIZE = 32768
+};
+struct console_t{
+ qboolean initialized;
+ char text[CON_TEXTSIZE];
+ int current; // line where next message will be printed
+ int x; // offset in current line for next print
+ int display; // bottom of console displays this line
+ int ormask; // high bit mask for colored characters
+ int linewidth; // characters across screen
+ int totallines; // total lines in console scrollback
+ float cursorspeed;
+ int vislines;
+ /* cls.realtime time the line was generated for transparent notify lines */
+ float times[NUM_CON_TIMES];
+};
+extern console_t con;
+
+extern cvar_t *cl_stereo_separation;
+extern cvar_t *cl_stereo;
+extern cvar_t *cl_gun;
+extern cvar_t *cl_add_blend;
+extern cvar_t *cl_add_lights;
+extern cvar_t *cl_add_particles;
+extern cvar_t *cl_add_entities;
+extern cvar_t *cl_predict;
+extern cvar_t *cl_footsteps;
+extern cvar_t *cl_noskins;
+extern cvar_t *cl_autoskins;
+extern cvar_t *cl_upspeed;
+extern cvar_t *cl_forwardspeed;
+extern cvar_t *cl_sidespeed;
+extern cvar_t *cl_yawspeed;
+extern cvar_t *cl_pitchspeed;
+extern cvar_t *cl_run;
+extern cvar_t *cl_anglespeedkey;
+extern cvar_t *cl_shownet;
+extern cvar_t *cl_showmiss;
+extern cvar_t *cl_showclamp;
+extern cvar_t *cl_lightlevel; // FIXME HACK
+extern cvar_t *cl_paused;
+extern cvar_t *cl_timedemo;
+extern cvar_t *cl_vwep;
+
+struct frame_t{
+ qboolean valid; // cleared if delta parsing was invalid
+ int serverframe;
+ int servertime; // server time the message is valid for (in msec)
+ int deltaframe;
+ uchar areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits
+ player_state_t playerstate;
+ int num_entities;
+ int parse_entities; // non-masked index into cl_parse_entities array
+};
+
+struct centity_t{
+ entity_state_t baseline; // delta from this if not from a previous frame
+ entity_state_t current;
+ entity_state_t prev; // will always be valid, but can be just a copy of current
+ int serverframe; // if not current, this ent isn't in the frame
+ int trailcount; // for diminishing grenade trails
+ vec3_t lerp_origin; // for trails (variable hz)
+ int fly_stoptime;
+};
+extern centity_t cl_entities[MAX_EDICTS];
+
+enum{
+ MAX_CLIENTWEAPONMODELS = 20
+};
+struct clientinfo_t{
+ char name[MAX_QPATH];
+ char cinfo[MAX_QPATH];
+ image_t *skin;
+ image_t *icon;
+ char iconname[MAX_QPATH];
+ model_t *model;
+ model_t *weaponmodel[MAX_CLIENTWEAPONMODELS];
+};
+extern char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
+extern int num_cl_weaponmodels;
+
+enum{
+ CMD_BACKUP = 64 // allow a lot of command backups for very fast systems
+};
+/* client_state_t is wiped completely at every server map change */
+struct client_state_t{
+ int timeoutcount;
+ int timedemo_frames;
+ int timedemo_start;
+ qboolean refresh_prepped; // false if on new level or new ref dll
+ qboolean sound_prepped; // ambient sounds can start
+ qboolean force_refdef; // vid has changed, so we can't use a paused refdef
+ int parse_entities; // index (not anded off) into cl_parse_entities[]
+ usercmd_t cmd;
+ usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds
+ int cmd_time[CMD_BACKUP]; // time sent, for calculating pings
+ short predicted_origins[CMD_BACKUP][3]; // for debug comparing against server
+ float predicted_step; // for stair up smoothing
+ uint predicted_step_time;
+ vec3_t predicted_origin; // generated by CL_PredictMovement
+ vec3_t predicted_angles;
+ vec3_t prediction_error;
+ frame_t frame; // received from server
+ int surpressCount; // number of messages rate supressed
+ frame_t frames[UPDATE_BACKUP];
+
+ /* the client maintains its own idea of view angles, which are sent to
+ * the server each frame. it is cleared to 0 upon entering each level.
+ * the server sends a delta each frame which is added to the locally
+ * tracked view angles to account for standing on rotating objects, and
+ * teleport direction changes. */
+ vec3_t viewangles;
+ /* time that the client is rendering at. always <= cls.realtime */
+ int time; // this is the time value that the client
+ float lerpfrac; // between oldframe and frame
+ refdef_t refdef;
+ vec3_t v_forward;
+ vec3_t v_right;
+ vec3_t v_up; // set when refdef.angles is set
+
+ /* transient data from server */
+ char layout[1024]; // general 2D overlay
+ int inventory[MAX_ITEMS];
+
+ // FIXME: move this cinematic stuff into the cin_t structure
+ /* non-gameserver infornamtion */
+ FILE *cinematic_file;
+ int cinematictime; // cls.realtime for first cinematic frame
+ int cinematicframe;
+ char cinematicpalette[768];
+ qboolean cinematicpalette_active;
+
+ /* server state information */
+ qboolean attractloop; // running the attract loop, any key will menu
+ int servercount; // server identification for prespawns
+ char gamedir[MAX_QPATH];
+ int playernum;
+ char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
+
+ /* locally derived information from server state */
+ model_t *model_draw[MAX_MODELS];
+ cmodel_t *model_clip[MAX_MODELS];
+ sfx_t *sound_precache[MAX_SOUNDS];
+ image_t *image_precache[MAX_IMAGES];
+ clientinfo_t clientinfo[MAX_CLIENTS];
+ clientinfo_t baseclientinfo;
+};
+extern client_state_t cl;
+
+typedef enum connstate_t{
+ ca_uninitialized,
+ ca_disconnected, // not talking to a server
+ ca_connecting, // sending request packets to the server
+ ca_connected, // netchan_t established, waiting for svc_serverdata
+ ca_active // game views should be displayed
+}connstate_t;
+typedef enum dltype_t{
+ dl_none,
+ dl_model,
+ dl_sound,
+ dl_skin,
+ dl_single
+}dltype_t;
+typedef enum keydest_t{
+ key_game,
+ key_console,
+ key_message,
+ key_menu
+}keydest_t;
+/* the client_static_t structure is persistant through an arbitrary number of
+ * server connections */
+struct client_static_t{
+ connstate_t state;
+ keydest_t key_dest;
+ int framecount;
+ int realtime; // always increasing, no clamping, etc
+ float frametime; // seconds since last frame
+
+ /* screen rendering information */
+ /* showing loading plaque between levels; if time gets >30 sec ahead,
+ * break it */
+ float disable_screen;
+ /* on receiving a frame and cl.servercount > cls.disable_servercount,
+ * clear disable_screen */
+ int disable_servercount;
+
+ /* connection information */
+ char servername[MAX_OSPATH]; // name of server from original connect
+ float connect_time; // for connection retransmits
+ /* ushort allowing servers to work around address translating routers */
+ int quakePort;
+ netchan_t netchan;
+ int serverProtocol; // in case we are doing some kind of version hack
+ int challenge; // from the server to use for connecting
+
+ FILE *download; // file transfer from server
+ char downloadtempname[MAX_OSPATH];
+ char downloadname[MAX_OSPATH];
+ int downloadnumber;
+ dltype_t downloadtype;
+ int downloadpercent;
+
+ /* demo recording info must be here, so it isn't cleared on level change */
+ qboolean demorecording;
+ qboolean demowaiting; // don't record until a non-delta message is received
+ FILE *demofile;
+};
+extern client_static_t cls;
+
+struct cdlight_t{
+ int key; // so entities can reuse same entry
+ vec3_t color;
+ vec3_t origin;
+ float radius;
+ float die; // stop lighting after this time
+ float decay; // drop this each second
+ float minlight; // don't add when contributing less
+};
+extern cdlight_t cl_dlights[MAX_DLIGHTS];
+
+enum{
+ MAX_SUSTAINS = 32
+};
+struct cl_sustain_t{
+ int id;
+ int type;
+ int endtime;
+ int nextthink;
+ int thinkinterval;
+ vec3_t org;
+ vec3_t dir;
+ int color;
+ int count;
+ int magnitude;
+ void (*think)(cl_sustain_t *);
+};
+
+#define INSTANT_PARTICLE -10000.0
+enum{
+ PARTICLE_GRAVITY = 40,
+ BLASTER_PARTICLE_COLOR = 0xe0
+};
+struct cparticle_t{
+ cparticle_t *next;
+ float time;
+ vec3_t org;
+ vec3_t vel;
+ vec3_t accel;
+ float color;
+ float colorvel;
+ float alpha;
+ float alphavel;
+};
+
+struct kbutton_t{
+ int down[2]; // key nums holding it down
+ uint downtime; // msec timestamp
+ uint msec; // msec down this frame
+ int state;
+};
+extern kbutton_t in_mlook;
+extern kbutton_t in_klook;
+extern kbutton_t in_strafe;
+extern kbutton_t in_speed;
+
+extern int gun_frame;
+extern model_t *gun_model;
+
+enum{
+ MAXMENUITEMS = 64,
+ MTYPE_SLIDER = 0,
+ MTYPE_LIST = 1,
+ MTYPE_ACTION = 2,
+ MTYPE_SPINCONTROL = 3,
+ MTYPE_SEPARATOR = 4,
+ MTYPE_FIELD = 5,
+ QMF_LEFT_JUSTIFY = 1<<0,
+ QMF_GRAYED = 1<<1,
+ QMF_NUMBERSONLY = 1<<2,
+};
+struct menuframework_t{
+ int x;
+ int y;
+ int cursor;
+ int nitems;
+ int nslots;
+ void *items[64];
+ char *statusbar;
+ void (*cursordraw)(menuframework_t *);
+};
+struct menucommon_t{
+ int type;
+ char *name;
+ int x;
+ int y;
+ menuframework_t *parent;
+ int cursor_offset;
+ int localdata[4];
+ uint flags;
+ char *statusbar;
+ void (*callback)(void *);
+ void (*statusbarfunc)(void *);
+ void (*ownerdraw)(void *);
+ void (*cursordraw)(void *);
+};
+struct menufield_t{
+ menucommon_t generic;
+ char buffer[80];
+ int cursor;
+ int length;
+ int visible_length;
+ int visible_offset;
+};
+struct menuslider_t{
+ menucommon_t generic;
+ float minvalue;
+ float maxvalue;
+ float curvalue;
+ float range;
+};
+struct menulist_t{
+ menucommon_t generic;
+ int curvalue;
+ char **itemnames;
+};
+struct menuaction_t{
+ menucommon_t generic;
+};
+struct menuseparator_t{
+ menucommon_t generic;
+};
+
+extern cvar_t *sv_paused;
+extern cvar_t *maxclients;
+/* don't reload level state when reentering */
+extern cvar_t *sv_noreload;
+/* don't reload level state when reentering development tool */
+extern cvar_t *sv_airaccelerate;
+extern cvar_t *sv_enforcetime;
+
+typedef enum redirect_t{
+ RD_NONE,
+ RD_CLIENT,
+ RD_PACKET
+}redirect_t;
+
+typedef enum server_state_t{
+ ss_dead, // no map loaded
+ ss_loading, // spawning level edicts
+ ss_game, // actively running
+ ss_cinematic,
+ ss_demo,
+ ss_pic
+}server_state_t;
+/* some qc commands are only valid before the server has finished initializing
+ * (precache commands, static sounds / objects, etc) */
+struct server_t{
+ server_state_t state; // precache commands are only valid during load
+ qboolean attractloop; // running cinematics and demos for the local system only
+ qboolean loadgame; // client begins should reuse existing entity
+ uint time; // always sv.framenum * 100 msec
+ int framenum;
+ char name[MAX_QPATH]; // map name, or cinematic name
+ cmodel_t *models[MAX_MODELS];
+ char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
+ entity_state_t baselines[MAX_EDICTS];
+ /* the multicast buffer is used to send a message to a set of clients
+ * it is only used to marshall data until SV_Multicast is called */
+ sizebuf_t multicast;
+ uchar multicast_buf[MAX_MSGLEN];
+ /* demo server information */
+ FILE *demofile;
+ qboolean timedemo; // don't time sync
+};
+extern server_t sv; // local server
+
+#define EDICT_NUM(n) ((edict_t *)((uchar *)ge->edicts + ge->edict_size*(n)))
+#define NUM_FOR_EDICT(e) ( ((uchar *)(e)-(uchar *)ge->edicts ) / ge->edict_size)
+
+struct client_frame_t{
+ int areabytes;
+ uchar areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits
+ player_state_t ps;
+ int num_entities;
+ int first_entity; // into the circular sv_packet_entities[]
+ int senttime; // for ping calculations
+};
+
+typedef enum clstate_t{
+ cs_free, // can be reused for a new connection
+ cs_zombie, // client disconnected, don't reuse connection for a couple secs
+ cs_connected, // has been assigned to a client_t, but not in game yet
+ cs_spawned // client is fully in game
+}clstate_t;
+
+enum{
+ LATENCY_COUNTS = 16,
+ RATE_MESSAGES = 10
+};
+struct client_t{
+ clstate_t state;
+ char userinfo[MAX_INFO_STRING]; // name, etc
+ int lastframe; // for delta compression
+ usercmd_t lastcmd; // for filling in big drops
+ /* every seconds this is reset, if user commands exhaust it, assume
+ * time cheating */
+ int commandMsec;
+ int frame_latency[LATENCY_COUNTS];
+ int ping;
+ int message_size[RATE_MESSAGES]; // used to rate drop packets
+ int rate;
+ int surpressCount; // number of messages rate supressed
+ edict_t *edict; // EDICT_NUM(clientnum+1)
+ char name[32]; // extracted from userinfo, high bits masked
+ int messagelevel; // for filtering printed messages
+ /* the datagram is written to by sound calls, prints, temp ents, etc.
+ * it can be harmlessly overflowed. */
+ sizebuf_t datagram;
+ uchar datagram_buf[MAX_MSGLEN];
+ client_frame_t frames[UPDATE_BACKUP]; // updates can be delta'd from here
+ uchar *download; // file being downloaded
+ int downloadsize; // total bytes (can't use EOF because of paks)
+ int downloadcount; // bytes sent
+ int lastmessage; // sv.framenum when packet was last received
+ int lastconnect;
+ int challenge; // challenge of this user, randomly generated
+ netchan_t netchan;
+};
+extern client_t *sv_client;
+
+/* a client can leave the server in one of four ways: dropping properly by
+ * quiting or disconnecting; timing out if no valid messages are received for
+ * timeout.value seconds; getting kicked off by the server operator; a program
+ * error, like an overflowed reliable buffer */
+enum{
+ /* for preventing denial of service attacks that could cycle all of
+ * them out before legitimate users connected */
+ MAX_CHALLENGES = 1024,
+ SV_OUTPUTBUF_LENGTH = MAX_MSGLEN - 16
+};
+struct challenge_t{
+ netadr_t adr;
+ int challenge;
+ int time;
+};
+struct server_static_t{
+ qboolean initialized; // sv_init has completed
+ int realtime; // always increasing, no clamping, etc
+ char mapcmd[MAX_TOKEN_CHARS]; // ie: *intro.cin+base
+ int spawncount; // incremented each server start used to check late spawns
+ client_t *clients; // [maxclients->value];
+ int num_client_entities; // maxclients->value*UPDATE_BACKUP*MAX_PACKET_ENTITIES
+ int next_client_entities; // next client_entity to use
+ entity_state_t *client_entities; // [num_client_entities]
+ int last_heartbeat;
+ challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
+ /* serverrecord values */
+ FILE *demofile;
+ sizebuf_t demo_multicast;
+ uchar demo_multicast_buf[MAX_MSGLEN];
+};
+extern server_static_t svs; // persistant server info
+
+extern edict_t *sv_player;
+extern char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
--- /dev/null
+++ b/files.c
@@ -1,0 +1,860 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+// define this to dissalow any data but the demo pak file
+//#define NO_ADDONS
+
+// if a packfile directory differs from this, it is assumed to be hacked
+// Full version
+#define PAK0_CHECKSUM 0x40e614e0
+// Demo
+//#define PAK0_CHECKSUM 0xb2c6d7ea
+// OEM
+//#define PAK0_CHECKSUM 0x78e135c
+
+/*
+=============================================================================
+
+QUAKE FILESYSTEM
+
+=============================================================================
+*/
+
+
+//
+// in memory
+//
+
+typedef struct
+{
+ char name[MAX_QPATH];
+ int filepos, filelen;
+} packfile_t;
+
+typedef struct pack_s
+{
+ char filename[MAX_OSPATH];
+ FILE *handle;
+ int numfiles;
+ packfile_t *files;
+} pack_t;
+
+char fs_gamedir[MAX_OSPATH];
+cvar_t *fs_basedir;
+cvar_t *fs_cddir;
+cvar_t *fs_gamedirvar;
+
+typedef struct filelink_s
+{
+ struct filelink_s *next;
+ char *from;
+ int fromlength;
+ char *to;
+} filelink_t;
+
+filelink_t *fs_links;
+
+typedef struct searchpath_s
+{
+ char filename[MAX_OSPATH];
+ pack_t *pack; // only one of filename / pack will be used
+ struct searchpath_s *next;
+} searchpath_t;
+
+searchpath_t *fs_searchpaths;
+searchpath_t *fs_base_searchpaths; // without gamedirs
+
+
+/*
+
+All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.
+
+The "base directory" is the path to the directory holding the quake.exe and all game directories. The sys_* files pass this to host_init in quakeparms_t->basedir. This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory. The base directory is
+only used during filesystem initialization.
+
+The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to. This can be overridden with the "-game" command line parameter. The game directory can never be changed while quake is executing. This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.
+
+*/
+
+
+/*
+================
+FS_filelength
+================
+*/
+int FS_filelength (FILE *f)
+{
+ int pos;
+ int end;
+
+ pos = ftell (f);
+ fseek (f, 0, SEEK_END);
+ end = ftell (f);
+ fseek (f, pos, SEEK_SET);
+
+ return end;
+}
+
+
+/*
+============
+FS_CreatePath
+
+Creates any directories needed to store the given filename
+============
+*/
+void FS_CreatePath (char *path)
+{
+ char *ofs;
+
+ for (ofs = path+1 ; *ofs ; ofs++)
+ {
+ if (*ofs == '/')
+ { // create the directory
+ *ofs = 0;
+ Sys_Mkdir (path);
+ *ofs = '/';
+ }
+ }
+}
+
+
+/*
+==============
+FS_FCloseFile
+
+For some reason, other dll's can't just cal fclose()
+on files returned by FS_FOpenFile...
+==============
+*/
+void FS_FCloseFile (FILE *f)
+{
+ fclose (f);
+}
+
+
+// RAFAEL
+/*
+ Developer_searchpath
+*/
+int Developer_searchpath (int /*who*/)
+{
+
+ // PMM - warning removal
+// char *start;
+ searchpath_t *search;
+
+ for (search = fs_searchpaths ; search ; search = search->next)
+ {
+ if (strstr (search->filename, "xatrix"))
+ return 1;
+
+ if (strstr (search->filename, "rogue"))
+ return 2;
+/*
+ start = strchr (search->filename, ch);
+
+ if (start == NULL)
+ continue;
+
+ if (strcmp (start ,"xatrix") == 0)
+ return (1);
+*/
+ }
+ return (0);
+
+}
+
+
+/*
+===========
+FS_FOpenFile
+
+Finds the file in the search path.
+returns filesize and an open FILE *
+Used for streaming data out of either a pak file or
+a seperate file.
+===========
+*/
+int file_from_pak = 0;
+#ifndef NO_ADDONS
+int FS_FOpenFile (char *filename, FILE **file)
+{
+ searchpath_t *search;
+ char netpath[MAX_OSPATH];
+ pack_t *pak;
+ int i;
+ filelink_t *link;
+
+ file_from_pak = 0;
+
+ // check for links first
+ for (link = fs_links ; link ; link=link->next)
+ {
+ if (!strncmp (filename, link->from, link->fromlength))
+ {
+ Com_sprintf (netpath, sizeof(netpath), "%s%s",link->to, filename+link->fromlength);
+ *file = fopen (netpath, "rb");
+ if (*file)
+ {
+ Com_DPrintf ("link file: %s\n",netpath);
+ return FS_filelength (*file);
+ }
+ return -1;
+ }
+ }
+
+//
+// search through the path, one element at a time
+//
+ for (search = fs_searchpaths ; search ; search = search->next)
+ {
+ // is the element a pak file?
+ if (search->pack)
+ {
+ // look through all the pak file elements
+ pak = search->pack;
+ for (i=0 ; i<pak->numfiles ; i++)
+ if (!cistrcmp (pak->files[i].name, filename))
+ { // found it!
+ file_from_pak = 1;
+ Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
+ // open a new file on the pakfile
+ *file = fopen (pak->filename, "rb");
+ if (!*file)
+ Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);
+ fseek (*file, pak->files[i].filepos, SEEK_SET);
+ return pak->files[i].filelen;
+ }
+ }
+ else
+ {
+ // check a file in the directory tree
+
+ Com_sprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename);
+
+ *file = fopen (netpath, "rb");
+ if (!*file)
+ continue;
+
+ Com_DPrintf ("FindFile: %s\n",netpath);
+
+ return FS_filelength (*file);
+ }
+
+ }
+
+ Com_DPrintf ("FindFile: can't find %s\n", filename);
+
+ *file = NULL;
+ return -1;
+}
+
+#else
+
+// this is just for demos to prevent add on hacking
+
+int FS_FOpenFile (char *filename, FILE **file)
+{
+ searchpath_t *search;
+ char netpath[MAX_OSPATH];
+ pack_t *pak;
+ int i;
+
+ file_from_pak = 0;
+
+ // get config from directory, everything else from pak
+ if (!strcmp(filename, "config.cfg") || !strncmp(filename, "players/", 8))
+ {
+ Com_sprintf (netpath, sizeof(netpath), "%s/%s",FS_Gamedir(), filename);
+
+ *file = fopen (netpath, "rb");
+ if (!*file)
+ return -1;
+
+ Com_DPrintf ("FindFile: %s\n",netpath);
+
+ return FS_filelength (*file);
+ }
+
+ for (search = fs_searchpaths ; search ; search = search->next)
+ if (search->pack)
+ break;
+ if (!search)
+ {
+ *file = NULL;
+ return -1;
+ }
+
+ pak = search->pack;
+ for (i=0 ; i<pak->numfiles ; i++)
+ if (!cistrcmp (pak->files[i].name, filename))
+ { // found it!
+ file_from_pak = 1;
+ Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
+ // open a new file on the pakfile
+ *file = fopen (pak->filename, "rb");
+ if (!*file)
+ Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);
+ fseek (*file, pak->files[i].filepos, SEEK_SET);
+ return pak->files[i].filelen;
+ }
+
+ Com_DPrintf ("FindFile: can't find %s\n", filename);
+
+ *file = NULL;
+ return -1;
+}
+
+#endif
+
+
+/*
+=================
+FS_ReadFile
+
+Properly handles partial reads
+=================
+*/
+void CDAudio_Stop(void);
+#define MAX_READ 0x10000 // read in blocks of 64k
+void FS_Read (void *buffer, int len, FILE *f)
+{
+ int block, remaining;
+ int read;
+ byte *buf;
+ int tries;
+
+ buf = (byte *)buffer;
+
+ // read in chunks for progress bar
+ remaining = len;
+ tries = 0;
+ while (remaining)
+ {
+ block = remaining;
+ if (block > MAX_READ)
+ block = MAX_READ;
+ read = fread (buf, 1, block, f);
+ if (read == 0)
+ {
+ // we might have been trying to read from a CD
+ if (!tries)
+ {
+ tries = 1;
+ CDAudio_Stop();
+ }
+ else
+ Com_Error (ERR_FATAL, "FS_Read: 0 bytes read");
+ }
+
+ if (read == -1)
+ Com_Error (ERR_FATAL, "FS_Read: -1 bytes read");
+
+ // do some progress bar thing here...
+
+ remaining -= read;
+ buf += read;
+ }
+}
+
+/*
+============
+FS_LoadFile
+
+Filename are reletive to the quake search path
+a null buffer will just return the file length without loading
+============
+*/
+int FS_LoadFile (char *path, void **buffer)
+{
+ FILE *h;
+ byte *buf;
+ int len;
+
+// look for it in the filesystem or pack files
+ len = FS_FOpenFile (path, &h);
+ if (!h)
+ {
+ if (buffer)
+ *buffer = NULL;
+ return -1;
+ }
+
+ if (!buffer)
+ {
+ fclose (h);
+ return len;
+ }
+
+ buf = Z_Malloc(len);
+ *buffer = buf;
+
+ FS_Read (buf, len, h);
+
+ fclose (h);
+
+ return len;
+}
+
+
+/*
+=============
+FS_FreeFile
+=============
+*/
+void FS_FreeFile (void *buffer)
+{
+ Z_Free (buffer);
+}
+
+/*
+=================
+FS_LoadPackFile
+
+Takes an explicit (not game tree related) path to a pak file.
+
+Loads the header and directory, adding the files at the beginning
+of the list so they override previous pack files.
+=================
+*/
+pack_t *FS_LoadPackFile (char *packfile)
+{
+ dpackheader_t header;
+ int i;
+ packfile_t *newfiles;
+ int numpackfiles;
+ pack_t *pack;
+ FILE *packhandle;
+ dpackfile_t info[MAX_FILES_IN_PACK];
+ unsigned checksum;
+
+ packhandle = fopen(packfile, "rb");
+ if (!packhandle)
+ return NULL;
+
+ fread (&header, 1, sizeof(header), packhandle);
+ if (LittleLong(header.ident) != IDPAKHEADER)
+ Com_Error (ERR_FATAL, "%s is not a packfile", packfile);
+ header.dirofs = LittleLong (header.dirofs);
+ header.dirlen = LittleLong (header.dirlen);
+
+ numpackfiles = header.dirlen / sizeof(dpackfile_t);
+
+ if (numpackfiles > MAX_FILES_IN_PACK)
+ Com_Error (ERR_FATAL, "%s has %i files", packfile, numpackfiles);
+
+ newfiles = Z_Malloc (numpackfiles * sizeof(packfile_t));
+
+ fseek (packhandle, header.dirofs, SEEK_SET);
+ fread (info, 1, header.dirlen, packhandle);
+
+// crc the directory to check for modifications
+ checksum = Com_BlockChecksum ((void *)info, header.dirlen);
+
+#ifdef NO_ADDONS
+ if (checksum != PAK0_CHECKSUM)
+ return NULL;
+#else
+ USED(checksum);
+#endif
+// parse the directory
+ for (i=0 ; i<numpackfiles ; i++)
+ {
+ strcpy (newfiles[i].name, info[i].name);
+ newfiles[i].filepos = LittleLong(info[i].filepos);
+ newfiles[i].filelen = LittleLong(info[i].filelen);
+ }
+
+ pack = Z_Malloc (sizeof (pack_t));
+ strcpy (pack->filename, packfile);
+ pack->handle = packhandle;
+ pack->numfiles = numpackfiles;
+ pack->files = newfiles;
+
+ Com_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
+ return pack;
+}
+
+
+/*
+================
+FS_AddGameDirectory
+
+Sets fs_gamedir, adds the directory to the head of the path,
+then loads and adds pak1.pak pak2.pak ...
+================
+*/
+void FS_AddGameDirectory (char *dir)
+{
+ int i;
+ searchpath_t *search;
+ pack_t *pak;
+ char pakfile[MAX_OSPATH];
+
+ strcpy (fs_gamedir, dir);
+
+ //
+ // add the directory to the search path
+ //
+ search = Z_Malloc (sizeof(searchpath_t));
+ strcpy (search->filename, dir);
+ search->next = fs_searchpaths;
+ fs_searchpaths = search;
+
+ //
+ // add any pak files in the format pak0.pak pak1.pak, ...
+ //
+ for (i=0; i<10; i++)
+ {
+ Com_sprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", dir, i);
+ pak = FS_LoadPackFile (pakfile);
+ if (!pak)
+ continue;
+ search = Z_Malloc (sizeof(searchpath_t));
+ search->pack = pak;
+ search->next = fs_searchpaths;
+ fs_searchpaths = search;
+ }
+
+
+}
+
+/*
+============
+FS_Gamedir
+
+Called to find where to write a file (demos, savegames, etc)
+============
+*/
+char *FS_Gamedir (void)
+{
+ return fs_gamedir;
+}
+
+/*
+=============
+FS_ExecAutoexec
+=============
+*/
+void FS_ExecAutoexec (void)
+{
+ char *dir;
+ char name [MAX_QPATH];
+
+ dir = Cvar_VariableString("gamedir");
+ if (*dir)
+ Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, dir);
+ else
+ Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, BASEDIRNAME);
+ if (Sys_FindFirst(name, 0, SFF_SUBDIR))
+ Cbuf_AddText ("exec autoexec.cfg\n");
+ Sys_FindClose();
+}
+
+
+/*
+================
+FS_SetGamedir
+
+Sets the gamedir and path to a different directory.
+================
+*/
+void FS_SetGamedir (char *dir)
+{
+ searchpath_t *next;
+
+ if (strstr(dir, "..") || strstr(dir, "/")
+ || strstr(dir, "\\") || strstr(dir, ":") )
+ {
+ Com_Printf ("Gamedir should be a single filename, not a path\n");
+ return;
+ }
+
+ //
+ // free up any current game dir info
+ //
+ while (fs_searchpaths != fs_base_searchpaths)
+ {
+ if (fs_searchpaths->pack)
+ {
+ fclose (fs_searchpaths->pack->handle);
+ Z_Free (fs_searchpaths->pack->files);
+ Z_Free (fs_searchpaths->pack);
+ }
+ next = fs_searchpaths->next;
+ Z_Free (fs_searchpaths);
+ fs_searchpaths = next;
+ }
+
+ //
+ // flush all data, so it will be forced to reload
+ //
+ if (dedicated && !dedicated->value)
+ Cbuf_AddText ("vid_restart\nsnd_restart\n");
+
+ Com_sprintf (fs_gamedir, sizeof(fs_gamedir), "%s/%s", fs_basedir->string, dir);
+
+ if (!strcmp(dir,BASEDIRNAME) || (*dir == 0))
+ {
+ Cvar_FullSet ("gamedir", "", CVAR_SERVERINFO|CVAR_NOSET);
+ Cvar_FullSet ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
+ }
+ else
+ {
+ Cvar_FullSet ("gamedir", dir, CVAR_SERVERINFO|CVAR_NOSET);
+ if (fs_cddir->string[0])
+ FS_AddGameDirectory (va("%s/%s", fs_cddir->string, dir) );
+ FS_AddGameDirectory (va("%s/%s", fs_basedir->string, dir) );
+ }
+}
+
+
+/*
+================
+FS_Link_f
+
+Creates a filelink_t
+================
+*/
+void FS_Link_f (void)
+{
+ filelink_t *l, **prev;
+
+ if (Cmd_Argc() != 3)
+ {
+ Com_Printf ("USAGE: link <from> <to>\n");
+ return;
+ }
+
+ // see if the link already exists
+ prev = &fs_links;
+ for (l=fs_links ; l ; l=l->next)
+ {
+ if (!strcmp (l->from, Cmd_Argv(1)))
+ {
+ Z_Free (l->to);
+ if (!strlen(Cmd_Argv(2)))
+ { // delete it
+ *prev = l->next;
+ Z_Free (l->from);
+ Z_Free (l);
+ return;
+ }
+ l->to = CopyString (Cmd_Argv(2));
+ return;
+ }
+ prev = &l->next;
+ }
+
+ // create a new link
+ l = Z_Malloc(sizeof(*l));
+ l->next = fs_links;
+ fs_links = l;
+ l->from = CopyString(Cmd_Argv(1));
+ l->fromlength = strlen(l->from);
+ l->to = CopyString(Cmd_Argv(2));
+}
+
+/*
+** FS_ListFiles
+*/
+char **FS_ListFiles( char *findname, int *numfiles, unsigned musthave, unsigned canthave )
+{
+ char *s;
+ int nfiles = 0;
+ char **list;
+
+ s = Sys_FindFirst( findname, musthave, canthave );
+ while ( s )
+ {
+ if ( s[strlen(s)-1] != '.' )
+ nfiles++;
+ s = Sys_FindNext( musthave, canthave );
+ }
+ Sys_FindClose ();
+
+ if ( !nfiles )
+ return NULL;
+
+ nfiles++; // add space for a guard
+ *numfiles = nfiles;
+
+ list = malloc( sizeof( char * ) * nfiles );
+ memset( list, 0, sizeof( char * ) * nfiles );
+
+ s = Sys_FindFirst( findname, musthave, canthave );
+ nfiles = 0;
+ while ( s )
+ {
+ if ( s[strlen(s)-1] != '.' )
+ {
+ list[nfiles] = strdup( s );
+ nfiles++;
+ }
+ s = Sys_FindNext( musthave, canthave );
+ }
+ Sys_FindClose ();
+
+ return list;
+}
+
+/*
+** FS_Dir_f
+*/
+void FS_Dir_f( void )
+{
+ char *path = NULL;
+ char findname[1024];
+ char wildcard[1024] = "*.*";
+ char **dirnames;
+ int ndirs;
+
+ if ( Cmd_Argc() != 1 )
+ {
+ strcpy( wildcard, Cmd_Argv( 1 ) );
+ }
+
+ while ( ( path = FS_NextPath( path ) ) != NULL )
+ {
+ char *tmp = findname;
+
+ Com_sprintf( findname, sizeof(findname), "%s/%s", path, wildcard );
+
+ while ( *tmp != 0 )
+ {
+ if ( *tmp == '\\' )
+ *tmp = '/';
+ tmp++;
+ }
+ Com_Printf( "Directory of %s\n", findname );
+ Com_Printf( "----\n" );
+
+ if ( ( dirnames = FS_ListFiles( findname, &ndirs, 0, 0 ) ) != 0 )
+ {
+ int i;
+
+ for ( i = 0; i < ndirs-1; i++ )
+ {
+ if ( strrchr( dirnames[i], '/' ) )
+ Com_Printf( "%s\n", strrchr( dirnames[i], '/' ) + 1 );
+ else
+ Com_Printf( "%s\n", dirnames[i] );
+
+ free( dirnames[i] );
+ }
+ free( dirnames );
+ }
+ Com_Printf( "\n" );
+ };
+}
+
+/*
+============
+FS_Path_f
+
+============
+*/
+void FS_Path_f (void)
+{
+ searchpath_t *s;
+ filelink_t *l;
+
+ Com_Printf ("Current search path:\n");
+ for (s=fs_searchpaths ; s ; s=s->next)
+ {
+ if (s == fs_base_searchpaths)
+ Com_Printf ("----------\n");
+ if (s->pack)
+ Com_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
+ else
+ Com_Printf ("%s\n", s->filename);
+ }
+
+ Com_Printf ("\nLinks:\n");
+ for (l=fs_links ; l ; l=l->next)
+ Com_Printf ("%s : %s\n", l->from, l->to);
+}
+
+/*
+================
+FS_NextPath
+
+Allows enumerating all of the directories in the search path
+================
+*/
+char *FS_NextPath (char *prevpath)
+{
+ searchpath_t *s;
+ char *prev;
+
+ if (!prevpath)
+ return fs_gamedir;
+
+ prev = fs_gamedir;
+ for (s=fs_searchpaths ; s ; s=s->next)
+ {
+ if (s->pack)
+ continue;
+ if (prevpath == prev)
+ return s->filename;
+ prev = s->filename;
+ }
+
+ return NULL;
+}
+
+
+/*
+================
+FS_InitFilesystem
+================
+*/
+void FS_InitFilesystem (void)
+{
+ static char homedir[1024];
+ char *home;
+
+ Cmd_AddCommand ("path", FS_Path_f);
+ Cmd_AddCommand ("link", FS_Link_f);
+ Cmd_AddCommand ("dir", FS_Dir_f );
+
+ //
+ // basedir <path>
+ // allows the game to run from outside the data tree
+ //
+ if(home = getenv("home")){
+ snprint(homedir, sizeof homedir, "%s/lib/quake2", home);
+ free(home);
+ }else
+ snprint(homedir, sizeof homedir, "/sys/lib/quake2");
+ fs_basedir = Cvar_Get ("basedir", homedir, CVAR_NOSET);
+
+ //
+ // cddir <path>
+ // Logically concatenates the cddir after the basedir for
+ // allows the game to run from outside the data tree
+ //
+ fs_cddir = Cvar_Get ("cddir", "", CVAR_NOSET);
+ if (fs_cddir->string[0])
+ FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_cddir->string) );
+
+ //
+ // start up with baseq2 by default
+ //
+ FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_basedir->string) );
+
+ // any set gamedirs will be freed up to here
+ fs_base_searchpaths = fs_searchpaths;
+
+ // check for game override
+ fs_gamedirvar = Cvar_Get ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
+ if (fs_gamedirvar->string[0])
+ FS_SetGamedir (fs_gamedirvar->string);
+}
+
+
+
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,613 @@
+void Qcommon_Init(int, char **);
+void Qcommon_Frame(int);
+void Z_Free(void *);
+void* Z_Malloc(int);
+void* Z_TagMalloc(int, int);
+void Z_FreeTags(int);
+int COM_Argc(void);
+char* COM_Argv(int);
+void COM_ClearArgv(int);
+int COM_CheckParm(char *);
+void COM_AddParm(char *);
+void COM_Init(void);
+void COM_InitArgv(int, char **);
+char* COM_SkipPath(char *);
+void COM_StripExtension(char *, char *);
+void COM_FileBase(char *, char *);
+void COM_FilePath(char *, char *);
+void COM_DefaultExtension(char *, char *);
+char* COM_Parse(char **);
+void Com_PageInMemory(uchar *, int);
+char* CopyString(char *);
+char* va(char *, ...);
+void Com_sprintf(char *, int, char *, ...);
+void Info_Print(char *);
+void Com_BeginRedirect(int, char *, int, void(*));
+void Com_EndRedirect(void);
+void Com_Printf(char *, ...);
+void Com_DPrintf(char *, ...);
+void Com_Error(int, char *, ...);
+void Com_Quit(void);
+int Com_ServerState(void);
+void Com_SetServerState(int state);
+unsigned Com_BlockChecksum(void *, int);
+uchar COM_BlockSequenceCRCByte(uchar *, int, int);
+float qfrand(void);
+float crand(void);
+
+void FS_InitFilesystem(void);
+void FS_SetGamedir(char *);
+char* FS_Gamedir(void);
+char* FS_NextPath(char *);
+void FS_ExecAutoexec(void);
+int FS_FOpenFile(char *, FILE **);
+void FS_FCloseFile(FILE *);
+int FS_LoadFile(char *, void **);
+void FS_Read(void *, int, FILE *);
+void FS_FreeFile(void *);
+void FS_CreatePath(char *);
+
+char* Sys_FindFirst(char *, uint, uint);
+char* Sys_FindNext(uint, uint);
+void Sys_FindClose(void);
+int Sys_Milliseconds(void);
+void Sys_Mkdir(char *);
+void Sys_Init(void);
+void Sys_AppActivate(void);
+void Sys_UnloadGame(void);
+char* Sys_ConsoleInput(void);
+void Sys_ConsoleOutput(char *);
+void Sys_SendKeyEvents(void);
+void Sys_Error(char *, ...);
+void Sys_Quit(void);
+char* Sys_GetClipboardData(void);
+void Sys_CopyProtect(void);
+void Sys_MakeCodeWriteable(ulong, ulong);
+void Sys_SetFPCW(void);
+vlong flen(int);
+void* Hunk_Begin(int);
+void* Hunk_Alloc(int);
+void Hunk_Free(void *);
+int Hunk_End(void);
+
+void CL_Init(void);
+void CL_Drop(void);
+void CL_Shutdown(void);
+void CL_Frame(int);
+
+short BigShort(short);
+short LittleShort(short);
+int BigLong(int);
+int LittleLong(int);
+float BigFloat(float);
+float LittleFloat(float);
+void Swap_Init(void);
+
+char* Info_ValueForKey(char *, char *);
+void Info_RemoveKey(char *, char *);
+void Info_SetValueForKey(char *, char *, char *);
+qboolean Info_Validate(char *);
+
+void SZ_Init(sizebuf_t *, uchar *, int);
+void SZ_Clear(sizebuf_t *);
+void* SZ_GetSpace(sizebuf_t *, int);
+void SZ_Write(sizebuf_t *, void *, int);
+void SZ_Print(sizebuf_t *, char *);
+void MSG_WriteChar(sizebuf_t *, int);
+void MSG_WriteByte(sizebuf_t *, int);
+void MSG_WriteShort(sizebuf_t *, int);
+void MSG_WriteLong(sizebuf_t *, int);
+void MSG_WriteFloat(sizebuf_t *, float);
+void MSG_WriteString(sizebuf_t *, char *);
+void MSG_WriteCoord(sizebuf_t *, float);
+void MSG_WritePos(sizebuf_t *, vec3_t);
+void MSG_WriteAngle(sizebuf_t *, float);
+void MSG_WriteAngle16(sizebuf_t *, float);
+void MSG_WriteDeltaUsercmd(sizebuf_t *, usercmd_t *, usercmd_t *);
+void MSG_WriteDeltaEntity(entity_state_t *, entity_state_t *, sizebuf_t *, qboolean, qboolean);
+void MSG_WriteDir(sizebuf_t *, vec3_t);
+void MSG_BeginReading(sizebuf_t *);
+int MSG_ReadChar(sizebuf_t *);
+int MSG_ReadByte(sizebuf_t *);
+int MSG_ReadShort(sizebuf_t *);
+int MSG_ReadLong(sizebuf_t *);
+float MSG_ReadFloat(sizebuf_t *);
+char* MSG_ReadString(sizebuf_t *);
+char* MSG_ReadStringLine(sizebuf_t *);
+float MSG_ReadCoord(sizebuf_t *);
+void MSG_ReadPos(sizebuf_t *, vec3_t);
+float MSG_ReadAngle(sizebuf_t *);
+float MSG_ReadAngle16(sizebuf_t *);
+void MSG_ReadDeltaUsercmd(sizebuf_t *, usercmd_t *, usercmd_t *);
+void MSG_ReadDir(sizebuf_t *, vec3_t);
+void MSG_ReadData(sizebuf_t *, void *, int);
+
+void CRC_Init(ushort *);
+void CRC_ProcessByte(ushort *, uchar);
+ushort CRC_Value(ushort);
+ushort CRC_Block(uchar *, int);
+
+void Cbuf_Init(void);
+void Cbuf_AddText(char *);
+void Cbuf_InsertText(char *);
+void Cbuf_ExecuteText(int, char *);
+void Cbuf_Execute(void);
+void Cbuf_AddEarlyCommands(qboolean);
+qboolean Cbuf_AddLateCommands(void);
+void Cbuf_CopyToDefer(void);
+void Cbuf_InsertFromDefer(void);
+void Cmd_Init(void);
+void Cmd_AddCommand(char *, xcommand_t);
+void Cmd_RemoveCommand(char *);
+qboolean Cmd_Exists(char *);
+char* Cmd_CompleteCommand(char *);
+int Cmd_Argc(void);
+char* Cmd_Argv(int);
+char* Cmd_Args(void);
+void Cmd_TokenizeString(char *, qboolean);
+void Cmd_ExecuteString(char *);
+void Cmd_ForwardToServer(void);
+
+void Con_DrawCharacter(int, int, int);
+void Con_CheckResize(void);
+void Con_Init(void);
+void Con_DrawConsole(float);
+void Con_Print(char *);
+void Con_CenteredPrint(char *);
+void Con_Clear_f(void);
+void Con_DrawNotify(void);
+void Con_ClearNotify(void);
+void Con_ToggleConsole_f(void);
+void DrawString(int, int, char *);
+void DrawAltString(int, int, char *);
+
+cvar_t* Cvar_Get(char *, char *, int);
+cvar_t* Cvar_Set(char *, char *);
+cvar_t* Cvar_ForceSet(char *, char *);
+cvar_t* Cvar_FullSet(char *, char *, int);
+void Cvar_SetValue(char *, float);
+float Cvar_VariableValue(char *);
+char* Cvar_VariableString(char *);
+char* Cvar_CompleteVariable(char *);
+void Cvar_GetLatchedVars(void);
+qboolean Cvar_Command(void);
+void Cvar_WriteVariables(char *);
+void Cvar_Init(void);
+char* Cvar_Userinfo(void);
+char* Cvar_Serverinfo(void);
+
+void CL_ParticleSteamEffect2(cl_sustain_t *);
+void CL_TeleporterParticles(entity_state_t *);
+void CL_ParticleEffect(vec3_t, vec3_t, int, int);
+void CL_ParticleEffect2(vec3_t, vec3_t, int, int);
+void CL_ParticleEffect3(vec3_t, vec3_t, int, int);
+void CL_ClearEffects(void);
+void CL_ClearTEnts(void);
+void CL_BlasterTrail(vec3_t, vec3_t);
+void CL_QuadTrail(vec3_t, vec3_t);
+void CL_RailTrail(vec3_t, vec3_t);
+void CL_BubbleTrail(vec3_t, vec3_t);
+void CL_FlagTrail(vec3_t, vec3_t, float);
+void CL_IonripperTrail(vec3_t, vec3_t);
+void CL_BlasterParticles2(vec3_t, vec3_t, uint);
+void CL_BlasterTrail2(vec3_t, vec3_t);
+void CL_DebugTrail(vec3_t, vec3_t);
+void CL_SmokeTrail(vec3_t, vec3_t, int, int, int);
+void CL_Flashlight(int, vec3_t);
+void CL_ForceWall(vec3_t, vec3_t, int);
+void CL_FlameEffects(centity_t *, vec3_t);
+void CL_GenericParticleEffect(vec3_t, vec3_t, int, int, int, int, float);
+void CL_BubbleTrail2(vec3_t, vec3_t, int);
+void CL_Heatbeam(vec3_t, vec3_t);
+void CL_ParticleSteamEffect(vec3_t, vec3_t, int, int, int);
+void CL_TrackerTrail(vec3_t, vec3_t, int);
+void CL_Tracker_Explode(vec3_t);
+void CL_TagTrail(vec3_t, vec3_t, float);
+void CL_ColorFlash(vec3_t, int, int, float, float, float);
+void CL_Tracker_Shell(vec3_t);
+void CL_MonsterPlasma_Shell(vec3_t);
+void CL_ColorExplosionParticles(vec3_t, int, int);
+void CL_ParticleSmokeEffect(vec3_t, vec3_t, int, int, int);
+void CL_Widowbeamout(cl_sustain_t *);
+void CL_Nukeblast(cl_sustain_t *);
+void CL_WidowSplash(vec3_t);
+int CL_ParseEntityBits(int *);
+void CL_ParseDelta(entity_state_t *, entity_state_t *, int, int);
+void CL_ParseFrame(void);
+void CL_ParseTEnt(void);
+void CL_ParseConfigString(void);
+void CL_ParseMuzzleFlash(void);
+void CL_ParseMuzzleFlash2(void);
+void SmokeAndFlash(vec3_t);
+void CL_SetLightstyle(int);
+void CL_RunParticles(void);
+void CL_RunDLights(void);
+void CL_RunLightStyles(void);
+void CL_AddEntities(void);
+void CL_AddDLights(void);
+void CL_AddTEnts(void);
+void CL_AddLightStyles(void);
+void CL_PrepRefresh(void);
+void CL_RegisterSounds(void);
+void CL_Quit_f(void);
+void CL_ParseLayout(void);
+void CL_Init(void);
+void CL_FixUpGender(void);
+void CL_Disconnect(void);
+void CL_Disconnect_f(void);
+void CL_GetChallengePacket(void);
+void CL_PingServers_f(void);
+void CL_Snd_Restart_f(void);
+void CL_RequestNextDownload(void);
+void CL_InitInput(void);
+void CL_SendCmd(void);
+void CL_SendMove(usercmd_t *);
+void CL_ClearState(void);
+void CL_ReadPackets(void);
+int CL_ReadFromServer(void);
+void CL_WriteToServer(usercmd_t *);
+void CL_BaseMove(usercmd_t *);
+void IN_CenterView(void);
+float CL_KeyState(kbutton_t *);
+char* Key_KeynumToString(int);
+void CL_WriteDemoMessage(void);
+void CL_Stop_f(void);
+void CL_Record_f(void);
+void CL_ParseServerMessage(void);
+void CL_LoadClientinfo(clientinfo_t *, char *);
+void SHOWNET(char *);
+void CL_ParseClientinfo(int);
+void CL_Download_f(void);
+void V_Init(void);
+void V_RenderView(float);
+void V_AddEntity(entity_t *);
+void V_AddParticle(vec3_t, int, float);
+void V_AddLight(vec3_t, float, float, float, float);
+void V_AddLightStyle(int, float, float, float);
+void CL_RegisterTEntSounds(void);
+void CL_RegisterTEntModels(void);
+void CL_SmokeAndFlash(vec3_t);
+void CL_InitPrediction(void);
+void CL_PredictMove(void);
+void CL_CheckPredictionError(void);
+cdlight_t* CL_AllocDlight(int);
+void CL_BigTeleportParticles(vec3_t);
+void CL_RocketTrail(vec3_t, vec3_t, centity_t *);
+void CL_DiminishingTrail(vec3_t, vec3_t, centity_t *, int);
+void CL_FlyEffect(centity_t *, vec3_t);
+void CL_BfgParticles(entity_t *);
+void CL_AddParticles(void);
+void CL_EntityEvent(entity_state_t *);
+void CL_TrapParticles(entity_t *);
+void M_Init(void);
+void M_Keydown(int);
+void M_Draw(void);
+void M_Menu_Main_f(void);
+void M_ForceMenuOff(void);
+void M_AddToServerList(netadr_t, char *);
+void CL_ParseInventory(void);
+void CL_KeyInventory(int);
+void CL_DrawInventory(void);
+void CL_PredictMovement(void);
+qboolean CL_CheckOrDownloadFile(char *);
+void CL_AddNetgraph(void);
+
+void SV_Init(void);
+void SV_Shutdown(char *, qboolean);
+void SV_Frame(int);
+void SV_FinalMessage(char *, qboolean);
+void SV_DropClient(client_t *);
+int SV_ModelIndex(char *);
+int SV_SoundIndex(char *);
+int SV_ImageIndex(char *);
+void SV_WriteClientdataToMessage(client_t *, sizebuf_t *);
+void SV_ExecuteUserCommand(char *);
+void SV_InitOperatorCommands(void);
+void SV_SendServerinfo(client_t *);
+void SV_UserinfoChanged(client_t *);
+void Master_Heartbeat(void);
+void Master_Packet(void);
+void SV_InitGame(void);
+void SV_Map(qboolean, char *, qboolean);
+void SV_PrepWorldFrame(void);
+void SV_FlushRedirect(int, char *);
+void SV_DemoCompleted(void);
+void SV_SendClientMessages(void);
+void SV_Multicast(vec3_t, multicast_t);
+void SV_StartSound(vec3_t, edict_t *, int, int, float, float, float);
+void SV_ClientPrintf(client_t *, int, char *, ...);
+void SV_BroadcastPrintf(int, char *, ...);
+void SV_BroadcastCommand(char *, ...);
+void SV_Nextserver(void);
+void SV_ExecuteClientMessage(client_t *);
+void SV_ReadLevelFile(void);
+void SV_Status_f(void);
+void SV_WriteFrameToClient(client_t *, sizebuf_t *);
+void SV_RecordDemoMessage(void);
+void SV_BuildClientFrame(client_t *);
+void SV_Error(char *, ...);
+void SV_InitGameProgs(void);
+void SV_ShutdownGameProgs(void);
+void SV_InitEdict(edict_t *);
+void SV_ClearWorld(void);
+void SV_UnlinkEdict(edict_t *);
+void SV_LinkEdict(edict_t *);
+int SV_AreaEdicts(vec3_t, vec3_t, edict_t **, int, int);
+int SV_PointContents(vec3_t);
+trace_t SV_Trace(vec3_t, vec3_t, vec3_t, vec3_t, edict_t *, int);
+
+void NET_Init(void);
+void NET_Shutdown(void);
+void NET_Config(qboolean);
+qboolean NET_GetPacket(netsrc_t, netadr_t *, sizebuf_t *);
+void NET_SendPacket(netsrc_t, int, void *, netadr_t);
+qboolean NET_CompareAdr(netadr_t, netadr_t);
+qboolean NET_CompareBaseAdr(netadr_t, netadr_t);
+qboolean NET_IsLocalAddress(netadr_t);
+char* NET_AdrToString(netadr_t);
+qboolean NET_StringToAdr (char *, netadr_t *);
+void NET_Sleep(int);
+
+void Netchan_Init(void);
+void Netchan_Setup(netsrc_t, netchan_t *, netadr_t, int);
+qboolean Netchan_NeedReliable(netchan_t *);
+void Netchan_Transmit(netchan_t *, int, uchar *);
+void Netchan_OutOfBand(int, netadr_t, int, uchar *);
+void Netchan_OutOfBandPrint(int, netadr_t, char *, ...);
+qboolean Netchan_Process(netchan_t *, sizebuf_t *);
+qboolean Netchan_CanReliable(netchan_t *);
+
+void Mod_Init(void);
+void Mod_ClearAll(void);
+model_t* Mod_ForName(char *, qboolean);
+void* Mod_Extradata(model_t *);
+void Mod_TouchModel(char *);
+mleaf_t* Mod_PointInLeaf(float *, model_t *);
+uchar* Mod_ClusterPVS(int, model_t *);
+void Mod_Modellist_f(void);
+void Mod_FreeAll(void);
+void Mod_Free(model_t *);
+
+void D_DrawSurfaces(void);
+void D_ViewChanged(void);
+void D_WarpScreen(void);
+void D_DrawSpans16(espan_t *);
+void D_DrawZSpans(espan_t *);
+void Turbulent8(espan_t *);
+void NonTurbulent8(espan_t *);
+void TransformVector(vec3_t, vec3_t);
+void SetUpForLineScan(fixed8_t, fixed8_t, fixed8_t, fixed8_t);
+surfcache_t* D_CacheSurface(msurface_t *, int);
+void R_DrawParticle(void);
+void R_PolysetUpdateTables(void);
+void R_DrawSurface(void);
+void R_RenderWorld(void);
+void R_ClearPolyList(void);
+void R_DrawPolyList(void);
+void R_DrawAlphaSurfaces(void);
+void R_DrawSprite(void);
+void R_DrawBeam(entity_t *);
+void R_RenderFace(msurface_t *, int);
+void R_RenderBmodelFace(bedge_t *, msurface_t *);
+void R_TransformPlane(mplane_t *, float *, float *);
+void R_TransformFrustum(void);
+void R_DrawSurfaceBlock16(void);
+void R_DrawSurfaceBlock8(void);
+void R_GenSkyTile(void *);
+void R_GenSkyTile16(void *);
+void R_Surf8Patch(void);
+void R_Surf16Patch(void);
+void R_DrawSubmodelPolygons(model_t *, int, mnode_t *);
+void R_DrawSolidClippedSubmodelPolygons(model_t *, mnode_t *);
+void R_AddPolygonEdges(emitpoint_t *, int, int);
+surf_t* R_GetSurf(void);
+void R_AliasDrawModel(void);
+void R_BeginEdgeFrame(void);
+void R_ScanEdges(void);
+void D_DrawSurfaces(void);
+void R_InsertNewEdges(edge_t *, edge_t *);
+void R_StepActiveU(edge_t *);
+void R_RemoveEdges(edge_t *);
+void R_PushDlights(model_t *);
+void R_Surf8Start(void);
+void R_Surf8End(void);
+void R_Surf16Start(void);
+void R_Surf16End(void);
+void R_EdgeCodeStart(void);
+void R_EdgeCodeEnd(void);
+void R_RotateBmodel(void);
+void R_InitTurb(void);
+void R_DrawParticles(void);
+void R_SurfacePatch(void);
+void R_DrawTriangle(void);
+void R_AliasClipTriangle(finalvert_t *, finalvert_t *, finalvert_t *);
+void R_PrintAliasStats(void);
+void R_PrintTimes(void);
+void R_PrintDSpeeds(void);
+void R_AnimateLight(void);
+void R_LightPoint(vec3_t, vec3_t);
+void R_SetupFrame(void);
+void R_cshift_f(void);
+void R_EmitEdge(mvertex_t *, mvertex_t *);
+void R_ClipEdge(mvertex_t *, mvertex_t *, clipplane_t *);
+void R_SplitEntityOnNode2(mnode_t *);
+float R_DLightPoint(vec3_t);
+void R_NewMap(void);
+void R_Register(void);
+void R_UnRegister(void);
+void Draw_InitLocal(void);
+qboolean R_Init(void *, void *);
+void R_Shutdown(void);
+void R_InitCaches(void);
+void D_FlushCaches(void);
+void R_ScreenShot_f(void);
+void R_BeginRegistration(char *map);
+model_t* R_RegisterModel(char *);
+void R_EndRegistration(void);
+void R_RenderFrame(refdef_t *);
+image_t* Draw_FindPic(char *);
+void Draw_GetPicSize(int *, int *, char *);
+void Draw_Pic(int, int, char *);
+void Draw_StretchPic(int, int, int, int, char *);
+void Draw_StretchRaw(int, int, int, int, int, int, uchar *);
+void Draw_Char(int, int, int);
+void Draw_TileClear(int, int, int, int, char *);
+void Draw_Fill(int, int, int, int, int);
+void Draw_FadeScreen(void);
+void Draw_GetPalette(void);
+void R_BeginFrame(float);
+void R_CinematicSetPalette(uchar *palette);
+void LoadPCX(char *, uchar **, uchar **, int *, int *);
+void R_InitImages(void);
+void R_ShutdownImages(void);
+image_t* R_FindImage(char *, imagetype_t);
+void R_FreeUnusedImages(void);
+void R_GammaCorrectAndSetPalette(uchar *pal);
+void R_InitSkyBox(void);
+void R_IMFlatShadedQuad(vec3_t, vec3_t, vec3_t, vec3_t, int, float);
+image_t* R_RegisterSkin(char *);
+
+void VectorMA(vec3_t, float, vec3_t, vec3_t);
+vec_t _DotProduct(vec3_t, vec3_t); // just in case you do't want to use the macros
+void _VectorSubtract(vec3_t, vec3_t, vec3_t);
+void _VectorAdd(vec3_t, vec3_t, vec3_t);
+void _VectorCopy(vec3_t, vec3_t);
+void ClearBounds(vec3_t, vec3_t);
+void AddPointToBounds(vec3_t, vec3_t, vec3_t);
+int VectorCompare(vec3_t, vec3_t);
+vec_t VectorLength(vec3_t);
+void CrossProduct(vec3_t, vec3_t, vec3_t);
+vec_t VectorNormalize(vec3_t);
+vec_t VectorNormalize2 (vec3_t, vec3_t);
+void VectorInverse(vec3_t);
+void VectorScale(vec3_t, vec_t, vec3_t);
+void R_ConcatRotations(float[3][3], float[3][3], float[3][3]);
+void R_ConcatTransforms(float[3][4], float[3][4], float[3][4]);
+void AngleVectors(vec3_t, vec3_t, vec3_t, vec3_t);
+int BoxOnPlaneSide(vec3_t, vec3_t, cplane_t *);
+float anglemod(float);
+float LerpAngle(float, float, float);
+void ProjectPointOnPlane(vec3_t, vec3_t, vec3_t);
+void PerpendicularVector(vec3_t, vec3_t);
+void RotatePointAroundVector(vec3_t, vec3_t, vec3_t, float);
+
+cmodel_t* CM_LoadMap(char *, qboolean, unsigned *);
+cmodel_t* CM_InlineModel(char *);
+int CM_NumClusters(void);
+int CM_NumInlineModels(void);
+char* CM_EntityString(void);
+int CM_HeadnodeForBox(vec3_t, vec3_t);
+int CM_PointContents(vec3_t, int);
+int CM_TransformedPointContents(vec3_t, int, vec3_t, vec3_t);
+trace_t CM_BoxTrace(vec3_t, vec3_t, vec3_t, vec3_t, int, int);
+trace_t CM_TransformedBoxTrace(vec3_t, vec3_t, vec3_t, vec3_t, int, int, vec3_t, vec3_t);
+uchar* CM_ClusterPVS(int);
+uchar* CM_ClusterPHS(int);
+int CM_PointLeafnum(vec3_t);
+int CM_BoxLeafnums(vec3_t, vec3_t, int *, int, int *);
+int CM_LeafContents(int);
+int CM_LeafCluster(int);
+int CM_LeafArea(int);
+void CM_SetAreaPortalState(int, qboolean);
+qboolean CM_AreasConnected(int, int);
+int CM_WriteAreaBits(uchar *, int);
+qboolean CM_HeadnodeVisible(int, uchar *);
+void CM_WritePortalState(FILE *);
+void CM_ReadPortalState(FILE *);
+
+void Pmove(pmove_t *);
+
+void SCR_Init(void);
+void SCR_UpdateScreen(void);
+void SCR_SizeUp(void);
+void SCR_SizeDown(void);
+void SCR_CenterPrint(char *);
+void SCR_BeginLoadingPlaque(void);
+void SCR_EndLoadingPlaque(void);
+void SCR_DebugGraph(float, int);
+void SCR_TouchPics(void);
+void SCR_RunConsole(void);
+void SCR_AddDirtyPoint(int, int);
+void SCR_DirtyScreen(void);
+void SCR_PlayCinematic (char *name);
+qboolean SCR_DrawCinematic(void);
+void SCR_RunCinematic(void);
+void SCR_StopCinematic(void);
+void SCR_FinishCinematic(void);
+
+void VID_Init(void);
+void VID_Shutdown(void);
+void VID_CheckChanges(void);
+void VID_MenuInit(void);
+void VID_MenuDraw(void);
+char* VID_MenuKey(int);
+
+void SWimp_BeginFrame(float);
+void SWimp_EndFrame(void);
+int SWimp_Init(void *, void *);
+void SWimp_SetPalette(uchar *);
+void SWimp_Shutdown(void);
+rserr_t SWimp_SetMode(int *, int *, int, qboolean);
+void SWimp_AppActivate(qboolean);
+
+void S_Init(void);
+void S_Shutdown(void);
+void S_StartSound(vec3_t, int, int, sfx_t *, float, float, float);
+void S_StartLocalSound(char *);
+void S_RawSamples(int, int, int, int, uchar *);
+void S_StopAllSounds(void);
+void S_Update(vec3_t, vec3_t, vec3_t, vec3_t);
+void S_Activate(qboolean);
+void S_BeginRegistration(void);
+sfx_t* S_RegisterSound(char *);
+void S_EndRegistration(void);
+void CL_GetEntitySoundOrigin(int, vec3_t);
+qboolean SNDDMA_Init(void);
+int SNDDMA_GetDMAPos(void);
+void SNDDMA_Shutdown(void);
+void SNDDMA_BeginPainting(void);
+void SNDDMA_Submit(void);
+wavinfo_t GetWavinfo(char *, uchar *, int);
+void S_InitScaletable(void);
+sfxcache_t* S_LoadSound(sfx_t *);
+void S_IssuePlaysound(playsound_t *);
+void S_PaintChannels(int);
+channel_t* S_PickChannel(int, int);
+void S_Spatialize(channel_t *);
+
+int CDAudio_Init(void);
+void CDAudio_Shutdown(void);
+void CDAudio_Play(int, qboolean);
+void CDAudio_Stop(void);
+void CDAudio_Update(void);
+void CDAudio_Activate(qboolean);
+
+void IN_Init(void);
+void IN_Shutdown(void);
+void IN_Commands(void);
+void IN_Frame(void);
+void IN_Move(usercmd_t *);
+void IN_Activate(qboolean);
+void IN_Grabm(int);
+
+void Key_Event(int, qboolean, unsigned);
+void Key_Init(void);
+void Key_WriteBindings(FILE *);
+void Key_SetBinding(int, char *);
+void Key_ClearStates(void);
+int Key_GetKey(void);
+
+qboolean Field_Key(menufield_t *, int);
+void Menu_AddItem(menuframework_t *, void *);
+void Menu_AdjustCursor(menuframework_t *, int);
+void Menu_Center(menuframework_t *);
+void Menu_Draw(menuframework_t *);
+void* Menu_ItemAtCursor(menuframework_t *);
+qboolean Menu_SelectItem(menuframework_t *);
+void Menu_SetStatusBar(menuframework_t *, char *);
+void Menu_SlideItem(menuframework_t *, int);
+int Menu_TallySlots(menuframework_t *);
+void Menu_DrawString(int, int, char *);
+void Menu_DrawStringDark(int, int, char *);
+void Menu_DrawStringR2L(int, int, char *);
+void Menu_DrawStringR2LDark(int, int, char *);
--- a/game/g_ai.c
+++ b/game/g_ai.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
qboolean FindTarget (edict_t *self);
extern cvar_t *maxclients;
--- a/game/g_chase.c
+++ b/game/g_chase.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
void UpdateChaseCam(edict_t *ent)
{
--- a/game/g_cmds.c
+++ b/game/g_cmds.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_player.h"
--- a/game/g_combat.c
+++ b/game/g_combat.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*
============
--- a/game/g_func.c
+++ b/game/g_func.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*
=========================================================
--- a/game/g_items.c
+++ b/game/g_items.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
qboolean Pickup_Weapon (edict_t *ent, edict_t *other);
--- a/game/g_local.h
+++ /dev/null
@@ -1,1074 +1,0 @@
-// g_local.h -- local definitions for game module
-
-// the "gameversion" client command will print this plus compile date
-#define GAMEVERSION "baseq2"
-
-// view pitching times
-#define DAMAGE_TIME 0.5
-#define FALL_TIME 0.3
-
-
-// edict->spawnflags
-// these are set with checkboxes on each entity in the map editor
-#define SPAWNFLAG_NOT_EASY 0x00000100
-#define SPAWNFLAG_NOT_MEDIUM 0x00000200
-#define SPAWNFLAG_NOT_HARD 0x00000400
-#define SPAWNFLAG_NOT_DEATHMATCH 0x00000800
-#define SPAWNFLAG_NOT_COOP 0x00001000
-
-// edict->flags
-#define FL_FLY 0x00000001
-#define FL_SWIM 0x00000002 // implied immunity to drowining
-#define FL_IMMUNE_LASER 0x00000004
-#define FL_INWATER 0x00000008
-#define FL_GODMODE 0x00000010
-#define FL_NOTARGET 0x00000020
-#define FL_IMMUNE_SLIME 0x00000040
-#define FL_IMMUNE_LAVA 0x00000080
-#define FL_PARTIALGROUND 0x00000100 // not all corners are valid
-#define FL_WATERJUMP 0x00000200 // player jumping out of water
-#define FL_TEAMSLAVE 0x00000400 // not the first on the team
-#define FL_NO_KNOCKBACK 0x00000800
-#define FL_POWER_ARMOR 0x00001000 // power armor (if any) is active
-#define FL_RESPAWN 0x80000000 // used for item respawning
-
-
-#define FRAMETIME 0.1
-
-// memory tags to allow dynamic memory to be cleaned up
-#define TAG_GAME 765 // clear when unloading the dll
-#define TAG_LEVEL 766 // clear when loading a new level
-
-
-#define MELEE_DISTANCE 80
-
-#define BODY_QUEUE_SIZE 8
-
-typedef enum
-{
- DAMAGE_NO,
- DAMAGE_YES, // will take damage if hit
- DAMAGE_AIM // auto targeting recognizes this
-} damage_t;
-
-typedef enum
-{
- WEAPON_READY,
- WEAPON_ACTIVATING,
- WEAPON_DROPPING,
- WEAPON_FIRING
-} weaponstate_t;
-
-typedef enum
-{
- AMMO_BULLETS,
- AMMO_SHELLS,
- AMMO_ROCKETS,
- AMMO_GRENADES,
- AMMO_CELLS,
- AMMO_SLUGS
-} ammo_t;
-
-
-//deadflag
-#define DEAD_NO 0
-#define DEAD_DYING 1
-#define DEAD_DEAD 2
-#define DEAD_RESPAWNABLE 3
-
-//range
-#define RANGE_MELEE 0
-#define RANGE_NEAR 1
-#define RANGE_MID 2
-#define RANGE_FAR 3
-
-//gib types
-#define GIB_ORGANIC 0
-#define GIB_METALLIC 1
-
-//monster ai flags
-#define AI_STAND_GROUND 0x00000001
-#define AI_TEMP_STAND_GROUND 0x00000002
-#define AI_SOUND_TARGET 0x00000004
-#define AI_LOST_SIGHT 0x00000008
-#define AI_PURSUIT_LAST_SEEN 0x00000010
-#define AI_PURSUE_NEXT 0x00000020
-#define AI_PURSUE_TEMP 0x00000040
-#define AI_HOLD_FRAME 0x00000080
-#define AI_GOOD_GUY 0x00000100
-#define AI_BRUTAL 0x00000200
-#define AI_NOSTEP 0x00000400
-#define AI_DUCKED 0x00000800
-#define AI_COMBAT_POINT 0x00001000
-#define AI_MEDIC 0x00002000
-#define AI_RESURRECTING 0x00004000
-
-//monster attack state
-#define AS_STRAIGHT 1
-#define AS_SLIDING 2
-#define AS_MELEE 3
-#define AS_MISSILE 4
-
-// armor types
-#define ARMOR_NONE 0
-#define ARMOR_JACKET 1
-#define ARMOR_COMBAT 2
-#define ARMOR_BODY 3
-#define ARMOR_SHARD 4
-
-// power armor types
-#define POWER_ARMOR_NONE 0
-#define POWER_ARMOR_SCREEN 1
-#define POWER_ARMOR_SHIELD 2
-
-// handedness values
-#define RIGHT_HANDED 0
-#define LEFT_HANDED 1
-#define CENTER_HANDED 2
-
-
-// game.serverflags values
-#define SFL_CROSS_TRIGGER_1 0x00000001
-#define SFL_CROSS_TRIGGER_2 0x00000002
-#define SFL_CROSS_TRIGGER_3 0x00000004
-#define SFL_CROSS_TRIGGER_4 0x00000008
-#define SFL_CROSS_TRIGGER_5 0x00000010
-#define SFL_CROSS_TRIGGER_6 0x00000020
-#define SFL_CROSS_TRIGGER_7 0x00000040
-#define SFL_CROSS_TRIGGER_8 0x00000080
-#define SFL_CROSS_TRIGGER_MASK 0x000000ff
-
-
-// noise types for PlayerNoise
-#define PNOISE_SELF 0
-#define PNOISE_WEAPON 1
-#define PNOISE_IMPACT 2
-
-
-// edict->movetype values
-typedef enum
-{
-MOVETYPE_NONE, // never moves
-MOVETYPE_NOCLIP, // origin and angles change with no interaction
-MOVETYPE_PUSH, // no clip to world, push on box contact
-MOVETYPE_STOP, // no clip to world, stops on box contact
-
-MOVETYPE_WALK, // gravity
-MOVETYPE_STEP, // gravity, special edge handling
-MOVETYPE_FLY,
-MOVETYPE_TOSS, // gravity
-MOVETYPE_FLYMISSILE, // extra size to monsters
-MOVETYPE_BOUNCE
-} movetype_t;
-
-
-
-typedef struct
-{
- int base_count;
- int max_count;
- float normal_protection;
- float energy_protection;
- int armor;
-} gitem_armor_t;
-
-
-// gitem_t->flags
-#define IT_WEAPON 1 // use makes active weapon
-#define IT_AMMO 2
-#define IT_ARMOR 4
-#define IT_STAY_COOP 8
-#define IT_KEY 16
-#define IT_POWERUP 32
-
-// gitem_t->weapmodel for weapons indicates model index
-#define WEAP_BLASTER 1
-#define WEAP_SHOTGUN 2
-#define WEAP_SUPERSHOTGUN 3
-#define WEAP_MACHINEGUN 4
-#define WEAP_CHAINGUN 5
-#define WEAP_GRENADES 6
-#define WEAP_GRENADELAUNCHER 7
-#define WEAP_ROCKETLAUNCHER 8
-#define WEAP_HYPERBLASTER 9
-#define WEAP_RAILGUN 10
-#define WEAP_BFG 11
-
-typedef struct gitem_s
-{
- char *classname; // spawning name
- qboolean (*pickup)(edict_t *ent, edict_t *other);
- void (*use)(edict_t *ent, struct gitem_s *item);
- void (*drop)(edict_t *ent, struct gitem_s *item);
- void (*weaponthink)(edict_t *ent);
- char *pickup_sound;
- char *world_model;
- int world_model_flags;
- char *view_model;
-
- // client side info
- char *icon;
- char *pickup_name; // for printing on pickup
- int count_width; // number of digits to display by icon
-
- int quantity; // for ammo how much, for weapons how much is used per shot
- char *ammo; // for weapons
- int flags; // IT_* flags
-
- int weapmodel; // weapon model index (for weapons)
-
- void *info;
- int tag;
-
- char *precaches; // string of all models, sounds, and images this item will use
-} gitem_t;
-
-
-
-//
-// this structure is left intact through an entire game
-// it should be initialized at dll load time, and read/written to
-// the server.ssv file for savegames
-//
-typedef struct
-{
- char helpmessage1[512];
- char helpmessage2[512];
- int helpchanged; // flash F1 icon if non 0, play sound
- // and increment only if 1, 2, or 3
-
- gclient_t *clients; // [maxclients]
-
- // can't store spawnpoint in level, because
- // it would get overwritten by the savegame restore
- char spawnpoint[512]; // needed for coop respawns
-
- // store latched cvars here that we want to get at often
- int maxclients;
- int maxentities;
-
- // cross level triggers
- int serverflags;
-
- // items
- int num_items;
-
- qboolean autosaved;
-} game_locals_t;
-
-
-//
-// this structure is cleared as each map is entered
-// it is read/written to the level.sav file for savegames
-//
-typedef struct
-{
- int framenum;
- float time;
-
- char level_name[MAX_QPATH]; // the descriptive name (Outer Base, etc)
- char mapname[MAX_QPATH]; // the server name (base1, etc)
- char nextmap[MAX_QPATH]; // go here when fraglimit is hit
-
- // intermission state
- float intermissiontime; // time the intermission was started
- char *changemap;
- int exitintermission;
- vec3_t intermission_origin;
- vec3_t intermission_angle;
-
- edict_t *sight_client; // changed once each frame for coop games
-
- edict_t *sight_entity;
- int sight_entity_framenum;
- edict_t *sound_entity;
- int sound_entity_framenum;
- edict_t *sound2_entity;
- int sound2_entity_framenum;
-
- int pic_health;
-
- int total_secrets;
- int found_secrets;
-
- int total_goals;
- int found_goals;
-
- int total_monsters;
- int killed_monsters;
-
- edict_t *current_entity; // entity running from G_RunFrame
- int body_que; // dead bodies
-
- int power_cubes; // ugly necessity for coop
-} level_locals_t;
-
-
-// spawn_temp_t is only used to hold entity field values that
-// can be set from the editor, but aren't actualy present
-// in edict_t during gameplay
-typedef struct
-{
- // world vars
- char *sky;
- float skyrotate;
- vec3_t skyaxis;
- char *nextmap;
-
- int lip;
- int distance;
- int height;
- char *noise;
- float pausetime;
- char *item;
- char *gravity;
-
- float minyaw;
- float maxyaw;
- float minpitch;
- float maxpitch;
-} spawn_temp_t;
-
-
-typedef struct
-{
- // fixed data
- vec3_t start_origin;
- vec3_t start_angles;
- vec3_t end_origin;
- vec3_t end_angles;
-
- int sound_start;
- int sound_middle;
- int sound_end;
-
- float accel;
- float speed;
- float decel;
- float distance;
-
- float wait;
-
- // state data
- int state;
- vec3_t dir;
- float current_speed;
- float move_speed;
- float next_speed;
- float remaining_distance;
- float decel_distance;
- void (*endfunc)(edict_t *);
-} moveinfo_t;
-
-
-typedef struct
-{
- void (*aifunc)(edict_t *self, float dist);
- float dist;
- void (*thinkfunc)(edict_t *self);
-} mframe_t;
-
-typedef struct
-{
- int firstframe;
- int lastframe;
- mframe_t *frame;
- void (*endfunc)(edict_t *self);
-} mmove_t;
-
-typedef struct
-{
- mmove_t *currentmove;
- int aiflags;
- int nextframe;
- float scale;
-
- void (*stand)(edict_t *self);
- void (*idle)(edict_t *self);
- void (*search)(edict_t *self);
- void (*walk)(edict_t *self);
- void (*run)(edict_t *self);
- void (*dodge)(edict_t *self, edict_t *other, float eta);
- void (*attack)(edict_t *self);
- void (*melee)(edict_t *self);
- void (*sight)(edict_t *self, edict_t *other);
- qboolean (*checkattack)(edict_t *self);
-
- float pausetime;
- float attack_finished;
-
- vec3_t saved_goal;
- float search_time;
- float trail_time;
- vec3_t last_sighting;
- int attack_state;
- int lefty;
- float idle_time;
- int linkcount;
-
- int power_armor_type;
- int power_armor_power;
-} monsterinfo_t;
-
-
-
-extern game_locals_t game;
-extern level_locals_t level;
-extern game_import_t gi;
-extern game_export_t globals;
-extern spawn_temp_t st;
-
-extern int sm_meat_index;
-extern int snd_fry;
-
-
-// means of death
-#define MOD_UNKNOWN 0
-#define MOD_BLASTER 1
-#define MOD_SHOTGUN 2
-#define MOD_SSHOTGUN 3
-#define MOD_MACHINEGUN 4
-#define MOD_CHAINGUN 5
-#define MOD_GRENADE 6
-#define MOD_G_SPLASH 7
-#define MOD_ROCKET 8
-#define MOD_R_SPLASH 9
-#define MOD_HYPERBLASTER 10
-#define MOD_RAILGUN 11
-#define MOD_BFG_LASER 12
-#define MOD_BFG_BLAST 13
-#define MOD_BFG_EFFECT 14
-#define MOD_HANDGRENADE 15
-#define MOD_HG_SPLASH 16
-#define MOD_WATER 17
-#define MOD_SLIME 18
-#define MOD_LAVA 19
-#define MOD_CRUSH 20
-#define MOD_TELEFRAG 21
-#define MOD_FALLING 22
-#define MOD_SUICIDE 23
-#define MOD_HELD_GRENADE 24
-#define MOD_EXPLOSIVE 25
-#define MOD_BARREL 26
-#define MOD_BOMB 27
-#define MOD_EXIT 28
-#define MOD_SPLASH 29
-#define MOD_TARGET_LASER 30
-#define MOD_TRIGGER_HURT 31
-#define MOD_HIT 32
-#define MOD_TARGET_BLASTER 33
-#define MOD_FRIENDLY_FIRE 0x8000000
-
-extern int meansOfDeath;
-
-
-extern edict_t *g_edicts;
-
-#define FOFS(x) (uintptr)&(((edict_t *)0)->x)
-#define STOFS(x) (uintptr)&(((spawn_temp_t *)0)->x)
-#define LLOFS(x) (uintptr)&(((level_locals_t *)0)->x)
-#define CLOFS(x) (uintptr)&(((gclient_t *)0)->x)
-
-#define qrandom() ((rand () & 0x7fff) / ((float)0x7fff)) /* >_< arrrrggghh */
-#define crandom() (2.0 * (qrandom() - 0.5))
-
-extern cvar_t *maxentities;
-extern cvar_t *deathmatch;
-extern cvar_t *coop;
-extern cvar_t *dmflags;
-extern cvar_t *skill;
-extern cvar_t *fraglimit;
-extern cvar_t *timelimit;
-extern cvar_t *password;
-extern cvar_t *spectator_password;
-extern cvar_t *g_select_empty;
-extern cvar_t *dedicated;
-
-extern cvar_t *filterban;
-
-extern cvar_t *sv_gravity;
-extern cvar_t *sv_maxvelocity;
-
-extern cvar_t *gun_x, *gun_y, *gun_z;
-extern cvar_t *sv_rollspeed;
-extern cvar_t *sv_rollangle;
-
-extern cvar_t *run_pitch;
-extern cvar_t *run_roll;
-extern cvar_t *bob_up;
-extern cvar_t *bob_pitch;
-extern cvar_t *bob_roll;
-
-extern cvar_t *sv_cheats;
-extern cvar_t *maxclients;
-extern cvar_t *maxspectators;
-
-extern cvar_t *flood_msgs;
-extern cvar_t *flood_persecond;
-extern cvar_t *flood_waitdelay;
-
-extern cvar_t *sv_maplist;
-
-#define WORLD (&g_edicts[0])
-
-// item spawnflags
-#define ITEM_TRIGGER_SPAWN 0x00000001
-#define ITEM_NO_TOUCH 0x00000002
-// 6 bits reserved for editor flags
-// 8 bits used as power cube id bits for coop games
-#define DROPPED_ITEM 0x00010000
-#define DROPPED_PLAYER_ITEM 0x00020000
-#define ITEM_TARGETS_USED 0x00040000
-
-//
-// fields are needed for spawning from the entity string
-// and saving / loading games
-//
-#define FFL_SPAWNTEMP 1
-#define FFL_NOSPAWN 2
-
-typedef enum {
- F_INT,
- F_FLOAT,
- F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
- F_GSTRING, // string on disk, pointer in memory, TAG_GAME
- F_VECTOR,
- F_ANGLEHACK,
- F_EDICT, // index on disk, pointer in memory
- F_ITEM, // index on disk, pointer in memory
- F_CLIENT, // index on disk, pointer in memory
- F_FUNCTION,
- F_MMOVE,
- F_IGNORE
-} fieldtype_t;
-
-typedef struct
-{
- char *name;
- int ofs;
- fieldtype_t type;
- int flags;
-} field_t;
-
-
-extern field_t fields[];
-extern gitem_t itemlist[];
-
-
-//
-// g_cmds.c
-//
-void Cmd_Help_f (edict_t *ent);
-void Cmd_Score_f (edict_t *ent);
-
-//
-// g_items.c
-//
-void PrecacheItem (gitem_t *it);
-void InitItems (void);
-void SetItemNames (void);
-gitem_t *FindItem (char *pickup_name);
-gitem_t *FindItemByClassname (char *classname);
-#define ITEM_INDEX(x) ((x)-itemlist)
-edict_t *Drop_Item (edict_t *ent, gitem_t *item);
-void SetRespawn (edict_t *ent, float delay);
-void ChangeWeapon (edict_t *ent);
-void SpawnItem (edict_t *ent, gitem_t *item);
-void Think_Weapon (edict_t *ent);
-int ArmorIndex (edict_t *ent);
-int PowerArmorType (edict_t *ent);
-gitem_t *GetItemByIndex (int index);
-qboolean Add_Ammo (edict_t *ent, gitem_t *item, int count);
-void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf);
-
-//
-// g_utils.c
-//
-qboolean KillBox (edict_t *ent);
-void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result);
-edict_t *G_Find (edict_t *from, int fieldofs, char *match);
-edict_t *findradius (edict_t *from, vec3_t org, float rad);
-edict_t *G_PickTarget (char *targetname);
-void G_UseTargets (edict_t *ent, edict_t *activator);
-void G_SetMovedir (vec3_t angles, vec3_t movedir);
-
-void G_InitEdict (edict_t *e);
-edict_t *G_Spawn (void);
-void G_FreeEdict (edict_t *e);
-
-void G_TouchTriggers (edict_t *ent);
-void G_TouchSolids (edict_t *ent);
-
-char *G_CopyString (char *in);
-
-float *tv (float x, float y, float z);
-char *vtos (vec3_t v);
-
-float vectoyaw (vec3_t vec);
-void vectoangles (vec3_t vec, vec3_t angles);
-
-//
-// g_combat.c
-//
-qboolean OnSameTeam (edict_t *ent1, edict_t *ent2);
-qboolean CanDamage (edict_t *targ, edict_t *inflictor);
-void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod);
-void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod);
-
-// damage flags
-#define DAMAGE_RADIUS 0x00000001 // damage was indirect
-#define DAMAGE_NO_ARMOR 0x00000002 // armour does not protect from this damage
-#define DAMAGE_ENERGY 0x00000004 // damage is from an energy based weapon
-#define DAMAGE_NO_KNOCKBACK 0x00000008 // do not affect velocity, just view angles
-#define DAMAGE_BULLET 0x00000010 // damage is from a bullet (used for ricochets)
-#define DAMAGE_NO_PROTECTION 0x00000020 // armor, shields, invulnerability, and godmode have no effect
-
-#define DEFAULT_BULLET_HSPREAD 300
-#define DEFAULT_BULLET_VSPREAD 500
-#define DEFAULT_SHOTGUN_HSPREAD 1000
-#define DEFAULT_SHOTGUN_VSPREAD 500
-#define DEFAULT_DEATHMATCH_SHOTGUN_COUNT 12
-#define DEFAULT_SHOTGUN_COUNT 12
-#define DEFAULT_SSHOTGUN_COUNT 20
-
-//
-// g_monster.c
-//
-void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype);
-void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int flashtype);
-void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect);
-void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype);
-void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype);
-void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype);
-void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype);
-void M_droptofloor (edict_t *ent);
-void monster_think (edict_t *self);
-void walkmonster_start (edict_t *self);
-void swimmonster_start (edict_t *self);
-void flymonster_start (edict_t *self);
-void AttackFinished (edict_t *self, float time);
-void monster_death_use (edict_t *self);
-void M_CatagorizePosition (edict_t *ent);
-qboolean M_CheckAttack (edict_t *self);
-void M_FlyCheck (edict_t *self);
-void M_CheckGround (edict_t *ent);
-
-//
-// g_misc.c
-//
-void ThrowHead (edict_t *self, char *gibname, int damage, int type);
-void ThrowClientHead (edict_t *self, int damage);
-void ThrowGib (edict_t *self, char *gibname, int damage, int type);
-void BecomeExplosion1(edict_t *self);
-
-//
-// g_ai.c
-//
-void AI_SetSightClient (void);
-
-void ai_stand (edict_t *self, float dist);
-void ai_move (edict_t *self, float dist);
-void ai_walk (edict_t *self, float dist);
-void ai_turn (edict_t *self, float dist);
-void ai_run (edict_t *self, float dist);
-void ai_charge (edict_t *self, float dist);
-int range (edict_t *self, edict_t *other);
-
-void FoundTarget (edict_t *self);
-qboolean infront (edict_t *self, edict_t *other);
-qboolean visible (edict_t *self, edict_t *other);
-qboolean FacingIdeal(edict_t *self);
-
-//
-// g_weapon.c
-//
-void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin);
-qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick);
-void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int mod);
-void fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int mod);
-void fire_blaster (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int effect, qboolean hyper);
-void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius);
-void fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held);
-void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage);
-void fire_rail (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick);
-void fire_bfg (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius);
-
-//
-// g_ptrail.c
-//
-void PlayerTrail_Init (void);
-void PlayerTrail_Add (vec3_t spot);
-void PlayerTrail_New (vec3_t spot);
-edict_t *PlayerTrail_PickFirst (edict_t *self);
-edict_t *PlayerTrail_PickNext (edict_t *self);
-edict_t *PlayerTrail_LastSpot (void);
-
-//
-// g_client.c
-//
-void respawn (edict_t *ent);
-void BeginIntermission (edict_t *targ);
-void PutClientInServer (edict_t *ent);
-void InitClientPersistant (gclient_t *client);
-void InitClientResp (gclient_t *client);
-void InitBodyQue (void);
-void ClientBeginServerFrame (edict_t *ent);
-
-//
-// g_player.c
-//
-void player_pain (edict_t *self, edict_t *other, float kick, int damage);
-void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
-
-//
-// g_svcmds.c
-//
-void ServerCommand (void);
-qboolean SV_FilterPacket (char *from);
-
-//
-// p_view.c
-//
-void ClientEndServerFrame (edict_t *ent);
-
-//
-// p_hud.c
-//
-void MoveClientToIntermission (edict_t *client);
-void G_SetStats (edict_t *ent);
-void G_SetSpectatorStats (edict_t *ent);
-void G_CheckChaseStats (edict_t *ent);
-void ValidateSelectedItem (edict_t *ent);
-void DeathmatchScoreboardMessage (edict_t *client, edict_t *killer);
-
-//
-// g_pweapon.c
-//
-void PlayerNoise(edict_t *who, vec3_t where, int type);
-
-//
-// m_move.c
-//
-qboolean M_CheckBottom (edict_t *ent);
-qboolean M_walkmove (edict_t *ent, float yaw, float dist);
-void M_MoveToGoal (edict_t *ent, float dist);
-void M_ChangeYaw (edict_t *ent);
-
-//
-// g_phys.c
-//
-void G_RunEntity (edict_t *ent);
-
-//
-// g_main.c
-//
-void SaveClientData (void);
-void FetchClientEntData (edict_t *ent);
-
-//
-// g_chase.c
-//
-void UpdateChaseCam(edict_t *ent);
-void ChaseNext(edict_t *ent);
-void ChasePrev(edict_t *ent);
-void GetChaseTarget(edict_t *ent);
-
-//============================================================================
-
-// client_t->anim_priority
-#define ANIM_BASIC 0 // stand / run
-#define ANIM_WAVE 1
-#define ANIM_JUMP 2
-#define ANIM_PAIN 3
-#define ANIM_ATTACK 4
-#define ANIM_DEATH 5
-#define ANIM_REVERSE 6
-
-
-// client data that stays across multiple level loads
-typedef struct
-{
- char userinfo[MAX_INFO_STRING];
- char netname[16];
- int hand;
-
- qboolean connected; // a loadgame will leave valid entities that
- // just don't have a connection yet
-
- // values saved and restored from edicts when changing levels
- int health;
- int max_health;
- int savedFlags;
-
- int selected_item;
- int inventory[MAX_ITEMS];
-
- // ammo capacities
- int max_bullets;
- int max_shells;
- int max_rockets;
- int max_grenades;
- int max_cells;
- int max_slugs;
-
- gitem_t *weapon;
- gitem_t *lastweapon;
-
- int power_cubes; // used for tracking the cubes in coop games
- int score; // for calculating total unit score in coop games
-
- int game_helpchanged;
- int helpchanged;
-
- qboolean spectator; // client is a spectator
-} client_persistant_t;
-
-// client data that stays across deathmatch respawns
-typedef struct
-{
- client_persistant_t coop_respawn; // what to set client->pers to on a respawn
- int enterframe; // level.framenum the client entered the game
- int score; // frags, etc
- vec3_t cmd_angles; // angles sent over in the last command
-
- qboolean spectator; // client is a spectator
-} client_respawn_t;
-
-// this structure is cleared on each PutClientInServer(),
-// except for 'client->pers'
-struct gclient_t
-{
- // known to server
- player_state_t ps; // communicated by server to clients
- int ping;
-
-// the server expects the first part
-// of gclient_s to be a player_state_t
-// but the rest of it is opaque
-
- // DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
- // EXPECTS THE FIELDS IN THAT ORDER!
- //================================
-
- client_persistant_t pers;
- client_respawn_t resp;
- pmove_state_t old_pmove; // for detecting out-of-pmove changes
-
- qboolean showscores; // set layout stat
- qboolean showinventory; // set layout stat
- qboolean showhelp;
- qboolean showhelpicon;
-
- int ammo_index;
-
- int buttons;
- int oldbuttons;
- int latched_buttons;
-
- qboolean weapon_thunk;
-
- gitem_t *newweapon;
-
- // sum up damage over an entire frame, so
- // shotgun blasts give a single big kick
- int damage_armor; // damage absorbed by armor
- int damage_parmor; // damage absorbed by power armor
- int damage_blood; // damage taken out of health
- int damage_knockback; // impact damage
- vec3_t damage_from; // origin for vector calculation
-
- float killer_yaw; // when dead, look at killer
-
- weaponstate_t weaponstate;
- vec3_t kick_angles; // weapon kicks
- vec3_t kick_origin;
- float v_dmg_roll, v_dmg_pitch, v_dmg_time; // damage kicks
- float fall_time, fall_value; // for view drop on fall
- float damage_alpha;
- float bonus_alpha;
- vec3_t damage_blend;
- vec3_t v_angle; // aiming direction
- float bobtime; // so off-ground doesn't change it
- vec3_t oldviewangles;
- vec3_t oldvelocity;
-
- float next_drown_time;
- int old_waterlevel;
- int breather_sound;
-
- int machinegun_shots; // for weapon raising
-
- // animation vars
- int anim_end;
- int anim_priority;
- qboolean anim_duck;
- qboolean anim_run;
-
- // powerup timers
- float quad_framenum;
- float invincible_framenum;
- float breather_framenum;
- float enviro_framenum;
-
- qboolean grenade_blew_up;
- float grenade_time;
- int silencer_shots;
- int weapon_sound;
-
- float pickup_msg_time;
-
- float flood_locktill; // locked from talking
- float flood_when[10]; // when messages were said
- int flood_whenhead; // head pointer for when said
-
- float respawn_time; // can respawn when time > this
-
- edict_t *chase_target; // player we are chasing
- qboolean update_chase; // need to update chase info?
-};
-
-
-struct edict_t
-{
- entity_state_t s;
- gclient_t *client; // NULL if not a player
-
- qboolean inuse;
- int linkcount;
-
- // FIXME: move these fields to a server private sv_entity_t
- link_t area; // linked to a division node or leaf
-
- int num_clusters; // if -1, use headnode instead
- int clusternums[MAX_ENT_CLUSTERS];
- int headnode; // unused if num_clusters != -1
- int areanum, areanum2;
-
- //================================
-
- int svflags; // SCF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc.
- vec3_t mins, maxs;
- vec3_t absmin, absmax, size;
- solid_t solid;
- int clipmask;
- edict_t *owner;
-
- // DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
- // EXPECTS THE FIELDS IN THAT ORDER!
- //================================
-
- int movetype;
- int flags;
-
- char *model;
- float freetime; // sv.time when the object was freed
-
- //
- // only used locally in game, not by server
- //
- char *message;
- char *classname;
- int spawnflags;
-
- float timestamp;
-
- float angle; // set in qe3, -1 = up, -2 = down
- char *target;
- char *targetname;
- char *killtarget;
- char *team;
- char *pathtarget;
- char *deathtarget;
- char *combattarget;
- edict_t *target_ent;
-
- float speed, accel, decel;
- vec3_t movedir;
- vec3_t pos1, pos2;
-
- vec3_t velocity;
- vec3_t avelocity;
- int mass;
- float air_finished;
- float gravity; // per entity gravity multiplier (1.0 is normal)
- // use for lowgrav artifact, flares
-
- edict_t *goalentity;
- edict_t *movetarget;
- float yaw_speed;
- float ideal_yaw;
-
- float nextthink;
- void (*prethink) (edict_t *ent);
- void (*think)(edict_t *self);
- void (*blocked)(edict_t *self, edict_t *other); //move to moveinfo?
- void (*touch)(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
- void (*use)(edict_t *self, edict_t *other, edict_t *activator);
- void (*pain)(edict_t *self, edict_t *other, float kick, int damage);
- void (*die)(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
-
- float touch_debounce_time; // are all these legit? do we need more/less of them?
- float pain_debounce_time;
- float damage_debounce_time;
- float fly_sound_debounce_time; //move to clientinfo
- float last_move_time;
-
- int health;
- int max_health;
- int gib_health;
- int deadflag;
- qboolean show_hostile;
-
- float powerarmor_time;
-
- char *map; // target_changelevel
-
- int viewheight; // height above origin where eyesight is determined
- int takedamage;
- int dmg;
- int radius_dmg;
- float dmg_radius;
- int sounds; //make this a spawntemp var?
- int count;
-
- edict_t *chain;
- edict_t *enemy;
- edict_t *oldenemy;
- edict_t *activator;
- edict_t *groundentity;
- int groundentity_linkcount;
- edict_t *teamchain;
- edict_t *teammaster;
-
- edict_t *mynoise; // can go in client only
- edict_t *mynoise2;
-
- int noise_index;
- int noise_index2;
- float volume;
- float attenuation;
-
- // timing variables
- float wait;
- float delay; // before firing targets
- float random;
-
- float teleport_time;
-
- int watertype;
- int waterlevel;
-
- vec3_t move_origin;
- vec3_t move_angles;
-
- // move this to clientinfo?
- int light_level;
-
- int style; // also used as areaportal number
-
- gitem_t *item; // for bonus items
-
- // common data blocks
- moveinfo_t moveinfo;
- monsterinfo_t monsterinfo;
-};
--- a/game/g_main.c
+++ b/game/g_main.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
game_locals_t game;
level_locals_t level;
--- a/game/g_misc.c
+++ b/game/g_misc.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*QUAKED func_group (0 0 0) ?
--- a/game/g_monster.c
+++ b/game/g_monster.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
//
--- a/game/g_phys.c
+++ b/game/g_phys.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*
--- a/game/g_save.c
+++ b/game/g_save.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#define Function(f) {#f, f}
--- a/game/g_spawn.c
+++ b/game/g_spawn.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
typedef struct
{
--- a/game/g_svcmds.c
+++ b/game/g_svcmds.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
void Svcmd_Test_f (void)
--- a/game/g_target.c
+++ b/game/g_target.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8)
Fire an origin based temp entity event to the clients.
--- a/game/g_trigger.c
+++ b/game/g_trigger.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
void InitTrigger (edict_t *self)
--- a/game/g_turret.c
+++ b/game/g_turret.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
void AnglesNormalize(vec3_t vec)
--- a/game/g_utils.c
+++ b/game/g_utils.c
@@ -3,7 +3,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
--- a/game/g_weapon.c
+++ b/game/g_weapon.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*
--- a/game/game.h
+++ b/game/game.h
@@ -1,173 +1,974 @@
-// game.h -- game dll information visible to server
+typedef struct link_t link_t;
+typedef struct game_import_t game_import_t;
+typedef struct game_export_t game_export_t;
+typedef struct gitem_armor_t gitem_armor_t;
+typedef struct gitem_t gitem_t;
+typedef struct game_locals_t game_locals_t;
+typedef struct level_locals_t level_locals_t;
+typedef struct spawn_temp_t spawn_temp_t;
+typedef struct moveinfo_t moveinfo_t;
+typedef struct mframe_t mframe_t;
+typedef struct mmove_t mmove_t;
+typedef struct monsterinfo_t monsterinfo_t;
+typedef struct field_t field_t;
+typedef struct client_persistant_t client_persistant_t;
+typedef struct client_respawn_t client_respawn_t;
+typedef struct edict_t edict_t;
+typedef struct gclient_t gclient_t;
-#define GAME_API_VERSION 3
+extern cvar_t *maxentities;
+extern cvar_t *deathmatch;
+extern cvar_t *coop;
+extern cvar_t *dmflags;
+extern cvar_t *skill;
+extern cvar_t *fraglimit;
+extern cvar_t *timelimit;
+extern cvar_t *password;
+extern cvar_t *spectator_password;
+extern cvar_t *g_select_empty;
+extern cvar_t *dedicated;
+extern cvar_t *filterban;
+extern cvar_t *sv_gravity;
+extern cvar_t *sv_maxvelocity;
+extern cvar_t *gun_x, *gun_y, *gun_z;
+extern cvar_t *sv_rollspeed;
+extern cvar_t *sv_rollangle;
+extern cvar_t *run_pitch;
+extern cvar_t *run_roll;
+extern cvar_t *bob_up;
+extern cvar_t *bob_pitch;
+extern cvar_t *bob_roll;
+extern cvar_t *sv_cheats;
+extern cvar_t *maxclients;
+extern cvar_t *maxspectators;
+extern cvar_t *flood_msgs;
+extern cvar_t *flood_persecond;
+extern cvar_t *flood_waitdelay;
+extern cvar_t *sv_maplist;
-// edict->svflags
+enum{
+ GAME_API_VERSION = 3,
-#define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects
-#define SVF_DEADMONSTER 0x00000002 // treat as CONTENTS_DEADMONSTER for collision
-#define SVF_MONSTER 0x00000004 // treat as CONTENTS_MONSTER for collision
+ /* edict->svflags */
+ SVF_NOCLIENT = 1<<0, // don't send entity to clients, even if it has effects
+ SVF_DEADMONSTER = 1<<1, // treat as CONTENTS_DEADMONSTER for collision
+ SVF_MONSTER = 1<<2, // treat as CONTENTS_MONSTER for collision
-// edict->solid values
+ MAX_ENT_CLUSTERS = 16
+};
-typedef enum
-{
-SOLID_NOT, // no interaction with other objects
-SOLID_TRIGGER, // only touch when inside, after moving
-SOLID_BBOX, // touch on edge
-SOLID_BSP // bsp clip, touch on edge
-} solid_t;
+/* edict->solid values */
+typedef enum solid_t{
+ SOLID_NOT, // no interaction with other objects
+ SOLID_TRIGGER, // only touch when inside, after moving
+ SOLID_BBOX, // touch on edge
+ SOLID_BSP // bsp clip, touch on edge
+}solid_t;
+
+/* link_t is only used for entity area links now */
+struct link_t{
+ link_t *prev;
+ link_t *next;
+};
+
+struct game_import_t{
+ void (*bprintf)(int, char *, ...);
+ void (*dprintf)(char *, ...);
+ void (*cprintf)(edict_t *, int, char *, ...);
+ void (*centerprintf)(edict_t *, char *, ...);
+ void (*sound)(edict_t *, int, int, float, float, float);
+ void (*positioned_sound)(vec3_t, edict_t *, int, int, float, float, float);
+ /* config strings hold all the index strings, the lightstyles, and misc
+ * data like the sky definition and cdtrack. all of the current
+ * configstrings are sent to clients when they connect, and changes are
+ * sent to all connected clients. */
+ void (*configstring)(int, char *);
+ void (*error)(char *, ...);
+ /* the *index functions create configstrings and some internal server
+ * state */
+ int (*modelindex)(char *);
+ int (*soundindex)(char *);
+ int (*imageindex)(char *);
+ void (*setmodel)(edict_t *, char *);
+ /* collision detection */
+ trace_t (*trace)(vec3_t, vec3_t, vec3_t, vec3_t, edict_t *, int);
+ int (*pointcontents)(vec3_t);
+ qboolean (*inPVS)(vec3_t, vec3_t);
+ qboolean (*inPHS)(vec3_t, vec3_t);
+ void (*SetAreaPortalState)(int, qboolean);
+ qboolean (*AreasConnected)(int, int);
+ /* an entity will never be sent to a client or used for collision if it
+ * is not passed to linkentity. If the size, position, or solidity
+ * changes, it must be relinked. */
+ void (*linkentity)(edict_t *);
+ /* call before removing an interactive edict */
+ void (*unlinkentity)(edict_t *);
+ int (*BoxEdicts)(vec3_t, vec3_t, edict_t **, int, int);
+ /* player movement code common with client prediction */
+ void (*Pmove)(pmove_t *);
+ /* network messaging */
+ void (*multicast)(vec3_t, multicast_t);
+ void (*unicast)(edict_t *, qboolean);
+ void (*WriteChar)(int);
+ void (*WriteByte)(int);
+ void (*WriteShort)(int);
+ void (*WriteLong)(int);
+ void (*WriteFloat)(float);
+ void (*WriteString)(char *);
+ void (*WritePosition)(vec3_t); // some fractional bits
+ void (*WriteDir)(vec3_t); // single byte encoded, very coarse
+ void (*WriteAngle)(float);
+ /* managed memory allocation */
+ void* (*TagMalloc)(int, int);
+ void (*TagFree)(void *);
+ void (*FreeTags)(int);
+ /* console variable interaction */
+ cvar_t* (*cvar)(char *, char *, int);
+ cvar_t* (*cvar_set)(char *, char *);
+ cvar_t* (*cvar_forceset)(char *, char *);
+ /* ClientCommand and ServerCommand parameter access */
+ int (*argc)(void);
+ char* (*argv)(int);
+ char* (*args)(void); // concatenation of all argv >= 1
+ /* add commands to the server console as if they were typed in for map
+ * changing, etc */
+ void (*AddCommandString)(char *);
+ void (*DebugGraph)(float, int);
+};
+extern game_import_t gi;
+
+struct game_export_t{
+ int apiversion;
+ /* the init function will only be called when a game starts, not each
+ * time a level is loaded. Persistant data for clients and the server
+ * can be allocated in init */
+ void (*Init)(void);
+ void (*Shutdown)(void);
+ /* each new level entered will cause a call to SpawnEntities */
+ void (*SpawnEntities)(char *, char *, char *);
+ /* Read/Write Game is for storing persistant cross level information
+ * about the world state and the clients. WriteGame is called every
+ * time a level is exited. ReadGame is called on a loadgame. */
+ void (*WriteGame)(char *, qboolean);
+ void (*ReadGame)(char *);
+ /* ReadLevel is called after the default map information has been
+ * loaded with SpawnEntities */
+ void (*WriteLevel)(char *);
+ void (*ReadLevel)(char *);
+ qboolean (*ClientConnect)(edict_t *, char *);
+ void (*ClientBegin)(edict_t *);
+ void (*ClientUserinfoChanged)(edict_t *, char *);
+ void (*ClientDisconnect)(edict_t *);
+ void (*ClientCommand)(edict_t *);
+ void (*ClientThink)(edict_t *, usercmd_t *);
+ void (*RunFrame)(void);
+ /* ServerCommand will be called when an "sv <command>" command is
+ * issued on the server console. the game can issue gi.argc() or
+ * gi.argv() commands to get the rest of the parameters */
+ void (*ServerCommand)(void);
+ /* global variables shared between game and server: the edict array is
+ * allocated in the game dll so it can vary in size from one game to
+ * another. the size will be fixed when ge->Init() is called */
+ edict_t *edicts;
+ int edict_size;
+ int num_edicts; // current number, <= max_edicts
+ int max_edicts;
+};
+extern game_export_t globals;
-//===============================================================
+game_export_t *GetGameAPI(game_import_t *);
-// link_t is only used for entity area links now
-typedef struct link_s
-{
- struct link_s *prev, *next;
-} link_t;
+#define GAMEVERSION "baseq2"
+#define DAMAGE_TIME 0.5 // view pitching times
+#define FALL_TIME 0.3
+#define FRAMETIME 0.1
+enum{
+ /* edict->spawnflags */
+ SPAWNFLAG_NOT_EASY = 1<<8,
+ SPAWNFLAG_NOT_MEDIUM = 1<<9,
+ SPAWNFLAG_NOT_HARD = 1<<10,
+ SPAWNFLAG_NOT_DEATHMATCH = 1<<11,
+ SPAWNFLAG_NOT_COOP = 1<<12,
+ /* edict->flags */
+ FL_FLY = 1<<0,
+ FL_SWIM = 1<<1, // implied immunity to drowining
+ FL_IMMUNE_LASER = 1<<2,
+ FL_INWATER = 1<<3,
+ FL_GODMODE = 1<<4,
+ FL_NOTARGET = 1<<5,
+ FL_IMMUNE_SLIME = 1<<6,
+ FL_IMMUNE_LAVA = 1<<7,
+ FL_PARTIALGROUND = 1<<8, // not all corners are valid
+ FL_WATERJUMP = 1<<9, // player jumping out of water
+ FL_TEAMSLAVE = 1<<10, // not the first on the team
+ FL_NO_KNOCKBACK = 1<<11,
+ FL_POWER_ARMOR = 1<<12, // power armor (if any) is active
+ FL_RESPAWN = 1<<31, // used for item respawning
-#define MAX_ENT_CLUSTERS 16
+ /* memory tags to allow dynamic memory to be cleaned up */
+ TAG_GAME = 765, // clear when unloading the dll
+ TAG_LEVEL = 766, // clear when loading a new level
+ MELEE_DISTANCE = 80,
+ BODY_QUEUE_SIZE = 8,
-typedef struct edict_t edict_t;
-typedef struct gclient_t gclient_t;
+ /* deadflag */
+ DEAD_NO = 0,
+ DEAD_DYING = 1,
+ DEAD_DEAD = 2,
+ DEAD_RESPAWNABLE = 3,
+ /* range */
+ RANGE_MELEE = 0,
+ RANGE_NEAR = 1,
+ RANGE_MID = 2,
+ RANGE_FAR = 3,
+ /* gib types */
+ GIB_ORGANIC = 0,
+ GIB_METALLIC = 1,
+ /* monster ai flags */
+ AI_STAND_GROUND = 1<<0,
+ AI_TEMP_STAND_GROUND = 1<<1,
+ AI_SOUND_TARGET = 1<<2,
+ AI_LOST_SIGHT = 1<<3,
+ AI_PURSUIT_LAST_SEEN = 1<<4,
+ AI_PURSUE_NEXT = 1<<5,
+ AI_PURSUE_TEMP = 1<<6,
+ AI_HOLD_FRAME = 1<<7,
+ AI_GOOD_GUY = 1<<8,
+ AI_BRUTAL = 1<<9,
+ AI_NOSTEP = 1<<10,
+ AI_DUCKED = 1<<11,
+ AI_COMBAT_POINT = 1<<12,
+ AI_MEDIC = 1<<13,
+ AI_RESURRECTING = 1<<14,
+ /* monster attack state */
+ AS_STRAIGHT = 1,
+ AS_SLIDING = 2,
+ AS_MELEE = 3,
+ AS_MISSILE = 4,
+ /* armor types */
+ ARMOR_NONE = 0,
+ ARMOR_JACKET = 1,
+ ARMOR_COMBAT = 2,
+ ARMOR_BODY = 3,
+ ARMOR_SHARD = 4,
+ /* power armor types */
+ POWER_ARMOR_NONE = 0,
+ POWER_ARMOR_SCREEN = 1,
+ POWER_ARMOR_SHIELD = 2,
+ /* handedness values */
+ RIGHT_HANDED = 0,
+ LEFT_HANDED = 1,
+ CENTER_HANDED = 2,
+ /* game.serverflags values */
+ SFL_CROSS_TRIGGER_1 = 1<<0,
+ SFL_CROSS_TRIGGER_2 = 1<<1,
+ SFL_CROSS_TRIGGER_3 = 1<<2,
+ SFL_CROSS_TRIGGER_4 = 1<<3,
+ SFL_CROSS_TRIGGER_5 = 1<<4,
+ SFL_CROSS_TRIGGER_6 = 1<<5,
+ SFL_CROSS_TRIGGER_7 = 1<<6,
+ SFL_CROSS_TRIGGER_8 = 1<<7,
+ SFL_CROSS_TRIGGER_MASK = 0xff,
+ /* noise types for PlayerNoise */
+ PNOISE_SELF = 0,
+ PNOISE_WEAPON = 1,
+ PNOISE_IMPACT = 2,
+};
+typedef enum damage_t{
+ DAMAGE_NO,
+ DAMAGE_YES, // will take damage if hit
+ DAMAGE_AIM // auto targeting recognizes this
+}damage_t;
+typedef enum weaponstate_t{
+ WEAPON_READY,
+ WEAPON_ACTIVATING,
+ WEAPON_DROPPING,
+ WEAPON_FIRING
+}weaponstate_t;
+typedef enum ammo_t{
+ AMMO_BULLETS,
+ AMMO_SHELLS,
+ AMMO_ROCKETS,
+ AMMO_GRENADES,
+ AMMO_CELLS,
+ AMMO_SLUGS
+}ammo_t;
-//===============================================================
+/* edict->movetype values */
+typedef enum movetype_t{
+ MOVETYPE_NONE, // never moves
+ MOVETYPE_NOCLIP, // origin and angles change with no interaction
+ MOVETYPE_PUSH, // no clip to world, push on box contact
+ MOVETYPE_STOP, // no clip to world, stops on box contact
+ MOVETYPE_WALK, // gravity
+ MOVETYPE_STEP, // gravity, special edge handling
+ MOVETYPE_FLY,
+ MOVETYPE_TOSS, // gravity
+ MOVETYPE_FLYMISSILE, // extra size to monsters
+ MOVETYPE_BOUNCE
+}movetype_t;
-//
-// functions provided by the main engine
-//
-typedef struct
-{
- // special messages
- void (*bprintf) (int printlevel, char *fmt, ...);
- void (*dprintf) (char *fmt, ...);
- void (*cprintf) (edict_t *ent, int printlevel, char *fmt, ...);
- void (*centerprintf) (edict_t *ent, char *fmt, ...);
- void (*sound) (edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs);
- void (*positioned_sound) (vec3_t origin, edict_t *ent, int channel, int soundinedex, float volume, float attenuation, float timeofs);
+struct gitem_armor_t{
+ int base_count;
+ int max_count;
+ float normal_protection;
+ float energy_protection;
+ int armor;
+};
- // config strings hold all the index strings, the lightstyles,
- // and misc data like the sky definition and cdtrack.
- // All of the current configstrings are sent to clients when
- // they connect, and changes are sent to all connected clients.
- void (*configstring) (int num, char *string);
+enum{
+ /* gitem_t->flags */
+ IT_WEAPON = 1<<0, // use makes active weapon
+ IT_AMMO = 1<<1,
+ IT_ARMOR = 1<<2,
+ IT_STAY_COOP = 1<<3,
+ IT_KEY = 1<<4,
+ IT_POWERUP = 1<<5,
+ /* gitem_t->weapmodel for weapons indicates model index */
+ WEAP_BLASTER = 1,
+ WEAP_SHOTGUN = 2,
+ WEAP_SUPERSHOTGUN = 3,
+ WEAP_MACHINEGUN = 4,
+ WEAP_CHAINGUN = 5,
+ WEAP_GRENADES = 6,
+ WEAP_GRENADELAUNCHER = 7,
+ WEAP_ROCKETLAUNCHER = 8,
+ WEAP_HYPERBLASTER = 9,
+ WEAP_RAILGUN = 10,
+ WEAP_BFG = 11
+};
+struct gitem_t{
+ char *classname; // spawning name
+ qboolean (*pickup)(edict_t *, edict_t *);
+ void (*use)(edict_t *, gitem_t *);
+ void (*drop)(edict_t *, gitem_t *);
+ void (*weaponthink)(edict_t *);
+ char *pickup_sound;
+ char *world_model;
+ int world_model_flags;
+ char *view_model;
+ /* client side info */
+ char *icon;
+ char *pickup_name; // for printing on pickup
+ int count_width; // number of digits to display by icon
+ int quantity; // for ammo how much, for weapons how much is used per shot
+ char *ammo; // for weapons
+ int flags; // IT_* flags
+ int weapmodel; // weapon model index (for weapons)
+ void *info;
+ int tag;
+ /* string of all models, sounds, and images this item will use */
+ char *precaches;
+};
+extern gitem_t itemlist[];
- void (*error) (char *fmt, ...);
+/* this structure is left intact through an entire game it should be
+ * initialized at dll load time, and read/written to the server.ssv file for
+ * savegames */
+struct game_locals_t{
+ char helpmessage1[512];
+ char helpmessage2[512];
+ /* flash F1 icon if non 0, play sound and increment only if 1, 2, or 3 */
+ int helpchanged;
+ gclient_t *clients; // [maxclients]
+ /* can't store spawnpoint in level, because it would get overwritten
+ * by the savegame restore */
+ char spawnpoint[512]; // needed for coop respawns
+ /* store latched cvars here that we want to get at often */
+ int maxclients;
+ int maxentities;
+ /* cross level triggers */
+ int serverflags;
+ int num_items;
+ qboolean autosaved;
+};
+extern game_locals_t game;
- // the *index functions create configstrings and some internal server state
- int (*modelindex) (char *name);
- int (*soundindex) (char *name);
- int (*imageindex) (char *name);
+/* this structure is cleared as each map is entered; it is read/written to the
+ * level.sav file for savegames */
+struct level_locals_t{
+ int framenum;
+ float time;
+ char level_name[MAX_QPATH]; // the descriptive name (Outer Base, etc)
+ char mapname[MAX_QPATH]; // the server name (base1, etc)
+ char nextmap[MAX_QPATH]; // go here when fraglimit is hit
+ /* intermission state */
+ float intermissiontime; // time the intermission was started
+ char *changemap;
+ int exitintermission;
+ vec3_t intermission_origin;
+ vec3_t intermission_angle;
+ edict_t *sight_client; // changed once each frame for coop games
+ edict_t *sight_entity;
+ int sight_entity_framenum;
+ edict_t *sound_entity;
+ int sound_entity_framenum;
+ edict_t *sound2_entity;
+ int sound2_entity_framenum;
+ int pic_health;
+ int total_secrets;
+ int found_secrets;
+ int total_goals;
+ int found_goals;
+ int total_monsters;
+ int killed_monsters;
+ edict_t *current_entity; // entity running from G_RunFrame
+ int body_que; // dead bodies
+ int power_cubes; // ugly necessity for coop
+};
+extern level_locals_t level;
- void (*setmodel) (edict_t *ent, char *name);
+/* spawn_temp_t is only used to hold entity field values that can be set from
+ * the editor, but aren't actualy present in edict_t during gameplay */
+struct spawn_temp_t{
+ /* world vars */
+ char *sky;
+ float skyrotate;
+ vec3_t skyaxis;
+ char *nextmap;
- // collision detection
- trace_t (*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask);
- int (*pointcontents) (vec3_t point);
- qboolean (*inPVS) (vec3_t p1, vec3_t p2);
- qboolean (*inPHS) (vec3_t p1, vec3_t p2);
- void (*SetAreaPortalState) (int portalnum, qboolean open);
- qboolean (*AreasConnected) (int area1, int area2);
+ int lip;
+ int distance;
+ int height;
+ char *noise;
+ float pausetime;
+ char *item;
+ char *gravity;
+ float minyaw;
+ float maxyaw;
+ float minpitch;
+ float maxpitch;
+};
+extern spawn_temp_t st;
- // an entity will never be sent to a client or used for collision
- // if it is not passed to linkentity. If the size, position, or
- // solidity changes, it must be relinked.
- void (*linkentity) (edict_t *ent);
- void (*unlinkentity) (edict_t *ent); // call before removing an interactive edict
- int (*BoxEdicts) (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype);
- void (*Pmove) (pmove_t *pmove); // player movement code common with client prediction
+struct moveinfo_t{
+ /* fixed data */
+ vec3_t start_origin;
+ vec3_t start_angles;
+ vec3_t end_origin;
+ vec3_t end_angles;
+ int sound_start;
+ int sound_middle;
+ int sound_end;
+ float accel;
+ float speed;
+ float decel;
+ float distance;
+ float wait;
+ /* state data */
+ int state;
+ vec3_t dir;
+ float current_speed;
+ float move_speed;
+ float next_speed;
+ float remaining_distance;
+ float decel_distance;
+ void (*endfunc)(edict_t *);
+};
- // network messaging
- void (*multicast) (vec3_t origin, multicast_t to);
- void (*unicast) (edict_t *ent, qboolean reliable);
- void (*WriteChar) (int c);
- void (*WriteByte) (int c);
- void (*WriteShort) (int c);
- void (*WriteLong) (int c);
- void (*WriteFloat) (float f);
- void (*WriteString) (char *s);
- void (*WritePosition) (vec3_t pos); // some fractional bits
- void (*WriteDir) (vec3_t pos); // single byte encoded, very coarse
- void (*WriteAngle) (float f);
+struct mframe_t{
+ void (*aifunc)(edict_t *, float);
+ float dist;
+ void (*thinkfunc)(edict_t *);
+};
- // managed memory allocation
- void *(*TagMalloc) (int size, int tag);
- void (*TagFree) (void *block);
- void (*FreeTags) (int tag);
+struct mmove_t{
+ int firstframe;
+ int lastframe;
+ mframe_t *frame;
+ void (*endfunc)(edict_t *);
+};
- // console variable interaction
- cvar_t *(*cvar) (char *var_name, char *value, int flags);
- cvar_t *(*cvar_set) (char *var_name, char *value);
- cvar_t *(*cvar_forceset) (char *var_name, char *value);
+struct monsterinfo_t{
+ mmove_t *currentmove;
+ int aiflags;
+ int nextframe;
+ float scale;
+ void (*stand)(edict_t *);
+ void (*idle)(edict_t *);
+ void (*search)(edict_t *);
+ void (*walk)(edict_t *);
+ void (*run)(edict_t *);
+ void (*dodge)(edict_t *, edict_t *, float);
+ void (*attack)(edict_t *);
+ void (*melee)(edict_t *);
+ void (*sight)(edict_t *, edict_t *);
+ qboolean (*checkattack)(edict_t *);
+ float pausetime;
+ float attack_finished;
+ vec3_t saved_goal;
+ float search_time;
+ float trail_time;
+ vec3_t last_sighting;
+ int attack_state;
+ int lefty;
+ float idle_time;
+ int linkcount;
+ int power_armor_type;
+ int power_armor_power;
+};
- // ClientCommand and ServerCommand parameter access
- int (*argc) (void);
- char *(*argv) (int n);
- char *(*args) (void); // concatenation of all argv >= 1
+extern int sm_meat_index;
+extern int snd_fry;
- // add commands to the server console as if they were typed in
- // for map changing, etc
- void (*AddCommandString) (char *text);
+/* means of death */
+enum{
+ MOD_UNKNOWN = 0,
+ MOD_BLASTER = 1,
+ MOD_SHOTGUN = 2,
+ MOD_SSHOTGUN = 3,
+ MOD_MACHINEGUN = 4,
+ MOD_CHAINGUN = 5,
+ MOD_GRENADE = 6,
+ MOD_G_SPLASH = 7,
+ MOD_ROCKET = 8,
+ MOD_R_SPLASH = 9,
+ MOD_HYPERBLASTER = 10,
+ MOD_RAILGUN = 11,
+ MOD_BFG_LASER = 12,
+ MOD_BFG_BLAST = 13,
+ MOD_BFG_EFFECT = 14,
+ MOD_HANDGRENADE = 15,
+ MOD_HG_SPLASH = 16,
+ MOD_WATER = 17,
+ MOD_SLIME = 18,
+ MOD_LAVA = 19,
+ MOD_CRUSH = 20,
+ MOD_TELEFRAG = 21,
+ MOD_FALLING = 22,
+ MOD_SUICIDE = 23,
+ MOD_HELD_GRENADE = 24,
+ MOD_EXPLOSIVE = 25,
+ MOD_BARREL = 26,
+ MOD_BOMB = 27,
+ MOD_EXIT = 28,
+ MOD_SPLASH = 29,
+ MOD_TARGET_LASER = 30,
+ MOD_TRIGGER_HURT = 31,
+ MOD_HIT = 32,
+ MOD_TARGET_BLASTER = 33,
+ MOD_FRIENDLY_FIRE = 1<<31
+};
+extern int meansOfDeath;
- void (*DebugGraph) (float value, int color);
-} game_import_t;
+enum{
+ /* item spawnflags */
+ ITEM_TRIGGER_SPAWN = 1<<0,
+ ITEM_NO_TOUCH = 1<<1,
+ /* 6 bits reserved for editor flags; 8 bits used as power cube id bits
+ * for coop games */
+ DROPPED_ITEM = 1<<16,
+ DROPPED_PLAYER_ITEM = 1<<17,
+ ITEM_TARGETS_USED = 1<<18,
+ /* fields are needed for spawning from the entity string and saving or
+ * loading games */
+ FFL_SPAWNTEMP = 1,
+ FFL_NOSPAWN = 2
+};
+typedef enum fieldtype_t{
+ F_INT,
+ F_FLOAT,
+ F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
+ F_GSTRING, // string on disk, pointer in memory, TAG_GAME
+ F_VECTOR,
+ F_ANGLEHACK,
+ F_EDICT, // index on disk, pointer in memory
+ F_ITEM, // index on disk, pointer in memory
+ F_CLIENT, // index on disk, pointer in memory
+ F_FUNCTION,
+ F_MMOVE,
+ F_IGNORE
+}fieldtype_t;
+struct field_t{
+ char *name;
+ int ofs;
+ fieldtype_t type;
+ int flags;
+};
+extern field_t fields[];
-//
-// functions exported by the game subsystem
-//
-typedef struct
-{
- int apiversion;
+enum{
+ /* damage flags */
+ DAMAGE_RADIUS = 1<<0, // indirect dmg
+ DAMAGE_NO_ARMOR = 1<<1, // not protected by armour
+ DAMAGE_ENERGY = 1<<2, // is from an energy based weapon
+ DAMAGE_NO_KNOCKBACK = 1<<3, // do not affect velocity, just view angles
+ DAMAGE_BULLET = 1<<4, // is from a bullet (used for ricochets)
+ /* no effect from armor, shields, invulnerability, and godmode */
+ DAMAGE_NO_PROTECTION = 1<<5,
- // the init function will only be called when a game starts,
- // not each time a level is loaded. Persistant data for clients
- // and the server can be allocated in init
- void (*Init) (void);
- void (*Shutdown) (void);
+ DEFAULT_BULLET_HSPREAD = 300,
+ DEFAULT_BULLET_VSPREAD = 500,
+ DEFAULT_SHOTGUN_HSPREAD = 1000,
+ DEFAULT_SHOTGUN_VSPREAD = 500,
+ DEFAULT_DEATHMATCH_SHOTGUN_COUNT = 12,
+ DEFAULT_SHOTGUN_COUNT = 12,
+ DEFAULT_SSHOTGUN_COUNT = 20,
- // each new level entered will cause a call to SpawnEntities
- void (*SpawnEntities) (char *mapname, char *entstring, char *spawnpoint);
+ /* client_t->anim_priority */
+ ANIM_BASIC = 0, // stand / run
+ ANIM_WAVE = 1,
+ ANIM_JUMP = 2,
+ ANIM_PAIN = 3,
+ ANIM_ATTACK = 4,
+ ANIM_DEATH = 5,
+ ANIM_REVERSE = 6
+};
- // Read/Write Game is for storing persistant cross level information
- // about the world state and the clients.
- // WriteGame is called every time a level is exited.
- // ReadGame is called on a loadgame.
- void (*WriteGame) (char *filename, qboolean autosave);
- void (*ReadGame) (char *filename);
+/* client data that stays across multiple level loads */
+struct client_persistant_t{
+ char userinfo[MAX_INFO_STRING];
+ char netname[16];
+ int hand;
+ /* a loadgame will leave valid entities that just don't have a connection yet */
+ qboolean connected;
+ /* values saved and restored from edicts when changing levels */
+ int health;
+ int max_health;
+ int savedFlags;
+ int selected_item;
+ int inventory[MAX_ITEMS];
+ int max_bullets;
+ int max_shells;
+ int max_rockets;
+ int max_grenades;
+ int max_cells;
+ int max_slugs;
+ gitem_t *weapon;
+ gitem_t *lastweapon;
+ int power_cubes; // used for tracking the cubes in coop games
+ int score; // for calculating total unit score in coop games
+ int game_helpchanged;
+ int helpchanged;
+ qboolean spectator; // client is a spectator
+};
+/* client data that stays across deathmatch respawns */
+struct client_respawn_t{
+ client_persistant_t coop_respawn; // assigned to client->pers on a respawn
+ int enterframe; // level.framenum the client entered the game
+ int score; // frags, etc
+ vec3_t cmd_angles; // angles sent over in the last command
+ qboolean spectator; // client is a spectator
+};
+/* this structure is cleared on each PutClientInServer(), except for .pers */
+struct gclient_t{
+ /* known to server */
+ player_state_t ps; // communicated by server to clients
+ int ping;
- // ReadLevel is called after the default map information has been
- // loaded with SpawnEntities
- void (*WriteLevel) (char *filename);
- void (*ReadLevel) (char *filename);
+ /* the server expects the first part of gclient_s to be a
+ * player_state_t but the rest of it is opaque
+ * DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER EXPECTS THE FIELDS IN
+ * THAT ORDER! */
- qboolean (*ClientConnect) (edict_t *ent, char *userinfo);
- void (*ClientBegin) (edict_t *ent);
- void (*ClientUserinfoChanged) (edict_t *ent, char *userinfo);
- void (*ClientDisconnect) (edict_t *ent);
- void (*ClientCommand) (edict_t *ent);
- void (*ClientThink) (edict_t *ent, usercmd_t *cmd);
+ client_persistant_t pers;
+ client_respawn_t resp;
+ pmove_state_t old_pmove; // for detecting out-of-pmove changes
+ qboolean showscores; // set layout stat
+ qboolean showinventory; // set layout stat
+ qboolean showhelp;
+ qboolean showhelpicon;
+ int ammo_index;
+ int buttons;
+ int oldbuttons;
+ int latched_buttons;
+ qboolean weapon_thunk;
+ gitem_t *newweapon;
- void (*RunFrame) (void);
+ /* sum up damage over an entire frame, so shotgun blasts give a single
+ * big kick */
+ int damage_armor; // damage absorbed by armor
+ int damage_parmor; // damage absorbed by power armor
+ int damage_blood; // damage taken out of health
+ int damage_knockback; // impact damage
+ vec3_t damage_from; // origin for vector calculation
+ float killer_yaw; // when dead, look at killer
+ weaponstate_t weaponstate;
+ vec3_t kick_angles; // weapon kicks
+ vec3_t kick_origin;
+ float v_dmg_roll; // damage kicks
+ float v_dmg_pitch;
+ float v_dmg_time;
+ float fall_time; // for view drop on fall
+ float fall_value;
+ float damage_alpha;
+ float bonus_alpha;
+ vec3_t damage_blend;
+ vec3_t v_angle; // aiming direction so off-ground doesn't change it
+ float bobtime;
+ vec3_t oldviewangles;
+ vec3_t oldvelocity;
+ float next_drown_time;
+ int old_waterlevel;
+ int breather_sound;
+ int machinegun_shots; // for weapon raising
+ int anim_end;
+ int anim_priority;
+ qboolean anim_duck;
+ qboolean anim_run;
+ /* powerup timers */
+ float quad_framenum;
+ float invincible_framenum;
+ float breather_framenum;
+ float enviro_framenum;
+ qboolean grenade_blew_up;
+ float grenade_time;
+ int silencer_shots;
+ int weapon_sound;
+ float pickup_msg_time;
+ float flood_locktill; // locked from talking
+ float flood_when[10]; // when messages were said
+ int flood_whenhead; // head pointer for when said
+ float respawn_time; // can respawn when time > this
+ edict_t *chase_target; // player we are chasing
+ qboolean update_chase; // need to update chase info?
+};
+struct edict_t{
+ entity_state_t s;
+ gclient_t *client; // nil if not a player
+ qboolean inuse;
+ int linkcount;
+ // FIXME: move these fields to a server private sv_entity_t
+ link_t area; // linked to a division node or leaf
+ int num_clusters; // if -1, use headnode instead
+ int clusternums[MAX_ENT_CLUSTERS];
+ int headnode; // unused if num_clusters != -1
+ int areanum;
+ int areanum2;
+ int svflags; // SCF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc.
+ vec3_t mins;
+ vec3_t maxs;
+ vec3_t absmin;
+ vec3_t absmax;
+ vec3_t size;
+ solid_t solid;
+ int clipmask;
+ edict_t *owner;
- // ServerCommand will be called when an "sv <command>" command is issued on the
- // server console.
- // The game can issue gi.argc() / gi.argv() commands to get the rest
- // of the parameters
- void (*ServerCommand) (void);
+ /* DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER EXPECTS THE FIELDS IN
+ * THAT ORDER! */
- //
- // global variables shared between game and server
- //
+ int movetype;
+ int flags;
+ char *model;
+ float freetime; // sv.time when the object was freed
+ /* only used locally in game, not by server */
+ char *message;
+ char *classname;
+ int spawnflags;
+ float timestamp;
+ float angle; // set in qe3, -1 = up, -2 = down
+ char *target;
+ char *targetname;
+ char *killtarget;
+ char *team;
+ char *pathtarget;
+ char *deathtarget;
+ char *combattarget;
+ edict_t *target_ent;
+ float speed;
+ float accel;
+ float decel;
+ vec3_t movedir;
+ vec3_t pos1;
+ vec3_t pos2;
+ vec3_t velocity;
+ vec3_t avelocity;
+ int mass;
+ float air_finished;
+ /* per entity gravity multiplier (1.0 is normal); use for lowgrav
+ * artifact, flares */
+ float gravity;
+ edict_t *goalentity;
+ edict_t *movetarget;
+ float yaw_speed;
+ float ideal_yaw;
+ float nextthink;
+ void (*prethink)(edict_t *);
+ void (*think)(edict_t *);
+ void (*blocked)(edict_t *, edict_t *); //move to moveinfo?
+ void (*touch)(edict_t *, edict_t *, cplane_t *, csurface_t *);
+ void (*use)(edict_t *, edict_t *, edict_t *);
+ void (*pain)(edict_t *, edict_t *, float, int);
+ void (*die)(edict_t *, edict_t *, edict_t *, int, vec3_t);
+ float touch_debounce_time; // are all these legit? do we need more/less of them?
+ float pain_debounce_time;
+ float damage_debounce_time;
+ float fly_sound_debounce_time; //move to clientinfo
+ float last_move_time;
+ int health;
+ int max_health;
+ int gib_health;
+ int deadflag;
+ qboolean show_hostile;
+ float powerarmor_time;
+ char *map; // target_changelevel
+ int viewheight; // height above origin where eyesight is determined
+ int takedamage;
+ int dmg;
+ int radius_dmg;
+ float dmg_radius;
+ int sounds; //make this a spawntemp var?
+ int count;
+ edict_t *chain;
+ edict_t *enemy;
+ edict_t *oldenemy;
+ edict_t *activator;
+ edict_t *groundentity;
+ int groundentity_linkcount;
+ edict_t *teamchain;
+ edict_t *teammaster;
+ edict_t *mynoise; // can go in client only
+ edict_t *mynoise2;
+ int noise_index;
+ int noise_index2;
+ float volume;
+ float attenuation;
+ /* timing variables */
+ float wait;
+ float delay; // before firing targets
+ float random;
+ float teleport_time;
+ int watertype;
+ int waterlevel;
+ vec3_t move_origin;
+ vec3_t move_angles;
+ /* move this to clientinfo? */
+ int light_level;
+ int style; // also used as areaportal number
+ gitem_t *item; // for bonus items
+ /* common data blocks */
+ moveinfo_t moveinfo;
+ monsterinfo_t monsterinfo;
+};
+extern edict_t *g_edicts;
- // The edict array is allocated in the game dll so it
- // can vary in size from one game to another.
- //
- // The size will be fixed when ge->Init() is called
- edict_t *edicts;
- int edict_size;
- int num_edicts; // current number, <= max_edicts
- int max_edicts;
-} game_export_t;
+#define WORLD (&g_edicts[0])
-game_export_t *GetGameAPI (game_import_t *import);
+#define ITEM_INDEX(x) ((x)-itemlist)
+#define FOFS(x) (uintptr)&(((edict_t *)0)->x)
+#define STOFS(x) (uintptr)&(((spawn_temp_t *)0)->x)
+#define LLOFS(x) (uintptr)&(((level_locals_t *)0)->x)
+#define CLOFS(x) (uintptr)&(((gclient_t *)0)->x)
+#define qrandom() ((rand () & 0x7fff) / ((float)0x7fff)) /* >_< arrrrggghh */
+#define crandom() (2.0 * (qrandom() - 0.5))
+
+void Cmd_Help_f(edict_t *);
+void Cmd_Score_f(edict_t *);
+void PrecacheItem(gitem_t *);
+void InitItems(void);
+void SetItemNames(void);
+gitem_t* FindItem(char *);
+gitem_t* FindItemByClassname(char *);
+edict_t* Drop_Item(edict_t *, gitem_t *);
+void SetRespawn(edict_t *, float);
+void ChangeWeapon(edict_t *);
+void SpawnItem(edict_t *, gitem_t *);
+void Think_Weapon(edict_t *);
+int ArmorIndex(edict_t *);
+int PowerArmorType(edict_t *);
+gitem_t* GetItemByIndex(int);
+qboolean Add_Ammo(edict_t *, gitem_t *, int);
+void Touch_Item(edict_t *, edict_t *, cplane_t *, csurface_t *);
+qboolean KillBox(edict_t *);
+void G_ProjectSource(vec3_t, vec3_t, vec3_t, vec3_t, vec3_t);
+edict_t* G_Find(edict_t *, int, char *);
+edict_t* findradius(edict_t *, vec3_t, float);
+edict_t* G_PickTarget(char *);
+void G_UseTargets(edict_t *, edict_t *);
+void G_SetMovedir(vec3_t, vec3_t);
+void G_InitEdict(edict_t *);
+edict_t* G_Spawn(void);
+void G_FreeEdict(edict_t *);
+void G_TouchTriggers(edict_t *);
+void G_TouchSolids(edict_t *);
+char* G_CopyString(char *);
+float* tv(float, float, float);
+char* vtos(vec3_t);
+float vectoyaw(vec3_t);
+void vectoangles(vec3_t, vec3_t);
+qboolean OnSameTeam(edict_t *, edict_t *);
+qboolean CanDamage(edict_t *, edict_t *);
+void T_Damage(edict_t *, edict_t *, edict_t *, vec3_t, vec3_t, vec3_t, int, int, int, int);
+void T_RadiusDamage(edict_t *, edict_t *, float, edict_t *, float, int);
+void monster_fire_bullet(edict_t *, vec3_t, vec3_t, int, int, int, int, int);
+void monster_fire_shotgun(edict_t *, vec3_t, vec3_t, int, int, int, int, int, int);
+void monster_fire_blaster(edict_t *, vec3_t, vec3_t, int, int, int, int);
+void monster_fire_grenade(edict_t *, vec3_t, vec3_t, int, int, int);
+void monster_fire_rocket(edict_t *, vec3_t, vec3_t, int, int, int);
+void monster_fire_railgun(edict_t *, vec3_t, vec3_t, int, int, int);
+void monster_fire_bfg(edict_t *, vec3_t, vec3_t, int, int, int, float, int);
+void M_droptofloor(edict_t *);
+void monster_think(edict_t *);
+void walkmonster_start(edict_t *);
+void swimmonster_start(edict_t *);
+void flymonster_start(edict_t *);
+void AttackFinished(edict_t *, float);
+void monster_death_use(edict_t *);
+void M_CatagorizePosition(edict_t *);
+qboolean M_CheckAttack(edict_t *);
+void M_FlyCheck(edict_t *);
+void M_CheckGround(edict_t *);
+void ThrowHead(edict_t *, char *, int, int);
+void ThrowClientHead(edict_t *, int);
+void ThrowGib(edict_t *, char *, int, int);
+void BecomeExplosion1(edict_t *);
+void AI_SetSightClient(void);
+void ai_stand(edict_t *, float);
+void ai_move(edict_t *, float);
+void ai_walk(edict_t *, float);
+void ai_turn(edict_t *, float);
+void ai_run(edict_t *, float);
+void ai_charge(edict_t *, float);
+int range(edict_t *, edict_t *);
+void FoundTarget(edict_t *);
+qboolean infront(edict_t *, edict_t *);
+qboolean visible(edict_t *, edict_t *);
+qboolean FacingIdeal(edict_t *);
+void ThrowDebris(edict_t *, char *, float, vec3_t);
+qboolean fire_hit(edict_t *, vec3_t, int, int);
+void fire_bullet(edict_t *, vec3_t, vec3_t, int, int, int, int, int);
+void fire_shotgun(edict_t *, vec3_t, vec3_t, int, int, int, int, int, int);
+void fire_blaster(edict_t *, vec3_t, vec3_t, int, int, int, qboolean);
+void fire_grenade(edict_t *, vec3_t, vec3_t, int, int, float, float);
+void fire_grenade2(edict_t *, vec3_t, vec3_t, int, int, float, float, qboolean);
+void fire_rocket(edict_t *, vec3_t, vec3_t, int, int, float, int);
+void fire_rail(edict_t *, vec3_t, vec3_t, int, int);
+void fire_bfg(edict_t *, vec3_t, vec3_t, int, int, float);
+void PlayerTrail_Init(void);
+void PlayerTrail_Add(vec3_t);
+void PlayerTrail_New(vec3_t);
+edict_t* PlayerTrail_PickFirst(edict_t *);
+edict_t* PlayerTrail_PickNext(edict_t *);
+edict_t* PlayerTrail_LastSpot(void);
+void respawn(edict_t *);
+void BeginIntermission(edict_t *);
+void PutClientInServer(edict_t *);
+void InitClientPersistant(gclient_t *);
+void InitClientResp(gclient_t *);
+void InitBodyQue(void);
+void ClientBeginServerFrame(edict_t *);
+void player_pain(edict_t *, edict_t *, float, int);
+void player_die(edict_t *, edict_t *, edict_t *, int, vec3_t);
+void ServerCommand(void);
+qboolean SV_FilterPacket(char *);
+void ClientEndServerFrame(edict_t *);
+void MoveClientToIntermission(edict_t *);
+void G_SetStats(edict_t *);
+void G_SetSpectatorStats(edict_t *);
+void G_CheckChaseStats(edict_t *);
+void ValidateSelectedItem(edict_t *);
+void DeathmatchScoreboardMessage(edict_t *, edict_t *);
+void PlayerNoise(edict_t *, vec3_t, int);
+qboolean M_CheckBottom(edict_t *);
+qboolean M_walkmove(edict_t *, float, float);
+void M_MoveToGoal(edict_t *, float);
+void M_ChangeYaw(edict_t *);
+void G_RunEntity(edict_t *);
+void SaveClientData(void);
+void FetchClientEntData(edict_t *);
+void UpdateChaseCam(edict_t *);
+void ChaseNext(edict_t *);
+void ChasePrev(edict_t *);
+void GetChaseTarget(edict_t *);
--- a/game/m_actor.c
+++ b/game/m_actor.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_actor.h"
#define MAX_ACTOR_NAMES 8
--- a/game/m_berserk.c
+++ b/game/m_berserk.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_berserk.h"
--- a/game/m_boss2.c
+++ b/game/m_boss2.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_boss2.h"
void BossExplode (edict_t *self);
--- a/game/m_boss3.c
+++ b/game/m_boss3.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_boss32.h"
void Use_Boss3 (edict_t *ent, edict_t */*other*/, edict_t */*activator*/)
--- a/game/m_boss31.c
+++ b/game/m_boss31.c
@@ -3,7 +3,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_boss31.h"
extern SP_monster_makron (edict_t *self);
--- a/game/m_boss32.c
+++ b/game/m_boss32.c
@@ -3,7 +3,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_boss32.h"
qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_brain.c
+++ b/game/m_brain.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_brain.h"
--- a/game/m_chick.c
+++ b/game/m_chick.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_chick.h"
qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_flash.c
+++ b/game/m_flash.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
// this file is included in both the game dll and quake2,
// the game needs it to source shot locations, the client
--- a/game/m_flipper.c
+++ b/game/m_flipper.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_flipper.h"
--- a/game/m_float.c
+++ b/game/m_float.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_float.h"
--- a/game/m_flyer.c
+++ b/game/m_flyer.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_flyer.h"
qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_gladiator.c
+++ b/game/m_gladiator.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_gladiator.h"
--- a/game/m_gunner.c
+++ b/game/m_gunner.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_gunner.h"
--- a/game/m_hover.c
+++ b/game/m_hover.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_hover.h"
qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_infantry.c
+++ b/game/m_infantry.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_infantry.h"
void InfantryMachineGun (edict_t *self);
--- a/game/m_insane.c
+++ b/game/m_insane.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_insane.h"
--- a/game/m_medic.c
+++ b/game/m_medic.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_medic.h"
qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_move.c
+++ b/game/m_move.c
@@ -3,7 +3,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#define STEPSIZE 18
--- a/game/m_mutant.c
+++ b/game/m_mutant.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_mutant.h"
--- a/game/m_parasite.c
+++ b/game/m_parasite.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_parasite.h"
--- a/game/m_soldier.c
+++ b/game/m_soldier.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_soldier.h"
--- a/game/m_supertank.c
+++ b/game/m_supertank.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_supertank.h"
qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_tank.c
+++ b/game/m_tank.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_tank.h"
--- a/game/p_client.c
+++ b/game/p_client.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_player.h"
void ClientUserinfoChanged (edict_t *ent, char *userinfo);
--- a/game/p_hud.c
+++ b/game/p_hud.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*
======================================================================
--- a/game/p_trail.c
+++ b/game/p_trail.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*
--- a/game/p_view.c
+++ b/game/p_view.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_player.h"
--- a/game/p_weapon.c
+++ b/game/p_weapon.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_player.h"
--- a/game/q_shared.c
+++ b/game/q_shared.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#define DEG2RAD( a ) ( a * M_PI ) / 180.0F
@@ -251,7 +252,7 @@
// this is the slow, general version
-int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, cplane_t *p)
{
int i;
float dist1, dist2;
@@ -289,7 +290,7 @@
Returns 1, 2, or 1 + 2
==================
*/
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, cplane_t *p)
{
float dist1, dist2;
int sides;
--- /dev/null
+++ b/in.c
@@ -1,0 +1,455 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <draw.h>
+#include <thread.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include "dat.h"
+#include "fns.h"
+
+extern int resized; /* vid.c */
+extern Point center;
+extern Channel *fuckchan, *tchan; /* sys.c */
+
+cvar_t *in_joystick;
+cvar_t *sensitivity;
+cvar_t *lookstrafe;
+cvar_t *lookspring;
+cvar_t *freelook;
+cvar_t *m_pitch;
+
+static cvar_t *m_filter;
+static cvar_t *m_windowed;
+static cvar_t *m_yaw;
+static cvar_t *m_side;
+static cvar_t *m_forward;
+
+static int mouseon;
+static int mlooking;
+static int dx, dy;
+static int oldmwin;
+
+typedef struct Kev Kev;
+struct Kev{
+ int key;
+ int down;
+};
+enum{
+ Nbuf = 64
+};
+static Channel *kchan, *mchan;
+static int iop = -1, pfd[2];
+static QLock killock;
+
+
+char *
+Sys_ConsoleInput(void)
+{
+ static char buf[256];
+ int n;
+
+ if(dedicated != nil && dedicated->value && iop >= 0){
+ if(flen(pfd[1]) < 1) /* only poll for input */
+ return nil;
+ if((n = read(pfd[1], buf, sizeof buf)) < 0)
+ sysfatal("Sys_ConsoleInput:read: %r");
+ if(n == 0){
+ iop = -1;
+ return nil;
+ }
+ return buf;
+ }
+ return nil;
+}
+
+void
+IN_Grabm(int on)
+{
+ static char nocurs[2*4+2*2*16];
+ static int fd = -1;
+
+ if(mouseon == on)
+ return;
+ if(mouseon = on && m_windowed->value){
+ if((fd = open("/dev/cursor", ORDWR|OCEXEC)) < 0){
+ sysfatal("IN_Grabm:open: %r\n");
+ return;
+ }
+ write(fd, nocurs, sizeof nocurs);
+ }else if(fd >= 0){
+ close(fd);
+ fd = -1;
+ }
+}
+
+void
+IN_Commands(void)
+{
+ /* joystick stuff */
+}
+
+void
+btnev(int btn, ulong msec)
+{
+ static int oldb;
+ int i, b;
+
+ for(i = 0; i < 3; i++){
+ b = 1<<i;
+ if(btn & b && ~oldb & b)
+ Key_Event(K_MOUSE1+i, true, msec);
+ else if(~btn & b && oldb & b)
+ Key_Event(K_MOUSE1+i, false, msec);
+ }
+ oldb = btn;
+ /* mwheelup and mwheeldn buttons are never held down */
+ for(i = 3; i < 5; i++){
+ b = 1<<i;
+ if(btn & b){
+ Key_Event(K_MOUSE1+i, true, msec);
+ Key_Event(K_MOUSE1+i, false, msec);
+ }
+ }
+}
+
+void
+KBD_Update(void)
+{
+ int r;
+ Kev ev;
+ Mouse m;
+
+ if(oldmwin != m_windowed->value){
+ oldmwin = m_windowed->value;
+ IN_Grabm(m_windowed->value);
+ }
+ while((r = nbrecv(kchan, &ev)) > 0)
+ Key_Event(ev.key, ev.down, Sys_Milliseconds());
+ if(r < 0)
+ sysfatal("KBD_Update:nbrecv: %r\n");
+ while((r = nbrecv(mchan, &m)) > 0){
+ dx += m.xy.x;
+ dy += m.xy.y;
+ btnev(m.buttons, m.msec);
+ }
+ if(r < 0)
+ sysfatal("KBD_Update:nbrecv: %r\n");
+}
+
+void
+IN_Move(usercmd_t *cmd)
+{
+ static int oldmx, oldmy;
+ int mx, my;
+
+ if(!mouseon)
+ return;
+
+ if(m_filter->value){
+ mx = (dx + oldmx) * 0.5;
+ my = (dy + oldmy) * 0.5;
+ }else{
+ mx = dx;
+ my = dy;
+ }
+ oldmx = dx;
+ oldmy = dy;
+ dx = dy = 0;
+ if(!mx && !my)
+ return;
+ mx *= sensitivity->value;
+ my *= sensitivity->value;
+
+ /* add mouse x/y movement to cmd */
+ if(in_strafe.state & 1 || lookstrafe->value && mlooking)
+ cmd->sidemove += m_side->value * mx;
+ else
+ cl.viewangles[YAW] -= m_yaw->value * mx;
+ if((mlooking || freelook->value) && ~in_strafe.state & 1)
+ cl.viewangles[PITCH] += m_pitch->value * my;
+ else
+ cmd->forwardmove -= m_forward->value * my;
+}
+
+/* called on focus/unfocus in win32 */
+void
+IN_Activate(qboolean)
+{
+}
+
+/* called every frame even if not generating commands */
+void
+IN_Frame(void)
+{
+}
+
+void
+IN_ForceCenterView(void)
+{
+ cl.viewangles[PITCH] = 0;
+}
+
+void
+IN_MLookDown(void)
+{
+ mlooking = true;
+}
+
+void
+IN_MLookUp(void)
+{
+ mlooking = false;
+ IN_CenterView();
+}
+
+static int
+runetokey(Rune r)
+{
+ int k = 0;
+
+ switch(r){
+ case Kpgup: k = K_PGUP; break;
+ case Kpgdown: k = K_PGDN; break;
+ case Khome: k = K_HOME; break;
+ case Kend: k = K_END; break;
+ case Kleft: k = K_LEFTARROW; break;
+ case Kright: k = K_RIGHTARROW; break;
+ case Kdown: k = K_DOWNARROW; break;
+ case Kup: k = K_UPARROW; break;
+ case Kesc: k = K_ESCAPE; break;
+ case '\n': k = K_ENTER; break;
+ case '\t': k = K_TAB; break;
+ case KF|1: k = K_F1; break;
+ case KF|2: k = K_F2; break;
+ case KF|3: k = K_F3; break;
+ case KF|4: k = K_F4; break;
+ case KF|5: k = K_F5; break;
+ case KF|6: k = K_F6; break;
+ case KF|7: k = K_F7; break;
+ case KF|8: k = K_F8; break;
+ case KF|9: k = K_F9; break;
+ case KF|10: k = K_F10; break;
+ case KF|11: k = K_F11; break;
+ case KF|12: k = K_F12; break;
+ case Kbs: k = K_BACKSPACE; break;
+ case Kdel: k = K_DEL; break;
+ case Kbreak: k = K_PAUSE; break;
+ case Kshift: k = K_SHIFT; break;
+ case Kctl: k = K_CTRL; break;
+ case Kalt:
+ case Kaltgr: k = K_ALT; break;
+ case Kins: k = K_INS; break;
+ default:
+ if(r < 0x80)
+ k = r;
+ };
+ return k;
+}
+
+static void
+kproc(void *)
+{
+ int n, k, fd;
+ char buf[128], kdown[128], *s;
+ Rune r;
+ Kev ev;
+
+ if(threadsetgrp(THin) < 0)
+ sysfatal("kproc:threadsetgrp: %r");
+ if((fd = open("/dev/kbd", OREAD)) < 0)
+ sysfatal("open /dev/kbd: %r");
+
+ kdown[0] = kdown[1] = 0;
+ while((n = read(fd, buf, sizeof buf)) > 0){
+ buf[n-1] = 0;
+ switch(*buf){
+ case 'c':
+ default:
+ continue;
+ case 'k':
+ s = buf+1;
+ while(*s){
+ s += chartorune(&r, s);
+ if(utfrune(kdown+1, r) == nil){
+ if(k = runetokey(r)){
+ ev.key = k;
+ ev.down = true;
+ if(send(kchan, &ev) < 0)
+ sysfatal("kproc:nbsend: %r\n");
+ }
+ }
+ }
+ break;
+ case 'K':
+ s = kdown+1;
+ while(*s){
+ s += chartorune(&r, s);
+ if(utfrune(buf+1, r) == nil){
+ if(k = runetokey(r)){
+ ev.key = k;
+ ev.down = false;
+ if(send(kchan, &ev) < 0)
+ sysfatal("mproc:nbsend: %r\n");
+ }
+ }
+ }
+ break;
+ }
+ strcpy(kdown, buf);
+ }
+ fprint(2, "kproc: %r\n");
+ close(fd);
+}
+
+static void
+mproc(void *)
+{
+ int n, nerr = 0, fd;
+ char buf[1+5*12];
+ Mouse m;
+
+ if(threadsetgrp(THin) < 0)
+ sysfatal("mproc:threadsetgrp: %r");
+ if((fd = open("/dev/mouse", ORDWR)) < 0)
+ sysfatal("open /dev/mouse: %r");
+
+ for(;;){
+ if((n = read(fd, buf, sizeof buf)) != 1+4*12){
+ fprint(2, "mproc:read: bad count %d not 49: %r\n", n);
+ if(n < 0 || ++nerr > 10)
+ break;
+ continue;
+ }
+ nerr = 0;
+ switch(*buf){
+ case 'r':
+ resized = 1;
+ /* fall through */
+ case 'm':
+ if(!mouseon)
+ break;
+
+ m.xy.x = atoi(buf+1+0*12) - center.x;
+ m.xy.y = atoi(buf+1+1*12) - center.y;
+ if(m.xy.x != 0 || m.xy.y != 0)
+ fprint(fd, "m%d %d", center.x, center.y);
+ m.buttons = atoi(buf+1+2*12);
+ m.msec = atoi(buf+1+3*12);
+ if(nbsend(mchan, &m) < 0)
+ sysfatal("mproc:nbsend: %r\n");
+ break;
+ }
+ }
+ fprint(2, "mproc: %r\n");
+ IN_Grabm(0);
+ close(fd);
+}
+
+static void
+tproc(void *) /* stupid select() timeout bullshit */
+{
+ int t, ms, n, r;
+
+ threadsetgrp(THin);
+
+ t = ms = 0;
+ for(;;){
+ sleep(1);
+ t++;
+
+ if((r = nbrecv(tchan, &n)) < 0)
+ sysfatal("tproc:nbrecv: %r");
+ if(r == 0){
+ if(t == ms && nbsend(fuckchan, nil) < 0)
+ sysfatal("tproc:nbsend: %r");
+ continue;
+ }
+ if(n <= 0)
+ ms = 0;
+ else{
+ ms = n;
+ t = 0;
+ }
+ }
+}
+
+static void
+iproc(void *)
+{
+ int n;
+ char s[256];
+
+ threadsetgrp(THin);
+
+ if((iop = pipe(pfd)) < 0)
+ sysfatal("iproc:pipe: %r");
+ for(;;){
+ if((n = read(0, s, sizeof s)) <= 0)
+ break;
+ s[n-1] = 0;
+ if((write(pfd[0], s, n)) != n)
+ break;
+ if(nbsend(fuckchan, nil) < 0)
+ sysfatal("iproc:nbsend: %r");
+ }
+ fprint(2, "iproc %d: %r\n", threadpid(threadid()));
+ iop = -1;
+}
+
+void
+IN_Shutdown(void)
+{
+ qlock(&killock); /* there can be only one */
+ IN_Grabm(0);
+ threadkillgrp(THin);
+ iop = -1;
+ close(pfd[0]);
+ close(pfd[1]);
+ if(kchan != nil){
+ chanfree(kchan);
+ kchan = nil;
+ }
+ if(mchan != nil){
+ chanfree(mchan);
+ mchan = nil;
+ }
+ qunlock(&killock);
+}
+
+void
+IN_Init(void)
+{
+ if(dedicated->value){
+ if(proccreate(iproc, nil, 8192) < 0)
+ sysfatal("proccreate iproc: %r");
+ if(proccreate(tproc, nil, 8192) < 0)
+ sysfatal("proccreate tproc: %r");
+ return;
+ }
+ in_joystick = Cvar_Get("in_joystick", "0", CVAR_ARCHIVE);
+ sensitivity = Cvar_Get("sensitivity", "3", CVAR_ARCHIVE);
+ freelook = Cvar_Get("freelook", "0", CVAR_ARCHIVE);
+ lookspring = Cvar_Get("lookspring", "0", CVAR_ARCHIVE);
+ lookstrafe = Cvar_Get("lookstrafe", "0", CVAR_ARCHIVE);
+ m_pitch = Cvar_Get("m_pitch", "0.022", CVAR_ARCHIVE);
+
+ m_yaw = Cvar_Get("m_yaw", "0.022", 0);
+ m_forward = Cvar_Get("m_forward", "1", 0);
+ m_side = Cvar_Get("m_side", "0.8", 0);
+ m_windowed = Cvar_Get("m_windowed", "0", CVAR_ARCHIVE);
+ m_filter = Cvar_Get("m_filter", "0", 0);
+
+ Cmd_AddCommand("+mlook", IN_MLookDown);
+ Cmd_AddCommand("-mlook", IN_MLookUp);
+ Cmd_AddCommand("force_centerview", IN_ForceCenterView);
+
+ if((kchan = chancreate(sizeof(Kev), Nbuf)) == nil)
+ sysfatal("chancreate kchan: %r");
+ if(proccreate(kproc, nil, 8192) < 0)
+ sysfatal("proccreate kproc: %r");
+ if((mchan = chancreate(sizeof(Mouse), Nbuf)) == nil)
+ sysfatal("chancreate kchan: %r");
+ if(proccreate(mproc, nil, 8192) < 0)
+ sysfatal("proccreate mproc: %r");
+}
--- /dev/null
+++ b/keys.c
@@ -1,0 +1,928 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+
+key up events are sent even if in console mode
+
+*/
+
+
+#define MAXCMDLINE 256
+char key_lines[32][MAXCMDLINE];
+int key_linepos;
+int shift_down=false;
+int anykeydown;
+
+int edit_line=0;
+int history_line=0;
+
+int key_waiting;
+char *keybindings[256];
+qboolean consolekeys[256]; // if true, can't be rebound while in console
+qboolean menubound[256]; // if true, can't be rebound while in menu
+int keyshift[256]; // key to map to if shift held down in console
+int key_repeats[256]; // if > 1, it is autorepeating
+qboolean keydown[256];
+
+typedef struct
+{
+ char *name;
+ int keynum;
+} keyname_t;
+
+keyname_t keynames[] =
+{
+ {"TAB", K_TAB},
+ {"ENTER", K_ENTER},
+ {"ESCAPE", K_ESCAPE},
+ {"SPACE", K_SPACE},
+ {"BACKSPACE", K_BACKSPACE},
+ {"UPARROW", K_UPARROW},
+ {"DOWNARROW", K_DOWNARROW},
+ {"LEFTARROW", K_LEFTARROW},
+ {"RIGHTARROW", K_RIGHTARROW},
+
+ {"ALT", K_ALT},
+ {"CTRL", K_CTRL},
+ {"SHIFT", K_SHIFT},
+
+ {"F1", K_F1},
+ {"F2", K_F2},
+ {"F3", K_F3},
+ {"F4", K_F4},
+ {"F5", K_F5},
+ {"F6", K_F6},
+ {"F7", K_F7},
+ {"F8", K_F8},
+ {"F9", K_F9},
+ {"F10", K_F10},
+ {"F11", K_F11},
+ {"F12", K_F12},
+
+ {"INS", K_INS},
+ {"DEL", K_DEL},
+ {"PGDN", K_PGDN},
+ {"PGUP", K_PGUP},
+ {"HOME", K_HOME},
+ {"END", K_END},
+
+ {"MOUSE1", K_MOUSE1},
+ {"MOUSE2", K_MOUSE2},
+ {"MOUSE3", K_MOUSE3},
+
+ {"JOY1", K_JOY1},
+ {"JOY2", K_JOY2},
+ {"JOY3", K_JOY3},
+ {"JOY4", K_JOY4},
+
+ {"AUX1", K_AUX1},
+ {"AUX2", K_AUX2},
+ {"AUX3", K_AUX3},
+ {"AUX4", K_AUX4},
+ {"AUX5", K_AUX5},
+ {"AUX6", K_AUX6},
+ {"AUX7", K_AUX7},
+ {"AUX8", K_AUX8},
+ {"AUX9", K_AUX9},
+ {"AUX10", K_AUX10},
+ {"AUX11", K_AUX11},
+ {"AUX12", K_AUX12},
+ {"AUX13", K_AUX13},
+ {"AUX14", K_AUX14},
+ {"AUX15", K_AUX15},
+ {"AUX16", K_AUX16},
+ {"AUX17", K_AUX17},
+ {"AUX18", K_AUX18},
+ {"AUX19", K_AUX19},
+ {"AUX20", K_AUX20},
+ {"AUX21", K_AUX21},
+ {"AUX22", K_AUX22},
+ {"AUX23", K_AUX23},
+ {"AUX24", K_AUX24},
+ {"AUX25", K_AUX25},
+ {"AUX26", K_AUX26},
+ {"AUX27", K_AUX27},
+ {"AUX28", K_AUX28},
+ {"AUX29", K_AUX29},
+ {"AUX30", K_AUX30},
+ {"AUX31", K_AUX31},
+ {"AUX32", K_AUX32},
+
+ {"KP_HOME", K_KP_HOME },
+ {"KP_UPARROW", K_KP_UPARROW },
+ {"KP_PGUP", K_KP_PGUP },
+ {"KP_LEFTARROW", K_KP_LEFTARROW },
+ {"KP_5", K_KP_5 },
+ {"KP_RIGHTARROW", K_KP_RIGHTARROW },
+ {"KP_END", K_KP_END },
+ {"KP_DOWNARROW", K_KP_DOWNARROW },
+ {"KP_PGDN", K_KP_PGDN },
+ {"KP_ENTER", K_KP_ENTER },
+ {"KP_INS", K_KP_INS },
+ {"KP_DEL", K_KP_DEL },
+ {"KP_SLASH", K_KP_SLASH },
+ {"KP_MINUS", K_KP_MINUS },
+ {"KP_PLUS", K_KP_PLUS },
+
+ {"MWHEELUP", K_MWHEELUP },
+ {"MWHEELDOWN", K_MWHEELDOWN },
+
+ {"PAUSE", K_PAUSE},
+
+ {"SEMICOLON", ';'}, // because a raw semicolon seperates commands
+
+ {NULL,0}
+};
+
+/*
+==============================================================================
+
+ LINE TYPING INTO THE CONSOLE
+
+==============================================================================
+*/
+
+void CompleteCommand (void)
+{
+ char *cmd, *s;
+
+ s = key_lines[edit_line]+1;
+ if (*s == '\\' || *s == '/')
+ s++;
+
+ cmd = Cmd_CompleteCommand (s);
+ if (!cmd)
+ cmd = Cvar_CompleteVariable (s);
+ if (cmd)
+ {
+ key_lines[edit_line][1] = '/';
+ strcpy (key_lines[edit_line]+2, cmd);
+ key_linepos = strlen(cmd)+2;
+ key_lines[edit_line][key_linepos] = ' ';
+ key_linepos++;
+ key_lines[edit_line][key_linepos] = 0;
+ return;
+ }
+}
+
+/*
+====================
+Key_Console
+
+Interactive line editing and console scrollback
+====================
+*/
+void Key_Console (int key)
+{
+
+ switch ( key )
+ {
+ case K_KP_SLASH:
+ key = '/';
+ break;
+ case K_KP_MINUS:
+ key = '-';
+ break;
+ case K_KP_PLUS:
+ key = '+';
+ break;
+ case K_KP_HOME:
+ key = '7';
+ break;
+ case K_KP_UPARROW:
+ key = '8';
+ break;
+ case K_KP_PGUP:
+ key = '9';
+ break;
+ case K_KP_LEFTARROW:
+ key = '4';
+ break;
+ case K_KP_5:
+ key = '5';
+ break;
+ case K_KP_RIGHTARROW:
+ key = '6';
+ break;
+ case K_KP_END:
+ key = '1';
+ break;
+ case K_KP_DOWNARROW:
+ key = '2';
+ break;
+ case K_KP_PGDN:
+ key = '3';
+ break;
+ case K_KP_INS:
+ key = '0';
+ break;
+ case K_KP_DEL:
+ key = '.';
+ break;
+ }
+
+ if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
+ ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
+ {
+ char *cbd;
+
+ if ( ( cbd = Sys_GetClipboardData() ) != 0 )
+ {
+ int i;
+
+ strtok( cbd, "\n\r\b" );
+
+ i = strlen( cbd );
+ if ( i + key_linepos >= MAXCMDLINE)
+ i= MAXCMDLINE - key_linepos;
+
+ if ( i > 0 )
+ {
+ cbd[i]=0;
+ strcat( key_lines[edit_line], cbd );
+ key_linepos += i;
+ }
+ free( cbd );
+ }
+
+ return;
+ }
+
+ if ( key == 'l' )
+ {
+ if ( keydown[K_CTRL] )
+ {
+ Cbuf_AddText ("clear\n");
+ return;
+ }
+ }
+
+ if ( key == K_ENTER || key == K_KP_ENTER )
+ { // backslash text are commands, else chat
+ if (key_lines[edit_line][1] == '\\' || key_lines[edit_line][1] == '/')
+ Cbuf_AddText (key_lines[edit_line]+2); // skip the >
+ else
+ Cbuf_AddText (key_lines[edit_line]+1); // valid command
+
+ Cbuf_AddText ("\n");
+ Com_Printf ("%s\n",key_lines[edit_line]);
+ edit_line = (edit_line + 1) & 31;
+ history_line = edit_line;
+ key_lines[edit_line][0] = ']';
+ key_linepos = 1;
+ if (cls.state == ca_disconnected)
+ SCR_UpdateScreen (); // force an update, because the command
+ // may take some time
+ return;
+ }
+
+ if (key == K_TAB)
+ { // command completion
+ CompleteCommand ();
+ return;
+ }
+
+ if ( ( key == K_BACKSPACE ) || ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) || ( ( key == 'h' ) && ( keydown[K_CTRL] ) ) )
+ {
+ if (key_linepos > 1)
+ key_linepos--;
+ return;
+ }
+
+ if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
+ ( ( key == 'p' ) && keydown[K_CTRL] ) )
+ {
+ do
+ {
+ history_line = (history_line - 1) & 31;
+ } while (history_line != edit_line
+ && !key_lines[history_line][1]);
+ if (history_line == edit_line)
+ history_line = (edit_line+1)&31;
+ strcpy(key_lines[edit_line], key_lines[history_line]);
+ key_linepos = strlen(key_lines[edit_line]);
+ return;
+ }
+
+ if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
+ ( ( key == 'n' ) && keydown[K_CTRL] ) )
+ {
+ if (history_line == edit_line) return;
+ do
+ {
+ history_line = (history_line + 1) & 31;
+ }
+ while (history_line != edit_line
+ && !key_lines[history_line][1]);
+ if (history_line == edit_line)
+ {
+ key_lines[edit_line][0] = ']';
+ key_linepos = 1;
+ }
+ else
+ {
+ strcpy(key_lines[edit_line], key_lines[history_line]);
+ key_linepos = strlen(key_lines[edit_line]);
+ }
+ return;
+ }
+
+ if (key == K_PGUP || key == K_KP_PGUP )
+ {
+ con.display -= 2;
+ return;
+ }
+
+ if (key == K_PGDN || key == K_KP_PGDN )
+ {
+ con.display += 2;
+ if (con.display > con.current)
+ con.display = con.current;
+ return;
+ }
+
+ if (key == K_HOME || key == K_KP_HOME )
+ {
+ con.display = con.current - con.totallines + 10;
+ return;
+ }
+
+ if (key == K_END || key == K_KP_END )
+ {
+ con.display = con.current;
+ return;
+ }
+
+ if (key < 32 || key > 127)
+ return; // non printable
+
+ if (key_linepos < MAXCMDLINE-1)
+ {
+ key_lines[edit_line][key_linepos] = key;
+ key_linepos++;
+ key_lines[edit_line][key_linepos] = 0;
+ }
+
+}
+
+//============================================================================
+
+qboolean chat_team;
+char chat_buffer[MAXCMDLINE];
+int chat_bufferlen = 0;
+
+void Key_Message (int key)
+{
+
+ if ( key == K_ENTER || key == K_KP_ENTER )
+ {
+ if (chat_team)
+ Cbuf_AddText ("say_team \"");
+ else
+ Cbuf_AddText ("say \"");
+ Cbuf_AddText(chat_buffer);
+ Cbuf_AddText("\"\n");
+
+ cls.key_dest = key_game;
+ chat_bufferlen = 0;
+ chat_buffer[0] = 0;
+ return;
+ }
+
+ if (key == K_ESCAPE)
+ {
+ cls.key_dest = key_game;
+ chat_bufferlen = 0;
+ chat_buffer[0] = 0;
+ return;
+ }
+
+ if (key < 32 || key > 127)
+ return; // non printable
+
+ if (key == K_BACKSPACE)
+ {
+ if (chat_bufferlen)
+ {
+ chat_bufferlen--;
+ chat_buffer[chat_bufferlen] = 0;
+ }
+ return;
+ }
+
+ if (chat_bufferlen == sizeof(chat_buffer)-1)
+ return; // all full
+
+ chat_buffer[chat_bufferlen++] = key;
+ chat_buffer[chat_bufferlen] = 0;
+}
+
+//============================================================================
+
+
+/*
+===================
+Key_StringToKeynum
+
+Returns a key number to be used to index keybindings[] by looking at
+the given string. Single ascii characters return themselves, while
+the K_* names are matched up.
+===================
+*/
+int Key_StringToKeynum (char *str)
+{
+ keyname_t *kn;
+
+ if (!str || !str[0])
+ return -1;
+ if (!str[1])
+ return str[0];
+
+ for (kn=keynames ; kn->name ; kn++)
+ {
+ if (!cistrcmp(str,kn->name))
+ return kn->keynum;
+ }
+ return -1;
+}
+
+/*
+===================
+Key_KeynumToString
+
+Returns a string (either a single ascii char, or a K_* name) for the
+given keynum.
+FIXME: handle quote special (general escape sequence?)
+===================
+*/
+char *Key_KeynumToString (int keynum)
+{
+ keyname_t *kn;
+ static char tinystr[2];
+
+ if (keynum == -1)
+ return "<KEY NOT FOUND>";
+ if (keynum > 32 && keynum < 127)
+ { // printable ascii
+ tinystr[0] = keynum;
+ tinystr[1] = 0;
+ return tinystr;
+ }
+
+ for (kn=keynames ; kn->name ; kn++)
+ if (keynum == kn->keynum)
+ return kn->name;
+
+ return "<UNKNOWN KEYNUM>";
+}
+
+
+/*
+===================
+Key_SetBinding
+===================
+*/
+void Key_SetBinding (int keynum, char *binding)
+{
+ char *new;
+ int l;
+
+ if (keynum == -1)
+ return;
+
+// free old bindings
+ if (keybindings[keynum])
+ {
+ Z_Free (keybindings[keynum]);
+ keybindings[keynum] = NULL;
+ }
+
+// allocate memory for new binding
+ l = strlen (binding);
+ new = Z_Malloc (l+1);
+ strcpy (new, binding);
+ new[l] = 0;
+ keybindings[keynum] = new;
+}
+
+/*
+===================
+Key_Unbind_f
+===================
+*/
+void Key_Unbind_f (void)
+{
+ int b;
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("unbind <key> : remove commands from a key\n");
+ return;
+ }
+
+ b = Key_StringToKeynum (Cmd_Argv(1));
+ if (b==-1)
+ {
+ Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
+ return;
+ }
+
+ Key_SetBinding (b, "");
+}
+
+void Key_Unbindall_f (void)
+{
+ int i;
+
+ for (i=0 ; i<256 ; i++)
+ if (keybindings[i])
+ Key_SetBinding (i, "");
+}
+
+
+/*
+===================
+Key_Bind_f
+===================
+*/
+void Key_Bind_f (void)
+{
+ int i, c, b;
+ char cmd[1024];
+
+ c = Cmd_Argc();
+
+ if (c < 2)
+ {
+ Com_Printf ("bind <key> [command] : attach a command to a key\n");
+ return;
+ }
+ b = Key_StringToKeynum (Cmd_Argv(1));
+ if (b==-1)
+ {
+ Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
+ return;
+ }
+
+ if (c == 2)
+ {
+ if (keybindings[b])
+ Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
+ else
+ Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
+ return;
+ }
+
+// copy the rest of the command line
+ cmd[0] = 0; // start out with a null string
+ for (i=2 ; i< c ; i++)
+ {
+ strcat (cmd, Cmd_Argv(i));
+ if (i != (c-1))
+ strcat (cmd, " ");
+ }
+
+ Key_SetBinding (b, cmd);
+}
+
+/*
+============
+Key_WriteBindings
+
+Writes lines containing "bind key value"
+============
+*/
+void Key_WriteBindings (FILE *f)
+{
+ int i;
+
+ for (i=0 ; i<256 ; i++)
+ if (keybindings[i] && keybindings[i][0])
+ fprintf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
+}
+
+
+/*
+============
+Key_Bindlist_f
+
+============
+*/
+void Key_Bindlist_f (void)
+{
+ int i;
+
+ for (i=0 ; i<256 ; i++)
+ if (keybindings[i] && keybindings[i][0])
+ Com_Printf ("%s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
+}
+
+
+/*
+===================
+Key_Init
+===================
+*/
+void Key_Init (void)
+{
+ int i;
+
+ for (i=0 ; i<32 ; i++)
+ {
+ key_lines[i][0] = ']';
+ key_lines[i][1] = 0;
+ }
+ key_linepos = 1;
+
+//
+// init ascii characters in console mode
+//
+ for (i=32 ; i<128 ; i++)
+ consolekeys[i] = true;
+ consolekeys[K_ENTER] = true;
+ consolekeys[K_KP_ENTER] = true;
+ consolekeys[K_TAB] = true;
+ consolekeys[K_LEFTARROW] = true;
+ consolekeys[K_KP_LEFTARROW] = true;
+ consolekeys[K_RIGHTARROW] = true;
+ consolekeys[K_KP_RIGHTARROW] = true;
+ consolekeys[K_UPARROW] = true;
+ consolekeys[K_KP_UPARROW] = true;
+ consolekeys[K_DOWNARROW] = true;
+ consolekeys[K_KP_DOWNARROW] = true;
+ consolekeys[K_BACKSPACE] = true;
+ consolekeys[K_HOME] = true;
+ consolekeys[K_KP_HOME] = true;
+ consolekeys[K_END] = true;
+ consolekeys[K_KP_END] = true;
+ consolekeys[K_PGUP] = true;
+ consolekeys[K_KP_PGUP] = true;
+ consolekeys[K_PGDN] = true;
+ consolekeys[K_KP_PGDN] = true;
+ consolekeys[K_SHIFT] = true;
+ consolekeys[K_INS] = true;
+ consolekeys[K_KP_INS] = true;
+ consolekeys[K_KP_DEL] = true;
+ consolekeys[K_KP_SLASH] = true;
+ consolekeys[K_KP_PLUS] = true;
+ consolekeys[K_KP_MINUS] = true;
+ consolekeys[K_KP_5] = true;
+
+ consolekeys['`'] = false;
+ consolekeys['~'] = false;
+
+ for (i=0 ; i<256 ; i++)
+ keyshift[i] = i;
+ for (i='a' ; i<='z' ; i++)
+ keyshift[i] = i - 'a' + 'A';
+ keyshift['1'] = '!';
+ keyshift['2'] = '@';
+ keyshift['3'] = '#';
+ keyshift['4'] = '$';
+ keyshift['5'] = '%';
+ keyshift['6'] = '^';
+ keyshift['7'] = '&';
+ keyshift['8'] = '*';
+ keyshift['9'] = '(';
+ keyshift['0'] = ')';
+ keyshift['-'] = '_';
+ keyshift['='] = '+';
+ keyshift[','] = '<';
+ keyshift['.'] = '>';
+ keyshift['/'] = '?';
+ keyshift[';'] = ':';
+ keyshift['\''] = '"';
+ keyshift['['] = '{';
+ keyshift[']'] = '}';
+ keyshift['`'] = '~';
+ keyshift['\\'] = '|';
+
+ menubound[K_ESCAPE] = true;
+ for (i=0 ; i<12 ; i++)
+ menubound[K_F1+i] = true;
+
+//
+// register our functions
+//
+ Cmd_AddCommand ("bind",Key_Bind_f);
+ Cmd_AddCommand ("unbind",Key_Unbind_f);
+ Cmd_AddCommand ("unbindall",Key_Unbindall_f);
+ Cmd_AddCommand ("bindlist",Key_Bindlist_f);
+}
+
+/*
+===================
+Key_Event
+
+Called by the system between frames for both key up and key down events
+Should NOT be called during an interrupt!
+===================
+*/
+void Key_Event (int key, qboolean down, unsigned time)
+{
+ char *kb;
+ char cmd[1024];
+
+ // hack for modal presses
+ if (key_waiting == -1)
+ {
+ if (down)
+ key_waiting = key;
+ return;
+ }
+
+ // update auto-repeat status
+ if (down)
+ {
+ key_repeats[key]++;
+ if (key != K_BACKSPACE
+ && key != K_PAUSE
+ && key != K_PGUP
+ && key != K_KP_PGUP
+ && key != K_PGDN
+ && key != K_KP_PGDN
+ && key_repeats[key] > 1)
+ return; // ignore most autorepeats
+
+ if (key >= 200 && !keybindings[key])
+ Com_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
+ }
+ else
+ {
+ key_repeats[key] = 0;
+ }
+
+ if (key == K_SHIFT)
+ shift_down = down;
+
+ // console key is hardcoded, so the user can never unbind it
+ if (key == '`' || key == '~')
+ {
+ if (!down)
+ return;
+ Con_ToggleConsole_f ();
+ return;
+ }
+
+ // any key during the attract mode will bring up the menu
+ if (cl.attractloop && cls.key_dest != key_menu)
+ key = K_ESCAPE;
+
+ // menu key is hardcoded, so the user can never unbind it
+ if (key == K_ESCAPE)
+ {
+ if (!down)
+ return;
+
+ if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
+ { // put away help computer / inventory
+ Cbuf_AddText ("cmd putaway\n");
+ return;
+ }
+ switch (cls.key_dest)
+ {
+ case key_message:
+ Key_Message (key);
+ break;
+ case key_menu:
+ M_Keydown (key);
+ break;
+ case key_game:
+ case key_console:
+ M_Menu_Main_f ();
+ break;
+ default:
+ Com_Error (ERR_FATAL, "Bad cls.key_dest");
+ }
+ return;
+ }
+
+ // track if any key is down for BUTTON_ANY
+ keydown[key] = down;
+ if (down)
+ {
+ if (key_repeats[key] == 1)
+ anykeydown++;
+ }
+ else
+ {
+ anykeydown--;
+ if (anykeydown < 0)
+ anykeydown = 0;
+ }
+
+//
+// key up events only generate commands if the game key binding is
+// a button command (leading + sign). These will occur even in console mode,
+// to keep the character from continuing an action started before a console
+// switch. Button commands include the kenum as a parameter, so multiple
+// downs can be matched with ups
+//
+ if (!down)
+ {
+ kb = keybindings[key];
+ if (kb && kb[0] == '+')
+ {
+ Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
+ Cbuf_AddText (cmd);
+ }
+ if (keyshift[key] != key)
+ {
+ kb = keybindings[keyshift[key]];
+ if (kb && kb[0] == '+')
+ {
+ Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
+ Cbuf_AddText (cmd);
+ }
+ }
+ return;
+ }
+
+//
+// if not a consolekey, send to the interpreter no matter what mode is
+//
+ if ( (cls.key_dest == key_menu && menubound[key])
+ || (cls.key_dest == key_console && !consolekeys[key])
+ || (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
+ {
+ kb = keybindings[key];
+ if (kb)
+ {
+ if (kb[0] == '+')
+ { // button commands add keynum and time as a parm
+ Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
+ Cbuf_AddText (cmd);
+ }
+ else
+ {
+ Cbuf_AddText (kb);
+ Cbuf_AddText ("\n");
+ }
+ }
+ return;
+ }
+
+ if (!down)
+ return; // other systems only care about key down events
+
+ if (shift_down)
+ key = keyshift[key];
+
+ switch (cls.key_dest)
+ {
+ case key_message:
+ Key_Message (key);
+ break;
+ case key_menu:
+ M_Keydown (key);
+ break;
+
+ case key_game:
+ case key_console:
+ Key_Console (key);
+ break;
+ default:
+ Com_Error (ERR_FATAL, "Bad cls.key_dest");
+ }
+}
+
+/*
+===================
+Key_ClearStates
+===================
+*/
+void Key_ClearStates (void)
+{
+ int i;
+
+ anykeydown = false;
+
+ for (i=0 ; i<256 ; i++)
+ {
+ if ( keydown[i] || key_repeats[i] )
+ Key_Event( i, false, 0 );
+ keydown[i] = 0;
+ key_repeats[i] = 0;
+ }
+}
+
+
+/*
+===================
+Key_GetKey
+===================
+*/
+int Key_GetKey (void)
+{
+ key_waiting = -1;
+
+ while (key_waiting == -1)
+ Sys_SendKeyEvents ();
+
+ return key_waiting;
+}
+
--- /dev/null
+++ b/md4.c
@@ -1,0 +1,276 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+
+/* MD4.H - header file for MD4C.C */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991.
+
+All rights reserved.
+
+License to copy and use this software is granted provided that it is identified as the �RSA Data Security, Inc. MD4 Message-Digest Algorithm� in all material mentioning or referencing this software or this function.
+License is also granted to make and use derivative works provided that such works are identified as �derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm� in all material mentioning or referencing the derived work.
+RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided �as is� without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this documentation and/or software. */
+
+/* MD4 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD4_CTX;
+
+void MD4Init (MD4_CTX *);
+void MD4Update (MD4_CTX *, unsigned char *, unsigned int);
+void MD4Final (unsigned char [16], MD4_CTX *);
+
+
+
+/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm */
+/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
+
+License to copy and use this software is granted provided that it is identified as the
+RSA Data Security, Inc. MD4 Message-Digest Algorithm
+ in all material mentioning or referencing this software or this function.
+License is also granted to make and use derivative works provided that such works are identified as
+derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm
+in all material mentioning or referencing the derived work.
+RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided
+as is without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this documentation and/or software. */
+
+/* Constants for MD4Transform routine. */
+#define S11 3
+#define S12 7
+#define S13 11
+#define S14 19
+#define S21 3
+#define S22 5
+#define S23 9
+#define S24 13
+#define S31 3
+#define S32 9
+#define S33 11
+#define S34 15
+
+static void MD4Transform (UINT4 [4], unsigned char [64]);
+static void Encode (unsigned char *, UINT4 *, unsigned int);
+static void Decode (UINT4 *, unsigned char *, unsigned int);
+
+static unsigned char PADDING[64] = {
+0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G and H are basic MD4 functions. */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits. */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) {(a) += F ((b), (c), (d)) + (x); (a) = ROTATE_LEFT ((a), (s));}
+
+#define GG(a, b, c, d, x, s) {(a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; (a) = ROTATE_LEFT ((a), (s));}
+
+#define HH(a, b, c, d, x, s) {(a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; (a) = ROTATE_LEFT ((a), (s));}
+
+
+/* MD4 initialization. Begins an MD4 operation, writing a new context. */
+void MD4Init (MD4_CTX *context)
+{
+ context->count[0] = context->count[1] = 0;
+
+/* Load magic initialization constants.*/
+context->state[0] = 0x67452301;
+context->state[1] = 0xefcdab89;
+context->state[2] = 0x98badcfe;
+context->state[3] = 0x10325476;
+}
+
+/* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */
+void MD4Update (MD4_CTX *context, unsigned char *input, unsigned int inputLen)
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3))
+ context->count[1]++;
+
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.*/
+ if (inputLen >= partLen)
+ {
+ memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD4Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD4Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
+}
+
+
+/* MD4 finalization. Ends an MD4 message-digest operation, writing the the message digest and zeroizing the context. */
+void MD4Final (unsigned char digest[16], MD4_CTX *context)
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD4Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD4Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.*/
+ memset ((POINTER)context, 0, sizeof (*context));
+}
+
+
+/* MD4 basic transformation. Transforms state based on block. */
+static void MD4Transform (UINT4 state[4], unsigned char block[64])
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+/* Round 1 */
+FF (a, b, c, d, x[ 0], S11); /* 1 */
+FF (d, a, b, c, x[ 1], S12); /* 2 */
+FF (c, d, a, b, x[ 2], S13); /* 3 */
+FF (b, c, d, a, x[ 3], S14); /* 4 */
+FF (a, b, c, d, x[ 4], S11); /* 5 */
+FF (d, a, b, c, x[ 5], S12); /* 6 */
+FF (c, d, a, b, x[ 6], S13); /* 7 */
+FF (b, c, d, a, x[ 7], S14); /* 8 */
+FF (a, b, c, d, x[ 8], S11); /* 9 */
+FF (d, a, b, c, x[ 9], S12); /* 10 */
+FF (c, d, a, b, x[10], S13); /* 11 */
+FF (b, c, d, a, x[11], S14); /* 12 */
+FF (a, b, c, d, x[12], S11); /* 13 */
+FF (d, a, b, c, x[13], S12); /* 14 */
+FF (c, d, a, b, x[14], S13); /* 15 */
+FF (b, c, d, a, x[15], S14); /* 16 */
+
+/* Round 2 */
+GG (a, b, c, d, x[ 0], S21); /* 17 */
+GG (d, a, b, c, x[ 4], S22); /* 18 */
+GG (c, d, a, b, x[ 8], S23); /* 19 */
+GG (b, c, d, a, x[12], S24); /* 20 */
+GG (a, b, c, d, x[ 1], S21); /* 21 */
+GG (d, a, b, c, x[ 5], S22); /* 22 */
+GG (c, d, a, b, x[ 9], S23); /* 23 */
+GG (b, c, d, a, x[13], S24); /* 24 */
+GG (a, b, c, d, x[ 2], S21); /* 25 */
+GG (d, a, b, c, x[ 6], S22); /* 26 */
+GG (c, d, a, b, x[10], S23); /* 27 */
+GG (b, c, d, a, x[14], S24); /* 28 */
+GG (a, b, c, d, x[ 3], S21); /* 29 */
+GG (d, a, b, c, x[ 7], S22); /* 30 */
+GG (c, d, a, b, x[11], S23); /* 31 */
+GG (b, c, d, a, x[15], S24); /* 32 */
+
+/* Round 3 */
+HH (a, b, c, d, x[ 0], S31); /* 33 */
+HH (d, a, b, c, x[ 8], S32); /* 34 */
+HH (c, d, a, b, x[ 4], S33); /* 35 */
+HH (b, c, d, a, x[12], S34); /* 36 */
+HH (a, b, c, d, x[ 2], S31); /* 37 */
+HH (d, a, b, c, x[10], S32); /* 38 */
+HH (c, d, a, b, x[ 6], S33); /* 39 */
+HH (b, c, d, a, x[14], S34); /* 40 */
+HH (a, b, c, d, x[ 1], S31); /* 41 */
+HH (d, a, b, c, x[ 9], S32); /* 42 */
+HH (c, d, a, b, x[ 5], S33); /* 43 */
+HH (b, c, d, a, x[13], S34); /* 44 */
+HH (a, b, c, d, x[ 3], S31); /* 45 */
+HH (d, a, b, c, x[11], S32); /* 46 */
+HH (c, d, a, b, x[ 7], S33); /* 47 */
+HH (b, c, d, a, x[15], S34); /* 48 */
+
+state[0] += a;
+state[1] += b;
+state[2] += c;
+state[3] += d;
+
+ /* Zeroize sensitive information.*/
+ memset ((POINTER)x, 0, sizeof (x));
+}
+
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */
+static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */
+static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
+{
+unsigned int i, j;
+
+for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+//===================================================================
+
+unsigned Com_BlockChecksum (void *buffer, int length)
+{
+ int digest[4];
+ unsigned val;
+ MD4_CTX ctx;
+
+ MD4Init (&ctx);
+ MD4Update (&ctx, (unsigned char *)buffer, length);
+ MD4Final ( (unsigned char *)digest, &ctx);
+
+ val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
+
+ return val;
+}
--- /dev/null
+++ b/menu.c
@@ -1,0 +1,3998 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "dat.h"
+#include "fns.h"
+
+static int m_main_cursor;
+
+#define NUM_CURSOR_FRAMES 15
+
+static char *menu_in_sound = "misc/menu1.wav";
+static char *menu_move_sound = "misc/menu2.wav";
+static char *menu_out_sound = "misc/menu3.wav";
+
+void M_Menu_Main_f (void);
+ void M_Menu_Game_f (void);
+ void M_Menu_LoadGame_f (void);
+ void M_Menu_SaveGame_f (void);
+ void M_Menu_PlayerConfig_f (void);
+ void M_Menu_DownloadOptions_f (void);
+ void M_Menu_Credits_f( void );
+ void M_Menu_Multiplayer_f( void );
+ void M_Menu_JoinServer_f (void);
+ void M_Menu_AddressBook_f( void );
+ void M_Menu_StartServer_f (void);
+ void M_Menu_DMOptions_f (void);
+ void M_Menu_Video_f (void);
+ void M_Menu_Options_f (void);
+ void M_Menu_Keys_f (void);
+ void M_Menu_Quit_f (void);
+
+ void M_Menu_Credits( void );
+
+qboolean m_entersound; // play after drawing a frame, so caching
+ // won't disrupt the sound
+
+void (*m_drawfunc) (void);
+char *(*m_keyfunc) (int key);
+
+//=============================================================================
+/* Support Routines */
+
+#define MAX_MENU_DEPTH 8
+
+
+typedef struct
+{
+ void (*draw) (void);
+ char *(*key) (int k);
+} menulayer_t;
+
+menulayer_t m_layers[MAX_MENU_DEPTH];
+int m_menudepth;
+
+static void M_Banner( char *name )
+{
+ int w, h;
+
+ re.DrawGetPicSize (&w, &h, name );
+ re.DrawPic( vid.width / 2 - w / 2, vid.height / 2 - 110, name );
+}
+
+void M_PushMenu ( void (*draw) (void), char *(*key) (int k) )
+{
+ int i;
+
+ if (Cvar_VariableValue ("maxclients") == 1
+ && Com_ServerState ())
+ Cvar_Set ("paused", "1");
+
+ // if this menu is already present, drop back to that level
+ // to avoid stacking menus by hotkeys
+ for (i=0 ; i<m_menudepth ; i++)
+ if (m_layers[i].draw == draw &&
+ m_layers[i].key == key)
+ {
+ m_menudepth = i;
+ }
+
+ if (i == m_menudepth)
+ {
+ if (m_menudepth >= MAX_MENU_DEPTH)
+ Com_Error (ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH");
+ m_layers[m_menudepth].draw = m_drawfunc;
+ m_layers[m_menudepth].key = m_keyfunc;
+ m_menudepth++;
+ }
+
+ m_drawfunc = draw;
+ m_keyfunc = key;
+
+ m_entersound = true;
+
+ cls.key_dest = key_menu;
+}
+
+void M_ForceMenuOff (void)
+{
+ m_drawfunc = 0;
+ m_keyfunc = 0;
+ cls.key_dest = key_game;
+ m_menudepth = 0;
+ Key_ClearStates ();
+ Cvar_Set ("paused", "0");
+ IN_Grabm (1);
+}
+
+void M_PopMenu (void)
+{
+ S_StartLocalSound( menu_out_sound );
+ if (m_menudepth < 1)
+ Com_Error (ERR_FATAL, "M_PopMenu: depth < 1");
+ m_menudepth--;
+
+ m_drawfunc = m_layers[m_menudepth].draw;
+ m_keyfunc = m_layers[m_menudepth].key;
+
+ if (!m_menudepth)
+ M_ForceMenuOff ();
+}
+
+
+char *Default_MenuKey( menuframework_t *m, int key )
+{
+ char *sound = nil;
+ menucommon_t *item;
+
+ if ( m )
+ {
+ if ( ( item = Menu_ItemAtCursor( m ) ) != 0 )
+ {
+ if ( item->type == MTYPE_FIELD )
+ {
+ if ( Field_Key( ( menufield_t * ) item, key ) )
+ return NULL;
+ }
+ }
+ }
+
+ switch ( key )
+ {
+ case K_ESCAPE:
+ M_PopMenu();
+ return menu_out_sound;
+ case K_KP_UPARROW:
+ case K_UPARROW:
+ if ( m )
+ {
+ m->cursor--;
+ Menu_AdjustCursor( m, -1 );
+ sound = menu_move_sound;
+ }
+ break;
+ case K_TAB:
+ if ( m )
+ {
+ m->cursor++;
+ Menu_AdjustCursor( m, 1 );
+ sound = menu_move_sound;
+ }
+ break;
+ case K_KP_DOWNARROW:
+ case K_DOWNARROW:
+ if ( m )
+ {
+ m->cursor++;
+ Menu_AdjustCursor( m, 1 );
+ sound = menu_move_sound;
+ }
+ break;
+ case K_KP_LEFTARROW:
+ case K_LEFTARROW:
+ if ( m )
+ {
+ Menu_SlideItem( m, -1 );
+ sound = menu_move_sound;
+ }
+ break;
+ case K_KP_RIGHTARROW:
+ case K_RIGHTARROW:
+ if ( m )
+ {
+ Menu_SlideItem( m, 1 );
+ sound = menu_move_sound;
+ }
+ break;
+
+ case K_MOUSE1:
+ case K_MOUSE2:
+ case K_MOUSE3:
+ case K_JOY1:
+ case K_JOY2:
+ case K_JOY3:
+ case K_JOY4:
+ case K_AUX1:
+ case K_AUX2:
+ case K_AUX3:
+ case K_AUX4:
+ case K_AUX5:
+ case K_AUX6:
+ case K_AUX7:
+ case K_AUX8:
+ case K_AUX9:
+ case K_AUX10:
+ case K_AUX11:
+ case K_AUX12:
+ case K_AUX13:
+ case K_AUX14:
+ case K_AUX15:
+ case K_AUX16:
+ case K_AUX17:
+ case K_AUX18:
+ case K_AUX19:
+ case K_AUX20:
+ case K_AUX21:
+ case K_AUX22:
+ case K_AUX23:
+ case K_AUX24:
+ case K_AUX25:
+ case K_AUX26:
+ case K_AUX27:
+ case K_AUX28:
+ case K_AUX29:
+ case K_AUX30:
+ case K_AUX31:
+ case K_AUX32:
+
+ case K_KP_ENTER:
+ case K_ENTER:
+ if ( m )
+ Menu_SelectItem( m );
+ sound = menu_move_sound;
+ break;
+ }
+
+ return sound;
+}
+
+//=============================================================================
+
+/*
+================
+M_DrawCharacter
+
+Draws one solid graphics character
+cx and cy are in 320*240 coordinates, and will be centered on
+higher res screens.
+================
+*/
+void M_DrawCharacter (int cx, int cy, int num)
+{
+ re.DrawChar ( cx + ((vid.width - 320)>>1), cy + ((vid.height - 240)>>1), num);
+}
+
+void M_Print (int cx, int cy, char *str)
+{
+ while (*str)
+ {
+ M_DrawCharacter (cx, cy, (*str)+128);
+ str++;
+ cx += 8;
+ }
+}
+
+void M_PrintWhite (int cx, int cy, char *str)
+{
+ while (*str)
+ {
+ M_DrawCharacter (cx, cy, *str);
+ str++;
+ cx += 8;
+ }
+}
+
+void M_DrawPic (int x, int y, char *pic)
+{
+ re.DrawPic (x + ((vid.width - 320)>>1), y + ((vid.height - 240)>>1), pic);
+}
+
+
+/*
+=============
+M_DrawCursor
+
+Draws an animating cursor with the point at
+x,y. The pic will extend to the left of x,
+and both above and below y.
+=============
+*/
+void M_DrawCursor( int x, int y, int f )
+{
+ char cursorname[80];
+ static qboolean cached;
+
+ if ( !cached )
+ {
+ int i;
+
+ for ( i = 0; i < NUM_CURSOR_FRAMES; i++ )
+ {
+ Com_sprintf( cursorname, sizeof( cursorname ), "m_cursor%d", i );
+
+ re.RegisterPic( cursorname );
+ }
+ cached = true;
+ }
+
+ Com_sprintf( cursorname, sizeof(cursorname), "m_cursor%d", f );
+ re.DrawPic( x, y, cursorname );
+}
+
+void M_DrawTextBox (int x, int y, int width, int lines)
+{
+ int cx, cy;
+ int n;
+
+ // draw left side
+ cx = x;
+ cy = y;
+ M_DrawCharacter (cx, cy, 1);
+ for (n = 0; n < lines; n++)
+ {
+ cy += 8;
+ M_DrawCharacter (cx, cy, 4);
+ }
+ M_DrawCharacter (cx, cy+8, 7);
+
+ // draw middle
+ cx += 8;
+ while (width > 0)
+ {
+ cy = y;
+ M_DrawCharacter (cx, cy, 2);
+ for (n = 0; n < lines; n++)
+ {
+ cy += 8;
+ M_DrawCharacter (cx, cy, 5);
+ }
+ M_DrawCharacter (cx, cy+8, 8);
+ width -= 1;
+ cx += 8;
+ }
+
+ // draw right side
+ cy = y;
+ M_DrawCharacter (cx, cy, 3);
+ for (n = 0; n < lines; n++)
+ {
+ cy += 8;
+ M_DrawCharacter (cx, cy, 6);
+ }
+ M_DrawCharacter (cx, cy+8, 9);
+}
+
+
+/*
+=======================================================================
+
+MAIN MENU
+
+=======================================================================
+*/
+#define MAIN_ITEMS 5
+
+
+void M_Main_Draw (void)
+{
+ int i;
+ int w, h;
+ int ystart;
+ int xoffset;
+ int widest = -1;
+ int totalheight = 0;
+ char litname[80];
+ char *names[] =
+ {
+ "m_main_game",
+ "m_main_multiplayer",
+ "m_main_options",
+ "m_main_video",
+ "m_main_quit",
+ 0
+ };
+
+ for ( i = 0; names[i] != 0; i++ )
+ {
+ re.DrawGetPicSize( &w, &h, names[i] );
+
+ if ( w > widest )
+ widest = w;
+ totalheight += ( h + 12 );
+ }
+
+ ystart = ( vid.height / 2 - 110 );
+ xoffset = ( vid.width - widest + 70 ) / 2;
+
+ for ( i = 0; names[i] != 0; i++ )
+ {
+ if ( i != m_main_cursor )
+ re.DrawPic( xoffset, ystart + i * 40 + 13, names[i] );
+ }
+ strcpy( litname, names[m_main_cursor] );
+ strcat( litname, "_sel" );
+ re.DrawPic( xoffset, ystart + m_main_cursor * 40 + 13, litname );
+
+ M_DrawCursor( xoffset - 25, ystart + m_main_cursor * 40 + 11, (int)(cls.realtime / 100)%NUM_CURSOR_FRAMES );
+
+ re.DrawGetPicSize( &w, &h, "m_main_plaque" );
+ re.DrawPic( xoffset - 30 - w, ystart, "m_main_plaque" );
+
+ re.DrawPic( xoffset - 30 - w, ystart + h + 5, "m_main_logo" );
+}
+
+
+char *M_Main_Key (int key)
+{
+ char *sound = menu_move_sound;
+
+ switch (key)
+ {
+ case K_ESCAPE:
+ M_PopMenu ();
+ break;
+
+ case K_KP_DOWNARROW:
+ case K_DOWNARROW:
+ if (++m_main_cursor >= MAIN_ITEMS)
+ m_main_cursor = 0;
+ return sound;
+
+ case K_KP_UPARROW:
+ case K_UPARROW:
+ if (--m_main_cursor < 0)
+ m_main_cursor = MAIN_ITEMS - 1;
+ return sound;
+
+ case K_KP_ENTER:
+ case K_ENTER:
+ m_entersound = true;
+
+ switch (m_main_cursor)
+ {
+ case 0:
+ M_Menu_Game_f ();
+ break;
+
+ case 1:
+ M_Menu_Multiplayer_f();
+ break;
+
+ case 2:
+ M_Menu_Options_f ();
+ break;
+
+ case 3:
+ M_Menu_Video_f ();
+ break;
+
+ case 4:
+ M_Menu_Quit_f ();
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+
+void M_Menu_Main_f (void)
+{
+ IN_Grabm (0);
+ M_PushMenu (M_Main_Draw, M_Main_Key);
+}
+
+/*
+=======================================================================
+
+MULTIPLAYER MENU
+
+=======================================================================
+*/
+static menuframework_t s_multiplayer_menu;
+static menuaction_t s_join_network_server_action;
+static menuaction_t s_start_network_server_action;
+static menuaction_t s_player_setup_action;
+
+static void Multiplayer_MenuDraw (void)
+{
+ M_Banner( "m_banner_multiplayer" );
+
+ Menu_AdjustCursor( &s_multiplayer_menu, 1 );
+ Menu_Draw( &s_multiplayer_menu );
+}
+
+static void PlayerSetupFunc( void * )
+{
+ M_Menu_PlayerConfig_f();
+}
+
+static void JoinNetworkServerFunc( void * )
+{
+ M_Menu_JoinServer_f();
+}
+
+static void StartNetworkServerFunc( void * )
+{
+ M_Menu_StartServer_f ();
+}
+
+void Multiplayer_MenuInit( void )
+{
+ s_multiplayer_menu.x = vid.width * 0.50 - 64;
+ s_multiplayer_menu.nitems = 0;
+
+ s_join_network_server_action.generic.type = MTYPE_ACTION;
+ s_join_network_server_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_join_network_server_action.generic.x = 0;
+ s_join_network_server_action.generic.y = 0;
+ s_join_network_server_action.generic.name = " join network server";
+ s_join_network_server_action.generic.callback = JoinNetworkServerFunc;
+
+ s_start_network_server_action.generic.type = MTYPE_ACTION;
+ s_start_network_server_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_start_network_server_action.generic.x = 0;
+ s_start_network_server_action.generic.y = 10;
+ s_start_network_server_action.generic.name = " start network server";
+ s_start_network_server_action.generic.callback = StartNetworkServerFunc;
+
+ s_player_setup_action.generic.type = MTYPE_ACTION;
+ s_player_setup_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_player_setup_action.generic.x = 0;
+ s_player_setup_action.generic.y = 20;
+ s_player_setup_action.generic.name = " player setup";
+ s_player_setup_action.generic.callback = PlayerSetupFunc;
+
+ Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_join_network_server_action );
+ Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_start_network_server_action );
+ Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_player_setup_action );
+
+ Menu_SetStatusBar( &s_multiplayer_menu, NULL );
+
+ Menu_Center( &s_multiplayer_menu );
+}
+
+char *Multiplayer_MenuKey( int key )
+{
+ return Default_MenuKey( &s_multiplayer_menu, key );
+}
+
+void M_Menu_Multiplayer_f( void )
+{
+ Multiplayer_MenuInit();
+ M_PushMenu( Multiplayer_MenuDraw, Multiplayer_MenuKey );
+}
+
+/*
+=======================================================================
+
+KEYS MENU
+
+=======================================================================
+*/
+char *bindnames[][2] =
+{
+{"+attack", "attack"},
+{"weapnext", "next weapon"},
+{"+forward", "walk forward"},
+{"+back", "backpedal"},
+{"+left", "turn left"},
+{"+right", "turn right"},
+{"+speed", "run"},
+{"+moveleft", "step left"},
+{"+moveright", "step right"},
+{"+strafe", "sidestep"},
+{"+lookup", "look up"},
+{"+lookdown", "look down"},
+{"centerview", "center view"},
+{"+mlook", "mouse look"},
+{"+klook", "keyboard look"},
+{"+moveup", "up / jump"},
+{"+movedown", "down / crouch"},
+
+{"inven", "inventory"},
+{"invuse", "use item"},
+{"invdrop", "drop item"},
+{"invprev", "prev item"},
+{"invnext", "next item"},
+
+{"cmd help", "help computer" },
+{ 0, 0 }
+};
+
+int keys_cursor;
+static int bind_grab;
+
+static menuframework_t s_keys_menu;
+static menuaction_t s_keys_attack_action;
+static menuaction_t s_keys_change_weapon_action;
+static menuaction_t s_keys_walk_forward_action;
+static menuaction_t s_keys_backpedal_action;
+static menuaction_t s_keys_turn_left_action;
+static menuaction_t s_keys_turn_right_action;
+static menuaction_t s_keys_run_action;
+static menuaction_t s_keys_step_left_action;
+static menuaction_t s_keys_step_right_action;
+static menuaction_t s_keys_sidestep_action;
+static menuaction_t s_keys_look_up_action;
+static menuaction_t s_keys_look_down_action;
+static menuaction_t s_keys_center_view_action;
+static menuaction_t s_keys_mouse_look_action;
+static menuaction_t s_keys_keyboard_look_action;
+static menuaction_t s_keys_move_up_action;
+static menuaction_t s_keys_move_down_action;
+static menuaction_t s_keys_inventory_action;
+static menuaction_t s_keys_inv_use_action;
+static menuaction_t s_keys_inv_drop_action;
+static menuaction_t s_keys_inv_prev_action;
+static menuaction_t s_keys_inv_next_action;
+
+static menuaction_t s_keys_help_computer_action;
+
+static void M_UnbindCommand (char *command)
+{
+ int j;
+ int l;
+ char *b;
+
+ l = strlen(command);
+
+ for (j=0 ; j<256 ; j++)
+ {
+ b = keybindings[j];
+ if (!b)
+ continue;
+ if (!strncmp (b, command, l) )
+ Key_SetBinding (j, "");
+ }
+}
+
+static void M_FindKeysForCommand (char *command, int *twokeys)
+{
+ int count;
+ int j;
+ int l;
+ char *b;
+
+ twokeys[0] = twokeys[1] = -1;
+ l = strlen(command);
+ count = 0;
+
+ for (j=0 ; j<256 ; j++)
+ {
+ b = keybindings[j];
+ if (!b)
+ continue;
+ if (!strncmp (b, command, l) )
+ {
+ twokeys[count] = j;
+ count++;
+ if (count == 2)
+ break;
+ }
+ }
+}
+
+static void KeyCursorDrawFunc( menuframework_t *menu )
+{
+ if ( bind_grab )
+ re.DrawChar( menu->x, menu->y + menu->cursor * 9, '=' );
+ else
+ re.DrawChar( menu->x, menu->y + menu->cursor * 9, 12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ) );
+}
+
+static void DrawKeyBindingFunc( void *self )
+{
+ int keys[2];
+ menuaction_t *a = ( menuaction_t * ) self;
+
+ M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys);
+
+ if (keys[0] == -1)
+ {
+ Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, "???" );
+ }
+ else
+ {
+ int x;
+ char *name;
+
+ name = Key_KeynumToString (keys[0]);
+
+ Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, name );
+
+ x = strlen(name) * 8;
+
+ if (keys[1] != -1)
+ {
+ Menu_DrawString( a->generic.x + a->generic.parent->x + 24 + x, a->generic.y + a->generic.parent->y, "or" );
+ Menu_DrawString( a->generic.x + a->generic.parent->x + 48 + x, a->generic.y + a->generic.parent->y, Key_KeynumToString (keys[1]) );
+ }
+ }
+}
+
+static void KeyBindingFunc( void *self )
+{
+ menuaction_t *a = ( menuaction_t * ) self;
+ int keys[2];
+
+ M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys );
+
+ if (keys[1] != -1)
+ M_UnbindCommand( bindnames[a->generic.localdata[0]][0]);
+
+ bind_grab = true;
+
+ Menu_SetStatusBar( &s_keys_menu, "press a key or button for this action" );
+}
+
+static void Keys_MenuInit( void )
+{
+ int y = 0;
+ int i = 0;
+
+ s_keys_menu.x = vid.width * 0.50;
+ s_keys_menu.nitems = 0;
+ s_keys_menu.cursordraw = KeyCursorDrawFunc;
+
+ s_keys_attack_action.generic.type = MTYPE_ACTION;
+ s_keys_attack_action.generic.flags = QMF_GRAYED;
+ s_keys_attack_action.generic.x = 0;
+ s_keys_attack_action.generic.y = y;
+ s_keys_attack_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_attack_action.generic.localdata[0] = i;
+ s_keys_attack_action.generic.name = bindnames[s_keys_attack_action.generic.localdata[0]][1];
+
+ s_keys_change_weapon_action.generic.type = MTYPE_ACTION;
+ s_keys_change_weapon_action.generic.flags = QMF_GRAYED;
+ s_keys_change_weapon_action.generic.x = 0;
+ s_keys_change_weapon_action.generic.y = y += 9;
+ s_keys_change_weapon_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_change_weapon_action.generic.localdata[0] = ++i;
+ s_keys_change_weapon_action.generic.name = bindnames[s_keys_change_weapon_action.generic.localdata[0]][1];
+
+ s_keys_walk_forward_action.generic.type = MTYPE_ACTION;
+ s_keys_walk_forward_action.generic.flags = QMF_GRAYED;
+ s_keys_walk_forward_action.generic.x = 0;
+ s_keys_walk_forward_action.generic.y = y += 9;
+ s_keys_walk_forward_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_walk_forward_action.generic.localdata[0] = ++i;
+ s_keys_walk_forward_action.generic.name = bindnames[s_keys_walk_forward_action.generic.localdata[0]][1];
+
+ s_keys_backpedal_action.generic.type = MTYPE_ACTION;
+ s_keys_backpedal_action.generic.flags = QMF_GRAYED;
+ s_keys_backpedal_action.generic.x = 0;
+ s_keys_backpedal_action.generic.y = y += 9;
+ s_keys_backpedal_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_backpedal_action.generic.localdata[0] = ++i;
+ s_keys_backpedal_action.generic.name = bindnames[s_keys_backpedal_action.generic.localdata[0]][1];
+
+ s_keys_turn_left_action.generic.type = MTYPE_ACTION;
+ s_keys_turn_left_action.generic.flags = QMF_GRAYED;
+ s_keys_turn_left_action.generic.x = 0;
+ s_keys_turn_left_action.generic.y = y += 9;
+ s_keys_turn_left_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_turn_left_action.generic.localdata[0] = ++i;
+ s_keys_turn_left_action.generic.name = bindnames[s_keys_turn_left_action.generic.localdata[0]][1];
+
+ s_keys_turn_right_action.generic.type = MTYPE_ACTION;
+ s_keys_turn_right_action.generic.flags = QMF_GRAYED;
+ s_keys_turn_right_action.generic.x = 0;
+ s_keys_turn_right_action.generic.y = y += 9;
+ s_keys_turn_right_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_turn_right_action.generic.localdata[0] = ++i;
+ s_keys_turn_right_action.generic.name = bindnames[s_keys_turn_right_action.generic.localdata[0]][1];
+
+ s_keys_run_action.generic.type = MTYPE_ACTION;
+ s_keys_run_action.generic.flags = QMF_GRAYED;
+ s_keys_run_action.generic.x = 0;
+ s_keys_run_action.generic.y = y += 9;
+ s_keys_run_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_run_action.generic.localdata[0] = ++i;
+ s_keys_run_action.generic.name = bindnames[s_keys_run_action.generic.localdata[0]][1];
+
+ s_keys_step_left_action.generic.type = MTYPE_ACTION;
+ s_keys_step_left_action.generic.flags = QMF_GRAYED;
+ s_keys_step_left_action.generic.x = 0;
+ s_keys_step_left_action.generic.y = y += 9;
+ s_keys_step_left_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_step_left_action.generic.localdata[0] = ++i;
+ s_keys_step_left_action.generic.name = bindnames[s_keys_step_left_action.generic.localdata[0]][1];
+
+ s_keys_step_right_action.generic.type = MTYPE_ACTION;
+ s_keys_step_right_action.generic.flags = QMF_GRAYED;
+ s_keys_step_right_action.generic.x = 0;
+ s_keys_step_right_action.generic.y = y += 9;
+ s_keys_step_right_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_step_right_action.generic.localdata[0] = ++i;
+ s_keys_step_right_action.generic.name = bindnames[s_keys_step_right_action.generic.localdata[0]][1];
+
+ s_keys_sidestep_action.generic.type = MTYPE_ACTION;
+ s_keys_sidestep_action.generic.flags = QMF_GRAYED;
+ s_keys_sidestep_action.generic.x = 0;
+ s_keys_sidestep_action.generic.y = y += 9;
+ s_keys_sidestep_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_sidestep_action.generic.localdata[0] = ++i;
+ s_keys_sidestep_action.generic.name = bindnames[s_keys_sidestep_action.generic.localdata[0]][1];
+
+ s_keys_look_up_action.generic.type = MTYPE_ACTION;
+ s_keys_look_up_action.generic.flags = QMF_GRAYED;
+ s_keys_look_up_action.generic.x = 0;
+ s_keys_look_up_action.generic.y = y += 9;
+ s_keys_look_up_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_look_up_action.generic.localdata[0] = ++i;
+ s_keys_look_up_action.generic.name = bindnames[s_keys_look_up_action.generic.localdata[0]][1];
+
+ s_keys_look_down_action.generic.type = MTYPE_ACTION;
+ s_keys_look_down_action.generic.flags = QMF_GRAYED;
+ s_keys_look_down_action.generic.x = 0;
+ s_keys_look_down_action.generic.y = y += 9;
+ s_keys_look_down_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_look_down_action.generic.localdata[0] = ++i;
+ s_keys_look_down_action.generic.name = bindnames[s_keys_look_down_action.generic.localdata[0]][1];
+
+ s_keys_center_view_action.generic.type = MTYPE_ACTION;
+ s_keys_center_view_action.generic.flags = QMF_GRAYED;
+ s_keys_center_view_action.generic.x = 0;
+ s_keys_center_view_action.generic.y = y += 9;
+ s_keys_center_view_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_center_view_action.generic.localdata[0] = ++i;
+ s_keys_center_view_action.generic.name = bindnames[s_keys_center_view_action.generic.localdata[0]][1];
+
+ s_keys_mouse_look_action.generic.type = MTYPE_ACTION;
+ s_keys_mouse_look_action.generic.flags = QMF_GRAYED;
+ s_keys_mouse_look_action.generic.x = 0;
+ s_keys_mouse_look_action.generic.y = y += 9;
+ s_keys_mouse_look_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_mouse_look_action.generic.localdata[0] = ++i;
+ s_keys_mouse_look_action.generic.name = bindnames[s_keys_mouse_look_action.generic.localdata[0]][1];
+
+ s_keys_keyboard_look_action.generic.type = MTYPE_ACTION;
+ s_keys_keyboard_look_action.generic.flags = QMF_GRAYED;
+ s_keys_keyboard_look_action.generic.x = 0;
+ s_keys_keyboard_look_action.generic.y = y += 9;
+ s_keys_keyboard_look_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_keyboard_look_action.generic.localdata[0] = ++i;
+ s_keys_keyboard_look_action.generic.name = bindnames[s_keys_keyboard_look_action.generic.localdata[0]][1];
+
+ s_keys_move_up_action.generic.type = MTYPE_ACTION;
+ s_keys_move_up_action.generic.flags = QMF_GRAYED;
+ s_keys_move_up_action.generic.x = 0;
+ s_keys_move_up_action.generic.y = y += 9;
+ s_keys_move_up_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_move_up_action.generic.localdata[0] = ++i;
+ s_keys_move_up_action.generic.name = bindnames[s_keys_move_up_action.generic.localdata[0]][1];
+
+ s_keys_move_down_action.generic.type = MTYPE_ACTION;
+ s_keys_move_down_action.generic.flags = QMF_GRAYED;
+ s_keys_move_down_action.generic.x = 0;
+ s_keys_move_down_action.generic.y = y += 9;
+ s_keys_move_down_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_move_down_action.generic.localdata[0] = ++i;
+ s_keys_move_down_action.generic.name = bindnames[s_keys_move_down_action.generic.localdata[0]][1];
+
+ s_keys_inventory_action.generic.type = MTYPE_ACTION;
+ s_keys_inventory_action.generic.flags = QMF_GRAYED;
+ s_keys_inventory_action.generic.x = 0;
+ s_keys_inventory_action.generic.y = y += 9;
+ s_keys_inventory_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_inventory_action.generic.localdata[0] = ++i;
+ s_keys_inventory_action.generic.name = bindnames[s_keys_inventory_action.generic.localdata[0]][1];
+
+ s_keys_inv_use_action.generic.type = MTYPE_ACTION;
+ s_keys_inv_use_action.generic.flags = QMF_GRAYED;
+ s_keys_inv_use_action.generic.x = 0;
+ s_keys_inv_use_action.generic.y = y += 9;
+ s_keys_inv_use_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_inv_use_action.generic.localdata[0] = ++i;
+ s_keys_inv_use_action.generic.name = bindnames[s_keys_inv_use_action.generic.localdata[0]][1];
+
+ s_keys_inv_drop_action.generic.type = MTYPE_ACTION;
+ s_keys_inv_drop_action.generic.flags = QMF_GRAYED;
+ s_keys_inv_drop_action.generic.x = 0;
+ s_keys_inv_drop_action.generic.y = y += 9;
+ s_keys_inv_drop_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_inv_drop_action.generic.localdata[0] = ++i;
+ s_keys_inv_drop_action.generic.name = bindnames[s_keys_inv_drop_action.generic.localdata[0]][1];
+
+ s_keys_inv_prev_action.generic.type = MTYPE_ACTION;
+ s_keys_inv_prev_action.generic.flags = QMF_GRAYED;
+ s_keys_inv_prev_action.generic.x = 0;
+ s_keys_inv_prev_action.generic.y = y += 9;
+ s_keys_inv_prev_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_inv_prev_action.generic.localdata[0] = ++i;
+ s_keys_inv_prev_action.generic.name = bindnames[s_keys_inv_prev_action.generic.localdata[0]][1];
+
+ s_keys_inv_next_action.generic.type = MTYPE_ACTION;
+ s_keys_inv_next_action.generic.flags = QMF_GRAYED;
+ s_keys_inv_next_action.generic.x = 0;
+ s_keys_inv_next_action.generic.y = y += 9;
+ s_keys_inv_next_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_inv_next_action.generic.localdata[0] = ++i;
+ s_keys_inv_next_action.generic.name = bindnames[s_keys_inv_next_action.generic.localdata[0]][1];
+
+ s_keys_help_computer_action.generic.type = MTYPE_ACTION;
+ s_keys_help_computer_action.generic.flags = QMF_GRAYED;
+ s_keys_help_computer_action.generic.x = 0;
+ s_keys_help_computer_action.generic.y = y += 9;
+ s_keys_help_computer_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_help_computer_action.generic.localdata[0] = ++i;
+ s_keys_help_computer_action.generic.name = bindnames[s_keys_help_computer_action.generic.localdata[0]][1];
+
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_attack_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_change_weapon_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_walk_forward_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_backpedal_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_left_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_right_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_run_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_left_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_right_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_sidestep_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_up_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_down_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_center_view_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_mouse_look_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_keyboard_look_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_up_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_down_action );
+
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inventory_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_use_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_drop_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_prev_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_next_action );
+
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_help_computer_action );
+
+ Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
+ Menu_Center( &s_keys_menu );
+}
+
+static void Keys_MenuDraw (void)
+{
+ Menu_AdjustCursor( &s_keys_menu, 1 );
+ Menu_Draw( &s_keys_menu );
+}
+
+static char *Keys_MenuKey( int key )
+{
+ menuaction_t *item = ( menuaction_t * ) Menu_ItemAtCursor( &s_keys_menu );
+
+ if ( bind_grab )
+ {
+ if ( key != K_ESCAPE && key != '`' )
+ {
+ char cmd[1024];
+
+ Com_sprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item->generic.localdata[0]][0]);
+ Cbuf_InsertText (cmd);
+ }
+
+ Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
+ bind_grab = false;
+ return menu_out_sound;
+ }
+
+ switch ( key )
+ {
+ case K_KP_ENTER:
+ case K_ENTER:
+ KeyBindingFunc( item );
+ return menu_in_sound;
+ case K_BACKSPACE: // delete bindings
+ case K_DEL: // delete bindings
+ case K_KP_DEL:
+ M_UnbindCommand( bindnames[item->generic.localdata[0]][0] );
+ return menu_out_sound;
+ default:
+ return Default_MenuKey( &s_keys_menu, key );
+ }
+}
+
+void M_Menu_Keys_f (void)
+{
+ Keys_MenuInit();
+ M_PushMenu( Keys_MenuDraw, Keys_MenuKey );
+}
+
+
+/*
+=======================================================================
+
+CONTROLS MENU
+
+=======================================================================
+*/
+static cvar_t *win_noalttab;
+
+static menuframework_t s_options_menu;
+static menuaction_t s_options_defaults_action;
+static menuaction_t s_options_customize_options_action;
+static menuslider_t s_options_sensitivity_slider;
+static menulist_t s_options_freelook_box;
+static menulist_t s_options_noalttab_box;
+static menulist_t s_options_alwaysrun_box;
+static menulist_t s_options_invertmouse_box;
+static menulist_t s_options_lookspring_box;
+static menulist_t s_options_lookstrafe_box;
+static menulist_t s_options_crosshair_box;
+static menuslider_t s_options_sfxvolume_slider;
+static menulist_t s_options_joystick_box;
+static menulist_t s_options_cdvolume_box;
+static menulist_t s_options_quality_list;
+static menulist_t s_options_compatibility_list;
+static menulist_t s_options_console_action;
+
+static void CrosshairFunc( void * )
+{
+ Cvar_SetValue( "crosshair", s_options_crosshair_box.curvalue );
+}
+
+static void JoystickFunc( void * )
+{
+ Cvar_SetValue( "in_joystick", s_options_joystick_box.curvalue );
+}
+
+static void CustomizeControlsFunc( void * )
+{
+ M_Menu_Keys_f();
+}
+
+static void AlwaysRunFunc( void * )
+{
+ Cvar_SetValue( "cl_run", s_options_alwaysrun_box.curvalue );
+}
+
+static void FreeLookFunc( void * )
+{
+ Cvar_SetValue( "freelook", s_options_freelook_box.curvalue );
+}
+
+static void MouseSpeedFunc( void * )
+{
+ Cvar_SetValue( "sensitivity", s_options_sensitivity_slider.curvalue / 2.0F );
+}
+
+static void NoAltTabFunc( void * )
+{
+ Cvar_SetValue( "win_noalttab", s_options_noalttab_box.curvalue );
+}
+
+static float ClampCvar( float min, float max, float value )
+{
+ if ( value < min ) return min;
+ if ( value > max ) return max;
+ return value;
+}
+
+static void ControlsSetMenuItemValues( void )
+{
+ s_options_sfxvolume_slider.curvalue = Cvar_VariableValue( "s_volume" ) * 10;
+ s_options_cdvolume_box.curvalue = !Cvar_VariableValue("cd_nocd");
+ s_options_quality_list.curvalue = !Cvar_VariableValue( "s_loadas8bit" );
+ s_options_sensitivity_slider.curvalue = ( sensitivity->value ) * 2;
+
+ Cvar_SetValue( "cl_run", ClampCvar( 0, 1, cl_run->value ) );
+ s_options_alwaysrun_box.curvalue = cl_run->value;
+
+ s_options_invertmouse_box.curvalue = m_pitch->value < 0;
+
+ Cvar_SetValue( "lookspring", ClampCvar( 0, 1, lookspring->value ) );
+ s_options_lookspring_box.curvalue = lookspring->value;
+
+ Cvar_SetValue( "lookstrafe", ClampCvar( 0, 1, lookstrafe->value ) );
+ s_options_lookstrafe_box.curvalue = lookstrafe->value;
+
+ Cvar_SetValue( "freelook", ClampCvar( 0, 1, freelook->value ) );
+ s_options_freelook_box.curvalue = freelook->value;
+
+ Cvar_SetValue( "crosshair", ClampCvar( 0, 3, crosshair->value ) );
+ s_options_crosshair_box.curvalue = crosshair->value;
+
+ Cvar_SetValue( "in_joystick", ClampCvar( 0, 1, in_joystick->value ) );
+ s_options_joystick_box.curvalue = in_joystick->value;
+
+ s_options_noalttab_box.curvalue = win_noalttab->value;
+}
+
+static void ControlsResetDefaultsFunc( void * )
+{
+ Cbuf_AddText ("exec default.cfg\n");
+ Cbuf_Execute();
+
+ ControlsSetMenuItemValues();
+}
+
+static void InvertMouseFunc( void * )
+{
+ if ( s_options_invertmouse_box.curvalue == 0 )
+ {
+ Cvar_SetValue( "m_pitch", fabs( m_pitch->value ) );
+ }
+ else
+ {
+ Cvar_SetValue( "m_pitch", -fabs( m_pitch->value ) );
+ }
+}
+
+static void LookspringFunc( void * )
+{
+ Cvar_SetValue( "lookspring", s_options_lookspring_box.curvalue );
+}
+
+static void LookstrafeFunc( void * )
+{
+ Cvar_SetValue( "lookstrafe", s_options_lookstrafe_box.curvalue );
+}
+
+static void UpdateVolumeFunc( void * )
+{
+ Cvar_SetValue( "s_volume", s_options_sfxvolume_slider.curvalue / 10 );
+}
+
+static void UpdateCDVolumeFunc( void * )
+{
+ Cvar_SetValue( "cd_nocd", !s_options_cdvolume_box.curvalue );
+}
+
+static void ConsoleFunc( void * )
+{
+ /*
+ ** the proper way to do this is probably to have ToggleConsole_f accept a parameter
+ */
+ extern void Key_ClearTyping( void );
+
+ if ( cl.attractloop )
+ {
+ Cbuf_AddText ("killserver\n");
+ return;
+ }
+
+ Key_ClearTyping ();
+ Con_ClearNotify ();
+
+ M_ForceMenuOff ();
+ cls.key_dest = key_console;
+}
+
+static void UpdateSoundQualityFunc( void * )
+{
+ if ( s_options_quality_list.curvalue )
+ {
+ Cvar_SetValue( "s_khz", 22 );
+ Cvar_SetValue( "s_loadas8bit", false );
+ }
+ else
+ {
+ Cvar_SetValue( "s_khz", 11 );
+ Cvar_SetValue( "s_loadas8bit", true );
+ }
+
+ Cvar_SetValue( "s_primary", s_options_compatibility_list.curvalue );
+
+ M_DrawTextBox( 8, 120 - 48, 36, 3 );
+ M_Print( 16 + 16, 120 - 48 + 8, "Restarting the sound system. This" );
+ M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
+ M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
+
+ // the text box won't show up unless we do a buffer swap
+ re.EndFrame();
+
+ CL_Snd_Restart_f();
+}
+
+void Options_MenuInit( void )
+{
+ static char *cd_music_items[] =
+ {
+ "disabled",
+ "enabled",
+ 0
+ };
+ static char *quality_items[] =
+ {
+ "low", "high", 0
+ };
+
+ static char *compatibility_items[] =
+ {
+ "max compatibility", "max performance", 0
+ };
+
+ static char *yesno_names[] =
+ {
+ "no",
+ "yes",
+ 0
+ };
+
+ static char *crosshair_names[] =
+ {
+ "none",
+ "cross",
+ "dot",
+ "angle",
+ 0
+ };
+
+ win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
+
+ /*
+ ** configure controls menu and menu items
+ */
+ s_options_menu.x = vid.width / 2;
+ s_options_menu.y = vid.height / 2 - 58;
+ s_options_menu.nitems = 0;
+
+ s_options_sfxvolume_slider.generic.type = MTYPE_SLIDER;
+ s_options_sfxvolume_slider.generic.x = 0;
+ s_options_sfxvolume_slider.generic.y = 0;
+ s_options_sfxvolume_slider.generic.name = "effects volume";
+ s_options_sfxvolume_slider.generic.callback = UpdateVolumeFunc;
+ s_options_sfxvolume_slider.minvalue = 0;
+ s_options_sfxvolume_slider.maxvalue = 10;
+ s_options_sfxvolume_slider.curvalue = Cvar_VariableValue( "s_volume" ) * 10;
+
+ s_options_cdvolume_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_cdvolume_box.generic.x = 0;
+ s_options_cdvolume_box.generic.y = 10;
+ s_options_cdvolume_box.generic.name = "CD music";
+ s_options_cdvolume_box.generic.callback = UpdateCDVolumeFunc;
+ s_options_cdvolume_box.itemnames = cd_music_items;
+ s_options_cdvolume_box.curvalue = !Cvar_VariableValue("cd_nocd");
+
+ s_options_quality_list.generic.type = MTYPE_SPINCONTROL;
+ s_options_quality_list.generic.x = 0;
+ s_options_quality_list.generic.y = 20;;
+ s_options_quality_list.generic.name = "sound quality";
+ s_options_quality_list.generic.callback = UpdateSoundQualityFunc;
+ s_options_quality_list.itemnames = quality_items;
+ s_options_quality_list.curvalue = !Cvar_VariableValue( "s_loadas8bit" );
+
+ s_options_compatibility_list.generic.type = MTYPE_SPINCONTROL;
+ s_options_compatibility_list.generic.x = 0;
+ s_options_compatibility_list.generic.y = 30;
+ s_options_compatibility_list.generic.name = "sound compatibility";
+ s_options_compatibility_list.generic.callback = UpdateSoundQualityFunc;
+ s_options_compatibility_list.itemnames = compatibility_items;
+ s_options_compatibility_list.curvalue = Cvar_VariableValue( "s_primary" );
+
+ s_options_sensitivity_slider.generic.type = MTYPE_SLIDER;
+ s_options_sensitivity_slider.generic.x = 0;
+ s_options_sensitivity_slider.generic.y = 50;
+ s_options_sensitivity_slider.generic.name = "mouse speed";
+ s_options_sensitivity_slider.generic.callback = MouseSpeedFunc;
+ s_options_sensitivity_slider.minvalue = 2;
+ s_options_sensitivity_slider.maxvalue = 22;
+
+ s_options_alwaysrun_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_alwaysrun_box.generic.x = 0;
+ s_options_alwaysrun_box.generic.y = 60;
+ s_options_alwaysrun_box.generic.name = "always run";
+ s_options_alwaysrun_box.generic.callback = AlwaysRunFunc;
+ s_options_alwaysrun_box.itemnames = yesno_names;
+
+ s_options_invertmouse_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_invertmouse_box.generic.x = 0;
+ s_options_invertmouse_box.generic.y = 70;
+ s_options_invertmouse_box.generic.name = "invert mouse";
+ s_options_invertmouse_box.generic.callback = InvertMouseFunc;
+ s_options_invertmouse_box.itemnames = yesno_names;
+
+ s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_lookspring_box.generic.x = 0;
+ s_options_lookspring_box.generic.y = 80;
+ s_options_lookspring_box.generic.name = "lookspring";
+ s_options_lookspring_box.generic.callback = LookspringFunc;
+ s_options_lookspring_box.itemnames = yesno_names;
+
+ s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_lookstrafe_box.generic.x = 0;
+ s_options_lookstrafe_box.generic.y = 90;
+ s_options_lookstrafe_box.generic.name = "lookstrafe";
+ s_options_lookstrafe_box.generic.callback = LookstrafeFunc;
+ s_options_lookstrafe_box.itemnames = yesno_names;
+
+ s_options_freelook_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_freelook_box.generic.x = 0;
+ s_options_freelook_box.generic.y = 100;
+ s_options_freelook_box.generic.name = "free look";
+ s_options_freelook_box.generic.callback = FreeLookFunc;
+ s_options_freelook_box.itemnames = yesno_names;
+
+ s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_crosshair_box.generic.x = 0;
+ s_options_crosshair_box.generic.y = 110;
+ s_options_crosshair_box.generic.name = "crosshair";
+ s_options_crosshair_box.generic.callback = CrosshairFunc;
+ s_options_crosshair_box.itemnames = crosshair_names;
+/*
+ s_options_noalttab_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_noalttab_box.generic.x = 0;
+ s_options_noalttab_box.generic.y = 110;
+ s_options_noalttab_box.generic.name = "disable alt-tab";
+ s_options_noalttab_box.generic.callback = NoAltTabFunc;
+ s_options_noalttab_box.itemnames = yesno_names;
+*/
+ s_options_joystick_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_joystick_box.generic.x = 0;
+ s_options_joystick_box.generic.y = 120;
+ s_options_joystick_box.generic.name = "use joystick";
+ s_options_joystick_box.generic.callback = JoystickFunc;
+ s_options_joystick_box.itemnames = yesno_names;
+
+ s_options_customize_options_action.generic.type = MTYPE_ACTION;
+ s_options_customize_options_action.generic.x = 0;
+ s_options_customize_options_action.generic.y = 140;
+ s_options_customize_options_action.generic.name = "customize controls";
+ s_options_customize_options_action.generic.callback = CustomizeControlsFunc;
+
+ s_options_defaults_action.generic.type = MTYPE_ACTION;
+ s_options_defaults_action.generic.x = 0;
+ s_options_defaults_action.generic.y = 150;
+ s_options_defaults_action.generic.name = "reset defaults";
+ s_options_defaults_action.generic.callback = ControlsResetDefaultsFunc;
+
+ s_options_console_action.generic.type = MTYPE_ACTION;
+ s_options_console_action.generic.x = 0;
+ s_options_console_action.generic.y = 160;
+ s_options_console_action.generic.name = "go to console";
+ s_options_console_action.generic.callback = ConsoleFunc;
+
+ ControlsSetMenuItemValues();
+
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_sfxvolume_slider );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_cdvolume_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_quality_list );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_compatibility_list );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_sensitivity_slider );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_alwaysrun_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_invertmouse_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookspring_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookstrafe_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_freelook_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_crosshair_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_joystick_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_customize_options_action );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_defaults_action );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_console_action );
+}
+
+void Options_MenuDraw (void)
+{
+ M_Banner( "m_banner_options" );
+ Menu_AdjustCursor( &s_options_menu, 1 );
+ Menu_Draw( &s_options_menu );
+}
+
+char *Options_MenuKey( int key )
+{
+ return Default_MenuKey( &s_options_menu, key );
+}
+
+void M_Menu_Options_f (void)
+{
+ Options_MenuInit();
+ M_PushMenu ( Options_MenuDraw, Options_MenuKey );
+}
+
+/*
+=======================================================================
+
+VIDEO MENU
+
+=======================================================================
+*/
+
+void M_Menu_Video_f (void)
+{
+ VID_MenuInit();
+ M_PushMenu( VID_MenuDraw, VID_MenuKey );
+}
+
+/*
+=============================================================================
+
+END GAME MENU
+
+=============================================================================
+*/
+static int credits_start_time;
+static char **credits;
+static char *creditsIndex[256];
+static char *creditsBuffer;
+static char *idcredits[] =
+{
+ "+QUAKE II BY ID SOFTWARE",
+ "",
+ "+PROGRAMMING",
+ "John Carmack",
+ "John Cash",
+ "Brian Hook",
+ "",
+ "+ART",
+ "Adrian Carmack",
+ "Kevin Cloud",
+ "Paul Steed",
+ "",
+ "+LEVEL DESIGN",
+ "Tim Willits",
+ "American McGee",
+ "Christian Antkow",
+ "Paul Jaquays",
+ "Brandon James",
+ "",
+ "+BIZ",
+ "Todd Hollenshead",
+ "Barrett (Bear) Alexander",
+ "Donna Jackson",
+ "",
+ "",
+ "+SPECIAL THANKS",
+ "Ben Donges for beta testing",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "+ADDITIONAL SUPPORT",
+ "",
+ "+LINUX PORT AND CTF",
+ "Dave \"Zoid\" Kirsch",
+ "",
+ "+CINEMATIC SEQUENCES",
+ "Ending Cinematic by Blur Studio - ",
+ "Venice, CA",
+ "",
+ "Environment models for Introduction",
+ "Cinematic by Karl Dolgener",
+ "",
+ "Assistance with environment design",
+ "by Cliff Iwai",
+ "",
+ "+SOUND EFFECTS AND MUSIC",
+ "Sound Design by Soundelux Media Labs.",
+ "Music Composed and Produced by",
+ "Soundelux Media Labs. Special thanks",
+ "to Bill Brown, Tom Ozanich, Brian",
+ "Celano, Jeff Eisner, and The Soundelux",
+ "Players.",
+ "",
+ "\"Level Music\" by Sonic Mayhem",
+ "www.sonicmayhem.com",
+ "",
+ "\"Quake II Theme Song\"",
+ "(C) 1997 Rob Zombie. All Rights",
+ "Reserved.",
+ "",
+ "Track 10 (\"Climb\") by Jer Sypult",
+ "",
+ "Voice of computers by",
+ "Carly Staehlin-Taylor",
+ "",
+ "+THANKS TO ACTIVISION",
+ "+IN PARTICULAR:",
+ "",
+ "John Tam",
+ "Steve Rosenthal",
+ "Marty Stratton",
+ "Henk Hartong",
+ "",
+ "Quake II(tm) (C)1997 Id Software, Inc.",
+ "All Rights Reserved. Distributed by",
+ "Activision, Inc. under license.",
+ "Quake II(tm), the Id Software name,",
+ "the \"Q II\"(tm) logo and id(tm)",
+ "logo are trademarks of Id Software,",
+ "Inc. Activision(R) is a registered",
+ "trademark of Activision, Inc. All",
+ "other trademarks and trade names are",
+ "properties of their respective owners.",
+ 0
+};
+
+static char *xatcredits[] =
+{
+ "+QUAKE II MISSION PACK: THE RECKONING",
+ "+BY",
+ "+XATRIX ENTERTAINMENT, INC.",
+ "",
+ "+DESIGN AND DIRECTION",
+ "Drew Markham",
+ "",
+ "+PRODUCED BY",
+ "Greg Goodrich",
+ "",
+ "+PROGRAMMING",
+ "Rafael Paiz",
+ "",
+ "+LEVEL DESIGN / ADDITIONAL GAME DESIGN",
+ "Alex Mayberry",
+ "",
+ "+LEVEL DESIGN",
+ "Mal Blackwell",
+ "Dan Koppel",
+ "",
+ "+ART DIRECTION",
+ "Michael \"Maxx\" Kaufman",
+ "",
+ "+COMPUTER GRAPHICS SUPERVISOR AND",
+ "+CHARACTER ANIMATION DIRECTION",
+ "Barry Dempsey",
+ "",
+ "+SENIOR ANIMATOR AND MODELER",
+ "Jason Hoover",
+ "",
+ "+CHARACTER ANIMATION AND",
+ "+MOTION CAPTURE SPECIALIST",
+ "Amit Doron",
+ "",
+ "+ART",
+ "Claire Praderie-Markham",
+ "Viktor Antonov",
+ "Corky Lehmkuhl",
+ "",
+ "+INTRODUCTION ANIMATION",
+ "Dominique Drozdz",
+ "",
+ "+ADDITIONAL LEVEL DESIGN",
+ "Aaron Barber",
+ "Rhett Baldwin",
+ "",
+ "+3D CHARACTER ANIMATION TOOLS",
+ "Gerry Tyra, SA Technology",
+ "",
+ "+ADDITIONAL EDITOR TOOL PROGRAMMING",
+ "Robert Duffy",
+ "",
+ "+ADDITIONAL PROGRAMMING",
+ "Ryan Feltrin",
+ "",
+ "+PRODUCTION COORDINATOR",
+ "Victoria Sylvester",
+ "",
+ "+SOUND DESIGN",
+ "Gary Bradfield",
+ "",
+ "+MUSIC BY",
+ "Sonic Mayhem",
+ "",
+ "",
+ "",
+ "+SPECIAL THANKS",
+ "+TO",
+ "+OUR FRIENDS AT ID SOFTWARE",
+ "",
+ "John Carmack",
+ "John Cash",
+ "Brian Hook",
+ "Adrian Carmack",
+ "Kevin Cloud",
+ "Paul Steed",
+ "Tim Willits",
+ "Christian Antkow",
+ "Paul Jaquays",
+ "Brandon James",
+ "Todd Hollenshead",
+ "Barrett (Bear) Alexander",
+ "Dave \"Zoid\" Kirsch",
+ "Donna Jackson",
+ "",
+ "",
+ "",
+ "+THANKS TO ACTIVISION",
+ "+IN PARTICULAR:",
+ "",
+ "Marty Stratton",
+ "Henk \"The Original Ripper\" Hartong",
+ "Kevin Kraff",
+ "Jamey Gottlieb",
+ "Chris Hepburn",
+ "",
+ "+AND THE GAME TESTERS",
+ "",
+ "Tim Vanlaw",
+ "Doug Jacobs",
+ "Steven Rosenthal",
+ "David Baker",
+ "Chris Campbell",
+ "Aaron Casillas",
+ "Steve Elwell",
+ "Derek Johnstone",
+ "Igor Krinitskiy",
+ "Samantha Lee",
+ "Michael Spann",
+ "Chris Toft",
+ "Juan Valdes",
+ "",
+ "+THANKS TO INTERGRAPH COMPUTER SYTEMS",
+ "+IN PARTICULAR:",
+ "",
+ "Michael T. Nicolaou",
+ "",
+ "",
+ "Quake II Mission Pack: The Reckoning",
+ "(tm) (C)1998 Id Software, Inc. All",
+ "Rights Reserved. Developed by Xatrix",
+ "Entertainment, Inc. for Id Software,",
+ "Inc. Distributed by Activision Inc.",
+ "under license. Quake(R) is a",
+ "registered trademark of Id Software,",
+ "Inc. Quake II Mission Pack: The",
+ "Reckoning(tm), Quake II(tm), the Id",
+ "Software name, the \"Q II\"(tm) logo",
+ "and id(tm) logo are trademarks of Id",
+ "Software, Inc. Activision(R) is a",
+ "registered trademark of Activision,",
+ "Inc. Xatrix(R) is a registered",
+ "trademark of Xatrix Entertainment,",
+ "Inc. All other trademarks and trade",
+ "names are properties of their",
+ "respective owners.",
+ 0
+};
+
+static char *roguecredits[] =
+{
+ "+QUAKE II MISSION PACK 2: GROUND ZERO",
+ "+BY",
+ "+ROGUE ENTERTAINMENT, INC.",
+ "",
+ "+PRODUCED BY",
+ "Jim Molinets",
+ "",
+ "+PROGRAMMING",
+ "Peter Mack",
+ "Patrick Magruder",
+ "",
+ "+LEVEL DESIGN",
+ "Jim Molinets",
+ "Cameron Lamprecht",
+ "Berenger Fish",
+ "Robert Selitto",
+ "Steve Tietze",
+ "Steve Thoms",
+ "",
+ "+ART DIRECTION",
+ "Rich Fleider",
+ "",
+ "+ART",
+ "Rich Fleider",
+ "Steve Maines",
+ "Won Choi",
+ "",
+ "+ANIMATION SEQUENCES",
+ "Creat Studios",
+ "Steve Maines",
+ "",
+ "+ADDITIONAL LEVEL DESIGN",
+ "Rich Fleider",
+ "Steve Maines",
+ "Peter Mack",
+ "",
+ "+SOUND",
+ "James Grunke",
+ "",
+ "+GROUND ZERO THEME",
+ "+AND",
+ "+MUSIC BY",
+ "Sonic Mayhem",
+ "",
+ "+VWEP MODELS",
+ "Brent \"Hentai\" Dill",
+ "",
+ "",
+ "",
+ "+SPECIAL THANKS",
+ "+TO",
+ "+OUR FRIENDS AT ID SOFTWARE",
+ "",
+ "John Carmack",
+ "John Cash",
+ "Brian Hook",
+ "Adrian Carmack",
+ "Kevin Cloud",
+ "Paul Steed",
+ "Tim Willits",
+ "Christian Antkow",
+ "Paul Jaquays",
+ "Brandon James",
+ "Todd Hollenshead",
+ "Barrett (Bear) Alexander",
+ "Katherine Anna Kang",
+ "Donna Jackson",
+ "Dave \"Zoid\" Kirsch",
+ "",
+ "",
+ "",
+ "+THANKS TO ACTIVISION",
+ "+IN PARTICULAR:",
+ "",
+ "Marty Stratton",
+ "Henk Hartong",
+ "Mitch Lasky",
+ "Steve Rosenthal",
+ "Steve Elwell",
+ "",
+ "+AND THE GAME TESTERS",
+ "",
+ "The Ranger Clan",
+ "Dave \"Zoid\" Kirsch",
+ "Nihilistic Software",
+ "Robert Duffy",
+ "",
+ "And Countless Others",
+ "",
+ "",
+ "",
+ "Quake II Mission Pack 2: Ground Zero",
+ "(tm) (C)1998 Id Software, Inc. All",
+ "Rights Reserved. Developed by Rogue",
+ "Entertainment, Inc. for Id Software,",
+ "Inc. Distributed by Activision Inc.",
+ "under license. Quake(R) is a",
+ "registered trademark of Id Software,",
+ "Inc. Quake II Mission Pack 2: Ground",
+ "Zero(tm), Quake II(tm), the Id",
+ "Software name, the \"Q II\"(tm) logo",
+ "and id(tm) logo are trademarks of Id",
+ "Software, Inc. Activision(R) is a",
+ "registered trademark of Activision,",
+ "Inc. Rogue(R) is a registered",
+ "trademark of Rogue Entertainment,",
+ "Inc. All other trademarks and trade",
+ "names are properties of their",
+ "respective owners.",
+ 0
+};
+
+
+void M_Credits_MenuDraw( void )
+{
+ int i, y;
+
+ /*
+ ** draw the credits
+ */
+ for ( i = 0, y = vid.height - ( ( cls.realtime - credits_start_time ) / 40.0F ); credits[i] && y < vid.height; y += 10, i++ )
+ {
+ int j, stringoffset;
+ int bold;
+
+ if ( y <= -8 )
+ continue;
+
+ if ( credits[i][0] == '+' )
+ {
+ bold = true;
+ stringoffset = 1;
+ }
+ else
+ {
+ bold = false;
+ stringoffset = 0;
+ }
+
+ for ( j = 0; credits[i][j+stringoffset]; j++ )
+ {
+ int x;
+
+ x = ( vid.width - strlen( credits[i] ) * 8 - stringoffset * 8 ) / 2 + ( j + stringoffset ) * 8;
+
+ if ( bold )
+ re.DrawChar( x, y, credits[i][j+stringoffset] + 128 );
+ else
+ re.DrawChar( x, y, credits[i][j+stringoffset] );
+ }
+ }
+
+ if ( y < 0 )
+ credits_start_time = cls.realtime;
+}
+
+char *M_Credits_Key( int key )
+{
+ switch (key)
+ {
+ case K_ESCAPE:
+ if (creditsBuffer)
+ FS_FreeFile (creditsBuffer);
+ M_PopMenu ();
+ break;
+ }
+
+ return menu_out_sound;
+
+}
+
+extern int Developer_searchpath (int who);
+
+void M_Menu_Credits_f( void )
+{
+ int n;
+ int count;
+ char *p;
+ int isdeveloper;
+
+ creditsBuffer = NULL;
+ count = FS_LoadFile ("credits", &creditsBuffer);
+ if (count != -1)
+ {
+ p = creditsBuffer;
+ for (n = 0; n < 255; n++)
+ {
+ creditsIndex[n] = p;
+ while (*p != '\r' && *p != '\n')
+ {
+ p++;
+ if (--count == 0)
+ break;
+ }
+ if (*p == '\r')
+ {
+ *p++ = 0;
+ if (--count == 0)
+ break;
+ }
+ *p++ = 0;
+ if (--count == 0)
+ break;
+ }
+ creditsIndex[++n] = 0;
+ credits = creditsIndex;
+ }
+ else
+ {
+ isdeveloper = Developer_searchpath (1);
+
+ if (isdeveloper == 1) // xatrix
+ credits = xatcredits;
+ else if (isdeveloper == 2) // ROGUE
+ credits = roguecredits;
+ else
+ {
+ credits = idcredits;
+ }
+
+ }
+
+ credits_start_time = cls.realtime;
+ M_PushMenu( M_Credits_MenuDraw, M_Credits_Key);
+}
+
+/*
+=============================================================================
+
+GAME MENU
+
+=============================================================================
+*/
+
+static int m_game_cursor;
+
+static menuframework_t s_game_menu;
+static menuaction_t s_easy_game_action;
+static menuaction_t s_medium_game_action;
+static menuaction_t s_hard_game_action;
+static menuaction_t s_load_game_action;
+static menuaction_t s_save_game_action;
+static menuaction_t s_credits_action;
+static menuseparator_t s_blankline;
+
+static void StartGame( void )
+{
+ // disable updates and start the cinematic going
+ cl.servercount = -1;
+ M_ForceMenuOff ();
+ Cvar_SetValue( "deathmatch", 0 );
+ Cvar_SetValue( "coop", 0 );
+
+ Cvar_SetValue( "gamerules", 0 ); //PGM
+
+ Cbuf_AddText ("loading ; killserver ; wait ; newgame\n");
+ cls.key_dest = key_game;
+}
+
+static void EasyGameFunc( void * )
+{
+ Cvar_ForceSet( "skill", "0" );
+ StartGame();
+}
+
+static void MediumGameFunc( void * )
+{
+ Cvar_ForceSet( "skill", "1" );
+ StartGame();
+}
+
+static void HardGameFunc( void * )
+{
+ Cvar_ForceSet( "skill", "2" );
+ StartGame();
+}
+
+static void LoadGameFunc( void * )
+{
+ M_Menu_LoadGame_f ();
+}
+
+static void SaveGameFunc( void * )
+{
+ M_Menu_SaveGame_f();
+}
+
+static void CreditsFunc( void * )
+{
+ M_Menu_Credits_f();
+}
+
+void Game_MenuInit( void )
+{
+ static char *difficulty_names[] =
+ {
+ "easy",
+ "medium",
+ "hard",
+ 0
+ };
+
+ s_game_menu.x = vid.width * 0.50;
+ s_game_menu.nitems = 0;
+
+ s_easy_game_action.generic.type = MTYPE_ACTION;
+ s_easy_game_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_easy_game_action.generic.x = 0;
+ s_easy_game_action.generic.y = 0;
+ s_easy_game_action.generic.name = "easy";
+ s_easy_game_action.generic.callback = EasyGameFunc;
+
+ s_medium_game_action.generic.type = MTYPE_ACTION;
+ s_medium_game_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_medium_game_action.generic.x = 0;
+ s_medium_game_action.generic.y = 10;
+ s_medium_game_action.generic.name = "medium";
+ s_medium_game_action.generic.callback = MediumGameFunc;
+
+ s_hard_game_action.generic.type = MTYPE_ACTION;
+ s_hard_game_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_hard_game_action.generic.x = 0;
+ s_hard_game_action.generic.y = 20;
+ s_hard_game_action.generic.name = "hard";
+ s_hard_game_action.generic.callback = HardGameFunc;
+
+ s_blankline.generic.type = MTYPE_SEPARATOR;
+
+ s_load_game_action.generic.type = MTYPE_ACTION;
+ s_load_game_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_load_game_action.generic.x = 0;
+ s_load_game_action.generic.y = 40;
+ s_load_game_action.generic.name = "load game";
+ s_load_game_action.generic.callback = LoadGameFunc;
+
+ s_save_game_action.generic.type = MTYPE_ACTION;
+ s_save_game_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_save_game_action.generic.x = 0;
+ s_save_game_action.generic.y = 50;
+ s_save_game_action.generic.name = "save game";
+ s_save_game_action.generic.callback = SaveGameFunc;
+
+ s_credits_action.generic.type = MTYPE_ACTION;
+ s_credits_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_credits_action.generic.x = 0;
+ s_credits_action.generic.y = 60;
+ s_credits_action.generic.name = "credits";
+ s_credits_action.generic.callback = CreditsFunc;
+
+ Menu_AddItem( &s_game_menu, ( void * ) &s_easy_game_action );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_medium_game_action );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_hard_game_action );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_load_game_action );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_save_game_action );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_credits_action );
+
+ Menu_Center( &s_game_menu );
+}
+
+void Game_MenuDraw( void )
+{
+ M_Banner( "m_banner_game" );
+ Menu_AdjustCursor( &s_game_menu, 1 );
+ Menu_Draw( &s_game_menu );
+}
+
+char *Game_MenuKey( int key )
+{
+ return Default_MenuKey( &s_game_menu, key );
+}
+
+void M_Menu_Game_f (void)
+{
+ Game_MenuInit();
+ M_PushMenu( Game_MenuDraw, Game_MenuKey );
+ m_game_cursor = 1;
+}
+
+/*
+=============================================================================
+
+LOADGAME MENU
+
+=============================================================================
+*/
+
+#define MAX_SAVEGAMES 15
+
+static menuframework_t s_savegame_menu;
+
+static menuframework_t s_loadgame_menu;
+static menuaction_t s_loadgame_actions[MAX_SAVEGAMES];
+
+char m_savestrings[MAX_SAVEGAMES][32];
+qboolean m_savevalid[MAX_SAVEGAMES];
+
+void Create_Savestrings (void)
+{
+ int i;
+ FILE *f;
+ char name[MAX_OSPATH];
+
+ for (i=0 ; i<MAX_SAVEGAMES ; i++)
+ {
+ Com_sprintf (name, sizeof(name), "%s/save/save%i/server.ssv", FS_Gamedir(), i);
+ f = fopen (name, "rb");
+ if (!f)
+ {
+ strcpy (m_savestrings[i], "<EMPTY>");
+ m_savevalid[i] = false;
+ }
+ else
+ {
+ FS_Read (m_savestrings[i], sizeof(m_savestrings[i]), f);
+ fclose (f);
+ m_savevalid[i] = true;
+ }
+ }
+}
+
+void LoadGameCallback( void *self )
+{
+ menuaction_t *a = ( menuaction_t * ) self;
+
+ if ( m_savevalid[ a->generic.localdata[0] ] )
+ Cbuf_AddText (va("load save%i\n", a->generic.localdata[0] ) );
+ M_ForceMenuOff ();
+}
+
+void LoadGame_MenuInit( void )
+{
+ int i;
+
+ s_loadgame_menu.x = vid.width / 2 - 120;
+ s_loadgame_menu.y = vid.height / 2 - 58;
+ s_loadgame_menu.nitems = 0;
+
+ Create_Savestrings();
+
+ for ( i = 0; i < MAX_SAVEGAMES; i++ )
+ {
+ s_loadgame_actions[i].generic.name = m_savestrings[i];
+ s_loadgame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
+ s_loadgame_actions[i].generic.localdata[0] = i;
+ s_loadgame_actions[i].generic.callback = LoadGameCallback;
+
+ s_loadgame_actions[i].generic.x = 0;
+ s_loadgame_actions[i].generic.y = ( i ) * 10;
+ if (i>0) // separate from autosave
+ s_loadgame_actions[i].generic.y += 10;
+
+ s_loadgame_actions[i].generic.type = MTYPE_ACTION;
+
+ Menu_AddItem( &s_loadgame_menu, &s_loadgame_actions[i] );
+ }
+}
+
+void LoadGame_MenuDraw( void )
+{
+ M_Banner( "m_banner_load_game" );
+// Menu_AdjustCursor( &s_loadgame_menu, 1 );
+ Menu_Draw( &s_loadgame_menu );
+}
+
+char *LoadGame_MenuKey( int key )
+{
+ if ( key == K_ESCAPE || key == K_ENTER )
+ {
+ s_savegame_menu.cursor = s_loadgame_menu.cursor - 1;
+ if ( s_savegame_menu.cursor < 0 )
+ s_savegame_menu.cursor = 0;
+ }
+ return Default_MenuKey( &s_loadgame_menu, key );
+}
+
+void M_Menu_LoadGame_f (void)
+{
+ LoadGame_MenuInit();
+ M_PushMenu( LoadGame_MenuDraw, LoadGame_MenuKey );
+}
+
+
+/*
+=============================================================================
+
+SAVEGAME MENU
+
+=============================================================================
+*/
+static menuframework_t s_savegame_menu;
+static menuaction_t s_savegame_actions[MAX_SAVEGAMES];
+
+void SaveGameCallback( void *self )
+{
+ menuaction_t *a = ( menuaction_t * ) self;
+
+ Cbuf_AddText (va("save save%i\n", a->generic.localdata[0] ));
+ M_ForceMenuOff ();
+}
+
+void SaveGame_MenuDraw( void )
+{
+ M_Banner( "m_banner_save_game" );
+ Menu_AdjustCursor( &s_savegame_menu, 1 );
+ Menu_Draw( &s_savegame_menu );
+}
+
+void SaveGame_MenuInit( void )
+{
+ int i;
+
+ s_savegame_menu.x = vid.width / 2 - 120;
+ s_savegame_menu.y = vid.height / 2 - 58;
+ s_savegame_menu.nitems = 0;
+
+ Create_Savestrings();
+
+ // don't include the autosave slot
+ for ( i = 0; i < MAX_SAVEGAMES-1; i++ )
+ {
+ s_savegame_actions[i].generic.name = m_savestrings[i+1];
+ s_savegame_actions[i].generic.localdata[0] = i+1;
+ s_savegame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
+ s_savegame_actions[i].generic.callback = SaveGameCallback;
+
+ s_savegame_actions[i].generic.x = 0;
+ s_savegame_actions[i].generic.y = ( i ) * 10;
+
+ s_savegame_actions[i].generic.type = MTYPE_ACTION;
+
+ Menu_AddItem( &s_savegame_menu, &s_savegame_actions[i] );
+ }
+}
+
+char *SaveGame_MenuKey( int key )
+{
+ if ( key == K_ENTER || key == K_ESCAPE )
+ {
+ s_loadgame_menu.cursor = s_savegame_menu.cursor - 1;
+ if ( s_loadgame_menu.cursor < 0 )
+ s_loadgame_menu.cursor = 0;
+ }
+ return Default_MenuKey( &s_savegame_menu, key );
+}
+
+void M_Menu_SaveGame_f (void)
+{
+ if (!Com_ServerState())
+ return; // not playing a game
+
+ SaveGame_MenuInit();
+ M_PushMenu( SaveGame_MenuDraw, SaveGame_MenuKey );
+ Create_Savestrings ();
+}
+
+
+/*
+=============================================================================
+
+JOIN SERVER MENU
+
+=============================================================================
+*/
+#define MAX_LOCAL_SERVERS 8
+
+static menuframework_t s_joinserver_menu;
+static menuseparator_t s_joinserver_server_title;
+static menuaction_t s_joinserver_search_action;
+static menuaction_t s_joinserver_address_book_action;
+static menuaction_t s_joinserver_server_actions[MAX_LOCAL_SERVERS];
+
+int m_num_servers;
+#define NO_SERVER_STRING "<no server>"
+
+// user readable information
+static char local_server_names[MAX_LOCAL_SERVERS][80];
+
+// network address
+static netadr_t local_server_netadr[MAX_LOCAL_SERVERS];
+
+void M_AddToServerList (netadr_t adr, char *info)
+{
+ int i;
+
+ if (m_num_servers == MAX_LOCAL_SERVERS)
+ return;
+ while ( *info == ' ' )
+ info++;
+
+ // ignore if duplicated
+ for (i=0 ; i<m_num_servers ; i++)
+ if (!strcmp(info, local_server_names[i]))
+ return;
+
+ local_server_netadr[m_num_servers] = adr;
+ strncpy (local_server_names[m_num_servers], info, sizeof(local_server_names[0])-1);
+ m_num_servers++;
+}
+
+
+void JoinServerFunc( void *self )
+{
+ char buffer[128];
+ int index;
+
+ index = ( menuaction_t * ) self - s_joinserver_server_actions;
+
+ if ( cistrcmp( local_server_names[index], NO_SERVER_STRING ) == 0 )
+ return;
+
+ if (index >= m_num_servers)
+ return;
+
+ Com_sprintf (buffer, sizeof(buffer), "connect %s\n", NET_AdrToString (local_server_netadr[index]));
+ Cbuf_AddText (buffer);
+ M_ForceMenuOff ();
+}
+
+void AddressBookFunc( void * )
+{
+ M_Menu_AddressBook_f();
+}
+
+void NullCursorDraw( void * )
+{
+}
+
+void SearchLocalGames( void )
+{
+ int i;
+
+ m_num_servers = 0;
+ for (i=0 ; i<MAX_LOCAL_SERVERS ; i++)
+ strcpy (local_server_names[i], NO_SERVER_STRING);
+
+ M_DrawTextBox( 8, 120 - 48, 36, 3 );
+ M_Print( 16 + 16, 120 - 48 + 8, "Searching for local servers, this" );
+ M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
+ M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
+
+ // the text box won't show up unless we do a buffer swap
+ re.EndFrame();
+
+ // send out info packets
+ CL_PingServers_f();
+}
+
+void SearchLocalGamesFunc( void * )
+{
+ SearchLocalGames();
+}
+
+void JoinServer_MenuInit( void )
+{
+ int i;
+
+ s_joinserver_menu.x = vid.width * 0.50 - 120;
+ s_joinserver_menu.nitems = 0;
+
+ s_joinserver_address_book_action.generic.type = MTYPE_ACTION;
+ s_joinserver_address_book_action.generic.name = "address book";
+ s_joinserver_address_book_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_joinserver_address_book_action.generic.x = 0;
+ s_joinserver_address_book_action.generic.y = 0;
+ s_joinserver_address_book_action.generic.callback = AddressBookFunc;
+
+ s_joinserver_search_action.generic.type = MTYPE_ACTION;
+ s_joinserver_search_action.generic.name = "refresh server list";
+ s_joinserver_search_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_joinserver_search_action.generic.x = 0;
+ s_joinserver_search_action.generic.y = 10;
+ s_joinserver_search_action.generic.callback = SearchLocalGamesFunc;
+ s_joinserver_search_action.generic.statusbar = "search for servers";
+
+ s_joinserver_server_title.generic.type = MTYPE_SEPARATOR;
+ s_joinserver_server_title.generic.name = "connect to...";
+ s_joinserver_server_title.generic.x = 80;
+ s_joinserver_server_title.generic.y = 30;
+
+ for ( i = 0; i < MAX_LOCAL_SERVERS; i++ )
+ {
+ s_joinserver_server_actions[i].generic.type = MTYPE_ACTION;
+ strcpy (local_server_names[i], NO_SERVER_STRING);
+ s_joinserver_server_actions[i].generic.name = local_server_names[i];
+ s_joinserver_server_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
+ s_joinserver_server_actions[i].generic.x = 0;
+ s_joinserver_server_actions[i].generic.y = 40 + i*10;
+ s_joinserver_server_actions[i].generic.callback = JoinServerFunc;
+ s_joinserver_server_actions[i].generic.statusbar = "press ENTER to connect";
+ }
+
+ Menu_AddItem( &s_joinserver_menu, &s_joinserver_address_book_action );
+ Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_title );
+ Menu_AddItem( &s_joinserver_menu, &s_joinserver_search_action );
+
+ for ( i = 0; i < 8; i++ )
+ Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_actions[i] );
+
+ Menu_Center( &s_joinserver_menu );
+
+ SearchLocalGames();
+}
+
+void JoinServer_MenuDraw(void)
+{
+ M_Banner( "m_banner_join_server" );
+ Menu_Draw( &s_joinserver_menu );
+}
+
+
+char *JoinServer_MenuKey( int key )
+{
+ return Default_MenuKey( &s_joinserver_menu, key );
+}
+
+void M_Menu_JoinServer_f (void)
+{
+ JoinServer_MenuInit();
+ M_PushMenu( JoinServer_MenuDraw, JoinServer_MenuKey );
+}
+
+
+/*
+=============================================================================
+
+START SERVER MENU
+
+=============================================================================
+*/
+static menuframework_t s_startserver_menu;
+static char **mapnames;
+static int nummaps;
+
+static menuaction_t s_startserver_start_action;
+static menuaction_t s_startserver_dmoptions_action;
+static menufield_t s_timelimit_field;
+static menufield_t s_fraglimit_field;
+static menufield_t s_maxclients_field;
+static menufield_t s_hostname_field;
+static menulist_t s_startmap_list;
+static menulist_t s_rules_box;
+
+void DMOptionsFunc( void * )
+{
+ if (s_rules_box.curvalue == 1)
+ return;
+ M_Menu_DMOptions_f();
+}
+
+void RulesChangeFunc ( void * )
+{
+ // DM
+ if (s_rules_box.curvalue == 0)
+ {
+ s_maxclients_field.generic.statusbar = NULL;
+ s_startserver_dmoptions_action.generic.statusbar = NULL;
+ }
+ else if(s_rules_box.curvalue == 1) // coop // PGM
+ {
+ s_maxclients_field.generic.statusbar = "4 maximum for cooperative";
+ if (atoi(s_maxclients_field.buffer) > 4)
+ strcpy( s_maxclients_field.buffer, "4" );
+ s_startserver_dmoptions_action.generic.statusbar = "N/A for cooperative";
+ }
+//=====
+//PGM
+ // ROGUE GAMES
+ else if(Developer_searchpath(2) == 2)
+ {
+ if (s_rules_box.curvalue == 2) // tag
+ {
+ s_maxclients_field.generic.statusbar = NULL;
+ s_startserver_dmoptions_action.generic.statusbar = NULL;
+ }
+/*
+ else if(s_rules_box.curvalue == 3) // deathball
+ {
+ s_maxclients_field.generic.statusbar = NULL;
+ s_startserver_dmoptions_action.generic.statusbar = NULL;
+ }
+*/
+ }
+//PGM
+//=====
+}
+
+void StartServerActionFunc( void * )
+{
+ char startmap[1024];
+ int timelimit;
+ int fraglimit;
+ int maxclients;
+ char *spot;
+
+ strcpy( startmap, strchr( mapnames[s_startmap_list.curvalue], '\n' ) + 1 );
+
+ maxclients = atoi( s_maxclients_field.buffer );
+ timelimit = atoi( s_timelimit_field.buffer );
+ fraglimit = atoi( s_fraglimit_field.buffer );
+
+ Cvar_SetValue( "maxclients", ClampCvar( 0, maxclients, maxclients ) );
+ Cvar_SetValue ("timelimit", ClampCvar( 0, timelimit, timelimit ) );
+ Cvar_SetValue ("fraglimit", ClampCvar( 0, fraglimit, fraglimit ) );
+ Cvar_Set("hostname", s_hostname_field.buffer );
+// Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
+// Cvar_SetValue ("coop", s_rules_box.curvalue );
+
+//PGM
+ if((s_rules_box.curvalue < 2) || (Developer_searchpath(2) != 2))
+ {
+ Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
+ Cvar_SetValue ("coop", s_rules_box.curvalue );
+ Cvar_SetValue ("gamerules", 0 );
+ }
+ else
+ {
+ Cvar_SetValue ("deathmatch", 1 ); // deathmatch is always true for rogue games, right?
+ Cvar_SetValue ("coop", 0 ); // FIXME - this might need to depend on which game we're running
+ Cvar_SetValue ("gamerules", s_rules_box.curvalue );
+ }
+//PGM
+
+ spot = NULL;
+ if (s_rules_box.curvalue == 1) // PGM
+ {
+ if(cistrcmp(startmap, "bunk1") == 0)
+ spot = "start";
+ else if(cistrcmp(startmap, "mintro") == 0)
+ spot = "start";
+ else if(cistrcmp(startmap, "fact1") == 0)
+ spot = "start";
+ else if(cistrcmp(startmap, "power1") == 0)
+ spot = "pstart";
+ else if(cistrcmp(startmap, "biggun") == 0)
+ spot = "bstart";
+ else if(cistrcmp(startmap, "hangar1") == 0)
+ spot = "unitstart";
+ else if(cistrcmp(startmap, "city1") == 0)
+ spot = "unitstart";
+ else if(cistrcmp(startmap, "boss1") == 0)
+ spot = "bosstart";
+ }
+
+ if (spot)
+ {
+ if (Com_ServerState())
+ Cbuf_AddText ("disconnect\n");
+ Cbuf_AddText (va("gamemap \"*%s$%s\"\n", startmap, spot));
+ }
+ else
+ {
+ Cbuf_AddText (va("map %s\n", startmap));
+ }
+
+ M_ForceMenuOff ();
+}
+
+void StartServer_MenuInit( void )
+{
+ static char *dm_coop_names[] =
+ {
+ "deathmatch",
+ "cooperative",
+ 0
+ };
+//=======
+//PGM
+ static char *dm_coop_names_rogue[] =
+ {
+ "deathmatch",
+ "cooperative",
+ "tag",
+// "deathball",
+ 0
+ };
+//PGM
+//=======
+ char *buffer;
+ char mapsname[1024];
+ char *s;
+ int length;
+ int i;
+ FILE *fp;
+
+ /*
+ ** load the list of map names
+ */
+ Com_sprintf( mapsname, sizeof( mapsname ), "%s/maps.lst", FS_Gamedir() );
+ if ( ( fp = fopen( mapsname, "rb" ) ) == 0 )
+ {
+ if ( ( length = FS_LoadFile( "maps.lst", ( void ** ) &buffer ) ) == -1 )
+ Com_Error( ERR_DROP, "couldn't find maps.lst\n" );
+ }
+ else
+ {
+#ifdef _WIN32
+ length = filelength( fileno( fp ) );
+#else
+ fseek(fp, 0, SEEK_END);
+ length = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+#endif
+ buffer = malloc( length );
+ fread( buffer, length, 1, fp );
+ }
+
+ s = buffer;
+
+ i = 0;
+ while ( i < length )
+ {
+ if ( s[i] == '\r' )
+ nummaps++;
+ i++;
+ }
+
+ if ( nummaps == 0 )
+ Com_Error( ERR_DROP, "no maps in maps.lst\n" );
+
+ mapnames = malloc( sizeof( char * ) * ( nummaps + 1 ) );
+ memset( mapnames, 0, sizeof( char * ) * ( nummaps + 1 ) );
+
+ s = buffer;
+
+ for ( i = 0; i < nummaps; i++ )
+ {
+ char shortname[MAX_TOKEN_CHARS];
+ char longname[MAX_TOKEN_CHARS];
+ char scratch[200];
+ int j, l;
+
+ strcpy( shortname, COM_Parse( &s ) );
+ l = strlen(shortname);
+ for (j=0 ; j<l ; j++)
+ shortname[j] = toupper(shortname[j]);
+ strcpy( longname, COM_Parse( &s ) );
+ Com_sprintf( scratch, sizeof( scratch ), "%s\n%s", longname, shortname );
+
+ mapnames[i] = malloc( strlen( scratch ) + 1 );
+ strcpy( mapnames[i], scratch );
+ }
+ mapnames[nummaps] = 0;
+
+ if ( fp != 0 )
+ {
+ free( buffer );
+ }
+ else
+ {
+ FS_FreeFile( buffer );
+ }
+
+ /*
+ ** initialize the menu stuff
+ */
+ s_startserver_menu.x = vid.width * 0.50;
+ s_startserver_menu.nitems = 0;
+
+ s_startmap_list.generic.type = MTYPE_SPINCONTROL;
+ s_startmap_list.generic.x = 0;
+ s_startmap_list.generic.y = 0;
+ s_startmap_list.generic.name = "initial map";
+ s_startmap_list.itemnames = mapnames;
+
+ s_rules_box.generic.type = MTYPE_SPINCONTROL;
+ s_rules_box.generic.x = 0;
+ s_rules_box.generic.y = 20;
+ s_rules_box.generic.name = "rules";
+
+//PGM - rogue games only available with rogue DLL.
+ if(Developer_searchpath(2) == 2)
+ s_rules_box.itemnames = dm_coop_names_rogue;
+ else
+ s_rules_box.itemnames = dm_coop_names;
+//PGM
+
+ if (Cvar_VariableValue("coop"))
+ s_rules_box.curvalue = 1;
+ else
+ s_rules_box.curvalue = 0;
+ s_rules_box.generic.callback = RulesChangeFunc;
+
+ s_timelimit_field.generic.type = MTYPE_FIELD;
+ s_timelimit_field.generic.name = "time limit";
+ s_timelimit_field.generic.flags = QMF_NUMBERSONLY;
+ s_timelimit_field.generic.x = 0;
+ s_timelimit_field.generic.y = 36;
+ s_timelimit_field.generic.statusbar = "0 = no limit";
+ s_timelimit_field.length = 3;
+ s_timelimit_field.visible_length = 3;
+ strcpy( s_timelimit_field.buffer, Cvar_VariableString("timelimit") );
+
+ s_fraglimit_field.generic.type = MTYPE_FIELD;
+ s_fraglimit_field.generic.name = "frag limit";
+ s_fraglimit_field.generic.flags = QMF_NUMBERSONLY;
+ s_fraglimit_field.generic.x = 0;
+ s_fraglimit_field.generic.y = 54;
+ s_fraglimit_field.generic.statusbar = "0 = no limit";
+ s_fraglimit_field.length = 3;
+ s_fraglimit_field.visible_length = 3;
+ strcpy( s_fraglimit_field.buffer, Cvar_VariableString("fraglimit") );
+
+ /*
+ ** maxclients determines the maximum number of players that can join
+ ** the game. If maxclients is only "1" then we should default the menu
+ ** option to 8 players, otherwise use whatever its current value is.
+ ** Clamping will be done when the server is actually started.
+ */
+ s_maxclients_field.generic.type = MTYPE_FIELD;
+ s_maxclients_field.generic.name = "max players";
+ s_maxclients_field.generic.flags = QMF_NUMBERSONLY;
+ s_maxclients_field.generic.x = 0;
+ s_maxclients_field.generic.y = 72;
+ s_maxclients_field.generic.statusbar = NULL;
+ s_maxclients_field.length = 3;
+ s_maxclients_field.visible_length = 3;
+ if ( Cvar_VariableValue( "maxclients" ) == 1 )
+ strcpy( s_maxclients_field.buffer, "8" );
+ else
+ strcpy( s_maxclients_field.buffer, Cvar_VariableString("maxclients") );
+
+ s_hostname_field.generic.type = MTYPE_FIELD;
+ s_hostname_field.generic.name = "hostname";
+ s_hostname_field.generic.flags = 0;
+ s_hostname_field.generic.x = 0;
+ s_hostname_field.generic.y = 90;
+ s_hostname_field.generic.statusbar = NULL;
+ s_hostname_field.length = 12;
+ s_hostname_field.visible_length = 12;
+ strcpy( s_hostname_field.buffer, Cvar_VariableString("hostname") );
+
+ s_startserver_dmoptions_action.generic.type = MTYPE_ACTION;
+ s_startserver_dmoptions_action.generic.name = " deathmatch flags";
+ s_startserver_dmoptions_action.generic.flags= QMF_LEFT_JUSTIFY;
+ s_startserver_dmoptions_action.generic.x = 24;
+ s_startserver_dmoptions_action.generic.y = 108;
+ s_startserver_dmoptions_action.generic.statusbar = NULL;
+ s_startserver_dmoptions_action.generic.callback = DMOptionsFunc;
+
+ s_startserver_start_action.generic.type = MTYPE_ACTION;
+ s_startserver_start_action.generic.name = " begin";
+ s_startserver_start_action.generic.flags= QMF_LEFT_JUSTIFY;
+ s_startserver_start_action.generic.x = 24;
+ s_startserver_start_action.generic.y = 128;
+ s_startserver_start_action.generic.callback = StartServerActionFunc;
+
+ Menu_AddItem( &s_startserver_menu, &s_startmap_list );
+ Menu_AddItem( &s_startserver_menu, &s_rules_box );
+ Menu_AddItem( &s_startserver_menu, &s_timelimit_field );
+ Menu_AddItem( &s_startserver_menu, &s_fraglimit_field );
+ Menu_AddItem( &s_startserver_menu, &s_maxclients_field );
+ Menu_AddItem( &s_startserver_menu, &s_hostname_field );
+ Menu_AddItem( &s_startserver_menu, &s_startserver_dmoptions_action );
+ Menu_AddItem( &s_startserver_menu, &s_startserver_start_action );
+
+ Menu_Center( &s_startserver_menu );
+
+ // call this now to set proper inital state
+ RulesChangeFunc ( NULL );
+}
+
+void StartServer_MenuDraw(void)
+{
+ Menu_Draw( &s_startserver_menu );
+}
+
+char *StartServer_MenuKey( int key )
+{
+ if ( key == K_ESCAPE )
+ {
+ if ( mapnames )
+ {
+ int i;
+
+ for ( i = 0; i < nummaps; i++ )
+ free( mapnames[i] );
+ free( mapnames );
+ }
+ mapnames = 0;
+ nummaps = 0;
+ }
+
+ return Default_MenuKey( &s_startserver_menu, key );
+}
+
+void M_Menu_StartServer_f (void)
+{
+ StartServer_MenuInit();
+ M_PushMenu( StartServer_MenuDraw, StartServer_MenuKey );
+}
+
+/*
+=============================================================================
+
+DMOPTIONS BOOK MENU
+
+=============================================================================
+*/
+static char dmoptions_statusbar[128];
+
+static menuframework_t s_dmoptions_menu;
+
+static menulist_t s_friendlyfire_box;
+static menulist_t s_falls_box;
+static menulist_t s_weapons_stay_box;
+static menulist_t s_instant_powerups_box;
+static menulist_t s_powerups_box;
+static menulist_t s_health_box;
+static menulist_t s_spawn_farthest_box;
+static menulist_t s_teamplay_box;
+static menulist_t s_samelevel_box;
+static menulist_t s_force_respawn_box;
+static menulist_t s_armor_box;
+static menulist_t s_allow_exit_box;
+static menulist_t s_infinite_ammo_box;
+static menulist_t s_fixed_fov_box;
+static menulist_t s_quad_drop_box;
+
+//ROGUE
+static menulist_t s_no_mines_box;
+static menulist_t s_no_nukes_box;
+static menulist_t s_stack_double_box;
+static menulist_t s_no_spheres_box;
+//ROGUE
+
+static void DMFlagCallback( void *self )
+{
+ menulist_t *f = ( menulist_t * ) self;
+ int flags;
+ int bit = 0;
+
+ flags = Cvar_VariableValue( "dmflags" );
+
+ if ( f == &s_friendlyfire_box )
+ {
+ if ( f->curvalue )
+ flags &= ~DF_NO_FRIENDLY_FIRE;
+ else
+ flags |= DF_NO_FRIENDLY_FIRE;
+ goto setvalue;
+ }
+ else if ( f == &s_falls_box )
+ {
+ if ( f->curvalue )
+ flags &= ~DF_NO_FALLING;
+ else
+ flags |= DF_NO_FALLING;
+ goto setvalue;
+ }
+ else if ( f == &s_weapons_stay_box )
+ {
+ bit = DF_WEAPONS_STAY;
+ }
+ else if ( f == &s_instant_powerups_box )
+ {
+ bit = DF_INSTANT_ITEMS;
+ }
+ else if ( f == &s_allow_exit_box )
+ {
+ bit = DF_ALLOW_EXIT;
+ }
+ else if ( f == &s_powerups_box )
+ {
+ if ( f->curvalue )
+ flags &= ~DF_NO_ITEMS;
+ else
+ flags |= DF_NO_ITEMS;
+ goto setvalue;
+ }
+ else if ( f == &s_health_box )
+ {
+ if ( f->curvalue )
+ flags &= ~DF_NO_HEALTH;
+ else
+ flags |= DF_NO_HEALTH;
+ goto setvalue;
+ }
+ else if ( f == &s_spawn_farthest_box )
+ {
+ bit = DF_SPAWN_FARTHEST;
+ }
+ else if ( f == &s_teamplay_box )
+ {
+ if ( f->curvalue == 1 )
+ {
+ flags |= DF_SKINTEAMS;
+ flags &= ~DF_MODELTEAMS;
+ }
+ else if ( f->curvalue == 2 )
+ {
+ flags |= DF_MODELTEAMS;
+ flags &= ~DF_SKINTEAMS;
+ }
+ else
+ {
+ flags &= ~( DF_MODELTEAMS | DF_SKINTEAMS );
+ }
+
+ goto setvalue;
+ }
+ else if ( f == &s_samelevel_box )
+ {
+ bit = DF_SAME_LEVEL;
+ }
+ else if ( f == &s_force_respawn_box )
+ {
+ bit = DF_FORCE_RESPAWN;
+ }
+ else if ( f == &s_armor_box )
+ {
+ if ( f->curvalue )
+ flags &= ~DF_NO_ARMOR;
+ else
+ flags |= DF_NO_ARMOR;
+ goto setvalue;
+ }
+ else if ( f == &s_infinite_ammo_box )
+ {
+ bit = DF_INFINITE_AMMO;
+ }
+ else if ( f == &s_fixed_fov_box )
+ {
+ bit = DF_FIXED_FOV;
+ }
+ else if ( f == &s_quad_drop_box )
+ {
+ bit = DF_QUAD_DROP;
+ }
+
+//=======
+//ROGUE
+ else if (Developer_searchpath(2) == 2)
+ {
+ if ( f == &s_no_mines_box)
+ {
+ bit = DF_NO_MINES;
+ }
+ else if ( f == &s_no_nukes_box)
+ {
+ bit = DF_NO_NUKES;
+ }
+ else if ( f == &s_stack_double_box)
+ {
+ bit = DF_NO_STACK_DOUBLE;
+ }
+ else if ( f == &s_no_spheres_box)
+ {
+ bit = DF_NO_SPHERES;
+ }
+ }
+//ROGUE
+//=======
+
+ if ( f )
+ {
+ if ( f->curvalue == 0 )
+ flags &= ~bit;
+ else
+ flags |= bit;
+ }
+
+setvalue:
+ Cvar_SetValue ("dmflags", flags);
+
+ Com_sprintf( dmoptions_statusbar, sizeof( dmoptions_statusbar ), "dmflags = %d", flags );
+
+}
+
+void DMOptions_MenuInit( void )
+{
+ static char *yes_no_names[] =
+ {
+ "no", "yes", 0
+ };
+ static char *teamplay_names[] =
+ {
+ "disabled", "by skin", "by model", 0
+ };
+ int dmflags = Cvar_VariableValue( "dmflags" );
+ int y = 0;
+
+ s_dmoptions_menu.x = vid.width * 0.50;
+ s_dmoptions_menu.nitems = 0;
+
+ s_falls_box.generic.type = MTYPE_SPINCONTROL;
+ s_falls_box.generic.x = 0;
+ s_falls_box.generic.y = y;
+ s_falls_box.generic.name = "falling damage";
+ s_falls_box.generic.callback = DMFlagCallback;
+ s_falls_box.itemnames = yes_no_names;
+ s_falls_box.curvalue = ( dmflags & DF_NO_FALLING ) == 0;
+
+ s_weapons_stay_box.generic.type = MTYPE_SPINCONTROL;
+ s_weapons_stay_box.generic.x = 0;
+ s_weapons_stay_box.generic.y = y += 10;
+ s_weapons_stay_box.generic.name = "weapons stay";
+ s_weapons_stay_box.generic.callback = DMFlagCallback;
+ s_weapons_stay_box.itemnames = yes_no_names;
+ s_weapons_stay_box.curvalue = ( dmflags & DF_WEAPONS_STAY ) != 0;
+
+ s_instant_powerups_box.generic.type = MTYPE_SPINCONTROL;
+ s_instant_powerups_box.generic.x = 0;
+ s_instant_powerups_box.generic.y = y += 10;
+ s_instant_powerups_box.generic.name = "instant powerups";
+ s_instant_powerups_box.generic.callback = DMFlagCallback;
+ s_instant_powerups_box.itemnames = yes_no_names;
+ s_instant_powerups_box.curvalue = ( dmflags & DF_INSTANT_ITEMS ) != 0;
+
+ s_powerups_box.generic.type = MTYPE_SPINCONTROL;
+ s_powerups_box.generic.x = 0;
+ s_powerups_box.generic.y = y += 10;
+ s_powerups_box.generic.name = "allow powerups";
+ s_powerups_box.generic.callback = DMFlagCallback;
+ s_powerups_box.itemnames = yes_no_names;
+ s_powerups_box.curvalue = ( dmflags & DF_NO_ITEMS ) == 0;
+
+ s_health_box.generic.type = MTYPE_SPINCONTROL;
+ s_health_box.generic.x = 0;
+ s_health_box.generic.y = y += 10;
+ s_health_box.generic.callback = DMFlagCallback;
+ s_health_box.generic.name = "allow health";
+ s_health_box.itemnames = yes_no_names;
+ s_health_box.curvalue = ( dmflags & DF_NO_HEALTH ) == 0;
+
+ s_armor_box.generic.type = MTYPE_SPINCONTROL;
+ s_armor_box.generic.x = 0;
+ s_armor_box.generic.y = y += 10;
+ s_armor_box.generic.name = "allow armor";
+ s_armor_box.generic.callback = DMFlagCallback;
+ s_armor_box.itemnames = yes_no_names;
+ s_armor_box.curvalue = ( dmflags & DF_NO_ARMOR ) == 0;
+
+ s_spawn_farthest_box.generic.type = MTYPE_SPINCONTROL;
+ s_spawn_farthest_box.generic.x = 0;
+ s_spawn_farthest_box.generic.y = y += 10;
+ s_spawn_farthest_box.generic.name = "spawn farthest";
+ s_spawn_farthest_box.generic.callback = DMFlagCallback;
+ s_spawn_farthest_box.itemnames = yes_no_names;
+ s_spawn_farthest_box.curvalue = ( dmflags & DF_SPAWN_FARTHEST ) != 0;
+
+ s_samelevel_box.generic.type = MTYPE_SPINCONTROL;
+ s_samelevel_box.generic.x = 0;
+ s_samelevel_box.generic.y = y += 10;
+ s_samelevel_box.generic.name = "same map";
+ s_samelevel_box.generic.callback = DMFlagCallback;
+ s_samelevel_box.itemnames = yes_no_names;
+ s_samelevel_box.curvalue = ( dmflags & DF_SAME_LEVEL ) != 0;
+
+ s_force_respawn_box.generic.type = MTYPE_SPINCONTROL;
+ s_force_respawn_box.generic.x = 0;
+ s_force_respawn_box.generic.y = y += 10;
+ s_force_respawn_box.generic.name = "force respawn";
+ s_force_respawn_box.generic.callback = DMFlagCallback;
+ s_force_respawn_box.itemnames = yes_no_names;
+ s_force_respawn_box.curvalue = ( dmflags & DF_FORCE_RESPAWN ) != 0;
+
+ s_teamplay_box.generic.type = MTYPE_SPINCONTROL;
+ s_teamplay_box.generic.x = 0;
+ s_teamplay_box.generic.y = y += 10;
+ s_teamplay_box.generic.name = "teamplay";
+ s_teamplay_box.generic.callback = DMFlagCallback;
+ s_teamplay_box.itemnames = teamplay_names;
+
+ s_allow_exit_box.generic.type = MTYPE_SPINCONTROL;
+ s_allow_exit_box.generic.x = 0;
+ s_allow_exit_box.generic.y = y += 10;
+ s_allow_exit_box.generic.name = "allow exit";
+ s_allow_exit_box.generic.callback = DMFlagCallback;
+ s_allow_exit_box.itemnames = yes_no_names;
+ s_allow_exit_box.curvalue = ( dmflags & DF_ALLOW_EXIT ) != 0;
+
+ s_infinite_ammo_box.generic.type = MTYPE_SPINCONTROL;
+ s_infinite_ammo_box.generic.x = 0;
+ s_infinite_ammo_box.generic.y = y += 10;
+ s_infinite_ammo_box.generic.name = "infinite ammo";
+ s_infinite_ammo_box.generic.callback = DMFlagCallback;
+ s_infinite_ammo_box.itemnames = yes_no_names;
+ s_infinite_ammo_box.curvalue = ( dmflags & DF_INFINITE_AMMO ) != 0;
+
+ s_fixed_fov_box.generic.type = MTYPE_SPINCONTROL;
+ s_fixed_fov_box.generic.x = 0;
+ s_fixed_fov_box.generic.y = y += 10;
+ s_fixed_fov_box.generic.name = "fixed FOV";
+ s_fixed_fov_box.generic.callback = DMFlagCallback;
+ s_fixed_fov_box.itemnames = yes_no_names;
+ s_fixed_fov_box.curvalue = ( dmflags & DF_FIXED_FOV ) != 0;
+
+ s_quad_drop_box.generic.type = MTYPE_SPINCONTROL;
+ s_quad_drop_box.generic.x = 0;
+ s_quad_drop_box.generic.y = y += 10;
+ s_quad_drop_box.generic.name = "quad drop";
+ s_quad_drop_box.generic.callback = DMFlagCallback;
+ s_quad_drop_box.itemnames = yes_no_names;
+ s_quad_drop_box.curvalue = ( dmflags & DF_QUAD_DROP ) != 0;
+
+ s_friendlyfire_box.generic.type = MTYPE_SPINCONTROL;
+ s_friendlyfire_box.generic.x = 0;
+ s_friendlyfire_box.generic.y = y += 10;
+ s_friendlyfire_box.generic.name = "friendly fire";
+ s_friendlyfire_box.generic.callback = DMFlagCallback;
+ s_friendlyfire_box.itemnames = yes_no_names;
+ s_friendlyfire_box.curvalue = ( dmflags & DF_NO_FRIENDLY_FIRE ) == 0;
+
+//============
+//ROGUE
+ if(Developer_searchpath(2) == 2)
+ {
+ s_no_mines_box.generic.type = MTYPE_SPINCONTROL;
+ s_no_mines_box.generic.x = 0;
+ s_no_mines_box.generic.y = y += 10;
+ s_no_mines_box.generic.name = "remove mines";
+ s_no_mines_box.generic.callback = DMFlagCallback;
+ s_no_mines_box.itemnames = yes_no_names;
+ s_no_mines_box.curvalue = ( dmflags & DF_NO_MINES ) != 0;
+
+ s_no_nukes_box.generic.type = MTYPE_SPINCONTROL;
+ s_no_nukes_box.generic.x = 0;
+ s_no_nukes_box.generic.y = y += 10;
+ s_no_nukes_box.generic.name = "remove nukes";
+ s_no_nukes_box.generic.callback = DMFlagCallback;
+ s_no_nukes_box.itemnames = yes_no_names;
+ s_no_nukes_box.curvalue = ( dmflags & DF_NO_NUKES ) != 0;
+
+ s_stack_double_box.generic.type = MTYPE_SPINCONTROL;
+ s_stack_double_box.generic.x = 0;
+ s_stack_double_box.generic.y = y += 10;
+ s_stack_double_box.generic.name = "2x/4x stacking off";
+ s_stack_double_box.generic.callback = DMFlagCallback;
+ s_stack_double_box.itemnames = yes_no_names;
+ s_stack_double_box.curvalue = ( dmflags & DF_NO_STACK_DOUBLE ) != 0;
+
+ s_no_spheres_box.generic.type = MTYPE_SPINCONTROL;
+ s_no_spheres_box.generic.x = 0;
+ s_no_spheres_box.generic.y = y += 10;
+ s_no_spheres_box.generic.name = "remove spheres";
+ s_no_spheres_box.generic.callback = DMFlagCallback;
+ s_no_spheres_box.itemnames = yes_no_names;
+ s_no_spheres_box.curvalue = ( dmflags & DF_NO_SPHERES ) != 0;
+
+ }
+//ROGUE
+//============
+
+ Menu_AddItem( &s_dmoptions_menu, &s_falls_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_weapons_stay_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_instant_powerups_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_powerups_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_health_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_armor_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_spawn_farthest_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_samelevel_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_force_respawn_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_teamplay_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_allow_exit_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_infinite_ammo_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_fixed_fov_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_quad_drop_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_friendlyfire_box );
+
+//=======
+//ROGUE
+ if(Developer_searchpath(2) == 2)
+ {
+ Menu_AddItem( &s_dmoptions_menu, &s_no_mines_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_no_nukes_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_stack_double_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_no_spheres_box );
+ }
+//ROGUE
+//=======
+
+ Menu_Center( &s_dmoptions_menu );
+
+ // set the original dmflags statusbar
+ DMFlagCallback( 0 );
+ Menu_SetStatusBar( &s_dmoptions_menu, dmoptions_statusbar );
+}
+
+void DMOptions_MenuDraw(void)
+{
+ Menu_Draw( &s_dmoptions_menu );
+}
+
+char *DMOptions_MenuKey( int key )
+{
+ return Default_MenuKey( &s_dmoptions_menu, key );
+}
+
+void M_Menu_DMOptions_f (void)
+{
+ DMOptions_MenuInit();
+ M_PushMenu( DMOptions_MenuDraw, DMOptions_MenuKey );
+}
+
+/*
+=============================================================================
+
+DOWNLOADOPTIONS BOOK MENU
+
+=============================================================================
+*/
+static menuframework_t s_downloadoptions_menu;
+
+static menuseparator_t s_download_title;
+static menulist_t s_allow_download_box;
+static menulist_t s_allow_download_maps_box;
+static menulist_t s_allow_download_models_box;
+static menulist_t s_allow_download_players_box;
+static menulist_t s_allow_download_sounds_box;
+
+static void DownloadCallback( void *self )
+{
+ menulist_t *f = ( menulist_t * ) self;
+
+ if (f == &s_allow_download_box)
+ {
+ Cvar_SetValue("allow_download", f->curvalue);
+ }
+
+ else if (f == &s_allow_download_maps_box)
+ {
+ Cvar_SetValue("allow_download_maps", f->curvalue);
+ }
+
+ else if (f == &s_allow_download_models_box)
+ {
+ Cvar_SetValue("allow_download_models", f->curvalue);
+ }
+
+ else if (f == &s_allow_download_players_box)
+ {
+ Cvar_SetValue("allow_download_players", f->curvalue);
+ }
+
+ else if (f == &s_allow_download_sounds_box)
+ {
+ Cvar_SetValue("allow_download_sounds", f->curvalue);
+ }
+}
+
+void DownloadOptions_MenuInit( void )
+{
+ static char *yes_no_names[] =
+ {
+ "no", "yes", 0
+ };
+ int y = 0;
+
+ s_downloadoptions_menu.x = vid.width * 0.50;
+ s_downloadoptions_menu.nitems = 0;
+
+ s_download_title.generic.type = MTYPE_SEPARATOR;
+ s_download_title.generic.name = "Download Options";
+ s_download_title.generic.x = 48;
+ s_download_title.generic.y = y;
+
+ s_allow_download_box.generic.type = MTYPE_SPINCONTROL;
+ s_allow_download_box.generic.x = 0;
+ s_allow_download_box.generic.y = y += 20;
+ s_allow_download_box.generic.name = "allow downloading";
+ s_allow_download_box.generic.callback = DownloadCallback;
+ s_allow_download_box.itemnames = yes_no_names;
+ s_allow_download_box.curvalue = (Cvar_VariableValue("allow_download") != 0);
+
+ s_allow_download_maps_box.generic.type = MTYPE_SPINCONTROL;
+ s_allow_download_maps_box.generic.x = 0;
+ s_allow_download_maps_box.generic.y = y += 20;
+ s_allow_download_maps_box.generic.name = "maps";
+ s_allow_download_maps_box.generic.callback = DownloadCallback;
+ s_allow_download_maps_box.itemnames = yes_no_names;
+ s_allow_download_maps_box.curvalue = (Cvar_VariableValue("allow_download_maps") != 0);
+
+ s_allow_download_players_box.generic.type = MTYPE_SPINCONTROL;
+ s_allow_download_players_box.generic.x = 0;
+ s_allow_download_players_box.generic.y = y += 10;
+ s_allow_download_players_box.generic.name = "player models/skins";
+ s_allow_download_players_box.generic.callback = DownloadCallback;
+ s_allow_download_players_box.itemnames = yes_no_names;
+ s_allow_download_players_box.curvalue = (Cvar_VariableValue("allow_download_players") != 0);
+
+ s_allow_download_models_box.generic.type = MTYPE_SPINCONTROL;
+ s_allow_download_models_box.generic.x = 0;
+ s_allow_download_models_box.generic.y = y += 10;
+ s_allow_download_models_box.generic.name = "models";
+ s_allow_download_models_box.generic.callback = DownloadCallback;
+ s_allow_download_models_box.itemnames = yes_no_names;
+ s_allow_download_models_box.curvalue = (Cvar_VariableValue("allow_download_models") != 0);
+
+ s_allow_download_sounds_box.generic.type = MTYPE_SPINCONTROL;
+ s_allow_download_sounds_box.generic.x = 0;
+ s_allow_download_sounds_box.generic.y = y += 10;
+ s_allow_download_sounds_box.generic.name = "sounds";
+ s_allow_download_sounds_box.generic.callback = DownloadCallback;
+ s_allow_download_sounds_box.itemnames = yes_no_names;
+ s_allow_download_sounds_box.curvalue = (Cvar_VariableValue("allow_download_sounds") != 0);
+
+ Menu_AddItem( &s_downloadoptions_menu, &s_download_title );
+ Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_box );
+ Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_maps_box );
+ Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_players_box );
+ Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_models_box );
+ Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_sounds_box );
+
+ Menu_Center( &s_downloadoptions_menu );
+
+ // skip over title
+ if (s_downloadoptions_menu.cursor == 0)
+ s_downloadoptions_menu.cursor = 1;
+}
+
+void DownloadOptions_MenuDraw(void)
+{
+ Menu_Draw( &s_downloadoptions_menu );
+}
+
+char *DownloadOptions_MenuKey( int key )
+{
+ return Default_MenuKey( &s_downloadoptions_menu, key );
+}
+
+void M_Menu_DownloadOptions_f (void)
+{
+ DownloadOptions_MenuInit();
+ M_PushMenu( DownloadOptions_MenuDraw, DownloadOptions_MenuKey );
+}
+/*
+=============================================================================
+
+ADDRESS BOOK MENU
+
+=============================================================================
+*/
+#define NUM_ADDRESSBOOK_ENTRIES 9
+
+static menuframework_t s_addressbook_menu;
+static menufield_t s_addressbook_fields[NUM_ADDRESSBOOK_ENTRIES];
+
+void AddressBook_MenuInit( void )
+{
+ int i;
+
+ s_addressbook_menu.x = vid.width / 2 - 142;
+ s_addressbook_menu.y = vid.height / 2 - 58;
+ s_addressbook_menu.nitems = 0;
+
+ for ( i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++ )
+ {
+ cvar_t *adr;
+ char buffer[20];
+
+ Com_sprintf( buffer, sizeof( buffer ), "adr%d", i );
+
+ adr = Cvar_Get( buffer, "", CVAR_ARCHIVE );
+
+ s_addressbook_fields[i].generic.type = MTYPE_FIELD;
+ s_addressbook_fields[i].generic.name = 0;
+ s_addressbook_fields[i].generic.callback = 0;
+ s_addressbook_fields[i].generic.x = 0;
+ s_addressbook_fields[i].generic.y = i * 18 + 0;
+ s_addressbook_fields[i].generic.localdata[0] = i;
+ s_addressbook_fields[i].cursor = 0;
+ s_addressbook_fields[i].length = 60;
+ s_addressbook_fields[i].visible_length = 30;
+
+ strcpy( s_addressbook_fields[i].buffer, adr->string );
+
+ Menu_AddItem( &s_addressbook_menu, &s_addressbook_fields[i] );
+ }
+}
+
+char *AddressBook_MenuKey( int key )
+{
+ if ( key == K_ESCAPE )
+ {
+ int index;
+ char buffer[20];
+
+ for ( index = 0; index < NUM_ADDRESSBOOK_ENTRIES; index++ )
+ {
+ Com_sprintf( buffer, sizeof( buffer ), "adr%d", index );
+ Cvar_Set( buffer, s_addressbook_fields[index].buffer );
+ }
+ }
+ return Default_MenuKey( &s_addressbook_menu, key );
+}
+
+void AddressBook_MenuDraw(void)
+{
+ M_Banner( "m_banner_addressbook" );
+ Menu_Draw( &s_addressbook_menu );
+}
+
+void M_Menu_AddressBook_f(void)
+{
+ AddressBook_MenuInit();
+ M_PushMenu( AddressBook_MenuDraw, AddressBook_MenuKey );
+}
+
+/*
+=============================================================================
+
+PLAYER CONFIG MENU
+
+=============================================================================
+*/
+static menuframework_t s_player_config_menu;
+static menufield_t s_player_name_field;
+static menulist_t s_player_model_box;
+static menulist_t s_player_skin_box;
+static menulist_t s_player_handedness_box;
+static menulist_t s_player_rate_box;
+static menuseparator_t s_player_skin_title;
+static menuseparator_t s_player_model_title;
+static menuseparator_t s_player_hand_title;
+static menuseparator_t s_player_rate_title;
+static menuaction_t s_player_download_action;
+
+#define MAX_DISPLAYNAME 16
+#define MAX_PLAYERMODELS 1024
+
+typedef struct
+{
+ int nskins;
+ char **skindisplaynames;
+ char displayname[MAX_DISPLAYNAME];
+ char directory[MAX_QPATH];
+} playermodelinfo_s;
+
+static playermodelinfo_s s_pmi[MAX_PLAYERMODELS];
+static char *s_pmnames[MAX_PLAYERMODELS];
+static int s_numplayermodels;
+
+static int rate_tbl[] = { 2500, 3200, 5000, 10000, 25000, 0 };
+static char *rate_names[] = { "28.8 Modem", "33.6 Modem", "Single ISDN",
+ "Dual ISDN/Cable", "T1/LAN", "User defined", 0 };
+
+void DownloadOptionsFunc( void * )
+{
+ M_Menu_DownloadOptions_f();
+}
+
+static void HandednessCallback( void * )
+{
+ Cvar_SetValue( "hand", s_player_handedness_box.curvalue );
+}
+
+static void RateCallback( void * )
+{
+ if (s_player_rate_box.curvalue != sizeof(rate_tbl) / sizeof(*rate_tbl) - 1)
+ Cvar_SetValue( "rate", rate_tbl[s_player_rate_box.curvalue] );
+}
+
+static void ModelCallback( void * )
+{
+ s_player_skin_box.itemnames = s_pmi[s_player_model_box.curvalue].skindisplaynames;
+ s_player_skin_box.curvalue = 0;
+}
+
+static void FreeFileList( char **list, int n )
+{
+ int i;
+
+ for ( i = 0; i < n; i++ )
+ {
+ if ( list[i] )
+ {
+ free( list[i] );
+ list[i] = 0;
+ }
+ }
+ free( list );
+}
+
+static qboolean IconOfSkinExists( char *skin, char **pcxfiles, int npcxfiles )
+{
+ int i;
+ char scratch[1024];
+
+ strcpy( scratch, skin );
+ *strrchr( scratch, '.' ) = 0;
+ strcat( scratch, "_i.pcx" );
+
+ for ( i = 0; i < npcxfiles; i++ )
+ {
+ if ( strcmp( pcxfiles[i], scratch ) == 0 )
+ return true;
+ }
+
+ return false;
+}
+
+static qboolean PlayerConfig_ScanDirectories( void )
+{
+ char findname[1024];
+ char scratch[1024];
+ int ndirs = 0, npms;
+ char **dirnames = NULL;
+ char *path = NULL;
+ int i;
+
+ extern char **FS_ListFiles( char *, int *, unsigned, unsigned );
+
+ s_numplayermodels = 0;
+
+ /*
+ ** get a list of directories
+ */
+ do
+ {
+ if ( ( path = FS_NextPath( path ) ) == NULL)
+ break;
+ Com_sprintf( findname, sizeof(findname), "%s/players/*.*", path );
+
+ if ( ( dirnames = FS_ListFiles( findname, &ndirs, SFF_SUBDIR, 0 ) ) != 0 )
+ break;
+ } while ( path );
+
+ if ( !dirnames )
+ return false;
+
+ /*
+ ** go through the subdirectories
+ */
+ npms = ndirs;
+ if ( npms > MAX_PLAYERMODELS )
+ npms = MAX_PLAYERMODELS;
+
+ for ( i = 0; i < npms; i++ )
+ {
+ int k, s;
+ char *a, *b, *c;
+ char **pcxnames;
+ char **skinnames;
+ int npcxfiles;
+ int nskins = 0;
+
+ if ( dirnames[i] == 0 )
+ continue;
+
+ // verify the existence of tris.md2
+ strcpy( scratch, dirnames[i] );
+ strcat( scratch, "/tris.md2" );
+ if ( !Sys_FindFirst( scratch, 0, SFF_SUBDIR ) )
+ {
+ free( dirnames[i] );
+ dirnames[i] = 0;
+ Sys_FindClose();
+ continue;
+ }
+ Sys_FindClose();
+
+ // verify the existence of at least one pcx skin
+ strcpy( scratch, dirnames[i] );
+ strcat( scratch, "/*.pcx" );
+ pcxnames = FS_ListFiles( scratch, &npcxfiles, 0, SFF_SUBDIR);
+
+ if ( !pcxnames )
+ {
+ free( dirnames[i] );
+ dirnames[i] = 0;
+ continue;
+ }
+
+ // count valid skins, which consist of a skin with a matching "_i" icon
+ for ( k = 0; k < npcxfiles-1; k++ )
+ {
+ if ( !strstr( pcxnames[k], "_i.pcx" ) )
+ {
+ if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
+ {
+ nskins++;
+ }
+ }
+ }
+ if ( !nskins )
+ continue;
+
+ skinnames = malloc( sizeof( char * ) * ( nskins + 1 ) );
+ memset( skinnames, 0, sizeof( char * ) * ( nskins + 1 ) );
+
+ // copy the valid skins
+ for ( s = 0, k = 0; k < npcxfiles-1; k++ )
+ {
+ char *a, *b, *c;
+
+ if ( !strstr( pcxnames[k], "_i.pcx" ) )
+ {
+ if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
+ {
+ a = strrchr( pcxnames[k], '/' );
+ b = strrchr( pcxnames[k], '\\' );
+
+ if ( a > b )
+ c = a;
+ else
+ c = b;
+
+ strcpy( scratch, c + 1 );
+
+ if ( strrchr( scratch, '.' ) )
+ *strrchr( scratch, '.' ) = 0;
+
+ skinnames[s] = strdup( scratch );
+ s++;
+ }
+ }
+ }
+
+ // at this point we have a valid player model
+ s_pmi[s_numplayermodels].nskins = nskins;
+ s_pmi[s_numplayermodels].skindisplaynames = skinnames;
+
+ // make short name for the model
+ a = strrchr( dirnames[i], '/' );
+ b = strrchr( dirnames[i], '\\' );
+
+ if ( a > b )
+ c = a;
+ else
+ c = b;
+
+ strncpy( s_pmi[s_numplayermodels].displayname, c + 1, MAX_DISPLAYNAME-1 );
+ strcpy( s_pmi[s_numplayermodels].directory, c + 1 );
+
+ FreeFileList( pcxnames, npcxfiles );
+
+ s_numplayermodels++;
+ }
+ if ( dirnames )
+ FreeFileList( dirnames, ndirs );
+ return true;
+}
+
+static int pmicmpfnc( void *_a, void *_b )
+{
+ playermodelinfo_s *a = ( playermodelinfo_s * ) _a;
+ playermodelinfo_s *b = ( playermodelinfo_s * ) _b;
+
+ /*
+ ** sort by male, female, then alphabetical
+ */
+ if ( strcmp( a->directory, "male" ) == 0 )
+ return -1;
+ else if ( strcmp( b->directory, "male" ) == 0 )
+ return 1;
+
+ if ( strcmp( a->directory, "female" ) == 0 )
+ return -1;
+ else if ( strcmp( b->directory, "female" ) == 0 )
+ return 1;
+
+ return strcmp( a->directory, b->directory );
+}
+
+
+qboolean PlayerConfig_MenuInit( void )
+{
+ extern cvar_t *name;
+ extern cvar_t *team;
+ extern cvar_t *skin;
+ char currentdirectory[1024];
+ char currentskin[1024];
+ int i;
+
+ int currentdirectoryindex = 0;
+ int currentskinindex = 0;
+
+ cvar_t *hand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
+
+ static char *handedness[] = { "right", "left", "center", 0 };
+
+ PlayerConfig_ScanDirectories();
+
+ if (s_numplayermodels == 0)
+ return false;
+
+ if ( hand->value < 0 || hand->value > 2 )
+ Cvar_SetValue( "hand", 0 );
+
+ strcpy( currentdirectory, skin->string );
+
+ if ( strchr( currentdirectory, '/' ) )
+ {
+ strcpy( currentskin, strchr( currentdirectory, '/' ) + 1 );
+ *strchr( currentdirectory, '/' ) = 0;
+ }
+ else if ( strchr( currentdirectory, '\\' ) )
+ {
+ strcpy( currentskin, strchr( currentdirectory, '\\' ) + 1 );
+ *strchr( currentdirectory, '\\' ) = 0;
+ }
+ else
+ {
+ strcpy( currentdirectory, "male" );
+ strcpy( currentskin, "grunt" );
+ }
+
+ qsort( s_pmi, s_numplayermodels, sizeof( s_pmi[0] ), pmicmpfnc );
+
+ memset( s_pmnames, 0, sizeof( s_pmnames ) );
+ for ( i = 0; i < s_numplayermodels; i++ )
+ {
+ s_pmnames[i] = s_pmi[i].displayname;
+ if ( cistrcmp( s_pmi[i].directory, currentdirectory ) == 0 )
+ {
+ int j;
+
+ currentdirectoryindex = i;
+
+ for ( j = 0; j < s_pmi[i].nskins; j++ )
+ {
+ if ( cistrcmp( s_pmi[i].skindisplaynames[j], currentskin ) == 0 )
+ {
+ currentskinindex = j;
+ break;
+ }
+ }
+ }
+ }
+
+ s_player_config_menu.x = vid.width / 2 - 95;
+ s_player_config_menu.y = vid.height / 2 - 97;
+ s_player_config_menu.nitems = 0;
+
+ s_player_name_field.generic.type = MTYPE_FIELD;
+ s_player_name_field.generic.name = "name";
+ s_player_name_field.generic.callback = 0;
+ s_player_name_field.generic.x = 0;
+ s_player_name_field.generic.y = 0;
+ s_player_name_field.length = 20;
+ s_player_name_field.visible_length = 20;
+ strcpy( s_player_name_field.buffer, name->string );
+ s_player_name_field.cursor = strlen( name->string );
+
+ s_player_model_title.generic.type = MTYPE_SEPARATOR;
+ s_player_model_title.generic.name = "model";
+ s_player_model_title.generic.x = -8;
+ s_player_model_title.generic.y = 60;
+
+ s_player_model_box.generic.type = MTYPE_SPINCONTROL;
+ s_player_model_box.generic.x = -56;
+ s_player_model_box.generic.y = 70;
+ s_player_model_box.generic.callback = ModelCallback;
+ s_player_model_box.generic.cursor_offset = -48;
+ s_player_model_box.curvalue = currentdirectoryindex;
+ s_player_model_box.itemnames = s_pmnames;
+
+ s_player_skin_title.generic.type = MTYPE_SEPARATOR;
+ s_player_skin_title.generic.name = "skin";
+ s_player_skin_title.generic.x = -16;
+ s_player_skin_title.generic.y = 84;
+
+ s_player_skin_box.generic.type = MTYPE_SPINCONTROL;
+ s_player_skin_box.generic.x = -56;
+ s_player_skin_box.generic.y = 94;
+ s_player_skin_box.generic.name = 0;
+ s_player_skin_box.generic.callback = 0;
+ s_player_skin_box.generic.cursor_offset = -48;
+ s_player_skin_box.curvalue = currentskinindex;
+ s_player_skin_box.itemnames = s_pmi[currentdirectoryindex].skindisplaynames;
+
+ s_player_hand_title.generic.type = MTYPE_SEPARATOR;
+ s_player_hand_title.generic.name = "handedness";
+ s_player_hand_title.generic.x = 32;
+ s_player_hand_title.generic.y = 108;
+
+ s_player_handedness_box.generic.type = MTYPE_SPINCONTROL;
+ s_player_handedness_box.generic.x = -56;
+ s_player_handedness_box.generic.y = 118;
+ s_player_handedness_box.generic.name = 0;
+ s_player_handedness_box.generic.cursor_offset = -48;
+ s_player_handedness_box.generic.callback = HandednessCallback;
+ s_player_handedness_box.curvalue = Cvar_VariableValue( "hand" );
+ s_player_handedness_box.itemnames = handedness;
+
+ for (i = 0; i < sizeof(rate_tbl) / sizeof(*rate_tbl) - 1; i++)
+ if (Cvar_VariableValue("rate") == rate_tbl[i])
+ break;
+
+ s_player_rate_title.generic.type = MTYPE_SEPARATOR;
+ s_player_rate_title.generic.name = "connect speed";
+ s_player_rate_title.generic.x = 56;
+ s_player_rate_title.generic.y = 156;
+
+ s_player_rate_box.generic.type = MTYPE_SPINCONTROL;
+ s_player_rate_box.generic.x = -56;
+ s_player_rate_box.generic.y = 166;
+ s_player_rate_box.generic.name = 0;
+ s_player_rate_box.generic.cursor_offset = -48;
+ s_player_rate_box.generic.callback = RateCallback;
+ s_player_rate_box.curvalue = i;
+ s_player_rate_box.itemnames = rate_names;
+
+ s_player_download_action.generic.type = MTYPE_ACTION;
+ s_player_download_action.generic.name = "download options";
+ s_player_download_action.generic.flags= QMF_LEFT_JUSTIFY;
+ s_player_download_action.generic.x = -24;
+ s_player_download_action.generic.y = 186;
+ s_player_download_action.generic.statusbar = NULL;
+ s_player_download_action.generic.callback = DownloadOptionsFunc;
+
+ Menu_AddItem( &s_player_config_menu, &s_player_name_field );
+ Menu_AddItem( &s_player_config_menu, &s_player_model_title );
+ Menu_AddItem( &s_player_config_menu, &s_player_model_box );
+ if ( s_player_skin_box.itemnames )
+ {
+ Menu_AddItem( &s_player_config_menu, &s_player_skin_title );
+ Menu_AddItem( &s_player_config_menu, &s_player_skin_box );
+ }
+ Menu_AddItem( &s_player_config_menu, &s_player_hand_title );
+ Menu_AddItem( &s_player_config_menu, &s_player_handedness_box );
+ Menu_AddItem( &s_player_config_menu, &s_player_rate_title );
+ Menu_AddItem( &s_player_config_menu, &s_player_rate_box );
+ Menu_AddItem( &s_player_config_menu, &s_player_download_action );
+
+ return true;
+}
+
+void PlayerConfig_MenuDraw( void )
+{
+ extern float CalcFov( float fov_x, float w, float h );
+ refdef_t refdef;
+ char scratch[MAX_QPATH];
+
+ memset( &refdef, 0, sizeof( refdef ) );
+
+ refdef.x = vid.width / 2;
+ refdef.y = vid.height / 2 - 72;
+ refdef.width = 144;
+ refdef.height = 168;
+ refdef.fov_x = 40;
+ refdef.fov_y = CalcFov( refdef.fov_x, refdef.width, refdef.height );
+ refdef.time = cls.realtime*0.001;
+
+ if ( s_pmi[s_player_model_box.curvalue].skindisplaynames )
+ {
+ static int yaw;
+ entity_t entity;
+
+ memset( &entity, 0, sizeof( entity ) );
+
+ Com_sprintf( scratch, sizeof( scratch ), "players/%s/tris.md2", s_pmi[s_player_model_box.curvalue].directory );
+ entity.model = re.RegisterModel( scratch );
+ Com_sprintf( scratch, sizeof( scratch ), "players/%s/%s.pcx", s_pmi[s_player_model_box.curvalue].directory, s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
+ entity.skin = re.RegisterSkin( scratch );
+ entity.flags = RF_FULLBRIGHT;
+ entity.origin[0] = 80;
+ entity.origin[1] = 0;
+ entity.origin[2] = 0;
+ VectorCopy( entity.origin, entity.oldorigin );
+ entity.frame = 0;
+ entity.oldframe = 0;
+ entity.backlerp = 0.0;
+ entity.angles[1] = yaw++;
+ if ( ++yaw > 360 )
+ yaw -= 360;
+
+ refdef.areabits = 0;
+ refdef.num_entities = 1;
+ refdef.entities = &entity;
+ refdef.lightstyles = 0;
+ refdef.rdflags = RDF_NOWORLDMODEL;
+
+ Menu_Draw( &s_player_config_menu );
+
+ M_DrawTextBox( ( refdef.x ) * ( 320.0F / vid.width ) - 8, ( vid.height / 2 ) * ( 240.0F / vid.height) - 77, refdef.width / 8, refdef.height / 8 );
+ refdef.height += 4;
+
+ re.RenderFrame( &refdef );
+
+ Com_sprintf( scratch, sizeof( scratch ), "/players/%s/%s_i.pcx",
+ s_pmi[s_player_model_box.curvalue].directory,
+ s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
+ re.DrawPic( s_player_config_menu.x - 40, refdef.y, scratch );
+ }
+}
+
+char *PlayerConfig_MenuKey (int key)
+{
+ int i;
+
+ if ( key == K_ESCAPE )
+ {
+ char scratch[1024];
+
+ Cvar_Set( "name", s_player_name_field.buffer );
+
+ Com_sprintf( scratch, sizeof( scratch ), "%s/%s",
+ s_pmi[s_player_model_box.curvalue].directory,
+ s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
+
+ Cvar_Set( "skin", scratch );
+
+ for ( i = 0; i < s_numplayermodels; i++ )
+ {
+ int j;
+
+ for ( j = 0; j < s_pmi[i].nskins; j++ )
+ {
+ if ( s_pmi[i].skindisplaynames[j] )
+ free( s_pmi[i].skindisplaynames[j] );
+ s_pmi[i].skindisplaynames[j] = 0;
+ }
+ free( s_pmi[i].skindisplaynames );
+ s_pmi[i].skindisplaynames = 0;
+ s_pmi[i].nskins = 0;
+ }
+ }
+ return Default_MenuKey( &s_player_config_menu, key );
+}
+
+
+void M_Menu_PlayerConfig_f (void)
+{
+ if (!PlayerConfig_MenuInit())
+ {
+ Menu_SetStatusBar( &s_multiplayer_menu, "No valid player models found" );
+ return;
+ }
+ Menu_SetStatusBar( &s_multiplayer_menu, NULL );
+ M_PushMenu( PlayerConfig_MenuDraw, PlayerConfig_MenuKey );
+}
+
+
+/*
+=======================================================================
+
+GALLERY MENU
+
+=======================================================================
+*/
+/* commented out in release
+void M_Menu_Gallery_f( void )
+{
+ extern void Gallery_MenuDraw( void );
+ extern char *Gallery_MenuKey( int key );
+
+ M_PushMenu( Gallery_MenuDraw, Gallery_MenuKey );
+}
+*/
+
+/*
+=======================================================================
+
+QUIT MENU
+
+=======================================================================
+*/
+
+char *M_Quit_Key (int key)
+{
+ switch (key)
+ {
+ case K_ESCAPE:
+ case 'n':
+ case 'N':
+ M_PopMenu ();
+ break;
+
+ case 'Y':
+ case 'y':
+ cls.key_dest = key_console;
+ CL_Quit_f ();
+ break;
+
+ default:
+ break;
+ }
+
+ return NULL;
+
+}
+
+
+void M_Quit_Draw (void)
+{
+ int w, h;
+
+ re.DrawGetPicSize (&w, &h, "quit");
+ re.DrawPic ( (vid.width-w)/2, (vid.height-h)/2, "quit");
+}
+
+
+void M_Menu_Quit_f (void)
+{
+ M_PushMenu (M_Quit_Draw, M_Quit_Key);
+}
+
+
+
+//=============================================================================
+/* Menu Subsystem */
+
+
+/*
+=================
+M_Init
+=================
+*/
+void M_Init (void)
+{
+ Cmd_AddCommand ("menu_main", M_Menu_Main_f);
+ Cmd_AddCommand ("menu_game", M_Menu_Game_f);
+ Cmd_AddCommand ("menu_loadgame", M_Menu_LoadGame_f);
+ Cmd_AddCommand ("menu_savegame", M_Menu_SaveGame_f);
+ Cmd_AddCommand ("menu_joinserver", M_Menu_JoinServer_f);
+ Cmd_AddCommand ("menu_addressbook", M_Menu_AddressBook_f);
+ Cmd_AddCommand ("menu_startserver", M_Menu_StartServer_f);
+ Cmd_AddCommand ("menu_dmoptions", M_Menu_DMOptions_f);
+ Cmd_AddCommand ("menu_playerconfig", M_Menu_PlayerConfig_f);
+ Cmd_AddCommand ("menu_downloadoptions", M_Menu_DownloadOptions_f);
+ Cmd_AddCommand ("menu_credits", M_Menu_Credits_f );
+ Cmd_AddCommand ("menu_multiplayer", M_Menu_Multiplayer_f );
+ Cmd_AddCommand ("menu_video", M_Menu_Video_f);
+ Cmd_AddCommand ("menu_options", M_Menu_Options_f);
+ Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
+ Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
+}
+
+
+/*
+=================
+M_Draw
+=================
+*/
+void M_Draw (void)
+{
+ if (cls.key_dest != key_menu)
+ return;
+
+ // repaint everything next frame
+ SCR_DirtyScreen ();
+
+ // dim everything behind it down
+ if (cl.cinematictime > 0)
+ re.DrawFill (0,0,vid.width, vid.height, 0);
+ else
+ re.DrawFadeScreen ();
+
+ m_drawfunc ();
+
+ // delay playing the enter sound until after the
+ // menu has been drawn, to avoid delay while
+ // caching images
+ if (m_entersound)
+ {
+ S_StartLocalSound( menu_in_sound );
+ m_entersound = false;
+ }
+}
+
+
+/*
+=================
+M_Keydown
+=================
+*/
+void M_Keydown (int key)
+{
+ char *s;
+
+ if (m_keyfunc)
+ if ( ( s = m_keyfunc( key ) ) != 0 )
+ S_StartLocalSound( ( char * ) s );
+}
+
+
--- a/mk.baseq2
+++ b/mk.baseq2
@@ -1,3 +1,5 @@
+TARG=quake2
+
GMOFILES=\
game/g_ai.$O\
game/p_client.$O\
@@ -49,7 +51,6 @@
game/q_shared.$O\
GMHFILES=\
- game/g_local.h\
game/game.h\
game/m_actor.h\
game/m_berserk.h\
--- a/mk.ctf
+++ b/mk.ctf
@@ -1,35 +1,32 @@
+TARG=q2ctf
+
GMOFILES=\
- ctf/g_ai.$O\
- ctf/g_chase.$O\
- ctf/g_cmds.$O\
- ctf/g_combat.$O\
- ctf/g_ctf.$O\
- ctf/g_func.$O\
- ctf/g_items.$O\
- ctf/g_main.$O\
- ctf/g_misc.$O\
- ctf/g_monster.$O\
- ctf/g_phys.$O\
- ctf/g_save.$O\
- ctf/g_spawn.$O\
- ctf/g_svcmds.$O\
- ctf/g_target.$O\
- ctf/g_trigger.$O\
- ctf/g_utils.$O\
- ctf/g_weapon.$O\
- ctf/m_move.$O\
- ctf/p_client.$O\
- ctf/p_hud.$O\
- ctf/p_menu.$O\
- ctf/p_trail.$O\
- ctf/p_view.$O\
- ctf/p_weapon.$O\
- ctf/q_shared.$O\
+ game/g_ai.$O\
+ game/g_chase.$O\
+ game/g_cmds.$O\
+ game/g_combat.$O\
+ game/g_game.$O\
+ game/g_func.$O\
+ game/g_items.$O\
+ game/g_main.$O\
+ game/g_misc.$O\
+ game/g_monster.$O\
+ game/g_phys.$O\
+ game/g_save.$O\
+ game/g_spawn.$O\
+ game/g_svcmds.$O\
+ game/g_target.$O\
+ game/g_trigger.$O\
+ game/g_utils.$O\
+ game/g_weapon.$O\
+ game/m_move.$O\
+ game/p_client.$O\
+ game/p_hud.$O\
+ game/p_menu.$O\
+ game/p_trail.$O\
+ game/p_view.$O\
+ game/p_weapon.$O\
+ game/q_shared.$O\
GMHFILES=\
- ctf/g_ctf.h\
- ctf/g_local.h\
- ctf/game.h\
- ctf/m_player.h\
- ctf/p_menu.h\
-
+ game/game.h\
--- a/mk.xatrix
+++ /dev/null
@@ -1,55 +1,0 @@
-GMFILES=\
- xatrix/g_ai.$O\
- xatrix/g_cmds.$O\
- xatrix/g_combat.$O\
- xatrix/g_func.$O\
- xatrix/g_items.$O\
- xatrix/g_main.$O\
- xatrix/g_misc.$O\
- xatrix/g_monster.$O\
- xatrix/g_phys.$O\
- xatrix/g_save.$O\
- xatrix/g_spawn.$O\
- xatrix/g_svcmds.$O\
- xatrix/g_target.$O\
- xatrix/g_trigger.$O\
- xatrix/g_turret.$O\
- xatrix/g_utils.$O\
- xatrix/g_weapon.$O\
- xatrix/m_actor.$O\
- xatrix/m_berserk.$O\
- xatrix/m_boss2.$O\
- xatrix/m_boss3.$O\
- xatrix/m_boss31.$O\
- xatrix/m_boss32.$O\
- xatrix/m_boss5.$O\
- xatrix/m_brain.$O\
- xatrix/m_chick.$O\
- xatrix/m_fixbot.$O\
- xatrix/m_flash.$O\
- xatrix/m_flipper.$O\
- xatrix/m_float.$O\
- xatrix/m_flyer.$O\
- xatrix/m_gekk.$O\
- xatrix/m_gladb.$O\
- xatrix/m_gladiator.$O\
- xatrix/m_gunner.$O\
- xatrix/m_hover.$O\
- xatrix/m_infantry.$O\
- xatrix/m_insane.$O\
- xatrix/m_medic.$O\
- xatrix/m_move.$O\
- xatrix/m_mutant.$O\
- xatrix/m_parasite.$O\
- xatrix/m_soldier.$O\
- xatrix/m_supertank.$O\
- xatrix/m_tank.$O\
- xatrix/p_client.$O\
- xatrix/p_hud.$O\
- xatrix/p_trail.$O\
- xatrix/p_view.$O\
- xatrix/p_weapon.$O\
- xatrix/q_shared.$O\
-
-GMHFILES=\
-
--- a/mkfile
+++ b/mkfile
@@ -1,95 +1,79 @@
</$objtype/mkfile
BIN=$home/bin/$objtype
-TARG=quake2
# change this to build/load a different game "dll"
<mk.baseq2
OFILES=\
- client/cl_cin.$O\
- client/cl_ents.$O\
- client/cl_fx.$O\
- client/cl_newfx.$O\
- client/cl_input.$O\
- client/cl_inv.$O\
- client/cl_main.$O\
- client/cl_parse.$O\
- client/cl_pred.$O\
- client/cl_tent.$O\
- client/cl_scrn.$O\
- client/cl_view.$O\
- client/console.$O\
- client/keys.$O\
- client/menu.$O\
- client/snd_dma.$O\
- client/snd_mem.$O\
- client/snd_mix.$O\
- client/qmenu.$O\
- server/sv_ccmds.$O\
- server/sv_ents.$O\
- server/sv_game.$O\
- server/sv_init.$O\
- server/sv_main.$O\
- server/sv_send.$O\
- server/sv_user.$O\
- server/sv_world.$O\
- qcommon/cmd.$O\
- qcommon/cmodel.$O\
- qcommon/common.$O\
- qcommon/crc.$O\
- qcommon/cvar.$O\
- qcommon/files.$O\
- qcommon/md4.$O\
- qcommon/net_chan.$O\
- qcommon/pmove.$O\
- plan9/cd.$O\
- plan9/in.$O\
- plan9/menu.$O\
- plan9/snd.$O\
- plan9/sys.$O\
- plan9/udp.$O\
- plan9/vid.$O\
- ref/r_aclip.$O\
- ref/r_alias.$O\
- ref/r_bsp.$O\
- ref/r_draw.$O\
- ref/r_edge.$O\
- ref/r_image.$O\
- ref/r_light.$O\
- ref/r_main.$O\
- ref/r_misc.$O\
- ref/r_model.$O\
- ref/r_part.$O\
- ref/r_poly.$O\
- ref/r_polyse.$O\
- ref/r_rast.$O\
- ref/r_scan.$O\
- ref/r_sprite.$O\
- ref/r_surf.$O\
+ cl_cin.$O\
+ cl_ents.$O\
+ cl_fx.$O\
+ cl_newfx.$O\
+ cl_input.$O\
+ cl_inv.$O\
+ cl_main.$O\
+ cl_parse.$O\
+ cl_pred.$O\
+ cl_tent.$O\
+ cl_scrn.$O\
+ cl_view.$O\
+ console.$O\
+ keys.$O\
+ menu.$O\
+ snd_dma.$O\
+ snd_mem.$O\
+ snd_mix.$O\
+ qmenu.$O\
+ sv_ccmds.$O\
+ sv_ents.$O\
+ sv_game.$O\
+ sv_init.$O\
+ sv_main.$O\
+ sv_send.$O\
+ sv_user.$O\
+ sv_world.$O\
+ cmd.$O\
+ cmodel.$O\
+ common.$O\
+ crc.$O\
+ cvar.$O\
+ files.$O\
+ md4.$O\
+ net_chan.$O\
+ pmove.$O\
+ cd.$O\
+ in.$O\
+ snd.$O\
+ sys.$O\
+ udp.$O\
+ vid.$O\
+ vmenu.$O\
+ r_aclip.$O\
+ r_alias.$O\
+ r_bsp.$O\
+ r_draw.$O\
+ r_edge.$O\
+ r_image.$O\
+ r_light.$O\
+ r_main.$O\
+ r_misc.$O\
+ r_model.$O\
+ r_part.$O\
+ r_poly.$O\
+ r_polyse.$O\
+ r_rast.$O\
+ r_scan.$O\
+ r_sprite.$O\
+ r_surf.$O\
$GMOFILES\
HFILES=\
+ adivtab.h\
anorms.h\
- q_shared.h\
- client/cdaudio.h\
- client/client.h\
- client/console.h\
- client/input.h\
- client/keys.h\
- client/qmenu.h\
- client/ref.h\
- client/screen.h\
- client/snd_loc.h\
- client/sound.h\
- client/vid.h\
- server/server.h\
- qcommon/crc.h\
- qcommon/qcommon.h\
- qcommon/qfiles.h\
- ref/adivtab.h\
- ref/r_local.h\
- ref/rand1k.h\
+ dat.h\
+ fns.h\
+ rand1k.h\
$GMHFILES\
# FIXME
--- /dev/null
+++ b/net_chan.c
@@ -1,0 +1,370 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+
+packet header
+-------------
+31 sequence
+1 does this message contain a reliable payload
+31 acknowledge sequence
+1 acknowledge receipt of even/odd message
+16 qport
+
+The remote connection never knows if it missed a reliable message, the
+local side detects that it has been dropped by seeing a sequence acknowledge
+higher thatn the last reliable sequence, but without the correct evon/odd
+bit for the reliable set.
+
+If the sender notices that a reliable message has been dropped, it will be
+retransmitted. It will not be retransmitted again until a message after
+the retransmit has been acknowledged and the reliable still failed to get there.
+
+if the sequence number is -1, the packet should be handled without a netcon
+
+The reliable message can be added to at any time by doing
+MSG_Write* (&netchan->message, <data>).
+
+If the message buffer is overflowed, either by a single message, or by
+multiple frames worth piling up while the last reliable transmit goes
+unacknowledged, the netchan signals a fatal error.
+
+Reliable messages are always placed first in a packet, then the unreliable
+message is included if there is sufficient room.
+
+To the receiver, there is no distinction between the reliable and unreliable
+parts of the message, they are just processed out as a single larger message.
+
+Illogical packet sequence numbers cause the packet to be dropped, but do
+not kill the connection. This, combined with the tight window of valid
+reliable acknowledgement numbers provides protection against malicious
+address spoofing.
+
+
+The qport field is a workaround for bad address translating routers that
+sometimes remap the client's source port on a packet during gameplay.
+
+If the base part of the net address matches and the qport matches, then the
+channel matches even if the IP port differs. The IP port should be updated
+to the new value before sending out any replies.
+
+
+If there is no information that needs to be transfered on a given frame,
+such as during the connection stage while waiting for the client to load,
+then a packet only needs to be delivered if there is something in the
+unacknowledged reliable
+*/
+
+cvar_t *showpackets;
+cvar_t *showdrop;
+cvar_t *qport;
+
+netadr_t net_from;
+sizebuf_t net_message;
+byte net_message_buffer[MAX_MSGLEN];
+
+/*
+===============
+Netchan_Init
+
+===============
+*/
+void Netchan_Init (void)
+{
+ int port;
+
+ // pick a port value that should be nice and random
+ port = Sys_Milliseconds() & 0xffff;
+
+ showpackets = Cvar_Get ("showpackets", "0", 0);
+ showdrop = Cvar_Get ("showdrop", "0", 0);
+ qport = Cvar_Get ("qport", va("%i", port), CVAR_NOSET);
+}
+
+/*
+===============
+Netchan_OutOfBand
+
+Sends an out-of-band datagram
+================
+*/
+void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data)
+{
+ sizebuf_t send;
+ byte send_buf[MAX_MSGLEN];
+
+// write the packet header
+ SZ_Init (&send, send_buf, sizeof(send_buf));
+
+ MSG_WriteLong (&send, -1); // -1 sequence means out of band
+ SZ_Write (&send, data, length);
+
+// send the datagram
+ NET_SendPacket (net_socket, send.cursize, send.data, adr);
+}
+
+/*
+===============
+Netchan_OutOfBandPrint
+
+Sends a text message in an out-of-band datagram
+================
+*/
+void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...)
+{
+ va_list argptr;
+ static char string[MAX_MSGLEN - 4];
+
+ va_start (argptr, format);
+ vsprintf (string, format,argptr);
+ va_end (argptr);
+
+ Netchan_OutOfBand (net_socket, adr, strlen(string), (byte *)string);
+}
+
+
+/*
+==============
+Netchan_Setup
+
+called to open a channel to a remote system
+==============
+*/
+void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport)
+{
+ memset (chan, 0, sizeof(*chan));
+
+ chan->sock = sock;
+ chan->remote_address = adr;
+ chan->qport = qport;
+ chan->last_received = curtime;
+ chan->incoming_sequence = 0;
+ chan->outgoing_sequence = 1;
+
+ SZ_Init (&chan->message, chan->message_buf, sizeof(chan->message_buf));
+ chan->message.allowoverflow = true;
+}
+
+
+/*
+===============
+Netchan_CanReliable
+
+Returns true if the last reliable message has acked
+================
+*/
+qboolean Netchan_CanReliable (netchan_t *chan)
+{
+ if (chan->reliable_length)
+ return false; // waiting for ack
+ return true;
+}
+
+
+qboolean Netchan_NeedReliable (netchan_t *chan)
+{
+ qboolean send_reliable;
+
+// if the remote side dropped the last reliable message, resend it
+ send_reliable = false;
+
+ if (chan->incoming_acknowledged > chan->last_reliable_sequence
+ && chan->incoming_reliable_acknowledged != chan->reliable_sequence)
+ send_reliable = true;
+
+// if the reliable transmit buffer is empty, copy the current message out
+ if (!chan->reliable_length && chan->message.cursize)
+ {
+ send_reliable = true;
+ }
+
+ return send_reliable;
+}
+
+/*
+===============
+Netchan_Transmit
+
+tries to send an unreliable message to a connection, and handles the
+transmition / retransmition of the reliable messages.
+
+A 0 length will still generate a packet and deal with the reliable messages.
+================
+*/
+void Netchan_Transmit (netchan_t *chan, int length, byte *data)
+{
+ sizebuf_t send;
+ byte send_buf[MAX_MSGLEN];
+ qboolean send_reliable;
+ unsigned w1, w2;
+
+// check for message overflow
+ if (chan->message.overflowed)
+ {
+ chan->fatal_error = true;
+ Com_Printf ("%s:Outgoing message overflow\n"
+ , NET_AdrToString (chan->remote_address));
+ return;
+ }
+
+ send_reliable = Netchan_NeedReliable (chan);
+
+ if (!chan->reliable_length && chan->message.cursize)
+ {
+ memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize);
+ chan->reliable_length = chan->message.cursize;
+ chan->message.cursize = 0;
+ chan->reliable_sequence ^= 1;
+ }
+
+
+// write the packet header
+ SZ_Init (&send, send_buf, sizeof(send_buf));
+
+ w1 = ( chan->outgoing_sequence & ~(1<<31) ) | (send_reliable<<31);
+ w2 = ( chan->incoming_sequence & ~(1<<31) ) | (chan->incoming_reliable_sequence<<31);
+
+ chan->outgoing_sequence++;
+ chan->last_sent = curtime;
+
+ MSG_WriteLong (&send, w1);
+ MSG_WriteLong (&send, w2);
+
+ // send the qport if we are a client
+ if (chan->sock == NS_CLIENT)
+ MSG_WriteShort (&send, qport->value);
+
+// copy the reliable message to the packet first
+ if (send_reliable)
+ {
+ SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
+ chan->last_reliable_sequence = chan->outgoing_sequence;
+ }
+
+// add the unreliable part if space is available
+ if (send.maxsize - send.cursize >= length)
+ SZ_Write (&send, data, length);
+ else
+ Com_Printf ("Netchan_Transmit: dumped unreliable\n");
+
+// send the datagram
+ NET_SendPacket (chan->sock, send.cursize, send.data, chan->remote_address);
+
+ if (showpackets->value)
+ {
+ if (send_reliable)
+ Com_Printf ("send %4i : s=%i reliable=%i ack=%i rack=%i\n"
+ , send.cursize
+ , chan->outgoing_sequence - 1
+ , chan->reliable_sequence
+ , chan->incoming_sequence
+ , chan->incoming_reliable_sequence);
+ else
+ Com_Printf ("send %4i : s=%i ack=%i rack=%i\n"
+ , send.cursize
+ , chan->outgoing_sequence - 1
+ , chan->incoming_sequence
+ , chan->incoming_reliable_sequence);
+ }
+}
+
+/*
+=================
+Netchan_Process
+
+called when the current net_message is from remote_address
+modifies net_message so that it points to the packet payload
+=================
+*/
+qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg)
+{
+ unsigned sequence, sequence_ack;
+ unsigned reliable_ack, reliable_message;
+
+// get sequence numbers
+ MSG_BeginReading (msg);
+ sequence = MSG_ReadLong (msg);
+ sequence_ack = MSG_ReadLong (msg);
+
+ // read the qport if we are a server
+ if (chan->sock == NS_SERVER)
+ MSG_ReadShort (msg); /* toss read */
+
+ reliable_message = sequence >> 31;
+ reliable_ack = sequence_ack >> 31;
+
+ sequence &= ~(1<<31);
+ sequence_ack &= ~(1<<31);
+
+ if (showpackets->value)
+ {
+ if (reliable_message)
+ Com_Printf ("recv %4i : s=%i reliable=%i ack=%i rack=%i\n"
+ , msg->cursize
+ , sequence
+ , chan->incoming_reliable_sequence ^ 1
+ , sequence_ack
+ , reliable_ack);
+ else
+ Com_Printf ("recv %4i : s=%i ack=%i rack=%i\n"
+ , msg->cursize
+ , sequence
+ , sequence_ack
+ , reliable_ack);
+ }
+
+//
+// discard stale or duplicated packets
+//
+ if (sequence <= chan->incoming_sequence)
+ {
+ if (showdrop->value)
+ Com_Printf ("%s:Out of order packet %i at %i\n"
+ , NET_AdrToString (chan->remote_address)
+ , sequence
+ , chan->incoming_sequence);
+ return false;
+ }
+
+//
+// dropped packets don't keep the message from being used
+//
+ chan->dropped = sequence - (chan->incoming_sequence+1);
+ if (chan->dropped > 0)
+ {
+ if (showdrop->value)
+ Com_Printf ("%s:Dropped %i packets at %i\n"
+ , NET_AdrToString (chan->remote_address)
+ , chan->dropped
+ , sequence);
+ }
+
+//
+// if the current outgoing reliable message has been acknowledged
+// clear the buffer to make way for the next
+//
+ if (reliable_ack == chan->reliable_sequence)
+ chan->reliable_length = 0; // it has been received
+
+//
+// if this message contains a reliable message, bump incoming_reliable_sequence
+//
+ chan->incoming_sequence = sequence;
+ chan->incoming_acknowledged = sequence_ack;
+ chan->incoming_reliable_acknowledged = reliable_ack;
+ if (reliable_message)
+ {
+ chan->incoming_reliable_sequence ^= 1;
+ }
+
+//
+// the message can now be read from the current message pointer
+//
+ chan->last_received = curtime;
+
+ return true;
+}
+
--- a/plan9/cd.c
+++ /dev/null
@@ -1,414 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-qboolean cdValid = false;
-qboolean playing = false;
-qboolean wasPlaying = false;
-qboolean initialized = false;
-qboolean enabled = true;
-qboolean playLooping = false;
-float cdvolume;
-byte remap[100];
-byte playTrack;
-byte maxTrack;
-int cdfile = -1;
-
-cvar_t *cd_volume;
-cvar_t *cd_nocd;
-cvar_t *cd_dev;
-
-
-void CDAudio_Eject(void)
-{
- if (cdfile == -1 || !enabled)
- return;
-
- Com_DPrintf("CDAudio_Eject: PORTME\n");
- /*
- if ( ioctl(cdfile, CDROMEJECT) == -1 )
- Com_DPrintf("ioctl cdromeject failed\n");
- */
-}
-
-void CDAudio_CloseDoor(void)
-{
- if (cdfile == -1 || !enabled)
- return;
-
- Com_DPrintf("CDAudio_CloseDoor: PORTME\n");
- /*
- if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 )
- Com_DPrintf("ioctl cdromclosetray failed\n");
- */
-}
-
-int CDAudio_GetAudioDiskInfo(void)
-{
- cdValid = false;
- Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
- return -1;
-
- /*
- struct cdrom_tochdr tochdr;
-
- if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 )
- {
- Com_DPrintf("ioctl cdromreadtochdr failed\n");
- return -1;
- }
-
- if (tochdr.cdth_trk0 < 1)
- {
- Com_DPrintf("CDAudio: no music tracks\n");
- return -1;
- }
-
- cdValid = true;
- maxTrack = tochdr.cdth_trk1;
- return 0;
- */
-}
-
-void CDAudio_Pause(void)
-{
- if (cdfile == -1 || !enabled)
- return;
- if (!playing)
- return;
-
- Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
-
- /*
- if ( ioctl(cdfile, CDROMPAUSE) == -1 )
- Com_DPrintf("ioctl cdrompause failed\n");
-
- wasPlaying = playing;
- playing = false;
- */
-}
-
-void CDAudio_Play(int track, qboolean looping)
-{
- if (cdfile == -1 || !enabled)
- return;
- if (!cdValid)
- {
- CDAudio_GetAudioDiskInfo();
- if (!cdValid)
- return;
- }
-
- track = remap[track];
- if (track < 1 || track > maxTrack)
- {
- Com_DPrintf("CDAudio: Bad track number %u.\n", track);
- return;
- }
-
- USED(looping);
- Com_DPrintf("CDAudio_Play: PORTME\n");
-
- /*
- struct cdrom_tocentry entry;
- struct cdrom_ti ti;
-
- // don't try to play a non-audio track
- entry.cdte_track = track;
- entry.cdte_format = CDROM_MSF;
- if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 )
- {
- Com_DPrintf("ioctl cdromreadtocentry failed\n");
- return;
- }
- if (entry.cdte_ctrl == CDROM_DATA_TRACK)
- {
- Com_Printf("CDAudio: track %i is not audio\n", track);
- return;
- }
-
- if (playing)
- {
- if (playTrack == track)
- return;
- CDAudio_Stop();
- }
-
- ti.cdti_trk0 = track;
- ti.cdti_trk1 = track;
- ti.cdti_ind0 = 1;
- ti.cdti_ind1 = 99;
- if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 )
- {
- Com_DPrintf("ioctl cdromplaytrkind failed\n");
- return;
- }
- if ( ioctl(cdfile, CDROMRESUME) == -1 )
- Com_DPrintf("ioctl cdromresume failed\n");
-
- playLooping = looping;
- playTrack = track;
- playing = true;
-
- if (cd_volume->value == 0.0)
- CDAudio_Pause ();
- */
-}
-
-
-void CDAudio_Stop(void)
-{
- if (cdfile == -1 || !enabled)
- return;
- if (!playing)
- return;
-
- Com_DPrintf("CDAudio_Stop: PORTME\n");
-
- /*
- if ( ioctl(cdfile, CDROMSTOP) == -1 )
- Com_DPrintf("ioctl cdromstop failed (%d)\n", errno);
-
- wasPlaying = false;
- playing = false;
- */
-}
-
-void CDAudio_Resume(void)
-{
- if (cdfile == -1 || !enabled)
- return;
- if (!cdValid)
- return;
- if (!wasPlaying)
- return;
-
- Com_DPrintf("CDAudio_Stop: PORTME\n");
-
- /*
- if ( ioctl(cdfile, CDROMRESUME) == -1 )
- Com_DPrintf("ioctl cdromresume failed\n");
- playing = true;
- */
-}
-
-static void CD_f (void)
-{
- char *command;
- int n, ret;
-
- if (Cmd_Argc() < 2)
- return;
-
- command = Cmd_Argv (1);
-
- if (cistrcmp(command, "on") == 0)
- {
- enabled = true;
- return;
- }
-
- if (cistrcmp(command, "off") == 0)
- {
- if (playing)
- CDAudio_Stop();
- enabled = false;
- return;
- }
-
- if (cistrcmp(command, "reset") == 0)
- {
- enabled = true;
- if (playing)
- CDAudio_Stop();
- for (n = 0; n < 100; n++)
- remap[n] = n;
- CDAudio_GetAudioDiskInfo();
- return;
- }
-
- if (cistrcmp(command, "remap") == 0)
- {
- ret = Cmd_Argc() - 2;
- if (ret <= 0)
- {
- for (n = 1; n < 100; n++)
- if (remap[n] != n)
- Com_Printf(" %u -> %u\n", n, remap[n]);
- return;
- }
- for (n = 1; n <= ret; n++)
- remap[n] = atoi(Cmd_Argv (n+1));
- return;
- }
-
- if (cistrcmp(command, "close") == 0)
- {
- CDAudio_CloseDoor();
- return;
- }
-
- if (!cdValid)
- {
- CDAudio_GetAudioDiskInfo();
- if (!cdValid)
- {
- Com_Printf("No CD in player.\n");
- return;
- }
- }
-
- if (cistrcmp(command, "play") == 0)
- {
- CDAudio_Play((byte)atoi(Cmd_Argv (2)), false);
- return;
- }
-
- if (cistrcmp(command, "loop") == 0)
- {
- CDAudio_Play((byte)atoi(Cmd_Argv (2)), true);
- return;
- }
-
- if (cistrcmp(command, "stop") == 0)
- {
- CDAudio_Stop();
- return;
- }
-
- if (cistrcmp(command, "pause") == 0)
- {
- CDAudio_Pause();
- return;
- }
-
- if (cistrcmp(command, "resume") == 0)
- {
- CDAudio_Resume();
- return;
- }
-
- if (cistrcmp(command, "eject") == 0)
- {
- if (playing)
- CDAudio_Stop();
- CDAudio_Eject();
- cdValid = false;
- return;
- }
-
- if (cistrcmp(command, "info") == 0)
- {
- Com_Printf("%u tracks\n", maxTrack);
- if (playing)
- Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
- else if (wasPlaying)
- Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
- Com_Printf("Volume is %f\n", cdvolume);
- return;
- }
-}
-
-void CDAudio_Update(void)
-{
- if (cdfile == -1 || !enabled)
- return;
- if (cd_volume && cd_volume->value != cdvolume)
- {
- if (cdvolume)
- {
- Cvar_SetValue ("cd_volume", 0.0);
- cdvolume = cd_volume->value;
- CDAudio_Pause ();
- }
- else
- {
- Cvar_SetValue ("cd_volume", 1.0);
- cdvolume = cd_volume->value;
- CDAudio_Resume ();
- }
- }
-
- Com_DPrintf("CDAudio_Stop: PORTME\n");
-
- /*
- struct cdrom_subchnl subchnl;
- static time_t lastchk;
-
- if (playing && lastchk < time(NULL)) {
- lastchk = time(NULL) + 2; //two seconds between chks
- subchnl.cdsc_format = CDROM_MSF;
- if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) {
- Com_DPrintf("ioctl cdromsubchnl failed\n");
- playing = false;
- return;
- }
- if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY &&
- subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) {
- playing = false;
- if (playLooping)
- CDAudio_Play(playTrack, true);
- }
- }
- */
-}
-
-int CDAudio_Init(void)
-{
- int i;
- cvar_t *cv;
-
- cv = Cvar_Get ("nocdaudio", "0", CVAR_NOSET);
- if (cv->value)
- return -1;
-
- cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
- if ( cd_nocd->value)
- return -1;
-
- cd_volume = Cvar_Get ("cd_volume", "1", CVAR_ARCHIVE);
-
- cd_dev = Cvar_Get("cd_dev", "/dev/cdrom", CVAR_ARCHIVE);
-
- if((cdfile = open(cd_dev->string, OREAD)) < 0){
- fprint(2, "CDAudio_Init: %r\n");
- Com_Printf("CDAudio_Init: failed to open \"%s\"\n", cd_dev->string);
- cdfile = -1;
- return -1;
- }
-
- for (i = 0; i < 100; i++)
- remap[i] = i;
- initialized = true;
- enabled = true;
-
- if (CDAudio_GetAudioDiskInfo())
- {
- Com_Printf("CDAudio_Init: No CD in player.\n");
- cdValid = false;
- }
-
- Cmd_AddCommand ("cd", CD_f);
-
- Com_Printf("CD Audio Initialized\n");
-
- return 0;
-}
-
-void CDAudio_Activate (qboolean active)
-{
- if (active)
- CDAudio_Resume ();
- else
- CDAudio_Pause ();
-}
-
-void CDAudio_Shutdown(void)
-{
- if (!initialized)
- return;
- CDAudio_Stop();
- close(cdfile);
- cdfile = -1;
-}
--- a/plan9/in.c
+++ /dev/null
@@ -1,454 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <draw.h>
-#include <thread.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include "../q_shared.h"
-
-extern int resized; /* vid.c */
-extern Point center;
-extern Channel *fuckchan, *tchan; /* sys.c */
-
-cvar_t *in_joystick;
-cvar_t *sensitivity;
-cvar_t *lookstrafe;
-cvar_t *lookspring;
-cvar_t *freelook;
-cvar_t *m_pitch;
-
-static cvar_t *m_filter;
-static cvar_t *m_windowed;
-static cvar_t *m_yaw;
-static cvar_t *m_side;
-static cvar_t *m_forward;
-
-static int mouseon;
-static int mlooking;
-static int dx, dy;
-static int oldmwin;
-
-typedef struct Kev Kev;
-struct Kev{
- int key;
- int down;
-};
-enum{
- Nbuf = 64
-};
-static Channel *kchan, *mchan;
-static int iop = -1, pfd[2];
-static QLock killock;
-
-
-char *
-Sys_ConsoleInput(void)
-{
- static char buf[256];
- int n;
-
- if(dedicated != nil && dedicated->value && iop >= 0){
- if(flen(pfd[1]) < 1) /* only poll for input */
- return nil;
- if((n = read(pfd[1], buf, sizeof buf)) < 0)
- sysfatal("Sys_ConsoleInput:read: %r");
- if(n == 0){
- iop = -1;
- return nil;
- }
- return buf;
- }
- return nil;
-}
-
-void
-IN_Grabm(int on)
-{
- static char nocurs[2*4+2*2*16];
- static int fd = -1;
-
- if(mouseon == on)
- return;
- if(mouseon = on && m_windowed->value){
- if((fd = open("/dev/cursor", ORDWR|OCEXEC)) < 0){
- sysfatal("IN_Grabm:open: %r\n");
- return;
- }
- write(fd, nocurs, sizeof nocurs);
- }else if(fd >= 0){
- close(fd);
- fd = -1;
- }
-}
-
-void
-IN_Commands(void)
-{
- /* joystick stuff */
-}
-
-void
-btnev(int btn, ulong msec)
-{
- static int oldb;
- int i, b;
-
- for(i = 0; i < 3; i++){
- b = 1<<i;
- if(btn & b && ~oldb & b)
- Key_Event(K_MOUSE1+i, true, msec);
- else if(~btn & b && oldb & b)
- Key_Event(K_MOUSE1+i, false, msec);
- }
- oldb = btn;
- /* mwheelup and mwheeldn buttons are never held down */
- for(i = 3; i < 5; i++){
- b = 1<<i;
- if(btn & b){
- Key_Event(K_MOUSE1+i, true, msec);
- Key_Event(K_MOUSE1+i, false, msec);
- }
- }
-}
-
-void
-KBD_Update(void)
-{
- int r;
- Kev ev;
- Mouse m;
-
- if(oldmwin != m_windowed->value){
- oldmwin = m_windowed->value;
- IN_Grabm(m_windowed->value);
- }
- while((r = nbrecv(kchan, &ev)) > 0)
- Key_Event(ev.key, ev.down, Sys_Milliseconds());
- if(r < 0)
- sysfatal("KBD_Update:nbrecv: %r\n");
- while((r = nbrecv(mchan, &m)) > 0){
- dx += m.xy.x;
- dy += m.xy.y;
- btnev(m.buttons, m.msec);
- }
- if(r < 0)
- sysfatal("KBD_Update:nbrecv: %r\n");
-}
-
-void
-IN_Move(usercmd_t *cmd)
-{
- static int oldmx, oldmy;
- int mx, my;
-
- if(!mouseon)
- return;
-
- if(m_filter->value){
- mx = (dx + oldmx) * 0.5;
- my = (dy + oldmy) * 0.5;
- }else{
- mx = dx;
- my = dy;
- }
- oldmx = dx;
- oldmy = dy;
- dx = dy = 0;
- if(!mx && !my)
- return;
- mx *= sensitivity->value;
- my *= sensitivity->value;
-
- /* add mouse x/y movement to cmd */
- if(in_strafe.state & 1 || lookstrafe->value && mlooking)
- cmd->sidemove += m_side->value * mx;
- else
- cl.viewangles[YAW] -= m_yaw->value * mx;
- if((mlooking || freelook->value) && ~in_strafe.state & 1)
- cl.viewangles[PITCH] += m_pitch->value * my;
- else
- cmd->forwardmove -= m_forward->value * my;
-}
-
-/* called on focus/unfocus in win32 */
-void
-IN_Activate(qboolean)
-{
-}
-
-/* called every frame even if not generating commands */
-void
-IN_Frame(void)
-{
-}
-
-void
-IN_ForceCenterView(void)
-{
- cl.viewangles[PITCH] = 0;
-}
-
-void
-IN_MLookDown(void)
-{
- mlooking = true;
-}
-
-void
-IN_MLookUp(void)
-{
- mlooking = false;
- IN_CenterView();
-}
-
-static int
-runetokey(Rune r)
-{
- int k = 0;
-
- switch(r){
- case Kpgup: k = K_PGUP; break;
- case Kpgdown: k = K_PGDN; break;
- case Khome: k = K_HOME; break;
- case Kend: k = K_END; break;
- case Kleft: k = K_LEFTARROW; break;
- case Kright: k = K_RIGHTARROW; break;
- case Kdown: k = K_DOWNARROW; break;
- case Kup: k = K_UPARROW; break;
- case Kesc: k = K_ESCAPE; break;
- case '\n': k = K_ENTER; break;
- case '\t': k = K_TAB; break;
- case KF|1: k = K_F1; break;
- case KF|2: k = K_F2; break;
- case KF|3: k = K_F3; break;
- case KF|4: k = K_F4; break;
- case KF|5: k = K_F5; break;
- case KF|6: k = K_F6; break;
- case KF|7: k = K_F7; break;
- case KF|8: k = K_F8; break;
- case KF|9: k = K_F9; break;
- case KF|10: k = K_F10; break;
- case KF|11: k = K_F11; break;
- case KF|12: k = K_F12; break;
- case Kbs: k = K_BACKSPACE; break;
- case Kdel: k = K_DEL; break;
- case Kbreak: k = K_PAUSE; break;
- case Kshift: k = K_SHIFT; break;
- case Kctl: k = K_CTRL; break;
- case Kalt:
- case Kaltgr: k = K_ALT; break;
- case Kins: k = K_INS; break;
- default:
- if(r < 0x80)
- k = r;
- };
- return k;
-}
-
-static void
-kproc(void *)
-{
- int n, k, fd;
- char buf[128], kdown[128], *s;
- Rune r;
- Kev ev;
-
- if(threadsetgrp(THin) < 0)
- sysfatal("kproc:threadsetgrp: %r");
- if((fd = open("/dev/kbd", OREAD)) < 0)
- sysfatal("open /dev/kbd: %r");
-
- kdown[0] = kdown[1] = 0;
- while((n = read(fd, buf, sizeof buf)) > 0){
- buf[n-1] = 0;
- switch(*buf){
- case 'c':
- default:
- continue;
- case 'k':
- s = buf+1;
- while(*s){
- s += chartorune(&r, s);
- if(utfrune(kdown+1, r) == nil){
- if(k = runetokey(r)){
- ev.key = k;
- ev.down = true;
- if(send(kchan, &ev) < 0)
- sysfatal("kproc:nbsend: %r\n");
- }
- }
- }
- break;
- case 'K':
- s = kdown+1;
- while(*s){
- s += chartorune(&r, s);
- if(utfrune(buf+1, r) == nil){
- if(k = runetokey(r)){
- ev.key = k;
- ev.down = false;
- if(send(kchan, &ev) < 0)
- sysfatal("mproc:nbsend: %r\n");
- }
- }
- }
- break;
- }
- strcpy(kdown, buf);
- }
- fprint(2, "kproc: %r\n");
- close(fd);
-}
-
-static void
-mproc(void *)
-{
- int n, nerr = 0, fd;
- char buf[1+5*12];
- Mouse m;
-
- if(threadsetgrp(THin) < 0)
- sysfatal("mproc:threadsetgrp: %r");
- if((fd = open("/dev/mouse", ORDWR)) < 0)
- sysfatal("open /dev/mouse: %r");
-
- for(;;){
- if((n = read(fd, buf, sizeof buf)) != 1+4*12){
- fprint(2, "mproc:read: bad count %d not 49: %r\n", n);
- if(n < 0 || ++nerr > 10)
- break;
- continue;
- }
- nerr = 0;
- switch(*buf){
- case 'r':
- resized = 1;
- /* fall through */
- case 'm':
- if(!mouseon)
- break;
-
- m.xy.x = atoi(buf+1+0*12) - center.x;
- m.xy.y = atoi(buf+1+1*12) - center.y;
- if(m.xy.x != 0 || m.xy.y != 0)
- fprint(fd, "m%d %d", center.x, center.y);
- m.buttons = atoi(buf+1+2*12);
- m.msec = atoi(buf+1+3*12);
- if(nbsend(mchan, &m) < 0)
- sysfatal("mproc:nbsend: %r\n");
- break;
- }
- }
- fprint(2, "mproc: %r\n");
- IN_Grabm(0);
- close(fd);
-}
-
-static void
-tproc(void *) /* stupid select() timeout bullshit */
-{
- int t, ms, n, r;
-
- threadsetgrp(THin);
-
- t = ms = 0;
- for(;;){
- sleep(1);
- t++;
-
- if((r = nbrecv(tchan, &n)) < 0)
- sysfatal("tproc:nbrecv: %r");
- if(r == 0){
- if(t == ms && nbsend(fuckchan, nil) < 0)
- sysfatal("tproc:nbsend: %r");
- continue;
- }
- if(n <= 0)
- ms = 0;
- else{
- ms = n;
- t = 0;
- }
- }
-}
-
-static void
-iproc(void *)
-{
- int n;
- char s[256];
-
- threadsetgrp(THin);
-
- if((iop = pipe(pfd)) < 0)
- sysfatal("iproc:pipe: %r");
- for(;;){
- if((n = read(0, s, sizeof s)) <= 0)
- break;
- s[n-1] = 0;
- if((write(pfd[0], s, n)) != n)
- break;
- if(nbsend(fuckchan, nil) < 0)
- sysfatal("iproc:nbsend: %r");
- }
- fprint(2, "iproc %d: %r\n", threadpid(threadid()));
- iop = -1;
-}
-
-void
-IN_Shutdown(void)
-{
- qlock(&killock); /* there can be only one */
- IN_Grabm(0);
- threadkillgrp(THin);
- iop = -1;
- close(pfd[0]);
- close(pfd[1]);
- if(kchan != nil){
- chanfree(kchan);
- kchan = nil;
- }
- if(mchan != nil){
- chanfree(mchan);
- mchan = nil;
- }
- qunlock(&killock);
-}
-
-void
-IN_Init(void)
-{
- if(dedicated->value){
- if(proccreate(iproc, nil, 8192) < 0)
- sysfatal("proccreate iproc: %r");
- if(proccreate(tproc, nil, 8192) < 0)
- sysfatal("proccreate tproc: %r");
- return;
- }
- in_joystick = Cvar_Get("in_joystick", "0", CVAR_ARCHIVE);
- sensitivity = Cvar_Get("sensitivity", "3", CVAR_ARCHIVE);
- freelook = Cvar_Get("freelook", "0", CVAR_ARCHIVE);
- lookspring = Cvar_Get("lookspring", "0", CVAR_ARCHIVE);
- lookstrafe = Cvar_Get("lookstrafe", "0", CVAR_ARCHIVE);
- m_pitch = Cvar_Get("m_pitch", "0.022", CVAR_ARCHIVE);
-
- m_yaw = Cvar_Get("m_yaw", "0.022", 0);
- m_forward = Cvar_Get("m_forward", "1", 0);
- m_side = Cvar_Get("m_side", "0.8", 0);
- m_windowed = Cvar_Get("m_windowed", "0", CVAR_ARCHIVE);
- m_filter = Cvar_Get("m_filter", "0", 0);
-
- Cmd_AddCommand("+mlook", IN_MLookDown);
- Cmd_AddCommand("-mlook", IN_MLookUp);
- Cmd_AddCommand("force_centerview", IN_ForceCenterView);
-
- if((kchan = chancreate(sizeof(Kev), Nbuf)) == nil)
- sysfatal("chancreate kchan: %r");
- if(proccreate(kproc, nil, 8192) < 0)
- sysfatal("proccreate kproc: %r");
- if((mchan = chancreate(sizeof(Mouse), Nbuf)) == nil)
- sysfatal("chancreate kchan: %r");
- if(proccreate(mproc, nil, 8192) < 0)
- sysfatal("proccreate mproc: %r");
-}
--- a/plan9/menu.c
+++ /dev/null
@@ -1,137 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-extern void M_PopMenu(void);
-
-static menuframework_s vmenu;
-static menuslider_s ssizeslide, gammaslide;
-static menulist_s fullscrbox;
-static menuaction_s applyaction, defaultsaction;
-
-
-void
-vmssize(void *s)
-{
- Cvar_SetValue("viewsize", ((menuslider_s *)s)->curvalue * 10);
-}
-
-void
-vmgamma(void *s)
-{
- // invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
- Cvar_SetValue("vid_gamma", 0.8 - (((menuslider_s *)s)->curvalue/10.0 - 0.5) + 0.5);
-}
-
-void
-vmreset(void *)
-{
- VID_MenuInit();
-}
-
-void
-vmapply(void *)
-{
- Cvar_SetValue("vid_gamma", 0.8 - (gammaslide.curvalue/10.0 - 0.5) + 0.5);
- Cvar_SetValue("vid_fullscreen", fullscrbox.curvalue);
- M_ForceMenuOff();
-}
-
-void
-VID_MenuInit(void)
-{
- static char *yesno[] = {"no", "yes", nil};
-
- if(!scr_viewsize)
- scr_viewsize = Cvar_Get("viewsize", "100", CVAR_ARCHIVE);
- ssizeslide.curvalue = scr_viewsize->value/10;
-
- vmenu.x = vid.width * 0.50;
- vmenu.nitems = 0;
-
- ssizeslide.generic.type = MTYPE_SLIDER;
- ssizeslide.generic.x = 0;
- ssizeslide.generic.y = 20;
- ssizeslide.generic.name = "screen size";
- ssizeslide.minvalue = 3;
- ssizeslide.maxvalue = 12;
- ssizeslide.generic.callback = vmssize;
-
- gammaslide.generic.type = MTYPE_SLIDER;
- gammaslide.generic.x = 0;
- gammaslide.generic.y = 30;
- gammaslide.generic.name = "gamma";
- gammaslide.generic.callback = vmgamma;
- gammaslide.minvalue = 5;
- gammaslide.maxvalue = 13;
- gammaslide.curvalue = (1.3 - vid_gamma->value + 0.5) * 10;
-
- fullscrbox.generic.type = MTYPE_SPINCONTROL;
- fullscrbox.generic.x = 0;
- fullscrbox.generic.y = 40;
- fullscrbox.generic.name = "fullscreen";
- fullscrbox.itemnames = yesno;
- fullscrbox.curvalue = vid_fullscreen->value;
-
- defaultsaction.generic.type = MTYPE_ACTION;
- defaultsaction.generic.name = "reset to default";
- defaultsaction.generic.x = 0;
- defaultsaction.generic.y = 90;
- defaultsaction.generic.callback = vmreset;
-
- applyaction.generic.type = MTYPE_ACTION;
- applyaction.generic.name = "apply";
- applyaction.generic.x = 0;
- applyaction.generic.y = 100;
- applyaction.generic.callback = vmapply;
-
- Menu_AddItem(&vmenu, (void *)&ssizeslide);
- Menu_AddItem(&vmenu, (void *)&gammaslide);
- Menu_AddItem(&vmenu, (void *)&fullscrbox);
- Menu_AddItem(&vmenu, (void *)&defaultsaction);
- Menu_AddItem(&vmenu, (void *)&applyaction);
-
- Menu_Center(&vmenu);
- vmenu.x -= 8;
-}
-
-void
-VID_MenuDraw(void)
-{
- int w, h;
-
- Draw_GetPicSize(&w, &h, "m_banner_video");
- Draw_Pic(vid.width/2 - w/2, vid.height/2 - 110, "m_banner_video");
- Menu_AdjustCursor(&vmenu, 1); // starting position
- Menu_Draw(&vmenu);
-}
-
-char *VID_MenuKey (int key)
-{
- static char *sound = "misc/menu1.wav";
-
- switch(key){
- case K_ESCAPE:
- M_PopMenu();
- return NULL;
- case K_UPARROW:
- vmenu.cursor--;
- Menu_AdjustCursor(&vmenu, -1);
- break;
- case K_DOWNARROW:
- vmenu.cursor++;
- Menu_AdjustCursor(&vmenu, 1);
- break;
- case K_LEFTARROW:
- Menu_SlideItem(&vmenu, -1);
- break;
- case K_RIGHTARROW:
- Menu_SlideItem(&vmenu, 1);
- break;
- case K_ENTER:
- Menu_SelectItem(&vmenu);
- break;
- }
- return sound;
-}
--- a/plan9/snd.c
+++ /dev/null
@@ -1,128 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <thread.h>
-#include "../q_shared.h"
-
-static cvar_t *sndbits;
-static cvar_t *sndspeed;
-static cvar_t *sndchannels;
-static cvar_t *snddev;
-
-static int afd, sndon, wpos;
-enum{
- Nbuf = 32
-};
-static Channel *schan;
-static QLock sndlock;
-
-
-static void
-sproc(void *)
-{
- int n;
-
- threadsetgrp(THsnd);
-
- for(;;){
- if(recv(schan, nil) < 0){
- fprint(2, "sproc:recv %r\n");
- break;
- }
- if((n = write(afd, dma.buffer, dma.samplebits/8 * dma.samples)) < 0){
- fprint(2, "sproc:write %r\n");
- break;
- }
- qlock(&sndlock);
- wpos += n;
- qunlock(&sndlock);
- }
- fprint(2, "sproc %d: %r\n", threadpid(threadid()));
-}
-
-qboolean
-SNDDMA_Init(void)
-{
- if(sndon)
- return false;
-
- if(COM_CheckParm("-nosound"))
- return false;
-
- if(snddev == nil){
- sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
- sndspeed = Cvar_Get("sndspeed", "44100", CVAR_ARCHIVE);
- sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
- snddev = Cvar_Get("snddev", "/dev/audio", CVAR_ARCHIVE);
- }
-
- if((afd = open(snddev->string, OWRITE)) < 0){
- fprint(2, "SNDDMA_Init:open %r\n");
- return false;
- }
-
- dma.samplebits = (int)sndbits->value;
- if(dma.samplebits != 16 && dma.samplebits != 8)
- dma.samplebits = 16;
- dma.speed = (int)sndspeed->value;
- if(dma.speed != 44100)
- dma.speed = 44100;
- dma.channels = (int)sndchannels->value;
- if(dma.channels < 1 || dma.channels > 2)
- dma.channels = 2;
- dma.samples = 8192;
- dma.submission_chunk = 1;
- if((dma.buffer = mallocz(dma.samplebits/8 * dma.samples, 1)) == nil)
- sysfatal("SNDDMA_Init:mallocz: %r\n");
- dma.samplepos = 0;
- sndon = 1;
- wpos = 0;
-
- schan = chancreate(sizeof(int), Nbuf);
- if(proccreate(sproc, nil, 8192) < 0){
- SNDDMA_Shutdown();
- sysfatal("SNDDMA_Init:proccreate: %r\n");
- }
- return true;
-}
-
-int
-SNDDMA_GetDMAPos(void)
-{
- if(!sndon)
- return 0;
- qlock(&sndlock);
- dma.samplepos = wpos / (dma.samplebits/8);
- qunlock(&sndlock);
- return dma.samplepos;
-}
-
-void
-SNDDMA_Shutdown(void)
-{
- if(!sndon)
- return;
-
- threadkillgrp(THsnd);
- close(afd);
- if(schan != nil){
- chanfree(schan);
- schan = nil;
- }
- free(dma.buffer);
- sndon = 0;
-}
-
-void
-SNDDMA_Submit(void)
-{
- if(nbsend(schan, nil) < 0){
- fprint(2, "SNDDMA_Submit:nbsend: %r\n");
- SNDDMA_Shutdown();
- }
-}
-
-void
-SNDDMA_BeginPainting(void)
-{
-}
--- a/plan9/sys.c
+++ /dev/null
@@ -1,452 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <thread.h>
-#include "../q_shared.h"
-
-void KBD_Update(void);
-
-mainstacksize = 512*1024;
-int curtime;
-uint sys_frame_time;
-Channel *fuckchan, *tchan;
-
-static uchar *membase;
-static int maxhunksize, curhunksize;
-static char findbase[MAX_OSPATH], findpath[MAX_OSPATH], findpattern[MAX_OSPATH];
-static Dir *dirs;
-static long dirn, di;
-
-static int glob_match(char *, char *);
-
-
-/* Like glob_match, but match PATTERN against any final segment of TEXT. */
-static int
-glob_match_after_star(char *pattern, char *text)
-{
- char *p = pattern, *t = text;
- char c, c1;
-
- while ((c = *p++) == '?' || c == '*')
- if (c == '?' && *t++ == '\0')
- return 0;
-
- if (c == '\0')
- return 1;
-
- if (c == '\\')
- c1 = *p;
- else
- c1 = c;
-
- while (1) {
- if ((c == '[' || *t == c1) && glob_match(p - 1, t))
- return 1;
- if (*t++ == '\0')
- return 0;
- }
-}
-
-/* Return nonzero if PATTERN has any special globbing chars in it. */
-static int
-glob_pattern_p(char *pattern)
-{
- char *p = pattern;
- char c;
- int open = 0;
-
- while ((c = *p++) != '\0')
- switch (c) {
- case '?':
- case '*':
- return 1;
-
- case '[': /* Only accept an open brace if there is a close */
- open++; /* brace to match it. Bracket expressions must be */
- continue; /* complete, according to Posix.2 */
- case ']':
- if (open)
- return 1;
- continue;
-
- case '\\':
- if (*p++ == '\0')
- return 0;
- }
-
- return 0;
-}
-
-/* Match the pattern PATTERN against the string TEXT;
- return 1 if it matches, 0 otherwise.
-
- A match means the entire string TEXT is used up in matching.
-
- In the pattern string, `*' matches any sequence of characters,
- `?' matches any character, [SET] matches any character in the specified set,
- [!SET] matches any character not in the specified set.
-
- A set is composed of characters or ranges; a range looks like
- character hyphen character (as in 0-9 or A-Z).
- [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
- Any other character in the pattern must be matched exactly.
-
- To suppress the special syntactic significance of any of `[]*?!-\',
- and match the character exactly, precede it with a `\'.
-*/
-
-static int
-glob_match(char *pattern, char *text)
-{
- char *p = pattern, *t = text;
- char c, c1, cstart, cend;
- int invert;
-
- while ((c = *p++) != '\0')
- switch (c) {
- case '?':
- if (*t == '\0')
- return 0;
- else
- ++t;
- break;
-
- case '\\':
- if (*p++ != *t++)
- return 0;
- break;
-
- case '*':
- return glob_match_after_star(p, t);
-
- case '[':
- {
- c1 = *t++;
-
- if (!c1)
- return (0);
-
- invert = ((*p == '!') || (*p == '^'));
- if (invert)
- p++;
-
- c = *p++;
- while (1) {
- cstart = c;
- cend = c;
-
- if (c == '\\') {
- cstart = *p++;
- cend = cstart;
- }
- if (c == '\0')
- return 0;
-
- c = *p++;
- if (c == '-' && *p != ']') {
- cend = *p++;
- if (cend == '\\')
- cend = *p++;
- if (cend == '\0')
- return 0;
- c = *p++;
- }
- if (c1 >= cstart && c1 <= cend)
- goto match;
- if (c == ']')
- break;
- }
- if (!invert)
- return 0;
- break;
-
- match:
- /* Skip the rest of the [...] construct that already matched. */
- while (c != ']') {
- if (c == '\0')
- return 0;
- c = *p++;
- if (c == '\0')
- return 0;
- else if (c == '\\')
- ++p;
- }
- if (invert)
- return 0;
- break;
- }
-
- default:
- if (c != *t++)
- return 0;
- }
-
- /* if the pattern is empty, Sys_FindNext looks at the current file anyway */
- return *t == '\0';
-}
-
-void *
-Hunk_Begin(int maxsize)
-{
- // reserve a huge chunk of memory, but don't commit any yet
- maxhunksize = maxsize;
- curhunksize = 0;
- if((membase = mallocz(maxhunksize, 1)) == nil)
- sysfatal("Hunk_Begin:malloc %d: %r", maxhunksize);
- return membase;
-}
-
-void *
-Hunk_Alloc(int size)
-{
- byte *buf;
-
- // round to cacheline
- size = (size+31)&~31;
- if(curhunksize + size > maxhunksize)
- Sys_Error("Hunk_Alloc overflow");
- buf = membase + curhunksize;
- curhunksize += size;
- return buf;
-}
-
-int
-Hunk_End(void)
-{
- if(realloc(membase, curhunksize) != membase)
- sysfatal("Hunk_End:realloc: %r");
- return curhunksize;
-}
-
-void
-Hunk_Free(void *base)
-{
- if(base != nil)
- free(base);
-}
-
-static qboolean
-CompareAttributes(ulong m, uint musthave, uint canthave)
-{
- if(m & DMDIR && canthave & SFF_SUBDIR)
- return false;
- if(musthave & SFF_SUBDIR && ~m & DMDIR)
- return false;
- return true;
-}
-
-char *
-Sys_FindFirst(char *path, uint musthave, uint canhave)
-{
- char *p;
- int fd;
-
- if(dirs != nil)
- Sys_Error("Sys_BeginFind without close");
-
- strncpy(findbase, path, sizeof findbase-1);
- if((p = strrchr(findbase, '/')) != nil){
- *p = 0;
- strncpy(findpattern, p+1, sizeof findpattern-1);
- }else
- strcpy(findpattern, "*");
- if(strcmp(findpattern, "*.*") == 0)
- strcpy(findpattern, "*");
- if(*findpattern == '\0'){
- Com_Printf("Sys_BeginFind: empty pattern\n");
- return nil;
- }
-
- if((fd = open(findbase, OREAD)) < 0){
- fprint(2, "Sys_BeginFind:open: %r\n");
- return nil;
- }
- dirn = dirreadall(fd, &dirs);
- close(fd);
- if(dirn == 0)
- return nil;
- if(dirn < 0){
- fprint(2, "Sys_BeginFind:dirread: %r\n");
- return nil;
- }
-
- di = 0;
- return Sys_FindNext (musthave, canhave);
-}
-
-char *
-Sys_FindNext(uint musthave, uint canhave)
-{
- int i;
-
- if(dirs == nil)
- Sys_Error("Sys_FindNext without open\n");
-
- while(di < dirn){
- i = di++;
- if(glob_match(findpattern, dirs[i].name)){
- if(CompareAttributes(dirs[i].mode, musthave, canhave)){
- snprintf(findpath, sizeof findpath, "%s/%s", findbase, dirs[i].name);
- return findpath;
- }
- }
- }
- return nil;
-}
-
-void
-Sys_FindClose(void)
-{
- if(dirs != nil){
- free(dirs);
- dirs = nil;
- }
-}
-
-/* prints to "debugging console" */
-void
-Sys_ConsoleOutput(char *s)
-{
- write(1, s, strlen(s));
-}
-
-void
-Sys_Error(char *error, ...)
-{
- char buf[1024], *out;
- va_list arg;
-
- CL_Shutdown();
-
- va_start(arg, error);
- out = vseprint(buf, buf+sizeof(buf), error, arg);
- va_end(arg);
- write(2, buf, out-buf);
- print("\n");
- sysfatal("ending.");
-}
-
-int
-Sys_Milliseconds(void)
-{
- static long msbase;
-
- if(msbase == 0)
- msbase = time(nil)*1000;
- curtime = nsec()/1000000 - msbase;
- return curtime;
-}
-
-void
-Sys_Mkdir(char *path)
-{
- int d;
-
- if((d = create(path, OREAD, DMDIR|0777)) < 0)
- fprint(2, "Sys_Mkdir:create: %r\n");
- else
- close(d);
-}
-
-vlong
-flen(int fd)
-{
- uchar bs[1024];
-
- if(fstat(fd, bs, sizeof bs) < 0){
- fprint(2, "flen:fstat: %r\n");
- return -1;
- }
- return *((vlong *)(bs+2+2+4+1+4+8+4+4+4)); /* length[8] */
-}
-
-int
-Sys_FileTime(char *path)
-{
- uchar sb[1024];
-
- if(stat(path, sb, sizeof sb) < 0){
- fprint(2, "Sys_FileTime:stat: %r\n");
- return -1;
- }
- return *((int *)(sb+25));
-}
-
-void
-Sys_UnloadGame(void)
-{
-}
-
-void
-Sys_AppActivate(void)
-{
-}
-
-void
-Sys_SendKeyEvents(void)
-{
- KBD_Update();
- sys_frame_time = Sys_Milliseconds(); // grab frame time
-}
-
-char *
-Sys_GetClipboardData(void)
-{
- return nil;
-}
-
-void
-Sys_CopyProtect(void)
-{
-}
-
-void
-Sys_Quit(void)
-{
- chanfree(fuckchan);
- chanfree(tchan);
- threadexitsall(nil);
-}
-
-void
-Sys_Init(void)
-{
- //Sys_SetFPCW();
- if((fuckchan = chancreate(sizeof(int), 1)) == nil)
- sysfatal("chancreate fuckchan: %r");
- if((tchan = chancreate(sizeof(int), 16)) == nil)
- sysfatal("chancreate tchan: %r");
-}
-
-void
-croak(void *, char *note)
-{
- if(!strncmp(note, "sys:", 4)){
- IN_Shutdown();
- SNDDMA_Shutdown();
- NET_Shutdown();
- }
- noted(NDFLT);
-}
-
-void
-threadmain(int argc, char *argv[])
-{
- int time, oldtime, newtime;
-
- setfcr(getfcr() & ~(FPOVFL|FPUNFL|FPINVAL|FPZDIV)); /* assumed ignored in code */
- notify(croak);
-
- Qcommon_Init(argc, argv);
-
- oldtime = Sys_Milliseconds();
- for(;;){
- do{
- newtime = Sys_Milliseconds();
- time = newtime - oldtime;
- }while(time < 1); // find time spent rendering last frame
- Qcommon_Frame(time);
- oldtime = newtime;
- }
-}
--- a/plan9/udp.c
+++ /dev/null
@@ -1,552 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <thread.h>
-#include <bio.h>
-#include <ndb.h>
-#include <ip.h>
-#include "../q_shared.h"
-
-/* FIXME: this shit SUCKS, and ipv4 only because of other code */
-
-extern Channel *fuckchan, *tchan;
-
-static cvar_t *svport; /* server port and copy of string value */
-static char srv[6];
-static cvar_t *clport; /* "client" port and copy */
-static char clsrv[6];
-
-typedef struct Loopmsg Loopmsg;
-typedef struct Loopback Loopback;
-typedef struct Conmsg Conmsg;
-typedef struct Conlist Conlist;
-
-enum{
- Hdrsz = 16+16+16+2+2, /* sizeof Udphdr w/o padding */
- Bufsz = MAX_MSGLEN,
- Nbuf = 64,
- MAX_LOOPBACK = 4,
- CLPORT = 27909
-};
-struct Loopmsg{
- byte data[MAX_MSGLEN];
- int datalen;
-};
-struct Loopback{
- Loopmsg msgs[MAX_LOOPBACK];
- int get;
- int send;
-};
-static Loopback loopbacks[2];
-
-struct Conlist{
- Conlist *p;
- uchar u[IPaddrlen+2];
- char addr[IPaddrlen*2+8+6]; /* ipv6 + separators + port in decimal */
- int dfd;
- Udphdr h;
- int src; /* q2 assumes broadcast replies are received on NS_CLIENT */
-};
-static Conlist *cnroot;
-
-struct Conmsg{
- Conlist *p;
- int n;
- uchar buf[Bufsz];
-};
-static Channel *udpchan, *clchan;
-
-static netadr_t laddr; /* 0.0.0.0:0 */
-static int cfd = -1, ufd = -1, clfd = -1, cldfd = -1;
-static QLock cnlock;
-
-
-qboolean
-NET_CompareAdr(netadr_t a, netadr_t b)
-{
- return(a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port);
-}
-
-/* compares without the port */
-qboolean
-NET_CompareBaseAdr(netadr_t a, netadr_t b)
-{
- if(a.type != b.type)
- return false;
- switch(a.type){
- case NA_LOOPBACK:
- return true;
- case NA_IP:
- return (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3]);
- case NA_IPX:
- return !memcmp(a.ipx, b.ipx, 10);
- default:
- return false;
- }
-}
-
-char *
-NET_AdrToString(netadr_t a)
-{
- static char s[256];
-
- seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud:%hud", a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port));
- return s;
-}
-
-char *
-NET_BaseAdrToString(netadr_t a)
-{
- static char s[256];
-
- seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
- return s;
-}
-
-/*
-=============
-NET_StringToAdr
-
-localhost
-idnewt
-idnewt:28000
-192.246.40.70
-192.246.40.70:28000
-=============
-*/
-qboolean
-NET_StringToAdr(char *addr, netadr_t *a) /* assumes IPv4 */
-{
- int i;
- char s[256], *p, *pp;
- Ndbtuple *t, *nt;
-
- if(!strcmp(addr, "localhost")){
- memset(a, 0, sizeof *a);
- a->type = NA_LOOPBACK;
- return true;
- }
-
- strncpy(s, addr, sizeof s);
- s[sizeof(s)-1] = 0;
-
- /* FIXME: arbitrary length strings */
- if((p = strrchr(s, ':')) != nil){
- *p++ = '\0';
- a->port = BigShort(atoi(p));
- }
-
- if((t = dnsquery(nil, s, "ip")) == nil){
- fprint(2, "NET_StringToAdr:dnsquery %s: %r\n", s);
- return 0;
- }
-
- for(nt = t; nt != nil; nt = nt->entry)
- if(!strcmp(nt->attr, "ip")){
- strncpy(s, nt->val, sizeof(s)-1);
- break;
- }
- ndbfree(t);
-
- /* FIXMEGASHIT */
- for(i = 0, pp = s; i < IPv4addrlen; i++){
- if((p = strchr(pp, '.')) != nil)
- *p++ = '\0';
- a->ip[i] = atoi(pp);
- pp = p;
- }
- a->type = NA_IP;
- return true;
-}
-
-qboolean
-NET_IsLocalAddress(netadr_t adr)
-{
- return NET_CompareAdr(adr, laddr);
-}
-
-static int
-looprecv(netsrc_t sock, netadr_t *net_from, sizebuf_t *d)
-{
- int i;
- Loopback *l;
-
- l = &loopbacks[sock];
- if(l->send - l->get > MAX_LOOPBACK)
- l->get = l->send - MAX_LOOPBACK;
- if(l->get >= l->send)
- return 0;
- i = l->get & (MAX_LOOPBACK-1);
- l->get++;
-
- memcpy(d->data, l->msgs[i].data, l->msgs[i].datalen);
- d->cursize = l->msgs[i].datalen;
- *net_from = laddr;
- return 1;
-}
-
-static void
-loopsend(netsrc_t sock, int length, void *data, netadr_t /*to*/)
-{
- Loopback *l;
- int i;
-
- l = &loopbacks[sock^1];
- i = l->send & (MAX_LOOPBACK-1);
- l->send++;
- memcpy(l->msgs[i].data, data, length);
- l->msgs[i].datalen = length;
-}
-
-static void
-cninit(void)
-{
- if(cnroot != nil)
- return;
- if((cnroot = malloc(sizeof *cnroot)) == nil)
- sysfatal("cninit:malloc: %r");
- cnroot->p = cnroot;
- memset(cnroot->u, 0, sizeof cnroot->u);
- memset(cnroot->addr, 0, sizeof cnroot->addr);
- cnroot->dfd = -1;
-}
-
-static Conlist *
-cnins(int fd, char *addr, uchar *u, Udphdr *h, int src)
-{
- Conlist *p, *l;
-
- l = cnroot;
- if((p = malloc(sizeof *p)) == nil)
- sysfatal("cnins:malloc: %r");
-
- strncpy(p->addr, addr, sizeof p->addr);
- memcpy(p->u, u, sizeof p->u);
- p->dfd = fd;
- if(h != nil)
- memcpy(&p->h, h, sizeof p->h);
- p->src = src;
- p->p = l->p;
- l->p = p;
- return p;
-}
-
-static Conlist *
-cnfind(char *raddr)
-{
- Conlist *p = cnroot->p;
-
- while(p != cnroot){
- if(!strncmp(p->addr, raddr, strlen(p->addr)))
- return p;
- p = p->p;
- }
- return nil;
-}
-
-static void
-cndel(Conlist *p)
-{
- Conlist *l = cnroot;
-
- while(l->p != p){
- l = l->p;
- if(l == cnroot)
- sysfatal("cndel: bad unlink: cnroot 0x%p node 0x%p\n", cnroot, p);
- }
- l->p = p->p;
- if(p->dfd != ufd && p->dfd != cldfd && p->dfd != -1)
- close(p->dfd);
- free(p);
-}
-
-static void
-cnnuke(void)
-{
- Conlist *p, *l = cnroot;
-
- if(cnroot == nil)
- return;
- do{
- p = l;
- l = l->p;
- if(p->dfd != -1)
- close(p->dfd);
- free(p);
- }while(l != cnroot);
- cnroot = nil;
-}
-
-static void
-dproc(void *me)
-{
- int n, fd;
- Conmsg m;
- Conlist *p;
- Channel *c;
-
- threadsetgrp(THnet);
-
- m.p = p = me;
- c = p->src == NS_CLIENT ? clchan : udpchan;
- fd = p->dfd;
-
- for(;;){
- if((n = read(fd, m.buf, sizeof m.buf)) <= 0)
- break;
- m.n = n;
- if(send(c, &m) < 0)
- sysfatal("uproc:send: %r");
- if(nbsend(fuckchan, nil) < 0)
- sysfatal("uproc:nbsend; %r");
- }
- fprint(2, "dproc %d: %r\n", threadpid(threadid()));
- cndel(me);
-}
-
-static void
-uproc(void *c)
-{
- int n, fd;
- uchar udpbuf[Bufsz+Hdrsz], u[IPaddrlen+2];
- char a[IPaddrlen*2+8+6];
- Udphdr h;
- Conmsg m;
- Conlist *p;
-
- threadsetgrp(THnet);
-
- fd = ufd;
- if(c == clchan)
- fd = cldfd;
- for(;;){
- if((n = read(fd, udpbuf, sizeof udpbuf)) <= 0)
- sysfatal("uproc:read: %r");
- memcpy(&h, udpbuf, Hdrsz);
-
- memcpy(u, h.raddr, IPaddrlen);
- memcpy(u+IPaddrlen, h.rport, 2);
- snprint(a, sizeof a, "%ud.%ud.%ud.%ud:%hud", u[12], u[13], u[14], u[15], u[16]<<8 | u[17]);
- qlock(&cnlock);
- if((p = cnfind(a)) == nil)
- p = cnins(fd, a, u, &h, 0);
- qunlock(&cnlock);
- m.p = p;
-
- if(n - Hdrsz < 0){ /* FIXME */
- m.n = n;
- memcpy(m.buf, udpbuf, m.n);
- }else{
- m.n = n - Hdrsz;
- memcpy(m.buf, udpbuf+Hdrsz, m.n);
- }
- if(send(c, &m) < 0)
- sysfatal("uproc:send: %r");
- if(nbsend(fuckchan, nil) < 0)
- sysfatal("uproc:nbsend: %r");
- }
-}
-
-qboolean
-NET_GetPacket(netsrc_t src, netadr_t *from, sizebuf_t *d)
-{
- int n;
- Conmsg m;
-
- if(looprecv(src, from, d))
- return true;
- if(cfd == -1)
- return false;
-
- if((n = nbrecv(src == NS_SERVER ? udpchan : clchan, &m)) < 0)
- sysfatal("NET_GetPacket:nbrecv: %r");
- if(n == 0)
- return false;
-
- memcpy(from->ip, m.p->u+12, 4);
- from->port = m.p->u[17] << 8 | m.p->u[16];
- if(m.n == d->maxsize){
- Com_Printf("Oversize packet from %s\n", NET_AdrToString(*from));
- return false;
- }
- from->type = NA_IP;
- d->cursize = m.n;
- memcpy(d->data, m.buf, m.n);
- return true;
-}
-
-void
-NET_SendPacket(netsrc_t src, int length, void *data, netadr_t to)
-{
- int fd;
- char *addr, *s, *lport;
- uchar b[Bufsz+Hdrsz], u[IPaddrlen+2];
- Conlist *p;
-
- switch(to.type){
- case NA_LOOPBACK:
- loopsend(src, length, data, to);
- break;
- case NA_BROADCAST_IPX:
- case NA_IPX:
- break;
- case NA_BROADCAST:
- memset(to.ip, 0xff, 4);
- addr = NET_AdrToString(to); /* port is PORT_SERVER */
- s = strrchr(addr, ':');
- *s++ = '\0';
- if((fd = dial(netmkaddr(addr, "udp", s), clsrv, nil, nil)) < 0)
- sysfatal("NET_SendPacket:dial bcast: %r");
- if(write(fd, data, length) != length)
- sysfatal("NET_SendPacket:write bcast: %r");
- close(fd);
- break;
- case NA_IP:
- if(cfd == -1)
- break;
-
- addr = NET_AdrToString(to);
- qlock(&cnlock);
- p = cnfind(addr);
- qunlock(&cnlock);
- if(p != nil){
- fd = p->dfd;
- if(fd == ufd || fd == cldfd){
- memcpy(b, &p->h, Hdrsz);
- memcpy(b+Hdrsz, data, length);
- write(fd, b, length+Hdrsz);
- break;
- }
- }else{
- lport = strrchr(addr, ':');
- *lport++ = '\0';
- s = netmkaddr(addr, "udp", lport);
- if((fd = dial(s, srv, nil, nil)) < 0)
- sysfatal("NET_SendPacket:dial: %r");
-
- memcpy(u, v4prefix, sizeof v4prefix);
- memcpy(u+IPv4off, to.ip, IPv4addrlen);
- u[16] = to.port;
- u[17] = to.port >> 8;
- *(lport-1) = ':';
- qlock(&cnlock);
- p = cnins(fd, addr, u, nil, src);
- qunlock(&cnlock);
-
- if(proccreate(dproc, p, 8196) < 0)
- sysfatal("NET_SendPacket:proccreate: %r");
- }
- if(write(fd, data, length) != length)
- sysfatal("NET_SendPacket:write: %r");
- break;
- default:
- Com_Error(ERR_FATAL, "NET_SendPacket: bad address type");
- }
-}
-
-void
-NET_Sleep(int ms) /* sleep for ms, or wakeup for stdio or incoming packets */
-{
- if(cfd == -1 || dedicated != nil && !dedicated->value)
- return; // we're not a server, just run full speed
-
- if(send(tchan, &ms) < 0)
- sysfatal("NET_Sleep:send: %r");
- if(recv(fuckchan, nil) < 0)
- sysfatal("NET_Sleep:recv: %r");
- ms = -1;
- if(nbsend(tchan, &ms) < 0) /* stop timer */
- sysfatal("NET_Sleep:nbsend: %r");
-}
-
-static int
-openname(char *port, int *dfd, Channel **c)
-{
- int fd;
- char data[64], adir[40];
-
- if((fd = announce(netmkaddr("*", "udp", port), adir)) < 0)
- sysfatal("openname:announce udp!*!%s: %r", port);
- if(fprint(fd, "headers") < 0)
- sysfatal("openname: failed to set header mode: %r");
- snprint(data, sizeof data, "%s/data", adir);
- if((*dfd = open(data, ORDWR)) < 0)
- sysfatal("openname:open %r");
- if((*c = chancreate(sizeof(Conmsg), Nbuf)) == nil)
- sysfatal("openname:chancreate: %r");
- if(proccreate(uproc, *c, 8192) < 0)
- sysfatal("openname:proccreate: %r");
- return fd;
-}
-
-static void
-openudp(void)
-{
- if(cfd != -1)
- return;
-
- /* svport value can be changed at any time */
- if(svport->value == PORT_ANY || svport->value > 32767)
- /* FIXME */
- strncpy(srv, "*", sizeof(srv)-1);
- else
- strncpy(srv, svport->string, sizeof(srv)-1);
- cfd = openname(srv, &ufd, &udpchan);
-
- /* broadcast kluge */
- if(clport->value == PORT_ANY || clport->value > 32767)
- strncpy(clsrv, "*", sizeof(clsrv)-1);
- else
- strncpy(clsrv, clport->string, sizeof(clsrv)-1);
- clfd = openname(clsrv, &cldfd, &clchan);
-}
-
-/* a single player game will only use the loopback code */
-void
-NET_Config(qboolean multiplayer)
-{
- if(!multiplayer){ /* shut down existing udp connections */
- threadkillgrp(THnet);
- cnnuke();
- if(udpchan != nil){
- chanfree(udpchan);
- udpchan = nil;
- }
- if(clchan != nil){
- chanfree(clchan);
- clchan = nil;
- }
- if(cfd != -1){
- close(cfd);
- cfd = -1;
- }
- if(clfd != -1){
- close(clfd);
- clfd = -1;
- }
- if(ufd != -1){
- close(ufd);
- ufd = -1;
- }
- if(cldfd != -1){
- close(cldfd);
- cldfd = -1;
- }
- }else{ /* announce open line and get cfd for it */
- cninit();
- openudp();
- }
-}
-
-void
-NET_Shutdown(void)
-{
- NET_Config(false);
-}
-
-void
-NET_Init(void)
-{
- svport = Cvar_Get("port", va("%hu", PORT_SERVER), CVAR_NOSET);
- clport = Cvar_Get("clport", va("%hu", CLPORT), CVAR_NOSET);
-}
--- a/plan9/vid.c
+++ /dev/null
@@ -1,249 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <stdio.h>
-#include <ctype.h>
-#include "../q_shared.h"
-
-refexport_t re; /* exported functions from refresh DLL */
-int resized;
-Point center;
-
-typedef ulong PIXEL;
-
-static int rwon;
-static uchar *framebuf;
-static Image *fbim;
-static PIXEL st2d_8to24table[256];
-static int shiftmask_fl;
-static int r_shift, g_shift, b_shift;
-static uint r_mask, g_mask, b_mask;
-
-refexport_t GetRefAPI(refimport_t);
-
-
-static void
-shiftmask_init(void)
-{
- uint x;
-
- r_mask = 0xff0000;
- g_mask = 0xff00;
- b_mask = 0xff;
- for(r_shift = -8, x = 1; x < r_mask; x <<= 1)
- r_shift++;
- for(g_shift = -8, x = 1; x < g_mask; x <<= 1)
- g_shift++;
- for(b_shift = -8, x = 1; x < b_mask; x <<= 1)
- b_shift++;
- shiftmask_fl = 1;
-}
-
-static PIXEL
-rgb24(int r, int g, int b)
-{
- PIXEL p = 0;
-
- if(shiftmask_fl == 0)
- shiftmask_init();
-
- if(r_shift > 0)
- p = r<<r_shift & r_mask;
- else if(r_shift < 0)
- p = r>>-r_shift & r_mask;
- else
- p |= r & r_mask;
- if(g_shift > 0)
- p |= g<<g_shift & g_mask;
- else if(g_shift < 0)
- p |= g>>-g_shift & g_mask;
- else
- p |= g & g_mask;
- if(b_shift > 0)
- p |= b<<b_shift & b_mask;
- else if(b_shift < 0)
- p |= b>>-b_shift & b_mask;
- else
- p |= b & b_mask;
- return p;
-}
-
-static void
-st3_fixup(void)
-{
- int x, y;
- uchar *src;
- PIXEL *dest;
-
- for(y = 0; y < vid.height; y++){
- src = &framebuf[y*vid.rowbytes];
- dest = (PIXEL*)src;
-
- /* vid.width % 8 not always 0
- for(x = vid.width-1; x >= 0; x -= 8) {
- dest[x ] = st2d_8to24table[src[x ]];
- dest[x-1] = st2d_8to24table[src[x-1]];
- dest[x-2] = st2d_8to24table[src[x-2]];
- dest[x-3] = st2d_8to24table[src[x-3]];
- dest[x-4] = st2d_8to24table[src[x-4]];
- dest[x-5] = st2d_8to24table[src[x-5]];
- dest[x-6] = st2d_8to24table[src[x-6]];
- dest[x-7] = st2d_8to24table[src[x-7]];
- }
- */
-
- for(x = vid.width-1; x >= 0; x--)
- dest[x] = st2d_8to24table[src[x]];
- }
-}
-
-static void
-resetfb(void)
-{
- vid.width = Dx(screen->r);
- vid.height = Dy(screen->r);
- if(framebuf != nil){
- free(framebuf);
- framebuf = nil;
- }
- if(fbim != nil){
- freeimage(fbim);
- fbim = nil;
- }
- if((framebuf = malloc(sizeof *framebuf * vid.width * vid.height * screen->depth/8)) == nil)
- sysfatal("resetfb:malloc: %r");
- if((fbim = allocimage(display, Rect(0, 0, vid.width, vid.height), screen->chan, 1, DNofill)) == nil)
- sysfatal("resetfb: %r");
- vid.buffer = framebuf;
- vid.rowbytes = vid.width * screen->depth/8;
- center = addpt(screen->r.min, Pt(vid.width/2, vid.height/2));
- sw_mode->modified = true; /* make ref_soft refresh its shit */
-}
-
-int
-SWimp_Init(void *, void *)
-{
- srand(getpid());
-
- if(initdraw(nil, nil, "quake2") < 0)
- sysfatal("VID_Init:initdraw: %r\n");
- resetfb();
- rwon = 1;
- return 1;
-}
-
-/* copy backbuffer to front buffer */
-void
-SWimp_EndFrame(void)
-{
- if(resized){ /* skip frame if window resizes */
- resized = 0;
- if(getwindow(display, Refnone) < 0)
- sysfatal("SWimp_EndFrame:getwindow: %r\n");
- resetfb();
- return;
- }
- st3_fixup();
- loadimage(fbim, fbim->r, framebuf, vid.height * vid.rowbytes);
- draw(screen, screen->r, fbim, nil, ZP);
- flushimage(display, 1);
-}
-
-rserr_t
-SWimp_SetMode(int */*pwidth*/, int */*pheight*/, int /*mode*/, qboolean /*fullscreen*/)
-{
- return rserr_ok;
-}
-
-/* nil palette == use existing; palette is expected to be in padded 4-byte xRGB format */
-void
-SWimp_SetPalette(uchar *palette)
-{
- int i;
-
- if(!rwon)
- return;
- if(!palette)
- palette = (uchar *)sw_state.currentpalette;
- for(i = 0; i < 256; i++)
- st2d_8to24table[i] = rgb24(palette[i*4], palette[i*4+1], palette[i*4+2]);
-}
-
-void
-SWimp_Shutdown(void)
-{
- if(!rwon)
- return;
- if(framebuf != nil)
- free(framebuf);
- if(fbim != nil)
- freeimage(fbim);
- rwon = 0;
-}
-
-void
-SWimp_AppActivate(qboolean /*active*/)
-{
-}
-
-void
-VID_Printf(int print_level, char *fmt, ...)
-{
- va_list argptr;
- char msg[4096];
-
- va_start(argptr, fmt);
- vsprintf(msg, fmt, argptr);
- va_end(argptr);
- if(print_level == PRINT_ALL)
- Com_Printf("%s", msg);
- else
- Com_DPrintf("%s", msg);
-}
-
-void
-VID_Error(int err_level, char *fmt, ...)
-{
- va_list argptr;
- char msg[4096];
-
- va_start(argptr, fmt);
- vsprintf(msg, fmt, argptr);
- va_end(argptr);
- Com_Error(err_level, "%s", msg);
-}
-
-void
-VID_CheckChanges(void)
-{
-}
-
-void
-VID_Shutdown(void)
-{
- R_Shutdown();
-}
-
-void
-VID_Init(void)
-{
- refimport_t ri;
-
- ri.Cmd_AddCommand = Cmd_AddCommand;
- ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
- ri.Cmd_Argc = Cmd_Argc;
- ri.Cmd_Argv = Cmd_Argv;
- ri.Cmd_ExecuteText = Cbuf_ExecuteText;
- ri.Con_Printf = VID_Printf;
- ri.Sys_Error = VID_Error;
- ri.FS_LoadFile = FS_LoadFile;
- ri.FS_FreeFile = FS_FreeFile;
- ri.FS_Gamedir = FS_Gamedir;
- ri.Cvar_Get = Cvar_Get;
- ri.Cvar_Set = Cvar_Set;
- ri.Cvar_SetValue = Cvar_SetValue;
- ri.Vid_MenuInit = VID_MenuInit;
-
- re = GetRefAPI(ri);
- re.Init(nil, nil);
-}
--- /dev/null
+++ b/pmove.c
@@ -1,0 +1,1338 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+#define STEPSIZE 18
+
+// all of the locals will be zeroed before each
+// pmove, just to make damn sure we don't have
+// any differences when running on client or server
+
+typedef struct
+{
+ vec3_t origin; // full float precision
+ vec3_t velocity; // full float precision
+
+ vec3_t forward, right, up;
+ float frametime;
+
+
+ csurface_t *groundsurface;
+ cplane_t groundplane;
+ int groundcontents;
+
+ vec3_t previous_origin;
+ qboolean ladder;
+} pml_t;
+
+pmove_t *pm;
+pml_t pml;
+
+
+// movement parameters
+float pm_stopspeed = 100;
+float pm_maxspeed = 300;
+float pm_duckspeed = 100;
+float pm_accelerate = 10;
+float pm_airaccelerate = 0;
+float pm_wateraccelerate = 10;
+float pm_friction = 6;
+float pm_waterfriction = 1;
+float pm_waterspeed = 400;
+
+/*
+
+ walking up a step should kill some velocity
+
+*/
+
+
+/*
+==================
+PM_ClipVelocity
+
+Slide off of the impacting object
+returns the blocked flags (1 = floor, 2 = step / wall)
+==================
+*/
+#define STOP_EPSILON 0.1
+
+void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
+{
+ float backoff;
+ float change;
+ int i;
+
+ backoff = DotProduct (in, normal) * overbounce;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ change = normal[i]*backoff;
+ out[i] = in[i] - change;
+ if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
+ out[i] = 0;
+ }
+}
+
+
+
+
+/*
+==================
+PM_StepSlideMove
+
+Each intersection will try to step over the obstruction instead of
+sliding along it.
+
+Returns a new origin, velocity, and contact entity
+Does not modify any world state?
+==================
+*/
+#define MIN_STEP_NORMAL 0.7 // can't step up onto very steep slopes
+#define MAX_CLIP_PLANES 5
+void PM_StepSlideMove_ (void)
+{
+ int bumpcount, numbumps;
+ vec3_t dir;
+ float d;
+ int numplanes;
+ vec3_t planes[MAX_CLIP_PLANES];
+ vec3_t primal_velocity;
+ int i, j;
+ trace_t trace;
+ vec3_t end;
+ float time_left;
+
+ numbumps = 4;
+
+ VectorCopy (pml.velocity, primal_velocity);
+ numplanes = 0;
+
+ time_left = pml.frametime;
+
+ for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
+ {
+ for (i=0 ; i<3 ; i++)
+ end[i] = pml.origin[i] + time_left * pml.velocity[i];
+
+ trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
+
+ if (trace.allsolid)
+ { // entity is trapped in another solid
+ pml.velocity[2] = 0; // don't build up falling damage
+ return;
+ }
+
+ if (trace.fraction > 0)
+ { // actually covered some distance
+ VectorCopy (trace.endpos, pml.origin);
+ numplanes = 0;
+ }
+
+ if (trace.fraction == 1)
+ break; // moved the entire distance
+
+ // save entity for contact
+ if (pm->numtouch < MAXTOUCH && trace.ent)
+ {
+ pm->touchents[pm->numtouch] = trace.ent;
+ pm->numtouch++;
+ }
+
+ time_left -= time_left * trace.fraction;
+
+ // slide along this plane
+ if (numplanes >= MAX_CLIP_PLANES)
+ { // this shouldn't really happen
+ VectorCopy (vec3_origin, pml.velocity);
+ break;
+ }
+
+ VectorCopy (trace.plane.normal, planes[numplanes]);
+ numplanes++;
+
+/* commented out in release
+ float rub;
+
+ //
+ // modify velocity so it parallels all of the clip planes
+ //
+ if (numplanes == 1)
+ { // go along this plane
+ VectorCopy (pml.velocity, dir);
+ VectorNormalize (dir);
+ rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
+
+ // slide along the plane
+ PM_ClipVelocity (pml.velocity, planes[0], pml.velocity, 1.01);
+ // rub some extra speed off on xy axis
+ // not on Z, or you can scrub down walls
+ pml.velocity[0] *= rub;
+ pml.velocity[1] *= rub;
+ pml.velocity[2] *= rub;
+ }
+ else if (numplanes == 2)
+ { // go along the crease
+ VectorCopy (pml.velocity, dir);
+ VectorNormalize (dir);
+ rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
+
+ // slide along the plane
+ CrossProduct (planes[0], planes[1], dir);
+ d = DotProduct (dir, pml.velocity);
+ VectorScale (dir, d, pml.velocity);
+
+ // rub some extra speed off
+ VectorScale (pml.velocity, rub, pml.velocity);
+ }
+ else
+ {
+// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
+ VectorCopy (vec3_origin, pml.velocity);
+ break;
+ }
+
+*/
+//
+// modify original_velocity so it parallels all of the clip planes
+//
+ for (i=0 ; i<numplanes ; i++)
+ {
+ PM_ClipVelocity (pml.velocity, planes[i], pml.velocity, 1.01);
+ for (j=0 ; j<numplanes ; j++)
+ if (j != i)
+ {
+ if (DotProduct (pml.velocity, planes[j]) < 0)
+ break; // not ok
+ }
+ if (j == numplanes)
+ break;
+ }
+
+ if (i != numplanes)
+ { // go along this plane
+ }
+ else
+ { // go along the crease
+ if (numplanes != 2)
+ {
+// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
+ VectorCopy (vec3_origin, pml.velocity);
+ break;
+ }
+ CrossProduct (planes[0], planes[1], dir);
+ d = DotProduct (dir, pml.velocity);
+ VectorScale (dir, d, pml.velocity);
+ }
+ //
+ // if velocity is against the original velocity, stop dead
+ // to avoid tiny occilations in sloping corners
+ //
+ if (DotProduct (pml.velocity, primal_velocity) <= 0)
+ {
+ VectorCopy (vec3_origin, pml.velocity);
+ break;
+ }
+ }
+
+ if (pm->s.pm_time)
+ {
+ VectorCopy (primal_velocity, pml.velocity);
+ }
+}
+
+/*
+==================
+PM_StepSlideMove
+
+==================
+*/
+void PM_StepSlideMove (void)
+{
+ vec3_t start_o, start_v;
+ vec3_t down_o, down_v;
+ trace_t trace;
+ float down_dist, up_dist;
+// vec3_t delta;
+ vec3_t up, down;
+
+ VectorCopy (pml.origin, start_o);
+ VectorCopy (pml.velocity, start_v);
+
+ PM_StepSlideMove_ ();
+
+ VectorCopy (pml.origin, down_o);
+ VectorCopy (pml.velocity, down_v);
+
+ VectorCopy (start_o, up);
+ up[2] += STEPSIZE;
+
+ trace = pm->trace (up, pm->mins, pm->maxs, up);
+ if (trace.allsolid)
+ return; // can't step up
+
+ // try sliding above
+ VectorCopy (up, pml.origin);
+ VectorCopy (start_v, pml.velocity);
+
+ PM_StepSlideMove_ ();
+
+ // push down the final amount
+ VectorCopy (pml.origin, down);
+ down[2] -= STEPSIZE;
+ trace = pm->trace (pml.origin, pm->mins, pm->maxs, down);
+ if (!trace.allsolid)
+ {
+ VectorCopy (trace.endpos, pml.origin);
+ }
+
+/*
+ VectorSubtract (pml.origin, up, delta);
+ up_dist = DotProduct (delta, start_v);
+
+ VectorSubtract (down_o, start_o, delta);
+ down_dist = DotProduct (delta, start_v);
+*/
+ VectorCopy(pml.origin, up);
+
+ // decide which one went farther
+ down_dist = (down_o[0] - start_o[0])*(down_o[0] - start_o[0])
+ + (down_o[1] - start_o[1])*(down_o[1] - start_o[1]);
+ up_dist = (up[0] - start_o[0])*(up[0] - start_o[0])
+ + (up[1] - start_o[1])*(up[1] - start_o[1]);
+
+ if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL)
+ {
+ VectorCopy (down_o, pml.origin);
+ VectorCopy (down_v, pml.velocity);
+ return;
+ }
+ //!! Special case
+ // if we were walking along a plane, then we need to copy the Z over
+ pml.velocity[2] = down_v[2];
+}
+
+
+/*
+==================
+PM_Friction
+
+Handles both ground friction and water friction
+==================
+*/
+void PM_Friction (void)
+{
+ float *vel;
+ float speed, newspeed, control;
+ float friction;
+ float drop;
+
+ vel = pml.velocity;
+
+ speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]);
+ if (speed < 1)
+ {
+ vel[0] = 0;
+ vel[1] = 0;
+ return;
+ }
+
+ drop = 0;
+
+// apply ground friction
+ if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK) ) || (pml.ladder) )
+ {
+ friction = pm_friction;
+ control = speed < pm_stopspeed ? pm_stopspeed : speed;
+ drop += control*friction*pml.frametime;
+ }
+
+// apply water friction
+ if (pm->waterlevel && !pml.ladder)
+ drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
+
+// scale the velocity
+ newspeed = speed - drop;
+ if (newspeed < 0)
+ {
+ newspeed = 0;
+ }
+ newspeed /= speed;
+
+ vel[0] = vel[0] * newspeed;
+ vel[1] = vel[1] * newspeed;
+ vel[2] = vel[2] * newspeed;
+}
+
+
+/*
+==============
+PM_Accelerate
+
+Handles user intended acceleration
+==============
+*/
+void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel)
+{
+ int i;
+ float addspeed, accelspeed, currentspeed;
+
+ currentspeed = DotProduct (pml.velocity, wishdir);
+ addspeed = wishspeed - currentspeed;
+ if (addspeed <= 0)
+ return;
+ accelspeed = accel*pml.frametime*wishspeed;
+ if (accelspeed > addspeed)
+ accelspeed = addspeed;
+
+ for (i=0 ; i<3 ; i++)
+ pml.velocity[i] += accelspeed*wishdir[i];
+}
+
+void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel)
+{
+ int i;
+ float addspeed, accelspeed, currentspeed, wishspd = wishspeed;
+
+ if (wishspd > 30)
+ wishspd = 30;
+ currentspeed = DotProduct (pml.velocity, wishdir);
+ addspeed = wishspd - currentspeed;
+ if (addspeed <= 0)
+ return;
+ accelspeed = accel * wishspeed * pml.frametime;
+ if (accelspeed > addspeed)
+ accelspeed = addspeed;
+
+ for (i=0 ; i<3 ; i++)
+ pml.velocity[i] += accelspeed*wishdir[i];
+}
+
+/*
+=============
+PM_AddCurrents
+=============
+*/
+void PM_AddCurrents (vec3_t wishvel)
+{
+ vec3_t v;
+ float s;
+
+ //
+ // account for ladders
+ //
+
+ if (pml.ladder && fabs(pml.velocity[2]) <= 200)
+ {
+ if ((pm->viewangles[PITCH] <= -15) && (pm->cmd.forwardmove > 0))
+ wishvel[2] = 200;
+ else if ((pm->viewangles[PITCH] >= 15) && (pm->cmd.forwardmove > 0))
+ wishvel[2] = -200;
+ else if (pm->cmd.upmove > 0)
+ wishvel[2] = 200;
+ else if (pm->cmd.upmove < 0)
+ wishvel[2] = -200;
+ else
+ wishvel[2] = 0;
+
+ // limit horizontal speed when on a ladder
+ if (wishvel[0] < -25)
+ wishvel[0] = -25;
+ else if (wishvel[0] > 25)
+ wishvel[0] = 25;
+
+ if (wishvel[1] < -25)
+ wishvel[1] = -25;
+ else if (wishvel[1] > 25)
+ wishvel[1] = 25;
+ }
+
+
+ //
+ // add water currents
+ //
+
+ if (pm->watertype & MASK_CURRENT)
+ {
+ VectorClear (v);
+
+ if (pm->watertype & CONTENTS_CURRENT_0)
+ v[0] += 1;
+ if (pm->watertype & CONTENTS_CURRENT_90)
+ v[1] += 1;
+ if (pm->watertype & CONTENTS_CURRENT_180)
+ v[0] -= 1;
+ if (pm->watertype & CONTENTS_CURRENT_270)
+ v[1] -= 1;
+ if (pm->watertype & CONTENTS_CURRENT_UP)
+ v[2] += 1;
+ if (pm->watertype & CONTENTS_CURRENT_DOWN)
+ v[2] -= 1;
+
+ s = pm_waterspeed;
+ if ((pm->waterlevel == 1) && (pm->groundentity))
+ s /= 2;
+
+ VectorMA (wishvel, s, v, wishvel);
+ }
+
+ //
+ // add conveyor belt velocities
+ //
+
+ if (pm->groundentity)
+ {
+ VectorClear (v);
+
+ if (pml.groundcontents & CONTENTS_CURRENT_0)
+ v[0] += 1;
+ if (pml.groundcontents & CONTENTS_CURRENT_90)
+ v[1] += 1;
+ if (pml.groundcontents & CONTENTS_CURRENT_180)
+ v[0] -= 1;
+ if (pml.groundcontents & CONTENTS_CURRENT_270)
+ v[1] -= 1;
+ if (pml.groundcontents & CONTENTS_CURRENT_UP)
+ v[2] += 1;
+ if (pml.groundcontents & CONTENTS_CURRENT_DOWN)
+ v[2] -= 1;
+
+ VectorMA (wishvel, 100 /* pm->groundentity->speed */, v, wishvel);
+ }
+}
+
+
+/*
+===================
+PM_WaterMove
+
+===================
+*/
+void PM_WaterMove (void)
+{
+ int i;
+ vec3_t wishvel;
+ float wishspeed;
+ vec3_t wishdir;
+
+//
+// user intentions
+//
+ for (i=0 ; i<3 ; i++)
+ wishvel[i] = pml.forward[i]*pm->cmd.forwardmove + pml.right[i]*pm->cmd.sidemove;
+
+ if (!pm->cmd.forwardmove && !pm->cmd.sidemove && !pm->cmd.upmove)
+ wishvel[2] -= 60; // drift towards bottom
+ else
+ wishvel[2] += pm->cmd.upmove;
+
+ PM_AddCurrents (wishvel);
+
+ VectorCopy (wishvel, wishdir);
+ wishspeed = VectorNormalize(wishdir);
+
+ if (wishspeed > pm_maxspeed)
+ {
+ VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
+ wishspeed = pm_maxspeed;
+ }
+ wishspeed *= 0.5;
+
+ PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
+
+ PM_StepSlideMove ();
+}
+
+
+/*
+===================
+PM_AirMove
+
+===================
+*/
+void PM_AirMove (void)
+{
+ int i;
+ vec3_t wishvel;
+ float fmove, smove;
+ vec3_t wishdir;
+ float wishspeed;
+ float maxspeed;
+
+ fmove = pm->cmd.forwardmove;
+ smove = pm->cmd.sidemove;
+
+//!!!!! pitch should be 1/3 so this isn't needed??!
+/*
+ pml.forward[2] = 0;
+ pml.right[2] = 0;
+ VectorNormalize (pml.forward);
+ VectorNormalize (pml.right);
+*/
+
+ for (i=0 ; i<2 ; i++)
+ wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
+ wishvel[2] = 0;
+
+ PM_AddCurrents (wishvel);
+
+ VectorCopy (wishvel, wishdir);
+ wishspeed = VectorNormalize(wishdir);
+
+//
+// clamp to server defined max speed
+//
+ maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pm_maxspeed;
+
+ if (wishspeed > maxspeed)
+ {
+ VectorScale (wishvel, maxspeed/wishspeed, wishvel);
+ wishspeed = maxspeed;
+ }
+
+ if ( pml.ladder )
+ {
+ PM_Accelerate (wishdir, wishspeed, pm_accelerate);
+ if (!wishvel[2])
+ {
+ if (pml.velocity[2] > 0)
+ {
+ pml.velocity[2] -= pm->s.gravity * pml.frametime;
+ if (pml.velocity[2] < 0)
+ pml.velocity[2] = 0;
+ }
+ else
+ {
+ pml.velocity[2] += pm->s.gravity * pml.frametime;
+ if (pml.velocity[2] > 0)
+ pml.velocity[2] = 0;
+ }
+ }
+ PM_StepSlideMove ();
+ }
+ else if ( pm->groundentity )
+ { // walking on ground
+ pml.velocity[2] = 0; //!!! this is before the accel
+ PM_Accelerate (wishdir, wishspeed, pm_accelerate);
+
+// PGM -- fix for negative trigger_gravity fields
+// pml.velocity[2] = 0;
+ if(pm->s.gravity > 0)
+ pml.velocity[2] = 0;
+ else
+ pml.velocity[2] -= pm->s.gravity * pml.frametime;
+// PGM
+
+ if (!pml.velocity[0] && !pml.velocity[1])
+ return;
+ PM_StepSlideMove ();
+ }
+ else
+ { // not on ground, so little effect on velocity
+ if (pm_airaccelerate)
+ PM_AirAccelerate (wishdir, wishspeed, pm_accelerate);
+ else
+ PM_Accelerate (wishdir, wishspeed, 1);
+ // add gravity
+ pml.velocity[2] -= pm->s.gravity * pml.frametime;
+ PM_StepSlideMove ();
+ }
+}
+
+
+
+/*
+=============
+PM_CatagorizePosition
+=============
+*/
+void PM_CatagorizePosition (void)
+{
+ vec3_t point;
+ int cont;
+ trace_t trace;
+ int sample1;
+ int sample2;
+
+// if the player hull point one unit down is solid, the player
+// is on ground
+
+// see if standing on something solid
+ point[0] = pml.origin[0];
+ point[1] = pml.origin[1];
+ point[2] = pml.origin[2] - 0.25;
+ if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel)
+ {
+ pm->s.pm_flags &= ~PMF_ON_GROUND;
+ pm->groundentity = NULL;
+ }
+ else
+ {
+ trace = pm->trace (pml.origin, pm->mins, pm->maxs, point);
+ pml.groundplane = trace.plane;
+ pml.groundsurface = trace.surface;
+ pml.groundcontents = trace.contents;
+
+ if (!trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid) )
+ {
+ pm->groundentity = NULL;
+ pm->s.pm_flags &= ~PMF_ON_GROUND;
+ }
+ else
+ {
+ pm->groundentity = trace.ent;
+
+ // hitting solid ground will end a waterjump
+ if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
+ {
+ pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
+ pm->s.pm_time = 0;
+ }
+
+ if (! (pm->s.pm_flags & PMF_ON_GROUND) )
+ { // just hit the ground
+ pm->s.pm_flags |= PMF_ON_GROUND;
+ // don't do landing time if we were just going down a slope
+ if (pml.velocity[2] < -200)
+ {
+ pm->s.pm_flags |= PMF_TIME_LAND;
+ // don't allow another jump for a little while
+ if (pml.velocity[2] < -400)
+ pm->s.pm_time = 25;
+ else
+ pm->s.pm_time = 18;
+ }
+ }
+ }
+
+/*
+ if (trace.fraction < 1.0 && trace.ent && pml.velocity[2] < 0)
+ pml.velocity[2] = 0;
+*/
+
+ if (pm->numtouch < MAXTOUCH && trace.ent)
+ {
+ pm->touchents[pm->numtouch] = trace.ent;
+ pm->numtouch++;
+ }
+ }
+
+//
+// get waterlevel, accounting for ducking
+//
+ pm->waterlevel = 0;
+ pm->watertype = 0;
+
+ sample2 = pm->viewheight - pm->mins[2];
+ sample1 = sample2 / 2;
+
+ point[2] = pml.origin[2] + pm->mins[2] + 1;
+ cont = pm->pointcontents (point);
+
+ if (cont & MASK_WATER)
+ {
+ pm->watertype = cont;
+ pm->waterlevel = 1;
+ point[2] = pml.origin[2] + pm->mins[2] + sample1;
+ cont = pm->pointcontents (point);
+ if (cont & MASK_WATER)
+ {
+ pm->waterlevel = 2;
+ point[2] = pml.origin[2] + pm->mins[2] + sample2;
+ cont = pm->pointcontents (point);
+ if (cont & MASK_WATER)
+ pm->waterlevel = 3;
+ }
+ }
+
+}
+
+
+/*
+=============
+PM_CheckJump
+=============
+*/
+void PM_CheckJump (void)
+{
+ if (pm->s.pm_flags & PMF_TIME_LAND)
+ { // hasn't been long enough since landing to jump again
+ return;
+ }
+
+ if (pm->cmd.upmove < 10)
+ { // not holding jump
+ pm->s.pm_flags &= ~PMF_JUMP_HELD;
+ return;
+ }
+
+ // must wait for jump to be released
+ if (pm->s.pm_flags & PMF_JUMP_HELD)
+ return;
+
+ if (pm->s.pm_type == PM_DEAD)
+ return;
+
+ if (pm->waterlevel >= 2)
+ { // swimming, not jumping
+ pm->groundentity = NULL;
+
+ if (pml.velocity[2] <= -300)
+ return;
+
+ if (pm->watertype == CONTENTS_WATER)
+ pml.velocity[2] = 100;
+ else if (pm->watertype == CONTENTS_SLIME)
+ pml.velocity[2] = 80;
+ else
+ pml.velocity[2] = 50;
+ return;
+ }
+
+ if (pm->groundentity == NULL)
+ return; // in air, so no effect
+
+ pm->s.pm_flags |= PMF_JUMP_HELD;
+
+ pm->groundentity = NULL;
+ pml.velocity[2] += 270;
+ if (pml.velocity[2] < 270)
+ pml.velocity[2] = 270;
+}
+
+
+/*
+=============
+PM_CheckSpecialMovement
+=============
+*/
+void PM_CheckSpecialMovement (void)
+{
+ vec3_t spot;
+ int cont;
+ vec3_t flatforward;
+ trace_t trace;
+
+ if (pm->s.pm_time)
+ return;
+
+ pml.ladder = false;
+
+ // check for ladder
+ flatforward[0] = pml.forward[0];
+ flatforward[1] = pml.forward[1];
+ flatforward[2] = 0;
+ VectorNormalize (flatforward);
+
+ VectorMA (pml.origin, 1, flatforward, spot);
+ trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot);
+ if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER))
+ pml.ladder = true;
+
+ // check for water jump
+ if (pm->waterlevel != 2)
+ return;
+
+ VectorMA (pml.origin, 30, flatforward, spot);
+ spot[2] += 4;
+ cont = pm->pointcontents (spot);
+ if (!(cont & CONTENTS_SOLID))
+ return;
+
+ spot[2] += 16;
+ cont = pm->pointcontents (spot);
+ if (cont)
+ return;
+ // jump out of water
+ VectorScale (flatforward, 50, pml.velocity);
+ pml.velocity[2] = 350;
+
+ pm->s.pm_flags |= PMF_TIME_WATERJUMP;
+ pm->s.pm_time = 255;
+}
+
+
+/*
+===============
+PM_FlyMove
+===============
+*/
+void PM_FlyMove (qboolean doclip)
+{
+ float speed, drop, friction, control, newspeed;
+ float currentspeed, addspeed, accelspeed;
+ int i;
+ vec3_t wishvel;
+ float fmove, smove;
+ vec3_t wishdir;
+ float wishspeed;
+ vec3_t end;
+ trace_t trace;
+
+ pm->viewheight = 22;
+
+ // friction
+
+ speed = VectorLength (pml.velocity);
+ if (speed < 1)
+ {
+ VectorCopy (vec3_origin, pml.velocity);
+ }
+ else
+ {
+ drop = 0;
+
+ friction = pm_friction*1.5; // extra friction
+ control = speed < pm_stopspeed ? pm_stopspeed : speed;
+ drop += control*friction*pml.frametime;
+
+ // scale the velocity
+ newspeed = speed - drop;
+ if (newspeed < 0)
+ newspeed = 0;
+ newspeed /= speed;
+
+ VectorScale (pml.velocity, newspeed, pml.velocity);
+ }
+
+ // accelerate
+ fmove = pm->cmd.forwardmove;
+ smove = pm->cmd.sidemove;
+
+ VectorNormalize (pml.forward);
+ VectorNormalize (pml.right);
+
+ for (i=0 ; i<3 ; i++)
+ wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
+ wishvel[2] += pm->cmd.upmove;
+
+ VectorCopy (wishvel, wishdir);
+ wishspeed = VectorNormalize(wishdir);
+
+ //
+ // clamp to server defined max speed
+ //
+ if (wishspeed > pm_maxspeed)
+ {
+ VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
+ wishspeed = pm_maxspeed;
+ }
+
+
+ currentspeed = DotProduct(pml.velocity, wishdir);
+ addspeed = wishspeed - currentspeed;
+ if (addspeed <= 0)
+ return;
+ accelspeed = pm_accelerate*pml.frametime*wishspeed;
+ if (accelspeed > addspeed)
+ accelspeed = addspeed;
+
+ for (i=0 ; i<3 ; i++)
+ pml.velocity[i] += accelspeed*wishdir[i];
+
+ if (doclip) {
+ for (i=0 ; i<3 ; i++)
+ end[i] = pml.origin[i] + pml.frametime * pml.velocity[i];
+
+ trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
+
+ VectorCopy (trace.endpos, pml.origin);
+ } else {
+ // move
+ VectorMA (pml.origin, pml.frametime, pml.velocity, pml.origin);
+ }
+}
+
+
+/*
+==============
+PM_CheckDuck
+
+Sets mins, maxs, and pm->viewheight
+==============
+*/
+void PM_CheckDuck (void)
+{
+ trace_t trace;
+
+ pm->mins[0] = -16;
+ pm->mins[1] = -16;
+
+ pm->maxs[0] = 16;
+ pm->maxs[1] = 16;
+
+ if (pm->s.pm_type == PM_GIB)
+ {
+ pm->mins[2] = 0;
+ pm->maxs[2] = 16;
+ pm->viewheight = 8;
+ return;
+ }
+
+ pm->mins[2] = -24;
+
+ if (pm->s.pm_type == PM_DEAD)
+ {
+ pm->s.pm_flags |= PMF_DUCKED;
+ }
+ else if (pm->cmd.upmove < 0 && (pm->s.pm_flags & PMF_ON_GROUND) )
+ { // duck
+ pm->s.pm_flags |= PMF_DUCKED;
+ }
+ else
+ { // stand up if possible
+ if (pm->s.pm_flags & PMF_DUCKED)
+ {
+ // try to stand up
+ pm->maxs[2] = 32;
+ trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin);
+ if (!trace.allsolid)
+ pm->s.pm_flags &= ~PMF_DUCKED;
+ }
+ }
+
+ if (pm->s.pm_flags & PMF_DUCKED)
+ {
+ pm->maxs[2] = 4;
+ pm->viewheight = -2;
+ }
+ else
+ {
+ pm->maxs[2] = 32;
+ pm->viewheight = 22;
+ }
+}
+
+
+/*
+==============
+PM_DeadMove
+==============
+*/
+void PM_DeadMove (void)
+{
+ float forward;
+
+ if (!pm->groundentity)
+ return;
+
+ // extra friction
+
+ forward = VectorLength (pml.velocity);
+ forward -= 20;
+ if (forward <= 0)
+ {
+ VectorClear (pml.velocity);
+ }
+ else
+ {
+ VectorNormalize (pml.velocity);
+ VectorScale (pml.velocity, forward, pml.velocity);
+ }
+}
+
+
+qboolean PM_GoodPosition (void)
+{
+ trace_t trace;
+ vec3_t origin, end;
+ int i;
+
+ if (pm->s.pm_type == PM_SPECTATOR)
+ return true;
+
+ for (i=0 ; i<3 ; i++)
+ origin[i] = end[i] = pm->s.origin[i]*0.125;
+ trace = pm->trace (origin, pm->mins, pm->maxs, end);
+
+ return !trace.allsolid;
+}
+
+/*
+================
+PM_SnapPosition
+
+On exit, the origin will have a value that is pre-quantized to the 0.125
+precision of the network channel and in a valid position.
+================
+*/
+void PM_SnapPosition (void)
+{
+ int sign[3];
+ int i, j, bits;
+ short base[3];
+ // try all single bits first
+ static int jitterbits[8] = {0,4,1,2,3,5,6,7};
+
+ // snap velocity to eigths
+ for (i=0 ; i<3 ; i++)
+ pm->s.velocity[i] = (int)(pml.velocity[i]*8);
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if (pml.origin[i] >= 0)
+ sign[i] = 1;
+ else
+ sign[i] = -1;
+ pm->s.origin[i] = (int)(pml.origin[i]*8);
+ if (pm->s.origin[i]*0.125 == pml.origin[i])
+ sign[i] = 0;
+ }
+ VectorCopy (pm->s.origin, base);
+
+ // try all combinations
+ for (j=0 ; j<8 ; j++)
+ {
+ bits = jitterbits[j];
+ VectorCopy (base, pm->s.origin);
+ for (i=0 ; i<3 ; i++)
+ if (bits & (1<<i) )
+ pm->s.origin[i] += sign[i];
+
+ if (PM_GoodPosition ())
+ return;
+ }
+
+ // go back to the last position
+ VectorCopy (pml.previous_origin, pm->s.origin);
+// Com_DPrintf ("using previous_origin\n");
+}
+
+/*
+================
+PM_InitialSnapPosition
+
+================
+*/
+/* NO LONGER USED
+void PM_InitialSnapPosition (void)
+{
+ int x, y, z;
+ short base[3];
+
+ VectorCopy (pm->s.origin, base);
+
+ for (z=1 ; z>=-1 ; z--)
+ {
+ pm->s.origin[2] = base[2] + z;
+ for (y=1 ; y>=-1 ; y--)
+ {
+ pm->s.origin[1] = base[1] + y;
+ for (x=1 ; x>=-1 ; x--)
+ {
+ pm->s.origin[0] = base[0] + x;
+ if (PM_GoodPosition ())
+ {
+ pml.origin[0] = pm->s.origin[0]*0.125;
+ pml.origin[1] = pm->s.origin[1]*0.125;
+ pml.origin[2] = pm->s.origin[2]*0.125;
+ VectorCopy (pm->s.origin, pml.previous_origin);
+ return;
+ }
+ }
+ }
+ }
+
+ Com_DPrintf ("Bad InitialSnapPosition\n");
+}
+*/
+/*
+================
+PM_InitialSnapPosition
+
+================
+*/
+void PM_InitialSnapPosition(void)
+{
+ int x, y, z;
+ short base[3];
+ static int offset[3] = { 0, -1, 1 };
+
+ VectorCopy (pm->s.origin, base);
+
+ for ( z = 0; z < 3; z++ ) {
+ pm->s.origin[2] = base[2] + offset[ z ];
+ for ( y = 0; y < 3; y++ ) {
+ pm->s.origin[1] = base[1] + offset[ y ];
+ for ( x = 0; x < 3; x++ ) {
+ pm->s.origin[0] = base[0] + offset[ x ];
+ if (PM_GoodPosition ()) {
+ pml.origin[0] = pm->s.origin[0]*0.125;
+ pml.origin[1] = pm->s.origin[1]*0.125;
+ pml.origin[2] = pm->s.origin[2]*0.125;
+ VectorCopy (pm->s.origin, pml.previous_origin);
+ return;
+ }
+ }
+ }
+ }
+
+ Com_DPrintf ("Bad InitialSnapPosition\n");
+}
+
+/*
+================
+PM_ClampAngles
+
+================
+*/
+void PM_ClampAngles (void)
+{
+ short temp;
+ int i;
+
+ if (pm->s.pm_flags & PMF_TIME_TELEPORT)
+ {
+ pm->viewangles[YAW] = SHORT2ANGLE(pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]);
+ pm->viewangles[PITCH] = 0;
+ pm->viewangles[ROLL] = 0;
+ }
+ else
+ {
+ // circularly clamp the angles with deltas
+ for (i=0 ; i<3 ; i++)
+ {
+ temp = pm->cmd.angles[i] + pm->s.delta_angles[i];
+ pm->viewangles[i] = SHORT2ANGLE(temp);
+ }
+
+ // don't let the player look up or down more than 90 degrees
+ if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180)
+ pm->viewangles[PITCH] = 89;
+ else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180)
+ pm->viewangles[PITCH] = 271;
+ }
+ AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up);
+}
+
+/*
+================
+Pmove
+
+Can be called by either the server or the client
+================
+*/
+void Pmove (pmove_t *pmove)
+{
+ pm = pmove;
+
+ // clear results
+ pm->numtouch = 0;
+ VectorClear (pm->viewangles);
+ pm->viewheight = 0;
+ pm->groundentity = 0;
+ pm->watertype = 0;
+ pm->waterlevel = 0;
+
+ // clear all pmove local vars
+ memset (&pml, 0, sizeof(pml));
+
+ // convert origin and velocity to float values
+ pml.origin[0] = pm->s.origin[0]*0.125;
+ pml.origin[1] = pm->s.origin[1]*0.125;
+ pml.origin[2] = pm->s.origin[2]*0.125;
+
+ pml.velocity[0] = pm->s.velocity[0]*0.125;
+ pml.velocity[1] = pm->s.velocity[1]*0.125;
+ pml.velocity[2] = pm->s.velocity[2]*0.125;
+
+ // save old org in case we get stuck
+ VectorCopy (pm->s.origin, pml.previous_origin);
+
+ pml.frametime = pm->cmd.msec * 0.001;
+
+ PM_ClampAngles ();
+
+ if (pm->s.pm_type == PM_SPECTATOR)
+ {
+ PM_FlyMove (false);
+ PM_SnapPosition ();
+ return;
+ }
+
+ if (pm->s.pm_type >= PM_DEAD)
+ {
+ pm->cmd.forwardmove = 0;
+ pm->cmd.sidemove = 0;
+ pm->cmd.upmove = 0;
+ }
+
+ if (pm->s.pm_type == PM_FREEZE)
+ return; // no movement at all
+
+ // set mins, maxs, and viewheight
+ PM_CheckDuck ();
+
+ if (pm->snapinitial)
+ PM_InitialSnapPosition ();
+
+ // set groundentity, watertype, and waterlevel
+ PM_CatagorizePosition ();
+
+ if (pm->s.pm_type == PM_DEAD)
+ PM_DeadMove ();
+
+ PM_CheckSpecialMovement ();
+
+ // drop timing counter
+ if (pm->s.pm_time)
+ {
+ int msec;
+
+ msec = pm->cmd.msec >> 3;
+ if (!msec)
+ msec = 1;
+ if ( msec >= pm->s.pm_time)
+ {
+ pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
+ pm->s.pm_time = 0;
+ }
+ else
+ pm->s.pm_time -= msec;
+ }
+
+ if (pm->s.pm_flags & PMF_TIME_TELEPORT)
+ { // teleport pause stays exactly in place
+ }
+ else if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
+ { // waterjump has no control, but falls
+ pml.velocity[2] -= pm->s.gravity * pml.frametime;
+ if (pml.velocity[2] < 0)
+ { // cancel as soon as we are falling down again
+ pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
+ pm->s.pm_time = 0;
+ }
+
+ PM_StepSlideMove ();
+ }
+ else
+ {
+ PM_CheckJump ();
+
+ PM_Friction ();
+
+ if (pm->waterlevel >= 2)
+ PM_WaterMove ();
+ else {
+ vec3_t angles;
+
+ VectorCopy(pm->viewangles, angles);
+ if (angles[PITCH] > 180)
+ angles[PITCH] = angles[PITCH] - 360;
+ angles[PITCH] /= 3;
+
+ AngleVectors (angles, pml.forward, pml.right, pml.up);
+
+ PM_AirMove ();
+ }
+ }
+
+ // set groundentity, watertype, and waterlevel for final spot
+ PM_CatagorizePosition ();
+
+ PM_SnapPosition ();
+}
+
--- a/q_shared.h
+++ /dev/null
@@ -1,1149 +1,0 @@
-// q_shared.h -- included first by ALL program modules
-
-//#define id386
-
-typedef unsigned char byte;
-typedef enum {false, true} qboolean;
-
-typedef struct edict_t edict_t;
-
-// angle indexes
-#define PITCH 0 // up / down
-#define YAW 1 // left / right
-#define ROLL 2 // fall over
-
-#define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString
-#define MAX_STRING_TOKENS 80 // max tokens resulting from Cmd_TokenizeString
-#define MAX_TOKEN_CHARS 128 // max length of an individual token
-
-#define MAX_QPATH 64 // max length of a quake game pathname
-#define MAX_OSPATH 128 // max length of a filesystem pathname
-
-//
-// per-level limits
-//
-#define MAX_CLIENTS 256 // absolute limit
-#define MAX_EDICTS 1024 // must change protocol to increase more
-#define MAX_LIGHTSTYLES 256
-#define MAX_MODELS 256 // these are sent over the net as bytes
-#define MAX_SOUNDS 256 // so they cannot be blindly increased
-#define MAX_IMAGES 256
-#define MAX_ITEMS 256
-#define MAX_GENERAL (MAX_CLIENTS*2) // general config strings
-
-
-// game print flags
-#define PRINT_LOW 0 // pickup messages
-#define PRINT_MEDIUM 1 // death messages
-#define PRINT_HIGH 2 // critical messages
-#define PRINT_CHAT 3 // chat messages
-
-
-// destination class for gi.multicast()
-typedef enum
-{
-MULTICAST_ALL,
-MULTICAST_PHS,
-MULTICAST_PVS,
-MULTICAST_ALL_R,
-MULTICAST_PHS_R,
-MULTICAST_PVS_R
-} multicast_t;
-
-
-/*
-==============================================================
-
-MATHLIB
-
-==============================================================
-*/
-
-typedef float vec_t;
-typedef vec_t vec3_t[3];
-typedef vec_t vec5_t[5];
-
-typedef int fixed4_t;
-typedef int fixed8_t;
-typedef int fixed16_t;
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
-#endif
-
-struct cplane_s;
-
-extern vec3_t vec3_origin;
-
-#define nanmask (255<<23)
-
-#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
-
-#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
-#define VectorSubtract(a,b,c) (c[0]=a[0]-b[0],c[1]=a[1]-b[1],c[2]=a[2]-b[2])
-#define VectorAdd(a,b,c) (c[0]=a[0]+b[0],c[1]=a[1]+b[1],c[2]=a[2]+b[2])
-#define VectorCopy(a,b) (b[0]=a[0],b[1]=a[1],b[2]=a[2])
-#define VectorClear(a) (a[0]=a[1]=a[2]=0)
-#define VectorNegate(a,b) (b[0]=-a[0],b[1]=-a[1],b[2]=-a[2])
-#define VectorSet(v, x, y, z) (v[0]=(x), v[1]=(y), v[2]=(z))
-
-void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc);
-
-// just in case you do't want to use the macros
-vec_t _DotProduct (vec3_t v1, vec3_t v2);
-void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out);
-void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out);
-void _VectorCopy (vec3_t in, vec3_t out);
-
-void ClearBounds (vec3_t mins, vec3_t maxs);
-void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs);
-int VectorCompare (vec3_t v1, vec3_t v2);
-vec_t VectorLength (vec3_t v);
-void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
-vec_t VectorNormalize (vec3_t v); // returns vector length
-vec_t VectorNormalize2 (vec3_t v, vec3_t out);
-void VectorInverse (vec3_t v);
-void VectorScale (vec3_t in, vec_t scale, vec3_t out);
-
-void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
-void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);
-
-void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane);
-float anglemod(float a);
-float LerpAngle (float a1, float a2, float frac);
-
-#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \
- (((p)->type < 3)? \
- ( \
- ((p)->dist <= (emins)[(p)->type])? \
- 1 \
- : \
- ( \
- ((p)->dist >= (emaxs)[(p)->type])?\
- 2 \
- : \
- 3 \
- ) \
- ) \
- : \
- BoxOnPlaneSide( (emins), (emaxs), (p)))
-
-void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal );
-void PerpendicularVector( vec3_t dst, const vec3_t src );
-void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
-
-
-//=============================================
-
-char *COM_SkipPath (char *pathname);
-void COM_StripExtension (char *in, char *out);
-void COM_FileBase (char *in, char *out);
-void COM_FilePath (char *in, char *out);
-void COM_DefaultExtension (char *path, char *extension);
-
-char *COM_Parse (char **data_p);
-// data is an in/out parm, returns a parsed out token
-
-void Com_sprintf (char *dest, int size, char *fmt, ...);
-
-void Com_PageInMemory (byte *buffer, int size);
-
-//=============================================
-
-short BigShort(short l);
-short LittleShort(short l);
-int BigLong (int l);
-int LittleLong (int l);
-float BigFloat (float l);
-float LittleFloat (float l);
-
-void Swap_Init (void);
-char *va(char *format, ...);
-
-//=============================================
-
-//
-// key / value info strings
-//
-#define MAX_INFO_KEY 64
-#define MAX_INFO_VALUE 64
-#define MAX_INFO_STRING 512
-
-char *Info_ValueForKey (char *s, char *key);
-void Info_RemoveKey (char *s, char *key);
-void Info_SetValueForKey (char *s, char *key, char *value);
-qboolean Info_Validate (char *s);
-
-/*
-==============================================================
-
-SYSTEM SPECIFIC
-
-==============================================================
-*/
-
-extern int curtime; // time returned by last Sys_Milliseconds
-
-int Sys_Milliseconds (void);
-void Sys_Mkdir (char *path);
-vlong flen(int);
-
-// large block stack allocation routines
-void *Hunk_Begin (int maxsize);
-void *Hunk_Alloc (int size);
-void Hunk_Free (void *buf);
-int Hunk_End (void);
-
-// directory searching
-#define SFF_ARCH 0x01
-#define SFF_HIDDEN 0x02
-#define SFF_RDONLY 0x04
-#define SFF_SUBDIR 0x08
-#define SFF_SYSTEM 0x10
-
-/*
-** pass in an attribute mask of things you wish to REJECT
-*/
-char *Sys_FindFirst (char *path, uint musthave, uint canthave );
-char *Sys_FindNext ( uint musthave, uint canthave );
-void Sys_FindClose (void);
-
-
-// this is only here so the functions in q_shared.c and q_shwin.c can link
-void Sys_Error (char *error, ...);
-void Com_Printf (char *msg, ...);
-
-
-/*
-==========================================================
-
-CVARS (console variables)
-
-==========================================================
-*/
-
-#ifndef CVAR
-#define CVAR
-
-#define CVAR_ARCHIVE 1 // set to cause it to be saved to vars.rc
-#define CVAR_USERINFO 2 // added to userinfo when changed
-#define CVAR_SERVERINFO 4 // added to serverinfo when changed
-#define CVAR_NOSET 8 // don't allow change from console at all,
- // but can be set from the command line
-#define CVAR_LATCH 16 // save changes until server restart
-
-// nothing outside the Cvar_*() functions should modify these fields!
-typedef struct cvar_s
-{
- char *name;
- char *string;
- char *latched_string; // for CVAR_LATCH vars
- int flags;
- qboolean modified; // set each time the cvar is changed
- float value;
- struct cvar_s *next;
-} cvar_t;
-
-#endif // CVAR
-
-/*
-==============================================================
-
-COLLISION DETECTION
-
-==============================================================
-*/
-
-// lower bits are stronger, and will eat weaker brushes completely
-#define CONTENTS_SOLID 1 // an eye is never valid in a solid
-#define CONTENTS_WINDOW 2 // translucent, but not watery
-#define CONTENTS_AUX 4
-#define CONTENTS_LAVA 8
-#define CONTENTS_SLIME 16
-#define CONTENTS_WATER 32
-#define CONTENTS_MIST 64
-#define LAST_VISIBLE_CONTENTS 64
-
-// remaining contents are non-visible, and don't eat brushes
-
-#define CONTENTS_AREAPORTAL 0x8000
-
-#define CONTENTS_PLAYERCLIP 0x10000
-#define CONTENTS_MONSTERCLIP 0x20000
-
-// currents can be added to any other contents, and may be mixed
-#define CONTENTS_CURRENT_0 0x40000
-#define CONTENTS_CURRENT_90 0x80000
-#define CONTENTS_CURRENT_180 0x100000
-#define CONTENTS_CURRENT_270 0x200000
-#define CONTENTS_CURRENT_UP 0x400000
-#define CONTENTS_CURRENT_DOWN 0x800000
-
-#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
-
-#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
-#define CONTENTS_DEADMONSTER 0x4000000
-#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
-#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
-#define CONTENTS_LADDER 0x20000000
-
-
-
-#define SURF_LIGHT 0x1 // value will hold the light strength
-
-#define SURF_SLICK 0x2 // effects game physics
-
-#define SURF_SKY 0x4 // don't draw, but add to skybox
-#define SURF_WARP 0x8 // turbulent water warp
-#define SURF_TRANS33 0x10
-#define SURF_TRANS66 0x20
-#define SURF_FLOWING 0x40 // scroll towards angle
-#define SURF_NODRAW 0x80 // don't bother referencing the texture
-
-
-
-// content masks
-#define MASK_ALL (-1)
-#define MASK_SOLID (CONTENTS_SOLID|CONTENTS_WINDOW)
-#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)
-#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW)
-#define MASK_MONSTERSOLID (CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)
-#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)
-#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA)
-#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEADMONSTER)
-#define MASK_CURRENT (CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN)
-
-
-// gi.BoxEdicts() can return a list of either solid or trigger entities
-// FIXME: eliminate AREA_ distinction?
-#define AREA_SOLID 1
-#define AREA_TRIGGERS 2
-
-
-// plane_t structure
-// !!! if this is changed, it must be changed in asm code too !!!
-typedef struct cplane_s
-{
- vec3_t normal;
- float dist;
- byte type; // for fast side tests
- byte signbits; // signx + (signy<<1) + (signz<<1)
- byte pad[2];
-} cplane_t;
-
-// structure offset for asm code<